From 1fcf5abcdf86e0f2cdfb44ae569be657f8ddd1b1 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Fri, 18 Sep 2026 20:48:21 +0200 Subject: [PATCH] test(05-06): assert HasHidden fields never marshal - Fixture model with json:\"-\" keeps the sentinel out of JSON - Registered-model walk stays in fonoteka.go so the framework stays app-agnostic --- lagoon/hidden_marshal_test.go | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 lagoon/hidden_marshal_test.go diff --git a/lagoon/hidden_marshal_test.go b/lagoon/hidden_marshal_test.go new file mode 100644 index 0000000..6088c0d --- /dev/null +++ b/lagoon/hidden_marshal_test.go @@ -0,0 +1,42 @@ +package lagoon + +import ( + "encoding/json" + "strings" + "testing" +) + +// hiddenMarshalFixture covers the HasHidden contract inside the framework +// module. Enumerating fonoteka.go plugin models.All() from this package +// would import the application into summercms.go, which CLAUDE.md forbids; +// that registry walk lives in fonoteka.go (classes.TestHiddenNeverMarshals). +type hiddenMarshalFixture struct { + Name string `gorm:"column:name" json:"name"` + CollectionID uint `gorm:"column:collection_id" json:"collection_id"` + Secret string `gorm:"column:secret" json:"-"` +} + +func (hiddenMarshalFixture) Hidden() []string { return []string{"secret"} } + +func TestHiddenNeverMarshals(t *testing.T) { + row := hiddenMarshalFixture{Name: "ok", CollectionID: 3, Secret: hiddenSentinel} + raw, err := json.Marshal(row) + if err != nil { + t.Fatal(err) + } + if strings.Contains(string(raw), hiddenSentinel) { + t.Fatalf("hidden sentinel leaked: %s", raw) + } + var payload map[string]any + if err := json.Unmarshal(raw, &payload); err != nil { + t.Fatal(err) + } + if _, ok := payload["secret"]; ok { + t.Fatalf("json:\"-\" field present: %s", raw) + } + if payload["name"] != "ok" { + t.Fatalf("visible field missing: %s", raw) + } +} + +const hiddenSentinel = "HIDDEN-SENTINEL-05-06"