1// Copyright 2018 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.
4
5package expect_test
6
7import (
8	"bytes"
9	"go/token"
10	"io/ioutil"
11	"testing"
12
13	"golang.org/x/tools/go/expect"
14)
15
16func TestMarker(t *testing.T) {
17	const filename = "testdata/test.go"
18	content, err := ioutil.ReadFile(filename)
19	if err != nil {
20		t.Fatal(err)
21	}
22
23	const expectNotes = 11
24	expectMarkers := map[string]string{
25		"αSimpleMarker": "α",
26		"OffsetMarker":  "β",
27		"RegexMarker":   "γ",
28		"εMultiple":     "ε",
29		"ζMarkers":      "ζ",
30		"ηBlockMarker":  "η",
31		"Declared":      "η",
32		"Comment":       "ι",
33		"NonIdentifier": "+",
34	}
35	expectChecks := map[string][]interface{}{
36		"αSimpleMarker": nil,
37		"StringAndInt":  []interface{}{"Number %d", int64(12)},
38		"Bool":          []interface{}{true},
39	}
40
41	readFile := func(string) ([]byte, error) { return content, nil }
42	markers := make(map[string]token.Pos)
43	for name, tok := range expectMarkers {
44		offset := bytes.Index(content, []byte(tok))
45		markers[name] = token.Pos(offset + 1)
46		end := bytes.Index(content[offset+1:], []byte(tok))
47		if end > 0 {
48			markers[name+"@"] = token.Pos(offset + end + 2)
49		}
50	}
51
52	fset := token.NewFileSet()
53	notes, err := expect.Parse(fset, filename, nil)
54	if err != nil {
55		t.Fatalf("Failed to extract notes: %v", err)
56	}
57	if len(notes) != expectNotes {
58		t.Errorf("Expected %v notes, got %v", expectNotes, len(notes))
59	}
60	for _, n := range notes {
61		switch {
62		case n.Args == nil:
63			// A //@foo note associates the name foo with the position of the
64			// first match of "foo" on the current line.
65			checkMarker(t, fset, readFile, markers, n.Pos, n.Name, n.Name)
66		case n.Name == "mark":
67			// A //@mark(name, "pattern") note associates the specified name
68			// with the position on the first match of pattern on the current line.
69			if len(n.Args) != 2 {
70				t.Errorf("%v: expected 2 args to mark, got %v", fset.Position(n.Pos), len(n.Args))
71				continue
72			}
73			ident, ok := n.Args[0].(expect.Identifier)
74			if !ok {
75				t.Errorf("%v: identifier, got %T", fset.Position(n.Pos), n.Args[0])
76				continue
77			}
78			checkMarker(t, fset, readFile, markers, n.Pos, string(ident), n.Args[1])
79
80		case n.Name == "check":
81			// A //@check(args, ...) note specifies some hypothetical action to
82			// be taken by the test driver and its expected outcome.
83			// In this test, the action is to compare the arguments
84			// against expectChecks.
85			if len(n.Args) < 1 {
86				t.Errorf("%v: expected 1 args to check, got %v", fset.Position(n.Pos), len(n.Args))
87				continue
88			}
89			ident, ok := n.Args[0].(expect.Identifier)
90			if !ok {
91				t.Errorf("%v: identifier, got %T", fset.Position(n.Pos), n.Args[0])
92				continue
93			}
94			args, ok := expectChecks[string(ident)]
95			if !ok {
96				t.Errorf("%v: unexpected check %v", fset.Position(n.Pos), ident)
97				continue
98			}
99			if len(n.Args) != len(args)+1 {
100				t.Errorf("%v: expected %v args to check, got %v", fset.Position(n.Pos), len(args)+1, len(n.Args))
101				continue
102			}
103			for i, got := range n.Args[1:] {
104				if args[i] != got {
105					t.Errorf("%v: arg %d expected %v, got %v", fset.Position(n.Pos), i, args[i], got)
106				}
107			}
108		default:
109			t.Errorf("Unexpected note %v at %v", n.Name, fset.Position(n.Pos))
110		}
111	}
112}
113
114func checkMarker(t *testing.T, fset *token.FileSet, readFile expect.ReadFile, markers map[string]token.Pos, pos token.Pos, name string, pattern interface{}) {
115	start, end, err := expect.MatchBefore(fset, readFile, pos, pattern)
116	if err != nil {
117		t.Errorf("%v: MatchBefore failed: %v", fset.Position(pos), err)
118		return
119	}
120	if start == token.NoPos {
121		t.Errorf("%v: Pattern %v did not match", fset.Position(pos), pattern)
122		return
123	}
124	expectStart, ok := markers[name]
125	if !ok {
126		t.Errorf("%v: unexpected marker %v", fset.Position(pos), name)
127		return
128	}
129	if start != expectStart {
130		t.Errorf("%v: Expected %v got %v", fset.Position(pos), fset.Position(expectStart), fset.Position(start))
131	}
132	if expectEnd, ok := markers[name+"@"]; ok && end != expectEnd {
133		t.Errorf("%v: Expected end %v got %v", fset.Position(pos), fset.Position(expectEnd), fset.Position(end))
134	}
135}
136