• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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