Skip to content
quarry Artifact [58af9f0b5d]
Login

Artifact [58af9f0b5d]

Artifact 58af9f0b5d3293e31c2612f3ea3b5762de5f7e146d6db7c36a16cfbbd0eac194:


package api

import (
	"path/filepath"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/artifact"
	"craftdesign.group/quarry/internal/index"
)

// ticketAt folds one ticket with the given status and returns its index.
func ticketAt(t *testing.T, id, status string) *index.Index {
	t.Helper()
	ix, err := index.Open(filepath.Join(t.TempDir(), "i.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { ix.Close() })
	if err := ix.FoldNow([]index.Parsed{{Hash: id, Art: &artifact.Artifact{
		Type: artifact.Ticket, TicketID: id, Date: "2026-09-01T10:00:00", User: "dan",
		Fields: []artifact.Field{{Name: "title", Value: "a thing"}, {Name: "status", Value: status}},
	}}}); err != nil {
		t.Fatal(err)
	}
	return ix
}

func closeIDs(repo string, ix *index.Index, title string) []string {
	var out []string
	for _, t := range ticketsToClose(repo, ix, index.LandingSummary{Title: title}) {
		out = append(out, t.ID)
	}
	return out
}

const openTicket = "cafb1f21be00000000000000000000000000000000000000000000000000abcd"

// The whole point: a landing that says it closes a ticket picks it.
func TestALandingPicksTheTicketItNames(t *testing.T) {
	ix := ticketAt(t, openTicket, "Open")
	got := closeIDs("quarry", ix, "zitcli: record every store subprocess. closes cafb1f21be")
	if len(got) != 1 || got[0] != openTicket {
		t.Errorf("FAIL: picked %v, want the named ticket", got)
	}
}

// A ticket somebody already closed is left exactly as they left it —
// re-closing would overwrite a resolution they chose with a generic one.
func TestAnAlreadyClosedTicketIsLeftAlone(t *testing.T) {
	ix := ticketAt(t, openTicket, "Closed")
	if got := closeIDs("quarry", ix, "closes cafb1f21be"); len(got) != 0 {
		t.Errorf("FAIL: picked %v, want nothing — it is already closed", got)
	}
}

// A reference that resolves to nothing is not an error and not a close:
// a landing cannot settle something by naming it.
func TestANameThatResolvesToNothingClosesNothing(t *testing.T) {
	ix := ticketAt(t, openTicket, "Open")
	if got := closeIDs("quarry", ix, "closes 0123456789ab"); len(got) != 0 {
		t.Errorf("FAIL: picked %v for a ticket that does not exist", got)
	}
}

// Another repository's ticket is never settled from here: it resolves
// against a store this caller may not even be able to read.
func TestAnotherRepositorysTicketIsNotClosed(t *testing.T) {
	ix := ticketAt(t, openTicket, "Open")
	if got := closeIDs("quarry", ix, "closes other:ticket/cafb1f21be"); len(got) != 0 {
		t.Errorf("FAIL: picked %v from another repository", got)
	}
	// Naming our OWN repository explicitly is still ours.
	if got := closeIDs("quarry", ix, "closes quarry:ticket/cafb1f21be"); len(got) != 1 {
		t.Errorf("FAIL: an explicit same-repository reference gave %v", got)
	}
}

// Prose that mentions a ticket without governing it settles nothing.
// The cost of getting this wrong is closing somebody's open work.
func TestProseDoesNotSettleAnything(t *testing.T) {
	ix := ticketAt(t, openTicket, "Open")
	for _, title := range []string{
		"see cafb1f21be for why",
		"this closes the gap that cafb1f21be describes",
		"landing-list-live: the queue follows the repository",
	} {
		if got := closeIDs("quarry", ix, title); len(got) != 0 {
			t.Errorf("FAIL: %q settled %v", title, got)
		}
	}
}

// The note left on the ticket says which branch settled it, so the
// close is traceable from the ticket rather than only from the landing.
func TestTheNoteNamesTheBranchThatSettledIt(t *testing.T) {
	l := index.LandingSummary{Branch: "zit-unattended", Target: "trunk"}
	note := "Closed by " + l.Branch + " landing on " + l.Target + " (" + shortHash("0e6de71dad35aaaa") + ")"
	for _, want := range []string{"zit-unattended", "trunk", "0e6de71dad35"} {
		if !strings.Contains(note, want) {
			t.Errorf("FAIL: the note does not name %s: %s", want, note)
		}
	}
}