diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
commit | 43a123c1ae6613b3efeed291fa552ecd909d3acf (patch) | |
tree | fd92518b7024bc74031f78a1cf9e454b65e73665 /src/cmd/internal/archive/archive_test.go | |
parent | Initial commit. (diff) | |
download | golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.tar.xz golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.zip |
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cmd/internal/archive/archive_test.go')
-rw-r--r-- | src/cmd/internal/archive/archive_test.go | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/src/cmd/internal/archive/archive_test.go b/src/cmd/internal/archive/archive_test.go new file mode 100644 index 0000000..0e2c7bc --- /dev/null +++ b/src/cmd/internal/archive/archive_test.go @@ -0,0 +1,388 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package archive + +import ( + "bytes" + "debug/elf" + "debug/macho" + "debug/pe" + "fmt" + "internal/testenv" + "internal/xcoff" + "io" + "os" + "path/filepath" + "runtime" + "sync" + "testing" + "unicode/utf8" +) + +var buildDir string + +func TestMain(m *testing.M) { + if !testenv.HasGoBuild() { + return + } + + exit := m.Run() + + if buildDir != "" { + os.RemoveAll(buildDir) + } + os.Exit(exit) +} + +func copyDir(dst, src string) error { + err := os.MkdirAll(dst, 0777) + if err != nil { + return err + } + entries, err := os.ReadDir(src) + if err != nil { + return err + } + for _, entry := range entries { + err = copyFile(filepath.Join(dst, entry.Name()), filepath.Join(src, entry.Name())) + if err != nil { + return err + } + } + return nil +} + +func copyFile(dst, src string) (err error) { + var s, d *os.File + s, err = os.Open(src) + if err != nil { + return err + } + defer s.Close() + d, err = os.Create(dst) + if err != nil { + return err + } + defer func() { + e := d.Close() + if err == nil { + err = e + } + }() + _, err = io.Copy(d, s) + if err != nil { + return err + } + return nil +} + +var ( + buildOnce sync.Once + builtGoobjs goobjPaths + buildErr error +) + +type goobjPaths struct { + go1obj string + go2obj string + goarchive string + cgoarchive string +} + +func buildGoobj(t *testing.T) goobjPaths { + buildOnce.Do(func() { + buildErr = func() (err error) { + buildDir, err = os.MkdirTemp("", "TestGoobj") + if err != nil { + return err + } + + go1obj := filepath.Join(buildDir, "go1.o") + go2obj := filepath.Join(buildDir, "go2.o") + goarchive := filepath.Join(buildDir, "go.a") + cgoarchive := "" + + gotool, err := testenv.GoTool() + if err != nil { + return err + } + + go1src := filepath.Join("testdata", "go1.go") + go2src := filepath.Join("testdata", "go2.go") + + importcfgfile := filepath.Join(buildDir, "importcfg") + testenv.WriteImportcfg(t, importcfgfile, nil) + + out, err := testenv.Command(t, gotool, "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-o", go1obj, go1src).CombinedOutput() + if err != nil { + return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go1obj, go1src, err, out) + } + out, err = testenv.Command(t, gotool, "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-o", go2obj, go2src).CombinedOutput() + if err != nil { + return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go2obj, go2src, err, out) + } + out, err = testenv.Command(t, gotool, "tool", "pack", "c", goarchive, go1obj, go2obj).CombinedOutput() + if err != nil { + return fmt.Errorf("go tool pack c %s %s %s: %v\n%s", goarchive, go1obj, go2obj, err, out) + } + + if testenv.HasCGO() { + cgoarchive = filepath.Join(buildDir, "mycgo.a") + gopath := filepath.Join(buildDir, "gopath") + err = copyDir(filepath.Join(gopath, "src", "mycgo"), filepath.Join("testdata", "mycgo")) + if err == nil { + err = os.WriteFile(filepath.Join(gopath, "src", "mycgo", "go.mod"), []byte("module mycgo\n"), 0666) + } + if err != nil { + return err + } + cmd := testenv.Command(t, gotool, "build", "-buildmode=archive", "-o", cgoarchive, "-gcflags=all="+os.Getenv("GO_GCFLAGS"), "mycgo") + cmd.Dir = filepath.Join(gopath, "src", "mycgo") + cmd.Env = append(os.Environ(), "GOPATH="+gopath) + out, err = cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("go install mycgo: %v\n%s", err, out) + } + } + + builtGoobjs = goobjPaths{ + go1obj: go1obj, + go2obj: go2obj, + goarchive: goarchive, + cgoarchive: cgoarchive, + } + return nil + }() + }) + + if buildErr != nil { + t.Helper() + t.Fatal(buildErr) + } + return builtGoobjs +} + +func TestParseGoobj(t *testing.T) { + path := buildGoobj(t).go1obj + + f, err := os.Open(path) + if err != nil { + t.Fatal(err) + } + defer f.Close() + + a, err := Parse(f, false) + if err != nil { + t.Fatal(err) + } + if len(a.Entries) != 2 { + t.Errorf("expect 2 entry, found %d", len(a.Entries)) + } + for _, e := range a.Entries { + if e.Type == EntryPkgDef { + continue + } + if e.Type != EntryGoObj { + t.Errorf("wrong type of object: want EntryGoObj, got %v", e.Type) + } + if !bytes.Contains(e.Obj.TextHeader, []byte(runtime.GOARCH)) { + t.Errorf("text header does not contain GOARCH %s: %q", runtime.GOARCH, e.Obj.TextHeader) + } + } +} + +func TestParseArchive(t *testing.T) { + path := buildGoobj(t).goarchive + + f, err := os.Open(path) + if err != nil { + t.Fatal(err) + } + defer f.Close() + + a, err := Parse(f, false) + if err != nil { + t.Fatal(err) + } + if len(a.Entries) != 3 { + t.Errorf("expect 3 entry, found %d", len(a.Entries)) + } + var found1 bool + var found2 bool + for _, e := range a.Entries { + if e.Type == EntryPkgDef { + continue + } + if e.Type != EntryGoObj { + t.Errorf("wrong type of object: want EntryGoObj, got %v", e.Type) + } + if !bytes.Contains(e.Obj.TextHeader, []byte(runtime.GOARCH)) { + t.Errorf("text header does not contain GOARCH %s: %q", runtime.GOARCH, e.Obj.TextHeader) + } + if e.Name == "go1.o" { + found1 = true + } + if e.Name == "go2.o" { + found2 = true + } + } + if !found1 { + t.Errorf(`object "go1.o" not found`) + } + if !found2 { + t.Errorf(`object "go2.o" not found`) + } +} + +func TestParseCGOArchive(t *testing.T) { + testenv.MustHaveCGO(t) + + path := buildGoobj(t).cgoarchive + + f, err := os.Open(path) + if err != nil { + t.Fatal(err) + } + defer f.Close() + + a, err := Parse(f, false) + if err != nil { + t.Fatal(err) + } + + c1 := "c1" + c2 := "c2" + switch runtime.GOOS { + case "darwin", "ios": + c1 = "_" + c1 + c2 = "_" + c2 + case "windows": + if runtime.GOARCH == "386" { + c1 = "_" + c1 + c2 = "_" + c2 + } + case "aix": + c1 = "." + c1 + c2 = "." + c2 + } + + var foundgo, found1, found2 bool + + for _, e := range a.Entries { + switch e.Type { + default: + t.Errorf("unknown object type") + case EntryPkgDef: + continue + case EntryGoObj: + foundgo = true + if !bytes.Contains(e.Obj.TextHeader, []byte(runtime.GOARCH)) { + t.Errorf("text header does not contain GOARCH %s: %q", runtime.GOARCH, e.Obj.TextHeader) + } + continue + case EntryNativeObj: + } + + obj := io.NewSectionReader(f, e.Offset, e.Size) + switch runtime.GOOS { + case "darwin", "ios": + mf, err := macho.NewFile(obj) + if err != nil { + t.Fatal(err) + } + if mf.Symtab == nil { + continue + } + for _, s := range mf.Symtab.Syms { + switch s.Name { + case c1: + found1 = true + case c2: + found2 = true + } + } + case "windows": + pf, err := pe.NewFile(obj) + if err != nil { + t.Fatal(err) + } + for _, s := range pf.Symbols { + switch s.Name { + case c1: + found1 = true + case c2: + found2 = true + } + } + case "aix": + xf, err := xcoff.NewFile(obj) + if err != nil { + t.Fatal(err) + } + for _, s := range xf.Symbols { + switch s.Name { + case c1: + found1 = true + case c2: + found2 = true + } + } + default: // ELF + ef, err := elf.NewFile(obj) + if err != nil { + t.Fatal(err) + } + syms, err := ef.Symbols() + if err != nil { + t.Fatal(err) + } + for _, s := range syms { + switch s.Name { + case c1: + found1 = true + case c2: + found2 = true + } + } + } + } + + if !foundgo { + t.Errorf(`go object not found`) + } + if !found1 { + t.Errorf(`symbol %q not found`, c1) + } + if !found2 { + t.Errorf(`symbol %q not found`, c2) + } +} + +func TestExactly16Bytes(t *testing.T) { + var tests = []string{ + "", + "a", + "日本語", + "1234567890123456", + "12345678901234567890", + "1234567890123本語4567890", + "12345678901234日本語567890", + "123456789012345日本語67890", + "1234567890123456日本語7890", + "1234567890123456日本語7日本語890", + } + for _, str := range tests { + got := exactly16Bytes(str) + if len(got) != 16 { + t.Errorf("exactly16Bytes(%q) is %q, length %d", str, got, len(got)) + } + // Make sure it is full runes. + for _, c := range got { + if c == utf8.RuneError { + t.Errorf("exactly16Bytes(%q) is %q, has partial rune", str, got) + } + } + } +} |