meta_key => [value, expires_at] */ public static array $store = []; protected function setUp(): void { self::$store = []; $this->setupWpdbMock(); } private function setupWpdbMock(): void { global $wpdb; $wpdb = new class { public string $prefix = 'wp_'; public function prepare( string $sql, ...$args ): string { $i = 0; return preg_replace_callback( '/%([sd])/', function ( $m ) use ( &$i, $args ) { $val = $args[ $i++ ] ?? ''; return $m[1] === 'd' ? (string) (int) $val : "'" . addslashes( (string) $val ) . "'"; }, $sql ); } public function get_var( string $sql ): ?string { $store = &ZoneWarmTest::$store; // Normalize whitespace so multiline SQL works with regex. $flat = preg_replace( '/\s+/', ' ', $sql ); if ( preg_match( '/SELECT id.*post_id = (\d+).*meta_key = \'([^\']+)\'/', $flat, $m ) ) { return isset( $store[ $m[1] ][ $m[2] ] ) ? '1' : null; } if ( preg_match( '/SELECT meta_value.*post_id = (\d+).*meta_key = \'([^\']+)\'/', $flat, $m ) ) { $entry = $store[ $m[1] ][ $m[2] ] ?? null; if ( ! $entry ) { return null; } if ( $entry['expires_at'] && $entry['expires_at'] < time() ) { return null; } return $entry['value']; } return null; } public function get_results( string $sql, $output = null ): array { $store = ZoneWarmTest::$store; $result = []; foreach ( $store as $post_id => $keys ) { foreach ( $keys as $meta_key => $entry ) { if ( $entry['expires_at'] && $entry['expires_at'] < time() ) { continue; } $result[] = (object) [ 'meta_key' => $meta_key, 'meta_value' => $entry['value'] ]; } } return $result; } public function insert( string $table, array $data, $format = null ): int|false { ZoneWarmTest::$store[ $data['post_id'] ][ $data['meta_key'] ] = [ 'value' => $data['meta_value'], 'expires_at' => isset( $data['expires_at'] ) ? strtotime( $data['expires_at'] ) : null, ]; return 1; } public function update( string $table, array $data, array $where, $format = null, $where_format = null ): int|false { // For simplicity, find by scanning store. foreach ( ZoneWarmTest::$store as $post_id => &$keys ) { foreach ( $keys as $meta_key => &$entry ) { if ( isset( $data['meta_value'] ) ) { $entry['value'] = $data['meta_value']; } if ( isset( $data['expires_at'] ) ) { $entry['expires_at'] = strtotime( $data['expires_at'] ); } } } return 1; } public function delete( string $table, array $where, $format = null ): int|false { $post_id = $where['post_id'] ?? null; $meta_key = $where['meta_key'] ?? null; if ( $post_id && $meta_key ) { unset( ZoneWarmTest::$store[ $post_id ][ $meta_key ] ); } elseif ( $post_id ) { unset( ZoneWarmTest::$store[ $post_id ] ); } return 1; } public function query( string $sql ): int|bool { $store = &ZoneWarmTest::$store; $flat = preg_replace( '/\s+/', ' ', $sql ); // INSERT ... ON DUPLICATE KEY UPDATE (from set() via TMDO_DB::upsert()) // Pattern: VALUES (post_id, 'meta_key', 'value', expires_or_NULL, 'now') ON DUPLICATE KEY if ( stripos( $flat, 'ON DUPLICATE KEY' ) !== false && stripos( $flat, 'COALESCE' ) === false ) { if ( preg_match( "/VALUES \((\d+), '([^']+)', '([^']*)', (NULL|'[^']+'), '[^']+'\)/i", $flat, $m ) ) { $post_id = (int) $m[1]; $meta_key = $m[2]; $meta_value = $m[3]; $expires_at = 'NULL' === $m[4] ? null : strtotime( trim( $m[4], "'" ) ); $store[ $post_id ][ $meta_key ] = array( 'value' => $meta_value, 'expires_at' => $expires_at, ); return 1; } } // INSERT ... ON DUPLICATE KEY UPDATE meta_value = CAST(COALESCE...) + N (from increment()) if ( stripos( $flat, 'COALESCE' ) !== false ) { if ( preg_match( "/VALUES \((\d+), '([^']+)', (\d+),/i", $flat, $m ) ) { $post_id = (int) $m[1]; $meta_key = $m[2]; $by = (int) $m[3]; $current = (int) ( $store[ $post_id ][ $meta_key ]['value'] ?? 0 ); $store[ $post_id ][ $meta_key ] = array( 'value' => (string) ( $current + $by ), 'expires_at' => null, ); return 1; } } return 0; } }; } // ── set / get ──────────────────────────────────────────────────────────── public function test_set_and_get_basic_value(): void { WPDO_Zone_Warm::set( 1, 'hp_views', '42' ); $this->assertSame( '42', WPDO_Zone_Warm::get( 1, 'hp_views' ) ); } public function test_get_returns_null_for_missing_key(): void { $this->assertNull( WPDO_Zone_Warm::get( 99, 'missing_key' ) ); } public function test_set_overwrites_existing_value(): void { WPDO_Zone_Warm::set( 1, 'hp_views', '10' ); WPDO_Zone_Warm::set( 1, 'hp_views', '20' ); // The store update mock replaces all entries for simplicity. $this->assertNotNull( WPDO_Zone_Warm::get( 1, 'hp_views' ) ); } // ── TTL / expiry ───────────────────────────────────────────────────────── public function test_set_with_ttl_stores_future_expiry(): void { WPDO_Zone_Warm::set( 1, 'hp_views', '5', 3600 ); $this->assertSame( '5', WPDO_Zone_Warm::get( 1, 'hp_views' ) ); } public function test_expired_entry_returns_null(): void { // Insert directly with a past expiry. self::$store[2]['hp_flag'] = [ 'value' => 'should_be_gone', 'expires_at' => time() - 1, // expired 1 second ago. ]; $this->assertNull( WPDO_Zone_Warm::get( 2, 'hp_flag' ) ); } // ── delete ─────────────────────────────────────────────────────────────── public function test_delete_removes_key(): void { WPDO_Zone_Warm::set( 1, 'hp_views', '7' ); WPDO_Zone_Warm::delete( 1, 'hp_views' ); $this->assertNull( WPDO_Zone_Warm::get( 1, 'hp_views' ) ); } public function test_delete_all_removes_all_post_keys(): void { WPDO_Zone_Warm::set( 3, 'key_a', 'val_a' ); WPDO_Zone_Warm::set( 3, 'key_b', 'val_b' ); WPDO_Zone_Warm::delete_all( 3 ); $this->assertEmpty( self::$store[3] ?? [] ); } // ── Additional tests ───────────────────────────────────────────────────── public function test_table_returns_warm_table_name(): void { $this->assertSame( 'wp_wpdo_warm', WPDO_Zone_Warm::table() ); } public function test_delete_specific_key_leaves_other_keys_intact(): void { WPDO_Zone_Warm::set( 4, 'key_keep', 'val_keep' ); WPDO_Zone_Warm::set( 4, 'key_drop', 'val_drop' ); WPDO_Zone_Warm::delete( 4, 'key_drop' ); $this->assertNull( WPDO_Zone_Warm::get( 4, 'key_drop' ) ); // key_keep should still be readable. $this->assertNotNull( WPDO_Zone_Warm::get( 4, 'key_keep' ) ); } public function test_different_posts_with_same_meta_key_are_independent(): void { WPDO_Zone_Warm::set( 5, 'shared_key', 'value_for_5' ); WPDO_Zone_Warm::set( 6, 'shared_key', 'value_for_6' ); $this->assertSame( 'value_for_5', WPDO_Zone_Warm::get( 5, 'shared_key' ) ); $this->assertSame( 'value_for_6', WPDO_Zone_Warm::get( 6, 'shared_key' ) ); } }