chore: add spec-kit and standardize signatures

- Added GitHub spec-kit for development workflow
- Standardized file signatures to Descomplicar® format
- Updated development configuration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Emanuel Almeida
2025-09-12 01:27:34 +01:00
parent 4a60be990e
commit 38bb926742
118 changed files with 40694 additions and 0 deletions

View File

@@ -0,0 +1,508 @@
/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php
/**
* Contract test for wp_ajax_care_booking_bulk_update endpoint
*
* @package CareBookingBlock
*/
/**
* Test AJAX endpoint: wp_ajax_care_booking_bulk_update
*/
class Test_Ajax_Bulk_Update extends Care_Booking_Test_Case
{
/**
* Test AJAX handler is registered
*/
public function test_ajax_handler_registered()
{
$this->assertTrue(has_action('wp_ajax_care_booking_bulk_update'), 'AJAX handler should be registered');
$this->assertFalse(has_action('wp_ajax_nopriv_care_booking_bulk_update'), 'Non-privileged AJAX should not be registered');
}
/**
* Test successful bulk update with mixed restrictions
*/
public function test_successful_bulk_update()
{
$this->set_current_user($this->admin_user_id);
$restrictions = [
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
],
[
'restriction_type' => 'doctor',
'target_id' => 998,
'is_blocked' => false
],
[
'restriction_type' => 'service',
'target_id' => 888,
'doctor_id' => 999,
'is_blocked' => true
]
];
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => $restrictions
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Test response structure according to contract
$this->assertArrayHasKey('message', $data['data']);
$this->assertArrayHasKey('updated', $data['data']);
$this->assertArrayHasKey('errors', $data['data']);
$this->assertEquals('Bulk update completed', $data['data']['message']);
$this->assertEquals(3, $data['data']['updated']);
$this->assertEmpty($data['data']['errors']);
}
/**
* Test bulk update with some failures
*/
public function test_bulk_update_with_partial_failures()
{
$this->set_current_user($this->admin_user_id);
$restrictions = [
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
],
[
'restriction_type' => 'invalid_type', // This should fail
'target_id' => 998,
'is_blocked' => true
],
[
'restriction_type' => 'service',
'target_id' => 888,
'doctor_id' => 999,
'is_blocked' => true
]
];
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => $restrictions
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false); // Partial failure should return false
$this->assertEquals('Partial failure in bulk update', $data['data']['message']);
$this->assertEquals(2, $data['data']['updated']); // Only 2 successful
$this->assertCount(1, $data['data']['errors']); // 1 error
// Check error structure
$error = $data['data']['errors'][0];
$this->assertArrayHasKey('restriction', $error);
$this->assertArrayHasKey('error', $error);
$this->assertEquals('invalid_type', $error['restriction']['restriction_type']);
}
/**
* Test bulk update with KiviCare target validation
*/
public function test_bulk_update_with_target_validation()
{
$this->set_current_user($this->admin_user_id);
$restrictions = [
[
'restriction_type' => 'doctor',
'target_id' => 99999, // Non-existent doctor
'is_blocked' => true
]
];
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => $restrictions
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals(0, $data['data']['updated']);
$this->assertCount(1, $data['data']['errors']);
$this->assertContains('Target not found in KiviCare', $data['data']['errors'][0]['error']);
}
/**
* Test invalid nonce returns error
*/
public function test_invalid_nonce_error()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => 'invalid_nonce',
'restrictions' => []
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Invalid nonce', $data['data']['message']);
}
/**
* Test insufficient permissions returns error
*/
public function test_insufficient_permissions_error()
{
$subscriber_id = $this->factory->user->create(['role' => 'subscriber']);
$this->set_current_user($subscriber_id);
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => []
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Insufficient permissions', $data['data']['message']);
}
/**
* Test empty restrictions array
*/
public function test_empty_restrictions_array()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => []
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
$this->assertEquals('Bulk update completed', $data['data']['message']);
$this->assertEquals(0, $data['data']['updated']);
$this->assertEmpty($data['data']['errors']);
}
/**
* Test missing restrictions parameter
*/
public function test_missing_restrictions_parameter()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update')
// Missing 'restrictions' parameter
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Missing restrictions parameter', $data['data']['message']);
}
/**
* Test invalid restrictions format
*/
public function test_invalid_restrictions_format()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => 'invalid_format' // Should be array
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Invalid restrictions format', $data['data']['message']);
}
/**
* Test response time performance requirement for bulk operation
*/
public function test_response_time_performance()
{
$this->set_current_user($this->admin_user_id);
// Create bulk data (50 items as per contract)
$restrictions = [];
for ($i = 1; $i <= 50; $i++) {
$restrictions[] = [
'restriction_type' => 'doctor',
'target_id' => 900 + $i,
'is_blocked' => $i % 2 === 0
];
}
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => $restrictions
];
$start_time = microtime(true);
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$end_time = microtime(true);
$response_time = ($end_time - $start_time) * 1000;
$this->assertLessThan(500, $response_time, 'Bulk update should complete in under 500ms for 50 items');
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
$this->assertEquals(50, $data['data']['updated']);
}
/**
* Test transaction rollback on critical errors
*/
public function test_transaction_rollback_on_critical_error()
{
$this->set_current_user($this->admin_user_id);
$restrictions = [
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
],
[
'restriction_type' => 'doctor',
'target_id' => 998,
'is_blocked' => true
]
];
// Mock database error during processing
global $wpdb;
// Hook into database operations to simulate error
add_filter('query', function($query) {
if (strpos($query, 'care_booking_restrictions') !== false && strpos($query, '998') !== false) {
return 'SELECT * FROM non_existent_table'; // Force error
}
return $query;
});
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => $restrictions
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
// Remove filter
remove_all_filters('query');
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
// Verify partial processing occurred with error handling
$this->assertIsInt($data['data']['updated']);
$this->assertIsArray($data['data']['errors']);
}
/**
* Test cache invalidation after bulk update
*/
public function test_cache_invalidation_after_bulk_update()
{
$this->set_current_user($this->admin_user_id);
// Set initial cache
set_transient('care_booking_doctors_blocked', [997], 3600);
set_transient('care_booking_services_blocked_999', [886], 3600);
$this->assertNotFalse(get_transient('care_booking_doctors_blocked'));
$this->assertNotFalse(get_transient('care_booking_services_blocked_999'));
$restrictions = [
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
]
];
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => $restrictions
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Cache should be invalidated
$this->assertFalse(get_transient('care_booking_doctors_blocked'));
$this->assertFalse(get_transient('care_booking_services_blocked_999'));
}
/**
* Test WordPress action triggered after bulk update
*/
public function test_action_triggered_after_bulk_update()
{
$this->set_current_user($this->admin_user_id);
$actions_fired = [];
add_action('care_booking_restriction_updated', function($type, $target_id, $doctor_id = null) use (&$actions_fired) {
$actions_fired[] = [$type, $target_id, $doctor_id];
}, 10, 3);
$restrictions = [
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
],
[
'restriction_type' => 'service',
'target_id' => 888,
'doctor_id' => 999,
'is_blocked' => false
]
];
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => $restrictions
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Actions should have fired for each restriction
$this->assertCount(2, $actions_fired);
$this->assertContains(['doctor', 999, null], $actions_fired);
$this->assertContains(['service', 888, 999], $actions_fired);
}
/**
* Test maximum bulk size limit
*/
public function test_maximum_bulk_size_limit()
{
$this->set_current_user($this->admin_user_id);
// Create oversized bulk request (more than allowed)
$restrictions = [];
for ($i = 1; $i <= 101; $i++) { // Over 100 items limit
$restrictions[] = [
'restriction_type' => 'doctor',
'target_id' => 800 + $i,
'is_blocked' => true
];
}
$_POST = [
'action' => 'care_booking_bulk_update',
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
'restrictions' => $restrictions
];
ob_start();
try {
do_action('wp_ajax_care_booking_bulk_update');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Bulk size limit exceeded', $data['data']['message']);
}
}

View File

@@ -0,0 +1,521 @@
/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php
/**
* Contract test for wp_ajax_care_booking_get_entities endpoint
*
* @package CareBookingBlock
*/
/**
* Test AJAX endpoint: wp_ajax_care_booking_get_entities
*/
class Test_Ajax_Get_Entities extends Care_Booking_Test_Case
{
/**
* Test AJAX handler is registered
*/
public function test_ajax_handler_registered()
{
$this->assertTrue(has_action('wp_ajax_care_booking_get_entities'), 'AJAX handler should be registered');
$this->assertFalse(has_action('wp_ajax_nopriv_care_booking_get_entities'), 'Non-privileged AJAX should not be registered');
}
/**
* Test successful doctors retrieval
*/
public function test_successful_doctors_retrieval()
{
$this->set_current_user($this->admin_user_id);
// Create some test restrictions to show restriction status
$this->create_test_doctor_restriction(999, true);
$this->create_test_doctor_restriction(998, false);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'doctors'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Test response structure according to contract
$this->assertArrayHasKey('entities', $data['data']);
$this->assertArrayHasKey('total', $data['data']);
$this->assertIsArray($data['data']['entities']);
$this->assertIsInt($data['data']['total']);
// Test entity structure if entities exist
if (!empty($data['data']['entities'])) {
$entity = $data['data']['entities'][0];
$this->assertArrayHasKey('id', $entity);
$this->assertArrayHasKey('name', $entity);
$this->assertArrayHasKey('email', $entity);
$this->assertArrayHasKey('is_blocked', $entity);
$this->assertIsBool($entity['is_blocked']);
}
}
/**
* Test successful services retrieval
*/
public function test_successful_services_retrieval()
{
$this->set_current_user($this->admin_user_id);
// Create service restriction for testing status
$this->create_test_service_restriction(888, 999, true);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'services'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
$this->assertArrayHasKey('entities', $data['data']);
$this->assertArrayHasKey('total', $data['data']);
// Test service entity structure if services exist
if (!empty($data['data']['entities'])) {
$service = $data['data']['entities'][0];
$this->assertArrayHasKey('id', $service);
$this->assertArrayHasKey('name', $service);
$this->assertArrayHasKey('doctor_id', $service);
$this->assertArrayHasKey('is_blocked', $service);
}
}
/**
* Test services retrieval filtered by doctor
*/
public function test_services_filtered_by_doctor()
{
$this->set_current_user($this->admin_user_id);
// Create services for different doctors
$this->create_test_service_restriction(888, 999, true);
$this->create_test_service_restriction(887, 998, false);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'services',
'doctor_id' => 999
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Should only return services for doctor 999
if (!empty($data['data']['entities'])) {
foreach ($data['data']['entities'] as $service) {
$this->assertEquals(999, $service['doctor_id'], 'All services should belong to doctor 999');
}
}
}
/**
* Test invalid nonce returns error
*/
public function test_invalid_nonce_error()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => 'invalid_nonce',
'entity_type' => 'doctors'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Invalid nonce', $data['data']['message']);
}
/**
* Test insufficient permissions returns error
*/
public function test_insufficient_permissions_error()
{
$subscriber_id = $this->factory->user->create(['role' => 'subscriber']);
$this->set_current_user($subscriber_id);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'doctors'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Insufficient permissions', $data['data']['message']);
}
/**
* Test invalid entity type returns error
*/
public function test_invalid_entity_type_error()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'invalid_type'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Invalid entity type', $data['data']['message']);
}
/**
* Test missing entity_type parameter
*/
public function test_missing_entity_type_parameter()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities')
// Missing entity_type parameter
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Missing entity_type parameter', $data['data']['message']);
}
/**
* Test KiviCare plugin not available
*/
public function test_kivicare_not_available()
{
$this->set_current_user($this->admin_user_id);
// Mock KiviCare as not available
add_filter('pre_option_active_plugins', function($plugins) {
return []; // No active plugins
});
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'doctors'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
remove_all_filters('pre_option_active_plugins');
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('KiviCare plugin not available', $data['data']['message']);
}
/**
* Test empty results return correct structure
*/
public function test_empty_results()
{
$this->set_current_user($this->admin_user_id);
// Mock empty KiviCare tables
global $wpdb;
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'doctors'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
$this->assertIsArray($data['data']['entities']);
$this->assertEquals(0, $data['data']['total']);
}
/**
* Test response time performance requirement
*/
public function test_response_time_performance()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'doctors'
];
$start_time = microtime(true);
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$end_time = microtime(true);
$response_time = ($end_time - $start_time) * 1000;
$this->assertLessThan(400, $response_time, 'Response time should be under 400ms according to contract');
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
}
/**
* Test restriction status accuracy
*/
public function test_restriction_status_accuracy()
{
$this->set_current_user($this->admin_user_id);
// Create known restrictions
$this->create_test_doctor_restriction(999, true); // Blocked
$this->create_test_doctor_restriction(998, false); // Not blocked
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'doctors'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Find our test doctors and verify restriction status
foreach ($data['data']['entities'] as $doctor) {
if ($doctor['id'] == 999) {
$this->assertTrue($doctor['is_blocked'], 'Doctor 999 should be marked as blocked');
} elseif ($doctor['id'] == 998) {
$this->assertFalse($doctor['is_blocked'], 'Doctor 998 should not be marked as blocked');
}
}
}
/**
* Test service restriction status with doctor context
*/
public function test_service_restriction_status_with_doctor()
{
$this->set_current_user($this->admin_user_id);
// Create service restrictions for specific doctors
$this->create_test_service_restriction(888, 999, true); // Service 888 blocked for doctor 999
$this->create_test_service_restriction(888, 998, false); // Service 888 not blocked for doctor 998
// Get services for doctor 999
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'services',
'doctor_id' => 999
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Check service 888 status for doctor 999
foreach ($data['data']['entities'] as $service) {
if ($service['id'] == 888) {
$this->assertTrue($service['is_blocked'], 'Service 888 should be blocked for doctor 999');
}
}
// Get services for doctor 998
$_POST['doctor_id'] = 998;
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Check service 888 status for doctor 998
foreach ($data['data']['entities'] as $service) {
if ($service['id'] == 888) {
$this->assertFalse($service['is_blocked'], 'Service 888 should not be blocked for doctor 998');
}
}
}
/**
* Test database error handling
*/
public function test_database_error_handling()
{
$this->set_current_user($this->admin_user_id);
// Mock database error
global $wpdb;
$original_prefix = $wpdb->prefix;
$wpdb->prefix = 'invalid_prefix_';
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'doctors'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
// Restore prefix
$wpdb->prefix = $original_prefix;
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertContains('Database error', $data['data']['message']);
}
/**
* Test large dataset handling
*/
public function test_large_dataset_handling()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'doctors'
];
// This test verifies the system can handle large result sets
// without timing out or running into memory issues
$start_memory = memory_get_usage();
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$end_memory = memory_get_usage();
$memory_used = $end_memory - $start_memory;
// Memory usage should be reasonable (less than 10MB for the operation)
$this->assertLessThan(10 * 1024 * 1024, $memory_used, 'Memory usage should be reasonable');
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
}
/**
* Test concurrent request handling
*/
public function test_concurrent_request_handling()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_entities',
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
'entity_type' => 'doctors'
];
// Simulate multiple concurrent requests
$responses = [];
for ($i = 0; $i < 3; $i++) {
ob_start();
try {
do_action('wp_ajax_care_booking_get_entities');
} catch (WPAjaxDieStopException $e) {}
$responses[] = ob_get_clean();
}
// All responses should be valid and consistent
foreach ($responses as $response) {
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Structure should be consistent across all responses
$this->assertArrayHasKey('entities', $data['data']);
$this->assertArrayHasKey('total', $data['data']);
}
}
}

View File

@@ -0,0 +1,361 @@
/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php
/**
* Contract test for wp_ajax_care_booking_get_restrictions endpoint
*
* @package CareBookingBlock
*/
/**
* Test AJAX endpoint: wp_ajax_care_booking_get_restrictions
*/
class Test_Ajax_Get_Restrictions extends Care_Booking_Test_Case
{
/**
* Test AJAX handler is registered
*/
public function test_ajax_handler_registered()
{
$this->assertTrue(has_action('wp_ajax_care_booking_get_restrictions'), 'AJAX handler should be registered');
$this->assertFalse(has_action('wp_ajax_nopriv_care_booking_get_restrictions'), 'Non-privileged AJAX should not be registered');
}
/**
* Test successful request returns correct structure
*/
public function test_successful_request_structure()
{
// Set up admin user
$this->set_current_user($this->admin_user_id);
// Create test restrictions
$this->create_test_doctor_restriction(999, true);
$this->create_test_service_restriction(888, 999, false);
// Mock AJAX request
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
'restriction_type' => 'all'
];
// Capture AJAX response
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {
// Expected for wp_die() in AJAX handlers
}
$response = ob_get_clean();
$data = json_decode($response, true);
// Test response structure according to contract
$this->assert_ajax_response($data, true);
$this->assertArrayHasKey('restrictions', $data['data']);
$this->assertArrayHasKey('total', $data['data']);
$this->assertIsArray($data['data']['restrictions']);
$this->assertIsInt($data['data']['total']);
// Test restriction object structure
$this->assertGreaterThan(0, count($data['data']['restrictions']));
$restriction = $data['data']['restrictions'][0];
$this->assertArrayHasKey('id', $restriction);
$this->assertArrayHasKey('restriction_type', $restriction);
$this->assertArrayHasKey('target_id', $restriction);
$this->assertArrayHasKey('doctor_id', $restriction);
$this->assertArrayHasKey('is_blocked', $restriction);
$this->assertArrayHasKey('created_at', $restriction);
$this->assertArrayHasKey('updated_at', $restriction);
}
/**
* Test filter by restriction type
*/
public function test_filter_by_restriction_type()
{
$this->set_current_user($this->admin_user_id);
// Create different types
$this->create_test_doctor_restriction(999, true);
$this->create_test_service_restriction(888, 999, true);
// Test filter by doctor
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
'restriction_type' => 'doctor'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Should only return doctor restrictions
foreach ($data['data']['restrictions'] as $restriction) {
$this->assertEquals('doctor', $restriction['restriction_type']);
}
// Test filter by service
$_POST['restriction_type'] = 'service';
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Should only return service restrictions
foreach ($data['data']['restrictions'] as $restriction) {
$this->assertEquals('service', $restriction['restriction_type']);
}
}
/**
* Test filter by doctor for service restrictions
*/
public function test_filter_services_by_doctor()
{
$this->set_current_user($this->admin_user_id);
// Create service restrictions for different doctors
$this->create_test_service_restriction(888, 999, true);
$this->create_test_service_restriction(887, 998, true);
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
'restriction_type' => 'service',
'doctor_id' => 999
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Should only return services for doctor 999
foreach ($data['data']['restrictions'] as $restriction) {
$this->assertEquals('service', $restriction['restriction_type']);
$this->assertEquals(999, $restriction['doctor_id']);
}
}
/**
* Test invalid nonce returns error
*/
public function test_invalid_nonce_error()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => 'invalid_nonce',
'restriction_type' => 'all'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Invalid nonce', $data['data']['message']);
}
/**
* Test insufficient permissions returns error
*/
public function test_insufficient_permissions_error()
{
// Create subscriber user (no manage_options capability)
$subscriber_id = $this->factory->user->create(['role' => 'subscriber']);
$this->set_current_user($subscriber_id);
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
'restriction_type' => 'all'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Insufficient permissions', $data['data']['message']);
}
/**
* Test invalid parameters return error
*/
public function test_invalid_parameters_error()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
'restriction_type' => 'invalid_type'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Invalid parameters', $data['data']['message']);
}
/**
* Test empty results return correct structure
*/
public function test_empty_results()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
'restriction_type' => 'all'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
$this->assertIsArray($data['data']['restrictions']);
$this->assertEmpty($data['data']['restrictions']);
$this->assertEquals(0, $data['data']['total']);
}
/**
* Test response time performance requirement
*/
public function test_response_time_performance()
{
$this->set_current_user($this->admin_user_id);
// Create test data
for ($i = 1; $i <= 50; $i++) {
$this->create_test_doctor_restriction(900 + $i, $i % 2 === 0);
}
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
'restriction_type' => 'all'
];
$start_time = microtime(true);
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$end_time = microtime(true);
$response_time = ($end_time - $start_time) * 1000; // Convert to milliseconds
$this->assertLessThan(200, $response_time, 'Response time should be under 200ms according to contract');
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
$this->assertEquals(50, $data['data']['total']);
}
/**
* Test JSON response format compliance
*/
public function test_json_response_format()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
'restriction_type' => 'all'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
// Test valid JSON
$data = json_decode($response, true);
$this->assertNotNull($data, 'Response should be valid JSON');
$this->assertEquals(JSON_ERROR_NONE, json_last_error(), 'JSON should be valid');
// Test WordPress AJAX standard format
$this->assertArrayHasKey('success', $data);
$this->assertArrayHasKey('data', $data);
$this->assertIsBool($data['success']);
}
/**
* Test database error handling
*/
public function test_database_error_handling()
{
$this->set_current_user($this->admin_user_id);
// Mock database error by temporarily corrupting table name
global $wpdb;
$original_prefix = $wpdb->prefix;
$wpdb->prefix = 'invalid_prefix_';
$_POST = [
'action' => 'care_booking_get_restrictions',
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
'restriction_type' => 'all'
];
ob_start();
try {
do_action('wp_ajax_care_booking_get_restrictions');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
// Restore database prefix
$wpdb->prefix = $original_prefix;
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertContains('Database error', $data['data']['message']);
}
}

View File

@@ -0,0 +1,431 @@
/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php
/**
* Contract test for wp_ajax_care_booking_toggle_restriction endpoint
*
* @package CareBookingBlock
*/
/**
* Test AJAX endpoint: wp_ajax_care_booking_toggle_restriction
*/
class Test_Ajax_Toggle_Restriction extends Care_Booking_Test_Case
{
/**
* Test AJAX handler is registered
*/
public function test_ajax_handler_registered()
{
$this->assertTrue(has_action('wp_ajax_care_booking_toggle_restriction'), 'AJAX handler should be registered');
$this->assertFalse(has_action('wp_ajax_nopriv_care_booking_toggle_restriction'), 'Non-privileged AJAX should not be registered');
}
/**
* Test successful doctor restriction toggle
*/
public function test_successful_doctor_restriction_toggle()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Test response structure according to contract
$this->assertArrayHasKey('message', $data['data']);
$this->assertArrayHasKey('restriction', $data['data']);
$this->assertEquals('Restriction updated successfully', $data['data']['message']);
// Test restriction object structure
$restriction = $data['data']['restriction'];
$this->assertArrayHasKey('id', $restriction);
$this->assertArrayHasKey('restriction_type', $restriction);
$this->assertArrayHasKey('target_id', $restriction);
$this->assertArrayHasKey('doctor_id', $restriction);
$this->assertArrayHasKey('is_blocked', $restriction);
$this->assertArrayHasKey('updated_at', $restriction);
// Test values match request
$this->assertEquals('doctor', $restriction['restriction_type']);
$this->assertEquals(999, $restriction['target_id']);
$this->assertNull($restriction['doctor_id']);
$this->assertTrue($restriction['is_blocked']);
}
/**
* Test successful service restriction toggle
*/
public function test_successful_service_restriction_toggle()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'service',
'target_id' => 888,
'doctor_id' => 999,
'is_blocked' => false
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
$restriction = $data['data']['restriction'];
$this->assertEquals('service', $restriction['restriction_type']);
$this->assertEquals(888, $restriction['target_id']);
$this->assertEquals(999, $restriction['doctor_id']);
$this->assertFalse($restriction['is_blocked']);
}
/**
* Test toggle existing restriction (update operation)
*/
public function test_toggle_existing_restriction()
{
$this->set_current_user($this->admin_user_id);
// Create initial restriction
$restriction_id = $this->create_test_doctor_restriction(999, true);
// Toggle to unblocked
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => false
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Should return same restriction ID but updated
$this->assertEquals($restriction_id, $data['data']['restriction']['id']);
$this->assertFalse($data['data']['restriction']['is_blocked']);
}
/**
* Test invalid nonce returns error
*/
public function test_invalid_nonce_error()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => 'invalid_nonce',
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Invalid nonce', $data['data']['message']);
}
/**
* Test insufficient permissions returns error
*/
public function test_insufficient_permissions_error()
{
$subscriber_id = $this->factory->user->create(['role' => 'subscriber']);
$this->set_current_user($subscriber_id);
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Insufficient permissions', $data['data']['message']);
}
/**
* Test missing required parameters
*/
public function test_missing_required_parameters()
{
$this->set_current_user($this->admin_user_id);
// Missing target_id
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'doctor',
'is_blocked' => true
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertContains('Missing required parameter', $data['data']['message']);
}
/**
* Test invalid restriction type
*/
public function test_invalid_restriction_type()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'invalid_type',
'target_id' => 999,
'is_blocked' => true
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Invalid restriction type', $data['data']['message']);
}
/**
* Test service restriction without doctor_id
*/
public function test_service_restriction_without_doctor_id()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'service',
'target_id' => 888,
'is_blocked' => true
// Missing doctor_id for service restriction
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('doctor_id required for service restrictions', $data['data']['message']);
}
/**
* Test target not found in KiviCare
*/
public function test_target_not_found()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'doctor',
'target_id' => 99999, // Non-existent doctor
'is_blocked' => true
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Target not found', $data['data']['message']);
}
/**
* Test database error handling
*/
public function test_database_error_handling()
{
$this->set_current_user($this->admin_user_id);
// Mock database error
global $wpdb;
$original_prefix = $wpdb->prefix;
$wpdb->prefix = 'invalid_prefix_';
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
// Restore prefix
$wpdb->prefix = $original_prefix;
$data = json_decode($response, true);
$this->assert_ajax_response($data, false);
$this->assertEquals('Database error', $data['data']['message']);
}
/**
* Test response time performance requirement
*/
public function test_response_time_performance()
{
$this->set_current_user($this->admin_user_id);
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
];
$start_time = microtime(true);
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$end_time = microtime(true);
$response_time = ($end_time - $start_time) * 1000;
$this->assertLessThan(300, $response_time, 'Response time should be under 300ms according to contract');
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
}
/**
* Test cache invalidation after toggle
*/
public function test_cache_invalidation_after_toggle()
{
$this->set_current_user($this->admin_user_id);
// Set initial cache
set_transient('care_booking_doctors_blocked', [998], 3600);
$this->assertNotFalse(get_transient('care_booking_doctors_blocked'));
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Cache should be invalidated
$this->assertFalse(get_transient('care_booking_doctors_blocked'), 'Cache should be invalidated after toggle');
}
/**
* Test WordPress action triggered after successful toggle
*/
public function test_action_triggered_after_toggle()
{
$this->set_current_user($this->admin_user_id);
$action_fired = false;
$action_args = [];
// Hook to test action
add_action('care_booking_restriction_updated', function($type, $target_id, $doctor_id = null) use (&$action_fired, &$action_args) {
$action_fired = true;
$action_args = [$type, $target_id, $doctor_id];
}, 10, 3);
$_POST = [
'action' => 'care_booking_toggle_restriction',
'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'),
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
];
ob_start();
try {
do_action('wp_ajax_care_booking_toggle_restriction');
} catch (WPAjaxDieStopException $e) {}
$response = ob_get_clean();
$data = json_decode($response, true);
$this->assert_ajax_response($data, true);
// Action should have fired
$this->assertTrue($action_fired, 'care_booking_restriction_updated action should fire');
$this->assertEquals(['doctor', 999, null], $action_args, 'Action should receive correct arguments');
}
}

View File

@@ -0,0 +1,297 @@
/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php
/**
* WordPress cache integration tests for Care Booking Block plugin
*
* @package CareBookingBlock
*/
/**
* Test WordPress cache integration functionality
*/
class Test_Cache_Integration extends Care_Booking_Test_Case
{
/**
* Test cache manager class exists and can be instantiated
*/
public function test_cache_manager_class_exists()
{
$this->assertTrue(class_exists('Care_Booking_Cache_Manager'), 'Care_Booking_Cache_Manager class should exist');
$cache_manager = new Care_Booking_Cache_Manager();
$this->assertInstanceOf('Care_Booking_Cache_Manager', $cache_manager);
}
/**
* Test cache blocked doctors list
*/
public function test_cache_blocked_doctors()
{
$cache_manager = new Care_Booking_Cache_Manager();
$blocked_doctors = [999, 998, 997];
// Set cache
$result = $cache_manager->set_blocked_doctors($blocked_doctors);
$this->assertTrue($result, 'Should successfully cache blocked doctors');
// Get from cache
$cached_doctors = $cache_manager->get_blocked_doctors();
$this->assertIsArray($cached_doctors, 'Should return array from cache');
$this->assertEquals($blocked_doctors, $cached_doctors, 'Cached data should match original data');
// Verify WordPress transient was set
$transient_data = get_transient('care_booking_doctors_blocked');
$this->assertEquals($blocked_doctors, $transient_data, 'WordPress transient should contain correct data');
}
/**
* Test cache blocked services for doctor
*/
public function test_cache_blocked_services_by_doctor()
{
$cache_manager = new Care_Booking_Cache_Manager();
$doctor_id = 999;
$blocked_services = [888, 887, 886];
// Set cache
$result = $cache_manager->set_blocked_services($doctor_id, $blocked_services);
$this->assertTrue($result, 'Should successfully cache blocked services');
// Get from cache
$cached_services = $cache_manager->get_blocked_services($doctor_id);
$this->assertIsArray($cached_services);
$this->assertEquals($blocked_services, $cached_services);
// Verify WordPress transient was set with correct key
$transient_key = "care_booking_services_blocked_$doctor_id";
$transient_data = get_transient($transient_key);
$this->assertEquals($blocked_services, $transient_data);
}
/**
* Test cache expiration
*/
public function test_cache_expiration()
{
$cache_manager = new Care_Booking_Cache_Manager();
// Set short expiration for testing
$blocked_doctors = [999];
$result = $cache_manager->set_blocked_doctors($blocked_doctors, 1); // 1 second expiration
$this->assertTrue($result);
// Verify cache exists
$cached_data = $cache_manager->get_blocked_doctors();
$this->assertEquals($blocked_doctors, $cached_data);
// Wait for expiration
sleep(2);
// Verify cache expired
$expired_data = $cache_manager->get_blocked_doctors();
$this->assertFalse($expired_data, 'Cache should expire after timeout');
}
/**
* Test cache invalidation
*/
public function test_cache_invalidation()
{
$cache_manager = new Care_Booking_Cache_Manager();
// Set initial cache data
$cache_manager->set_blocked_doctors([999, 998]);
$cache_manager->set_blocked_services(999, [888, 887]);
$cache_manager->set_blocked_services(998, [886]);
// Verify cache exists
$this->assertNotFalse($cache_manager->get_blocked_doctors());
$this->assertNotFalse($cache_manager->get_blocked_services(999));
$this->assertNotFalse($cache_manager->get_blocked_services(998));
// Invalidate all cache
$result = $cache_manager->invalidate_all();
$this->assertTrue($result, 'Should successfully invalidate all cache');
// Verify cache was cleared
$this->assertFalse($cache_manager->get_blocked_doctors(), 'Blocked doctors cache should be cleared');
$this->assertFalse($cache_manager->get_blocked_services(999), 'Blocked services cache should be cleared');
$this->assertFalse($cache_manager->get_blocked_services(998), 'Blocked services cache should be cleared');
}
/**
* Test cache hash for change detection
*/
public function test_cache_hash_management()
{
$cache_manager = new Care_Booking_Cache_Manager();
// Set initial hash
$initial_hash = 'test_hash_123';
$result = $cache_manager->set_restrictions_hash($initial_hash);
$this->assertTrue($result);
// Get hash
$cached_hash = $cache_manager->get_restrictions_hash();
$this->assertEquals($initial_hash, $cached_hash);
// Update hash
$new_hash = 'test_hash_456';
$cache_manager->set_restrictions_hash($new_hash);
$updated_hash = $cache_manager->get_restrictions_hash();
$this->assertEquals($new_hash, $updated_hash);
$this->assertNotEquals($initial_hash, $updated_hash);
}
/**
* Test cache miss behavior
*/
public function test_cache_miss_behavior()
{
$cache_manager = new Care_Booking_Cache_Manager();
// Test getting non-existent cache
$non_existent_doctors = $cache_manager->get_blocked_doctors();
$this->assertFalse($non_existent_doctors, 'Should return false for cache miss');
$non_existent_services = $cache_manager->get_blocked_services(123);
$this->assertFalse($non_existent_services, 'Should return false for cache miss');
$non_existent_hash = $cache_manager->get_restrictions_hash();
$this->assertFalse($non_existent_hash, 'Should return false for cache miss');
}
/**
* Test cache key generation
*/
public function test_cache_key_generation()
{
$cache_manager = new Care_Booking_Cache_Manager();
// Test different doctor IDs generate different cache keys
$doctor1_services = [888];
$doctor2_services = [887];
$cache_manager->set_blocked_services(999, $doctor1_services);
$cache_manager->set_blocked_services(998, $doctor2_services);
// Verify separate caches
$cached_services_1 = $cache_manager->get_blocked_services(999);
$cached_services_2 = $cache_manager->get_blocked_services(998);
$this->assertEquals($doctor1_services, $cached_services_1);
$this->assertEquals($doctor2_services, $cached_services_2);
$this->assertNotEquals($cached_services_1, $cached_services_2);
}
/**
* Test cache size limits and memory usage
*/
public function test_cache_size_and_memory()
{
$cache_manager = new Care_Booking_Cache_Manager();
// Test caching large dataset
$large_doctor_list = range(1, 1000); // 1000 doctor IDs
$result = $cache_manager->set_blocked_doctors($large_doctor_list);
$this->assertTrue($result, 'Should handle large datasets');
$cached_large_list = $cache_manager->get_blocked_doctors();
$this->assertEquals($large_doctor_list, $cached_large_list, 'Large dataset should be cached correctly');
$this->assertCount(1000, $cached_large_list, 'All items should be cached');
}
/**
* Test cache with WordPress object cache compatibility
*/
public function test_wordpress_object_cache_compatibility()
{
$cache_manager = new Care_Booking_Cache_Manager();
// Test with WordPress wp_cache functions if available
if (function_exists('wp_cache_set') && function_exists('wp_cache_get')) {
$test_data = [999, 998];
// Use WordPress object cache directly
wp_cache_set('care_booking_test', $test_data, 'care_booking', 3600);
$wp_cached_data = wp_cache_get('care_booking_test', 'care_booking');
$this->assertEquals($test_data, $wp_cached_data, 'WordPress object cache should work with plugin data');
} else {
$this->markTestSkipped('WordPress object cache not available in test environment');
}
}
/**
* Test cache performance benchmarks
*/
public function test_cache_performance()
{
$cache_manager = new Care_Booking_Cache_Manager();
$test_data = range(1, 100);
// Measure cache write performance
$start_time = microtime(true);
$cache_manager->set_blocked_doctors($test_data);
$write_time = microtime(true) - $start_time;
$this->assertLessThan(0.1, $write_time, 'Cache write should complete in under 100ms');
// Measure cache read performance
$start_time = microtime(true);
$cached_data = $cache_manager->get_blocked_doctors();
$read_time = microtime(true) - $start_time;
$this->assertLessThan(0.05, $read_time, 'Cache read should complete in under 50ms');
$this->assertEquals($test_data, $cached_data);
}
/**
* Test cache invalidation on restriction changes
*/
public function test_cache_invalidation_on_changes()
{
$cache_manager = new Care_Booking_Cache_Manager();
// Set initial cache
$cache_manager->set_blocked_doctors([999]);
$cache_manager->set_blocked_services(999, [888]);
// Verify cache exists
$this->assertNotFalse($cache_manager->get_blocked_doctors());
$this->assertNotFalse($cache_manager->get_blocked_services(999));
// Simulate restriction change event
do_action('care_booking_restriction_updated', 'doctor', 999);
// Cache should be automatically invalidated
$this->assertFalse($cache_manager->get_blocked_doctors(), 'Cache should be invalidated on restriction change');
}
/**
* Test cache with concurrent access
*/
public function test_concurrent_cache_access()
{
$cache_manager = new Care_Booking_Cache_Manager();
// Simulate concurrent writes (in real scenario this would be multiple requests)
$cache_manager->set_blocked_doctors([999]);
$cache_manager->set_blocked_doctors([998]);
$cache_manager->set_blocked_doctors([997]);
// Last write should win
$final_data = $cache_manager->get_blocked_doctors();
$this->assertEquals([997], $final_data, 'Last cache write should be preserved');
}
}

View File

@@ -0,0 +1,287 @@
/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php
/**
* Database schema tests for Care Booking Block plugin
*
* @package CareBookingBlock
*/
/**
* Test database schema creation and structure
*/
class Test_Database_Schema extends Care_Booking_Test_Case
{
/**
* Test that wp_care_booking_restrictions table exists
*/
public function test_restrictions_table_exists()
{
global $wpdb;
$table_name = $wpdb->prefix . 'care_booking_restrictions';
$table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
$this->assertTrue($table_exists, 'wp_care_booking_restrictions table should exist');
}
/**
* Test table has required columns with correct types
*/
public function test_table_has_correct_columns()
{
global $wpdb;
$table_name = $wpdb->prefix . 'care_booking_restrictions';
$columns = $wpdb->get_results("DESCRIBE $table_name");
// Convert to associative array for easier testing
$column_data = [];
foreach ($columns as $column) {
$column_data[$column->Field] = [
'Type' => $column->Type,
'Null' => $column->Null,
'Key' => $column->Key,
'Default' => $column->Default,
'Extra' => $column->Extra
];
}
// Test required columns exist
$expected_columns = ['id', 'restriction_type', 'target_id', 'doctor_id', 'is_blocked', 'created_at', 'updated_at'];
foreach ($expected_columns as $column) {
$this->assertArrayHasKey($column, $column_data, "Column '$column' should exist");
}
// Test column types
$this->assertEquals('bigint(20) unsigned', $column_data['id']['Type']);
$this->assertEquals("enum('doctor','service')", $column_data['restriction_type']['Type']);
$this->assertEquals('bigint(20) unsigned', $column_data['target_id']['Type']);
$this->assertEquals('bigint(20) unsigned', $column_data['doctor_id']['Type']);
$this->assertEquals('tinyint(1)', $column_data['is_blocked']['Type']);
$this->assertEquals('timestamp', $column_data['created_at']['Type']);
$this->assertEquals('timestamp', $column_data['updated_at']['Type']);
// Test primary key
$this->assertEquals('PRI', $column_data['id']['Key']);
$this->assertEquals('auto_increment', $column_data['id']['Extra']);
// Test null constraints
$this->assertEquals('NO', $column_data['id']['Null']);
$this->assertEquals('NO', $column_data['restriction_type']['Null']);
$this->assertEquals('NO', $column_data['target_id']['Null']);
$this->assertEquals('YES', $column_data['doctor_id']['Null']);
$this->assertEquals('NO', $column_data['is_blocked']['Null']);
// Test default values
$this->assertEquals('0', $column_data['is_blocked']['Default']);
$this->assertEquals('current_timestamp()', $column_data['created_at']['Default']);
}
/**
* Test table has required indexes
*/
public function test_table_has_required_indexes()
{
global $wpdb;
$table_name = $wpdb->prefix . 'care_booking_restrictions';
$indexes = $wpdb->get_results("SHOW INDEX FROM $table_name");
// Convert to associative array for easier testing
$index_data = [];
foreach ($indexes as $index) {
$index_data[$index->Key_name][] = $index->Column_name;
}
// Test required indexes exist
$this->assertArrayHasKey('PRIMARY', $index_data, 'PRIMARY index should exist');
$this->assertArrayHasKey('idx_type_target', $index_data, 'idx_type_target index should exist');
$this->assertArrayHasKey('idx_doctor_service', $index_data, 'idx_doctor_service index should exist');
$this->assertArrayHasKey('idx_blocked', $index_data, 'idx_blocked index should exist');
// Test index columns
$this->assertEquals(['id'], $index_data['PRIMARY']);
$this->assertEquals(['restriction_type', 'target_id'], $index_data['idx_type_target']);
$this->assertEquals(['doctor_id', 'target_id'], $index_data['idx_doctor_service']);
$this->assertEquals(['is_blocked'], $index_data['idx_blocked']);
}
/**
* Test enum constraint on restriction_type
*/
public function test_restriction_type_enum_constraint()
{
global $wpdb;
$table_name = $wpdb->prefix . 'care_booking_restrictions';
// Test valid enum values
$valid_insert = $wpdb->insert(
$table_name,
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => 1
]
);
$this->assertNotFalse($valid_insert, 'Should insert valid restriction_type');
// Clean up
$wpdb->delete($table_name, ['target_id' => 999]);
// Test invalid enum values (this should fail)
$invalid_insert = $wpdb->insert(
$table_name,
[
'restriction_type' => 'invalid_type',
'target_id' => 999,
'is_blocked' => 1
]
);
$this->assertFalse($invalid_insert, 'Should not insert invalid restriction_type');
}
/**
* Test auto-increment behavior on id field
*/
public function test_auto_increment_id_field()
{
global $wpdb;
$table_name = $wpdb->prefix . 'care_booking_restrictions';
// Insert first record
$result1 = $wpdb->insert(
$table_name,
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => 1
]
);
$this->assertNotFalse($result1);
$id1 = $wpdb->insert_id;
// Insert second record
$result2 = $wpdb->insert(
$table_name,
[
'restriction_type' => 'service',
'target_id' => 998,
'doctor_id' => 999,
'is_blocked' => 1
]
);
$this->assertNotFalse($result2);
$id2 = $wpdb->insert_id;
// Test auto-increment
$this->assertGreaterThan($id1, $id2, 'Second ID should be greater than first');
// Clean up
$wpdb->delete($table_name, ['target_id' => 999]);
$wpdb->delete($table_name, ['target_id' => 998]);
}
/**
* Test timestamp fields behavior
*/
public function test_timestamp_fields()
{
global $wpdb;
$table_name = $wpdb->prefix . 'care_booking_restrictions';
// Insert record and check timestamps
$before_insert = current_time('mysql');
$result = $wpdb->insert(
$table_name,
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => 1
]
);
$this->assertNotFalse($result);
$after_insert = current_time('mysql');
// Get the inserted record
$record = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE target_id = %d", 999));
$this->assertNotNull($record);
// Test created_at is set automatically
$this->assertNotNull($record->created_at);
$this->assertGreaterThanOrEqual($before_insert, $record->created_at);
$this->assertLessThanOrEqual($after_insert, $record->created_at);
// Test updated_at matches created_at on insert
$this->assertEquals($record->created_at, $record->updated_at);
// Wait a moment and update record
sleep(1);
$before_update = current_time('mysql');
$wpdb->update(
$table_name,
['is_blocked' => 0],
['target_id' => 999]
);
$after_update = current_time('mysql');
// Get updated record
$updated_record = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE target_id = %d", 999));
// Test updated_at changed automatically
$this->assertNotEquals($record->updated_at, $updated_record->updated_at);
$this->assertGreaterThanOrEqual($before_update, $updated_record->updated_at);
$this->assertLessThanOrEqual($after_update, $updated_record->updated_at);
// Test created_at remained unchanged
$this->assertEquals($record->created_at, $updated_record->created_at);
// Clean up
$wpdb->delete($table_name, ['target_id' => 999]);
}
/**
* Test database table cleanup on plugin deactivation
*/
public function test_plugin_deactivation_preserves_data()
{
global $wpdb;
$table_name = $wpdb->prefix . 'care_booking_restrictions';
// Insert test data
$wpdb->insert(
$table_name,
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => 1
]
);
// Simulate plugin deactivation
$plugin = CareBookingBlock::get_instance();
$plugin->deactivate();
// Check that table and data still exist
$table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
$this->assertTrue($table_exists, 'Table should still exist after deactivation');
$record_exists = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table_name WHERE target_id = %d", 999));
$this->assertEquals('1', $record_exists, 'Data should be preserved after deactivation');
// Clean up
$wpdb->delete($table_name, ['target_id' => 999]);
}
}

View File

@@ -0,0 +1,351 @@
/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php
/**
* Restriction model CRUD tests for Care Booking Block plugin
*
* @package CareBookingBlock
*/
/**
* Test restriction model CRUD operations
*/
class Test_Restriction_Model extends Care_Booking_Test_Case
{
/**
* Test restriction model class exists and can be instantiated
*/
public function test_restriction_model_class_exists()
{
$this->assertTrue(class_exists('Care_Booking_Restriction_Model'), 'Care_Booking_Restriction_Model class should exist');
$model = new Care_Booking_Restriction_Model();
$this->assertInstanceOf('Care_Booking_Restriction_Model', $model);
}
/**
* Test create doctor restriction
*/
public function test_create_doctor_restriction()
{
$model = new Care_Booking_Restriction_Model();
$restriction_data = [
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
];
$restriction_id = $model->create($restriction_data);
$this->assertIsInt($restriction_id, 'Should return integer restriction ID');
$this->assertGreaterThan(0, $restriction_id, 'Restriction ID should be greater than 0');
// Verify restriction was created in database
$created_restriction = $model->get($restriction_id);
$this->assertNotFalse($created_restriction, 'Should retrieve created restriction');
$this->assertEquals('doctor', $created_restriction->restriction_type);
$this->assertEquals(999, $created_restriction->target_id);
$this->assertNull($created_restriction->doctor_id);
$this->assertEquals(1, $created_restriction->is_blocked);
}
/**
* Test create service restriction
*/
public function test_create_service_restriction()
{
$model = new Care_Booking_Restriction_Model();
$restriction_data = [
'restriction_type' => 'service',
'target_id' => 888,
'doctor_id' => 999,
'is_blocked' => true
];
$restriction_id = $model->create($restriction_data);
$this->assertIsInt($restriction_id);
$this->assertGreaterThan(0, $restriction_id);
// Verify restriction was created
$created_restriction = $model->get($restriction_id);
$this->assertEquals('service', $created_restriction->restriction_type);
$this->assertEquals(888, $created_restriction->target_id);
$this->assertEquals(999, $created_restriction->doctor_id);
$this->assertEquals(1, $created_restriction->is_blocked);
}
/**
* Test read restriction by ID
*/
public function test_read_restriction_by_id()
{
$model = new Care_Booking_Restriction_Model();
// Create test restriction
$restriction_id = $this->create_test_doctor_restriction(999, true);
$this->assertNotFalse($restriction_id);
// Read restriction
$restriction = $model->get($restriction_id);
$this->assertNotFalse($restriction, 'Should retrieve restriction by ID');
$this->assertEquals($restriction_id, $restriction->id);
$this->assertEquals('doctor', $restriction->restriction_type);
$this->assertEquals(999, $restriction->target_id);
}
/**
* Test get restrictions by type
*/
public function test_get_restrictions_by_type()
{
$model = new Care_Booking_Restriction_Model();
// Create test restrictions
$this->create_test_doctor_restriction(999, true);
$this->create_test_doctor_restriction(998, false);
$this->create_test_service_restriction(888, 999, true);
// Get doctor restrictions
$doctor_restrictions = $model->get_by_type('doctor');
$this->assertIsArray($doctor_restrictions, 'Should return array of doctor restrictions');
$this->assertCount(2, $doctor_restrictions, 'Should return 2 doctor restrictions');
// Verify all are doctor type
foreach ($doctor_restrictions as $restriction) {
$this->assertEquals('doctor', $restriction->restriction_type);
}
// Get service restrictions
$service_restrictions = $model->get_by_type('service');
$this->assertIsArray($service_restrictions);
$this->assertCount(1, $service_restrictions, 'Should return 1 service restriction');
$this->assertEquals('service', $service_restrictions[0]->restriction_type);
}
/**
* Test get blocked doctors
*/
public function test_get_blocked_doctors()
{
$model = new Care_Booking_Restriction_Model();
// Create test restrictions
$this->create_test_doctor_restriction(999, true); // Blocked
$this->create_test_doctor_restriction(998, false); // Not blocked
$this->create_test_doctor_restriction(997, true); // Blocked
$blocked_doctors = $model->get_blocked_doctors();
$this->assertIsArray($blocked_doctors, 'Should return array of blocked doctor IDs');
$this->assertCount(2, $blocked_doctors, 'Should return 2 blocked doctors');
// Check that correct doctors are blocked
$this->assertContains(999, $blocked_doctors);
$this->assertContains(997, $blocked_doctors);
$this->assertNotContains(998, $blocked_doctors, 'Non-blocked doctor should not be in list');
}
/**
* Test get blocked services for specific doctor
*/
public function test_get_blocked_services_by_doctor()
{
$model = new Care_Booking_Restriction_Model();
// Create test service restrictions for doctor 999
$this->create_test_service_restriction(888, 999, true); // Blocked
$this->create_test_service_restriction(887, 999, false); // Not blocked
$this->create_test_service_restriction(886, 998, true); // Different doctor
$blocked_services = $model->get_blocked_services(999);
$this->assertIsArray($blocked_services);
$this->assertCount(1, $blocked_services, 'Should return 1 blocked service for doctor 999');
$this->assertContains(888, $blocked_services);
$this->assertNotContains(887, $blocked_services, 'Non-blocked service should not be in list');
$this->assertNotContains(886, $blocked_services, 'Service for different doctor should not be in list');
}
/**
* Test update restriction
*/
public function test_update_restriction()
{
$model = new Care_Booking_Restriction_Model();
// Create test restriction
$restriction_id = $this->create_test_doctor_restriction(999, true);
// Update restriction
$update_data = ['is_blocked' => false];
$result = $model->update($restriction_id, $update_data);
$this->assertTrue($result, 'Update should return true on success');
// Verify update
$updated_restriction = $model->get($restriction_id);
$this->assertEquals(0, $updated_restriction->is_blocked, 'is_blocked should be updated to false');
// Verify updated_at timestamp changed
$this->assertNotNull($updated_restriction->updated_at);
}
/**
* Test delete restriction
*/
public function test_delete_restriction()
{
$model = new Care_Booking_Restriction_Model();
// Create test restriction
$restriction_id = $this->create_test_doctor_restriction(999, true);
// Verify restriction exists
$restriction = $model->get($restriction_id);
$this->assertNotFalse($restriction);
// Delete restriction
$result = $model->delete($restriction_id);
$this->assertTrue($result, 'Delete should return true on success');
// Verify restriction no longer exists
$deleted_restriction = $model->get($restriction_id);
$this->assertFalse($deleted_restriction, 'Restriction should not exist after deletion');
}
/**
* Test find existing restriction
*/
public function test_find_existing_restriction()
{
$model = new Care_Booking_Restriction_Model();
// Create doctor restriction
$doctor_restriction_id = $this->create_test_doctor_restriction(999, true);
// Find existing doctor restriction
$found_doctor = $model->find_existing('doctor', 999);
$this->assertNotFalse($found_doctor, 'Should find existing doctor restriction');
$this->assertEquals($doctor_restriction_id, $found_doctor->id);
// Create service restriction
$service_restriction_id = $this->create_test_service_restriction(888, 999, true);
// Find existing service restriction
$found_service = $model->find_existing('service', 888, 999);
$this->assertNotFalse($found_service, 'Should find existing service restriction');
$this->assertEquals($service_restriction_id, $found_service->id);
// Try to find non-existing restriction
$not_found = $model->find_existing('doctor', 123);
$this->assertFalse($not_found, 'Should return false for non-existing restriction');
}
/**
* Test toggle restriction (create or update)
*/
public function test_toggle_restriction()
{
$model = new Care_Booking_Restriction_Model();
// Toggle non-existing restriction (should create)
$result = $model->toggle('doctor', 999, null, true);
$this->assertIsInt($result, 'Should return restriction ID when creating');
// Verify restriction was created
$restriction = $model->find_existing('doctor', 999);
$this->assertNotFalse($restriction);
$this->assertEquals(1, $restriction->is_blocked);
// Toggle existing restriction (should update)
$result2 = $model->toggle('doctor', 999, null, false);
$this->assertTrue($result2, 'Should return true when updating existing');
// Verify restriction was updated
$updated_restriction = $model->find_existing('doctor', 999);
$this->assertEquals(0, $updated_restriction->is_blocked);
}
/**
* Test validation errors
*/
public function test_validation_errors()
{
$model = new Care_Booking_Restriction_Model();
// Test invalid restriction type
$invalid_data = [
'restriction_type' => 'invalid',
'target_id' => 999,
'is_blocked' => true
];
$result = $model->create($invalid_data);
$this->assertFalse($result, 'Should return false for invalid restriction type');
// Test missing target_id
$invalid_data2 = [
'restriction_type' => 'doctor',
'is_blocked' => true
];
$result2 = $model->create($invalid_data2);
$this->assertFalse($result2, 'Should return false for missing target_id');
// Test service restriction without doctor_id
$invalid_data3 = [
'restriction_type' => 'service',
'target_id' => 888,
'is_blocked' => true
];
$result3 = $model->create($invalid_data3);
$this->assertFalse($result3, 'Should return false for service restriction without doctor_id');
}
/**
* Test bulk operations
*/
public function test_bulk_operations()
{
$model = new Care_Booking_Restriction_Model();
$bulk_data = [
[
'restriction_type' => 'doctor',
'target_id' => 999,
'is_blocked' => true
],
[
'restriction_type' => 'doctor',
'target_id' => 998,
'is_blocked' => true
],
[
'restriction_type' => 'service',
'target_id' => 888,
'doctor_id' => 999,
'is_blocked' => false
]
];
$results = $model->bulk_create($bulk_data);
$this->assertIsArray($results, 'Should return array of results');
$this->assertCount(3, $results, 'Should return 3 results');
// Verify all were created successfully
foreach ($results as $result) {
$this->assertIsInt($result, 'Each result should be a restriction ID');
$this->assertGreaterThan(0, $result);
}
// Verify restrictions exist
$doctor_restrictions = $model->get_by_type('doctor');
$this->assertCount(2, $doctor_restrictions);
$service_restrictions = $model->get_by_type('service');
$this->assertCount(1, $service_restrictions);
}
}