1
2
3
4
5 package diff_test
6
7 import (
8 "bytes"
9 "math/rand"
10 "os"
11 "os/exec"
12 "path/filepath"
13 "reflect"
14 "strings"
15 "testing"
16 "unicode/utf8"
17
18 "golang.org/x/tools/internal/diff"
19 "golang.org/x/tools/internal/diff/difftest"
20 "golang.org/x/tools/internal/testenv"
21 )
22
23 func TestApply(t *testing.T) {
24 for _, tc := range difftest.TestCases {
25 t.Run(tc.Name, func(t *testing.T) {
26 got, err := diff.Apply(tc.In, tc.Edits)
27 if err != nil {
28 t.Fatalf("Apply(Edits) failed: %v", err)
29 }
30 if got != tc.Out {
31 t.Errorf("Apply(Edits): got %q, want %q", got, tc.Out)
32 }
33 if tc.LineEdits != nil {
34 got, err := diff.Apply(tc.In, tc.LineEdits)
35 if err != nil {
36 t.Fatalf("Apply(LineEdits) failed: %v", err)
37 }
38 if got != tc.Out {
39 t.Errorf("Apply(LineEdits): got %q, want %q", got, tc.Out)
40 }
41 }
42 })
43 }
44 }
45
46 func TestNEdits(t *testing.T) {
47 for _, tc := range difftest.TestCases {
48 edits := diff.Strings(tc.In, tc.Out)
49 got, err := diff.Apply(tc.In, edits)
50 if err != nil {
51 t.Fatalf("Apply failed: %v", err)
52 }
53 if got != tc.Out {
54 t.Fatalf("%s: got %q wanted %q", tc.Name, got, tc.Out)
55 }
56 if len(edits) < len(tc.Edits) {
57 t.Errorf("got %v, expected %v for %#v", edits, tc.Edits, tc)
58 }
59 }
60 }
61
62 func TestNRandom(t *testing.T) {
63 rand.Seed(1)
64 for i := 0; i < 1000; i++ {
65 a := randstr("abω", 16)
66 b := randstr("abωc", 16)
67 edits := diff.Strings(a, b)
68 got, err := diff.Apply(a, edits)
69 if err != nil {
70 t.Fatalf("Apply failed: %v", err)
71 }
72 if got != b {
73 t.Fatalf("%d: got %q, wanted %q, starting with %q", i, got, b, a)
74 }
75 }
76 }
77
78
79 func FuzzRoundTrip(f *testing.F) {
80 f.Fuzz(func(t *testing.T, a, b string) {
81 if !utf8.ValidString(a) || !utf8.ValidString(b) {
82 return
83 }
84 edits := diff.Strings(a, b)
85 got, err := diff.Apply(a, edits)
86 if err != nil {
87 t.Fatalf("Apply failed: %v", err)
88 }
89 if got != b {
90 t.Fatalf("applying diff(%q, %q) gives %q; edits=%v", a, b, got, edits)
91 }
92 })
93 }
94
95 func TestLineEdits(t *testing.T) {
96 for _, tc := range difftest.TestCases {
97 t.Run(tc.Name, func(t *testing.T) {
98 want := tc.LineEdits
99 if want == nil {
100 want = tc.Edits
101 }
102 got, err := diff.LineEdits(tc.In, tc.Edits)
103 if err != nil {
104 t.Fatalf("LineEdits: %v", err)
105 }
106 if !reflect.DeepEqual(got, want) {
107 t.Errorf("in=<<%s>>\nout=<<%s>>\nraw edits=%s\nline edits=%s\nwant: %s",
108 tc.In, tc.Out, tc.Edits, got, want)
109 }
110
111 fixed, err := diff.Apply(tc.In, got)
112 if err != nil {
113 t.Error(err)
114 }
115 if fixed != tc.Out {
116 t.Errorf("Apply(LineEdits): got %q, want %q", fixed, tc.Out)
117 }
118 })
119 }
120 }
121
122 func TestToUnified(t *testing.T) {
123 testenv.NeedsTool(t, "patch")
124 for _, tc := range difftest.TestCases {
125 t.Run(tc.Name, func(t *testing.T) {
126 unified, err := diff.ToUnified(difftest.FileA, difftest.FileB, tc.In, tc.Edits, diff.DefaultContextLines)
127 if err != nil {
128 t.Fatal(err)
129 }
130 if unified == "" {
131 return
132 }
133 orig := filepath.Join(t.TempDir(), "original")
134 err = os.WriteFile(orig, []byte(tc.In), 0644)
135 if err != nil {
136 t.Fatal(err)
137 }
138 temp := filepath.Join(t.TempDir(), "patched")
139 err = os.WriteFile(temp, []byte(tc.In), 0644)
140 if err != nil {
141 t.Fatal(err)
142 }
143 cmd := exec.Command("patch", "-p0", "-u", "-s", "-o", temp, orig)
144 cmd.Stdin = strings.NewReader(unified)
145 cmd.Stdout = new(bytes.Buffer)
146 cmd.Stderr = new(bytes.Buffer)
147 if err = cmd.Run(); err != nil {
148 t.Fatalf("%v: %q (%q) (%q)", err, cmd.String(),
149 cmd.Stderr, cmd.Stdout)
150 }
151 got, err := os.ReadFile(temp)
152 if err != nil {
153 t.Fatal(err)
154 }
155 if string(got) != tc.Out {
156 t.Errorf("applying unified failed: got\n%q, wanted\n%q unified\n%q",
157 got, tc.Out, unified)
158 }
159
160 })
161 }
162 }
163
164 func TestRegressionOld001(t *testing.T) {
165 a := "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage diff_test\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"golang.org/x/tools/gopls/internal/lsp/diff\"\n\t\"golang.org/x/tools/internal/diff/difftest\"\n\t\"golang.org/x/tools/gopls/internal/span\"\n)\n"
166
167 b := "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage diff_test\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/google/safehtml/template\"\n\t\"golang.org/x/tools/gopls/internal/lsp/diff\"\n\t\"golang.org/x/tools/internal/diff/difftest\"\n\t\"golang.org/x/tools/gopls/internal/span\"\n)\n"
168 diffs := diff.Strings(a, b)
169 got, err := diff.Apply(a, diffs)
170 if err != nil {
171 t.Fatalf("Apply failed: %v", err)
172 }
173 if got != b {
174 i := 0
175 for ; i < len(a) && i < len(b) && got[i] == b[i]; i++ {
176 }
177 t.Errorf("oops %vd\n%q\n%q", diffs, got, b)
178 t.Errorf("\n%q\n%q", got[i:], b[i:])
179 }
180 }
181
182 func TestRegressionOld002(t *testing.T) {
183 a := "n\"\n)\n"
184 b := "n\"\n\t\"golang.org/x//nnal/stack\"\n)\n"
185 diffs := diff.Strings(a, b)
186 got, err := diff.Apply(a, diffs)
187 if err != nil {
188 t.Fatalf("Apply failed: %v", err)
189 }
190 if got != b {
191 i := 0
192 for ; i < len(a) && i < len(b) && got[i] == b[i]; i++ {
193 }
194 t.Errorf("oops %vd\n%q\n%q", diffs, got, b)
195 t.Errorf("\n%q\n%q", got[i:], b[i:])
196 }
197 }
198
199
200 func randstr(s string, n int) string {
201 src := []rune(s)
202 x := make([]rune, n)
203 for i := 0; i < n; i++ {
204 x[i] = src[rand.Intn(len(src))]
205 }
206 return string(x)
207 }
208
View as plain text