package common import ( "bufio" "slices" "strings" "testing" ) func newStringScanner(s string) *bufio.Scanner { return bufio.NewScanner(strings.NewReader(s)) } func TestAssociatedPRScanner(t *testing.T) { testTable := []struct { name string input string prs []BasicPR desc string }{ { "No PRs", "", []BasicPR{}, "", }, { "Single PRs", "Some header of the issue\n\nFollowed by some description\n\nPR: test/foo#4\n", []BasicPR{{Org: "test", Repo: "foo", Num: 4}}, "Some header of the issue\n\nFollowed by some description", }, { "Multiple PRs", "Some header of the issue\n\nFollowed by some description\nPR: test/foo#4\n\nPR: test/goo#5\n", []BasicPR{ {Org: "test", Repo: "foo", Num: 4}, {Org: "test", Repo: "goo", Num: 5}, }, "Some header of the issue\n\nFollowed by some description", }, { "Multiple PRs with whitespace", "Some header of the issue\n\n\tPR: test/goo#5\n\n Followed by some description\n \t PR: test/foo#4\n", []BasicPR{ {Org: "test", Repo: "foo", Num: 4}, {Org: "test", Repo: "goo", Num: 5}, }, "Some header of the issue\n\n\n Followed by some description", }, { "Multiple PRs with missing names and other special cases to ignore", "Some header of the issue\n\n\n\t PR: foobar#5 \n\t PR: rd/goo5 \n\t PR: test/#5 \n" + "\t PR: /goo#5 \n\t PR: test/goo# \n\t PR: test / goo # 10 \n\tPR: test/gool# 10 \n" + "\t PR: test/goo#5 \n\t\n Followed by some description\n\t PR: test/foo#4 \n\t\n\n", []BasicPR{ { Org: "test", Repo: "foo", Num: 4, }, { Org: "test", Repo: "goo", Num: 5, }, }, "Some header of the issue\n\n\n\t PR: foobar#5 \n\t PR: rd/goo5 \n\t PR: test/#5 \n" + "\t PR: /goo#5 \n\t PR: test/goo# \n\t PR: test / goo # 10 \n\tPR: test/gool# 10 \n" + "\t\n Followed by some description", }, } for _, test := range testTable { t.Run(test.name, func(t *testing.T) { desc, prs := ExtractDescriptionAndPRs(newStringScanner(test.input)) if len(prs) != len(test.prs) { t.Error("Unexpected length:", len(prs), "expected:", len(test.prs)) return } for _, p := range test.prs { if !slices.Contains(prs, p) { t.Error("missing expected PR", p) } } if desc != test.desc { t.Error("Desc output", len(desc), "!=", len(test.desc), ":", desc) } }) } } func TestAppendingPRsToDescription(t *testing.T) { testTable := []struct { name string desc string PRs []BasicPR output string }{ { "Append single PR to end of description", "something", []BasicPR{ {Org: "a", Repo: "b", Num: 100}, }, "something\n\nPR: a/b#100", }, { "Append multiple PR to end of description", "something", []BasicPR{ {Org: "a1", Repo: "b", Num: 100}, {Org: "a1", Repo: "c", Num: 100}, {Org: "a1", Repo: "c", Num: 101}, {Org: "b", Repo: "b", Num: 100}, {Org: "c", Repo: "b", Num: 100}, }, "something\n\nPR: a1/b#100\nPR: a1/c#100\nPR: a1/c#101\nPR: b/b#100\nPR: c/b#100", }, { "Append multiple sorted PR to end of description and remove dups", "something", []BasicPR{ {Org: "a1", Repo: "c", Num: 101}, {Org: "a1", Repo: "c", Num: 100}, {Org: "c", Repo: "b", Num: 100}, {Org: "b", Repo: "b", Num: 100}, {Org: "a1", Repo: "c", Num: 101}, {Org: "a1", Repo: "c", Num: 101}, {Org: "a1", Repo: "b", Num: 100}, }, "something\n\nPR: a1/b#100\nPR: a1/c#100\nPR: a1/c#101\nPR: b/b#100\nPR: c/b#100", }, } for _, test := range testTable { t.Run(test.name, func(t *testing.T) { d := AppendPRsToDescription(test.desc, test.PRs) if d != test.output { t.Error(len(d), "vs", len(test.output)) t.Error("unpected output", d) } }) } }