package main import ( "fmt" "testing" ) func TestCanonicalWorkflowBranches(t *testing.T) { c, err := loadUseCases("..") if err != nil { t.Fatal(err) } for id, u := range c.UC { t.Run(id, func(t *testing.T) { d := draftDiagram(u) if err := validateDiagram(d); err != nil { t.Fatal(err) } seen := map[string]bool{"start": true} for changed := true; changed; { changed = false for _, e := range d.Edges { if seen[e.Source] && !seen[e.Target] { seen[e.Target] = true changed = true } } } for _, n := range d.Nodes { if !seen[n.ID] { t.Errorf("unreachable %s", n.ID) } if n.Type != "end" { found := false for _, e := range d.Edges { found = found || e.Source == n.ID } if !found { t.Errorf("dead end %s", n.ID) } } } canFinish := map[string]bool{} for _, n := range d.Nodes { if n.Type == "end" { canFinish[n.ID] = true } } for changed := true; changed; { changed = false for _, e := range d.Edges { if canFinish[e.Target] && !canFinish[e.Source] { canFinish[e.Source] = true changed = true } } } for _, n := range d.Nodes { if !canFinish[n.ID] { t.Errorf("no terminal outcome from %s", n.ID) } } for i := range u.Flow { if !seen[fmt.Sprintf("step-%d", i+1)] { t.Fatal("source step lost") } } }) } check := func(id, from, to, label string) { t.Helper() for _, e := range draftDiagram(c.UC[id]).Edges { if e.Source == from && e.Target == to && e.Label == label { return } } t.Fatalf("missing %s: %s -> %s (%s)", id, from, to, label) } check("W-41", "decision-3", "step-4", "ไม่จำเป็น — สมัครด้วยตนเอง") check("W-77", "step-3", "step-2", "") check("W-14", "decision-1", "step-5", "ฉุกเฉินเข้าเกณฑ์") check("W-14", "step-4", "step-6", "") for _, e := range draftDiagram(c.UC["W-147"]).Edges { if e.Source == "decision-3" && e.Label == "ต่อสัญญา" && e.Target == "step-3" { t.Fatal("renewal entered checkout") } } u := c.UC["W-41"] old := sourceDigest(u) u.Workflow.Decisions[0].Title += " changed" if old == sourceDigest(u) { t.Fatal("workflow missing from approval fingerprint") } } func TestWorkflowChangeStalesApprovalWithoutReplacingSavedDiagram(t *testing.T) { c, err := loadUseCases("..") if err != nil { t.Fatal(err) } u := c.UC["W-41"] ds := &diagramStore{dir: t.TempDir()} status, err := ds.approve(u, 0, sourceDigest(u), "Test reviewer", "Temporary fixture only", true) if err != nil || !status.Approved { t.Fatal(err, status) } before, err := ds.load(u.ID, u) if err != nil { t.Fatal(err) } u.Workflow.Decisions[0].Branches[0].Label += " revised" if ds.approvalStatus(u).Approved { t.Fatal("changed condition kept approval") } after, err := ds.load(u.ID, u) if err != nil || digestJSON(before) != digestJSON(after) { t.Fatal("saved user graph overwritten", err) } }