package atlas_test import ( "testing" "git.d-ma.be/mathias/cad-atlas/internal/atlas" caddomain "git.d-ma.be/mathias/cad/domain" ) func stage(no, generate string) atlas.Stage { s := atlas.Stage{No: no, Title: "example"} if generate != "" { s.Generate = atlas.GenerateKeys{generate} } return s } func finding(repo string, issue int, cat caddomain.StuckCategory, class caddomain.StuckClass) caddomain.StuckFinding { return caddomain.StuckFinding{ Repo: repo, Issue: issue, Title: "example", Category: cat, Class: class, Detail: "detail", Locators: []string{"https://git.d-ma.be/" + repo + "/issues/1"}, } } func TestApplyStuckOverlay_BadgesOnlyOnGeneratedStages(t *testing.T) { stages := []atlas.Stage{ stage("STAGE 04", ""), // no generate marker — must be untouched stage("STAGE 04b", "stuck-badges"), // marked but no findings map here } out := atlas.ApplyStuckOverlay(stages, nil) if len(out[0].Nodes) != 0 || out[0].StuckCount != 0 { t.Fatalf("un-marked stage was touched: %+v", out[0]) } } func TestApplyStuckOverlay_ArmedNeverFiredGoesToStage04(t *testing.T) { stages := []atlas.Stage{stage("STAGE 04", "stuck-badges")} findings := []caddomain.StuckFinding{ finding("mathias/brain-gardener", 190, caddomain.CategoryArmedNeverFired, caddomain.ClassStuck), } out := atlas.ApplyStuckOverlay(stages, findings) if out[0].StuckCount != 1 || out[0].AwaitingCount != 0 { t.Fatalf("counts = stuck=%d awaiting=%d, want stuck=1 awaiting=0", out[0].StuckCount, out[0].AwaitingCount) } if len(out[0].Nodes) != 1 { t.Fatalf("want 1 node, got %d", len(out[0].Nodes)) } n := out[0].Nodes[0] if n.Cls != "stuck" { t.Errorf("Cls = %q, want %q", n.Cls, "stuck") } if n.URL == "" { t.Error("node has no URL locator") } if n.Title != "#190 armed_never_fired" { t.Errorf("Title = %q", n.Title) } } func TestApplyStuckOverlay_DoneNotClosedIsAwaitingHumanAtStage08(t *testing.T) { stages := []atlas.Stage{stage("STAGE 08", "stuck-badges")} findings := []caddomain.StuckFinding{ finding("mathias/cobalt-dingo", 19, caddomain.CategoryDoneNotClosed, caddomain.ClassAwaitingHuman), finding("mathias/cobalt-dingo", 16, caddomain.CategoryDoneNotClosed, caddomain.ClassAwaitingHuman), } out := atlas.ApplyStuckOverlay(stages, findings) if out[0].StuckCount != 0 || out[0].AwaitingCount != 2 { t.Fatalf("counts = stuck=%d awaiting=%d, want stuck=0 awaiting=2 — done_not_closed must never render as stuck", out[0].StuckCount, out[0].AwaitingCount) } for _, n := range out[0].Nodes { if n.Cls != "awaiting-human" { t.Errorf("node Cls = %q, want %q", n.Cls, "awaiting-human") } } } func TestApplyStuckOverlay_ExecutionCategoriesCollapseToStage05(t *testing.T) { stages := []atlas.Stage{stage("STAGE 05", "stuck-badges")} findings := []caddomain.StuckFinding{ finding("mathias/cobalt-dingo", 30, caddomain.CategoryCeilingHit, caddomain.ClassStuck), finding("mathias/cad-atlas", 10, caddomain.CategoryNearAttemptCap, caddomain.ClassStuck), finding("mathias/cobalt-dingo", 16, caddomain.CategoryReFireLoop, caddomain.ClassStuck), finding("mathias/cobalt-dingo", 41, caddomain.CategoryClaimedNeverRan, caddomain.ClassStuck), } out := atlas.ApplyStuckOverlay(stages, findings) if out[0].StuckCount != 4 { t.Fatalf("StuckCount = %d, want 4", out[0].StuckCount) } } func TestApplyStuckOverlay_NodesPrependedNotReplacingAuthoredContent(t *testing.T) { s := stage("STAGE 04", "stuck-badges") s.Nodes = []atlas.Node{{Title: "authored node"}} out := atlas.ApplyStuckOverlay([]atlas.Stage{s}, []caddomain.StuckFinding{ finding("mathias/brain-gardener", 190, caddomain.CategoryArmedNeverFired, caddomain.ClassStuck), }) if len(out[0].Nodes) != 2 { t.Fatalf("want 2 nodes (1 live + 1 authored), got %d", len(out[0].Nodes)) } if out[0].Nodes[len(out[0].Nodes)-1].Title != "authored node" { t.Errorf("authored node was not preserved: %+v", out[0].Nodes) } } func TestApplyStuckOverlay_DoesNotMutateInput(t *testing.T) { stages := []atlas.Stage{stage("STAGE 04", "stuck-badges")} _ = atlas.ApplyStuckOverlay(stages, []caddomain.StuckFinding{ finding("mathias/brain-gardener", 190, caddomain.CategoryArmedNeverFired, caddomain.ClassStuck), }) if len(stages[0].Nodes) != 0 { t.Fatalf("input slice was mutated: %+v", stages[0].Nodes) } }