1
2
3
4
5 package noder_test
6
7 import (
8 "encoding/json"
9 "flag"
10 exec "internal/execabs"
11 "os"
12 "reflect"
13 "runtime"
14 "strings"
15 "testing"
16 )
17
18 var (
19 flagCmp = flag.Bool("cmp", false, "enable TestUnifiedCompare")
20 flagPkgs = flag.String("pkgs", "std", "list of packages to compare (ignored in -short mode)")
21 flagAll = flag.Bool("all", false, "enable testing of all GOOS/GOARCH targets")
22 flagParallel = flag.Bool("parallel", false, "test GOOS/GOARCH targets in parallel")
23 )
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 func TestUnifiedCompare(t *testing.T) {
41
42
43 if !*flagCmp {
44 t.Skip("skipping TestUnifiedCompare (use -cmp to enable)")
45 }
46
47 targets, err := exec.Command("go", "tool", "dist", "list").Output()
48 if err != nil {
49 t.Fatal(err)
50 }
51
52 for _, target := range strings.Fields(string(targets)) {
53 t.Run(target, func(t *testing.T) {
54 parts := strings.Split(target, "/")
55 goos, goarch := parts[0], parts[1]
56
57 if !(*flagAll || goos == runtime.GOOS && goarch == runtime.GOARCH) {
58 t.Skip("skipping non-native target (use -all to enable)")
59 }
60 if *flagParallel {
61 t.Parallel()
62 }
63
64 pkgs1 := loadPackages(t, goos, goarch, "-d=unified=0 -d=inlfuncswithclosures=0 -d=unifiedquirks=1 -G=0")
65 pkgs2 := loadPackages(t, goos, goarch, "-d=unified=1 -d=inlfuncswithclosures=0 -d=unifiedquirks=1 -G=0")
66
67 if len(pkgs1) != len(pkgs2) {
68 t.Fatalf("length mismatch: %v != %v", len(pkgs1), len(pkgs2))
69 }
70
71 for i := range pkgs1 {
72 pkg1 := pkgs1[i]
73 pkg2 := pkgs2[i]
74
75 path := pkg1.ImportPath
76 if path != pkg2.ImportPath {
77 t.Fatalf("mismatched paths: %q != %q", path, pkg2.ImportPath)
78 }
79
80
81
82 if pkg1.Export == "" && pkg2.Export == "" {
83 continue
84 }
85
86 if pkg1.BuildID == pkg2.BuildID {
87 t.Errorf("package %q: build IDs unexpectedly matched", path)
88 }
89
90
91
92
93
94
95
96
97
98
99 file1 := strings.Split(readFile(t, pkg1.Export), pkg1.BuildID)
100 file2 := strings.Split(readFile(t, pkg2.Export), pkg2.BuildID)
101 if !reflect.DeepEqual(file1, file2) {
102 t.Errorf("package %q: compile output differs", path)
103 }
104 }
105 })
106 }
107 }
108
109 type pkg struct {
110 ImportPath string
111 Export string
112 BuildID string
113 Incomplete bool
114 }
115
116 func loadPackages(t *testing.T, goos, goarch, gcflags string) []pkg {
117 args := []string{"list", "-e", "-export", "-json", "-gcflags=all=" + gcflags, "--"}
118 if testing.Short() {
119 t.Log("short testing mode; only testing package runtime")
120 args = append(args, "runtime")
121 } else {
122 args = append(args, strings.Fields(*flagPkgs)...)
123 }
124
125 cmd := exec.Command("go", args...)
126 cmd.Env = append(os.Environ(), "GOOS="+goos, "GOARCH="+goarch)
127 cmd.Stderr = os.Stderr
128 t.Logf("running %v", cmd)
129 stdout, err := cmd.StdoutPipe()
130 if err != nil {
131 t.Fatal(err)
132 }
133 if err := cmd.Start(); err != nil {
134 t.Fatal(err)
135 }
136
137 var res []pkg
138 for dec := json.NewDecoder(stdout); dec.More(); {
139 var pkg pkg
140 if err := dec.Decode(&pkg); err != nil {
141 t.Fatal(err)
142 }
143 if pkg.Incomplete {
144 t.Fatalf("incomplete package: %q", pkg.ImportPath)
145 }
146 res = append(res, pkg)
147 }
148 if err := cmd.Wait(); err != nil {
149 t.Fatal(err)
150 }
151 return res
152 }
153
154 func readFile(t *testing.T, name string) string {
155 buf, err := os.ReadFile(name)
156 if err != nil {
157 t.Fatal(err)
158 }
159 return string(buf)
160 }
161
View as plain text