insert() calls. */ public static array $store = []; /** Arguments of the last $wpdb->delete() call. */ public static array $last_delete = []; protected function setUp(): void { self::$store = []; self::$last_delete = []; $GLOBALS['_wp_postmeta'] = []; $this->setup_wpdb_mock(); } private function setup_wpdb_mock(): 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 insert( string $table, array $data, $format = null ): int|false { ZoneArchiveTest::$store[] = $data; return 1; } public function delete( string $table, array $where, $format = null ): int|false { ZoneArchiveTest::$last_delete = [ 'table' => $table, 'where' => $where ]; // Remove matching rows (single-column where only). ZoneArchiveTest::$store = array_values( array_filter( ZoneArchiveTest::$store, static function ( array $row ) use ( $where ): bool { foreach ( $where as $col => $val ) { if ( isset( $row[ $col ] ) && (string) $row[ $col ] === (string) $val ) { return false; // row matches → remove. } } return true; } ) ); return 1; } public function get_results( string $sql, $output = OBJECT ): array { $flat = preg_replace( '/\s+/', ' ', $sql ); // stats() GROUP BY post_type query. if ( stripos( $flat, 'GROUP BY post_type' ) !== false ) { $by_type = []; foreach ( ZoneArchiveTest::$store as $row ) { $pt = $row['post_type'] ?? 'unknown'; $by_type[ $pt ] = ( $by_type[ $pt ] ?? 0 ) + 1; } $result = []; foreach ( $by_type as $pt => $cnt ) { $result[] = [ 'post_type' => $pt, 'cnt' => (string) $cnt ]; } return $result; } // get() queries — filter by post_id and optional meta_key. $post_id = null; $meta_key = null; if ( preg_match( '/post_id = (\d+)/', $flat, $m ) ) { $post_id = (int) $m[1]; } if ( preg_match( "/AND meta_key = '([^']+)'/", $flat, $m ) ) { $meta_key = $m[1]; } $result = []; foreach ( ZoneArchiveTest::$store as $row ) { if ( $post_id !== null && (int) ( $row['post_id'] ?? 0 ) !== $post_id ) { continue; } if ( $meta_key !== null && ( $row['meta_key'] ?? '' ) !== $meta_key ) { continue; } $result[] = [ 'meta_key' => $row['meta_key'] ?? '', 'meta_value' => $row['meta_value'] ?? '', 'compressed' => $row['compressed'] ?? 0, 'archived_at' => $row['archived_at'] ?? '', ]; } return $result; } public function get_var( string $sql ): ?string { $flat = preg_replace( '/\s+/', ' ', $sql ); if ( stripos( $flat, 'WHERE compressed = 1' ) !== false ) { $count = count( array_filter( ZoneArchiveTest::$store, static fn( array $r ) => (int) ( $r['compressed'] ?? 0 ) === 1 ) ); return (string) $count; } if ( stripos( $flat, 'COUNT(*)' ) !== false ) { return (string) count( ZoneArchiveTest::$store ); } return null; } public function query( string $sql ): int|bool { return 1; // BEGIN, COMMIT, ROLLBACK pass-through. } }; } // ── table() ────────────────────────────────────────────────────────────── public function test_table_returns_archive_table_name(): void { $this->assertSame( 'wp_wpdo_archive', WPDO_Zone_Archive::table() ); } // ── archive() ──────────────────────────────────────────────────────────── public function test_archive_inserts_row_with_correct_fields(): void { WPDO_Zone_Archive::archive( 1, 'hp_listing', 'hp_price', '99.99' ); $this->assertCount( 1, self::$store ); $row = self::$store[0]; $this->assertSame( 1, $row['post_id'] ); $this->assertSame( 'hp_listing', $row['post_type'] ); $this->assertSame( 'hp_price', $row['meta_key'] ); $this->assertSame( '99.99', $row['meta_value'] ); } public function test_archive_without_compress_keeps_plaintext_value(): void { WPDO_Zone_Archive::archive( 2, 'hp_listing', 'hp_price', 'plain_value', 0, false ); $this->assertSame( 'plain_value', self::$store[0]['meta_value'] ); $this->assertSame( 0, self::$store[0]['compressed'] ); } public function test_archive_with_compress_sets_compressed_flag(): void { WPDO_Zone_Archive::archive( 3, 'hp_listing', 'hp_price', 'compress_me', 0, true ); $this->assertSame( 1, self::$store[0]['compressed'] ); } public function test_archive_with_compress_stores_base64_encoded_gzip(): void { $original = 'hello compressed world'; WPDO_Zone_Archive::archive( 4, 'hp_listing', 'hp_bio', $original, 0, true ); $stored = self::$store[0]['meta_value']; $decoded = base64_decode( $stored, true ); $restored = gzdecode( $decoded ); $this->assertSame( $original, $restored ); } public function test_archive_stores_original_meta_id(): void { WPDO_Zone_Archive::archive( 5, 'hp_listing', 'hp_price', '10', 42 ); $this->assertSame( 42, self::$store[0]['original_meta_id'] ); } // ── archive_batch() ────────────────────────────────────────────────────── public function test_archive_batch_inserts_all_entries(): void { WPDO_Zone_Archive::archive_batch( [ [ 'post_id' => 10, 'post_type' => 'hp_listing', 'meta_key' => 'hp_price', 'meta_value' => '100', 'meta_id' => 0 ], [ 'post_id' => 11, 'post_type' => 'hp_listing', 'meta_key' => 'hp_price', 'meta_value' => '200', 'meta_id' => 0 ], [ 'post_id' => 12, 'post_type' => 'hp_listing', 'meta_key' => 'hp_price', 'meta_value' => '300', 'meta_id' => 0 ], ] ); $this->assertCount( 3, self::$store ); } public function test_archive_batch_with_empty_entries_is_safe(): void { WPDO_Zone_Archive::archive_batch( [] ); $this->assertCount( 0, self::$store ); } // ── get() ───────────────────────────────────────────────────────────────── public function test_get_returns_empty_array_for_missing_post(): void { $result = WPDO_Zone_Archive::get( 999 ); $this->assertSame( [], $result ); } public function test_get_returns_all_entries_for_post(): void { WPDO_Zone_Archive::archive( 20, 'hp_listing', 'hp_price', '50' ); WPDO_Zone_Archive::archive( 20, 'hp_listing', 'hp_category', '3' ); $result = WPDO_Zone_Archive::get( 20 ); $this->assertCount( 2, $result ); } public function test_get_with_meta_key_filter_returns_only_matching(): void { WPDO_Zone_Archive::archive( 21, 'hp_listing', 'hp_price', '150' ); WPDO_Zone_Archive::archive( 21, 'hp_listing', 'hp_category', '2' ); $result = WPDO_Zone_Archive::get( 21, 'hp_price' ); $this->assertCount( 1, $result ); $this->assertSame( 'hp_price', $result[0]['meta_key'] ); } public function test_get_decompresses_gzipped_values(): void { $original = 'hello decompressed world'; WPDO_Zone_Archive::archive( 22, 'hp_listing', 'hp_bio', $original, 0, true ); $result = WPDO_Zone_Archive::get( 22 ); $this->assertCount( 1, $result ); $this->assertSame( $original, $result[0]['meta_value'] ); } public function test_get_removes_compressed_field_from_result(): void { WPDO_Zone_Archive::archive( 23, 'hp_listing', 'hp_price', '10' ); $result = WPDO_Zone_Archive::get( 23 ); $this->assertArrayNotHasKey( 'compressed', $result[0] ); } // ── restore() ──────────────────────────────────────────────────────────── public function test_restore_writes_to_post_meta(): void { WPDO_Zone_Archive::archive( 30, 'hp_listing', 'hp_price', '77' ); WPDO_Zone_Archive::archive( 30, 'hp_listing', 'hp_category', '5' ); WPDO_Zone_Archive::restore( 30 ); $this->assertSame( '77', $GLOBALS['_wp_postmeta'][30]['hp_price'] ); $this->assertSame( '5', $GLOBALS['_wp_postmeta'][30]['hp_category'] ); } public function test_restore_returns_correct_entry_count(): void { WPDO_Zone_Archive::archive( 31, 'hp_listing', 'hp_price', '88' ); WPDO_Zone_Archive::archive( 31, 'hp_listing', 'hp_category', '9' ); $count = WPDO_Zone_Archive::restore( 31 ); $this->assertSame( 2, $count ); } public function test_restore_returns_zero_for_missing_post(): void { $count = WPDO_Zone_Archive::restore( 999 ); $this->assertSame( 0, $count ); } // ── delete() ───────────────────────────────────────────────────────────── public function test_delete_passes_correct_post_id_to_wpdb(): void { WPDO_Zone_Archive::archive( 40, 'hp_listing', 'hp_price', '100' ); WPDO_Zone_Archive::delete( 40 ); $this->assertNotEmpty( self::$last_delete ); $this->assertSame( 40, self::$last_delete['where']['post_id'] ); } // ── stats() ────────────────────────────────────────────────────────────── public function test_stats_includes_required_keys(): void { $stats = WPDO_Zone_Archive::stats(); $this->assertArrayHasKey( 'total_rows', $stats ); $this->assertArrayHasKey( 'compressed_rows', $stats ); $this->assertArrayHasKey( 'post_types', $stats ); } public function test_stats_total_and_compressed_counts(): void { WPDO_Zone_Archive::archive( 50, 'hp_listing', 'hp_price', '1', 0, true ); WPDO_Zone_Archive::archive( 51, 'hp_listing', 'hp_price', '2', 0, false ); WPDO_Zone_Archive::archive( 52, 'hp_listing', 'hp_price', '3', 0, true ); $stats = WPDO_Zone_Archive::stats(); $this->assertSame( 3, $stats['total_rows'] ); $this->assertSame( 2, $stats['compressed_rows'] ); } public function test_stats_post_types_groups_by_type(): void { WPDO_Zone_Archive::archive( 60, 'hp_listing', 'hp_price', '1' ); WPDO_Zone_Archive::archive( 61, 'hp_listing', 'hp_price', '2' ); WPDO_Zone_Archive::archive( 62, 'hp_vendor', 'hp_bio', 'x' ); $stats = WPDO_Zone_Archive::stats(); $by_type = array_column( $stats['post_types'], 'cnt', 'post_type' ); $this->assertSame( '2', $by_type['hp_listing'] ); $this->assertSame( '1', $by_type['hp_vendor'] ); } }