summaryrefslogtreecommitdiffstats
path: root/src/cmd/internal/archive/archive_test.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
commit43a123c1ae6613b3efeed291fa552ecd909d3acf (patch)
treefd92518b7024bc74031f78a1cf9e454b65e73665 /src/cmd/internal/archive/archive_test.go
parentInitial commit. (diff)
downloadgolang-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.go388
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)
+ }
+ }
+ }
+}