+++ /dev/null
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-package main
-
-import (
- "bytes"
- "fmt"
- "reflect"
- "sort"
- "strings"
- "testing"
-)
-
-func TestDigraph(t *testing.T) {
- const g1 = `
-socks shoes
-shorts pants
-pants belt shoes
-shirt tie sweater
-sweater jacket
-hat
-`
-
- const g2 = `
-a b c
-b d
-c d
-d c
-`
-
- for _, test := range []struct {
- name string
- input string
- cmd string
- args []string
- want string
- }{
- {"nodes", g1, "nodes", nil, "belt\nhat\njacket\npants\nshirt\nshoes\nshorts\nsocks\nsweater\ntie\n"},
- {"reverse", g1, "reverse", []string{"jacket"}, "jacket\nshirt\nsweater\n"},
- {"transpose", g1, "transpose", nil, "belt pants\njacket sweater\npants shorts\nshoes pants\nshoes socks\nsweater shirt\ntie shirt\n"},
- {"forward", g1, "forward", []string{"socks"}, "shoes\nsocks\n"},
- {"forward multiple args", g1, "forward", []string{"socks", "sweater"}, "jacket\nshoes\nsocks\nsweater\n"},
- {"scss", g2, "sccs", nil, "a\nb\nc d\n"},
- {"scc", g2, "scc", []string{"d"}, "c\nd\n"},
- {"succs", g2, "succs", []string{"a"}, "b\nc\n"},
- {"preds", g2, "preds", []string{"c"}, "a\nd\n"},
- {"preds multiple args", g2, "preds", []string{"c", "d"}, "a\nb\nc\nd\n"},
- } {
- t.Run(test.name, func(t *testing.T) {
- stdin = strings.NewReader(test.input)
- stdout = new(bytes.Buffer)
- if err := digraph(test.cmd, test.args); err != nil {
- t.Fatal(err)
- }
-
- got := stdout.(fmt.Stringer).String()
- if got != test.want {
- t.Errorf("digraph(%s, %s) = got %q, want %q", test.cmd, test.args, got, test.want)
- }
- })
- }
-
- // TODO(adonovan):
- // - test somepath (it's nondeterministic).
- // - test errors
-}
-
-func TestAllpaths(t *testing.T) {
- for _, test := range []struct {
- name string
- in string
- to string // from is always "A"
- want string
- }{
- {
- name: "Basic",
- in: "A B\nB C",
- to: "B",
- want: "A B\n",
- },
- {
- name: "Long",
- in: "A B\nB C\n",
- to: "C",
- want: "A B\nB C\n",
- },
- {
- name: "Cycle Basic",
- in: "A B\nB A",
- to: "B",
- want: "A B\nB A\n",
- },
- {
- name: "Cycle Path Out",
- // A <-> B -> C -> D
- in: "A B\nB A\nB C\nC D",
- to: "C",
- want: "A B\nB A\nB C\n",
- },
- {
- name: "Cycle Path Out Further Out",
- // A -> B <-> C -> D -> E
- in: "A B\nB C\nC D\nC B\nD E",
- to: "D",
- want: "A B\nB C\nC B\nC D\n",
- },
- {
- name: "Two Paths Basic",
- // /-> C --\
- // A -> B -- -> E -> F
- // \-> D --/
- in: "A B\nB C\nC E\nB D\nD E\nE F",
- to: "E",
- want: "A B\nB C\nB D\nC E\nD E\n",
- },
- {
- name: "Two Paths With One Immediately From Start",
- // /-> B -+ -> D
- // A -- |
- // \-> C <+
- in: "A B\nA C\nB C\nB D",
- to: "C",
- want: "A B\nA C\nB C\n",
- },
- {
- name: "Two Paths Further Up",
- // /-> B --\
- // A -- -> D -> E -> F
- // \-> C --/
- in: "A B\nA C\nB D\nC D\nD E\nE F",
- to: "E",
- want: "A B\nA C\nB D\nC D\nD E\n",
- },
- {
- // We should include A - C - D even though it's further up the
- // second path than D (which would already be in the graph by
- // the time we get around to integrating the second path).
- name: "Two Splits",
- // /-> B --\ /-> E --\
- // A -- -> D -- -> G -> H
- // \-> C --/ \-> F --/
- in: "A B\nA C\nB D\nC D\nD E\nD F\nE G\nF G\nG H",
- to: "G",
- want: "A B\nA C\nB D\nC D\nD E\nD F\nE G\nF G\n",
- },
- {
- // D - E should not be duplicated.
- name: "Two Paths - Two Splits With Gap",
- // /-> B --\ /-> F --\
- // A -- -> D -> E -- -> H -> I
- // \-> C --/ \-> G --/
- in: "A B\nA C\nB D\nC D\nD E\nE F\nE G\nF H\nG H\nH I",
- to: "H",
- want: "A B\nA C\nB D\nC D\nD E\nE F\nE G\nF H\nG H\n",
- },
- } {
- t.Run(test.name, func(t *testing.T) {
- stdin = strings.NewReader(test.in)
- stdout = new(bytes.Buffer)
- if err := digraph("allpaths", []string{"A", test.to}); err != nil {
- t.Fatal(err)
- }
-
- got := stdout.(fmt.Stringer).String()
- if got != test.want {
- t.Errorf("digraph(allpaths, A, %s) = got %q, want %q", test.to, got, test.want)
- }
- })
- }
-}
-
-func TestSomepath(t *testing.T) {
- for _, test := range []struct {
- name string
- in string
- to string
- // somepath is non-deterministic, so we have to provide all the
- // possible options. Each option is separated with |.
- wantAnyOf string
- }{
- {
- name: "Basic",
- in: "A B\n",
- to: "B",
- wantAnyOf: "A B",
- },
- {
- name: "Basic With Cycle",
- in: "A B\nB A",
- to: "B",
- wantAnyOf: "A B",
- },
- {
- name: "Two Paths",
- // /-> B --\
- // A -- -> D
- // \-> C --/
- in: "A B\nA C\nB D\nC D",
- to: "D",
- wantAnyOf: "A B\nB D|A C\nC D",
- },
- } {
- t.Run(test.name, func(t *testing.T) {
- stdin = strings.NewReader(test.in)
- stdout = new(bytes.Buffer)
- if err := digraph("somepath", []string{"A", test.to}); err != nil {
- t.Fatal(err)
- }
-
- got := stdout.(fmt.Stringer).String()
- lines := strings.Split(got, "\n")
- sort.Strings(lines)
- got = strings.Join(lines[1:], "\n")
-
- var oneMatch bool
- for _, want := range strings.Split(test.wantAnyOf, "|") {
- if got == want {
- oneMatch = true
- }
- }
- if !oneMatch {
- t.Errorf("digraph(somepath, A, %s) = got %q, want any of\n%s", test.to, got, test.wantAnyOf)
- }
- })
- }
-}
-
-func TestSplit(t *testing.T) {
- for _, test := range []struct {
- line string
- want []string
- }{
- {`one "2a 2b" three`, []string{"one", "2a 2b", "three"}},
- {`one tw"\n\x0a\u000a\012"o three`, []string{"one", "tw\n\n\n\no", "three"}},
- } {
- got, err := split(test.line)
- if err != nil {
- t.Errorf("split(%s) failed: %v", test.line, err)
- }
- if !reflect.DeepEqual(got, test.want) {
- t.Errorf("split(%s) = %v, want %v", test.line, got, test.want)
- }
- }
-}
-
-func TestQuotedLength(t *testing.T) {
- for _, test := range []struct {
- input string
- want int
- }{
- {`"abc"`, 5},
- {`"abc"def`, 5},
- {`"abc\"d"ef`, 8}, // "abc\"d" is consumed, ef is residue
- {`"\012\n\x0a\u000a\U0000000a"`, 28},
- {"\"\xff\"", 3}, // bad UTF-8 is ok
- {`"\xff"`, 6}, // hex escape for bad UTF-8 is ok
- } {
- got, ok := quotedLength(test.input)
- if !ok {
- got = 0
- }
- if got != test.want {
- t.Errorf("quotedLength(%s) = %d, want %d", test.input, got, test.want)
- }
- }
-
- // errors
- for _, input := range []string{
- ``, // not a quotation
- `a`, // not a quotation
- `'a'`, // not a quotation
- `"a`, // not terminated
- `"\0"`, // short octal escape
- `"\x1"`, // short hex escape
- `"\u000"`, // short \u escape
- `"\U0000000"`, // short \U escape
- `"\k"`, // invalid escape
- "\"ab\nc\"", // newline
- } {
- if n, ok := quotedLength(input); ok {
- t.Errorf("quotedLength(%s) = %d, want !ok", input, n)
- }
- }
-}
-
-func TestFocus(t *testing.T) {
- for _, test := range []struct {
- name string
- in string
- focus string
- want string
- }{
- {
- name: "Basic",
- in: "A B",
- focus: "B",
- want: "A B\n",
- },
- {
- name: "Some Nodes Not Included",
- // C does not have a path involving B, and should not be included
- // in the output.
- in: "A B\nA C",
- focus: "B",
- want: "A B\n",
- },
- {
- name: "Cycle In Path",
- // A <-> B -> C
- in: "A B\nB A\nB C",
- focus: "C",
- want: "A B\nB A\nB C\n",
- },
- {
- name: "Cycle Out Of Path",
- // C <- A <->B
- in: "A B\nB A\nB C",
- focus: "C",
- want: "A B\nB A\nB C\n",
- },
- {
- name: "Complex",
- // Paths in and out from focus.
- // /-> F
- // /-> B -> D --
- // A -- \-> E
- // \-> C
- in: "A B\nA C\nB D\nD F\nD E",
- focus: "D",
- want: "A B\nB D\nD E\nD F\n",
- },
- } {
- t.Run(test.name, func(t *testing.T) {
- stdin = strings.NewReader(test.in)
- stdout = new(bytes.Buffer)
- if err := digraph("focus", []string{test.focus}); err != nil {
- t.Fatal(err)
- }
- got := stdout.(fmt.Stringer).String()
- if got != test.want {
- t.Errorf("digraph(focus, %s) = got %q, want %q", test.focus, got, test.want)
- }
- })
- }
-}