Source file src/cmd/api/goapi_test.go

     1  // Copyright 2011 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 main
     6  
     7  import (
     8  	"bytes"
     9  	"flag"
    10  	"fmt"
    11  	"go/build"
    12  	"os"
    13  	"path/filepath"
    14  	"sort"
    15  	"strings"
    16  	"sync"
    17  	"testing"
    18  )
    19  
    20  func TestMain(m *testing.M) {
    21  	flag.Parse()
    22  	for _, c := range contexts {
    23  		c.Compiler = build.Default.Compiler
    24  	}
    25  
    26  	// Warm up the import cache in parallel.
    27  	var wg sync.WaitGroup
    28  	for _, context := range contexts {
    29  		context := context
    30  		wg.Add(1)
    31  		go func() {
    32  			defer wg.Done()
    33  			_ = NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
    34  		}()
    35  	}
    36  	wg.Wait()
    37  
    38  	os.Exit(m.Run())
    39  }
    40  
    41  var (
    42  	updateGolden = flag.Bool("updategolden", false, "update golden files")
    43  )
    44  
    45  func TestGolden(t *testing.T) {
    46  	td, err := os.Open("testdata/src/pkg")
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	fis, err := td.Readdir(0)
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  	for _, fi := range fis {
    55  		if !fi.IsDir() {
    56  			continue
    57  		}
    58  
    59  		// TODO(gri) remove extra pkg directory eventually
    60  		goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
    61  		w := NewWalker(nil, "testdata/src/pkg")
    62  		pkg, _ := w.Import(fi.Name())
    63  		w.export(pkg)
    64  
    65  		if *updateGolden {
    66  			os.Remove(goldenFile)
    67  			f, err := os.Create(goldenFile)
    68  			if err != nil {
    69  				t.Fatal(err)
    70  			}
    71  			for _, feat := range w.Features() {
    72  				fmt.Fprintf(f, "%s\n", feat)
    73  			}
    74  			f.Close()
    75  		}
    76  
    77  		bs, err := os.ReadFile(goldenFile)
    78  		if err != nil {
    79  			t.Fatalf("opening golden.txt for package %q: %v", fi.Name(), err)
    80  		}
    81  		wanted := strings.Split(string(bs), "\n")
    82  		sort.Strings(wanted)
    83  		for _, feature := range wanted {
    84  			if feature == "" {
    85  				continue
    86  			}
    87  			_, ok := w.features[feature]
    88  			if !ok {
    89  				t.Errorf("package %s: missing feature %q", fi.Name(), feature)
    90  			}
    91  			delete(w.features, feature)
    92  		}
    93  
    94  		for _, feature := range w.Features() {
    95  			t.Errorf("package %s: extra feature not in golden file: %q", fi.Name(), feature)
    96  		}
    97  	}
    98  }
    99  
   100  func TestCompareAPI(t *testing.T) {
   101  	tests := []struct {
   102  		name                                    string
   103  		features, required, optional, exception []string
   104  		ok                                      bool   // want
   105  		out                                     string // want
   106  	}{
   107  		{
   108  			name:     "feature added",
   109  			features: []string{"A", "B", "C", "D", "E", "F"},
   110  			required: []string{"B", "D"},
   111  			ok:       true,
   112  			out:      "+A\n+C\n+E\n+F\n",
   113  		},
   114  		{
   115  			name:     "feature removed",
   116  			features: []string{"C", "A"},
   117  			required: []string{"A", "B", "C"},
   118  			ok:       false,
   119  			out:      "-B\n",
   120  		},
   121  		{
   122  			name:     "feature added then removed",
   123  			features: []string{"A", "C"},
   124  			optional: []string{"B"},
   125  			required: []string{"A", "C"},
   126  			ok:       true,
   127  			out:      "±B\n",
   128  		},
   129  		{
   130  			name:      "exception removal",
   131  			required:  []string{"A", "B", "C"},
   132  			features:  []string{"A", "C"},
   133  			exception: []string{"B"},
   134  			ok:        true,
   135  			out:       "",
   136  		},
   137  		{
   138  			// https://golang.org/issue/4303
   139  			name: "contexts reconverging",
   140  			required: []string{
   141  				"A",
   142  				"pkg syscall (darwin-amd64), type RawSockaddrInet6 struct",
   143  			},
   144  			features: []string{
   145  				"A",
   146  				"pkg syscall, type RawSockaddrInet6 struct",
   147  			},
   148  			ok:  true,
   149  			out: "+pkg syscall, type RawSockaddrInet6 struct\n",
   150  		},
   151  	}
   152  	for _, tt := range tests {
   153  		buf := new(bytes.Buffer)
   154  		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception, true)
   155  		if gotok != tt.ok {
   156  			t.Errorf("%s: ok = %v; want %v", tt.name, gotok, tt.ok)
   157  		}
   158  		if got := buf.String(); got != tt.out {
   159  			t.Errorf("%s: output differs\nGOT:\n%s\nWANT:\n%s", tt.name, got, tt.out)
   160  		}
   161  	}
   162  }
   163  
   164  func TestSkipInternal(t *testing.T) {
   165  	tests := []struct {
   166  		pkg  string
   167  		want bool
   168  	}{
   169  		{"net/http", true},
   170  		{"net/http/internal-foo", true},
   171  		{"net/http/internal", false},
   172  		{"net/http/internal/bar", false},
   173  		{"internal/foo", false},
   174  		{"internal", false},
   175  	}
   176  	for _, tt := range tests {
   177  		got := !internalPkg.MatchString(tt.pkg)
   178  		if got != tt.want {
   179  			t.Errorf("%s is internal = %v; want %v", tt.pkg, got, tt.want)
   180  		}
   181  	}
   182  }
   183  
   184  func BenchmarkAll(b *testing.B) {
   185  	for i := 0; i < b.N; i++ {
   186  		for _, context := range contexts {
   187  			w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
   188  			for _, name := range w.stdPackages {
   189  				pkg, _ := w.Import(name)
   190  				w.export(pkg)
   191  			}
   192  			w.Features()
   193  		}
   194  	}
   195  }
   196  
   197  func TestIssue21181(t *testing.T) {
   198  	for _, context := range contexts {
   199  		w := NewWalker(context, "testdata/src/issue21181")
   200  		pkg, err := w.Import("p")
   201  		if err != nil {
   202  			t.Fatalf("%s: (%s-%s) %s %v", err, context.GOOS, context.GOARCH,
   203  				pkg.Name(), w.imported)
   204  		}
   205  		w.export(pkg)
   206  	}
   207  }
   208  
   209  func TestIssue29837(t *testing.T) {
   210  	for _, context := range contexts {
   211  		w := NewWalker(context, "testdata/src/issue29837")
   212  		_, err := w.Import("p")
   213  		if _, nogo := err.(*build.NoGoError); !nogo {
   214  			t.Errorf("expected *build.NoGoError, got %T", err)
   215  		}
   216  	}
   217  }
   218  
   219  func TestIssue41358(t *testing.T) {
   220  	context := new(build.Context)
   221  	*context = build.Default
   222  	context.Dir = filepath.Join(context.GOROOT, "src")
   223  
   224  	w := NewWalker(context, context.Dir)
   225  	for _, pkg := range w.stdPackages {
   226  		if strings.HasPrefix(pkg, "vendor/") || strings.HasPrefix(pkg, "golang.org/x/") {
   227  			t.Fatalf("stdPackages contains unexpected package %s", pkg)
   228  		}
   229  	}
   230  }
   231  

View as plain text