blob: 19fa5edd35f72e725a75fa501e9cbb9222936ddb [file] [log] [blame]
Colin Cross24860652018-07-14 22:19:14 -07001// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package main
16
17import (
18 "bytes"
19 "fmt"
20 "os"
21 "strconv"
22 "strings"
23 "testing"
24
25 "android/soong/jar"
26 "android/soong/third_party/zip"
27)
28
29type testZipEntry struct {
30 name string
31 mode os.FileMode
32 data []byte
33}
34
35var (
36 A = testZipEntry{"A", 0755, []byte("foo")}
37 a = testZipEntry{"a", 0755, []byte("foo")}
38 a2 = testZipEntry{"a", 0755, []byte("FOO2")}
39 a3 = testZipEntry{"a", 0755, []byte("Foo3")}
40 bDir = testZipEntry{"b/", os.ModeDir | 0755, nil}
41 bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil}
42 bbb = testZipEntry{"b/b/b", 0755, nil}
43 ba = testZipEntry{"b/a", 0755, []byte("foob")}
44 bc = testZipEntry{"b/c", 0755, []byte("bar")}
45 bd = testZipEntry{"b/d", 0700, []byte("baz")}
46 be = testZipEntry{"b/e", 0700, []byte("")}
47
48 metainfDir = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil}
49 manifestFile = testZipEntry{jar.ManifestFile, 0755, []byte("manifest")}
50 manifestFile2 = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2")}
51 moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info")}
52)
53
54func TestMergeZips(t *testing.T) {
55 testCases := []struct {
56 name string
57 in [][]testZipEntry
58 stripFiles []string
59 stripDirs []string
60 jar bool
61 sort bool
62 ignoreDuplicates bool
63 stripDirEntries bool
64 zipsToNotStrip map[string]bool
65
66 out []testZipEntry
67 err string
68 }{
69 {
70 name: "duplicates error",
71 in: [][]testZipEntry{
72 {a},
73 {a2},
74 {a3},
75 },
76 out: []testZipEntry{a},
77 err: "duplicate",
78 },
79 {
80 name: "duplicates take first",
81 in: [][]testZipEntry{
82 {a},
83 {a2},
84 {a3},
85 },
86 out: []testZipEntry{a},
87
88 ignoreDuplicates: true,
89 },
90 {
Colin Crossdc1e8292018-10-17 15:05:56 -070091 name: "duplicates identical",
92 in: [][]testZipEntry{
93 {a},
94 {a},
95 },
96 out: []testZipEntry{a},
97 },
98 {
Colin Cross24860652018-07-14 22:19:14 -070099 name: "sort",
100 in: [][]testZipEntry{
101 {be, bc, bDir, bbDir, bbb, A, metainfDir, manifestFile},
102 },
103 out: []testZipEntry{A, metainfDir, manifestFile, bDir, bbDir, bbb, bc, be},
104
105 sort: true,
106 },
107 {
108 name: "jar sort",
109 in: [][]testZipEntry{
110 {be, bc, bDir, A, metainfDir, manifestFile},
111 },
112 out: []testZipEntry{metainfDir, manifestFile, A, bDir, bc, be},
113
114 jar: true,
115 },
116 {
117 name: "jar merge",
118 in: [][]testZipEntry{
119 {metainfDir, manifestFile, bDir, be},
120 {metainfDir, manifestFile2, bDir, bc},
121 {metainfDir, manifestFile2, A},
122 },
123 out: []testZipEntry{metainfDir, manifestFile, A, bDir, bc, be},
124
125 jar: true,
126 },
127 {
128 name: "merge",
129 in: [][]testZipEntry{
130 {bDir, be},
131 {bDir, bc},
132 {A},
133 },
134 out: []testZipEntry{bDir, be, bc, A},
135 },
136 {
137 name: "strip dir entries",
138 in: [][]testZipEntry{
139 {a, bDir, bbDir, bbb, bc, bd, be},
140 },
141 out: []testZipEntry{a, bbb, bc, bd, be},
142
143 stripDirEntries: true,
144 },
145 {
Colin Cross4c03f682018-07-15 08:16:31 -0700146 name: "strip files",
147 in: [][]testZipEntry{
148 {a, bDir, bbDir, bbb, bc, bd, be},
149 },
150 out: []testZipEntry{a, bDir, bbDir, bbb, bc},
151
152 stripFiles: []string{"b/d", "b/e"},
153 },
154 {
155 // merge_zips used to treat -stripFile a as stripping any file named a, it now only strips a in the
156 // root of the zip.
Colin Cross24860652018-07-14 22:19:14 -0700157 name: "strip file name",
158 in: [][]testZipEntry{
159 {a, bDir, ba},
160 },
Colin Cross4c03f682018-07-15 08:16:31 -0700161 out: []testZipEntry{bDir, ba},
162
163 stripFiles: []string{"a"},
164 },
165 {
166 name: "strip files glob",
167 in: [][]testZipEntry{
168 {a, bDir, ba},
169 },
Colin Cross24860652018-07-14 22:19:14 -0700170 out: []testZipEntry{bDir},
171
Colin Cross4c03f682018-07-15 08:16:31 -0700172 stripFiles: []string{"**/a"},
Colin Cross24860652018-07-14 22:19:14 -0700173 },
174 {
175 name: "strip dirs",
176 in: [][]testZipEntry{
177 {a, bDir, bbDir, bbb, bc, bd, be},
178 },
179 out: []testZipEntry{a},
180
181 stripDirs: []string{"b"},
182 },
183 {
Colin Cross4c03f682018-07-15 08:16:31 -0700184 name: "strip dirs glob",
185 in: [][]testZipEntry{
186 {a, bDir, bbDir, bbb, bc, bd, be},
187 },
188 out: []testZipEntry{a, bDir, bc, bd, be},
189
190 stripDirs: []string{"b/*"},
191 },
192 {
Colin Cross24860652018-07-14 22:19:14 -0700193 name: "zips to not strip",
194 in: [][]testZipEntry{
195 {a, bDir, bc},
196 {bDir, bd},
197 {bDir, be},
198 },
199 out: []testZipEntry{a, bDir, bd},
200
201 stripDirs: []string{"b"},
202 zipsToNotStrip: map[string]bool{
203 "in1": true,
204 },
205 },
206 }
207
208 for _, test := range testCases {
209 t.Run(test.name, func(t *testing.T) {
210 var readers []namedZipReader
211 for i, in := range test.in {
212 r := testZipEntriesToZipReader(in)
213 readers = append(readers, namedZipReader{
214 path: "in" + strconv.Itoa(i),
215 reader: r,
216 })
217 }
218
219 want := testZipEntriesToBuf(test.out)
220
221 out := &bytes.Buffer{}
222 writer := zip.NewWriter(out)
223
224 err := mergeZips(readers, writer, "", "", "",
225 test.sort, test.jar, false, test.stripDirEntries, test.ignoreDuplicates,
226 test.stripFiles, test.stripDirs, test.zipsToNotStrip)
227
228 closeErr := writer.Close()
229 if closeErr != nil {
230 t.Fatal(err)
231 }
232
233 if test.err != "" {
234 if err == nil {
235 t.Fatal("missing err, expected: ", test.err)
236 } else if !strings.Contains(strings.ToLower(err.Error()), strings.ToLower(test.err)) {
237 t.Fatal("incorrect err, want:", test.err, "got:", err)
238 }
239 return
240 }
241
242 if !bytes.Equal(want, out.Bytes()) {
243 t.Error("incorrect zip output")
244 t.Errorf("want:\n%s", dumpZip(want))
245 t.Errorf("got:\n%s", dumpZip(out.Bytes()))
246 }
247 })
248 }
249}
250
251func testZipEntriesToBuf(entries []testZipEntry) []byte {
252 b := &bytes.Buffer{}
253 zw := zip.NewWriter(b)
254
255 for _, e := range entries {
256 fh := zip.FileHeader{
257 Name: e.name,
258 }
259 fh.SetMode(e.mode)
260
261 w, err := zw.CreateHeader(&fh)
262 if err != nil {
263 panic(err)
264 }
265
266 _, err = w.Write(e.data)
267 if err != nil {
268 panic(err)
269 }
270 }
271
272 err := zw.Close()
273 if err != nil {
274 panic(err)
275 }
276
277 return b.Bytes()
278}
279
280func testZipEntriesToZipReader(entries []testZipEntry) *zip.Reader {
281 b := testZipEntriesToBuf(entries)
282 r := bytes.NewReader(b)
283
284 zr, err := zip.NewReader(r, int64(len(b)))
285 if err != nil {
286 panic(err)
287 }
288
289 return zr
290}
291
292func dumpZip(buf []byte) string {
293 r := bytes.NewReader(buf)
294 zr, err := zip.NewReader(r, int64(len(buf)))
295 if err != nil {
296 panic(err)
297 }
298
299 var ret string
300
301 for _, f := range zr.File {
302 ret += fmt.Sprintf("%v: %v %v %08x\n", f.Name, f.Mode(), f.UncompressedSize64, f.CRC32)
303 }
304
305 return ret
306}