package artifact
import "testing"
// A check-in in a sub-manifest store lists S cards where a flat one
// lists F, as every check-in of netbsd-src does. It is a manifest: read
// as one, the fold skips it without a parse, as it skips flat ones.
func TestAnSCardCheckinIsAManifest(t *testing.T) {
raw := []byte("C initial\\simport\n" +
"D 1993-03-21T09:45:37\n" +
"P 97a86ea938482eb15026533cdc560ca53c2e9039424db7747f2eb136f8f4d05e\n" +
"S Makefile 149872c845b50c8f542cd729ab2bae46cbd5f487f7c09fcf8a61e7cf6c324fe7\n" +
"U dmestas\n" +
"Z 00000000000000000000000000000000\n")
isM, decided := QuickIsManifest(raw)
if !decided || !isM {
t.Errorf("FAIL: an S-card check-in read as manifest=%v decided=%v", isM, decided)
}
}
// A tree check-in parses as the manifest it is: header, parents and the
// S run it lists in place of F cards. Refused, it fell to content and
// the live fold never saw the check-in (quarry ticket 431).
func TestAnSCardCheckinParses(t *testing.T) {
a := parseOK(t, "C tree\\scheck-in\n"+
"D 2026-11-12T10:00:00\n"+
"P "+h64+"\n"+
"S alpha/a.c "+h40+"\n"+
"S beta/b.c "+h64+"\n"+
"T *branch * trunk\n"+
"U ana\n")
if a.Type != Manifest {
t.Fatalf("FAIL: type %v, want a manifest", a.Type)
}
if a.Comment != "tree check-in" || a.Date != "2026-11-12T10:00:00" || a.User != "ana" ||
len(a.Parents) != 1 || a.Parents[0] != h64 || len(a.Tags) != 1 {
t.Errorf("FAIL: header read as %+v", a)
}
want := []File{{Name: "alpha/a.c", Hash: h40}, {Name: "beta/b.c", Hash: h64}}
if len(a.SubManifests) != 2 || a.SubManifests[0] != want[0] || a.SubManifests[1] != want[1] {
t.Errorf("FAIL: S run read as %+v, want %+v", a.SubManifests, want)
}
if len(a.Files) != 0 {
t.Errorf("FAIL: S cards read as F cards: %+v", a.Files)
}
if !t.Failed() {
t.Log("ok")
}
}
// A D-less node of the tree is a sub-manifest, interior (S) or leaf (F),
// never a check-in.
func TestATreeNodeIsASubManifest(t *testing.T) {
interior := parseOK(t, "S alpha/a.c "+h40+"\nS beta/b.c "+h64+"\n")
if interior.Type != SubManifest || len(interior.SubManifests) != 2 {
t.Errorf("FAIL: interior node read as %v with %d S cards", interior.Type, len(interior.SubManifests))
}
leaf := parseOK(t, "F alpha/a.c "+h40+"\nF alpha/b.c "+h64+" x\n")
if leaf.Type != SubManifest || len(leaf.Files) != 2 || leaf.Files[1].Perm != "x" {
t.Errorf("FAIL: leaf node read as %v with files %+v", leaf.Type, leaf.Files)
}
if !t.Failed() {
t.Log("ok")
}
}
func TestSubManifestRulesAreEnforced(t *testing.T) {
wantReject(t, "D 2026-11-12T10:00:00\nF a.c "+h40+"\nS b.c "+h40+"\n", "F and S in one check-in")
wantReject(t, "B "+h40+"\nD 2026-11-12T10:00:00\nS b.c "+h40+"\n", "B and S in one check-in")
wantReject(t, "F a.c "+h40+"\nS b.c "+h40+"\n", "F and S in one node")
wantReject(t, "F a.c\n", "hash-less F in a node")
wantReject(t, "S b.c "+h40+"\nS a.c "+h40+"\n", "S run descending")
wantReject(t, "S a.c "+h40+"\nS a.c "+h64+"\n", "S run repeating a name")
wantReject(t, "S a.c "+h40+" x\n", "S card with a third token")
wantReject(t, "S a.c nothex\n", "S card with a bad hash")
wantReject(t, "S ../a.c "+h40+"\n", "S card with a bad name")
wantReject(t, "C x\nS a.c "+h40+"\n", "C card in a node")
t.Log("ok")
}