Black Lives Matter. Support the Equal Justice Initiative.

Source file src/go/build/deps_test.go

Documentation: go/build

     1  // Copyright 2012 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  // This file exercises the import parser but also checks that
     6  // some low-level packages do not have new dependencies added.
     7  
     8  package build
     9  
    10  import (
    11  	"bytes"
    12  	"fmt"
    13  	"go/token"
    14  	"internal/testenv"
    15  	"io/fs"
    16  	"os"
    17  	"path/filepath"
    18  	"runtime"
    19  	"sort"
    20  	"strings"
    21  	"testing"
    22  )
    23  
    24  // depsRules defines the expected dependencies between packages in
    25  // the Go source tree. It is a statement of policy.
    26  //
    27  // DO NOT CHANGE THIS DATA TO FIX BUILDS.
    28  // Existing packages should not have their constraints relaxed
    29  // without prior discussion.
    30  // Negative assertions should almost never be removed.
    31  //
    32  // The general syntax of a rule is:
    33  //
    34  //		a, b < c, d;
    35  //
    36  // which means c and d come after a and b in the partial order
    37  // (that is, c and d can import a and b),
    38  // but doesn't provide a relative order between a vs b or c vs d.
    39  //
    40  // The rules can chain together, as in:
    41  //
    42  //		e < f, g < h;
    43  //
    44  // which is equivalent to
    45  //
    46  //		e < f, g;
    47  //		f, g < h;
    48  //
    49  // Except for the special bottom element "NONE", each name
    50  // must appear exactly once on the right-hand side of a rule.
    51  // That rule serves as the definition of the allowed dependencies
    52  // for that name. The definition must appear before any uses
    53  // of the name on the left-hand side of a rule. (That is, the
    54  // rules themselves must be ordered according to the partial
    55  // order, for easier reading by people.)
    56  //
    57  // Negative assertions double-check the partial order:
    58  //
    59  //		i !< j
    60  //
    61  // means that it must NOT be the case that i < j.
    62  // Negative assertions may appear anywhere in the rules,
    63  // even before i and j have been defined.
    64  //
    65  // Comments begin with #.
    66  //
    67  // All-caps names are pseudo-names for specific points
    68  // in the dependency lattice.
    69  //
    70  var depsRules = `
    71  	# No dependencies allowed for any of these packages.
    72  	NONE
    73  	< container/list, container/ring,
    74  	  internal/cfg, internal/cpu, internal/goexperiment,
    75  	  internal/goversion, internal/nettrace,
    76  	  unicode/utf8, unicode/utf16, unicode,
    77  	  unsafe;
    78  
    79  	# These packages depend only on unsafe.
    80  	unsafe
    81  	< internal/abi;
    82  
    83  	# RUNTIME is the core runtime group of packages, all of them very light-weight.
    84  	internal/abi, internal/cpu, internal/goexperiment, unsafe
    85  	< internal/bytealg
    86  	< internal/itoa
    87  	< internal/unsafeheader
    88  	< runtime/internal/sys
    89  	< runtime/internal/atomic
    90  	< runtime/internal/math
    91  	< runtime
    92  	< sync/atomic
    93  	< internal/race
    94  	< sync
    95  	< internal/reflectlite
    96  	< errors
    97  	< internal/oserror, math/bits
    98  	< RUNTIME;
    99  
   100  	RUNTIME
   101  	< sort
   102  	< container/heap;
   103  
   104  	RUNTIME
   105  	< io;
   106  
   107  	syscall !< io;
   108  	reflect !< sort;
   109  
   110  	RUNTIME, unicode/utf8
   111  	< path;
   112  
   113  	unicode !< path;
   114  
   115  	# SYSCALL is RUNTIME plus the packages necessary for basic system calls.
   116  	RUNTIME, unicode/utf8, unicode/utf16
   117  	< internal/syscall/windows/sysdll, syscall/js
   118  	< syscall
   119  	< internal/syscall/unix, internal/syscall/windows, internal/syscall/windows/registry
   120  	< internal/syscall/execenv
   121  	< SYSCALL;
   122  
   123  	# TIME is SYSCALL plus the core packages about time, including context.
   124  	SYSCALL
   125  	< time/tzdata
   126  	< time
   127  	< context
   128  	< TIME;
   129  
   130  	TIME, io, path, sort
   131  	< io/fs;
   132  
   133  	# MATH is RUNTIME plus the basic math packages.
   134  	RUNTIME
   135  	< math
   136  	< MATH;
   137  
   138  	unicode !< math;
   139  
   140  	MATH
   141  	< math/cmplx;
   142  
   143  	MATH
   144  	< math/rand;
   145  
   146  	MATH
   147  	< runtime/metrics;
   148  
   149  	MATH, unicode/utf8
   150  	< strconv;
   151  
   152  	unicode !< strconv;
   153  
   154  	# STR is basic string and buffer manipulation.
   155  	RUNTIME, io, unicode/utf8, unicode/utf16, unicode
   156  	< bytes, strings
   157  	< bufio;
   158  
   159  	bufio, path, strconv
   160  	< STR;
   161  
   162  	# OS is basic OS access, including helpers (path/filepath, os/exec, etc).
   163  	# OS includes string routines, but those must be layered above package os.
   164  	# OS does not include reflection.
   165  	io/fs
   166  	< internal/testlog
   167  	< internal/poll
   168  	< os
   169  	< os/signal;
   170  
   171  	io/fs
   172  	< embed;
   173  
   174  	unicode, fmt !< os, os/signal;
   175  
   176  	os/signal, STR
   177  	< path/filepath
   178  	< io/ioutil, os/exec;
   179  
   180  	io/ioutil, os/exec, os/signal
   181  	< OS;
   182  
   183  	reflect !< OS;
   184  
   185  	OS
   186  	< golang.org/x/sys/cpu;
   187  
   188  	# FMT is OS (which includes string routines) plus reflect and fmt.
   189  	# It does not include package log, which should be avoided in core packages.
   190  	strconv, unicode
   191  	< reflect;
   192  
   193  	os, reflect
   194  	< internal/fmtsort
   195  	< fmt;
   196  
   197  	OS, fmt
   198  	< FMT;
   199  
   200  	log !< FMT;
   201  
   202  	OS, FMT
   203  	< internal/execabs;
   204  
   205  	OS, internal/execabs
   206  	< internal/goroot;
   207  
   208  	# Misc packages needing only FMT.
   209  	FMT
   210  	< flag,
   211  	  html,
   212  	  mime/quotedprintable,
   213  	  net/internal/socktest,
   214  	  net/url,
   215  	  runtime/debug,
   216  	  runtime/trace,
   217  	  text/scanner,
   218  	  text/tabwriter;
   219  
   220  	# encodings
   221  	# core ones do not use fmt.
   222  	io, strconv
   223  	< encoding;
   224  
   225  	encoding, reflect
   226  	< encoding/binary
   227  	< encoding/base32, encoding/base64;
   228  
   229  	fmt !< encoding/base32, encoding/base64;
   230  
   231  	FMT, encoding/base32, encoding/base64
   232  	< encoding/ascii85, encoding/csv, encoding/gob, encoding/hex,
   233  	  encoding/json, encoding/pem, encoding/xml, mime;
   234  
   235  	# hashes
   236  	io
   237  	< hash
   238  	< hash/adler32, hash/crc32, hash/crc64, hash/fnv, hash/maphash;
   239  
   240  	# math/big
   241  	FMT, encoding/binary, math/rand
   242  	< math/big;
   243  
   244  	# compression
   245  	FMT, encoding/binary, hash/adler32, hash/crc32
   246  	< compress/bzip2, compress/flate, compress/lzw
   247  	< archive/zip, compress/gzip, compress/zlib;
   248  
   249  	# templates
   250  	FMT
   251  	< text/template/parse;
   252  
   253  	net/url, text/template/parse
   254  	< text/template
   255  	< internal/lazytemplate;
   256  
   257  	encoding/json, html, text/template
   258  	< html/template;
   259  
   260  	# regexp
   261  	FMT
   262  	< regexp/syntax
   263  	< regexp
   264  	< internal/lazyregexp;
   265  
   266  	# suffix array
   267  	encoding/binary, regexp
   268  	< index/suffixarray;
   269  
   270  	# executable parsing
   271  	FMT, encoding/binary, compress/zlib
   272  	< debug/dwarf
   273  	< debug/elf, debug/gosym, debug/macho, debug/pe, debug/plan9obj, internal/xcoff
   274  	< DEBUG;
   275  
   276  	# go parser and friends.
   277  	FMT
   278  	< go/token
   279  	< go/scanner
   280  	< go/ast
   281  	< go/internal/typeparams
   282  	< go/parser;
   283  
   284  	FMT
   285  	< go/build/constraint;
   286  
   287  	go/build/constraint, go/parser, text/tabwriter
   288  	< go/printer
   289  	< go/format;
   290  
   291  	go/parser, internal/lazyregexp, text/template
   292  	< go/doc;
   293  
   294  	math/big, go/token
   295  	< go/constant;
   296  
   297  	container/heap, go/constant, go/parser, regexp
   298  	< go/types;
   299  
   300  	FMT, internal/goexperiment
   301  	< internal/buildcfg;
   302  
   303  	go/build/constraint, go/doc, go/parser, internal/buildcfg, internal/goroot, internal/goversion
   304  	< go/build;
   305  
   306  	DEBUG, go/build, go/types, text/scanner
   307  	< go/internal/gcimporter, go/internal/gccgoimporter, go/internal/srcimporter
   308  	< go/importer;
   309  
   310  	# databases
   311  	FMT
   312  	< database/sql/internal
   313  	< database/sql/driver
   314  	< database/sql;
   315  
   316  	# images
   317  	FMT, compress/lzw, compress/zlib
   318  	< image/color
   319  	< image, image/color/palette
   320  	< image/internal/imageutil
   321  	< image/draw
   322  	< image/gif, image/jpeg, image/png;
   323  
   324  	# cgo, delayed as long as possible.
   325  	# If you add a dependency on CGO, you must add the package
   326  	# to cgoPackages in cmd/dist/test.go as well.
   327  	RUNTIME
   328  	< C
   329  	< runtime/cgo
   330  	< CGO
   331  	< runtime/race, runtime/msan;
   332  
   333  	# Bulk of the standard library must not use cgo.
   334  	# The prohibition stops at net and os/user.
   335  	C !< fmt, go/types, CRYPTO-MATH;
   336  
   337  	CGO, OS
   338  	< plugin;
   339  
   340  	CGO, FMT
   341  	< os/user
   342  	< archive/tar;
   343  
   344  	sync
   345  	< internal/singleflight;
   346  
   347  	os
   348  	< golang.org/x/net/dns/dnsmessage,
   349  	  golang.org/x/net/lif,
   350  	  golang.org/x/net/route;
   351  
   352  	# net is unavoidable when doing any networking,
   353  	# so large dependencies must be kept out.
   354  	# This is a long-looking list but most of these
   355  	# are small with few dependencies.
   356  	CGO,
   357  	golang.org/x/net/dns/dnsmessage,
   358  	golang.org/x/net/lif,
   359  	golang.org/x/net/route,
   360  	internal/nettrace,
   361  	internal/poll,
   362  	internal/singleflight,
   363  	internal/race,
   364  	os
   365  	< net;
   366  
   367  	fmt, unicode !< net;
   368  	math/rand !< net; # net uses runtime instead
   369  
   370  	# NET is net plus net-helper packages.
   371  	FMT, net
   372  	< net/textproto;
   373  
   374  	mime, net/textproto, net/url
   375  	< NET;
   376  
   377  	# logging - most packages should not import; http and up is allowed
   378  	FMT
   379  	< log;
   380  
   381  	log !< crypto/tls, database/sql, go/importer, testing;
   382  
   383  	FMT, log, net
   384  	< log/syslog;
   385  
   386  	NET, log
   387  	< net/mail;
   388  
   389  	# CRYPTO is core crypto algorithms - no cgo, fmt, net.
   390  	# Unfortunately, stuck with reflect via encoding/binary.
   391  	encoding/binary, golang.org/x/sys/cpu, hash
   392  	< crypto
   393  	< crypto/subtle
   394  	< crypto/internal/subtle
   395  	< crypto/elliptic/internal/fiat
   396  	< crypto/ed25519/internal/edwards25519/field
   397  	< crypto/ed25519/internal/edwards25519
   398  	< crypto/cipher
   399  	< crypto/aes, crypto/des, crypto/hmac, crypto/md5, crypto/rc4,
   400  	  crypto/sha1, crypto/sha256, crypto/sha512
   401  	< CRYPTO;
   402  
   403  	CGO, fmt, net !< CRYPTO;
   404  
   405  	# CRYPTO-MATH is core bignum-based crypto - no cgo, net; fmt now ok.
   406  	CRYPTO, FMT, math/big
   407  	< crypto/rand
   408  	< crypto/internal/randutil
   409  	< crypto/ed25519
   410  	< encoding/asn1
   411  	< golang.org/x/crypto/cryptobyte/asn1
   412  	< golang.org/x/crypto/cryptobyte
   413  	< golang.org/x/crypto/curve25519
   414  	< crypto/dsa, crypto/elliptic, crypto/rsa
   415  	< crypto/ecdsa
   416  	< CRYPTO-MATH;
   417  
   418  	CGO, net !< CRYPTO-MATH;
   419  
   420  	# TLS, Prince of Dependencies.
   421  	CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem
   422  	< golang.org/x/crypto/internal/subtle
   423  	< golang.org/x/crypto/chacha20
   424  	< golang.org/x/crypto/poly1305
   425  	< golang.org/x/crypto/chacha20poly1305
   426  	< golang.org/x/crypto/hkdf
   427  	< crypto/x509/internal/macos
   428  	< crypto/x509/pkix
   429  	< crypto/x509
   430  	< crypto/tls;
   431  
   432  	# crypto-aware packages
   433  
   434  	NET, crypto/rand, mime/quotedprintable
   435  	< mime/multipart;
   436  
   437  	crypto/tls
   438  	< net/smtp;
   439  
   440  	# HTTP, King of Dependencies.
   441  
   442  	FMT
   443  	< golang.org/x/net/http2/hpack
   444  	< net/http/internal, net/http/internal/ascii, net/http/internal/testcert;
   445  
   446  	FMT, NET, container/list, encoding/binary, log
   447  	< golang.org/x/text/transform
   448  	< golang.org/x/text/unicode/norm
   449  	< golang.org/x/text/unicode/bidi
   450  	< golang.org/x/text/secure/bidirule
   451  	< golang.org/x/net/idna
   452  	< golang.org/x/net/http/httpguts, golang.org/x/net/http/httpproxy;
   453  
   454  	NET, crypto/tls
   455  	< net/http/httptrace;
   456  
   457  	compress/gzip,
   458  	golang.org/x/net/http/httpguts,
   459  	golang.org/x/net/http/httpproxy,
   460  	golang.org/x/net/http2/hpack,
   461  	net/http/internal,
   462  	net/http/internal/ascii,
   463  	net/http/internal/testcert,
   464  	net/http/httptrace,
   465  	mime/multipart,
   466  	log
   467  	< net/http;
   468  
   469  	# HTTP-aware packages
   470  
   471  	encoding/json, net/http
   472  	< expvar;
   473  
   474  	net/http, net/http/internal/ascii
   475  	< net/http/cookiejar, net/http/httputil;
   476  
   477  	net/http, flag
   478  	< net/http/httptest;
   479  
   480  	net/http, regexp
   481  	< net/http/cgi
   482  	< net/http/fcgi;
   483  
   484  	# Profiling
   485  	FMT, compress/gzip, encoding/binary, text/tabwriter
   486  	< runtime/pprof;
   487  
   488  	OS, compress/gzip, regexp
   489  	< internal/profile;
   490  
   491  	html, internal/profile, net/http, runtime/pprof, runtime/trace
   492  	< net/http/pprof;
   493  
   494  	# RPC
   495  	encoding/gob, encoding/json, go/token, html/template, net/http
   496  	< net/rpc
   497  	< net/rpc/jsonrpc;
   498  
   499  	# System Information
   500  	internal/cpu, sync
   501  	< internal/sysinfo;
   502  
   503  	# Test-only
   504  	log
   505  	< testing/iotest
   506  	< testing/fstest;
   507  
   508  	FMT, flag, math/rand
   509  	< testing/quick;
   510  
   511  	FMT, flag, runtime/debug, runtime/trace, internal/sysinfo, math/rand
   512  	< testing;
   513  
   514  	internal/testlog, runtime/pprof, regexp
   515  	< testing/internal/testdeps;
   516  
   517  	OS, flag, testing, internal/cfg
   518  	< internal/testenv;
   519  
   520  	OS, encoding/base64
   521  	< internal/obscuretestdata;
   522  
   523  	CGO, OS, fmt
   524  	< os/signal/internal/pty;
   525  
   526  	NET, testing, math/rand
   527  	< golang.org/x/net/nettest;
   528  
   529  	FMT, container/heap, math/rand
   530  	< internal/trace;
   531  `
   532  
   533  // listStdPkgs returns the same list of packages as "go list std".
   534  func listStdPkgs(goroot string) ([]string, error) {
   535  	// Based on cmd/go's matchPackages function.
   536  	var pkgs []string
   537  
   538  	src := filepath.Join(goroot, "src") + string(filepath.Separator)
   539  	walkFn := func(path string, d fs.DirEntry, err error) error {
   540  		if err != nil || !d.IsDir() || path == src {
   541  			return nil
   542  		}
   543  
   544  		base := filepath.Base(path)
   545  		if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
   546  			return filepath.SkipDir
   547  		}
   548  
   549  		name := filepath.ToSlash(path[len(src):])
   550  		if name == "builtin" || name == "cmd" {
   551  			return filepath.SkipDir
   552  		}
   553  
   554  		pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/"))
   555  		return nil
   556  	}
   557  	if err := filepath.WalkDir(src, walkFn); err != nil {
   558  		return nil, err
   559  	}
   560  	return pkgs, nil
   561  }
   562  
   563  func TestDependencies(t *testing.T) {
   564  	if !testenv.HasSrc() {
   565  		// Tests run in a limited file system and we do not
   566  		// provide access to every source file.
   567  		t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
   568  	}
   569  
   570  	ctxt := Default
   571  	all, err := listStdPkgs(ctxt.GOROOT)
   572  	if err != nil {
   573  		t.Fatal(err)
   574  	}
   575  	sort.Strings(all)
   576  
   577  	sawImport := map[string]map[string]bool{} // from package => to package => true
   578  	policy := depsPolicy(t)
   579  
   580  	for _, pkg := range all {
   581  		imports, err := findImports(pkg)
   582  		if err != nil {
   583  			t.Error(err)
   584  			continue
   585  		}
   586  		if sawImport[pkg] == nil {
   587  			sawImport[pkg] = map[string]bool{}
   588  		}
   589  		ok := policy[pkg]
   590  		var bad []string
   591  		for _, imp := range imports {
   592  			sawImport[pkg][imp] = true
   593  			if !ok[imp] {
   594  				bad = append(bad, imp)
   595  			}
   596  		}
   597  		if bad != nil {
   598  			t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
   599  		}
   600  	}
   601  
   602  	// depPath returns the path between the given from and to packages.
   603  	// It returns the empty string if there's no dependency path.
   604  	var depPath func(string, string) string
   605  	depPath = func(from, to string) string {
   606  		if sawImport[from][to] {
   607  			return from + " => " + to
   608  		}
   609  		for pkg := range sawImport[from] {
   610  			if p := depPath(pkg, to); p != "" {
   611  				return from + " => " + p
   612  			}
   613  		}
   614  		return ""
   615  	}
   616  }
   617  
   618  var buildIgnore = []byte("\n// +build ignore")
   619  
   620  func findImports(pkg string) ([]string, error) {
   621  	vpkg := pkg
   622  	if strings.HasPrefix(pkg, "golang.org") {
   623  		vpkg = "vendor/" + pkg
   624  	}
   625  	dir := filepath.Join(Default.GOROOT, "src", vpkg)
   626  	files, err := os.ReadDir(dir)
   627  	if err != nil {
   628  		return nil, err
   629  	}
   630  	var imports []string
   631  	var haveImport = map[string]bool{}
   632  	fset := token.NewFileSet()
   633  	for _, file := range files {
   634  		name := file.Name()
   635  		if name == "slice_go14.go" || name == "slice_go18.go" {
   636  			// These files are for compiler bootstrap with older versions of Go and not built in the standard build.
   637  			continue
   638  		}
   639  		if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
   640  			continue
   641  		}
   642  		info := fileInfo{
   643  			name: filepath.Join(dir, name),
   644  			fset: fset,
   645  		}
   646  		f, err := os.Open(info.name)
   647  		if err != nil {
   648  			return nil, err
   649  		}
   650  		err = readGoInfo(f, &info)
   651  		f.Close()
   652  		if err != nil {
   653  			return nil, fmt.Errorf("reading %v: %v", name, err)
   654  		}
   655  		if bytes.Contains(info.header, buildIgnore) {
   656  			continue
   657  		}
   658  		for _, imp := range info.imports {
   659  			path := imp.path
   660  			if !haveImport[path] {
   661  				haveImport[path] = true
   662  				imports = append(imports, path)
   663  			}
   664  		}
   665  	}
   666  	sort.Strings(imports)
   667  	return imports, nil
   668  }
   669  
   670  // depsPolicy returns a map m such that m[p][d] == true when p can import d.
   671  func depsPolicy(t *testing.T) map[string]map[string]bool {
   672  	allowed := map[string]map[string]bool{"NONE": {}}
   673  	disallowed := [][2][]string{}
   674  
   675  	parseDepsRules(t, func(deps []string, op string, users []string) {
   676  		if op == "!<" {
   677  			disallowed = append(disallowed, [2][]string{deps, users})
   678  			return
   679  		}
   680  		for _, u := range users {
   681  			if allowed[u] != nil {
   682  				t.Errorf("multiple deps lists for %s", u)
   683  			}
   684  			allowed[u] = make(map[string]bool)
   685  			for _, d := range deps {
   686  				if allowed[d] == nil {
   687  					t.Errorf("use of %s before its deps list", d)
   688  				}
   689  				allowed[u][d] = true
   690  			}
   691  		}
   692  	})
   693  
   694  	// Check for missing deps info.
   695  	for _, deps := range allowed {
   696  		for d := range deps {
   697  			if allowed[d] == nil {
   698  				t.Errorf("missing deps list for %s", d)
   699  			}
   700  		}
   701  	}
   702  
   703  	// Complete transitive allowed deps.
   704  	for k := range allowed {
   705  		for i := range allowed {
   706  			for j := range allowed {
   707  				if i != k && k != j && allowed[i][k] && allowed[k][j] {
   708  					if i == j {
   709  						// Can only happen along with a "use of X before deps" error above,
   710  						// but this error is more specific - it makes clear that reordering the
   711  						// rules will not be enough to fix the problem.
   712  						t.Errorf("deps policy cycle: %s < %s < %s", j, k, i)
   713  					}
   714  					allowed[i][j] = true
   715  				}
   716  			}
   717  		}
   718  	}
   719  
   720  	// Check negative assertions against completed allowed deps.
   721  	for _, bad := range disallowed {
   722  		deps, users := bad[0], bad[1]
   723  		for _, d := range deps {
   724  			for _, u := range users {
   725  				if allowed[u][d] {
   726  					t.Errorf("deps policy incorrect: assertion failed: %s !< %s", d, u)
   727  				}
   728  			}
   729  		}
   730  	}
   731  
   732  	if t.Failed() {
   733  		t.FailNow()
   734  	}
   735  
   736  	return allowed
   737  }
   738  
   739  // parseDepsRules parses depsRules, calling save(deps, op, users)
   740  // for each deps < users or deps !< users rule
   741  // (op is "<" or "!<").
   742  func parseDepsRules(t *testing.T, save func(deps []string, op string, users []string)) {
   743  	p := &depsParser{t: t, lineno: 1, text: depsRules}
   744  
   745  	var prev []string
   746  	var op string
   747  	for {
   748  		list, tok := p.nextList()
   749  		if tok == "" {
   750  			if prev == nil {
   751  				break
   752  			}
   753  			p.syntaxError("unexpected EOF")
   754  		}
   755  		if prev != nil {
   756  			save(prev, op, list)
   757  		}
   758  		prev = list
   759  		if tok == ";" {
   760  			prev = nil
   761  			op = ""
   762  			continue
   763  		}
   764  		if tok != "<" && tok != "!<" {
   765  			p.syntaxError("missing <")
   766  		}
   767  		op = tok
   768  	}
   769  }
   770  
   771  // A depsParser parses the depsRules syntax described above.
   772  type depsParser struct {
   773  	t        *testing.T
   774  	lineno   int
   775  	lastWord string
   776  	text     string
   777  }
   778  
   779  // syntaxError reports a parsing error.
   780  func (p *depsParser) syntaxError(msg string) {
   781  	p.t.Fatalf("deps:%d: syntax error: %s near %s", p.lineno, msg, p.lastWord)
   782  }
   783  
   784  // nextList parses and returns a comma-separated list of names.
   785  func (p *depsParser) nextList() (list []string, token string) {
   786  	for {
   787  		tok := p.nextToken()
   788  		switch tok {
   789  		case "":
   790  			if len(list) == 0 {
   791  				return nil, ""
   792  			}
   793  			fallthrough
   794  		case ",", "<", "!<", ";":
   795  			p.syntaxError("bad list syntax")
   796  		}
   797  		list = append(list, tok)
   798  
   799  		tok = p.nextToken()
   800  		if tok != "," {
   801  			return list, tok
   802  		}
   803  	}
   804  }
   805  
   806  // nextToken returns the next token in the deps rules,
   807  // one of ";" "," "<" "!<" or a name.
   808  func (p *depsParser) nextToken() string {
   809  	for {
   810  		if p.text == "" {
   811  			return ""
   812  		}
   813  		switch p.text[0] {
   814  		case ';', ',', '<':
   815  			t := p.text[:1]
   816  			p.text = p.text[1:]
   817  			return t
   818  
   819  		case '!':
   820  			if len(p.text) < 2 || p.text[1] != '<' {
   821  				p.syntaxError("unexpected token !")
   822  			}
   823  			p.text = p.text[2:]
   824  			return "!<"
   825  
   826  		case '#':
   827  			i := strings.Index(p.text, "\n")
   828  			if i < 0 {
   829  				i = len(p.text)
   830  			}
   831  			p.text = p.text[i:]
   832  			continue
   833  
   834  		case '\n':
   835  			p.lineno++
   836  			fallthrough
   837  		case ' ', '\t':
   838  			p.text = p.text[1:]
   839  			continue
   840  
   841  		default:
   842  			i := strings.IndexAny(p.text, "!;,<#\n \t")
   843  			if i < 0 {
   844  				i = len(p.text)
   845  			}
   846  			t := p.text[:i]
   847  			p.text = p.text[i:]
   848  			p.lastWord = t
   849  			return t
   850  		}
   851  	}
   852  }
   853  
   854  // TestStdlibLowercase tests that all standard library package names are
   855  // lowercase. See Issue 40065.
   856  func TestStdlibLowercase(t *testing.T) {
   857  	if !testenv.HasSrc() {
   858  		t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
   859  	}
   860  
   861  	ctxt := Default
   862  	all, err := listStdPkgs(ctxt.GOROOT)
   863  	if err != nil {
   864  		t.Fatal(err)
   865  	}
   866  
   867  	for _, pkgname := range all {
   868  		if strings.ToLower(pkgname) != pkgname {
   869  			t.Errorf("package %q should not use upper-case path", pkgname)
   870  		}
   871  	}
   872  }
   873  
   874  // TestFindImports tests that findImports works.  See #43249.
   875  func TestFindImports(t *testing.T) {
   876  	imports, err := findImports("go/build")
   877  	if err != nil {
   878  		t.Fatal(err)
   879  	}
   880  	t.Logf("go/build imports %q", imports)
   881  	want := []string{"bytes", "os", "path/filepath", "strings"}
   882  wantLoop:
   883  	for _, w := range want {
   884  		for _, imp := range imports {
   885  			if imp == w {
   886  				continue wantLoop
   887  			}
   888  		}
   889  		t.Errorf("expected to find %q in import list", w)
   890  	}
   891  }
   892  

View as plain text