* @since 1.0.0 */ namespace Care_API\Tests\Unit\Models; use Care_API\Models\Patient; use Care_API\Models\Clinic; class PatientTest extends \Care_API_Test_Case { /** * Mock wpdb for database operations */ private $mock_wpdb; /** * Setup before each test */ public function setUp(): void { parent::setUp(); // Mock wpdb global global $wpdb; $this->mock_wpdb = $this->createMock('wpdb'); $wpdb = $this->mock_wpdb; } /** * Test patient creation with valid data * * @covers Patient::create * @covers Patient::validate_patient_data */ public function test_patient_creation_valid_data() { // Arrange $valid_patient_data = array( 'first_name' => 'João', 'last_name' => 'Silva', 'user_email' => 'joao.silva@example.com', 'birth_date' => '1985-03-15', 'gender' => 'M', 'mobile_number' => '+351912345678', 'address' => 'Rua das Flores, 123', 'city' => 'Lisboa', 'country' => 'Portugal', 'blood_group' => 'A+', 'clinic_id' => 1 ); // Mock WordPress functions $this->mock_wp_functions_for_user_creation(); // Act $result = Patient::create($valid_patient_data); // Assert $this->assertIsInt($result, 'Patient creation should return user ID'); $this->assertGreaterThan(0, $result, 'User ID should be positive'); } /** * Test patient creation with invalid data (missing required fields) * * @covers Patient::create * @covers Patient::validate_patient_data */ public function test_patient_creation_invalid_data_missing_fields() { // Arrange $invalid_patient_data = array( 'first_name' => 'João', // Missing required fields: last_name, user_email, birth_date, gender 'mobile_number' => '+351912345678' ); // Act $result = Patient::create($invalid_patient_data); // Assert $this->assertInstanceOf('WP_Error', $result, 'Should return WP_Error for invalid data'); $this->assertEquals('patient_validation_failed', $result->get_error_code()); $error_data = $result->get_error_data(); $this->assertArrayHasKey('errors', $error_data); $this->assertContains("Field 'last_name' is required", $error_data['errors']); $this->assertContains("Field 'user_email' is required", $error_data['errors']); $this->assertContains("Field 'birth_date' is required", $error_data['errors']); $this->assertContains("Field 'gender' is required", $error_data['errors']); } /** * Test patient creation with invalid email format * * @covers Patient::validate_patient_data */ public function test_patient_creation_invalid_email_format() { // Arrange $patient_data_invalid_email = array( 'first_name' => 'Maria', 'last_name' => 'Santos', 'user_email' => 'invalid-email-format', // Invalid email 'birth_date' => '1990-07-20', 'gender' => 'F' ); // Act $result = Patient::create($patient_data_invalid_email); // Assert $this->assertInstanceOf('WP_Error', $result); $error_data = $result->get_error_data(); $this->assertContains('Invalid email format', $error_data['errors']); } /** * Test patient creation with invalid birth date format * * @covers Patient::validate_patient_data */ public function test_patient_creation_invalid_birth_date() { // Arrange $patient_data_invalid_date = array( 'first_name' => 'Carlos', 'last_name' => 'Oliveira', 'user_email' => 'carlos@example.com', 'birth_date' => '15/03/1985', // Invalid format (should be Y-m-d) 'gender' => 'M' ); // Act $result = Patient::create($patient_data_invalid_date); // Assert $this->assertInstanceOf('WP_Error', $result); $error_data = $result->get_error_data(); $this->assertContains('Invalid birth date format. Use YYYY-MM-DD', $error_data['errors']); } /** * Test patient creation with invalid gender * * @covers Patient::validate_patient_data */ public function test_patient_creation_invalid_gender() { // Arrange $patient_data_invalid_gender = array( 'first_name' => 'Ana', 'last_name' => 'Costa', 'user_email' => 'ana@example.com', 'birth_date' => '1988-12-10', 'gender' => 'X' // Invalid gender (should be M, F, or O) ); // Act $result = Patient::create($patient_data_invalid_gender); // Assert $this->assertInstanceOf('WP_Error', $result); $error_data = $result->get_error_data(); $this->assertContains('Invalid gender. Use M, F, or O', $error_data['errors']); } /** * Test patient-clinic associations * * @covers Patient::assign_to_clinic * @covers Patient::get_patient_full_data */ public function test_patient_clinic_associations() { // Arrange $patient_id = $this->create_test_patient(); $clinic_id = $this->create_test_clinic(); // Mock clinic exists check $clinic_mock = $this->createMock('Care_API\Models\Clinic'); $clinic_mock->method('exists')->willReturn(true); // Mock wpdb operations for clinic assignment $this->mock_wpdb->expects($this->once()) ->method('get_var') ->willReturn(0); // No existing mapping $this->mock_wpdb->expects($this->once()) ->method('insert') ->willReturn(1); // Successful insert // Act $result = Patient::assign_to_clinic($patient_id, $clinic_id); // Assert $this->assertTrue($result, 'Patient should be successfully assigned to clinic'); } /** * Test patient statistics calculation * * @covers Patient::get_statistics */ public function test_patient_statistics() { // Arrange $patient_id = $this->create_test_patient(); // Mock database queries for statistics $this->mock_wpdb->expects($this->exactly(5)) ->method('get_var') ->willReturnOnConsecutiveCalls( 5, // total_appointments 3, // completed_encounters 2, // pending_appointments 4, // total_prescriptions '2024-01-15' // next_appointment ); // Act $statistics = Patient::get_statistics($patient_id); // Assert $this->assertIsArray($statistics, 'Statistics should be an array'); $this->assertArrayHasKey('total_appointments', $statistics); $this->assertArrayHasKey('completed_encounters', $statistics); $this->assertArrayHasKey('pending_appointments', $statistics); $this->assertArrayHasKey('total_prescriptions', $statistics); $this->assertArrayHasKey('next_appointment', $statistics); $this->assertEquals(5, $statistics['total_appointments']); $this->assertEquals(3, $statistics['completed_encounters']); $this->assertEquals(2, $statistics['pending_appointments']); $this->assertEquals(4, $statistics['total_prescriptions']); $this->assertEquals('2024-01-15', $statistics['next_appointment']); } /** * Test age calculation from birth date * * @covers Patient::calculate_age (private method tested via get_patient_full_data) */ public function test_patient_age_calculation() { // Arrange $birth_date = '1990-05-15'; $expected_age = date('Y') - 1990; // Adjust for birthday not yet occurred this year if (date('md') < '0515') { $expected_age--; } // Mock patient data with birth date $patient_data = array( 'user_id' => 123, 'birth_date' => $birth_date ); // Mock WordPress user and meta functions $mock_user = (object) array( 'ID' => 123, 'roles' => array('kivicare_patient'), 'user_login' => 'test_patient', 'user_email' => 'patient@test.com', 'first_name' => 'Test', 'last_name' => 'Patient', 'display_name' => 'Test Patient' ); // Mock get_user_by global $wp_test_expectations; $wp_test_expectations['get_user_by'] = $mock_user; // Mock get_user_meta for birth_date $wp_test_expectations['get_user_meta'] = $birth_date; // Mock wpdb query for clinic mapping $this->mock_wpdb->expects($this->once()) ->method('get_row') ->willReturn(null); // Act $full_data = Patient::get_patient_full_data(123); // Assert $this->assertEquals($expected_age, $full_data['age'], 'Age should be correctly calculated from birth date'); } /** * Helper method to create test patient */ private function create_test_patient() { return $this->factory->user->create(array( 'user_login' => 'test_patient_' . wp_rand(1000, 9999), 'user_email' => 'testpatient' . wp_rand(1000, 9999) . '@example.com', 'first_name' => 'Test', 'last_name' => 'Patient', 'role' => 'kivicare_patient' )); } /** * Helper method to mock WordPress functions for user creation */ private function mock_wp_functions_for_user_creation() { global $wp_test_expectations; // Mock successful user creation $wp_test_expectations['wp_insert_user'] = 123; $wp_test_expectations['is_email'] = true; $wp_test_expectations['get_user_by'] = false; // No existing user $wp_test_expectations['username_exists'] = false; // Username available $wp_test_expectations['sanitize_email'] = function($email) { return $email; }; $wp_test_expectations['sanitize_text_field'] = function($text) { return $text; }; $wp_test_expectations['wp_generate_password'] = 'test_password'; $wp_test_expectations['current_time'] = '2024-01-15 10:30:00'; $wp_test_expectations['update_user_meta'] = true; } }