1
2
3
4
5 package main
6
7 import (
8 "archive/zip"
9 "bytes"
10 "fmt"
11 "io/fs"
12 "os"
13 "os/exec"
14 "path/filepath"
15 "runtime"
16 "strings"
17 "testing"
18
19 "golang.org/x/tools/internal/diffp"
20 "golang.org/x/tools/internal/testenv"
21 "golang.org/x/tools/txtar"
22 )
23
24 func init() {
25 if os.Getenv("TestGonewMain") == "1" {
26 main()
27 os.Exit(0)
28 }
29 }
30
31 func Test(t *testing.T) {
32 if !testenv.HasExec() {
33 t.Skipf("skipping test: exec not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
34 }
35 exe, err := os.Executable()
36 if err != nil {
37 t.Fatal(err)
38 }
39
40
41
42
43 files, err := filepath.Glob("testdata/*.txt")
44 if err != nil {
45 t.Fatal(err)
46 }
47 if len(files) == 0 {
48 t.Fatal("no test cases")
49 }
50
51 for _, file := range files {
52 t.Run(filepath.Base(file), func(t *testing.T) {
53 data, err := os.ReadFile(file)
54 if err != nil {
55 t.Fatal(err)
56 }
57 ar := txtar.Parse(data)
58
59
60
61
62 args := strings.Fields(string(ar.Comment))
63 wantFail := false
64 if len(args) > 0 && args[0] == "!" {
65 wantFail = true
66 args = args[1:]
67 }
68 if len(args) == 0 || args[0] != "gonew" {
69 t.Fatalf("invalid command comment")
70 }
71
72
73 dir := t.TempDir()
74 proxyDir := filepath.Join(dir, "proxy")
75 writeProxyFiles(t, proxyDir, ar)
76 extra := ""
77 if runtime.GOOS == "windows" {
78
79 extra = "/"
80 }
81 proxyURL := "file://" + extra + filepath.ToSlash(proxyDir)
82
83
84 out := filepath.Join(dir, "out")
85 if err := os.Mkdir(out, 0777); err != nil {
86 t.Fatal(err)
87 }
88 cmd := exec.Command(exe, args[1:]...)
89 cmd.Dir = out
90 cmd.Env = append(os.Environ(), "TestGonewMain=1", "GOPROXY="+proxyURL, "GOSUMDB=off")
91 var stdout bytes.Buffer
92 var stderr bytes.Buffer
93 cmd.Stdout = &stdout
94 cmd.Stderr = &stderr
95 if err := cmd.Run(); err == nil && wantFail {
96 t.Errorf("unexpected success exit")
97 } else if err != nil && !wantFail {
98 t.Errorf("unexpected failure exit")
99 }
100
101
102 want := make(map[string]txtar.File)
103 for _, f := range ar.Files {
104 if f.Name == "stdout" || f.Name == "stderr" || strings.HasPrefix(f.Name, "out/") {
105 want[f.Name] = f
106 }
107 }
108
109
110
111 stdoutBuf := bytes.ReplaceAll(stdout.Bytes(), []byte(`\`), []byte("/"))
112 stderrBuf := bytes.ReplaceAll(stderr.Bytes(), []byte(`\`), []byte("/"))
113
114 if !bytes.Equal(stdoutBuf, want["stdout"].Data) {
115 t.Errorf("wrong stdout: %s", diffp.Diff("want", want["stdout"].Data, "have", stdoutBuf))
116 }
117 if !bytes.Equal(stderrBuf, want["stderr"].Data) {
118 t.Errorf("wrong stderr: %s", diffp.Diff("want", want["stderr"].Data, "have", stderrBuf))
119 }
120 delete(want, "stdout")
121 delete(want, "stderr")
122
123
124 err = filepath.WalkDir(out, func(name string, info fs.DirEntry, err error) error {
125 if err != nil {
126 return err
127 }
128 if info.IsDir() {
129 return nil
130 }
131 data, err := os.ReadFile(name)
132 if err != nil {
133 return err
134 }
135 short := "out" + filepath.ToSlash(strings.TrimPrefix(name, out))
136 f, ok := want[short]
137 if !ok {
138 t.Errorf("unexpected file %s:\n%s", short, data)
139 return nil
140 }
141 delete(want, short)
142 if !bytes.Equal(data, f.Data) {
143 t.Errorf("wrong %s: %s", short, diffp.Diff("want", f.Data, "have", data))
144 }
145 return nil
146 })
147 if err != nil {
148 t.Fatal(err)
149 }
150 for name := range want {
151 t.Errorf("missing file %s", name)
152 }
153 })
154 }
155 }
156
157
158 type Zip struct {
159 buf bytes.Buffer
160 w *zip.Writer
161 }
162
163
164
165
166 func writeProxyFiles(t *testing.T, proxy string, ar *txtar.Archive) {
167 zips := make(map[string]*Zip)
168 others := make(map[string]string)
169 for _, f := range ar.Files {
170 i := strings.Index(f.Name, "@")
171 if i < 0 {
172 continue
173 }
174 j := strings.Index(f.Name[i:], "/")
175 if j < 0 {
176 t.Fatalf("unexpected archive file %s", f.Name)
177 }
178 j += i
179 mod, vers, file := f.Name[:i], f.Name[i+1:j], f.Name[j+1:]
180 zipName := mod + "/@v/" + vers + ".zip"
181 z := zips[zipName]
182 if z == nil {
183 others[mod+"/@v/list"] += vers + "\n"
184 others[mod+"/@v/"+vers+".info"] = fmt.Sprintf("{%q: %q}\n", "Version", vers)
185 z = new(Zip)
186 z.w = zip.NewWriter(&z.buf)
187 zips[zipName] = z
188 }
189 if file == "go.mod" {
190 others[mod+"/@v/"+vers+".mod"] = string(f.Data)
191 }
192 w, err := z.w.Create(f.Name)
193 if err != nil {
194 t.Fatal(err)
195 }
196 if _, err := w.Write(f.Data); err != nil {
197 t.Fatal(err)
198 }
199 }
200
201 for name, z := range zips {
202 if err := z.w.Close(); err != nil {
203 t.Fatal(err)
204 }
205 if err := os.MkdirAll(filepath.Dir(filepath.Join(proxy, name)), 0777); err != nil {
206 t.Fatal(err)
207 }
208 if err := os.WriteFile(filepath.Join(proxy, name), z.buf.Bytes(), 0666); err != nil {
209 t.Fatal(err)
210 }
211 }
212 for name, data := range others {
213
214 if err := os.WriteFile(filepath.Join(proxy, name), []byte(data), 0666); err != nil {
215 t.Fatal(err)
216 }
217 }
218 }
219
View as plain text