query( "CREATE TABLE `{$table}` ( id BIGINT NOT NULL AUTO_INCREMENT, user_id BIGINT NOT NULL DEFAULT 0, PRIMARY KEY (id) ) ENGINE=InnoDB" ); } $GLOBALS['_wp_options'] = array(); $GLOBALS['_wp_cli_output'] = array(); TMDO_Mode_Manager::reset_cache(); WPDO_Entity_Registry::init(); WPDO_Entity_Registry::register_adapter( 'user', new WPDO_Adapter_User() ); WPDO_Entity_Registry::register_group( 'user', 'dt_have', array( array( 'key' => 'dt_a', 'type' => 'text' ) ) ); WPDO_Schema_Manager::flush_table_exists_cache(); } protected function tearDown(): void { self::drop(); WPDO_Entity_Registry::init(); TMDO_Mode_Manager::reset_cache(); } private static function drop(): void { global $wpdb; foreach ( array_merge( array( self::HAVE ), self::CORE ) as $table ) { $wpdb->query( "DROP TABLE IF EXISTS `{$table}`" ); } } private function cli_output(): string { return implode( "\n", $GLOBALS['_wp_cli_output'] ?? array() ); } public function test_entity_tables_come_from_the_registry(): void { $ok = TMDO_CLI::check_entity_tables(); $this->assertTrue( $ok, $this->cli_output() ); $this->assertStringContainsString( '[OK] ' . self::HAVE, $this->cli_output() ); $this->assertStringNotContainsString( 'wpdo_user_sso', $this->cli_output() ); } public function test_a_registered_group_without_its_table_is_reported(): void { WPDO_Entity_Registry::register_group( 'user', 'dt_missing', array( array( 'key' => 'dt_b', 'type' => 'text' ) ) ); $ok = TMDO_CLI::check_entity_tables(); $this->assertFalse( $ok ); $this->assertStringContainsString( '[MISSING] wp_itest_wpdo_user_dt_missing', $this->cli_output() ); } public function test_reports_drifting_groups(): void { $GLOBALS['_wp_options']['wpdo_bridge_modes'] = array( 'user' => 'dual_write' ); $GLOBALS['_wp_options'][ TMDO_Drift_Check::OPTION ] = array( 'user' => array( 'dt_have' => array( 'miss' => 1, 'diff' => 2, 'extra' => 0, 'sample' => 0, 'checked_at' => '2026-09-27 00:00:00', ), ), ); TMDO_Mode_Manager::reset_cache(); TMDO_CLI::report_guard_and_drift(); $this->assertStringContainsString( 'dt_have miss=1 diff=2 extra=0', $this->cli_output() ); $this->assertStringContainsString( 'wp tmdo drift-check user --fix', $this->cli_output() ); } public function test_ignores_the_record_of_a_group_no_longer_registered(): void { $GLOBALS['_wp_options']['wpdo_bridge_modes'] = array( 'user' => 'dual_write' ); $GLOBALS['_wp_options'][ TMDO_Drift_Check::OPTION ] = array( 'user' => array( 'dt_have' => array( 'miss' => 0, 'diff' => 0, 'extra' => 0, 'sample' => 0, 'checked_at' => '2026-09-27 00:00:00', ), 'dt_gone' => array( 'miss' => 3, 'diff' => 0, 'extra' => 0, 'sample' => 0, 'checked_at' => '2026-09-20 00:00:00', ), ), ); TMDO_Mode_Manager::reset_cache(); TMDO_CLI::report_guard_and_drift(); $this->assertStringContainsString( '[OK] user: 1 group(s) clean (oldest check 2026-09-27 00:00:00 UTC)', $this->cli_output() ); $this->assertStringNotContainsString( 'dt_gone', $this->cli_output() ); } public function test_reports_an_entity_never_checked(): void { $GLOBALS['_wp_options']['wpdo_bridge_modes'] = array( 'user' => 'dual_write' ); TMDO_Mode_Manager::reset_cache(); TMDO_CLI::report_guard_and_drift(); $this->assertStringContainsString( 'user: never checked', $this->cli_output() ); $this->assertStringContainsString( 'Promotion Guard: no violation', $this->cli_output() ); } }