code = $code; $this->message = $message; $this->data = (array) $data; } public function get_error_code(): string { return $this->code; } public function get_error_message(): string { return $this->message; } public function get_error_data() { return $this->data; } } } require_once dirname( __DIR__, 3 ) . '/includes/class-tmdo-logger.php'; require_once dirname( __DIR__, 3 ) . '/includes/diagnostic/class-tmdo-health-cron.php'; /** * Unit tests for WPDO_Health_Cron (v2.3.0 M6). * * Pure-logic tests — does not exercise actual cron firing or full Site Health * subprocess (those covered by integration suite). Asserts on output shape + * counter aggregation + alert flag setting. */ class HealthCronTest extends TestCase { protected function setUp(): void { $GLOBALS['_wp_options'] = array(); $this->setup_wpdb_mock(); } private function setup_wpdb_mock(): void { global $wpdb; $wpdb = new class { public string $prefix = 'wp_'; public string $options = 'wp_options'; // v2.5.0:Module_Detector reads $wpdb->posts during Health_Cron // integration; declared here to silence undefined-property warning. public string $posts = 'wp_posts'; public string $postmeta = 'wp_postmeta'; public function prepare( string $sql, ...$args ): string { $i = 0; return preg_replace_callback( '/%[sd]/', function() use ( &$i, $args ) { return (string) ( $args[ $i++ ] ?? '?' ); }, $sql ); } public function get_var( string $sql ) { $upper = strtoupper( $sql ); // Table-existence probes → truthy so schema_drift / orphan_zone passes. if ( str_contains( $upper, 'SHOW TABLES' ) || str_contains( $upper, 'INFORMATION_SCHEMA' ) ) { return '1'; } return '0'; } public function get_results( string $sql, $output = ARRAY_A ): array { return array(); } public function query( string $sql ): int { return 0; } public function insert( string $table, array $data ): int { return 1; } }; } public function test_get_last_run_returns_null_when_never_run(): void { $this->assertNull( WPDO_Health_Cron::get_last_run() ); } public function test_run_returns_summary_shape(): void { $result = WPDO_Health_Cron::run(); $this->assertTrue( $result['ok'] ); $this->assertArrayHasKey( 'summary', $result ); $this->assertArrayHasKey( 'critical_count', $result ); $this->assertArrayHasKey( 'recommended_count', $result ); $this->assertArrayHasKey( 'ts', $result ); $this->assertArrayHasKey( 'tests', $result['summary'] ); $this->assertArrayHasKey( 'conflicts', $result['summary'] ); $this->assertArrayHasKey( 'shadow_diffs', $result['summary'] ); $this->assertArrayHasKey( 'autoload_bytes', $result['summary'] ); $this->assertArrayHasKey( 'duration_ms', $result['summary'] ); } public function test_run_persists_last_run_option(): void { WPDO_Health_Cron::run(); $last = WPDO_Health_Cron::get_last_run(); $this->assertIsArray( $last ); $this->assertArrayHasKey( 'tests', $last ); $this->assertArrayHasKey( 'critical_count', $last ); } public function test_run_clears_alert_when_no_critical(): void { // Pre-set an alert. update_option( WPDO_Health_Cron::OPTION_ALERT, array( 'level' => 'critical' ), false ); WPDO_Health_Cron::run(); $this->assertFalse( get_option( WPDO_Health_Cron::OPTION_ALERT ), 'alert should be cleared on green run' ); } public function test_consecutive_green_days_zero_when_no_run(): void { $this->assertSame( 0, WPDO_Health_Cron::consecutive_green_days() ); } public function test_consecutive_green_days_one_after_green_run(): void { WPDO_Health_Cron::run(); $this->assertSame( 1, WPDO_Health_Cron::consecutive_green_days() ); } public function test_option_keys_are_documented(): void { $this->assertSame( 'wpdo_health_last_run', WPDO_Health_Cron::OPTION_LAST_RUN ); $this->assertSame( 'wpdo_health_alert', WPDO_Health_Cron::OPTION_ALERT ); } }