package zitcli
import (
"bufio"
"context"
"maps"
"os"
"path/filepath"
"strings"
"testing"
)
// crosslink's lines line counts the file line before it, and "- -" is a
// binary file. A lines line with no file before it is malformed.
func TestParseCrosslinkLineCounts(t *testing.T) {
stream := "crosslink 1\n" +
"checkin bb22 893869787000 aa11\n" +
"comment 0\n\n" +
"file M src/main.c\nlines 12 3\n" +
"file A logo.png\nlines - -\n" +
"file D gone\\sname.txt\n" +
"end\n"
var got CrosslinkRecord
if err := parseCrosslink(bufio.NewReader(strings.NewReader(stream)),
func(r CrosslinkRecord) error { got = r; return nil }); err != nil {
t.Fatal(err)
}
want := map[string]LineCount{"src/main.c": {12, 3}, "logo.png": {-1, -1}}
if !maps.Equal(got.Lines, want) {
t.Errorf("FAIL: lines %v, want %v (the uncounted delete absent)", got.Lines, want)
}
bad := "crosslink 1\ncheckin dd44 900000000000\ncomment 0\n\nlines 1 2\nend\n"
if err := parseCrosslink(bufio.NewReader(strings.NewReader(bad)), func(CrosslinkRecord) error { return nil }); err == nil {
t.Error("FAIL: a lines line with no file before it was accepted")
}
}
// A live fold counts with numstat and a rebuild with crosslink; both
// must give the same numbers for the same check-in.
func TestNumStatAgreesWithCrosslink(t *testing.T) {
dir := testRepo(t, 1)
if err := os.WriteFile(filepath.Join(dir, "a.txt"), []byte("one\ntwo\nthree\n"), 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "b.bin"), []byte{0, 1, 2, 0}, 0o644); err != nil {
t.Fatal(err)
}
run(t, dir, "add", "b.bin")
run(t, dir, "commit", "-m", "edit a, add b")
z := New(dir)
tip, _, err := z.Info(context.Background(), "trunk")
if err != nil {
t.Fatal(err)
}
num, err := z.NumStat(context.Background(), tip)
if err != nil {
t.Fatal(err)
}
var cross map[string]LineCount
if err := z.Crosslink(func(r CrosslinkRecord) error {
if r.Hash == tip {
cross = r.Lines
}
return nil
}); err != nil {
t.Fatal(err)
}
if !maps.Equal(num, cross) || num["a.txt"] != (LineCount{3, 1}) || num["b.bin"] != (LineCount{-1, -1}) {
t.Errorf("FAIL: numstat %v, crosslink %v", num, cross)
}
}