ci_mock = $this->createMock(stdClass::class); // Mock get_instance function if (!function_exists('get_instance')) { function get_instance() { return $GLOBALS['CI_INSTANCE']; } } $GLOBALS['CI_INSTANCE'] = $this->ci_mock; // Create CustomerMapper instance require_once 'modules/desk_moloni/libraries/mappers/CustomerMapper.php'; $this->customer_mapper = new CustomerMapper(); } #[Test] #[Group('unit')] public function testCustomerMapperInitialization(): void { $this->assertInstanceOf(CustomerMapper::class, $this->customer_mapper); } #[Test] #[Group('unit')] public function testPerfexToMoloniMapping(): void { $perfex_client = [ 'userid' => '123', 'company' => 'Test Company Ltd', 'firstname' => 'John', 'lastname' => 'Doe', 'email' => 'john@testcompany.com', 'phonenumber' => '+351999888777', 'website' => 'https://testcompany.com', 'vat' => 'PT999888777', 'address' => 'Test Street 123', 'city' => 'Porto', 'zip' => '4000-001', 'country' => 'PT', 'admin_notes' => 'VIP customer' ]; $moloni_data = $this->customer_mapper->toMoloni($perfex_client); $this->assertIsArray($moloni_data); $this->assertEquals('Test Company Ltd', $moloni_data['name']); $this->assertEquals('john@testcompany.com', $moloni_data['email']); $this->assertEquals('+351999888777', $moloni_data['phone']); $this->assertEquals('https://testcompany.com', $moloni_data['website']); $this->assertEquals('PT999888777', $moloni_data['vat']); $this->assertEquals('PT999888777', $moloni_data['number']); $this->assertEquals('VIP customer', $moloni_data['notes']); $this->assertEquals('Test Street 123', $moloni_data['address']); $this->assertEquals('Porto', $moloni_data['city']); $this->assertEquals('4000-001', $moloni_data['zip_code']); } #[Test] #[Group('unit')] public function testPerfexToMoloniMappingWithoutCompanyName(): void { $perfex_client = [ 'userid' => '456', 'company' => '', 'firstname' => 'Jane', 'lastname' => 'Smith', 'email' => 'jane@example.com', 'phonenumber' => '+351888777666', 'vat' => 'PT888777666' ]; $moloni_data = $this->customer_mapper->toMoloni($perfex_client); // Should use firstname + lastname when company is empty $this->assertEquals('Jane Smith', $moloni_data['name']); $this->assertEquals('jane@example.com', $moloni_data['email']); $this->assertEquals('+351888777666', $moloni_data['phone']); $this->assertEquals('PT888777666', $moloni_data['vat']); } #[Test] #[Group('unit')] public function testPerfexToMoloniMappingWithoutVat(): void { $perfex_client = [ 'userid' => '789', 'company' => 'No VAT Company', 'email' => 'novat@company.com', 'vat' => '' ]; $moloni_data = $this->customer_mapper->toMoloni($perfex_client); // Should use userid as number when VAT is empty $this->assertEquals('789', $moloni_data['number']); $this->assertEquals('', $moloni_data['vat']); } #[Test] #[Group('unit')] public function testMoloniToPerfexMapping(): void { $moloni_customer = [ 'customer_id' => '555', 'name' => 'Moloni Test Company', 'email' => 'moloni@testcompany.com', 'phone' => '+351777666555', 'website' => 'https://molonittest.com', 'vat' => 'PT777666555', 'address' => 'Moloni Street 456', 'city' => 'Lisboa', 'zip_code' => '1000-001', 'country_id' => '187', // Portugal 'notes' => 'Important client' ]; $perfex_data = $this->customer_mapper->toPerfex($moloni_customer); $this->assertIsArray($perfex_data); $this->assertEquals('Moloni Test Company', $perfex_data['company']); $this->assertEquals('moloni@testcompany.com', $perfex_data['email']); $this->assertEquals('+351777666555', $perfex_data['phonenumber']); $this->assertEquals('https://molonittest.com', $perfex_data['website']); $this->assertEquals('PT777666555', $perfex_data['vat']); $this->assertEquals('Moloni Street 456', $perfex_data['address']); $this->assertEquals('Lisboa', $perfex_data['city']); $this->assertEquals('1000-001', $perfex_data['zip']); $this->assertEquals('Important client', $perfex_data['admin_notes']); } #[Test] #[Group('unit')] #[DataProvider('invalidDataProvider')] public function testMappingWithInvalidData(array $input_data, string $direction): void { if ($direction === 'toMoloni') { $result = $this->customer_mapper->toMoloni($input_data); } else { $result = $this->customer_mapper->toPerfex($input_data); } $this->assertIsArray($result); // Should return array even with invalid input (graceful handling) } public static function invalidDataProvider(): array { return [ 'Empty Perfex data' => [[], 'toMoloni'], 'Empty Moloni data' => [[], 'toPerfex'], 'Null values Perfex' => [['company' => null, 'email' => null], 'toMoloni'], 'Null values Moloni' => [['name' => null, 'email' => null], 'toPerfex'] ]; } #[Test] #[Group('unit')] public function testFieldSanitization(): void { $perfex_client = [ 'company' => ' Test Company with Spaces ', 'email' => ' EMAIL@UPPERCASE.COM ', 'phonenumber' => ' +351 999 888 777 ', 'vat' => ' pt999888777 ' ]; $moloni_data = $this->customer_mapper->toMoloni($perfex_client); // Check if data is properly sanitized $this->assertEquals('Test Company with Spaces', trim($moloni_data['name'])); $this->assertEquals('email@uppercase.com', strtolower(trim($moloni_data['email']))); } #[Test] #[Group('unit')] public function testVatNumberValidation(): void { // Test Portuguese VAT validation $valid_vats = [ 'PT999888777', '999888777', 'pt777666555' ]; foreach ($valid_vats as $vat) { $perfex_client = ['vat' => $vat, 'company' => 'Test']; $moloni_data = $this->customer_mapper->toMoloni($perfex_client); $this->assertNotEmpty($moloni_data['vat']); } } #[Test] #[Group('unit')] public function testEmailValidation(): void { $test_cases = [ 'valid@email.com' => true, 'invalid-email' => false, 'test@domain' => true, // Basic validation '' => false, null => false ]; foreach ($test_cases as $email => $should_be_valid) { $perfex_client = ['company' => 'Test', 'email' => $email]; $moloni_data = $this->customer_mapper->toMoloni($perfex_client); if ($should_be_valid) { $this->assertEquals($email, $moloni_data['email']); } else { // Should handle invalid emails gracefully $this->assertTrue(true); } } } #[Test] #[Group('unit')] public function testPhoneNumberFormatting(): void { $phone_formats = [ '+351999888777' => '+351999888777', '999888777' => '999888777', '+351 999 888 777' => '+351999888777', '(+351) 999-888-777' => '+351999888777' ]; foreach ($phone_formats as $input => $expected) { $perfex_client = ['company' => 'Test', 'phonenumber' => $input]; $moloni_data = $this->customer_mapper->toMoloni($perfex_client); // Phone formatting logic would be tested here $this->assertNotEmpty($moloni_data['phone']); } } #[Test] #[Group('unit')] public function testCountryCodeMapping(): void { $country_mappings = [ 'PT' => '187', // Portugal 'ES' => '195', // Spain 'FR' => '76', // France 'DE' => '81', // Germany 'UK' => '224' // United Kingdom ]; foreach ($country_mappings as $country_code => $expected_id) { $moloni_customer = [ 'name' => 'Test', 'country_id' => $expected_id ]; $perfex_data = $this->customer_mapper->toPerfex($moloni_customer); // Country mapping logic would be tested here $this->assertIsArray($perfex_data); } } #[Test] #[Group('unit')] public function testBidirectionalMapping(): void { // Test that mapping back and forth preserves essential data $original_perfex = [ 'company' => 'Bidirectional Test Company', 'email' => 'bidirectional@test.com', 'vat' => 'PT123456789' ]; // Perfex -> Moloni -> Perfex $moloni_data = $this->customer_mapper->toMoloni($original_perfex); $back_to_perfex = $this->customer_mapper->toPerfex($moloni_data); // Essential fields should be preserved $this->assertEquals($original_perfex['company'], $back_to_perfex['company']); $this->assertEquals($original_perfex['email'], $back_to_perfex['email']); $this->assertEquals($original_perfex['vat'], $back_to_perfex['vat']); } protected function tearDown(): void { $this->customer_mapper = null; $this->ci_mock = null; parent::tearDown(); } }