package spec import ( "os" "path/filepath" "strings" "testing" ) // The real specs must load. If either stops validating, the tool has drifted // away from the artifacts it exists to read. func TestRealSpecsLoad(t *testing.T) { for _, p := range []string{ "../../presence/telegram.example.yaml", "../../../pr-hall-of-helix/presence/telegram.yaml", } { if _, err := os.Stat(p); err != nil { t.Skipf("not present in this checkout: %s", p) } got, digest, err := Load(p) if err != nil { t.Fatalf("%s: %v", p, err) } if got.Campaign == "" || !strings.HasPrefix(digest, "sha256:") { t.Fatalf("%s: campaign=%q digest=%q", p, got.Campaign, digest) } } } func base() Presence { return Presence{ SchemaVersion: "0.1", Campaign: "hall-of-helix", Interface: "helix-forge-telegram-publishing", Bot: Bot{ Name: "HelixForge", UsernamePreference: []string{"HelixForgeBot"}, About: "about", Description: "description", }, Channels: map[string]Channel{ Test: {Title: "t", Visibility: Private, AdminRights: []string{PostMessages}}, Live: {Title: "p", Visibility: Public, UsernamePreference: []string{"hallofhelix"}, AdminRights: []string{PostMessages}}, }, } } // Every rule the schema states, asserted here too. These are the cases the // schema file rejects; if this table and presence/telegram.schema.yaml ever // disagree, one of them is wrong and a spec will pass one gate and fail another. func TestValidateRejects(t *testing.T) { cases := []struct { name string mutate func(*Presence) want string }{ {"extra admin right", func(p *Presence) { c := p.Channels[Live] c.AdminRights = []string{PostMessages, "can_delete_messages"} p.Channels[Live] = c }, "can_delete_messages"}, {"wrong admin right", func(p *Presence) { c := p.Channels[Live] c.AdminRights = []string{"can_delete_messages"} p.Channels[Live] = c }, "refused"}, {"private channel with username", func(p *Presence) { c := p.Channels[Test] c.UsernamePreference = []string{"secretchan"} p.Channels[Test] = c }, "must not declare a username"}, {"public channel without username", func(p *Presence) { c := p.Channels[Live] c.UsernamePreference = nil p.Channels[Live] = c }, "must declare at least one"}, {"bot username not ending in bot", func(p *Presence) { p.Bot.UsernamePreference = []string{"HelixForge"} }, `end in "bot"`}, {"no bot username candidates", func(p *Presence) { p.Bot.UsernamePreference = nil }, "at least one candidate"}, {"missing test channel", func(p *Presence) { delete(p.Channels, Test) }, "channels.test is required"}, {"unknown channel key", func(p *Presence) { p.Channels["archive"] = Channel{Title: "a", Visibility: Private} }, "not a known channel"}, {"bad visibility", func(p *Presence) { c := p.Channels[Test] c.Visibility = "unlisted" p.Channels[Test] = c }, "visibility must be"}, {"wrong schema version", func(p *Presence) { p.SchemaVersion = "0.2" }, "schema_version"}, {"campaign not a slug", func(p *Presence) { p.Campaign = "Hall Of Helix" }, "lowercase slug"}, {"about too long", func(p *Presence) { p.Bot.About = strings.Repeat("x", 121) }, "limit is 120"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { p := base() tc.mutate(&p) err := p.Validate() if err == nil { t.Fatalf("accepted a spec that must be rejected") } if !strings.Contains(err.Error(), tc.want) { t.Fatalf("error did not mention %q:\n%v", tc.want, err) } }) } } func TestValidateAcceptsBase(t *testing.T) { p := base() if err := p.Validate(); err != nil { t.Fatalf("rejected a valid spec: %v", err) } } // An unknown field is a mistake about what is being declared, not a comment. func TestUnknownFieldRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "s.yaml") os.WriteFile(f, []byte(` presence: schema_version: "0.1" campaign: "c" interface: "i" pinned: true bot: {name: "n", username_preference: ["aBot"], about: "a", description: "d"} channels: test: {title: "t", visibility: private} public: {title: "p", visibility: public, username_preference: ["abcdef"]} `), 0o600) if _, _, err := Load(f); err == nil { t.Fatal("accepted an unknown field") } } // Rights are the tool's decision, not the spec's. func TestRightsAlwaysClamped(t *testing.T) { c := Channel{AdminRights: nil} got := c.Rights() if len(got) != 1 || got[0] != PostMessages { t.Fatalf("Rights() = %v, want [%s]", got, PostMessages) } }