github.com/gopherjs/gopherjs@v1.19.0-beta1.0.20240506212314-27071a8796e4/build/context_test.go (about)

     1  package build
     2  
     3  import (
     4  	"fmt"
     5  	"go/build"
     6  	"net/http"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/google/go-cmp/cmp"
    12  	"github.com/google/go-cmp/cmp/cmpopts"
    13  	"github.com/gopherjs/gopherjs/compiler/gopherjspkg"
    14  	"golang.org/x/tools/go/buildutil"
    15  )
    16  
    17  func init() {
    18  	gopherjspkg.RegisterFS(http.Dir(".."))
    19  }
    20  
    21  func TestSimpleCtx(t *testing.T) {
    22  	e := DefaultEnv()
    23  
    24  	gopherjsRoot := filepath.Join(e.GOROOT, "src", "github.com", "gopherjs", "gopherjs")
    25  	fs := &withPrefix{gopherjspkg.FS, gopherjsRoot}
    26  	ec := embeddedCtx(fs, e)
    27  	ec.bctx.JoinPath = filepath.Join // Avoid diffs in the test on Windows.
    28  
    29  	gc := goCtx(e)
    30  
    31  	t.Run("exists", func(t *testing.T) {
    32  		tests := []struct {
    33  			buildCtx XContext
    34  			wantPkg  *PackageData
    35  		}{
    36  			{
    37  				buildCtx: ec,
    38  				wantPkg: &PackageData{
    39  					Package:   expectedPackage(&ec.bctx, "github.com/gopherjs/gopherjs/js", "wasm"),
    40  					IsVirtual: true,
    41  				},
    42  			}, {
    43  				buildCtx: gc,
    44  				wantPkg: &PackageData{
    45  					Package:   expectedPackage(&gc.bctx, "fmt", "wasm"),
    46  					IsVirtual: false,
    47  				},
    48  			},
    49  		}
    50  
    51  		for _, test := range tests {
    52  			t.Run(fmt.Sprintf("%T", test.buildCtx), func(t *testing.T) {
    53  				importPath := test.wantPkg.ImportPath
    54  				got, err := test.buildCtx.Import(importPath, "", build.FindOnly)
    55  				if err != nil {
    56  					t.Fatalf("ec.Import(%q) returned error: %s. Want: no error.", importPath, err)
    57  				}
    58  				if diff := cmp.Diff(test.wantPkg, got, cmpopts.IgnoreUnexported(*got)); diff != "" {
    59  					t.Errorf("ec.Import(%q) returned diff (-want,+got):\n%s", importPath, diff)
    60  				}
    61  			})
    62  		}
    63  	})
    64  
    65  	t.Run("not found", func(t *testing.T) {
    66  		tests := []struct {
    67  			buildCtx   XContext
    68  			importPath string
    69  		}{
    70  			{
    71  				buildCtx:   ec,
    72  				importPath: "package/not/found",
    73  			}, {
    74  				// Outside of the main module.
    75  				buildCtx:   gc,
    76  				importPath: "package/not/found",
    77  			}, {
    78  				// In the main module.
    79  				buildCtx:   gc,
    80  				importPath: "github.com/gopherjs/gopherjs/not/found",
    81  			},
    82  		}
    83  
    84  		for _, test := range tests {
    85  			t.Run(fmt.Sprintf("%T", test.buildCtx), func(t *testing.T) {
    86  				_, err := ec.Import(test.importPath, "", build.FindOnly)
    87  				want := "cannot find package"
    88  				if err == nil || !strings.Contains(err.Error(), want) {
    89  					t.Errorf("ec.Import(%q) returned error: %s. Want error containing %q.", test.importPath, err, want)
    90  				}
    91  			})
    92  		}
    93  	})
    94  }
    95  
    96  func TestChainedCtx(t *testing.T) {
    97  	// Construct a chained context of two fake contexts so that we could verify
    98  	// fallback behavior.
    99  	cc := chainedCtx{
   100  		primary: simpleCtx{
   101  			bctx: *buildutil.FakeContext(map[string]map[string]string{
   102  				"primaryonly": {"po.go": "package primaryonly"},
   103  				"both":        {"both.go": "package both"},
   104  			}),
   105  			isVirtual: false,
   106  		},
   107  		secondary: simpleCtx{
   108  			bctx: *buildutil.FakeContext(map[string]map[string]string{
   109  				"both":          {"both_secondary.go": "package both"},
   110  				"secondaryonly": {"so.go": "package secondaryonly"},
   111  			}),
   112  			isVirtual: true,
   113  		},
   114  	}
   115  
   116  	tests := []struct {
   117  		importPath      string
   118  		wantFromPrimary bool
   119  	}{
   120  		{
   121  			importPath:      "primaryonly",
   122  			wantFromPrimary: true,
   123  		}, {
   124  			importPath:      "both",
   125  			wantFromPrimary: true,
   126  		}, {
   127  			importPath:      "secondaryonly",
   128  			wantFromPrimary: false,
   129  		},
   130  	}
   131  
   132  	for _, test := range tests {
   133  		t.Run(test.importPath, func(t *testing.T) {
   134  			pkg, err := cc.Import(test.importPath, "", 0)
   135  			if err != nil {
   136  				t.Errorf("cc.Import() returned error: %v. Want: no error.", err)
   137  			}
   138  			gotFromPrimary := !pkg.IsVirtual
   139  			if gotFromPrimary != test.wantFromPrimary {
   140  				t.Errorf("Got package imported from primary: %t. Want: %t.", gotFromPrimary, test.wantFromPrimary)
   141  			}
   142  		})
   143  	}
   144  }
   145  
   146  func TestIsStd(t *testing.T) {
   147  	realGOROOT := goCtx(DefaultEnv())
   148  	overlayGOROOT := overlayCtx(DefaultEnv())
   149  	gopherjsPackages := gopherjsCtx(DefaultEnv())
   150  	tests := []struct {
   151  		descr      string
   152  		importPath string
   153  		context    *simpleCtx
   154  		want       bool
   155  	}{
   156  		{
   157  			descr:      "real goroot, standard package",
   158  			importPath: "fmt",
   159  			context:    realGOROOT,
   160  			want:       true,
   161  		},
   162  		{
   163  			descr:      "real goroot, non-standard package",
   164  			importPath: "github.com/gopherjs/gopherjs/build",
   165  			context:    realGOROOT,
   166  			want:       false,
   167  		},
   168  		{
   169  			descr:      "real goroot, non-exiting package",
   170  			importPath: "does/not/exist",
   171  			context:    realGOROOT,
   172  			want:       false,
   173  		},
   174  		{
   175  			descr:      "overlay goroot, standard package",
   176  			importPath: "fmt",
   177  			context:    overlayGOROOT,
   178  			want:       true,
   179  		},
   180  		{
   181  			descr:      "embedded gopherjs packages, gopherjs/js package",
   182  			importPath: "github.com/gopherjs/gopherjs/js",
   183  			context:    gopherjsPackages,
   184  			// When user's source tree doesn't contain gopherjs package (e.g. it uses
   185  			// syscall/js API only), we pretend that gopherjs/js package is included
   186  			// in the standard library.
   187  			want: true,
   188  		},
   189  	}
   190  
   191  	for _, test := range tests {
   192  		t.Run(test.descr, func(t *testing.T) {
   193  			got := test.context.isStd(test.importPath, "")
   194  			if got != test.want {
   195  				t.Errorf("Got: simpleCtx.isStd(%q) = %v. Want: %v", test.importPath, got, test.want)
   196  			}
   197  		})
   198  	}
   199  }
   200  
   201  func expectedPackage(bctx *build.Context, importPath string, goarch string) *build.Package {
   202  	targetRoot := filepath.Clean(filepath.Join(bctx.GOROOT, "pkg", bctx.GOOS+"_"+goarch))
   203  	return &build.Package{
   204  		Dir:           filepath.Join(bctx.GOROOT, "src", importPath),
   205  		ImportPath:    importPath,
   206  		Root:          bctx.GOROOT,
   207  		SrcRoot:       filepath.Join(bctx.GOROOT, "src"),
   208  		PkgRoot:       filepath.Join(bctx.GOROOT, "pkg"),
   209  		PkgTargetRoot: targetRoot,
   210  		BinDir:        filepath.Join(bctx.GOROOT, "bin"),
   211  		Goroot:        true,
   212  		PkgObj:        filepath.Join(targetRoot, importPath+".a"),
   213  	}
   214  }