Skip to content
quarry Artifact [62bb688381]
Login

Artifact [62bb688381]

Artifact 62bb688381ac6f83a4518d654c2a2131c0e80272771276ef32a656f6e2600ac6:


package index

import (
	"testing"

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

func foldForum(t *testing.T, ix *Index, hash, root, parent, title, date string) {
	t.Helper()
	if err := ix.FoldNow([]Parsed{{Hash: hash, Art: &artifact.Artifact{
		Type: artifact.Forum, ThreadRoot: root, InReplyTo: parent,
		ThreadTitle: title, Date: date, User: "dan", Body: []byte("hi"),
	}}}); err != nil {
		t.Fatal(err)
	}
}

// Votes are keyed on full post hashes while pages link with prefixes;
// the resolver bridges the two and also answers which thread a post
// belongs to, so a vote row can carry its thread without trusting the
// form data.
func TestForumPostThreadResolvesPrefix(t *testing.T) {
	ix := openIndex(t)
	foldForum(t, ix, "aaaa1111", "", "", "hello", "2026-01-01T10:00:00")
	foldForum(t, ix, "bbbb2222", "aaaa1111", "aaaa1111", "", "2026-01-02T10:00:00")

	post, thread, ok, err := ix.ForumPostThread("bbbb")
	if err != nil || !ok {
		t.Fatalf("resolve reply: ok=%v err=%v", ok, err)
	}
	if post != "bbbb2222" || thread != "aaaa1111" {
		t.Fatalf("reply resolved to post=%q thread=%q", post, thread)
	}
	// An opener roots its own thread.
	if _, thread, _, _ := ix.ForumPostThread("aaaa"); thread != "aaaa1111" {
		t.Fatalf("opener thread = %q, want itself", thread)
	}
	if _, _, ok, err := ix.ForumPostThread("ffff"); ok || err != nil {
		t.Fatalf("absent prefix: ok=%v err=%v, want false nil", ok, err)
	}
}

func foldForumBody(t *testing.T, ix *Index, hash, root, title, date, body string) {
	t.Helper()
	if err := ix.FoldNow([]Parsed{{Hash: hash, Art: &artifact.Artifact{
		Type: artifact.Forum, ThreadRoot: root, ThreadTitle: title,
		Date: date, User: "dan", Body: []byte(body),
	}}}); err != nil {
		t.Fatal(err)
	}
}

// Anchors extract at fold and resolve only at query: the backlink query
// asks by the page's own full hash, so a stored ref surfaces exactly on
// the pages it prefixes — the honesty gate is structural.
func TestThreadsMentioning(t *testing.T) {
	ix := openIndex(t)
	const target = "4bd6301f22bd6301f22bd6301f22bd63"
	foldForumBody(t, ix, "aaaa1111", "", "Broken build", "2026-01-01T10:00:00",
		"bisected to [4bd6301f22] which landed yesterday")
	foldForumBody(t, ix, "bbbb2222", "", "Naming decade debate", "2026-01-02T10:00:00",
		"a decade of efface and facade — hexy words, no digits")
	foldForumBody(t, ix, "cccc3333", "aaaa1111", "", "2026-01-03T10:00:00",
		"also see deadbeef99 maybe")

	threads, err := ix.ThreadsMentioning(target)
	if err != nil {
		t.Fatal(err)
	}
	if len(threads) != 1 || threads[0].Root != "aaaa1111" {
		t.Fatalf("mentions of %s = %+v, want thread aaaa1111", target, threads)
	}
	if threads[0].Title != "Broken build" || threads[0].Posts != 2 {
		t.Fatalf("backlink row = %+v", threads[0])
	}
	// Hex-spelling English never anchors: no digits, no ref.
	if got, _ := ix.ThreadsMentioning("decade00decade00decade00"); len(got) != 0 {
		t.Fatalf("digit-free word anchored: %+v", got)
	}
	// A ref that prefixes nothing on this page stays silent.
	if got, _ := ix.ThreadsMentioning("ffffffffffffffff"); len(got) != 0 {
		t.Fatalf("unrelated hash has mentions: %+v", got)
	}
	// Re-folding the same post must not duplicate its anchors.
	foldForumBody(t, ix, "aaaa1111", "", "Broken build", "2026-01-01T10:00:00",
		"bisected to [4bd6301f22] which landed yesterday")
	if got, _ := ix.ThreadsMentioning(target); len(got) != 1 {
		t.Fatalf("re-fold duplicated anchors: %+v", got)
	}
}