Skip to content
quarry Artifact [d8d853d088]
Login

Artifact [d8d853d088]

Artifact d8d853d08897b64108bfd693101e2f6e3b8edef49bad662cecab2545131c3f62:


package markup

import "testing"

func refIDs(refs []RefToken) []string {
	var out []string
	for _, r := range refs {
		out = append(out, r.ID)
	}
	return out
}

// addresses is the verb for work on a ticket that does not finish it.
// Same grammar, same link, and no effect on the ticket's state.
func TestAddressesParsesLikeClosesAndActsLikeNothing(t *testing.T) {
	const msg = "landings: the second half\n\naddresses a488d7fa42 and closes 0eafaa1984."
	if got := refIDs(AddressingRefs(msg)); len(got) != 1 || got[0] != "a488d7fa42" {
		t.Errorf("FAIL: addresses read %q, want [a488d7fa42]", got)
	}
	if got := refIDs(ClosingRefs(msg)); len(got) != 1 || got[0] != "0eafaa1984" {
		t.Errorf("FAIL: closes read %q, want [0eafaa1984]", got)
	}
}

// The two verbs never read each other's references. A landing that
// addresses a ticket must not close it, and that separation is the
// whole reason the second verb exists.
func TestTheTwoVerbsDoNotOverlap(t *testing.T) {
	if got := ClosingRefs("addresses a488d7fa42"); len(got) != 0 {
		t.Errorf("FAIL: an addresses was read as a close: %q", refIDs(got))
	}
	if got := AddressingRefs("closes a488d7fa42"); len(got) != 0 {
		t.Errorf("FAIL: a close was read as an addresses: %q", refIDs(got))
	}
}

// Same distance rule as closes: the reference must follow the verb, or
// prose that happens to contain both words would act.
func TestAddressesNeedsTheReferenceRightAfterTheVerb(t *testing.T) {
	if got := AddressingRefs("this addresses the gap that a488d7fa42 describes"); len(got) != 0 {
		t.Errorf("FAIL: prose was read as a declaration: %q", refIDs(got))
	}
	if got := refIDs(AddressingRefs("addresses: [a488d7fa42]")); len(got) != 1 || got[0] != "a488d7fa42" {
		t.Errorf("FAIL: the bracketed spelling read %q", got)
	}
}

// Adjacency is the safety, not a short verb list, so the tenses people
// actually write all count. A landing message in the past tense is the
// common case: "fixed a488d7fa42" is a reader plainly asking for the
// link, and refusing it bought nothing.
func TestEveryTenseOfTheClosingVerbsCounts(t *testing.T) {
	for _, verb := range []string{"close", "closes", "closed", "closing",
		"fix", "fixes", "fixed", "fixing", "resolve", "resolves", "resolved", "resolving"} {
		got := refIDs(ClosingRefs(verb + " a488d7fa42"))
		if len(got) != 1 || got[0] != "a488d7fa42" {
			t.Errorf("FAIL: %q did not close: %q", verb, got)
		}
		if other := AddressingRefs(verb + " a488d7fa42"); len(other) != 0 {
			t.Errorf("FAIL: %q also addressed: %q", verb, refIDs(other))
		}
	}
}

// The addressing set is wider on purpose and safe to be: a false
// positive links a ticket a reader can see is linked, where a false
// positive on a close shuts somebody's ticket.
func TestTheWaysToSayAddressesAllCount(t *testing.T) {
	for _, verb := range []string{"address", "addresses", "addressed", "addressing",
		"ref", "refs", "reference", "references", "referenced", "referencing",
		"part of", "relates to", "relate to", "related to", "relating to",
		"works on", "work on", "working on", "toward", "towards",
		"progress on", "progresses on", "contributes to", "contribute to"} {
		got := refIDs(AddressingRefs(verb + " a488d7fa42"))
		if len(got) != 1 || got[0] != "a488d7fa42" {
			t.Errorf("FAIL: %q did not address: %q", verb, got)
		}
		if other := ClosingRefs(verb + " a488d7fa42"); len(other) != 0 {
			t.Errorf("FAIL: %q also closed: %q", verb, refIDs(other))
		}
	}
}

// The words that precede a reference in ordinary prose are NOT
// declarations. The adjacency rule cannot help there, because the
// reference is the next token either way.
func TestProseWordsAreNotDeclarations(t *testing.T) {
	for _, prose := range []string{
		"see a488d7fa42 for the numbers",
		"re a488d7fa42",
		"waited for 3600000",
		"the fix for a488d7fa42 is elsewhere",
	} {
		if got := AddressingRefs(prose); len(got) != 0 {
			t.Errorf("FAIL: %q read as an addresses: %q", prose, refIDs(got))
		}
		if got := ClosingRefs(prose); len(got) != 0 {
			t.Errorf("FAIL: %q read as a close: %q", prose, refIDs(got))
		}
	}
}