Source file
src/cmd/pack/pack_test.go
1
2
3
4
5 package main
6
7 import (
8 "bufio"
9 "cmd/internal/archive"
10 "fmt"
11 "internal/testenv"
12 "io"
13 "io/fs"
14 "os"
15 "path/filepath"
16 "runtime"
17 "strings"
18 "testing"
19 "time"
20 )
21
22
23
24 func TestMain(m *testing.M) {
25 if os.Getenv("GO_PACKTEST_IS_PACK") != "" {
26 main()
27 os.Exit(0)
28 }
29
30 os.Setenv("GO_PACKTEST_IS_PACK", "1")
31 os.Exit(m.Run())
32 }
33
34
35 func packPath(t testing.TB) string {
36 return testenv.Executable(t)
37 }
38
39
40 func testCreate(t *testing.T, dir string) {
41 name := filepath.Join(dir, "pack.a")
42 ar := openArchive(name, os.O_RDWR|os.O_CREATE, nil)
43
44 ar.addFile(helloFile.Reset())
45 ar.a.File().Close()
46
47 ar = openArchive(name, os.O_RDONLY, []string{helloFile.name})
48 var buf strings.Builder
49 stdout = &buf
50 verbose = true
51 defer func() {
52 stdout = os.Stdout
53 verbose = false
54 }()
55 ar.scan(ar.printContents)
56 ar.a.File().Close()
57 result := buf.String()
58
59 expect := fmt.Sprintf("%s\n%s", helloFile.name, helloFile.contents)
60 if result != expect {
61 t.Fatalf("expected %q got %q", expect, result)
62 }
63 }
64
65
66
67 func TestCreate(t *testing.T) {
68 dir := t.TempDir()
69 testCreate(t, dir)
70 }
71
72
73 func TestCreateTwice(t *testing.T) {
74 dir := t.TempDir()
75 testCreate(t, dir)
76 testCreate(t, dir)
77 }
78
79
80
81 func TestTableOfContents(t *testing.T) {
82 dir := t.TempDir()
83 name := filepath.Join(dir, "pack.a")
84 ar := openArchive(name, os.O_RDWR|os.O_CREATE, nil)
85
86
87 ar.addFile(helloFile.Reset())
88 ar.addFile(goodbyeFile.Reset())
89 ar.a.File().Close()
90
91
92 var buf strings.Builder
93 stdout = &buf
94 verbose = true
95 defer func() {
96 stdout = os.Stdout
97 verbose = false
98 }()
99 ar = openArchive(name, os.O_RDONLY, nil)
100 ar.scan(ar.tableOfContents)
101 ar.a.File().Close()
102 result := buf.String()
103
104 expect := fmt.Sprintf("%s\n%s\n", helloFile.Entry(), goodbyeFile.Entry())
105 if result != expect {
106 t.Fatalf("expected %q got %q", expect, result)
107 }
108
109
110 verbose = false
111 buf.Reset()
112 ar = openArchive(name, os.O_RDONLY, nil)
113 ar.scan(ar.tableOfContents)
114 ar.a.File().Close()
115 result = buf.String()
116
117 expect = fmt.Sprintf("%s\n%s\n", helloFile.name, goodbyeFile.name)
118 if result != expect {
119 t.Fatalf("expected %q got %q", expect, result)
120 }
121
122
123 verbose = false
124 buf.Reset()
125 ar = openArchive(name, os.O_RDONLY, []string{helloFile.name})
126 ar.scan(ar.tableOfContents)
127 ar.a.File().Close()
128 result = buf.String()
129
130 expect = fmt.Sprintf("%s\n", helloFile.name)
131 if result != expect {
132 t.Fatalf("expected %q got %q", expect, result)
133 }
134 }
135
136
137
138 func TestExtract(t *testing.T) {
139 dir := t.TempDir()
140 name := filepath.Join(dir, "pack.a")
141 ar := openArchive(name, os.O_RDWR|os.O_CREATE, nil)
142
143 ar.addFile(helloFile.Reset())
144 ar.addFile(goodbyeFile.Reset())
145 ar.a.File().Close()
146
147 t.Chdir(dir)
148 ar = openArchive(name, os.O_RDONLY, []string{goodbyeFile.name})
149 ar.scan(ar.extractContents)
150 ar.a.File().Close()
151 data, err := os.ReadFile(goodbyeFile.name)
152 if err != nil {
153 t.Fatal(err)
154 }
155
156 result := string(data)
157 expect := goodbyeFile.contents
158 if result != expect {
159 t.Fatalf("expected %q got %q", expect, result)
160 }
161 }
162
163
164 func TestHello(t *testing.T) {
165 testenv.MustHaveGoBuild(t)
166
167
168 testenv.MustInternalLink(t, testenv.NoSpecialBuildTypes)
169
170 dir := t.TempDir()
171 hello := filepath.Join(dir, "hello.go")
172 prog := `
173 package main
174 func main() {
175 println("hello world")
176 }
177 `
178 err := os.WriteFile(hello, []byte(prog), 0666)
179 if err != nil {
180 t.Fatal(err)
181 }
182
183 run := func(args ...string) string {
184 return doRun(t, dir, args...)
185 }
186
187 importcfgfile := filepath.Join(dir, "hello.importcfg")
188 testenv.WriteImportcfg(t, importcfgfile, nil, hello)
189
190 goBin := testenv.GoToolPath(t)
191 run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "hello.go")
192 run(packPath(t), "grc", "hello.a", "hello.o")
193 run(goBin, "tool", "link", "-importcfg="+importcfgfile, "-o", "a.out", "hello.a")
194 out := run("./a.out")
195 if out != "hello world\n" {
196 t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
197 }
198 }
199
200
201 func TestLargeDefs(t *testing.T) {
202 if testing.Short() {
203 t.Skip("skipping in -short mode")
204 }
205 testenv.MustHaveGoBuild(t)
206
207 dir := t.TempDir()
208 large := filepath.Join(dir, "large.go")
209 f, err := os.Create(large)
210 if err != nil {
211 t.Fatal(err)
212 }
213 b := bufio.NewWriter(f)
214
215 printf := func(format string, args ...any) {
216 _, err := fmt.Fprintf(b, format, args...)
217 if err != nil {
218 t.Fatalf("Writing to %s: %v", large, err)
219 }
220 }
221
222 printf("package large\n\ntype T struct {\n")
223 for i := 0; i < 1000; i++ {
224 printf("f%d int `tag:\"", i)
225 for j := 0; j < 100; j++ {
226 printf("t%d=%d,", j, j)
227 }
228 printf("\"`\n")
229 }
230 printf("}\n")
231 if err = b.Flush(); err != nil {
232 t.Fatal(err)
233 }
234 if err = f.Close(); err != nil {
235 t.Fatal(err)
236 }
237
238 main := filepath.Join(dir, "main.go")
239 prog := `
240 package main
241 import "large"
242 var V large.T
243 func main() {
244 println("ok")
245 }
246 `
247 err = os.WriteFile(main, []byte(prog), 0666)
248 if err != nil {
249 t.Fatal(err)
250 }
251
252 run := func(args ...string) string {
253 return doRun(t, dir, args...)
254 }
255
256 importcfgfile := filepath.Join(dir, "hello.importcfg")
257 testenv.WriteImportcfg(t, importcfgfile, nil)
258
259 goBin := testenv.GoToolPath(t)
260 run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=large", "large.go")
261 run(packPath(t), "grc", "large.a", "large.o")
262 testenv.WriteImportcfg(t, importcfgfile, map[string]string{"large": filepath.Join(dir, "large.o")}, "runtime")
263 run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
264 run(goBin, "tool", "link", "-importcfg="+importcfgfile, "-L", ".", "-o", "a.out", "main.o")
265 out := run("./a.out")
266 if out != "ok\n" {
267 t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
268 }
269 }
270
271
272
273 func TestIssue21703(t *testing.T) {
274 testenv.MustHaveGoBuild(t)
275
276 dir := t.TempDir()
277
278 const aSrc = `package a; const X = "\n!\n"`
279 err := os.WriteFile(filepath.Join(dir, "a.go"), []byte(aSrc), 0666)
280 if err != nil {
281 t.Fatal(err)
282 }
283
284 const bSrc = `package b; import _ "a"`
285 err = os.WriteFile(filepath.Join(dir, "b.go"), []byte(bSrc), 0666)
286 if err != nil {
287 t.Fatal(err)
288 }
289
290 run := func(args ...string) string {
291 return doRun(t, dir, args...)
292 }
293
294 goBin := testenv.GoToolPath(t)
295 run(goBin, "tool", "compile", "-p=a", "a.go")
296 run(packPath(t), "c", "a.a", "a.o")
297 run(goBin, "tool", "compile", "-p=b", "-I", ".", "b.go")
298 }
299
300
301
302 func TestCreateWithCompilerObj(t *testing.T) {
303 testenv.MustHaveGoBuild(t)
304
305 dir := t.TempDir()
306 src := filepath.Join(dir, "p.go")
307 prog := "package p; var X = 42\n"
308 err := os.WriteFile(src, []byte(prog), 0666)
309 if err != nil {
310 t.Fatal(err)
311 }
312
313 run := func(args ...string) string {
314 return doRun(t, dir, args...)
315 }
316
317 goBin := testenv.GoToolPath(t)
318 run(goBin, "tool", "compile", "-pack", "-p=p", "-o", "p.a", "p.go")
319 run(packPath(t), "c", "packed.a", "p.a")
320 fi, err := os.Stat(filepath.Join(dir, "p.a"))
321 if err != nil {
322 t.Fatalf("stat p.a failed: %v", err)
323 }
324 fi2, err := os.Stat(filepath.Join(dir, "packed.a"))
325 if err != nil {
326 t.Fatalf("stat packed.a failed: %v", err)
327 }
328
329
330
331 if want, got := fi.Size(), fi2.Size(); want != got {
332 t.Errorf("packed file with different size: want %d, got %d", want, got)
333 }
334
335
336 run(goBin, "tool", "compile", "-p=p", "-linkobj", "p2.a", "-o", "p.x", "p.go")
337 run(packPath(t), "c", "packed2.a", "p2.a")
338 fi, err = os.Stat(filepath.Join(dir, "p2.a"))
339 if err != nil {
340 t.Fatalf("stat p2.a failed: %v", err)
341 }
342 fi2, err = os.Stat(filepath.Join(dir, "packed2.a"))
343 if err != nil {
344 t.Fatalf("stat packed2.a failed: %v", err)
345 }
346 if want, got := fi.Size(), fi2.Size(); want != got {
347 t.Errorf("packed file with different size: want %d, got %d", want, got)
348 }
349
350 run(packPath(t), "c", "packed3.a", "p.x")
351 fi, err = os.Stat(filepath.Join(dir, "p.x"))
352 if err != nil {
353 t.Fatalf("stat p.x failed: %v", err)
354 }
355 fi2, err = os.Stat(filepath.Join(dir, "packed3.a"))
356 if err != nil {
357 t.Fatalf("stat packed3.a failed: %v", err)
358 }
359 if want, got := fi.Size(), fi2.Size(); want != got {
360 t.Errorf("packed file with different size: want %d, got %d", want, got)
361 }
362 }
363
364
365 func TestRWithNonexistentFile(t *testing.T) {
366 testenv.MustHaveGoBuild(t)
367
368 dir := t.TempDir()
369 src := filepath.Join(dir, "p.go")
370 prog := "package p; var X = 42\n"
371 err := os.WriteFile(src, []byte(prog), 0666)
372 if err != nil {
373 t.Fatal(err)
374 }
375
376 run := func(args ...string) string {
377 return doRun(t, dir, args...)
378 }
379
380 goBin := testenv.GoToolPath(t)
381 run(goBin, "tool", "compile", "-p=p", "-o", "p.o", "p.go")
382 run(packPath(t), "r", "p.a", "p.o")
383 }
384
385
386 func doRun(t *testing.T, dir string, args ...string) string {
387 cmd := testenv.Command(t, args[0], args[1:]...)
388 cmd.Dir = dir
389 out, err := cmd.CombinedOutput()
390 if err != nil {
391 if t.Name() == "TestHello" && runtime.GOOS == "android" && runtime.GOARCH == "arm64" {
392 testenv.SkipFlaky(t, 58806)
393 }
394 t.Fatalf("%v: %v\n%s", args, err, string(out))
395 }
396 return string(out)
397 }
398
399
400
401 var helloFile = &FakeFile{
402 name: "hello",
403 contents: "hello world",
404 mode: 0644,
405 }
406
407 var goodbyeFile = &FakeFile{
408 name: "goodbye",
409 contents: "Sayonara, Jim",
410 mode: 0644,
411 }
412
413
414 type FakeFile struct {
415 name string
416 contents string
417 mode fs.FileMode
418 offset int
419 }
420
421
422 func (f *FakeFile) Reset() *FakeFile {
423 f.offset = 0
424 return f
425 }
426
427
428
429 func (f *FakeFile) Name() string {
430
431 return f.name
432 }
433
434 func (f *FakeFile) Stat() (fs.FileInfo, error) {
435 return f, nil
436 }
437
438 func (f *FakeFile) Read(p []byte) (int, error) {
439 if f.offset >= len(f.contents) {
440 return 0, io.EOF
441 }
442 n := copy(p, f.contents[f.offset:])
443 f.offset += n
444 return n, nil
445 }
446
447 func (f *FakeFile) Close() error {
448 return nil
449 }
450
451
452
453 func (f *FakeFile) Size() int64 {
454 return int64(len(f.contents))
455 }
456
457 func (f *FakeFile) Mode() fs.FileMode {
458 return f.mode
459 }
460
461 func (f *FakeFile) ModTime() time.Time {
462 return time.Time{}
463 }
464
465 func (f *FakeFile) IsDir() bool {
466 return false
467 }
468
469 func (f *FakeFile) Sys() any {
470 return nil
471 }
472
473 func (f *FakeFile) String() string {
474 return fs.FormatFileInfo(f)
475 }
476
477
478
479 func (f *FakeFile) Entry() *archive.Entry {
480 return &archive.Entry{
481 Name: f.name,
482 Mtime: 0,
483 Uid: 0,
484 Gid: 0,
485 Mode: f.mode,
486 Data: archive.Data{Size: int64(len(f.contents))},
487 }
488 }
489
View as plain text