github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/refactor/rename/mvpkg_test.go (about)

     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.
     4  
     5  package rename
     6  
     7  import (
     8  	"fmt"
     9  	"go/build"
    10  	"io/ioutil"
    11  	"path/filepath"
    12  	"regexp"
    13  	"strings"
    14  	"testing"
    15  
    16  	"golang.org/x/tools/go/buildutil"
    17  )
    18  
    19  func TestErrors(t *testing.T) {
    20  	tests := []struct {
    21  		ctxt     *build.Context
    22  		from, to string
    23  		want     string // regexp to match error, or "OK"
    24  	}{
    25  		// Simple example.
    26  		{
    27  			ctxt: fakeContext(map[string][]string{
    28  				"foo": {`package foo; type T int`},
    29  				"bar": {`package bar`},
    30  				"main": {`package main
    31  
    32  import "foo"
    33  
    34  var _ foo.T
    35  `},
    36  			}),
    37  			from: "foo", to: "bar",
    38  			want: `invalid move destination: bar conflicts with directory .go.src.bar`,
    39  		},
    40  		// Subpackage already exists.
    41  		{
    42  			ctxt: fakeContext(map[string][]string{
    43  				"foo":     {`package foo; type T int`},
    44  				"foo/sub": {`package sub`},
    45  				"bar/sub": {`package sub`},
    46  				"main": {`package main
    47  
    48  import "foo"
    49  
    50  var _ foo.T
    51  `},
    52  			}),
    53  			from: "foo", to: "bar",
    54  			want: "invalid move destination: bar; package or subpackage bar/sub already exists",
    55  		},
    56  		// Invalid base name.
    57  		{
    58  			ctxt: fakeContext(map[string][]string{
    59  				"foo": {`package foo; type T int`},
    60  				"main": {`package main
    61  
    62  import "foo"
    63  
    64  var _ foo.T
    65  `},
    66  			}),
    67  			from: "foo", to: "bar-v2.0",
    68  			want: "invalid move destination: bar-v2.0; gomvpkg does not " +
    69  				"support move destinations whose base names are not valid " +
    70  				"go identifiers",
    71  		},
    72  	}
    73  
    74  	for _, test := range tests {
    75  		ctxt := test.ctxt
    76  
    77  		got := make(map[string]string)
    78  		writeFile = func(filename string, content []byte) error {
    79  			got[filename] = string(content)
    80  			return nil
    81  		}
    82  		moveDirectory = func(from, to string) error {
    83  			for path, contents := range got {
    84  				if strings.HasPrefix(path, from) {
    85  					newPath := strings.Replace(path, from, to, 1)
    86  					delete(got, path)
    87  					got[newPath] = contents
    88  				}
    89  			}
    90  			return nil
    91  		}
    92  
    93  		err := Move(ctxt, test.from, test.to, "")
    94  		prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
    95  		if err == nil {
    96  			t.Errorf("%s: nil error. Expected error: %s", prefix, test.want)
    97  			continue
    98  		}
    99  		matched, err2 := regexp.MatchString(test.want, err.Error())
   100  		if err2 != nil {
   101  			t.Errorf("regexp.MatchString failed %s", err2)
   102  			continue
   103  		}
   104  		if !matched {
   105  			t.Errorf("%s: conflict does not match expectation:\n"+
   106  				"Error: %q\n"+
   107  				"Pattern: %q",
   108  				prefix, err.Error(), test.want)
   109  		}
   110  	}
   111  }
   112  
   113  func TestMoves(t *testing.T) {
   114  	tests := []struct {
   115  		ctxt     *build.Context
   116  		from, to string
   117  		want     map[string]string
   118  	}{
   119  		// Simple example.
   120  		{
   121  			ctxt: fakeContext(map[string][]string{
   122  				"foo": {`package foo; type T int`},
   123  				"main": {`package main
   124  
   125  import "foo"
   126  
   127  var _ foo.T
   128  `},
   129  			}),
   130  			from: "foo", to: "bar",
   131  			want: map[string]string{
   132  				"/go/src/main/0.go": `package main
   133  
   134  import "bar"
   135  
   136  var _ bar.T
   137  `,
   138  				"/go/src/bar/0.go": `package bar
   139  
   140  type T int
   141  `,
   142  			},
   143  		},
   144  
   145  		// Example with subpackage.
   146  		{
   147  			ctxt: fakeContext(map[string][]string{
   148  				"foo":     {`package foo; type T int`},
   149  				"foo/sub": {`package sub; type T int`},
   150  				"main": {`package main
   151  
   152  import "foo"
   153  import "foo/sub"
   154  
   155  var _ foo.T
   156  var _ sub.T
   157  `},
   158  			}),
   159  			from: "foo", to: "bar",
   160  			want: map[string]string{
   161  				"/go/src/main/0.go": `package main
   162  
   163  import "bar"
   164  import "bar/sub"
   165  
   166  var _ bar.T
   167  var _ sub.T
   168  `,
   169  				"/go/src/bar/0.go": `package bar
   170  
   171  type T int
   172  `,
   173  				"/go/src/bar/sub/0.go": `package sub; type T int`,
   174  			},
   175  		},
   176  
   177  		// References into subpackages
   178  		{
   179  			ctxt: fakeContext(map[string][]string{
   180  				"foo":   {`package foo; import "foo/a"; var _ a.T`},
   181  				"foo/a": {`package a; type T int`},
   182  				"foo/b": {`package b; import "foo/a"; var _ a.T`},
   183  			}),
   184  			from: "foo", to: "bar",
   185  			want: map[string]string{
   186  				"/go/src/bar/0.go": `package bar
   187  
   188  import "bar/a"
   189  
   190  var _ a.T
   191  `,
   192  				"/go/src/bar/a/0.go": `package a; type T int`,
   193  				"/go/src/bar/b/0.go": `package b
   194  
   195  import "bar/a"
   196  
   197  var _ a.T
   198  `,
   199  			},
   200  		},
   201  
   202  		// External test packages
   203  		{
   204  			ctxt: buildutil.FakeContext(map[string]map[string]string{
   205  				"foo": {
   206  					"0.go":      `package foo; type T int`,
   207  					"0_test.go": `package foo_test; import "foo"; var _ foo.T`,
   208  				},
   209  				"baz": {
   210  					"0_test.go": `package baz_test; import "foo"; var _ foo.T`,
   211  				},
   212  			}),
   213  			from: "foo", to: "bar",
   214  			want: map[string]string{
   215  				"/go/src/bar/0.go": `package bar
   216  
   217  type T int
   218  `,
   219  				"/go/src/bar/0_test.go": `package bar_test
   220  
   221  import "bar"
   222  
   223  var _ bar.T
   224  `,
   225  				"/go/src/baz/0_test.go": `package baz_test
   226  
   227  import "bar"
   228  
   229  var _ bar.T
   230  `,
   231  			},
   232  		},
   233  		// package import comments
   234  		{
   235  			ctxt: fakeContext(map[string][]string{"foo": {`package foo // import "baz"`}}),
   236  			from: "foo", to: "bar",
   237  			want: map[string]string{"/go/src/bar/0.go": `package bar // import "bar"
   238  `},
   239  		},
   240  		{
   241  			ctxt: fakeContext(map[string][]string{"foo": {`package foo /* import "baz" */`}}),
   242  			from: "foo", to: "bar",
   243  			want: map[string]string{"/go/src/bar/0.go": `package bar /* import "bar" */
   244  `},
   245  		},
   246  		{
   247  			ctxt: fakeContext(map[string][]string{"foo": {`package foo       // import "baz"`}}),
   248  			from: "foo", to: "bar",
   249  			want: map[string]string{"/go/src/bar/0.go": `package bar // import "bar"
   250  `},
   251  		},
   252  		{
   253  			ctxt: fakeContext(map[string][]string{"foo": {`package foo
   254  // import " this is not an import comment`}}),
   255  			from: "foo", to: "bar",
   256  			want: map[string]string{"/go/src/bar/0.go": `package bar
   257  
   258  // import " this is not an import comment
   259  `},
   260  		},
   261  		{
   262  			ctxt: fakeContext(map[string][]string{"foo": {`package foo
   263  /* import " this is not an import comment */`}}),
   264  			from: "foo", to: "bar",
   265  			want: map[string]string{"/go/src/bar/0.go": `package bar
   266  
   267  /* import " this is not an import comment */
   268  `},
   269  		},
   270  	}
   271  
   272  	for _, test := range tests {
   273  		ctxt := test.ctxt
   274  
   275  		got := make(map[string]string)
   276  		// Populate got with starting file set. rewriteFile and moveDirectory
   277  		// will mutate got to produce resulting file set.
   278  		buildutil.ForEachPackage(ctxt, func(importPath string, err error) {
   279  			if err != nil {
   280  				return
   281  			}
   282  			path := filepath.Join("/go/src", importPath, "0.go")
   283  			if !buildutil.FileExists(ctxt, path) {
   284  				return
   285  			}
   286  			f, err := ctxt.OpenFile(path)
   287  			if err != nil {
   288  				t.Errorf("unexpected error opening file: %s", err)
   289  				return
   290  			}
   291  			bytes, err := ioutil.ReadAll(f)
   292  			f.Close()
   293  			if err != nil {
   294  				t.Errorf("unexpected error reading file: %s", err)
   295  				return
   296  			}
   297  			got[path] = string(bytes)
   298  		})
   299  		writeFile = func(filename string, content []byte) error {
   300  			got[filename] = string(content)
   301  			return nil
   302  		}
   303  		moveDirectory = func(from, to string) error {
   304  			for path, contents := range got {
   305  				if strings.HasPrefix(path, from) {
   306  					newPath := strings.Replace(path, from, to, 1)
   307  					delete(got, path)
   308  					got[newPath] = contents
   309  				}
   310  			}
   311  			return nil
   312  		}
   313  
   314  		err := Move(ctxt, test.from, test.to, "")
   315  		prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
   316  		if err != nil {
   317  			t.Errorf("%s: unexpected error: %s", prefix, err)
   318  			continue
   319  		}
   320  
   321  		for file, wantContent := range test.want {
   322  			k := filepath.FromSlash(file)
   323  			gotContent, ok := got[k]
   324  			delete(got, k)
   325  			if !ok {
   326  				// TODO(matloob): some testcases might have files that won't be
   327  				// rewritten
   328  				t.Errorf("%s: file %s not rewritten", prefix, file)
   329  				continue
   330  			}
   331  			if gotContent != wantContent {
   332  				t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
   333  					"want <<<%s>>>", prefix, file, gotContent, wantContent)
   334  			}
   335  		}
   336  		// got should now be empty
   337  		for file := range got {
   338  			t.Errorf("%s: unexpected rewrite of file %s", prefix, file)
   339  		}
   340  	}
   341  }