|
1 | 1 | package main
|
2 | 2 |
|
3 | 3 | import (
|
4 |
| - "fmt" |
5 |
| - "os" |
| 4 | + "go/token" |
6 | 5 | "path/filepath"
|
7 | 6 | "strings"
|
8 | 7 | "testing"
|
9 | 8 |
|
10 |
| - "golang.org/x/tools/go/buildutil" |
| 9 | + "golang.org/x/tools/go/packages/packagestest" |
11 | 10 | )
|
12 | 11 |
|
13 | 12 | func TestIdent(t *testing.T) {
|
14 |
| - cleanup := setGopath(filepath.Join(".", "testdata", "package"), t) |
15 |
| - defer cleanup() |
16 |
| - filename := filepath.Join(".", "testdata", "package", "src", "somepkg", "idents.go") |
17 |
| - |
18 |
| - tests := []struct { |
19 |
| - Pos int |
20 |
| - Doc string |
21 |
| - Decl string |
22 |
| - }{ |
23 |
| - {Pos: 146, Doc: "IsNaN reports whether f is an IEEE 754 ``not-a-number'' value.\n", Decl: "func IsNaN(f float64) (is bool)"}, // std func call (alias import) |
24 |
| - {Pos: 190, Doc: "SayHello says hello.\n", Decl: "func (X) SayHello()"}, // method call |
25 |
| - {Pos: 202, Doc: "SayGoodbye says goodbye.\n", Decl: "func SayGoodbye() (string, error)"}, // function call |
26 |
| - {Pos: 319, Doc: "Message is a message.\n", Decl: "var Message string"}, // var (use) |
27 |
| - {Pos: 415, Doc: "Message is a message.\n"}, // var (definition) |
28 |
| - {Pos: 329, Doc: "Sprintf formats according to a format specifier and returns the resulting string.\n"}, // std func |
29 |
| - {Pos: 358, Doc: "Answer is the answer to life the universe and everything.\n\nConstant Value: 42", Decl: "const Answer untyped int"}, // const (use) |
30 |
| - {Pos: 510, Doc: "Answer is the answer to life the universe and everything.\n\nConstant Value: 42"}, // const (definition) |
31 |
| - |
32 |
| - // field doc/comment precedence |
33 |
| - {Pos: 656, Doc: "FieldA has doc\n", Decl: "field FieldA string"}, |
34 |
| - {Pos: 665, Doc: "FieldB has a comment\n"}, |
35 |
| - |
36 |
| - // GenDecl doc/comment precedence |
37 |
| - {Pos: 1017, Doc: "Alpha doc", Decl: "var Alpha int"}, |
38 |
| - {Pos: 1032, Doc: "Bravo comment", Decl: "var Bravo int"}, |
39 |
| - |
40 |
| - // builtins |
41 |
| - {Pos: 975, Doc: "The error built-in interface type is the conventional"}, |
42 |
| - {Pos: 735, Doc: "The append built-in function appends elements to the end", Decl: "func append(slice []Type, elems ...Type) []Type"}, |
43 |
| - {Pos: 762, Doc: "float32 is the set of all IEEE-754 32-bit floating-point numbers."}, |
44 |
| - {Pos: 821, Doc: "iota is a predeclared identifier representing the untyped integer ordinal"}, |
45 |
| - {Pos: 864, Doc: "nil is a predeclared identifier representing the zero"}, |
46 |
| - {Pos: 914, Doc: "The len built-in function returns the length of v"}, |
47 |
| - {Pos: 950, Doc: "The close built-in function closes a channel, which must"}, |
48 |
| - |
49 |
| - // type spec |
50 |
| - {Pos: 53, Decl: "type X struct{}"}, |
51 |
| - {Pos: 1222, Decl: "type NewString string"}, |
| 13 | + dir := filepath.Join(".", "testdata", "package") |
| 14 | + mods := []packagestest.Module{ |
| 15 | + {Name: "somepkg", Files: packagestest.MustCopyFileTree(dir)}, |
52 | 16 | }
|
53 | 17 |
|
54 |
| - for _, test := range tests { |
55 |
| - t.Run(fmt.Sprintf("ident pos %d", test.Pos), func(t *testing.T) { |
56 |
| - doc, err := Run(filename, test.Pos, nil) |
57 |
| - if err != nil { |
58 |
| - t.Fatal(err) |
59 |
| - } |
60 |
| - if !strings.HasPrefix(doc.Doc, test.Doc) { |
61 |
| - t.Errorf("Want %q, got %q\n", test.Doc, doc.Doc) |
62 |
| - } |
63 |
| - if test.Decl != "" && doc.Decl != test.Decl { |
64 |
| - t.Errorf("Decl: want %q, got %q\n", test.Decl, doc.Decl) |
65 |
| - } |
66 |
| - }) |
67 |
| - } |
68 |
| -} |
69 |
| - |
70 |
| -func TestModified(t *testing.T) { |
71 |
| - cleanup := setGopath(filepath.Join(".", "testdata", "package"), t) |
72 |
| - defer cleanup() |
73 |
| - |
74 |
| - filename := filepath.Join(".", "testdata", "package", "src", "somepkg", "const.go") |
75 |
| - path, err := filepath.Abs(filename) |
76 |
| - if err != nil { |
77 |
| - t.Fatal(err) |
78 |
| - } |
79 |
| - contents := `package somepkg |
80 |
| -
|
81 |
| -import "fmt" |
82 |
| -
|
83 |
| -const ( |
84 |
| - Zero = iota |
85 |
| - One |
86 |
| - Two |
87 |
| -) |
88 |
| -
|
89 |
| -const Three = 3 |
90 |
| -
|
91 |
| -func main() { |
92 |
| - fmt.Println(Zero, Three, Two, Three) |
93 |
| -} |
94 |
| -` |
95 |
| - archive := fmt.Sprintf("%s\n%d\n%s", path, len(contents), contents) |
96 |
| - overlay, err := buildutil.ParseOverlayArchive(strings.NewReader(archive)) |
97 |
| - if err != nil { |
98 |
| - t.Fatalf("couldn't parse overlay: %v", err) |
99 |
| - } |
100 |
| - |
101 |
| - d, err := Run(path, 118, overlay) |
102 |
| - if err != nil { |
103 |
| - t.Fatal(err) |
104 |
| - } |
105 |
| - if n := d.Name; n != "Three" { |
106 |
| - t.Errorf("got const %s, want Three", n) |
107 |
| - } |
108 |
| -} |
109 |
| - |
110 |
| -func TestConstantValue(t *testing.T) { |
111 |
| - cleanup := setGopath(filepath.Join(".", "testdata", "package"), t) |
112 |
| - defer cleanup() |
113 |
| - filename := filepath.Join(".", "testdata", "package", "src", "somepkg", "const.go") |
114 |
| - |
115 |
| - for _, offset := range []int{111, 116, 121, 128} { |
116 |
| - doc, err := Run(filename, offset, nil) |
117 |
| - if err != nil { |
118 |
| - t.Error(err) |
| 18 | + packagestest.TestAll(t, func(t *testing.T, exporter packagestest.Exporter) { |
| 19 | + if exporter == packagestest.Modules { |
| 20 | + return // TODO get working with Modules and GOPATH |
119 | 21 | }
|
120 |
| - if !strings.Contains(doc.Doc, "Constant Value:") { |
121 |
| - t.Errorf("Expected doc to contain constant value: %q", doc.Doc) |
122 |
| - } |
123 |
| - } |
124 |
| -} |
| 22 | + exported := packagestest.Export(t, exporter, mods) |
| 23 | + defer exported.Cleanup() |
125 | 24 |
|
126 |
| -func TestUnexportedFields(t *testing.T) { |
127 |
| - cleanup := setGopath(filepath.Join(".", "testdata", "package"), t) |
128 |
| - defer cleanup() |
129 |
| - filename := filepath.Join(".", "testdata", "package", "src", "somepkg", "idents.go") |
| 25 | + teardown := setup(exported.Config) |
| 26 | + defer teardown() |
130 | 27 |
|
131 |
| - for _, showUnexported := range []bool{true, false} { |
132 |
| - *showUnexportedFields = showUnexported |
133 |
| - doc, err := Run(filename, 1085, nil) |
134 |
| - if err != nil { |
135 |
| - t.Fatalf("showUnexportedFields=%v: %v", showUnexported, err) |
136 |
| - } |
137 |
| - hasUnexportedField := strings.Contains(doc.Decl, "notVisible") |
138 |
| - if hasUnexportedField != *showUnexportedFields { |
139 |
| - t.Errorf("show unexported fields is %v, but got %q", showUnexported, doc.Decl) |
140 |
| - } |
141 |
| - } |
142 |
| -} |
143 |
| - |
144 |
| -func TestEmbeddedTypes(t *testing.T) { |
145 |
| - cleanup := setGopath(filepath.Join(".", "testdata", "package"), t) |
146 |
| - defer cleanup() |
147 |
| - filename := filepath.Join(".", "testdata", "package", "src", "somepkg", "embed.go") |
148 |
| - |
149 |
| - tests := []struct { |
150 |
| - description string |
151 |
| - offset int |
152 |
| - want string |
153 |
| - }{ |
154 |
| - {"embedded value", 77, "foo doc\n"}, |
155 |
| - {"embedded pointer", 113, "foo doc\n"}, |
156 |
| - } |
157 |
| - |
158 |
| - for _, test := range tests { |
159 |
| - t.Run(test.description, func(t *testing.T) { |
160 |
| - doc, err := Run(filename, test.offset, nil) |
161 |
| - if err != nil { |
162 |
| - t.Fatal(err) |
163 |
| - } |
164 |
| - if doc.Doc != test.want { |
165 |
| - t.Errorf("want %q, got %q", test.want, doc.Doc) |
| 28 | + getDoc := func(p token.Position) *Doc { |
| 29 | + t.Helper() |
| 30 | + doc, docErr := Run(p.Filename, p.Offset, nil) |
| 31 | + if docErr != nil { |
| 32 | + t.Fatal(docErr) |
166 | 33 | }
|
167 |
| - if doc.Pkg != "somepkg" { |
168 |
| - t.Errorf("want package somepkg, got %q", doc.Pkg) |
169 |
| - } |
170 |
| - }) |
171 |
| - } |
172 |
| -} |
173 |
| - |
174 |
| -func TestIssue20(t *testing.T) { |
175 |
| - cleanup := setGopath(filepath.Join(".", "testdata", "package"), t) |
176 |
| - defer cleanup() |
177 |
| - filename := filepath.Join(".", "testdata", "package", "src", "somepkg", "issue20.go") |
| 34 | + return doc |
| 35 | + } |
178 | 36 |
|
179 |
| - tests := []struct { |
180 |
| - desc string |
181 |
| - want string |
182 |
| - offset int |
183 |
| - }{ |
184 |
| - {"named type", "var words []string", 116}, |
185 |
| - {"unnamed type", "var tests []struct{Name string; args string}", 283}, |
186 |
| - } |
187 |
| - for _, test := range tests { |
188 |
| - t.Run(test.desc, func(t *testing.T) { |
189 |
| - doc, err := Run(filename, test.offset, nil) |
190 |
| - if err != nil { |
191 |
| - t.Fatal(err) |
| 37 | + pcmp := func(want, got string) { |
| 38 | + t.Helper() |
| 39 | + if !strings.HasPrefix(got, want) { |
| 40 | + if len(got) > 64 { |
| 41 | + got = got[:64] |
| 42 | + } |
| 43 | + t.Errorf("expected prefix %q in %q", want, got) |
192 | 44 | }
|
| 45 | + } |
193 | 46 |
|
194 |
| - if doc.Decl != test.want { |
195 |
| - t.Errorf("want %s, got %s", test.want, doc.Decl) |
| 47 | + cmp := func(want, got string) { |
| 48 | + t.Helper() |
| 49 | + if got != want { |
| 50 | + t.Errorf("want %q, got %q", want, got) |
196 | 51 | }
|
| 52 | + } |
197 | 53 |
|
198 |
| - if doc.Doc != "" { |
199 |
| - t.Errorf("expect doc to be empty, but got %q", doc.Doc) |
200 |
| - } |
201 |
| - }) |
202 |
| - } |
| 54 | + if expectErr := exported.Expect(map[string]interface{}{ |
| 55 | + "doc": func(p token.Position, doc string) { pcmp(doc, getDoc(p).Doc) }, |
| 56 | + "pkg": func(p token.Position, pkg string) { cmp(pkg, getDoc(p).Pkg) }, |
| 57 | + "decl": func(p token.Position, decl string) { cmp(decl, getDoc(p).Decl) }, |
| 58 | + "const": func(p token.Position, val string) { |
| 59 | + d := getDoc(p) |
| 60 | + needle := "Constant Value: " + val |
| 61 | + if !strings.Contains(d.Doc, needle) { |
| 62 | + t.Errorf("Expected %q in %q", needle, d.Doc) |
| 63 | + } |
| 64 | + }, |
| 65 | + "exported": func(p token.Position) { |
| 66 | + for _, showUnexported := range []bool{true, false} { |
| 67 | + *showUnexportedFields = showUnexported |
| 68 | + d := getDoc(p) |
| 69 | + hasUnexportedField := strings.Contains(d.Decl, "notVisible") |
| 70 | + if hasUnexportedField != *showUnexportedFields { |
| 71 | + t.Errorf("show unexported fields is %v, but got %q", showUnexported, d.Decl) |
| 72 | + } |
| 73 | + } |
| 74 | + }, |
| 75 | + }); expectErr != nil { |
| 76 | + t.Fatal(expectErr) |
| 77 | + } |
| 78 | + }) |
203 | 79 | }
|
204 | 80 |
|
205 |
| -func TestVendoredIdent(t *testing.T) { |
206 |
| - cleanup := setGopath(filepath.Join(".", "testdata", "withvendor"), t) |
207 |
| - defer cleanup() |
208 |
| - |
209 |
| - filename := filepath.Join(".", "testdata", "withvendor", "src", "main", "main.go") |
210 |
| - doc, err := Run(filename, 76, nil) |
211 |
| - if err != nil { |
212 |
| - t.Fatal(err) |
| 81 | +func TestVendoredCode(t *testing.T) { |
| 82 | + dir := filepath.Join(".", "testdata", "withvendor") |
| 83 | + mods := []packagestest.Module{ |
| 84 | + {Name: "main", Files: packagestest.MustCopyFileTree(dir)}, |
213 | 85 | }
|
214 | 86 |
|
215 |
| - want := "github.com/zmb3/vp" |
216 |
| - if doc.Import != want { |
217 |
| - t.Errorf("want %s, got %s", want, doc.Import) |
218 |
| - } |
219 |
| - if doc.Doc != "Hello says hello.\n" { |
220 |
| - t.Errorf("want 'Hello says hello.\n', got %q", doc.Doc) |
221 |
| - } |
| 87 | + exported := packagestest.Export(t, packagestest.GOPATH, mods) |
| 88 | + defer exported.Cleanup() |
222 | 89 |
|
223 |
| - doc, err = Run(filename, 99, nil) |
224 |
| - if err != nil { |
225 |
| - t.Fatal(err) |
226 |
| - } |
| 90 | + teardown := setup(exported.Config) |
| 91 | + defer teardown() |
227 | 92 |
|
228 |
| - decl := `const Foo untyped string` |
229 |
| - if decl != doc.Decl { |
230 |
| - t.Errorf("invalid decl: want %q, got %q", decl, doc.Decl) |
| 93 | + filename := exported.File("main", "main.go") |
| 94 | + getDoc := func(p token.Position) *Doc { |
| 95 | + t.Helper() |
| 96 | + doc, docErr := Run(filename, p.Offset, nil) |
| 97 | + if docErr != nil { |
| 98 | + t.Fatal(docErr) |
| 99 | + } |
| 100 | + return doc |
231 | 101 | }
|
232 |
| -} |
233 | 102 |
|
234 |
| -func setGopath(path string, t *testing.T) func() { |
235 |
| - t.Helper() |
| 103 | + compare := func(want, got string) { |
| 104 | + if want != got { |
| 105 | + t.Errorf("want %q, got %q", want, got) |
| 106 | + } |
| 107 | + } |
236 | 108 |
|
237 |
| - orig := os.Getenv("GOPATH") |
238 |
| - abs, err := filepath.Abs(path) |
239 |
| - if err != nil { |
240 |
| - t.Fatal(err) |
| 109 | + if expectErr := exported.Expect(map[string]interface{}{ |
| 110 | + "import": func(p token.Position, path string) { compare(path, getDoc(p).Import) }, |
| 111 | + "decl": func(p token.Position, decl string) { compare(decl, getDoc(p).Decl) }, |
| 112 | + "doc": func(p token.Position, doc string) { compare(doc, getDoc(p).Doc) }, |
| 113 | + }); expectErr != nil { |
| 114 | + t.Fatal(expectErr) |
241 | 115 | }
|
242 |
| - os.Setenv("GOPATH", abs) |
243 |
| - return func() { os.Setenv("GOPATH", orig) } |
244 | 116 | }
|
0 commit comments