|  | // Copyright (c) 2018, Google Inc. | 
|  | // | 
|  | // Permission to use, copy, modify, and/or distribute this software for any | 
|  | // purpose with or without fee is hereby granted, provided that the above | 
|  | // copyright notice and this permission notice appear in all copies. | 
|  | // | 
|  | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 
|  | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 
|  | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | 
|  | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
|  | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | 
|  | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | 
|  | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
|  |  | 
|  | package ar | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "flag" | 
|  | "os" | 
|  | "path/filepath" | 
|  | "testing" | 
|  | ) | 
|  |  | 
|  | var testDataDir = flag.String("testdata", "testdata", "The path to the test data directory.") | 
|  |  | 
|  | type arTest struct { | 
|  | name string | 
|  | in   string | 
|  | out  map[string]string | 
|  | // allowPadding is true if the contents may have trailing newlines at end. | 
|  | // On macOS, ar calls ranlib which pads all inputs up to eight bytes with | 
|  | // newlines. Unlike ar's native padding up to two bytes, this padding is | 
|  | // included in the size field, so it is not removed when decoding. | 
|  | allowPadding bool | 
|  | } | 
|  |  | 
|  | func (test *arTest) Path(file string) string { | 
|  | return filepath.Join(*testDataDir, test.name, file) | 
|  | } | 
|  |  | 
|  | func removeTrailingNewlines(in []byte) []byte { | 
|  | for len(in) > 0 && in[len(in)-1] == '\n' { | 
|  | in = in[:len(in)-1] | 
|  | } | 
|  | return in | 
|  | } | 
|  |  | 
|  | var arTests = []arTest{ | 
|  | { | 
|  | "linux", | 
|  | "libsample.a", | 
|  | map[string]string{ | 
|  | "foo.c.o":  "foo.c.o", | 
|  | "bar.cc.o": "bar.cc.o", | 
|  | }, | 
|  | false, | 
|  | }, | 
|  | { | 
|  | "mac", | 
|  | "libsample.a", | 
|  | map[string]string{ | 
|  | "foo.c.o":  "foo.c.o", | 
|  | "bar.cc.o": "bar.cc.o", | 
|  | }, | 
|  | true, | 
|  | }, | 
|  | { | 
|  | "windows", | 
|  | "sample.lib", | 
|  | map[string]string{ | 
|  | "CMakeFiles\\sample.dir\\foo.c.obj":  "foo.c.obj", | 
|  | "CMakeFiles\\sample.dir\\bar.cc.obj": "bar.cc.obj", | 
|  | }, | 
|  | false, | 
|  | }, | 
|  | } | 
|  |  | 
|  | func TestAR(t *testing.T) { | 
|  | for _, test := range arTests { | 
|  | t.Run(test.name, func(t *testing.T) { | 
|  | in, err := os.Open(test.Path(test.in)) | 
|  | if err != nil { | 
|  | t.Fatalf("opening input failed: %s", err) | 
|  | } | 
|  | defer in.Close() | 
|  |  | 
|  | ret, err := ParseAR(in) | 
|  | if err != nil { | 
|  | t.Fatalf("reading input failed: %s", err) | 
|  | } | 
|  |  | 
|  | for file, contentsPath := range test.out { | 
|  | expected, err := os.ReadFile(test.Path(contentsPath)) | 
|  | if err != nil { | 
|  | t.Fatalf("error reading %s: %s", contentsPath, err) | 
|  | } | 
|  | got, ok := ret[file] | 
|  | if test.allowPadding { | 
|  | got = removeTrailingNewlines(got) | 
|  | expected = removeTrailingNewlines(got) | 
|  | } | 
|  | if !ok { | 
|  | t.Errorf("file %s missing from output", file) | 
|  | } else if !bytes.Equal(got, expected) { | 
|  | t.Errorf("contents for file %s did not match", file) | 
|  | } | 
|  | } | 
|  |  | 
|  | for file, _ := range ret { | 
|  | if _, ok := test.out[file]; !ok { | 
|  | t.Errorf("output contained unexpected file %q", file) | 
|  | } | 
|  | } | 
|  | }) | 
|  | } | 
|  | } |