1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // licence that can be found in the LICENSE file.
18 "golang.org/x/tools/go/buildutil"
21 func TestErrors(t *testing.T) {
25 want string // regexp to match error, or "OK"
29 ctxt: fakeContext(map[string][]string{
30 "foo": {`package foo; type T int`},
31 "bar": {`package bar`},
32 "main": {`package main
39 from: "foo", to: "bar",
40 want: `invalid move destination: bar conflicts with directory .go.src.bar`,
42 // Subpackage already exists.
44 ctxt: fakeContext(map[string][]string{
45 "foo": {`package foo; type T int`},
46 "foo/sub": {`package sub`},
47 "bar/sub": {`package sub`},
48 "main": {`package main
55 from: "foo", to: "bar",
56 want: "invalid move destination: bar; package or subpackage bar/sub already exists",
60 ctxt: fakeContext(map[string][]string{
61 "foo": {`package foo; type T int`},
62 "main": {`package main
69 from: "foo", to: "bar-v2.0",
70 want: "invalid move destination: bar-v2.0; gomvpkg does not " +
71 "support move destinations whose base names are not valid " +
75 ctxt: fakeContext(map[string][]string{
77 "bar": {`package bar`},
79 from: "foo", to: "bar",
80 want: `no initial packages were loaded`,
84 for _, test := range tests {
87 got := make(map[string]string)
88 writeFile = func(filename string, content []byte) error {
89 got[filename] = string(content)
92 moveDirectory = func(from, to string) error {
93 for path, contents := range got {
94 if strings.HasPrefix(path, from) {
95 newPath := strings.Replace(path, from, to, 1)
97 got[newPath] = contents
103 err := Move(ctxt, test.from, test.to, "")
104 prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
106 t.Errorf("%s: nil error. Expected error: %s", prefix, test.want)
109 matched, err2 := regexp.MatchString(test.want, err.Error())
111 t.Errorf("regexp.MatchString failed %s", err2)
115 t.Errorf("%s: conflict does not match expectation:\n"+
118 prefix, err.Error(), test.want)
123 func TestMoves(t *testing.T) {
127 want map[string]string
128 wantWarnings []string
132 ctxt: fakeContext(map[string][]string{
133 "foo": {`package foo; type T int`},
134 "main": {`package main
141 from: "foo", to: "bar",
142 want: map[string]string{
143 "/go/src/main/0.go": `package main
149 "/go/src/bar/0.go": `package bar
156 // Example with subpackage.
158 ctxt: fakeContext(map[string][]string{
159 "foo": {`package foo; type T int`},
160 "foo/sub": {`package sub; type T int`},
161 "main": {`package main
170 from: "foo", to: "bar",
171 want: map[string]string{
172 "/go/src/main/0.go": `package main
180 "/go/src/bar/0.go": `package bar
184 "/go/src/bar/sub/0.go": `package sub; type T int`,
188 // References into subpackages
190 ctxt: fakeContext(map[string][]string{
191 "foo": {`package foo; import "foo/a"; var _ a.T`},
192 "foo/a": {`package a; type T int`},
193 "foo/b": {`package b; import "foo/a"; var _ a.T`},
195 from: "foo", to: "bar",
196 want: map[string]string{
197 "/go/src/bar/0.go": `package bar
203 "/go/src/bar/a/0.go": `package a; type T int`,
204 "/go/src/bar/b/0.go": `package b
213 // References into subpackages where directories have overlapped names
215 ctxt: fakeContext(map[string][]string{
217 "foo/a": {`package a`},
218 "foo/aa": {`package bar`},
219 "foo/c": {`package c; import _ "foo/bar";`},
221 from: "foo/a", to: "foo/spam",
222 want: map[string]string{
223 "/go/src/foo/spam/0.go": `package spam
225 "/go/src/foo/aa/0.go": `package bar`,
226 "/go/src/foo/c/0.go": `package c; import _ "foo/bar";`,
230 // External test packages
232 ctxt: buildutil.FakeContext(map[string]map[string]string{
234 "0.go": `package foo; type T int`,
235 "0_test.go": `package foo_test; import "foo"; var _ foo.T`,
238 "0_test.go": `package baz_test; import "foo"; var _ foo.T`,
241 from: "foo", to: "bar",
242 want: map[string]string{
243 "/go/src/bar/0.go": `package bar
247 "/go/src/bar/0_test.go": `package bar_test
253 "/go/src/baz/0_test.go": `package baz_test
261 // package import comments
263 ctxt: fakeContext(map[string][]string{"foo": {`package foo // import "baz"`}}),
264 from: "foo", to: "bar",
265 want: map[string]string{"/go/src/bar/0.go": `package bar // import "bar"
269 ctxt: fakeContext(map[string][]string{"foo": {`package foo /* import "baz" */`}}),
270 from: "foo", to: "bar",
271 want: map[string]string{"/go/src/bar/0.go": `package bar /* import "bar" */
275 ctxt: fakeContext(map[string][]string{"foo": {`package foo // import "baz"`}}),
276 from: "foo", to: "bar",
277 want: map[string]string{"/go/src/bar/0.go": `package bar // import "bar"
281 ctxt: fakeContext(map[string][]string{"foo": {`package foo
282 // import " this is not an import comment`}}),
283 from: "foo", to: "bar",
284 want: map[string]string{"/go/src/bar/0.go": `package bar
286 // import " this is not an import comment
290 ctxt: fakeContext(map[string][]string{"foo": {`package foo
291 /* import " this is not an import comment */`}}),
292 from: "foo", to: "bar",
293 want: map[string]string{"/go/src/bar/0.go": `package bar
295 /* import " this is not an import comment */
298 // Import name conflict generates a warning, not an error.
300 ctxt: fakeContext(map[string][]string{
302 "a": {`package a; type A int`},
303 "b": {`package b; type B int`},
304 "conflict": {`package conflict
316 from: "b", to: "x/a",
317 want: map[string]string{
318 "/go/src/a/0.go": `package a; type A int`,
319 "/go/src/ok/0.go": `package ok
325 "/go/src/conflict/0.go": `package conflict
333 "/go/src/x/a/0.go": `package a
338 wantWarnings: []string{
339 `/go/src/conflict/0.go:4:8: renaming this imported package name "b" to "a"`,
340 `/go/src/conflict/0.go:3:8: conflicts with imported package name in same block`,
341 `/go/src/conflict/0.go:3:8: skipping update of this file`,
344 // Rename with same base name.
346 ctxt: fakeContext(map[string][]string{
349 "x/foo": {`package foo
353 "main": {`package main; import "x/foo"; var _ foo.T`},
355 from: "x/foo", to: "y/foo",
356 want: map[string]string{
357 "/go/src/y/foo/0.go": `package foo
361 "/go/src/main/0.go": `package main
371 for _, test := range tests {
374 got := make(map[string]string)
375 // Populate got with starting file set. rewriteFile and moveDirectory
376 // will mutate got to produce resulting file set.
377 buildutil.ForEachPackage(ctxt, func(importPath string, err error) {
381 path := filepath.Join("/go/src", importPath, "0.go")
382 if !buildutil.FileExists(ctxt, path) {
385 f, err := ctxt.OpenFile(path)
387 t.Errorf("unexpected error opening file: %s", err)
390 bytes, err := ioutil.ReadAll(f)
393 t.Errorf("unexpected error reading file: %s", err)
396 got[path] = string(bytes)
398 var warnings []string
399 reportError = func(posn token.Position, message string) {
400 warning := fmt.Sprintf("%s:%d:%d: %s",
401 filepath.ToSlash(posn.Filename), // for MS Windows
405 warnings = append(warnings, warning)
408 writeFile = func(filename string, content []byte) error {
409 got[filename] = string(content)
412 moveDirectory = func(from, to string) error {
413 for path, contents := range got {
414 if !(strings.HasPrefix(path, from) &&
415 (len(path) == len(from) || path[len(from)] == filepath.Separator)) {
418 newPath := strings.Replace(path, from, to, 1)
420 got[newPath] = contents
425 err := Move(ctxt, test.from, test.to, "")
426 prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
428 t.Errorf("%s: unexpected error: %s", prefix, err)
432 if !reflect.DeepEqual(warnings, test.wantWarnings) {
433 t.Errorf("%s: unexpected warnings:\n%s\nwant:\n%s",
435 strings.Join(warnings, "\n"),
436 strings.Join(test.wantWarnings, "\n"))
439 for file, wantContent := range test.want {
440 k := filepath.FromSlash(file)
441 gotContent, ok := got[k]
444 // TODO(matloob): some testcases might have files that won't be
446 t.Errorf("%s: file %s not rewritten", prefix, file)
449 if gotContent != wantContent {
450 t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
451 "want <<<%s>>>", prefix, file, gotContent, wantContent)
454 // got should now be empty
455 for file := range got {
456 t.Errorf("%s: unexpected rewrite of file %s", prefix, file)