diff options
Diffstat (limited to 'internal/game/hardening_admin_player_file_online_test.go')
| -rw-r--r-- | internal/game/hardening_admin_player_file_online_test.go | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/game/hardening_admin_player_file_online_test.go b/internal/game/hardening_admin_player_file_online_test.go new file mode 100644 index 0000000..f0c64f3 --- /dev/null +++ b/internal/game/hardening_admin_player_file_online_test.go @@ -0,0 +1,70 @@ +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") + } +} |
