query( "CREATE TABLE `{$wpdb->usermeta}` ( umeta_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL DEFAULT 0, meta_key VARCHAR(255) DEFAULT NULL, meta_value LONGTEXT, PRIMARY KEY (umeta_id), KEY user_id (user_id) ) ENGINE=InnoDB" ); $wpdb->query( 'CREATE TABLE `' . self::TABLE . '` ( id BIGINT NOT NULL AUTO_INCREMENT, user_id BIGINT NOT NULL, login_count BIGINT(20) DEFAULT 0, session_count BIGINT(20) DEFAULT 0, note VARCHAR(255) DEFAULT NULL, req_flag BIGINT(20) NOT NULL DEFAULT 0, PRIMARY KEY (id), UNIQUE KEY uk_entity (user_id) ) ENGINE=InnoDB' ); $wpdb->query( 'CREATE TABLE `' . self::STATUS . "` ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, entity_type VARCHAR(50) NOT NULL, group_name VARCHAR(50) NOT NULL, last_id BIGINT UNSIGNED NOT NULL DEFAULT 0, total_migrated BIGINT UNSIGNED NOT NULL DEFAULT 0, status VARCHAR(20) NOT NULL DEFAULT 'pending', started_at DATETIME DEFAULT NULL, completed_at DATETIME DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY entity_group (entity_type, group_name) ) ENGINE=InnoDB" ); $GLOBALS['_wp_cache'] = array(); WPDO_Entity_Registry::init(); WPDO_Entity_Registry::register_adapter( 'user', new WPDO_Adapter_User() ); WPDO_Entity_Registry::register_group( 'user', 'md_act', array( array( 'key' => 'login_count', 'type' => 'integer', 'default' => 0 ), array( 'key' => 'session_count', 'type' => 'integer', 'default' => 0 ), array( 'key' => 'note', 'type' => 'text' ), array( 'key' => 'req_flag', 'type' => 'integer', 'default' => 0, 'required' => true ), ) ); WPDO_Schema_Manager::flush_table_exists_cache(); } protected function tearDown(): void { self::drop(); WPDO_Entity_Registry::init(); } private static function drop(): void { global $wpdb; foreach ( array( $wpdb->usermeta, self::TABLE, self::STATUS ) as $table ) { $wpdb->query( "DROP TABLE IF EXISTS `{$table}`" ); } } private function native( int $user_id, string $key, string $value ): void { global $wpdb; $wpdb->insert( $wpdb->usermeta, array( 'user_id' => $user_id, 'meta_key' => $key, 'meta_value' => $value ) ); } /** @return array */ private function flat_row( int $user_id ): array { global $wpdb; return (array) $wpdb->get_row( $wpdb->prepare( 'SELECT login_count, session_count, note, req_flag FROM `' . self::TABLE . '` WHERE user_id = %d', $user_id ), ARRAY_A ); } private function migrate(): array { return TMDO_Entity_Migration_Engine::migrate_group( 'user', 'md_act', array( 'resume' => false, 'sleep_ms' => 0 ) ); } public function test_keys_without_a_native_row_stay_null_instead_of_the_column_default(): void { $this->native( 1, 'login_count', '7' ); $report = $this->migrate(); $this->assertSame( 1, $report['migrated'] ); $row = $this->flat_row( 1 ); $this->assertSame( '7', $row['login_count'] ); $this->assertNull( $row['session_count'], 'no native session_count — must not become the DEFAULT 0' ); $this->assertNull( $row['note'] ); } public function test_a_native_value_equal_to_the_default_is_still_written(): void { $this->native( 1, 'session_count', '0' ); $this->migrate(); $this->assertSame( '0', $this->flat_row( 1 )['session_count'] ); } public function test_a_stale_flat_value_is_cleared_when_the_native_row_is_gone(): void { global $wpdb; $wpdb->insert( self::TABLE, array( 'user_id' => 1, 'login_count' => 3, 'session_count' => 5, 'note' => 'old' ) ); $this->native( 1, 'login_count', '4' ); $this->migrate(); $row = $this->flat_row( 1 ); $this->assertSame( '4', $row['login_count'] ); $this->assertNull( $row['session_count'] ); $this->assertNull( $row['note'] ); } public function test_a_required_column_without_a_native_row_keeps_its_default(): void { $this->native( 1, 'login_count', '1' ); $report = $this->migrate(); $this->assertSame( 0, $report['errors'] ); $this->assertSame( '0', $this->flat_row( 1 )['req_flag'], 'NOT NULL column cannot hold NULL — its default is the documented stand-in' ); } public function test_the_cron_batch_path_does_not_invent_defaults_either(): void { $this->native( 1, 'login_count', '2' ); $result = TMDO_Entity_Migration_Engine::migrate_group_batch( 'user', 'md_act' ); $this->assertSame( 1, $result['migrated'] ); $this->assertNull( $this->flat_row( 1 )['session_count'] ); } }