Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / go / ast / astutil / enclosing_test.go
1 // Copyright 2013 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 astutil_test
6
7 // This file defines tests of PathEnclosingInterval.
8
9 // TODO(adonovan): exhaustive tests that run over the whole input
10 // tree, not just handcrafted examples.
11
12 import (
13         "bytes"
14         "fmt"
15         "go/ast"
16         "go/parser"
17         "go/token"
18         "strings"
19         "testing"
20
21         "golang.org/x/tools/go/ast/astutil"
22 )
23
24 // pathToString returns a string containing the concrete types of the
25 // nodes in path.
26 func pathToString(path []ast.Node) string {
27         var buf bytes.Buffer
28         fmt.Fprint(&buf, "[")
29         for i, n := range path {
30                 if i > 0 {
31                         fmt.Fprint(&buf, " ")
32                 }
33                 fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast."))
34         }
35         fmt.Fprint(&buf, "]")
36         return buf.String()
37 }
38
39 // findInterval parses input and returns the [start, end) positions of
40 // the first occurrence of substr in input.  f==nil indicates failure;
41 // an error has already been reported in that case.
42 //
43 func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *ast.File, start, end token.Pos) {
44         f, err := parser.ParseFile(fset, "<input>", input, 0)
45         if err != nil {
46                 t.Errorf("parse error: %s", err)
47                 return
48         }
49
50         i := strings.Index(input, substr)
51         if i < 0 {
52                 t.Errorf("%q is not a substring of input", substr)
53                 f = nil
54                 return
55         }
56
57         filePos := fset.File(f.Package)
58         return f, filePos.Pos(i), filePos.Pos(i + len(substr))
59 }
60
61 // Common input for following tests.
62 const input = `
63 // Hello.
64 package main
65 import "fmt"
66 func f() {}
67 func main() {
68         z := (x + y) // add them
69         f() // NB: ExprStmt and its CallExpr have same Pos/End
70 }
71 `
72
73 func TestPathEnclosingInterval_Exact(t *testing.T) {
74         // For the exact tests, we check that a substring is mapped to
75         // the canonical string for the node it denotes.
76         tests := []struct {
77                 substr string // first occurrence of this string indicates interval
78                 node   string // complete text of expected containing node
79         }{
80                 {"package",
81                         input[11 : len(input)-1]},
82                 {"\npack",
83                         input[11 : len(input)-1]},
84                 {"main",
85                         "main"},
86                 {"import",
87                         "import \"fmt\""},
88                 {"\"fmt\"",
89                         "\"fmt\""},
90                 {"\nfunc f() {}\n",
91                         "func f() {}"},
92                 {"x ",
93                         "x"},
94                 {" y",
95                         "y"},
96                 {"z",
97                         "z"},
98                 {" + ",
99                         "x + y"},
100                 {" :=",
101                         "z := (x + y)"},
102                 {"x + y",
103                         "x + y"},
104                 {"(x + y)",
105                         "(x + y)"},
106                 {" (x + y) ",
107                         "(x + y)"},
108                 {" (x + y) // add",
109                         "(x + y)"},
110                 {"func",
111                         "func f() {}"},
112                 {"func f() {}",
113                         "func f() {}"},
114                 {"\nfun",
115                         "func f() {}"},
116                 {" f",
117                         "f"},
118         }
119         for _, test := range tests {
120                 f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
121                 if f == nil {
122                         continue
123                 }
124
125                 path, exact := astutil.PathEnclosingInterval(f, start, end)
126                 if !exact {
127                         t.Errorf("PathEnclosingInterval(%q) not exact", test.substr)
128                         continue
129                 }
130
131                 if len(path) == 0 {
132                         if test.node != "" {
133                                 t.Errorf("PathEnclosingInterval(%q).path: got [], want %q",
134                                         test.substr, test.node)
135                         }
136                         continue
137                 }
138
139                 if got := input[path[0].Pos():path[0].End()]; got != test.node {
140                         t.Errorf("PathEnclosingInterval(%q): got %q, want %q (path was %s)",
141                                 test.substr, got, test.node, pathToString(path))
142                         continue
143                 }
144         }
145 }
146
147 func TestPathEnclosingInterval_Paths(t *testing.T) {
148         // For these tests, we check only the path of the enclosing
149         // node, but not its complete text because it's often quite
150         // large when !exact.
151         tests := []struct {
152                 substr string // first occurrence of this string indicates interval
153                 path   string // the pathToString(),exact of the expected path
154         }{
155                 {"// add",
156                         "[BlockStmt FuncDecl File],false"},
157                 {"(x + y",
158                         "[ParenExpr AssignStmt BlockStmt FuncDecl File],false"},
159                 {"x +",
160                         "[BinaryExpr ParenExpr AssignStmt BlockStmt FuncDecl File],false"},
161                 {"z := (x",
162                         "[AssignStmt BlockStmt FuncDecl File],false"},
163                 {"func f",
164                         "[FuncDecl File],false"},
165                 {"func f()",
166                         "[FuncDecl File],false"},
167                 {" f()",
168                         "[FuncDecl File],false"},
169                 {"() {}",
170                         "[FuncDecl File],false"},
171                 {"// Hello",
172                         "[File],false"},
173                 {" f",
174                         "[Ident FuncDecl File],true"},
175                 {"func ",
176                         "[FuncDecl File],true"},
177                 {"mai",
178                         "[Ident File],true"},
179                 {"f() // NB",
180                         "[CallExpr ExprStmt BlockStmt FuncDecl File],true"},
181         }
182         for _, test := range tests {
183                 f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
184                 if f == nil {
185                         continue
186                 }
187
188                 path, exact := astutil.PathEnclosingInterval(f, start, end)
189                 if got := fmt.Sprintf("%s,%v", pathToString(path), exact); got != test.path {
190                         t.Errorf("PathEnclosingInterval(%q): got %q, want %q",
191                                 test.substr, got, test.path)
192                         continue
193                 }
194         }
195 }