// 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)) } }