instance('config', new Repository()); Facade::setFacadeApplication($app); $db = new Manager($app); $db->addConnection(['driver' => 'sqlite', 'database' => ':memory:', 'prefix' => 'bot_']); $db->setAsGlobal(); $app->instance('db', $db->getDatabaseManager()); $app->bind('db.schema', fn () => $db->schema()); $db->schema()->create('egame_items', function (Blueprint $table) { $table->id(); $table->string('item_type'); $table->string('plat_type')->default(''); $table->unsignedTinyInteger('game_type'); $table->string('game_code')->default(''); $table->string('name')->default(''); $table->string('logo')->default(''); $table->text('logo_langs')->nullable(); $table->string('ingress')->default('3'); $table->integer('status')->default(1); $table->integer('sort')->default(0); $table->timestamps(); $table->unique(['item_type', 'plat_type', 'game_type', 'game_code']); }); (require dirname(__DIR__, 2) . '/database/migrations/2026_07_21_120000_add_catalog_management_to_egame_items_table.php')->up(); } protected function tearDown(): void { DB::disconnect(); Facade::clearResolvedInstances(); parent::tearDown(); } private function migration() { return require dirname(__DIR__, 2) . '/database/migrations/2026_10_28_180000_restore_esports_platform_relations.php'; } public function test_upgrades_the_legacy_catalog_without_changing_other_rows_or_display_fields(): void { $targets = DB::table('egame_items')->where('item_type', 'platform')->where('game_type', 5)->get(); $this->assertCount(3, $targets); foreach ($targets as $row) { $this->assertSame(0, (int) $row->status, 'Reproduce the legacy whitelist omission'); } DB::table('egame_items')->where('plat_type', 'db5')->where('game_type', 5)->update([ 'name' => '自定义电竞名称', 'logo' => '/custom.png', 'sort' => 99, 'lobby_enabled' => 0, ]); // Explicit category/global closures remain effective after the repair. DB::table('egame_items')->where('item_type', 'category')->where('game_type', 5)->update(['status' => 0]); DB::table('egame_items')->where('plat_type', 'tf')->where('game_type', 0)->update(['status' => 0]); DB::table('egame_items')->insert([ ['item_type' => 'game', 'plat_type' => 'db5', 'game_type' => 5, 'game_code' => 'closed-game', 'status' => 0], ['item_type' => 'platform', 'plat_type' => 'custom', 'game_type' => 5, 'game_code' => '', 'status' => 0], ]); $before = DB::table('egame_items')->orderBy('id')->get(); $this->migration()->up(); $this->assertSame($before->count(), DB::table('egame_items')->count()); foreach ($before as $row) { $after = DB::table('egame_items')->where('id', $row->id)->first(); if ($row->item_type === 'platform' && (int) $row->game_type === 5 && in_array($row->plat_type, ['db5', 'esb', 'tf'], true) && $row->game_code === '') { $this->assertSame(1, (int) $after->status); $this->assertSame(1, (int) $after->lobby_enabled); foreach (['status', 'lobby_enabled', 'updated_at'] as $field) { unset($row->{$field}, $after->{$field}); } } $this->assertEquals($row, $after); } } public function test_repeated_up_is_unchanged_and_rollback_preserves_later_admin_changes(): void { $migration = $this->migration(); $migration->up(); DB::table('egame_items')->update(['updated_at' => '2026-01-01 00:00:00']); $before = DB::table('egame_items')->orderBy('id')->get(); $migration->up(); $this->assertEquals($before, DB::table('egame_items')->orderBy('id')->get()); DB::table('egame_items')->where('plat_type', 'esb')->where('game_type', 5)->update(['status' => 0]); $before = DB::table('egame_items')->orderBy('id')->get(); $migration->down(); $this->assertEquals($before, DB::table('egame_items')->orderBy('id')->get()); } }