fork of go-gitdiff with jj support
1package gitdiff
2
3import (
4 "bytes"
5 "fmt"
6 "os"
7 "path/filepath"
8 "slices"
9 "testing"
10)
11
12func TestFormatRoundtrip(t *testing.T) {
13 patches := []struct {
14 File string
15 SkipTextCompare bool
16 }{
17 {File: "copy.patch"},
18 {File: "copy_modify.patch"},
19 {File: "delete.patch"},
20 {File: "mode.patch"},
21 {File: "mode_modify.patch"},
22 {File: "modify.patch"},
23 {File: "new.patch"},
24 {File: "new_empty.patch"},
25 {File: "new_mode.patch"},
26 {File: "rename.patch"},
27 {File: "rename_modify.patch"},
28
29 // Due to differences between Go's 'encoding/zlib' package and the zlib
30 // C library, binary patches cannot be compared directly as the patch
31 // data is slightly different when re-encoded by Go.
32 {File: "binary_modify.patch", SkipTextCompare: true},
33 {File: "binary_new.patch", SkipTextCompare: true},
34 {File: "binary_modify_nodata.patch"},
35 }
36
37 for _, patch := range patches {
38 t.Run(patch.File, func(t *testing.T) {
39 b, err := os.ReadFile(filepath.Join("testdata", "string", patch.File))
40 if err != nil {
41 t.Fatalf("failed to read patch: %v", err)
42 }
43
44 original := assertParseSingleFile(t, b, "patch")
45 str := original.String()
46
47 if !patch.SkipTextCompare {
48 if string(b) != str {
49 t.Errorf("incorrect patch text\nexpected: %q\n actual: %q\n", string(b), str)
50 }
51 }
52
53 reparsed := assertParseSingleFile(t, []byte(str), "formatted patch")
54 assertFilesEqual(t, original, reparsed)
55 })
56 }
57}
58
59func assertParseSingleFile(t *testing.T, b []byte, kind string) *File {
60 files, _, err := Parse(bytes.NewReader(b))
61 if err != nil {
62 t.Fatalf("failed to parse %s: %v", kind, err)
63 }
64 if len(files) != 1 {
65 t.Fatalf("expected %s to contain a single files, but found %d", kind, len(files))
66 }
67 return files[0]
68}
69
70func assertFilesEqual(t *testing.T, expected, actual *File) {
71 assertEqual(t, expected.OldName, actual.OldName, "OldName")
72 assertEqual(t, expected.NewName, actual.NewName, "NewName")
73
74 assertEqual(t, expected.IsNew, actual.IsNew, "IsNew")
75 assertEqual(t, expected.IsDelete, actual.IsDelete, "IsDelete")
76 assertEqual(t, expected.IsCopy, actual.IsCopy, "IsCopy")
77 assertEqual(t, expected.IsRename, actual.IsRename, "IsRename")
78
79 assertEqual(t, expected.OldMode, actual.OldMode, "OldMode")
80 assertEqual(t, expected.NewMode, actual.NewMode, "NewMode")
81
82 assertEqual(t, expected.OldOIDPrefix, actual.OldOIDPrefix, "OldOIDPrefix")
83 assertEqual(t, expected.NewOIDPrefix, actual.NewOIDPrefix, "NewOIDPrefix")
84 assertEqual(t, expected.Score, actual.Score, "Score")
85
86 if len(expected.TextFragments) == len(actual.TextFragments) {
87 for i := range expected.TextFragments {
88 prefix := fmt.Sprintf("TextFragments[%d].", i)
89 ef := expected.TextFragments[i]
90 af := actual.TextFragments[i]
91
92 assertEqual(t, ef.Comment, af.Comment, prefix+"Comment")
93
94 assertEqual(t, ef.OldPosition, af.OldPosition, prefix+"OldPosition")
95 assertEqual(t, ef.OldLines, af.OldLines, prefix+"OldLines")
96
97 assertEqual(t, ef.NewPosition, af.NewPosition, prefix+"NewPosition")
98 assertEqual(t, ef.NewLines, af.NewLines, prefix+"NewLines")
99
100 assertEqual(t, ef.LinesAdded, af.LinesAdded, prefix+"LinesAdded")
101 assertEqual(t, ef.LinesDeleted, af.LinesDeleted, prefix+"LinesDeleted")
102
103 assertEqual(t, ef.LeadingContext, af.LeadingContext, prefix+"LeadingContext")
104 assertEqual(t, ef.TrailingContext, af.TrailingContext, prefix+"TrailingContext")
105
106 if !slices.Equal(ef.Lines, af.Lines) {
107 t.Errorf("%sLines: expected %#v, actual %#v", prefix, ef.Lines, af.Lines)
108 }
109 }
110 } else {
111 t.Errorf("TextFragments: expected length %d, actual length %d", len(expected.TextFragments), len(actual.TextFragments))
112 }
113
114 assertEqual(t, expected.IsBinary, actual.IsBinary, "IsBinary")
115
116 if expected.BinaryFragment != nil {
117 if actual.BinaryFragment == nil {
118 t.Errorf("BinaryFragment: expected non-nil, actual is nil")
119 } else {
120 ef := expected.BinaryFragment
121 af := expected.BinaryFragment
122
123 assertEqual(t, ef.Method, af.Method, "BinaryFragment.Method")
124 assertEqual(t, ef.Size, af.Size, "BinaryFragment.Size")
125
126 if !slices.Equal(ef.Data, af.Data) {
127 t.Errorf("BinaryFragment.Data: expected %#v, actual %#v", ef.Data, af.Data)
128 }
129 }
130 } else if actual.BinaryFragment != nil {
131 t.Errorf("BinaryFragment: expected nil, actual is non-nil")
132 }
133
134 if expected.ReverseBinaryFragment != nil {
135 if actual.ReverseBinaryFragment == nil {
136 t.Errorf("ReverseBinaryFragment: expected non-nil, actual is nil")
137 } else {
138 ef := expected.ReverseBinaryFragment
139 af := expected.ReverseBinaryFragment
140
141 assertEqual(t, ef.Method, af.Method, "ReverseBinaryFragment.Method")
142 assertEqual(t, ef.Size, af.Size, "ReverseBinaryFragment.Size")
143
144 if !slices.Equal(ef.Data, af.Data) {
145 t.Errorf("ReverseBinaryFragment.Data: expected %#v, actual %#v", ef.Data, af.Data)
146 }
147 }
148 } else if actual.ReverseBinaryFragment != nil {
149 t.Errorf("ReverseBinaryFragment: expected nil, actual is non-nil")
150 }
151}
152
153func assertEqual[T comparable](t *testing.T, expected, actual T, name string) {
154 if expected != actual {
155 t.Errorf("%s: expected %#v, actual %#v", name, expected, actual)
156 }
157}