Skip to content
go-libfossil Artifact [8a911d9939]
Login

Artifact [8a911d9939]

Artifact 8a911d99394d296fdb2fb87f6c7ffd85a8eacc00d2bc59565227282130e7fc38:


package conformance

import (
	"fmt"
	"strings"
)

func rsAPICases() []rsAPICase {
	var all []rsAPICase
	for _, table := range [][]rsAPICase{
		resolveCases(), resolveFormCases(), leafAPICases(), commitLeafCases(),
		branchAPICases(), writerAPICases(),
	} {
		all = append(all, table...)
	}
	for i := range all {
		all[i].Gap = repostateGaps[all[i].ID]
	}
	return all
}

// forked is c1 with two trunk children, a and b, b the newer; b closes
// itself when closed is set.
func forked(closed bool) []rsArt {
	var tags []string
	if closed {
		tags = []string{"+closed *"}
	}
	return []rsArt{
		checkin("c1", 1, nil, rsRoot...),
		checkin("a", 2, of("c1")),
		checkin("b", 3, of("c1"), tags...),
	}
}

// c2Prefix is the first n hex digits of chain's c2, which depends only on
// c1 and c2, so a script may use it before it is built.
func c2Prefix(n int) string { return rsBuild(chain()).hashes["c2"][:n] }

func resolveCases() []rsAPICase {
	return []rsAPICase{
		// Tagged later, c1 carries the newer tag row; c3 has the newer
		// check-in time, which is what the rule compares.
		resolves("repostate.8.2.event-mtime", "RS-8.2-1",
			with(chain(), control("t1", 8, "+sym-rel {c3}"), control("t2", 9, "+sym-rel {c1}")),
			"rel", "c3"),
		// c3 and c2 inherit sym-trunk from c1, with c1's tag time; only
		// their own times tell them apart.
		resolves("repostate.8.2.trunk-chain", "RS-8.2-1", []rsArt{
			checkin("c1", 1, nil, rsRoot...),
			checkin("c3", 9, of("c1")), checkin("c2", 2, of("c1")),
		}, "trunk", "c3"),
		resolves("repostate.8.2.closed-newer", "RS-8.2-2", forked(true), "trunk", "b"),
		// c2, the newest trunk check-in, has a child, so is no leaf.
		resolves("repostate.8.2.not-leaf", "RS-8.2-3", []rsArt{
			checkin("c1", 1, nil, rsRoot...),
			checkin("c2", 9, of("c1")), checkin("c3", 3, of("c2")),
		}, "trunk", "c2"),
		resolves("repostate.8.2.unknown", "RS-8.2-4", chain(), "nosuch", ""),
		resolves("repostate.8.2.no-trunk-sym", "RS-8.2-4",
			[]rsArt{checkin("c1", 1, nil), checkin("c2", 2, of("c1"))}, "trunk", ""),
		resolves("repostate.9.fork-symbol", "RS-9-2", forked(false), "trunk", "b"),
		{
			Case: Case{ID: "repostate.8.5.resolution-not-leaves", Req: "RS-8.5-1"},
			arts: forked(true),
			run: func(e *rsEnv) error {
				if err := resolves("", "", nil, "trunk", "b").run(e); err != nil {
					return err
				}
				return openLeaves("", "", nil, "trunk", "a").run(e)
			},
		},
	}
}

func resolveFormCases() []rsAPICase {
	release := with(chain(), control("t1", 8, "+sym-release {c3}"))
	// A tag named like c2's hash prefix, on c1.
	hexTag := with(chain(), control("t1", 8, "+sym-"+c2Prefix(6)+" {c1}"))
	mergedIn := []rsArt{
		checkin("c1", 1, nil, rsRoot...),
		checkin("b1", 2, of("c1"), rsFeat...),
		checkin("c2", 3, of("c1")),
		checkin("b2", 4, of("b1", "c2")),
		checkin("b3", 5, of("b2")),
	}
	return []rsAPICase{
		resolves("repostate.8.3.rid", "RS-8.3-1", chain(), "rid:{rid:c2}", "c2"),
		// Without the prefix the name would be read as c2's hash.
		resolves("repostate.8.3.tag-prefix", "RS-8.3-2", hexTag, "tag:"+c2Prefix(6), "c1"),
		// tip is the newest check-in on any branch, here b3 on feat.
		resolves("repostate.8.3.tip", "RS-8.3-3",
			with(branched(), checkin("b3", 6, of("b2"))), "tip", "b3"),
		resolves("repostate.8.3.root", "RS-8.3-5", branched(), "root:feat", "c1"),
		resolves("repostate.8.3.start", "RS-8.3-6",
			with(branched(), checkin("b3", 6, of("b2"))), "start:feat", "b1"),
		resolves("repostate.8.3.merge-in", "RS-8.3-7", mergedIn, "merge-in:feat", "c2"),
		resolves("repostate.8.3.name-timestamp", "RS-8.3-8", chain(),
			"trunk:2026-01-01T00:00:03", "c3"),
		resolves("repostate.8.3.hash-before-name", "RS-8.3-9", hexTag, c2Prefix(6), "c2"),
		resolves("repostate.8.3.ambiguous-prefix", "RS-8.3-10", ambiguous(), ambiguousPrefix(), ""),
		// fossil retries "release." but not a three-letter stem such as
		// "rel."; the case uses the longer name.
		resolves("repostate.8.3.trailing-punct", "RS-8.3-11", release, "release.", "c3"),
	}
}

// ambiguous is chain[:1] and a second root whose hash shares its first four
// hex digits with c1's: the comment is varied until it does.
func ambiguous() []rsArt {
	c1 := chain()[0]
	prefix := rsBuild([]rsArt{c1}).hashes["c1"][:4]
	for n := 0; n < 1<<22; n++ {
		twin := checkin("twin", 2, nil, rsRoot...)
		twin.body = strings.Replace(twin.body, "C twin", fmt.Sprintf("C twin%d", n), 1)
		if rsBuild([]rsArt{twin}).hashes["twin"][:4] == prefix {
			return []rsArt{c1, twin}
		}
	}
	panic("conformance: no artifact shares c1's hash prefix")
}

func ambiguousPrefix() string { return rsBuild(chain()[:1]).hashes["c1"][:4] }

func leafAPICases() []rsAPICase {
	forkedChain := with(chain(), checkin("f", 5, of("c3")))
	closedC4 := with(forkedChain, control("t", 9, "+closed {c4}"))
	return []rsAPICase{
		openLeaves("repostate.7.4.closed-leaf", "RS-7.4-1", closedC4, "trunk", "f"),
		openLeaves("repostate.7.4.reopened", "RS-7.4-1",
			with(closedC4, control("t2", 10, "-closed {c4}")), "trunk", "c4", "f"),
		openLeaves("repostate.7.5.branch-open-leaves", "RS-7.5-1", merged(), "feat", "b1"),
		// BranchLeaves selects a branch's members by their active branch
		// row: b2, which inherits feat, is on feat; c2, a leaf too, is not.
		openLeaves("repostate.6.1.branch-membership", "RS-6.1-1", branched(), "feat", "b2"),
		openLeaves("repostate.9.branch-not-open", "RS-9-3",
			with(branched(), control("t", 9, "+closed {b2}")), "feat"),
		wouldFork("repostate.7.5.ambiguity-non-leaf", "RS-7.5-2", forkedChain, "c3", false),
		wouldFork("repostate.7.5.ambiguity-open", "RS-7.5-3", forkedChain, "f", true),
		wouldFork("repostate.7.5.ambiguity-closed", "RS-7.5-3", closedC4, "f", false),
	}
}