1 // Copyright 2019 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.
19 "golang.org/x/tools/go/packages"
20 "golang.org/x/tools/internal/testenv"
23 func TestChanges(t *testing.T) {
24 dir, err := ioutil.TempDir("", "apidiff_test")
28 dir = filepath.Join(dir, "go")
29 wanti, wantc := splitIntoPackages(t, dir)
30 defer os.RemoveAll(dir)
34 oldpkg, err := load(t, "apidiff/old", dir)
38 newpkg, err := load(t, "apidiff/new", dir)
43 report := Changes(oldpkg.Types, newpkg.Types)
45 got := report.messages(false)
46 if !reflect.DeepEqual(got, wanti) {
47 t.Errorf("incompatibles: got %v\nwant %v\n", got, wanti)
49 got = report.messages(true)
50 if !reflect.DeepEqual(got, wantc) {
51 t.Errorf("compatibles: got %v\nwant %v\n", got, wantc)
55 func splitIntoPackages(t *testing.T, dir string) (incompatibles, compatibles []string) {
56 // Read the input file line by line.
57 // Write a line into the old or new package,
58 // dependent on comments.
59 // Also collect expected messages.
60 f, err := os.Open("testdata/tests.go")
66 if err := os.MkdirAll(filepath.Join(dir, "src", "apidiff"), 0700); err != nil {
69 if err := ioutil.WriteFile(filepath.Join(dir, "src", "apidiff", "go.mod"), []byte("module apidiff\n"), 0666); err != nil {
73 oldd := filepath.Join(dir, "src/apidiff/old")
74 newd := filepath.Join(dir, "src/apidiff/new")
75 if err := os.MkdirAll(oldd, 0700); err != nil {
78 if err := os.Mkdir(newd, 0700); err != nil && !os.IsExist(err) {
82 oldf, err := os.Create(filepath.Join(oldd, "old.go"))
86 newf, err := os.Create(filepath.Join(newd, "new.go"))
91 wl := func(f *os.File, line string) {
92 if _, err := fmt.Fprintln(f, line); err != nil {
96 writeBoth := func(line string) { wl(oldf, line); wl(newf, line) }
98 s := bufio.NewScanner(f)
101 tl := strings.TrimSpace(line)
104 writeln = func(line string) { wl(oldf, line) }
106 writeln = func(line string) { wl(newf, line) }
107 case tl == "// both":
109 case strings.HasPrefix(tl, "// i "):
110 incompatibles = append(incompatibles, strings.TrimSpace(tl[4:]))
111 case strings.HasPrefix(tl, "// c "):
112 compatibles = append(compatibles, strings.TrimSpace(tl[4:]))
123 func load(t *testing.T, importPath, goPath string) (*packages.Package, error) {
124 testenv.NeedsGoPackages(t)
126 cfg := &packages.Config{
127 Mode: packages.LoadTypes,
130 cfg.Env = append(os.Environ(), "GOPATH="+goPath)
131 cfg.Dir = filepath.Join(goPath, "src", filepath.FromSlash(importPath))
133 pkgs, err := packages.Load(cfg, importPath)
137 if len(pkgs[0].Errors) > 0 {
138 return nil, pkgs[0].Errors[0]
143 func TestExportedFields(t *testing.T) {
144 pkg, err := load(t, "golang.org/x/tools/internal/apidiff/testdata/exported_fields", "")
148 typeof := func(name string) types.Type {
149 return pkg.Types.Scope().Lookup(name).Type()
153 su := s.(*types.Named).Underlying().(*types.Struct)
155 ef := exportedSelectableFields(su)
160 {"A1", typeof("A1")},
161 {"D", types.Typ[types.Bool]},
162 {"E", types.Typ[types.Int]},
164 {"S", types.NewPointer(s)},
167 if got, want := len(ef), len(wants); got != want {
168 t.Errorf("got %d fields, want %d\n%+v", got, want, ef)
170 for _, w := range wants {
171 if got := ef[w.name]; got != nil && !types.Identical(got.Type(), w.typ) {
172 t.Errorf("%s: got %v, want %v", w.name, got.Type(), w.typ)