golang.org/x/tools@v0.21.0/go/expect/expect_test.go (about)

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