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