1// Copyright (c) 2018, Google Inc. 2// 3// Permission to use, copy, modify, and/or distribute this software for any 4// purpose with or without fee is hereby granted, provided that the above 5// copyright notice and this permission notice appear in all copies. 6// 7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15package ar 16 17import ( 18 "bytes" 19 "flag" 20 "io/ioutil" 21 "os" 22 "path/filepath" 23 "testing" 24) 25 26var testDataDir = flag.String("testdata", "testdata", "The path to the test data directory.") 27 28type arTest struct { 29 name string 30 in string 31 out map[string]string 32 // allowPadding is true if the contents may have trailing newlines at end. 33 // On macOS, ar calls ranlib which pads all inputs up to eight bytes with 34 // newlines. Unlike ar's native padding up to two bytes, this padding is 35 // included in the size field, so it is not removed when decoding. 36 allowPadding bool 37} 38 39func (test *arTest) Path(file string) string { 40 return filepath.Join(*testDataDir, test.name, file) 41} 42 43func removeTrailingNewlines(in []byte) []byte { 44 for len(in) > 0 && in[len(in)-1] == '\n' { 45 in = in[:len(in)-1] 46 } 47 return in 48} 49 50var arTests = []arTest{ 51 { 52 "linux", 53 "libsample.a", 54 map[string]string{ 55 "foo.c.o": "foo.c.o", 56 "bar.cc.o": "bar.cc.o", 57 }, 58 false, 59 }, 60 { 61 "mac", 62 "libsample.a", 63 map[string]string{ 64 "foo.c.o": "foo.c.o", 65 "bar.cc.o": "bar.cc.o", 66 }, 67 true, 68 }, 69 { 70 "windows", 71 "sample.lib", 72 map[string]string{ 73 "CMakeFiles\\sample.dir\\foo.c.obj": "foo.c.obj", 74 "CMakeFiles\\sample.dir\\bar.cc.obj": "bar.cc.obj", 75 }, 76 false, 77 }, 78} 79 80func TestAR(t *testing.T) { 81 for _, test := range arTests { 82 t.Run(test.name, func(t *testing.T) { 83 in, err := os.Open(test.Path(test.in)) 84 if err != nil { 85 t.Fatalf("opening input failed: %s", err) 86 } 87 defer in.Close() 88 89 ret, err := ParseAR(in) 90 if err != nil { 91 t.Fatalf("reading input failed: %s", err) 92 } 93 94 for file, contentsPath := range test.out { 95 expected, err := ioutil.ReadFile(test.Path(contentsPath)) 96 if err != nil { 97 t.Fatalf("error reading %s: %s", contentsPath, err) 98 } 99 got, ok := ret[file] 100 if test.allowPadding { 101 got = removeTrailingNewlines(got) 102 expected = removeTrailingNewlines(got) 103 } 104 if !ok { 105 t.Errorf("file %s missing from output", file) 106 } else if !bytes.Equal(got, expected) { 107 t.Errorf("contents for file %s did not match", file) 108 } 109 } 110 111 for file, _ := range ret { 112 if _, ok := test.out[file]; !ok { 113 t.Errorf("output contained unexpected file %q", file) 114 } 115 } 116 }) 117 } 118} 119