query( 'DROP TABLE IF EXISTS `' . self::POSTS . '`' ); $wpdb->query( 'CREATE TABLE `' . self::POSTS . '` ( ID bigint(20) unsigned NOT NULL AUTO_INCREMENT, post_type varchar(20) NOT NULL DEFAULT \'post\', post_status varchar(20) NOT NULL DEFAULT \'publish\', PRIMARY KEY (ID), KEY post_type (post_type) ) DEFAULT CHARACTER SET utf8mb4' ); $wpdb->query( 'DROP TABLE IF EXISTS `' . self::POSTMETA . '`' ); $wpdb->query( 'CREATE TABLE `' . self::POSTMETA . '` ( meta_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, post_id bigint(20) unsigned NOT NULL DEFAULT 0, meta_key varchar(255) DEFAULT NULL, meta_value longtext, PRIMARY KEY (meta_id), KEY post_id (post_id), KEY meta_key (meta_key(191)) ) DEFAULT CHARACTER SET utf8mb4' ); $wpdb->query( 'DROP TABLE IF EXISTS `' . self::FLAT . '`' ); $wpdb->query( 'CREATE TABLE `' . self::FLAT . '` ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, post_id bigint(20) unsigned NOT NULL, _price decimal(18,6) DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_post_id (post_id), KEY idx__price (_price) ) DEFAULT CHARACTER SET utf8mb4' ); // Seed 50 products with _price = 10..59 in both tables. for ( $i = 1; $i <= 50; $i++ ) { $wpdb->insert( self::POSTS, array( 'ID' => $i, 'post_type' => 'product', 'post_status' => 'publish' ) ); $price = (string) ( 10 + $i ); $wpdb->insert( self::POSTMETA, array( 'post_id' => $i, 'meta_key' => '_price', 'meta_value' => $price ) ); $wpdb->insert( self::FLAT, array( 'post_id' => $i, '_price' => $price ) ); } } public static function tearDownAfterClass(): void { global $wpdb; $wpdb->query( 'DROP TABLE IF EXISTS `' . self::POSTS . '`' ); $wpdb->query( 'DROP TABLE IF EXISTS `' . self::POSTMETA . '`' ); $wpdb->query( 'DROP TABLE IF EXISTS `' . self::FLAT . '`' ); } // ── benchmark_query() ──────────────────────────────────────────────────── public function test_benchmark_returns_expected_shape(): void { $result = WPDO_Post_Migration::benchmark_query( 'product', '_price', '>=', '30', self::FLAT, 5 ); $this->assertArrayHasKey( 'samples', $result ); $this->assertArrayHasKey( 'postmeta_avg_ms', $result ); $this->assertArrayHasKey( 'flat_avg_ms', $result ); $this->assertArrayHasKey( 'speedup', $result ); $this->assertArrayHasKey( 'postmeta_rows', $result ); $this->assertArrayHasKey( 'flat_rows', $result ); $this->assertSame( 5, $result['samples'] ); $this->assertGreaterThan( 0.0, $result['postmeta_avg_ms'] ); $this->assertGreaterThan( 0.0, $result['flat_avg_ms'] ); } public function test_benchmark_finds_same_rows_via_both_paths(): void { // _price >= 30 should match products 20..50 (i.e. 31 rows). $result = WPDO_Post_Migration::benchmark_query( 'product', '_price', '>=', '30', self::FLAT, 3 ); // Both paths must return the same count — verifies router correctness. $this->assertSame( $result['postmeta_rows'], $result['flat_rows'] ); $this->assertGreaterThan( 0, $result['postmeta_rows'] ); } public function test_benchmark_speedup_is_positive_number(): void { $result = WPDO_Post_Migration::benchmark_query( 'product', '_price', '=', '25', self::FLAT, 3 ); $this->assertIsFloat( $result['speedup'] ); $this->assertGreaterThan( 0.0, $result['speedup'] ); } public function test_benchmark_rejects_zero_samples(): void { $this->expectException( InvalidArgumentException::class ); WPDO_Post_Migration::benchmark_query( 'product', '_price', '=', '25', self::FLAT, 0 ); } public function test_benchmark_rejects_invalid_compare(): void { $this->expectException( InvalidArgumentException::class ); WPDO_Post_Migration::benchmark_query( 'product', '_price', 'BOGUS', '25', self::FLAT, 3 ); } public function test_benchmark_throws_when_flat_table_missing(): void { $this->expectException( RuntimeException::class ); WPDO_Post_Migration::benchmark_query( 'product', '_price', '=', '25', 'wp_itest_nonexistent_flat', 3 ); } }