package api
import (
"context"
"errors"
"slices"
"testing"
"craftdesign.group/quarry/internal/zitcli"
)
// zit's current is the target and its other the branch; the forge says
// theirs and ours, and swaps them here and nowhere else — regions and
// blobs alike.
func TestConflictFileOfSaysOursForTheBranch(t *testing.T) {
cf := conflictFileOf(zitcli.MergeFile{Path: "f.txt", Kind: "text", Base: "b", Current: "c", Other: "o",
Mode: map[string]string{"base": "regular", "current": "regular", "other": "executable"},
Regions: []zitcli.MergeRegion{
{Kind: "current", Base: [2]int{0, 1}, Current: [2]int{0, 2}, Other: [2]int{0, 1}},
{Kind: "other", Base: [2]int{1, 1}, Current: [2]int{2, 2}, Other: [2]int{1, 3}},
{Kind: "conflict", Base: [2]int{1, 2}, Current: [2]int{2, 3}, Other: [2]int{3, 5}},
}})
if cf.Ours.Blob != "o" || cf.Theirs.Blob != "c" || cf.Base.Blob != "b" || cf.Ours.Mode != "executable" {
t.Errorf("FAIL: sides %+v %+v %+v", cf.Ours, cf.Theirs, cf.Base)
}
var kinds []string
for _, r := range cf.Regions {
kinds = append(kinds, r.Kind)
}
if !slices.Equal(kinds, []string{"theirs", "ours", "conflict"}) {
t.Errorf("FAIL: regions %v", kinds)
}
if r := cf.Regions[2]; r.Ours != (lineSpan{3, 5}) || r.Theirs != (lineSpan{2, 3}) {
t.Errorf("FAIL: a conflict's ranges are not swapped with its sides: %+v", r)
}
}
type fakeBlobs map[string]string
func (f fakeBlobs) ArtifactSize(_ context.Context, h string) (int, error) {
b, ok := f[h]
if !ok {
return 0, errors.New("no such blob")
}
return len(b), nil
}
func (f fakeBlobs) ArtifactRaw(_ context.Context, h string, max int) ([]byte, error) {
b, ok := f[h]
if !ok || len(b) > max {
return nil, errors.New("no")
}
return []byte(b), nil
}
// Each side's lines are read by its blob, as zit counts them; a side the
// other added has none; an oversized or unreadable side keeps the file
// listed but undrawn.
func TestReadConflictSides(t *testing.T) {
blobs := fakeBlobs{"o": "a\nB\n", "c": "a\nb\nc", "big": string(make([]byte, maxConflictBytes+1))}
cf := conflictFile{Ours: conflictSide{Blob: "o"}, Theirs: conflictSide{Blob: "c"}}
if why := readConflictSides(context.Background(), blobs, &cf); why != "" {
t.Fatalf("FAIL: %s", why)
}
if !slices.Equal(cf.Ours.Lines, []string{"a", "B"}) || !slices.Equal(cf.Theirs.Lines, []string{"a", "b", "c"}) || cf.Base.Lines != nil {
t.Errorf("FAIL: lines %q %q %q", cf.Ours.Lines, cf.Theirs.Lines, cf.Base.Lines)
}
if why := readConflictSides(context.Background(), blobs, &conflictFile{Ours: conflictSide{Blob: "big"}}); why != "too large" {
t.Errorf("FAIL: an oversized side gave %q", why)
}
if why := readConflictSides(context.Background(), blobs, &conflictFile{Ours: conflictSide{Blob: "gone"}}); why != "unreadable" {
t.Errorf("FAIL: a missing blob gave %q", why)
}
}