--- /dev/null
+// Copyright 2018 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 expect_test
+
+import (
+ "bytes"
+ "go/token"
+ "io/ioutil"
+ "testing"
+
+ "golang.org/x/tools/go/expect"
+)
+
+func TestMarker(t *testing.T) {
+ for _, tt := range []struct {
+ filename string
+ expectNotes int
+ expectMarkers map[string]string
+ expectChecks map[string][]interface{}
+ }{
+ {
+ filename: "testdata/test.go",
+ expectNotes: 13,
+ expectMarkers: map[string]string{
+ "αSimpleMarker": "α",
+ "OffsetMarker": "β",
+ "RegexMarker": "γ",
+ "εMultiple": "ε",
+ "ζMarkers": "ζ",
+ "ηBlockMarker": "η",
+ "Declared": "η",
+ "Comment": "ι",
+ "LineComment": "someFunc",
+ "NonIdentifier": "+",
+ "StringMarker": "\"hello\"",
+ },
+ expectChecks: map[string][]interface{}{
+ "αSimpleMarker": nil,
+ "StringAndInt": {"Number %d", int64(12)},
+ "Bool": {true},
+ },
+ },
+ {
+ filename: "testdata/go.mod",
+ expectNotes: 2,
+ expectMarkers: map[string]string{
+ "αMarker": "αfake1α",
+ "βMarker": "require golang.org/modfile v0.0.0",
+ },
+ },
+ } {
+ t.Run(tt.filename, func(t *testing.T) {
+ content, err := ioutil.ReadFile(tt.filename)
+ if err != nil {
+ t.Fatal(err)
+ }
+ readFile := func(string) ([]byte, error) { return content, nil }
+
+ markers := make(map[string]token.Pos)
+ for name, tok := range tt.expectMarkers {
+ offset := bytes.Index(content, []byte(tok))
+ markers[name] = token.Pos(offset + 1)
+ end := bytes.Index(content[offset:], []byte(tok))
+ if end > 0 {
+ markers[name+"@"] = token.Pos(offset + end + 2)
+ }
+ }
+
+ fset := token.NewFileSet()
+ notes, err := expect.Parse(fset, tt.filename, content)
+ if err != nil {
+ t.Fatalf("Failed to extract notes: %v", err)
+ }
+ if len(notes) != tt.expectNotes {
+ t.Errorf("Expected %v notes, got %v", tt.expectNotes, len(notes))
+ }
+ for _, n := range notes {
+ switch {
+ case n.Args == nil:
+ // A //@foo note associates the name foo with the position of the
+ // first match of "foo" on the current line.
+ checkMarker(t, fset, readFile, markers, n.Pos, n.Name, n.Name)
+ case n.Name == "mark":
+ // A //@mark(name, "pattern") note associates the specified name
+ // with the position on the first match of pattern on the current line.
+ if len(n.Args) != 2 {
+ t.Errorf("%v: expected 2 args to mark, got %v", fset.Position(n.Pos), len(n.Args))
+ continue
+ }
+ ident, ok := n.Args[0].(expect.Identifier)
+ if !ok {
+ t.Errorf("%v: identifier, got %T", fset.Position(n.Pos), n.Args[0])
+ continue
+ }
+ checkMarker(t, fset, readFile, markers, n.Pos, string(ident), n.Args[1])
+
+ case n.Name == "check":
+ // A //@check(args, ...) note specifies some hypothetical action to
+ // be taken by the test driver and its expected outcome.
+ // In this test, the action is to compare the arguments
+ // against expectChecks.
+ if len(n.Args) < 1 {
+ t.Errorf("%v: expected 1 args to check, got %v", fset.Position(n.Pos), len(n.Args))
+ continue
+ }
+ ident, ok := n.Args[0].(expect.Identifier)
+ if !ok {
+ t.Errorf("%v: identifier, got %T", fset.Position(n.Pos), n.Args[0])
+ continue
+ }
+ args, ok := tt.expectChecks[string(ident)]
+ if !ok {
+ t.Errorf("%v: unexpected check %v", fset.Position(n.Pos), ident)
+ continue
+ }
+ if len(n.Args) != len(args)+1 {
+ t.Errorf("%v: expected %v args to check, got %v", fset.Position(n.Pos), len(args)+1, len(n.Args))
+ continue
+ }
+ for i, got := range n.Args[1:] {
+ if args[i] != got {
+ t.Errorf("%v: arg %d expected %v, got %v", fset.Position(n.Pos), i, args[i], got)
+ }
+ }
+ default:
+ t.Errorf("Unexpected note %v at %v", n.Name, fset.Position(n.Pos))
+ }
+ }
+ })
+ }
+}
+
+func checkMarker(t *testing.T, fset *token.FileSet, readFile expect.ReadFile, markers map[string]token.Pos, pos token.Pos, name string, pattern interface{}) {
+ start, end, err := expect.MatchBefore(fset, readFile, pos, pattern)
+ if err != nil {
+ t.Errorf("%v: MatchBefore failed: %v", fset.Position(pos), err)
+ return
+ }
+ if start == token.NoPos {
+ t.Errorf("%v: Pattern %v did not match", fset.Position(pos), pattern)
+ return
+ }
+ expectStart, ok := markers[name]
+ if !ok {
+ t.Errorf("%v: unexpected marker %v", fset.Position(pos), name)
+ return
+ }
+ if start != expectStart {
+ t.Errorf("%v: Expected %v got %v", fset.Position(pos), fset.Position(expectStart), fset.Position(start))
+ }
+ if expectEnd, ok := markers[name+"@"]; ok && end != expectEnd {
+ t.Errorf("%v: Expected end %v got %v", fset.Position(pos), fset.Position(expectEnd), fset.Position(end))
+ }
+}