knowledge_head, _operations, _section, _draft, _parts, _asked, _fill, _rebuild_index, _review_again, _integrity, _move and _move_check, beside the health, highest and marks tools; the manifest lists them and a test compares them with the code. Issue 1966. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
137 lines
4.9 KiB
Go
137 lines
4.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func callTool(t *testing.T, tools []toolRun, name string, args map[string]any) (map[string]any, error) {
|
|
t.Helper()
|
|
for _, tool := range tools {
|
|
if tool.name == name {
|
|
out, err := tool.run(args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
raw, _ := json.Marshal(out)
|
|
var m map[string]any
|
|
_ = json.Unmarshal(raw, &m)
|
|
return m, nil
|
|
}
|
|
}
|
|
t.Fatalf("no tool %s", name)
|
|
return nil, nil
|
|
}
|
|
|
|
type toolRun struct {
|
|
name string
|
|
run func(map[string]any) (any, error)
|
|
}
|
|
|
|
// Every state the module keeps on the bus has a tool that reads it, and every act it does by itself one that does it by
|
|
// hand (to-be 55 §1.1, AC54): the head, the history, a section, a draft, the parts' verdicts, the parts in flight, the fill,
|
|
// the index, the review asked again, the integrity of the sections, the move and its check.
|
|
func TestEveryStateTheModuleKeepsHasAToolThatReadsIt(t *testing.T) {
|
|
w, f := ledgerWorld(t)
|
|
var tools []toolRun
|
|
for _, tool := range moduleTools(w.k, callerOf) {
|
|
tools = append(tools, toolRun{tool.Name, tool.Run})
|
|
}
|
|
r, _ := w.k.ReserveNumber("author@g14", KindDecision, "a test record")
|
|
p := valid(r.Number)
|
|
p.Sections[0].Text = "The merge window of ADR 0276 §1 waits too long."
|
|
key := map[string]any{"number": float64(r.Number)}
|
|
if _, err := w.k.Open("author@g14", ProposeAsk{Kind: KindDecision, Number: r.Number, Title: p.Title, Topic: p.Topic, Date: p.Date, Deciders: p.Deciders, Clauses: p.Clauses, Links: p.Links, Homes: p.Homes}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := w.k.Write("author@g14", Key{KindDecision, r.Number}, "Context", p.Sections[0].Text); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
d, err := callTool(t, tools, DraftTool, key)
|
|
if err != nil || d["author"] != "author@g14" || len(d["sections"].([]any)) != 1 {
|
|
t.Fatalf("%v %v", err, d)
|
|
}
|
|
for _, s := range p.Sections[1:] {
|
|
_, _ = w.k.Write("author@g14", Key{KindDecision, r.Number}, s.Name, s.Text)
|
|
}
|
|
if _, err := w.k.SubmitDraft("author@g14", Key{KindDecision, r.Number}, ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
w.reviewAll(t)
|
|
|
|
h, err := callTool(t, tools, HeadTool, key)
|
|
if err != nil || h["entry"] == nil {
|
|
t.Fatalf("%v %v", err, h)
|
|
}
|
|
ops, err := callTool(t, tools, OperationsTool, key)
|
|
if err != nil || len(ops["operations"].([]any)) < 6 {
|
|
t.Fatalf("%v %v", err, ops)
|
|
}
|
|
var first map[string]any
|
|
for _, o := range ops["operations"].([]any) {
|
|
op := o.(map[string]any)
|
|
if op["body"] != nil {
|
|
t.Fatalf("the history shows a body: %v", op)
|
|
}
|
|
if first == nil && op["operation"] == OpWriteSection {
|
|
first = op
|
|
}
|
|
}
|
|
sec, err := callTool(t, tools, SectionTool, map[string]any{"number": key["number"], "sequence": first["sequence"]})
|
|
if err != nil || sec["text"] != p.Sections[0].Text || sec["title"] != "Context" {
|
|
t.Fatalf("%v %v", err, sec)
|
|
}
|
|
parts, err := callTool(t, tools, PartsTool, key)
|
|
if err != nil || len(parts["parts"].([]any)) != 5 {
|
|
t.Fatalf("%v %v", err, parts)
|
|
}
|
|
if _, err := callTool(t, tools, AskedTool, map[string]any{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if fill, err := callTool(t, tools, FillTool, map[string]any{}); err != nil || fill["keys"] == nil {
|
|
t.Fatalf("%v %v", err, fill)
|
|
}
|
|
if st, err := callTool(t, tools, IndexTool, map[string]any{}); err != nil || st["built"] != true {
|
|
t.Fatalf("%v %v", err, st)
|
|
}
|
|
// The integrity of the sections: all well, then one damaged text in the history is named.
|
|
if res, err := callTool(t, tools, IntegrityTool, map[string]any{}); err != nil || len(res["damaged"].([]any)) != 0 {
|
|
t.Fatalf("%v %v", err, res)
|
|
}
|
|
hist := f.hist[InstanceOf(Key{KindDecision, r.Number})]
|
|
for i := range hist {
|
|
if hist[i].Operation == OpWriteSection && strings.Contains(string(hist[i].Body), "Considered Options") {
|
|
hist[i].Body = mustJSON(t, map[string]any{"title": "Considered Options", "text": "damaged", "digest": SectionDigest("1. **Keep it.** Rejected.")})
|
|
}
|
|
}
|
|
if res, _ := callTool(t, tools, IntegrityTool, key); len(res["damaged"].([]any)) == 0 {
|
|
t.Fatalf("a damaged section was not named: %v", res)
|
|
}
|
|
// An accepted record has no review to ask again; a proposed one does.
|
|
if _, err := callTool(t, tools, AgainTool, key); err == nil {
|
|
t.Fatal("a review of an accepted record was asked again")
|
|
}
|
|
q, _ := w.k.ReserveNumber("author@g14", KindDecision, "another")
|
|
if _, err := w.k.Propose("author@g14", valid(q.Number)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
w.judge.review = `{"verdict":"changes","findings":["x"]}`
|
|
w.reviewAll(t)
|
|
w.judge.review = ""
|
|
if _, err := w.k.ReviewAgain("author@g14", Key{KindDecision, q.Number}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
w.reviewAll(t)
|
|
if e := mustGet(t, w.k.Store, Key{KindDecision, q.Number}); e.Current.Status != StatusAccepted {
|
|
t.Fatalf("a review asked again: %s", e.Current.Status)
|
|
}
|
|
// The move's tools need the database beside the ledger.
|
|
if _, err := callTool(t, tools, MoveCheckTool, map[string]any{}); err == nil {
|
|
t.Fatal("a move check without a database")
|
|
}
|
|
if len(ModuleTools) != 15 {
|
|
t.Fatalf("%v", ModuleTools)
|
|
}
|
|
}
|