package game // Regression coverage for Game.AdminPlayerFileOnline, the hook the admin raw // file editor uses (admin.AdminServer.SetPlayerFileOnlineCheck) to refuse // editing a character/account file whose character is live. import "testing" func TestAdminPlayerFileOnlineRefusesLivePlayerFiles(t *testing.T) { h := newHarness(t) h.seedAccount("alice") h.seedCharacter("alice", "alice") // A second character of the same account, offline, so the account check // cannot pass merely because the file exists. h.seedCharacter("alicia", "alice") h.seedAccount("carol") h.seedCharacter("carol", "carol") sess, _ := h.connect("alice") if sess.Player == nil || sess.Player.Name != "alice" { t.Fatalf("alice is not registered as online: %+v", sess.Player) } cases := []struct { name string path string want bool }{ {"online character", "players/characters/alice.yaml", true}, {"offline character of a live account", "players/characters/alicia.yaml", false}, {"offline character", "players/characters/carol.yaml", false}, {"unknown character", "players/characters/nobody.yaml", false}, {"account of an online character", "players/accounts/alice.yaml", true}, {"account with no online character", "players/accounts/carol.yaml", false}, {"unknown account", "players/accounts/nobody.yaml", false}, {"leading slash", "/players/characters/alice.yaml", true}, {"data/ prefix", "data/players/accounts/alice.yaml", true}, {"non-yaml file", "players/characters/alice.txt", false}, {"bare directory", "players/characters", false}, {"nested path", "players/characters/sub/alice.yaml", false}, {"non-player file", "rooms/1.yaml", false}, {"empty path", "", false}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { if got := h.g.AdminPlayerFileOnline(tc.path); got != tc.want { t.Fatalf("AdminPlayerFileOnline(%q) = %v, want %v", tc.path, got, tc.want) } }) } } // TestAdminPlayerFileOnlineIgnoresMenuOnlySession pins that an account sitting // in the character menu is NOT treated as an online character: only a live // character (a loggedInChars entry) makes its file, or its account's file, // editable-refused for that reason. func TestAdminPlayerFileOnlineIgnoresMenuOnlySession(t *testing.T) { h := newHarness(t) h.seedAccount("dave") h.seedCharacter("dave", "dave") h.connectMenu("dave") if h.g.AdminPlayerFileOnline("players/characters/dave.yaml") { t.Fatal("a menu session was treated as a live character") } if h.g.AdminPlayerFileOnline("players/accounts/dave.yaml") { t.Fatal("a menu session was treated as a live account character") } }