github.com/dara-project/godist@v0.0.0-20200823115410-e0c80c8f0c78/src/cmd/api/goapi_test.go (about)

     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  	"internal/testenv"
    13  	"io/ioutil"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"sort"
    18  	"strings"
    19  	"testing"
    20  )
    21  
    22  var (
    23  	updateGolden = flag.Bool("updategolden", false, "update golden files")
    24  )
    25  
    26  func TestGolden(t *testing.T) {
    27  	td, err := os.Open("testdata/src/pkg")
    28  	if err != nil {
    29  		t.Fatal(err)
    30  	}
    31  	fis, err := td.Readdir(0)
    32  	if err != nil {
    33  		t.Fatal(err)
    34  	}
    35  	for _, fi := range fis {
    36  		if !fi.IsDir() {
    37  			continue
    38  		}
    39  
    40  		// TODO(gri) remove extra pkg directory eventually
    41  		goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
    42  		w := NewWalker(nil, "testdata/src/pkg")
    43  		pkg, _ := w.Import(fi.Name())
    44  		w.export(pkg)
    45  
    46  		if *updateGolden {
    47  			os.Remove(goldenFile)
    48  			f, err := os.Create(goldenFile)
    49  			if err != nil {
    50  				t.Fatal(err)
    51  			}
    52  			for _, feat := range w.Features() {
    53  				fmt.Fprintf(f, "%s\n", feat)
    54  			}
    55  			f.Close()
    56  		}
    57  
    58  		bs, err := ioutil.ReadFile(goldenFile)
    59  		if err != nil {
    60  			t.Fatalf("opening golden.txt for package %q: %v", fi.Name(), err)
    61  		}
    62  		wanted := strings.Split(string(bs), "\n")
    63  		sort.Strings(wanted)
    64  		for _, feature := range wanted {
    65  			if feature == "" {
    66  				continue
    67  			}
    68  			_, ok := w.features[feature]
    69  			if !ok {
    70  				t.Errorf("package %s: missing feature %q", fi.Name(), feature)
    71  			}
    72  			delete(w.features, feature)
    73  		}
    74  
    75  		for _, feature := range w.Features() {
    76  			t.Errorf("package %s: extra feature not in golden file: %q", fi.Name(), feature)
    77  		}
    78  	}
    79  }
    80  
    81  func TestCompareAPI(t *testing.T) {
    82  	tests := []struct {
    83  		name                                    string
    84  		features, required, optional, exception []string
    85  		ok                                      bool   // want
    86  		out                                     string // want
    87  	}{
    88  		{
    89  			name:     "feature added",
    90  			features: []string{"A", "B", "C", "D", "E", "F"},
    91  			required: []string{"B", "D"},
    92  			ok:       true,
    93  			out:      "+A\n+C\n+E\n+F\n",
    94  		},
    95  		{
    96  			name:     "feature removed",
    97  			features: []string{"C", "A"},
    98  			required: []string{"A", "B", "C"},
    99  			ok:       false,
   100  			out:      "-B\n",
   101  		},
   102  		{
   103  			name:     "feature added then removed",
   104  			features: []string{"A", "C"},
   105  			optional: []string{"B"},
   106  			required: []string{"A", "C"},
   107  			ok:       true,
   108  			out:      "±B\n",
   109  		},
   110  		{
   111  			name:      "exception removal",
   112  			required:  []string{"A", "B", "C"},
   113  			features:  []string{"A", "C"},
   114  			exception: []string{"B"},
   115  			ok:        true,
   116  			out:       "",
   117  		},
   118  		{
   119  			// https://golang.org/issue/4303
   120  			name: "contexts reconverging",
   121  			required: []string{
   122  				"A",
   123  				"pkg syscall (darwin-386), type RawSockaddrInet6 struct",
   124  				"pkg syscall (darwin-amd64), type RawSockaddrInet6 struct",
   125  			},
   126  			features: []string{
   127  				"A",
   128  				"pkg syscall, type RawSockaddrInet6 struct",
   129  			},
   130  			ok:  true,
   131  			out: "+pkg syscall, type RawSockaddrInet6 struct\n",
   132  		},
   133  	}
   134  	for _, tt := range tests {
   135  		buf := new(bytes.Buffer)
   136  		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception, true)
   137  		if gotok != tt.ok {
   138  			t.Errorf("%s: ok = %v; want %v", tt.name, gotok, tt.ok)
   139  		}
   140  		if got := buf.String(); got != tt.out {
   141  			t.Errorf("%s: output differs\nGOT:\n%s\nWANT:\n%s", tt.name, got, tt.out)
   142  		}
   143  	}
   144  }
   145  
   146  func TestSkipInternal(t *testing.T) {
   147  	tests := []struct {
   148  		pkg  string
   149  		want bool
   150  	}{
   151  		{"net/http", true},
   152  		{"net/http/internal-foo", true},
   153  		{"net/http/internal", false},
   154  		{"net/http/internal/bar", false},
   155  		{"internal/foo", false},
   156  		{"internal", false},
   157  	}
   158  	for _, tt := range tests {
   159  		got := !internalPkg.MatchString(tt.pkg)
   160  		if got != tt.want {
   161  			t.Errorf("%s is internal = %v; want %v", tt.pkg, got, tt.want)
   162  		}
   163  	}
   164  }
   165  
   166  func BenchmarkAll(b *testing.B) {
   167  	stds, err := exec.Command(testenv.GoToolPath(b), "list", "std").Output()
   168  	if err != nil {
   169  		b.Fatal(err)
   170  	}
   171  	b.ResetTimer()
   172  	pkgNames := strings.Fields(string(stds))
   173  
   174  	for _, c := range contexts {
   175  		c.Compiler = build.Default.Compiler
   176  	}
   177  
   178  	for i := 0; i < b.N; i++ {
   179  		for _, context := range contexts {
   180  			w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
   181  			for _, name := range pkgNames {
   182  				if name != "unsafe" && !strings.HasPrefix(name, "cmd/") && !internalPkg.MatchString(name) {
   183  					pkg, _ := w.Import(name)
   184  					w.export(pkg)
   185  				}
   186  			}
   187  			w.Features()
   188  		}
   189  	}
   190  }