1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 func TestDigraph(t *testing.T) {
32 for _, test := range []struct {
39 {"nodes", g1, "nodes", nil, "belt\nhat\njacket\npants\nshirt\nshoes\nshorts\nsocks\nsweater\ntie\n"},
40 {"reverse", g1, "reverse", []string{"jacket"}, "jacket\nshirt\nsweater\n"},
41 {"transpose", g1, "transpose", nil, "belt pants\njacket sweater\npants shorts\nshoes pants\nshoes socks\nsweater shirt\ntie shirt\n"},
42 {"forward", g1, "forward", []string{"socks"}, "shoes\nsocks\n"},
43 {"forward multiple args", g1, "forward", []string{"socks", "sweater"}, "jacket\nshoes\nsocks\nsweater\n"},
44 {"scss", g2, "sccs", nil, "a\nb\nc d\n"},
45 {"scc", g2, "scc", []string{"d"}, "c\nd\n"},
46 {"succs", g2, "succs", []string{"a"}, "b\nc\n"},
47 {"preds", g2, "preds", []string{"c"}, "a\nd\n"},
48 {"preds multiple args", g2, "preds", []string{"c", "d"}, "a\nb\nc\nd\n"},
50 t.Run(test.name, func(t *testing.T) {
51 stdin = strings.NewReader(test.input)
52 stdout = new(bytes.Buffer)
53 if err := digraph(test.cmd, test.args); err != nil {
57 got := stdout.(fmt.Stringer).String()
59 t.Errorf("digraph(%s, %s) = got %q, want %q", test.cmd, test.args, got, test.want)
65 // - test somepath (it's nondeterministic).
69 func TestAllpaths(t *testing.T) {
70 for _, test := range []struct {
73 to string // from is always "A"
95 name: "Cycle Path Out",
97 in: "A B\nB A\nB C\nC D",
99 want: "A B\nB A\nB C\n",
102 name: "Cycle Path Out Further Out",
103 // A -> B <-> C -> D -> E
104 in: "A B\nB C\nC D\nC B\nD E",
106 want: "A B\nB C\nC B\nC D\n",
109 name: "Two Paths Basic",
111 // A -> B -- -> E -> F
113 in: "A B\nB C\nC E\nB D\nD E\nE F",
115 want: "A B\nB C\nB D\nC E\nD E\n",
118 name: "Two Paths With One Immediately From Start",
122 in: "A B\nA C\nB C\nB D",
124 want: "A B\nA C\nB C\n",
127 name: "Two Paths Further Up",
129 // A -- -> D -> E -> F
131 in: "A B\nA C\nB D\nC D\nD E\nE F",
133 want: "A B\nA C\nB D\nC D\nD E\n",
136 // We should include A - C - D even though it's further up the
137 // second path than D (which would already be in the graph by
138 // the time we get around to integrating the second path).
140 // /-> B --\ /-> E --\
141 // A -- -> D -- -> G -> H
142 // \-> C --/ \-> F --/
143 in: "A B\nA C\nB D\nC D\nD E\nD F\nE G\nF G\nG H",
145 want: "A B\nA C\nB D\nC D\nD E\nD F\nE G\nF G\n",
148 // D - E should not be duplicated.
149 name: "Two Paths - Two Splits With Gap",
150 // /-> B --\ /-> F --\
151 // A -- -> D -> E -- -> H -> I
152 // \-> C --/ \-> G --/
153 in: "A B\nA C\nB D\nC D\nD E\nE F\nE G\nF H\nG H\nH I",
155 want: "A B\nA C\nB D\nC D\nD E\nE F\nE G\nF H\nG H\n",
158 t.Run(test.name, func(t *testing.T) {
159 stdin = strings.NewReader(test.in)
160 stdout = new(bytes.Buffer)
161 if err := digraph("allpaths", []string{"A", test.to}); err != nil {
165 got := stdout.(fmt.Stringer).String()
166 if got != test.want {
167 t.Errorf("digraph(allpaths, A, %s) = got %q, want %q", test.to, got, test.want)
173 func TestSomepath(t *testing.T) {
174 for _, test := range []struct {
178 // somepath is non-deterministic, so we have to provide all the
179 // possible options. Each option is separated with |.
189 name: "Basic With Cycle",
199 in: "A B\nA C\nB D\nC D",
201 wantAnyOf: "A B\nB D|A C\nC D",
204 t.Run(test.name, func(t *testing.T) {
205 stdin = strings.NewReader(test.in)
206 stdout = new(bytes.Buffer)
207 if err := digraph("somepath", []string{"A", test.to}); err != nil {
211 got := stdout.(fmt.Stringer).String()
212 lines := strings.Split(got, "\n")
214 got = strings.Join(lines[1:], "\n")
217 for _, want := range strings.Split(test.wantAnyOf, "|") {
223 t.Errorf("digraph(somepath, A, %s) = got %q, want any of\n%s", test.to, got, test.wantAnyOf)
229 func TestSplit(t *testing.T) {
230 for _, test := range []struct {
234 {`one "2a 2b" three`, []string{"one", "2a 2b", "three"}},
235 {`one tw"\n\x0a\u000a\012"o three`, []string{"one", "tw\n\n\n\no", "three"}},
237 got, err := split(test.line)
239 t.Errorf("split(%s) failed: %v", test.line, err)
241 if !reflect.DeepEqual(got, test.want) {
242 t.Errorf("split(%s) = %v, want %v", test.line, got, test.want)
247 func TestQuotedLength(t *testing.T) {
248 for _, test := range []struct {
254 {`"abc\"d"ef`, 8}, // "abc\"d" is consumed, ef is residue
255 {`"\012\n\x0a\u000a\U0000000a"`, 28},
256 {"\"\xff\"", 3}, // bad UTF-8 is ok
257 {`"\xff"`, 6}, // hex escape for bad UTF-8 is ok
259 got, ok := quotedLength(test.input)
263 if got != test.want {
264 t.Errorf("quotedLength(%s) = %d, want %d", test.input, got, test.want)
269 for _, input := range []string{
270 ``, // not a quotation
271 `a`, // not a quotation
272 `'a'`, // not a quotation
273 `"a`, // not terminated
274 `"\0"`, // short octal escape
275 `"\x1"`, // short hex escape
276 `"\u000"`, // short \u escape
277 `"\U0000000"`, // short \U escape
278 `"\k"`, // invalid escape
279 "\"ab\nc\"", // newline
281 if n, ok := quotedLength(input); ok {
282 t.Errorf("quotedLength(%s) = %d, want !ok", input, n)
287 func TestFocus(t *testing.T) {
288 for _, test := range []struct {
301 name: "Some Nodes Not Included",
302 // C does not have a path involving B, and should not be included
309 name: "Cycle In Path",
313 want: "A B\nB A\nB C\n",
316 name: "Cycle Out Of Path",
320 want: "A B\nB A\nB C\n",
324 // Paths in and out from focus.
329 in: "A B\nA C\nB D\nD F\nD E",
331 want: "A B\nB D\nD E\nD F\n",
334 t.Run(test.name, func(t *testing.T) {
335 stdin = strings.NewReader(test.in)
336 stdout = new(bytes.Buffer)
337 if err := digraph("focus", []string{test.focus}); err != nil {
340 got := stdout.(fmt.Stringer).String()
341 if got != test.want {
342 t.Errorf("digraph(focus, %s) = got %q, want %q", test.focus, got, test.want)