1
2
3
4 package main
5
6 import (
7 "bytes"
8 "fmt"
9 "io"
10 "reflect"
11 "sort"
12 "strings"
13 "testing"
14 )
15
16 func TestDigraph(t *testing.T) {
17 const g1 = `
18 socks shoes
19 shorts pants
20 pants belt shoes
21 shirt tie sweater
22 sweater jacket
23 hat
24 `
25
26 const g2 = `
27 a b c
28 b d
29 c d
30 d c
31 e e
32 `
33
34 for _, test := range []struct {
35 name string
36 input string
37 cmd string
38 args []string
39 want string
40 }{
41 {"nodes", g1, "nodes", nil, "belt\nhat\njacket\npants\nshirt\nshoes\nshorts\nsocks\nsweater\ntie\n"},
42 {"reverse", g1, "reverse", []string{"jacket"}, "jacket\nshirt\nsweater\n"},
43 {"transpose", g1, "transpose", nil, "belt pants\njacket sweater\npants shorts\nshoes pants\nshoes socks\nsweater shirt\ntie shirt\n"},
44 {"forward", g1, "forward", []string{"socks"}, "shoes\nsocks\n"},
45 {"forward multiple args", g1, "forward", []string{"socks", "sweater"}, "jacket\nshoes\nsocks\nsweater\n"},
46 {"scss", g2, "sccs", nil, "c d\ne\n"},
47 {"scc", g2, "scc", []string{"d"}, "c\nd\n"},
48 {"succs", g2, "succs", []string{"a"}, "b\nc\n"},
49 {"succs-long-token", g2 + "x " + strings.Repeat("x", 96*1024), "succs", []string{"x"}, strings.Repeat("x", 96*1024) + "\n"},
50 {"preds", g2, "preds", []string{"c"}, "a\nd\n"},
51 {"preds multiple args", g2, "preds", []string{"c", "d"}, "a\nb\nc\nd\n"},
52 } {
53 t.Run(test.name, func(t *testing.T) {
54 stdin = strings.NewReader(test.input)
55 stdout = new(bytes.Buffer)
56 if err := digraph(test.cmd, test.args); err != nil {
57 t.Fatal(err)
58 }
59
60 got := stdout.(fmt.Stringer).String()
61 if got != test.want {
62 t.Errorf("digraph(%s, %s) = got %q, want %q", test.cmd, test.args, got, test.want)
63 }
64 })
65 }
66
67
68
69 }
70
71 func TestAllpaths(t *testing.T) {
72 for _, test := range []struct {
73 name string
74 in string
75 to string
76 want string
77 }{
78 {
79 name: "Basic",
80 in: "A B\nB C",
81 to: "B",
82 want: "A B\n",
83 },
84 {
85 name: "Long",
86 in: "A B\nB C\n",
87 to: "C",
88 want: "A B\nB C\n",
89 },
90 {
91 name: "Cycle Basic",
92 in: "A B\nB A",
93 to: "B",
94 want: "A B\nB A\n",
95 },
96 {
97 name: "Cycle Path Out",
98
99 in: "A B\nB A\nB C\nC D",
100 to: "C",
101 want: "A B\nB A\nB C\n",
102 },
103 {
104 name: "Cycle Path Out Further Out",
105
106 in: "A B\nB C\nC D\nC B\nD E",
107 to: "D",
108 want: "A B\nB C\nC B\nC D\n",
109 },
110 {
111 name: "Two Paths Basic",
112
113
114
115 in: "A B\nB C\nC E\nB D\nD E\nE F",
116 to: "E",
117 want: "A B\nB C\nB D\nC E\nD E\n",
118 },
119 {
120 name: "Two Paths With One Immediately From Start",
121
122
123
124 in: "A B\nA C\nB C\nB D",
125 to: "C",
126 want: "A B\nA C\nB C\n",
127 },
128 {
129 name: "Two Paths Further Up",
130
131
132
133 in: "A B\nA C\nB D\nC D\nD E\nE F",
134 to: "E",
135 want: "A B\nA C\nB D\nC D\nD E\n",
136 },
137 {
138
139
140
141 name: "Two Splits",
142
143
144
145 in: "A B\nA C\nB D\nC D\nD E\nD F\nE G\nF G\nG H",
146 to: "G",
147 want: "A B\nA C\nB D\nC D\nD E\nD F\nE G\nF G\n",
148 },
149 {
150
151 name: "Two Paths - Two Splits With Gap",
152
153
154
155 in: "A B\nA C\nB D\nC D\nD E\nE F\nE G\nF H\nG H\nH I",
156 to: "H",
157 want: "A B\nA C\nB D\nC D\nD E\nE F\nE G\nF H\nG H\n",
158 },
159 } {
160 t.Run(test.name, func(t *testing.T) {
161 stdin = strings.NewReader(test.in)
162 stdout = new(bytes.Buffer)
163 if err := digraph("allpaths", []string{"A", test.to}); err != nil {
164 t.Fatal(err)
165 }
166
167 got := stdout.(fmt.Stringer).String()
168 if got != test.want {
169 t.Errorf("digraph(allpaths, A, %s) = got %q, want %q", test.to, got, test.want)
170 }
171 })
172 }
173 }
174
175 func TestSomepath(t *testing.T) {
176 for _, test := range []struct {
177 name string
178 in string
179 to string
180
181
182 wantAnyOf string
183 }{
184 {
185 name: "Basic",
186 in: "A B\n",
187 to: "B",
188 wantAnyOf: "A B",
189 },
190 {
191 name: "Basic With Cycle",
192 in: "A B\nB A",
193 to: "B",
194 wantAnyOf: "A B",
195 },
196 {
197 name: "Two Paths",
198
199
200
201 in: "A B\nA C\nB D\nC D",
202 to: "D",
203 wantAnyOf: "A B\nB D|A C\nC D",
204 },
205 {
206 name: "Printed path is minimal",
207
208
209
210 in: "A D C1 B1\nD E\nC1 C2\nC2 E\nB1 B2\nB2 B3\nB3 E",
211 to: "E",
212 wantAnyOf: "A D\nD E",
213 },
214 } {
215 t.Run(test.name, func(t *testing.T) {
216 stdin = strings.NewReader(test.in)
217 stdout = new(bytes.Buffer)
218 if err := digraph("somepath", []string{"A", test.to}); err != nil {
219 t.Fatal(err)
220 }
221
222 got := stdout.(fmt.Stringer).String()
223 lines := strings.Split(got, "\n")
224 sort.Strings(lines)
225 got = strings.Join(lines[1:], "\n")
226
227 var oneMatch bool
228 for _, want := range strings.Split(test.wantAnyOf, "|") {
229 if got == want {
230 oneMatch = true
231 }
232 }
233 if !oneMatch {
234 t.Errorf("digraph(somepath, A, %s) = got %q, want any of\n%s", test.to, got, test.wantAnyOf)
235 }
236 })
237 }
238 }
239
240 func TestSplit(t *testing.T) {
241 for _, test := range []struct {
242 line string
243 want []string
244 }{
245 {`one "2a 2b" three`, []string{"one", "2a 2b", "three"}},
246 {`one tw"\n\x0a\u000a\012"o three`, []string{"one", "tw\n\n\n\no", "three"}},
247 } {
248 got, err := split(test.line)
249 if err != nil {
250 t.Errorf("split(%s) failed: %v", test.line, err)
251 }
252 if !reflect.DeepEqual(got, test.want) {
253 t.Errorf("split(%s) = %v, want %v", test.line, got, test.want)
254 }
255 }
256 }
257
258 func TestQuotedLength(t *testing.T) {
259 for _, test := range []struct {
260 input string
261 want int
262 }{
263 {`"abc"`, 5},
264 {`"abc"def`, 5},
265 {`"abc\"d"ef`, 8},
266 {`"\012\n\x0a\u000a\U0000000a"`, 28},
267 {"\"\xff\"", 3},
268 {`"\xff"`, 6},
269 } {
270 got, ok := quotedLength(test.input)
271 if !ok {
272 got = 0
273 }
274 if got != test.want {
275 t.Errorf("quotedLength(%s) = %d, want %d", test.input, got, test.want)
276 }
277 }
278
279
280 for _, input := range []string{
281 ``,
282 `a`,
283 `'a'`,
284 `"a`,
285 `"\0"`,
286 `"\x1"`,
287 `"\u000"`,
288 `"\U0000000"`,
289 `"\k"`,
290 "\"ab\nc\"",
291 } {
292 if n, ok := quotedLength(input); ok {
293 t.Errorf("quotedLength(%s) = %d, want !ok", input, n)
294 }
295 }
296 }
297
298 func TestFocus(t *testing.T) {
299 for _, test := range []struct {
300 name string
301 in string
302 focus string
303 want string
304 }{
305 {
306 name: "Basic",
307 in: "A B",
308 focus: "B",
309 want: "A B\n",
310 },
311 {
312 name: "Some Nodes Not Included",
313
314
315 in: "A B\nA C",
316 focus: "B",
317 want: "A B\n",
318 },
319 {
320 name: "Cycle In Path",
321
322 in: "A B\nB A\nB C",
323 focus: "C",
324 want: "A B\nB A\nB C\n",
325 },
326 {
327 name: "Cycle Out Of Path",
328
329 in: "A B\nB A\nB C",
330 focus: "C",
331 want: "A B\nB A\nB C\n",
332 },
333 {
334 name: "Complex",
335
336
337
338
339
340 in: "A B\nA C\nB D\nD F\nD E",
341 focus: "D",
342 want: "A B\nB D\nD E\nD F\n",
343 },
344 } {
345 t.Run(test.name, func(t *testing.T) {
346 stdin = strings.NewReader(test.in)
347 stdout = new(bytes.Buffer)
348 if err := digraph("focus", []string{test.focus}); err != nil {
349 t.Fatal(err)
350 }
351 got := stdout.(fmt.Stringer).String()
352 if got != test.want {
353 t.Errorf("digraph(focus, %s) = got %q, want %q", test.focus, got, test.want)
354 }
355 })
356 }
357 }
358
359 func TestToDot(t *testing.T) {
360 in := `a b c
361 b "d\"\\d"
362 c "d\"\\d"`
363 want := `digraph {
364 "a" -> "b";
365 "a" -> "c";
366 "b" -> "d\"\\d";
367 "c" -> "d\"\\d";
368 }
369 `
370 defer func(in io.Reader, out io.Writer) { stdin, stdout = in, out }(stdin, stdout)
371 stdin = strings.NewReader(in)
372 stdout = new(bytes.Buffer)
373 if err := digraph("to", []string{"dot"}); err != nil {
374 t.Fatal(err)
375 }
376 got := stdout.(fmt.Stringer).String()
377 if got != want {
378 t.Errorf("digraph(to, dot) = got %q, want %q", got, want)
379 }
380
381 }
382
View as plain text