~bigbes/sr-ht-compare

ref: eb87ed542adbba81c07706b367fd6aecc94317f6 sr-ht-compare/gitx/mapping_test.go -rw-r--r-- 4.3 KiB
eb87ed54 — bigbes authz: bootstrap the tests from ecoretest 9 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package gitx

import (
	"strings"
	"testing"

	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/filemode"
	"github.com/go-git/go-git/v5/plumbing/format/diff"
)

// --- fakes implementing the go-git diff interfaces for pure-function tests ---

type fakeFile struct{ path string }

func (f fakeFile) Hash() plumbing.Hash     { return plumbing.ZeroHash }
func (f fakeFile) Mode() filemode.FileMode { return filemode.Regular }
func (f fakeFile) Path() string            { return f.path }

type fakeChunk struct {
	content string
	op      diff.Operation
}

func (c fakeChunk) Content() string      { return c.content }
func (c fakeChunk) Type() diff.Operation { return c.op }

type fakeFilePatch struct {
	from, to diff.File
	binary   bool
	chunks   []diff.Chunk
}

func (f fakeFilePatch) IsBinary() bool                { return f.binary }
func (f fakeFilePatch) Files() (diff.File, diff.File) { return f.from, f.to }
func (f fakeFilePatch) Chunks() []diff.Chunk          { return f.chunks }

func file(p string) diff.File { return fakeFile{path: p} }

func TestMapFilePatches(t *testing.T) {
	add := func(s string) diff.Chunk { return fakeChunk{content: s, op: diff.Add} }
	del := func(s string) diff.Chunk { return fakeChunk{content: s, op: diff.Delete} }
	eq := func(s string) diff.Chunk { return fakeChunk{content: s, op: diff.Equal} }

	tests := []struct {
		name string
		fp   fakeFilePatch
		want FileChange
	}{
		{
			"added",
			fakeFilePatch{to: file("new.txt"), chunks: []diff.Chunk{add("a\nb\n")}},
			FileChange{Status: "A", Path: "new.txt", Additions: 2},
		},
		{
			"deleted",
			fakeFilePatch{from: file("gone.txt"), chunks: []diff.Chunk{del("x\n")}},
			FileChange{Status: "D", Path: "gone.txt", Deletions: 1},
		},
		{
			"modified",
			fakeFilePatch{
				from:   file("a.txt"),
				to:     file("a.txt"),
				chunks: []diff.Chunk{eq("ctx\n"), add("n\n"), del("o1\no2\n")},
			},
			FileChange{Status: "M", Path: "a.txt", Additions: 1, Deletions: 2},
		},
		{
			"renamed with edit",
			fakeFilePatch{
				from:   file("old.txt"),
				to:     file("new.txt"),
				chunks: []diff.Chunk{add("x\n"), del("y\n")},
			},
			FileChange{Status: "R", OldPath: "old.txt", Path: "new.txt", Additions: 1, Deletions: 1},
		},
		{
			"binary skips counts",
			fakeFilePatch{
				from:   file("img.bin"),
				to:     file("img.bin"),
				binary: true,
				chunks: []diff.Chunk{add("should be ignored\n")},
			},
			FileChange{Status: "M", Path: "img.bin", Binary: true},
		},
		{
			"unterminated final line counts as one",
			fakeFilePatch{to: file("f"), chunks: []diff.Chunk{add("noeol")}},
			FileChange{Status: "A", Path: "f", Additions: 1},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := mapFilePatches([]diff.FilePatch{tt.fp})
			if len(got) != 1 {
				t.Fatalf("len = %d, want 1", len(got))
			}
			if got[0] != tt.want {
				t.Errorf("got %+v, want %+v", got[0], tt.want)
			}
		})
	}

	t.Run("empty from and to is skipped", func(t *testing.T) {
		got := mapFilePatches([]diff.FilePatch{fakeFilePatch{}})
		if len(got) != 0 {
			t.Errorf("got %+v, want none", got)
		}
	})
}

func TestCutPatch(t *testing.T) {
	fileA := "diff --git a/a.txt b/a.txt\n@@ -1 +1 @@\n-x\n+y\n"
	fileB := "diff --git a/b.txt b/b.txt\n@@ -1 +1 @@\n-p\n+q\n"
	full := fileA + fileB

	t.Run("under limit unchanged", func(t *testing.T) {
		got, trunc := cutPatch(full, 1<<20)
		if trunc || got != full {
			t.Errorf("trunc=%v got=%q", trunc, got)
		}
	})

	t.Run("zero limit unchanged", func(t *testing.T) {
		got, trunc := cutPatch(full, 0)
		if trunc || got != full {
			t.Errorf("trunc=%v", trunc)
		}
	})

	t.Run("cut at file boundary drops torn file", func(t *testing.T) {
		// A limit that lands inside fileB must cut back to the end of fileA.
		limit := int64(len(fileA) + 10)
		got, trunc := cutPatch(full, limit)
		if !trunc {
			t.Fatalf("expected truncated")
		}
		if got != fileA {
			t.Errorf("got %q, want just fileA (no torn diff --git)", got)
		}
		if strings.Count(got, "diff --git") != 1 {
			t.Errorf("torn file leaked: %q", got)
		}
	})

	t.Run("single huge leading file cut hard at limit", func(t *testing.T) {
		huge := "diff --git a/big b/big\n" + strings.Repeat("+line\n", 1000)
		got, trunc := cutPatch(huge, 40)
		if !trunc {
			t.Fatalf("expected truncated")
		}
		if int64(len(got)) != 40 {
			t.Errorf("len = %d, want 40", len(got))
		}
	})
}