diff options
Diffstat (limited to 'internal/game/snapshot_render_guard_test.go')
| -rw-r--r-- | internal/game/snapshot_render_guard_test.go | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/internal/game/snapshot_render_guard_test.go b/internal/game/snapshot_render_guard_test.go new file mode 100644 index 0000000..83833d5 --- /dev/null +++ b/internal/game/snapshot_render_guard_test.go @@ -0,0 +1,40 @@ +package game + +// Guard for the last per-game presentation seam: the Snapshot marker interface +// guarantees an event carries a structured view, but renderCasinoSnapshot's +// type switch silently returns "" for a snapshot it does not know. This +// source-level test pairs every `func (*X) snapshot() {}` in the casino package +// with a `case *casino.X:` in the renderer, so adding a game cannot silently +// drop its view (the text message would still appear, hiding the loss). + +import ( + "os" + "path/filepath" + "regexp" + "strings" + "testing" +) + +func TestEveryCasinoSnapshotHasARenderer(t *testing.T) { + typesSrc, err := os.ReadFile(filepath.Join("..", "casino", "types.go")) + if err != nil { + t.Fatalf("read casino types: %v", err) + } + renderSrc, err := os.ReadFile("casino.go") + if err != nil { + t.Fatalf("read renderer: %v", err) + } + + re := regexp.MustCompile(`func \(\*(\w+)\) snapshot\(\)`) + matches := re.FindAllStringSubmatch(string(typesSrc), -1) + if len(matches) == 0 { + t.Fatal("no Snapshot implementations found in casino/types.go") + } + for _, m := range matches { + name := m[1] + want := "case *casino." + name + ":" + if !strings.Contains(string(renderSrc), want) { + t.Errorf("snapshot %s has no renderer: add `%s` to renderCasinoSnapshot", name, want) + } + } +} |
