Source file src/cmd/go/internal/work/build_test.go

     1  // Copyright 2016 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 work
     6  
     7  import (
     8  	"fmt"
     9  	"internal/testenv"
    10  	"io/fs"
    11  	"os"
    12  	"path/filepath"
    13  	"reflect"
    14  	"runtime"
    15  	"strings"
    16  	"testing"
    17  
    18  	"cmd/go/internal/base"
    19  	"cmd/go/internal/cfg"
    20  	"cmd/go/internal/load"
    21  )
    22  
    23  func TestRemoveDevNull(t *testing.T) {
    24  	fi, err := os.Lstat(os.DevNull)
    25  	if err != nil {
    26  		t.Skip(err)
    27  	}
    28  	if fi.Mode().IsRegular() {
    29  		t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull)
    30  	}
    31  	mayberemovefile(os.DevNull)
    32  	_, err = os.Lstat(os.DevNull)
    33  	if err != nil {
    34  		t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull)
    35  	}
    36  }
    37  
    38  func TestSplitPkgConfigOutput(t *testing.T) {
    39  	for _, test := range []struct {
    40  		in   []byte
    41  		want []string
    42  	}{
    43  		{[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
    44  		{[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
    45  		{[]byte("\textra     whitespace\r\n"), []string{"extra", "whitespace\r"}},
    46  		{[]byte("     \r\n      "), []string{"\r"}},
    47  		{[]byte(`"-r:foo" "-L/usr/white space/lib" "-lfoo bar" "-lbar baz"`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
    48  		{[]byte(`"-lextra fun arg\\"`), []string{`-lextra fun arg\`}},
    49  		{[]byte(`"     \r\n\      "`), []string{`     \r\n\      `}},
    50  		{[]byte(`""`), []string{""}},
    51  		{[]byte(``), nil},
    52  		{[]byte(`"\\"`), []string{`\`}},
    53  		{[]byte(`"\x"`), []string{`\x`}},
    54  		{[]byte(`"\\x"`), []string{`\x`}},
    55  		{[]byte(`'\\'`), []string{`\\`}},
    56  		{[]byte(`'\x'`), []string{`\x`}},
    57  		{[]byte(`"\\x"`), []string{`\x`}},
    58  		{[]byte("\\\n"), nil},
    59  		{[]byte(`-fPIC -I/test/include/foo -DQUOTED='"/test/share/doc"'`), []string{"-fPIC", "-I/test/include/foo", `-DQUOTED="/test/share/doc"`}},
    60  		{[]byte(`-fPIC -I/test/include/foo -DQUOTED="/test/share/doc"`), []string{"-fPIC", "-I/test/include/foo", "-DQUOTED=/test/share/doc"}},
    61  		{[]byte(`-fPIC -I/test/include/foo -DQUOTED=\"/test/share/doc\"`), []string{"-fPIC", "-I/test/include/foo", `-DQUOTED="/test/share/doc"`}},
    62  		{[]byte(`-fPIC -I/test/include/foo -DQUOTED='/test/share/doc'`), []string{"-fPIC", "-I/test/include/foo", "-DQUOTED=/test/share/doc"}},
    63  		{[]byte(`-DQUOTED='/te\st/share/d\oc'`), []string{`-DQUOTED=/te\st/share/d\oc`}},
    64  		{[]byte(`-Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world`), []string{"-Dhello=10", "-Dworld=+32", "-DDEFINED_FROM_PKG_CONFIG=hello world"}},
    65  		{[]byte(`"broken\"" \\\a "a"`), []string{"broken\"", "\\a", "a"}},
    66  	} {
    67  		got, err := splitPkgConfigOutput(test.in)
    68  		if err != nil {
    69  			t.Errorf("splitPkgConfigOutput on %#q failed with error %v", test.in, err)
    70  			continue
    71  		}
    72  		if !reflect.DeepEqual(got, test.want) {
    73  			t.Errorf("splitPkgConfigOutput(%#q) = %#q; want %#q", test.in, got, test.want)
    74  		}
    75  	}
    76  
    77  	for _, test := range []struct {
    78  		in   []byte
    79  		want []string
    80  	}{
    81  		// broken quotation
    82  		{[]byte(`"     \r\n      `), nil},
    83  		{[]byte(`"-r:foo" "-L/usr/white space/lib "-lfoo bar" "-lbar baz"`), nil},
    84  		{[]byte(`"-lextra fun arg\\`), nil},
    85  		// broken char escaping
    86  		{[]byte(`broken flag\`), nil},
    87  		{[]byte(`extra broken flag \`), nil},
    88  		{[]byte(`\`), nil},
    89  		{[]byte(`"broken\"" "extra" \`), nil},
    90  	} {
    91  		got, err := splitPkgConfigOutput(test.in)
    92  		if err == nil {
    93  			t.Errorf("splitPkgConfigOutput(%v) = %v; haven't failed with error as expected.", test.in, got)
    94  		}
    95  		if !reflect.DeepEqual(got, test.want) {
    96  			t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
    97  		}
    98  	}
    99  
   100  }
   101  
   102  func TestSharedLibName(t *testing.T) {
   103  	// TODO(avdva) - make these values platform-specific
   104  	prefix := "lib"
   105  	suffix := ".so"
   106  	testData := []struct {
   107  		args      []string
   108  		pkgs      []*load.Package
   109  		expected  string
   110  		expectErr bool
   111  		rootedAt  string
   112  	}{
   113  		{
   114  			args:     []string{"std"},
   115  			pkgs:     []*load.Package{},
   116  			expected: "std",
   117  		},
   118  		{
   119  			args:     []string{"std", "cmd"},
   120  			pkgs:     []*load.Package{},
   121  			expected: "std,cmd",
   122  		},
   123  		{
   124  			args:     []string{},
   125  			pkgs:     []*load.Package{pkgImportPath("gopkg.in/somelib")},
   126  			expected: "gopkg.in-somelib",
   127  		},
   128  		{
   129  			args:     []string{"./..."},
   130  			pkgs:     []*load.Package{pkgImportPath("somelib")},
   131  			expected: "somelib",
   132  			rootedAt: "somelib",
   133  		},
   134  		{
   135  			args:     []string{"../somelib", "../somelib"},
   136  			pkgs:     []*load.Package{pkgImportPath("somelib")},
   137  			expected: "somelib",
   138  		},
   139  		{
   140  			args:     []string{"../lib1", "../lib2"},
   141  			pkgs:     []*load.Package{pkgImportPath("gopkg.in/lib1"), pkgImportPath("gopkg.in/lib2")},
   142  			expected: "gopkg.in-lib1,gopkg.in-lib2",
   143  		},
   144  		{
   145  			args: []string{"./..."},
   146  			pkgs: []*load.Package{
   147  				pkgImportPath("gopkg.in/dir/lib1"),
   148  				pkgImportPath("gopkg.in/lib2"),
   149  				pkgImportPath("gopkg.in/lib3"),
   150  			},
   151  			expected: "gopkg.in",
   152  			rootedAt: "gopkg.in",
   153  		},
   154  		{
   155  			args:      []string{"std", "../lib2"},
   156  			pkgs:      []*load.Package{},
   157  			expectErr: true,
   158  		},
   159  		{
   160  			args:      []string{"all", "./"},
   161  			pkgs:      []*load.Package{},
   162  			expectErr: true,
   163  		},
   164  		{
   165  			args:      []string{"cmd", "fmt"},
   166  			pkgs:      []*load.Package{},
   167  			expectErr: true,
   168  		},
   169  	}
   170  	for _, data := range testData {
   171  		func() {
   172  			if data.rootedAt != "" {
   173  				tmpGopath, err := os.MkdirTemp("", "gopath")
   174  				if err != nil {
   175  					t.Fatal(err)
   176  				}
   177  				cwd := base.Cwd()
   178  				oldGopath := cfg.BuildContext.GOPATH
   179  				defer func() {
   180  					cfg.BuildContext.GOPATH = oldGopath
   181  					os.Chdir(cwd)
   182  					err := os.RemoveAll(tmpGopath)
   183  					if err != nil {
   184  						t.Error(err)
   185  					}
   186  				}()
   187  				root := filepath.Join(tmpGopath, "src", data.rootedAt)
   188  				err = os.MkdirAll(root, 0755)
   189  				if err != nil {
   190  					t.Fatal(err)
   191  				}
   192  				cfg.BuildContext.GOPATH = tmpGopath
   193  				os.Chdir(root)
   194  			}
   195  			computed, err := libname(data.args, data.pkgs)
   196  			if err != nil {
   197  				if !data.expectErr {
   198  					t.Errorf("libname returned an error %q, expected a name", err.Error())
   199  				}
   200  			} else if data.expectErr {
   201  				t.Errorf("libname returned %q, expected an error", computed)
   202  			} else {
   203  				expected := prefix + data.expected + suffix
   204  				if expected != computed {
   205  					t.Errorf("libname returned %q, expected %q", computed, expected)
   206  				}
   207  			}
   208  		}()
   209  	}
   210  }
   211  
   212  func pkgImportPath(pkgpath string) *load.Package {
   213  	return &load.Package{
   214  		PackagePublic: load.PackagePublic{
   215  			ImportPath: pkgpath,
   216  		},
   217  	}
   218  }
   219  
   220  // When installing packages, the installed package directory should
   221  // respect the SetGID bit and group name of the destination
   222  // directory.
   223  // See https://golang.org/issue/18878.
   224  func TestRespectSetgidDir(t *testing.T) {
   225  	// Check that `cp` is called instead of `mv` by looking at the output
   226  	// of `(*Shell).ShowCmd` afterwards as a sanity check.
   227  	cfg.BuildX = true
   228  	var cmdBuf strings.Builder
   229  	sh := NewShell("", func(a ...any) (int, error) {
   230  		return cmdBuf.WriteString(fmt.Sprint(a...))
   231  	})
   232  
   233  	setgiddir := t.TempDir()
   234  
   235  	// BSD mkdir(2) inherits the parent directory group, and other platforms
   236  	// can inherit the parent directory group via setgid. The test setup (chmod
   237  	// setgid) will fail if the process does not have the group permission to
   238  	// the new temporary directory.
   239  	err := os.Chown(setgiddir, os.Getuid(), os.Getgid())
   240  	if err != nil {
   241  		if testenv.SyscallIsNotSupported(err) {
   242  			t.Skip("skipping: chown is not supported on " + runtime.GOOS)
   243  		}
   244  		t.Fatal(err)
   245  	}
   246  
   247  	// Change setgiddir's permissions to include the SetGID bit.
   248  	if err := os.Chmod(setgiddir, 0755|fs.ModeSetgid); err != nil {
   249  		if testenv.SyscallIsNotSupported(err) {
   250  			t.Skip("skipping: chmod is not supported on " + runtime.GOOS)
   251  		}
   252  		t.Fatal(err)
   253  	}
   254  	if fi, err := os.Stat(setgiddir); err != nil {
   255  		t.Fatal(err)
   256  	} else if fi.Mode()&fs.ModeSetgid == 0 {
   257  		t.Skip("skipping: Chmod ignored ModeSetgid on " + runtime.GOOS)
   258  	}
   259  
   260  	pkgfile, err := os.CreateTemp("", "pkgfile")
   261  	if err != nil {
   262  		t.Fatalf("os.CreateTemp(\"\", \"pkgfile\"): %v", err)
   263  	}
   264  	defer os.Remove(pkgfile.Name())
   265  	defer pkgfile.Close()
   266  
   267  	dirGIDFile := filepath.Join(setgiddir, "setgid")
   268  	if err := sh.moveOrCopyFile(dirGIDFile, pkgfile.Name(), 0666, true); err != nil {
   269  		t.Fatalf("moveOrCopyFile: %v", err)
   270  	}
   271  
   272  	got := strings.TrimSpace(cmdBuf.String())
   273  	want := sh.fmtCmd("", "cp %s %s", pkgfile.Name(), dirGIDFile)
   274  	if got != want {
   275  		t.Fatalf("moveOrCopyFile(%q, %q): want %q, got %q", dirGIDFile, pkgfile.Name(), want, got)
   276  	}
   277  }
   278  

View as plain text