package catalogue import ( "strings" "testing" ) // The router of novox/hq ADR 0259: it declares the operator's seat and the two kinded benches. func router() Manifest { return Manifest{Module: "messenger", Tools: []string{"open", "history", "notify"}, State: []StateDeclaration{{Name: "asks"}}, DefinesSeats: []SeatDeclaration{ {Name: "operator-channel", Scope: ScopeMesh, Accepts: []string{"ask", "cancel"}, Emits: []string{"decided"}, ByCaller: []string{"ask", "cancel", "decided"}, Records: []string{"asks"}, Serves: []Verb{{Name: "open"}, {Name: "history"}, {Name: "notify"}}}, {Name: "channel", Scope: ScopeMesh, Kinded: true, Accepts: []string{"show", "edit", "send"}}, {Name: "intake", Scope: ScopeMesh, Kinded: true, Emits: []string{"choice", "link"}, Proofs: []string{"code"}}, }, Claims: []Claim{{Name: "operator-channel", Scope: ScopeMesh}}, Uses: []string{"channel"}} } func aChannel(module, kind string) Manifest { return Manifest{Module: module, Claims: []Claim{ {Name: "channel", Scope: ScopeMesh, Kind: kind}, {Name: "intake", Scope: ScopeMesh, Kind: kind}}} } func TestTwoChannelsOfDifferentKindsHoldTheBenches(t *testing.T) { shelf := Shelf{"messenger": router(), "telegram": aChannel("telegram", "telegram"), "desk-channel": aChannel("desk-channel", "desktop")} if got := problemsFor(t, shelf); got != "" { t.Fatalf("two kinds were refused: %s", got) } for _, m := range shelf { if got := declaredSeatProblems(m); len(got) > 0 { t.Fatalf("%s: %v", m.Module, got) } } } func TestASecondClaimOfOneKindIsRefused(t *testing.T) { got := problemsFor(t, Shelf{"messenger": router(), "telegram": aChannel("telegram", "telegram"), "telegram-two": aChannel("telegram-two", "telegram")}) if !strings.Contains(got, `of kind "telegram", which telegram already claims`) { t.Fatalf("a second holder of one kind stood: %s", got) } } func TestAKindedBenchNeedsAKindAndNoOtherSeatTakesOne(t *testing.T) { got := problemsFor(t, Shelf{"messenger": router(), "nameless": aChannel("nameless", "")}) if !strings.Contains(got, "claims the kinded bench channel and names no kind") { t.Fatalf("a claim without a kind stood: %s", got) } odd := Manifest{Module: "odd", Claims: []Claim{{Name: "operator-channel", Scope: ScopeMesh, Kind: "telegram"}}} got = problemsFor(t, Shelf{"messenger": router(), "odd": odd}) if !strings.Contains(got, "only a kinded bench takes a kind") { t.Fatalf("a kind on a seat that is not kinded stood: %s", got) } dotted := problemsFor(t, Shelf{"messenger": router(), "dotted": aChannel("dotted", "a.b")}) if !strings.Contains(dotted, "not a usable name") { t.Fatalf("a kind that would widen a subject stood: %s", dotted) } } func TestOnlyChannelAndIntakeAreKinded(t *testing.T) { m := Manifest{Module: "x", DefinesSeats: []SeatDeclaration{{Name: "pager", Kinded: true, Accepts: []string{"page"}}}} if got := strings.Join(declaredSeatProblems(m), "; "); !strings.Contains(got, "only channel and intake are kinded") { t.Fatalf("another kinded bench was declared: %s", got) } } func TestTheNewRulesAreHeldToWhatTheSeatSays(t *testing.T) { m := Manifest{Module: "x", DefinesSeats: []SeatDeclaration{{Name: "thing", Accepts: []string{"do"}, ByCaller: []string{"undo"}, Proofs: []string{"code"}, Records: []string{"nothing"}}}} got := strings.Join(declaredSeatProblems(m), "; ") for _, want := range []string{"names thing.undo by its caller, which the seat neither accepts nor emits", "declares proofs on thing, which is not kinded", `read its records "nothing", which it keeps no state of`} { if !strings.Contains(got, want) { t.Errorf("not refused: %q in %s", want, got) } } } // Two kinds on one machine are two holders, and one kind on two machines is a second claimant. func TestEachKindIsItsOwnHolderWhenResolved(t *testing.T) { modules := []Manifest{aChannel("telegram", "telegram"), aChannel("desk-channel", "desktop")} held, problems := checkClaims(modules, Node{Name: "anchor"}, nil, nil) if len(problems) > 0 || len(held) != 4 { t.Fatalf("two kinds on one machine: held %v, problems %v", held, problems) } _, problems = checkClaims([]Manifest{aChannel("telegram", "telegram")}, Node{Name: "home"}, held, nil) if len(problems) == 0 { t.Fatal("one kind held on two machines was not refused") } } // A channel's capabilities come from the fixed vocabulary, and only a kinded claim carries any. func TestCapabilitiesAreTheVocabularysAndOnlyOnAKindedClaim(t *testing.T) { good := aChannel("telegram", "telegram") good.Claims[0].Capabilities = []string{"deliver", "choice", "verified-sender", "max-length:4096"} if got := problemsFor(t, Shelf{"messenger": router(), "telegram": good}); got != "" { t.Fatalf("the vocabulary was refused: %s", got) } bad := aChannel("telegram", "telegram") bad.Claims[0].Capabilities = []string{"trusted", "max-length:lots"} got := problemsFor(t, Shelf{"messenger": router(), "telegram": bad}) for _, w := range []string{`"trusted"`, `"max-length:lots"`} { if !strings.Contains(got, w+", which channel-capabilities/1 does not have") { t.Errorf("%s was not refused: %s", w, got) } } odd := Manifest{Module: "odd", Claims: []Claim{{Name: "operator-channel", Scope: ScopeMesh, Capabilities: []string{"deliver"}}}} if got := problemsFor(t, Shelf{"messenger": router(), "odd": odd}); !strings.Contains(got, "only a kinded bench's claim carries them") { t.Errorf("capabilities on a seat that is not kinded stood: %s", got) } }