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 "os" 21 "path/filepath" 22 "testing" 23) 24 25var testDataDir = flag.String("testdata", "testdata", "The path to the test data directory.") 26 27type arTest struct { 28 name string 29 in string 30 out map[string]string 31 // allowPadding is true if the contents may have trailing newlines at end. 32 // On macOS, ar calls ranlib which pads all inputs up to eight bytes with 33 // newlines. Unlike ar's native padding up to two bytes, this padding is 34 // included in the size field, so it is not removed when decoding. 35 allowPadding bool 36} 37 38func (test *arTest) Path(file string) string { 39 return filepath.Join(*testDataDir, test.name, file) 40} 41 42func removeTrailingNewlines(in []byte) []byte { 43 for len(in) > 0 && in[len(in)-1] == '\n' { 44 in = in[:len(in)-1] 45 } 46 return in 47} 48 49var arTests = []arTest{ 50 { 51 "linux", 52 "libsample.a", 53 map[string]string{ 54 "foo.c.o": "foo.c.o", 55 "bar.cc.o": "bar.cc.o", 56 }, 57 false, 58 }, 59 { 60 "mac", 61 "libsample.a", 62 map[string]string{ 63 "foo.c.o": "foo.c.o", 64 "bar.cc.o": "bar.cc.o", 65 }, 66 true, 67 }, 68 { 69 "windows", 70 "sample.lib", 71 map[string]string{ 72 "CMakeFiles\\sample.dir\\foo.c.obj": "foo.c.obj", 73 "CMakeFiles\\sample.dir\\bar.cc.obj": "bar.cc.obj", 74 }, 75 false, 76 }, 77} 78 79func TestAR(t *testing.T) { 80 for _, test := range arTests { 81 t.Run(test.name, func(t *testing.T) { 82 in, err := os.Open(test.Path(test.in)) 83 if err != nil { 84 t.Fatalf("opening input failed: %s", err) 85 } 86 defer in.Close() 87 88 ret, err := ParseAR(in) 89 if err != nil { 90 t.Fatalf("reading input failed: %s", err) 91 } 92 93 for file, contentsPath := range test.out { 94 expected, err := os.ReadFile(test.Path(contentsPath)) 95 if err != nil { 96 t.Fatalf("error reading %s: %s", contentsPath, err) 97 } 98 got, ok := ret[file] 99 if test.allowPadding { 100 got = removeTrailingNewlines(got) 101 expected = removeTrailingNewlines(got) 102 } 103 if !ok { 104 t.Errorf("file %s missing from output", file) 105 } else if !bytes.Equal(got, expected) { 106 t.Errorf("contents for file %s did not match", file) 107 } 108 } 109 110 for file, _ := range ret { 111 if _, ok := test.out[file]; !ok { 112 t.Errorf("output contained unexpected file %q", file) 113 } 114 } 115 }) 116 } 117} 118