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 testenv.MustInternalLink(t, false)
167
168 dir := t.TempDir()
169 hello := filepath.Join(dir, "hello.go")
170 prog := `
171 package main
172 func main() {
173 println("hello world")
174 }
175 `
176 err := os.WriteFile(hello, []byte(prog), 0666)
177 if err != nil {
178 t.Fatal(err)
179 }
180
181 run := func(args ...string) string {
182 return doRun(t, dir, args...)
183 }
184
185 importcfgfile := filepath.Join(dir, "hello.importcfg")
186 testenv.WriteImportcfg(t, importcfgfile, nil, hello)
187
188 goBin := testenv.GoToolPath(t)
189 run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "hello.go")
190 run(packPath(t), "grc", "hello.a", "hello.o")
191 run(goBin, "tool", "link", "-importcfg="+importcfgfile, "-o", "a.out", "hello.a")
192 out := run("./a.out")
193 if out != "hello world\n" {
194 t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
195 }
196 }
197
198
199 func TestLargeDefs(t *testing.T) {
200 if testing.Short() {
201 t.Skip("skipping in -short mode")
202 }
203 testenv.MustHaveGoBuild(t)
204
205 dir := t.TempDir()
206 large := filepath.Join(dir, "large.go")
207 f, err := os.Create(large)
208 if err != nil {
209 t.Fatal(err)
210 }
211 b := bufio.NewWriter(f)
212
213 printf := func(format string, args ...any) {
214 _, err := fmt.Fprintf(b, format, args...)
215 if err != nil {
216 t.Fatalf("Writing to %s: %v", large, err)
217 }
218 }
219
220 printf("package large\n\ntype T struct {\n")
221 for i := 0; i < 1000; i++ {
222 printf("f%d int `tag:\"", i)
223 for j := 0; j < 100; j++ {
224 printf("t%d=%d,", j, j)
225 }
226 printf("\"`\n")
227 }
228 printf("}\n")
229 if err = b.Flush(); err != nil {
230 t.Fatal(err)
231 }
232 if err = f.Close(); err != nil {
233 t.Fatal(err)
234 }
235
236 main := filepath.Join(dir, "main.go")
237 prog := `
238 package main
239 import "large"
240 var V large.T
241 func main() {
242 println("ok")
243 }
244 `
245 err = os.WriteFile(main, []byte(prog), 0666)
246 if err != nil {
247 t.Fatal(err)
248 }
249
250 run := func(args ...string) string {
251 return doRun(t, dir, args...)
252 }
253
254 importcfgfile := filepath.Join(dir, "hello.importcfg")
255 testenv.WriteImportcfg(t, importcfgfile, nil)
256
257 goBin := testenv.GoToolPath(t)
258 run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=large", "large.go")
259 run(packPath(t), "grc", "large.a", "large.o")
260 testenv.WriteImportcfg(t, importcfgfile, map[string]string{"large": filepath.Join(dir, "large.o")}, "runtime")
261 run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
262 run(goBin, "tool", "link", "-importcfg="+importcfgfile, "-L", ".", "-o", "a.out", "main.o")
263 out := run("./a.out")
264 if out != "ok\n" {
265 t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
266 }
267 }
268
269
270
271 func TestIssue21703(t *testing.T) {
272 testenv.MustHaveGoBuild(t)
273
274 dir := t.TempDir()
275
276 const aSrc = `package a; const X = "\n!\n"`
277 err := os.WriteFile(filepath.Join(dir, "a.go"), []byte(aSrc), 0666)
278 if err != nil {
279 t.Fatal(err)
280 }
281
282 const bSrc = `package b; import _ "a"`
283 err = os.WriteFile(filepath.Join(dir, "b.go"), []byte(bSrc), 0666)
284 if err != nil {
285 t.Fatal(err)
286 }
287
288 run := func(args ...string) string {
289 return doRun(t, dir, args...)
290 }
291
292 goBin := testenv.GoToolPath(t)
293 run(goBin, "tool", "compile", "-p=a", "a.go")
294 run(packPath(t), "c", "a.a", "a.o")
295 run(goBin, "tool", "compile", "-p=b", "-I", ".", "b.go")
296 }
297
298
299
300 func TestCreateWithCompilerObj(t *testing.T) {
301 testenv.MustHaveGoBuild(t)
302
303 dir := t.TempDir()
304 src := filepath.Join(dir, "p.go")
305 prog := "package p; var X = 42\n"
306 err := os.WriteFile(src, []byte(prog), 0666)
307 if err != nil {
308 t.Fatal(err)
309 }
310
311 run := func(args ...string) string {
312 return doRun(t, dir, args...)
313 }
314
315 goBin := testenv.GoToolPath(t)
316 run(goBin, "tool", "compile", "-pack", "-p=p", "-o", "p.a", "p.go")
317 run(packPath(t), "c", "packed.a", "p.a")
318 fi, err := os.Stat(filepath.Join(dir, "p.a"))
319 if err != nil {
320 t.Fatalf("stat p.a failed: %v", err)
321 }
322 fi2, err := os.Stat(filepath.Join(dir, "packed.a"))
323 if err != nil {
324 t.Fatalf("stat packed.a failed: %v", err)
325 }
326
327
328
329 if want, got := fi.Size(), fi2.Size(); want != got {
330 t.Errorf("packed file with different size: want %d, got %d", want, got)
331 }
332
333
334 run(goBin, "tool", "compile", "-p=p", "-linkobj", "p2.a", "-o", "p.x", "p.go")
335 run(packPath(t), "c", "packed2.a", "p2.a")
336 fi, err = os.Stat(filepath.Join(dir, "p2.a"))
337 if err != nil {
338 t.Fatalf("stat p2.a failed: %v", err)
339 }
340 fi2, err = os.Stat(filepath.Join(dir, "packed2.a"))
341 if err != nil {
342 t.Fatalf("stat packed2.a failed: %v", err)
343 }
344 if want, got := fi.Size(), fi2.Size(); want != got {
345 t.Errorf("packed file with different size: want %d, got %d", want, got)
346 }
347
348 run(packPath(t), "c", "packed3.a", "p.x")
349 fi, err = os.Stat(filepath.Join(dir, "p.x"))
350 if err != nil {
351 t.Fatalf("stat p.x failed: %v", err)
352 }
353 fi2, err = os.Stat(filepath.Join(dir, "packed3.a"))
354 if err != nil {
355 t.Fatalf("stat packed3.a failed: %v", err)
356 }
357 if want, got := fi.Size(), fi2.Size(); want != got {
358 t.Errorf("packed file with different size: want %d, got %d", want, got)
359 }
360 }
361
362
363 func TestRWithNonexistentFile(t *testing.T) {
364 testenv.MustHaveGoBuild(t)
365
366 dir := t.TempDir()
367 src := filepath.Join(dir, "p.go")
368 prog := "package p; var X = 42\n"
369 err := os.WriteFile(src, []byte(prog), 0666)
370 if err != nil {
371 t.Fatal(err)
372 }
373
374 run := func(args ...string) string {
375 return doRun(t, dir, args...)
376 }
377
378 goBin := testenv.GoToolPath(t)
379 run(goBin, "tool", "compile", "-p=p", "-o", "p.o", "p.go")
380 run(packPath(t), "r", "p.a", "p.o")
381 }
382
383
384 func doRun(t *testing.T, dir string, args ...string) string {
385 cmd := testenv.Command(t, args[0], args[1:]...)
386 cmd.Dir = dir
387 out, err := cmd.CombinedOutput()
388 if err != nil {
389 if t.Name() == "TestHello" && runtime.GOOS == "android" && runtime.GOARCH == "arm64" {
390 testenv.SkipFlaky(t, 58806)
391 }
392 t.Fatalf("%v: %v\n%s", args, err, string(out))
393 }
394 return string(out)
395 }
396
397
398
399 var helloFile = &FakeFile{
400 name: "hello",
401 contents: "hello world",
402 mode: 0644,
403 }
404
405 var goodbyeFile = &FakeFile{
406 name: "goodbye",
407 contents: "Sayonara, Jim",
408 mode: 0644,
409 }
410
411
412 type FakeFile struct {
413 name string
414 contents string
415 mode fs.FileMode
416 offset int
417 }
418
419
420 func (f *FakeFile) Reset() *FakeFile {
421 f.offset = 0
422 return f
423 }
424
425
426
427 func (f *FakeFile) Name() string {
428
429 return f.name
430 }
431
432 func (f *FakeFile) Stat() (fs.FileInfo, error) {
433 return f, nil
434 }
435
436 func (f *FakeFile) Read(p []byte) (int, error) {
437 if f.offset >= len(f.contents) {
438 return 0, io.EOF
439 }
440 n := copy(p, f.contents[f.offset:])
441 f.offset += n
442 return n, nil
443 }
444
445 func (f *FakeFile) Close() error {
446 return nil
447 }
448
449
450
451 func (f *FakeFile) Size() int64 {
452 return int64(len(f.contents))
453 }
454
455 func (f *FakeFile) Mode() fs.FileMode {
456 return f.mode
457 }
458
459 func (f *FakeFile) ModTime() time.Time {
460 return time.Time{}
461 }
462
463 func (f *FakeFile) IsDir() bool {
464 return false
465 }
466
467 func (f *FakeFile) Sys() any {
468 return nil
469 }
470
471 func (f *FakeFile) String() string {
472 return fs.FormatFileInfo(f)
473 }
474
475
476
477 func (f *FakeFile) Entry() *archive.Entry {
478 return &archive.Entry{
479 Name: f.name,
480 Mtime: 0,
481 Uid: 0,
482 Gid: 0,
483 Mode: f.mode,
484 Data: archive.Data{Size: int64(len(f.contents))},
485 }
486 }
487
View as plain text