github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/pack/pack_test.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bufio" 9 "bytes" 10 "fmt" 11 "io" 12 "io/ioutil" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "regexp" 17 "runtime" 18 "testing" 19 "time" 20 "unicode/utf8" 21 ) 22 23 func TestExactly16Bytes(t *testing.T) { 24 var tests = []string{ 25 "", 26 "a", 27 "日本語", 28 "1234567890123456", 29 "12345678901234567890", 30 "1234567890123本語4567890", 31 "12345678901234日本語567890", 32 "123456789012345日本語67890", 33 "1234567890123456日本語7890", 34 "1234567890123456日本語7日本語890", 35 } 36 for _, str := range tests { 37 got := exactly16Bytes(str) 38 if len(got) != 16 { 39 t.Errorf("exactly16Bytes(%q) is %q, length %d", str, got, len(got)) 40 } 41 // Make sure it is full runes. 42 for _, c := range got { 43 if c == utf8.RuneError { 44 t.Errorf("exactly16Bytes(%q) is %q, has partial rune", str, got) 45 } 46 } 47 } 48 } 49 50 // tmpDir creates a temporary directory and returns its name. 51 func tmpDir(t *testing.T) string { 52 name, err := ioutil.TempDir("", "pack") 53 if err != nil { 54 t.Fatal(err) 55 } 56 return name 57 } 58 59 // testCreate creates an archive in the specified directory. 60 func testCreate(t *testing.T, dir string) { 61 name := filepath.Join(dir, "pack.a") 62 ar := archive(name, os.O_RDWR, nil) 63 // Add an entry by hand. 64 ar.addFile(helloFile.Reset()) 65 ar.fd.Close() 66 // Now check it. 67 ar = archive(name, os.O_RDONLY, []string{helloFile.name}) 68 var buf bytes.Buffer 69 stdout = &buf 70 verbose = true 71 defer func() { 72 stdout = os.Stdout 73 verbose = false 74 }() 75 ar.scan(ar.printContents) 76 ar.fd.Close() 77 result := buf.String() 78 // Expect verbose output plus file contents. 79 expect := fmt.Sprintf("%s\n%s", helloFile.name, helloFile.contents) 80 if result != expect { 81 t.Fatalf("expected %q got %q", expect, result) 82 } 83 } 84 85 // Test that we can create an archive, write to it, and get the same contents back. 86 // Tests the rv and then the pv command on a new archive. 87 func TestCreate(t *testing.T) { 88 dir := tmpDir(t) 89 defer os.RemoveAll(dir) 90 testCreate(t, dir) 91 } 92 93 // Test that we can create an archive twice with the same name (Issue 8369). 94 func TestCreateTwice(t *testing.T) { 95 dir := tmpDir(t) 96 defer os.RemoveAll(dir) 97 testCreate(t, dir) 98 testCreate(t, dir) 99 } 100 101 // Test that we can create an archive, put some files in it, and get back a correct listing. 102 // Tests the tv command. 103 func TestTableOfContents(t *testing.T) { 104 dir := tmpDir(t) 105 defer os.RemoveAll(dir) 106 name := filepath.Join(dir, "pack.a") 107 ar := archive(name, os.O_RDWR, nil) 108 109 // Add some entries by hand. 110 ar.addFile(helloFile.Reset()) 111 ar.addFile(goodbyeFile.Reset()) 112 ar.fd.Close() 113 114 // Now print it. 115 ar = archive(name, os.O_RDONLY, nil) 116 var buf bytes.Buffer 117 stdout = &buf 118 verbose = true 119 defer func() { 120 stdout = os.Stdout 121 verbose = false 122 }() 123 ar.scan(ar.tableOfContents) 124 ar.fd.Close() 125 result := buf.String() 126 // Expect verbose listing. 127 expect := fmt.Sprintf("%s\n%s\n", helloFile.Entry(), goodbyeFile.Entry()) 128 if result != expect { 129 t.Fatalf("expected %q got %q", expect, result) 130 } 131 132 // Do it again without verbose. 133 verbose = false 134 buf.Reset() 135 ar = archive(name, os.O_RDONLY, nil) 136 ar.scan(ar.tableOfContents) 137 ar.fd.Close() 138 result = buf.String() 139 // Expect non-verbose listing. 140 expect = fmt.Sprintf("%s\n%s\n", helloFile.name, goodbyeFile.name) 141 if result != expect { 142 t.Fatalf("expected %q got %q", expect, result) 143 } 144 145 // Do it again with file list arguments. 146 verbose = false 147 buf.Reset() 148 ar = archive(name, os.O_RDONLY, []string{helloFile.name}) 149 ar.scan(ar.tableOfContents) 150 ar.fd.Close() 151 result = buf.String() 152 // Expect only helloFile. 153 expect = fmt.Sprintf("%s\n", helloFile.name) 154 if result != expect { 155 t.Fatalf("expected %q got %q", expect, result) 156 } 157 } 158 159 // Test that we can create an archive, put some files in it, and get back a file. 160 // Tests the x command. 161 func TestExtract(t *testing.T) { 162 dir := tmpDir(t) 163 defer os.RemoveAll(dir) 164 name := filepath.Join(dir, "pack.a") 165 ar := archive(name, os.O_RDWR, nil) 166 // Add some entries by hand. 167 ar.addFile(helloFile.Reset()) 168 ar.addFile(goodbyeFile.Reset()) 169 ar.fd.Close() 170 // Now extract one file. We chdir to the directory of the archive for simplicity. 171 pwd, err := os.Getwd() 172 if err != nil { 173 t.Fatal("os.Getwd: ", err) 174 } 175 err = os.Chdir(dir) 176 if err != nil { 177 t.Fatal("os.Chdir: ", err) 178 } 179 defer func() { 180 err := os.Chdir(pwd) 181 if err != nil { 182 t.Fatal("os.Chdir: ", err) 183 } 184 }() 185 ar = archive(name, os.O_RDONLY, []string{goodbyeFile.name}) 186 ar.scan(ar.extractContents) 187 ar.fd.Close() 188 data, err := ioutil.ReadFile(goodbyeFile.name) 189 if err != nil { 190 t.Fatal(err) 191 } 192 // Expect contents of file. 193 result := string(data) 194 expect := goodbyeFile.contents 195 if result != expect { 196 t.Fatalf("expected %q got %q", expect, result) 197 } 198 } 199 200 // Test that pack-created archives can be understood by the tools. 201 func TestHello(t *testing.T) { 202 switch runtime.GOOS { 203 case "android", "nacl": 204 t.Skipf("skipping on %s", runtime.GOOS) 205 } 206 207 dir := tmpDir(t) 208 defer os.RemoveAll(dir) 209 hello := filepath.Join(dir, "hello.go") 210 prog := ` 211 package main 212 func main() { 213 println("hello world") 214 } 215 ` 216 err := ioutil.WriteFile(hello, []byte(prog), 0666) 217 if err != nil { 218 t.Fatal(err) 219 } 220 221 char := findChar(t, dir) 222 223 run := func(args ...string) string { 224 return doRun(t, dir, args...) 225 } 226 227 run("go", "build", "cmd/pack") // writes pack binary to dir 228 run("go", "tool", char+"g", "hello.go") 229 run("./pack", "grc", "hello.a", "hello."+char) 230 run("go", "tool", char+"l", "-o", "a.out", "hello.a") 231 out := run("./a.out") 232 if out != "hello world\n" { 233 t.Fatalf("incorrect output: %q, want %q", out, "hello world\n") 234 } 235 } 236 237 // Test that pack works with very long lines in PKGDEF. 238 func TestLargeDefs(t *testing.T) { 239 switch runtime.GOOS { 240 case "android", "nacl": 241 t.Skipf("skipping on %s", runtime.GOOS) 242 } 243 244 dir := tmpDir(t) 245 defer os.RemoveAll(dir) 246 large := filepath.Join(dir, "large.go") 247 f, err := os.Create(large) 248 if err != nil { 249 t.Fatal(err) 250 } 251 b := bufio.NewWriter(f) 252 253 printf := func(format string, args ...interface{}) { 254 _, err := fmt.Fprintf(b, format, args...) 255 if err != nil { 256 t.Fatalf("Writing to %s: %v", large, err) 257 } 258 } 259 260 printf("package large\n\ntype T struct {\n") 261 for i := 0; i < 10000; i++ { 262 printf("f%d int `tag:\"", i) 263 for j := 0; j < 100; j++ { 264 printf("t%d=%d,", j, j) 265 } 266 printf("\"`\n") 267 } 268 printf("}\n") 269 if err = b.Flush(); err != nil { 270 t.Fatal(err) 271 } 272 if err = f.Close(); err != nil { 273 t.Fatal(err) 274 } 275 276 main := filepath.Join(dir, "main.go") 277 prog := ` 278 package main 279 import "large" 280 var V large.T 281 func main() { 282 println("ok") 283 } 284 ` 285 err = ioutil.WriteFile(main, []byte(prog), 0666) 286 if err != nil { 287 t.Fatal(err) 288 } 289 290 char := findChar(t, dir) 291 292 run := func(args ...string) string { 293 return doRun(t, dir, args...) 294 } 295 296 run("go", "build", "cmd/pack") // writes pack binary to dir 297 run("go", "tool", char+"g", "large.go") 298 run("./pack", "grc", "large.a", "large."+char) 299 run("go", "tool", char+"g", "-I", ".", "main.go") 300 run("go", "tool", char+"l", "-L", ".", "-o", "a.out", "main."+char) 301 out := run("./a.out") 302 if out != "ok\n" { 303 t.Fatalf("incorrect output: %q, want %q", out, "ok\n") 304 } 305 } 306 307 // doRun runs a program in a directory and returns the output. 308 func doRun(t *testing.T, dir string, args ...string) string { 309 cmd := exec.Command(args[0], args[1:]...) 310 cmd.Dir = dir 311 out, err := cmd.CombinedOutput() 312 if err != nil { 313 t.Fatalf("%v: %v\n%s", args, err, string(out)) 314 } 315 return string(out) 316 } 317 318 // findChar returns the architecture character for the go command. 319 func findChar(t *testing.T, dir string) string { 320 out := doRun(t, dir, "go", "env") 321 re, err := regexp.Compile(`\s*GOCHAR=['"]?(\w)['"]?`) 322 if err != nil { 323 t.Fatal(err) 324 } 325 fields := re.FindStringSubmatch(out) 326 if fields == nil { 327 t.Fatal("cannot find GOCHAR in 'go env' output:\n", out) 328 } 329 return fields[1] 330 } 331 332 // Fake implementation of files. 333 334 var helloFile = &FakeFile{ 335 name: "hello", 336 contents: "hello world", // 11 bytes, an odd number. 337 mode: 0644, 338 } 339 340 var goodbyeFile = &FakeFile{ 341 name: "goodbye", 342 contents: "Sayonara, Jim", // 13 bytes, another odd number. 343 mode: 0644, 344 } 345 346 // FakeFile implements FileLike and also os.FileInfo. 347 type FakeFile struct { 348 name string 349 contents string 350 mode os.FileMode 351 offset int 352 } 353 354 // Reset prepares a FakeFile for reuse. 355 func (f *FakeFile) Reset() *FakeFile { 356 f.offset = 0 357 return f 358 } 359 360 // FileLike methods. 361 362 func (f *FakeFile) Name() string { 363 // A bit of a cheat: we only have a basename, so that's also ok for FileInfo. 364 return f.name 365 } 366 367 func (f *FakeFile) Stat() (os.FileInfo, error) { 368 return f, nil 369 } 370 371 func (f *FakeFile) Read(p []byte) (int, error) { 372 if f.offset >= len(f.contents) { 373 return 0, io.EOF 374 } 375 n := copy(p, f.contents[f.offset:]) 376 f.offset += n 377 return n, nil 378 } 379 380 func (f *FakeFile) Close() error { 381 return nil 382 } 383 384 // os.FileInfo methods. 385 386 func (f *FakeFile) Size() int64 { 387 return int64(len(f.contents)) 388 } 389 390 func (f *FakeFile) Mode() os.FileMode { 391 return f.mode 392 } 393 394 func (f *FakeFile) ModTime() time.Time { 395 return time.Time{} 396 } 397 398 func (f *FakeFile) IsDir() bool { 399 return false 400 } 401 402 func (f *FakeFile) Sys() interface{} { 403 return nil 404 } 405 406 // Special helpers. 407 408 func (f *FakeFile) Entry() *Entry { 409 return &Entry{ 410 name: f.name, 411 mtime: 0, // Defined to be zero. 412 uid: 0, // Ditto. 413 gid: 0, // Ditto. 414 mode: f.mode, 415 size: int64(len(f.contents)), 416 } 417 }