117 lines
5.4 KiB
Go
117 lines
5.4 KiB
Go
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)
|
|
}
|
|
}
|