xref: /aosp_15_r20/external/boringssl/src/util/ar/ar_test.go (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
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