package main import ( "strings" "testing" ) // A form-only version (to-be 55 ยง2.2, AC55): file-named sections get plain titles and links to files become references of // the one form, in one version a check proves changes only form; the old names stay as aliases; a part's review carries over; // nothing is written without commit, and a record waiting for its review is skipped. func TestAFormOnlyVersionChangesTheNamesAndTheLinksAndNothingElse(t *testing.T) { w, _ := ledgerWorld(t) r, _ := w.k.ReserveNumber("author@g14", KindResearch, "an effort") old := effortAsk(r.Number, StatusActive, Section{Name: "00-overview.md", Text: "What it is. See [the window](0276-merges-are-assembled-in-a-rolling-window-and-each-batch-is-delivered-by-one-walk-with-one-commit-per-repository.md) and [the plan](https://example.org/plan.md)."}, Section{Name: "01-open-questions.md", Text: "Is it [ready](../../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/01-findings.md)?"}) w.accepted(t, "author@g14", old) key := Key{KindResearch, r.Number} before := mustGet(t, w.k.Store, key) w.k.Store.(*ledgerStore).mu.Lock() versions := before.Versions w.k.Store.(*ledgerStore).mu.Unlock() dry, err := w.k.FormOnly("lead@g14", &key, false) if err != nil || len(dry) != 1 || dry[0].Renamed["00-overview.md"] != "Overview" || dry[0].Renamed["01-open-questions.md"] != "Open questions" || dry[0].Relinked != 2 { t.Fatalf("%v %+v", err, dry) } if e := mustGet(t, w.k.Store, key); e.Versions != versions { t.Fatal("a dry run wrote a version") } if _, err := w.k.FormOnly("", &key, true); err == nil { t.Fatal("an unproven caller wrote a form-only version") } done, err := w.k.FormOnly("lead@g14", &key, true) if err != nil || len(done) != 1 || done[0].Skipped != "" { t.Fatalf("%v %+v", err, done) } e := mustGet(t, w.k.Store, key) if e.Versions != versions+1 || e.Current.Status != StatusActive || e.Pending != nil || e.Current.Judging != nil { t.Fatalf("%d versions, %s", e.Versions, e.Current.Status) } got := e.Current if got.Sections[0].Name != "Overview" || got.Sections[1].Name != "Open questions" || !strings.Contains(got.Sections[0].Text, "[the window](ref:ADR%200276)") || !strings.Contains(got.Sections[0].Text, "(https://example.org/plan.md)") || !strings.Contains(got.Sections[1].Text, "[ready](ref:research%20045)") { t.Fatalf("%+v", got.Sections) } // get takes the old name as an alias, and the review of the parts carries over to the renamed parts. if got.Section("00-overview.md") != got.Sections[0].Text || got.Aliases["01-open-questions.md"] != "Open questions" { t.Fatalf("aliases %v", got.Aliases) } if len(got.Parts) != 3 || got.Parts[1].Part != "Overview" { t.Fatalf("parts %+v", got.Parts) } for _, p := range partsOf(got, w.k.linkedOf(t.Context(), got)) { if keptPart(got, p) == nil { t.Errorf("the part %q is judged again after a change of form", p.name) } } h, _ := w.k.History(key, 0, 0, 0) if last := h.Versions[len(h.Versions)-1]; !strings.HasPrefix(last.Why, "form only:") { t.Fatalf("%+v", last) } if len(w.said.of(EventFormed)) != 1 { t.Fatalf("events %v", w.said.events) } // Done: another run has nothing left to do; and the check refuses a change that is more than form. if again, _ := w.k.FormOnly("lead@g14", &key, true); len(again) != 0 { t.Fatalf("%+v", again) } more := e.Current.Clone() more.Sections[0].Text += " And more." if err := checkForm(e.Current, more, &FormChange{Relinked: 1}); err == nil { t.Fatal("a change of text passed as form") } moreLinks := old _ = moreLinks wrong, ch := formOf(&Record{Kind: KindResearch, Number: 1, Sections: []Section{{Name: "a.md", Text: "[x](0276-a.md)"}}}) wrong.Sections[0].Text = "[x](ref:ADR%200131)" if err := checkForm(&Record{Kind: KindResearch, Number: 1, Sections: []Section{{Name: "a.md", Text: "[x](0276-a.md)"}}}, wrong, ch); err == nil { t.Fatal("a link to another record passed as form") } }