Skip to content
quarry Artifact [4eef3b51aa]
Login

Artifact [4eef3b51aa]

Artifact 4eef3b51aa792018c494acdc7436b3ed31ace7d12788e27ba27dda55def4e461:


package markup

import "testing"

func closing(t *testing.T, text string) []string {
	t.Helper()
	var out []string
	for _, tok := range ClosingRefs(text) {
		out = append(out, tok.Canonical())
	}
	return out
}

// The three verbs, in the spellings a landing message actually uses.
func TestAClosingPhraseNamesItsTicket(t *testing.T) {
	// A bare hash canonicalizes bracketed — [hash] is the one spelling
	// every reference to it collapses to, so a pasted URL and a typed
	// hash never look like two references.
	for _, tc := range []struct{ text, want string }{
		{"zitcli: record every store subprocess. closes cafb1f21be", "[cafb1f21be]"},
		{"fixes cafb1f21be", "[cafb1f21be]"},
		{"resolves cafb1f21be", "[cafb1f21be]"},
		{"Closes cafb1f21be", "[cafb1f21be]"},
		{"CLOSES cafb1f21be", "[cafb1f21be]"},
		{"closes: cafb1f21be", "[cafb1f21be]"},
		{"closes  cafb1f21be", "[cafb1f21be]"},
		// Trailing punctuation is the sentence's, not the token's.
		{"closes cafb1f21be.", "[cafb1f21be]"},
		{"closes cafb1f21be, and tidies up", "[cafb1f21be]"},
	} {
		got := closing(t, tc.text)
		if len(got) != 1 || got[0] != tc.want {
			t.Errorf("FAIL: %q gave %v, want [%s]", tc.text, got, tc.want)
		}
	}
}

// The verb must govern the token. Prose that contains both words but
// points the reference somewhere else is not an instruction — and an
// accident here closes somebody's ticket.
func TestProseIsNotAnInstruction(t *testing.T) {
	for _, text := range []string{
		"this closes the gap that cafb1f21be describes",
		"closes the door",
		"a landing that closes",
		"see cafb1f21be for why this closes badly",
		"the ticket cafb1f21be says it closes on merge",
	} {
		if got := closing(t, text); len(got) != 0 {
			t.Errorf("FAIL: %q closed %v", text, got)
		}
	}
}

// Every spelling of a reference works, because the grammar is the same
// one the renderer links with: a reference that acts is one a reader
// can click.
func TestEverySpellingOfAReferenceCloses(t *testing.T) {
	for _, text := range []string{
		"closes cafb1f21be",
		"closes ticket/cafb1f21be",
		"closes [cafb1f21be]",
		"closes /r/quarry/ticket/cafb1f21be",
		"closes https://zeitforge.app/r/quarry/ticket/cafb1f21be",
	} {
		if got := closing(t, text); len(got) != 1 {
			t.Errorf("FAIL: %q gave %v, want one reference", text, got)
		}
	}
}

// Several tickets in one landing, each once however often it is named.
func TestManyTicketsAndNoDuplicates(t *testing.T) {
	got := closing(t, "closes cafb1f21be, fixes 8d5aa739f8 and closes cafb1f21be again")
	if len(got) != 2 {
		t.Fatalf("FAIL: got %v, want two distinct references", got)
	}
}

// A person and a chat line both parse as tokens and neither is a thing
// to close. Refused here rather than left for the caller to notice.
func TestAPersonIsNotClosable(t *testing.T) {
	for _, text := range []string{"closes @dmestas", "closes #412"} {
		if got := closing(t, text); len(got) != 0 {
			t.Errorf("FAIL: %q closed %v", text, got)
		}
	}
}

// Saying nothing closes nothing — the ordinary case for most landings.
func TestAnOrdinaryMessageClosesNothing(t *testing.T) {
	if got := closing(t, "csp: allow the page to state its own address"); len(got) != 0 {
		t.Errorf("FAIL: an ordinary message closed %v", got)
	}
	if got := closing(t, ""); len(got) != 0 {
		t.Errorf("FAIL: an empty message closed %v", got)
	}
}