diff options
Diffstat (limited to 'internal/player/roomset_test.go')
| -rw-r--r-- | internal/player/roomset_test.go | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/internal/player/roomset_test.go b/internal/player/roomset_test.go index 2b6b9cb..38bd993 100644 --- a/internal/player/roomset_test.go +++ b/internal/player/roomset_test.go @@ -1,6 +1,8 @@ package player import ( + "encoding/base64" + "encoding/binary" "strings" "testing" @@ -85,3 +87,59 @@ func TestRoomSetMarshalEmpty(t *testing.T) { t.Errorf("MarshalYAML empty = %q, want empty string", s) } } + +// Sparse, high room IDs are the reason RoomSet is not a dense bitset: the +// encoding must stay proportional to the visited count, not the largest ID. +func TestRoomSetSparseEncodingIsCompact(t *testing.T) { + var rs RoomSet + for _, id := range []int{1001, 1002, 1003, 2001, 2006, 99999301} { + rs.Add(id) + } + data, err := yaml.Marshal(PlayerStats{RoomsVisited: rs}) + if err != nil { + t.Fatalf("marshal: %v", err) + } + if len(data) > 200 { + t.Fatalf("encoding is not compact for sparse IDs: %d bytes\n%s", len(data), data) + } + + var loaded PlayerStats + if err := yaml.Unmarshal(data, &loaded); err != nil { + t.Fatalf("unmarshal: %v", err) + } + for _, id := range []int{1001, 1002, 1003, 2001, 2006, 99999301} { + if !loaded.RoomsVisited.Has(id) { + t.Errorf("round trip lost room %d", id) + } + } + if loaded.RoomsVisited.Has(5000) { + t.Error("round trip invented room 5000") + } +} + +// The prototype has no legacy formats: anything without the v1 prefix is a +// hard error rather than a silently-decoded old bitset. +func TestRoomSetRejectsUnknownEncoding(t *testing.T) { + var wrap struct { + Visited RoomSet `yaml:"rooms_visited"` + } + if err := yaml.Unmarshal([]byte("rooms_visited: AQIDBA==\n"), &wrap); err == nil { + t.Fatal("expected error for unprefixed encoding") + } + if err := yaml.Unmarshal([]byte("rooms_visited: [7, 42, 900]\n"), &wrap); err == nil { + t.Fatal("expected error for YAML sequence encoding") + } +} + +func TestRoomSetRejectsOutOfRangeDelta(t *testing.T) { + // A valid uvarint delta above roomSetMaxID must fail rather than wrap or + // synthesize an absurd room ID. + buf := binary.AppendUvarint(nil, uint64(roomSetMaxID)+1) + encoded := roomSetV1Prefix + base64.StdEncoding.EncodeToString(buf) + var wrap struct { + Visited RoomSet `yaml:"rooms_visited"` + } + if err := yaml.Unmarshal([]byte("rooms_visited: "+encoded+"\n"), &wrap); err == nil { + t.Fatal("expected error for out-of-range delta") + } +} |
