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