blob: 2c4e0056970f5b3837092872c5084cee7254875f [file] [log] [blame]
Dan Willemsen82218f22017-06-19 16:35:00 -07001// Copyright 2017 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 "reflect"
21 "testing"
22
23 "android/soong/third_party/zip"
24)
25
26var testCases = []struct {
27 name string
28
Colin Crossb1a5e9c2018-10-07 21:30:12 -070029 inputFiles []string
30 sortGlobs bool
31 sortJava bool
32 args []string
33 excludes []string
Colin Cross38247712018-10-09 10:19:54 -070034 includes []string
Colin Crossb1a5e9c2018-10-07 21:30:12 -070035 uncompresses []string
Dan Willemsen82218f22017-06-19 16:35:00 -070036
37 outputFiles []string
Colin Crossb1a5e9c2018-10-07 21:30:12 -070038 storedFiles []string
Dan Willemsen82218f22017-06-19 16:35:00 -070039 err error
40}{
41 {
42 name: "unsupported \\",
43
44 args: []string{"a\\b:b"},
45
46 err: fmt.Errorf("\\ characters are not currently supported"),
47 },
Dan Willemsen82218f22017-06-19 16:35:00 -070048 { // This is modelled after the update package build rules in build/make/core/Makefile
49 name: "filter globs",
50
51 inputFiles: []string{
52 "RADIO/a",
53 "IMAGES/system.img",
54 "IMAGES/b.txt",
55 "IMAGES/recovery.img",
56 "IMAGES/vendor.img",
57 "OTA/android-info.txt",
58 "OTA/b",
59 },
60 args: []string{"OTA/android-info.txt:android-info.txt", "IMAGES/*.img:."},
61
62 outputFiles: []string{
63 "android-info.txt",
64 "system.img",
65 "recovery.img",
66 "vendor.img",
67 },
68 },
69 {
70 name: "sorted filter globs",
71
72 inputFiles: []string{
73 "RADIO/a",
74 "IMAGES/system.img",
75 "IMAGES/b.txt",
76 "IMAGES/recovery.img",
77 "IMAGES/vendor.img",
78 "OTA/android-info.txt",
79 "OTA/b",
80 },
81 sortGlobs: true,
82 args: []string{"IMAGES/*.img:.", "OTA/android-info.txt:android-info.txt"},
83
84 outputFiles: []string{
85 "recovery.img",
86 "system.img",
87 "vendor.img",
88 "android-info.txt",
89 },
90 },
91 {
92 name: "sort all",
93
94 inputFiles: []string{
Colin Crossf3831d02017-11-22 12:53:08 -080095 "RADIO/",
Dan Willemsen82218f22017-06-19 16:35:00 -070096 "RADIO/a",
Colin Crossf3831d02017-11-22 12:53:08 -080097 "IMAGES/",
Dan Willemsen82218f22017-06-19 16:35:00 -070098 "IMAGES/system.img",
99 "IMAGES/b.txt",
100 "IMAGES/recovery.img",
101 "IMAGES/vendor.img",
Colin Crossf3831d02017-11-22 12:53:08 -0800102 "OTA/",
Dan Willemsen82218f22017-06-19 16:35:00 -0700103 "OTA/b",
104 "OTA/android-info.txt",
105 },
106 sortGlobs: true,
Colin Crossf3831d02017-11-22 12:53:08 -0800107 args: []string{"**/*"},
Dan Willemsen82218f22017-06-19 16:35:00 -0700108
109 outputFiles: []string{
110 "IMAGES/b.txt",
111 "IMAGES/recovery.img",
112 "IMAGES/system.img",
113 "IMAGES/vendor.img",
114 "OTA/android-info.txt",
115 "OTA/b",
116 "RADIO/a",
117 },
118 },
119 {
Colin Cross06382992017-06-23 14:08:42 -0700120 name: "sort all implicit",
121
122 inputFiles: []string{
Colin Crossf3831d02017-11-22 12:53:08 -0800123 "RADIO/",
Colin Cross06382992017-06-23 14:08:42 -0700124 "RADIO/a",
Colin Crossf3831d02017-11-22 12:53:08 -0800125 "IMAGES/",
Colin Cross06382992017-06-23 14:08:42 -0700126 "IMAGES/system.img",
127 "IMAGES/b.txt",
128 "IMAGES/recovery.img",
129 "IMAGES/vendor.img",
Colin Crossf3831d02017-11-22 12:53:08 -0800130 "OTA/",
Colin Cross06382992017-06-23 14:08:42 -0700131 "OTA/b",
132 "OTA/android-info.txt",
133 },
134 sortGlobs: true,
135 args: nil,
136
137 outputFiles: []string{
Colin Crossf3831d02017-11-22 12:53:08 -0800138 "IMAGES/",
Colin Cross06382992017-06-23 14:08:42 -0700139 "IMAGES/b.txt",
140 "IMAGES/recovery.img",
141 "IMAGES/system.img",
142 "IMAGES/vendor.img",
Colin Crossf3831d02017-11-22 12:53:08 -0800143 "OTA/",
Colin Cross06382992017-06-23 14:08:42 -0700144 "OTA/android-info.txt",
145 "OTA/b",
Colin Crossf3831d02017-11-22 12:53:08 -0800146 "RADIO/",
Colin Cross06382992017-06-23 14:08:42 -0700147 "RADIO/a",
148 },
149 },
150 {
Colin Cross8936b022017-06-23 13:00:17 -0700151 name: "sort jar",
152
153 inputFiles: []string{
154 "MANIFEST.MF",
155 "META-INF/MANIFEST.MF",
156 "META-INF/aaa/",
157 "META-INF/aaa/aaa",
158 "META-INF/AAA",
159 "META-INF.txt",
160 "META-INF/",
161 "AAA",
162 "aaa",
163 },
164 sortJava: true,
165 args: nil,
166
167 outputFiles: []string{
168 "META-INF/",
169 "META-INF/MANIFEST.MF",
170 "META-INF/AAA",
171 "META-INF/aaa/",
172 "META-INF/aaa/aaa",
173 "AAA",
174 "MANIFEST.MF",
175 "META-INF.txt",
176 "aaa",
177 },
178 },
179 {
Dan Willemsen82218f22017-06-19 16:35:00 -0700180 name: "double input",
181
182 inputFiles: []string{
183 "b",
184 "a",
185 },
Colin Crossf3831d02017-11-22 12:53:08 -0800186 args: []string{"a:a2", "**/*"},
Dan Willemsen82218f22017-06-19 16:35:00 -0700187
188 outputFiles: []string{
189 "a2",
190 "b",
191 "a",
192 },
193 },
Colin Crossf3831d02017-11-22 12:53:08 -0800194 {
195 name: "multiple matches",
196
197 inputFiles: []string{
198 "a/a",
199 },
200 args: []string{"a/a", "a/*"},
201
202 outputFiles: []string{
203 "a/a",
204 },
205 },
206 {
207 name: "multiple conflicting matches",
208
209 inputFiles: []string{
210 "a/a",
211 "a/b",
212 },
213 args: []string{"a/b:a/a", "a/*"},
214
215 err: fmt.Errorf(`multiple entries for "a/a" with different contents`),
216 },
217 {
218 name: "excludes",
219
220 inputFiles: []string{
221 "a/a",
222 "a/b",
223 },
224 args: nil,
225 excludes: []string{"a/a"},
226
227 outputFiles: []string{
228 "a/b",
229 },
230 },
231 {
Colin Cross38247712018-10-09 10:19:54 -0700232 name: "excludes with args",
Colin Crossf3831d02017-11-22 12:53:08 -0800233
234 inputFiles: []string{
235 "a/a",
236 "a/b",
237 },
238 args: []string{"a/*"},
239 excludes: []string{"a/a"},
240
241 outputFiles: []string{
242 "a/b",
243 },
244 },
245 {
Colin Cross38247712018-10-09 10:19:54 -0700246 name: "excludes over args",
247
248 inputFiles: []string{
249 "a/a",
250 "a/b",
251 },
252 args: []string{"a/a"},
253 excludes: []string{"a/*"},
254
255 outputFiles: nil,
256 },
257 {
258 name: "excludes with includes",
259
260 inputFiles: []string{
261 "a/a",
262 "a/b",
263 },
264 args: nil,
265 excludes: []string{"a/*"},
266 includes: []string{"a/b"},
267
268 outputFiles: []string{"a/b"},
269 },
270 {
Colin Crossf3831d02017-11-22 12:53:08 -0800271 name: "excludes with glob",
272
273 inputFiles: []string{
274 "a/a",
275 "a/b",
276 },
277 args: []string{"a/*"},
278 excludes: []string{"a/*"},
279
280 outputFiles: nil,
281 },
Colin Crossb1a5e9c2018-10-07 21:30:12 -0700282 {
283 name: "uncompress one",
284
285 inputFiles: []string{
286 "a/a",
287 "a/b",
288 },
289 uncompresses: []string{"a/a"},
290
291 outputFiles: []string{
292 "a/a",
293 "a/b",
294 },
295 storedFiles: []string{
296 "a/a",
297 },
298 },
299 {
300 name: "uncompress two",
301
302 inputFiles: []string{
303 "a/a",
304 "a/b",
305 },
306 uncompresses: []string{"a/a", "a/b"},
307
308 outputFiles: []string{
309 "a/a",
310 "a/b",
311 },
312 storedFiles: []string{
313 "a/a",
314 "a/b",
315 },
316 },
317 {
318 name: "uncompress glob",
319
320 inputFiles: []string{
321 "a/a",
322 "a/b",
323 "a/c.so",
324 "a/d.so",
325 },
326 uncompresses: []string{"a/*.so"},
327
328 outputFiles: []string{
329 "a/a",
330 "a/b",
331 "a/c.so",
332 "a/d.so",
333 },
334 storedFiles: []string{
335 "a/c.so",
336 "a/d.so",
337 },
338 },
339 {
340 name: "uncompress rename",
341
342 inputFiles: []string{
343 "a/a",
344 },
345 args: []string{"a/a:a/b"},
346 uncompresses: []string{"a/b"},
347
348 outputFiles: []string{
349 "a/b",
350 },
351 storedFiles: []string{
352 "a/b",
353 },
354 },
Colin Cross714614c2018-11-01 13:27:58 -0700355 {
356 name: "recursive glob",
357
358 inputFiles: []string{
359 "a/a/a",
360 "a/a/b",
361 },
362 args: []string{"a/**/*:b"},
363 outputFiles: []string{
364 "b/a/a",
365 "b/a/b",
366 },
367 },
368 {
369 name: "glob",
370
371 inputFiles: []string{
372 "a/a/a",
373 "a/a/b",
374 "a/b",
375 "a/c",
376 },
377 args: []string{"a/*:b"},
378 outputFiles: []string{
379 "b/b",
380 "b/c",
381 },
382 },
383 {
384 name: "top level glob",
385
386 inputFiles: []string{
387 "a",
388 "b",
389 },
390 args: []string{"*:b"},
391 outputFiles: []string{
392 "b/a",
393 "b/b",
394 },
395 },
396 {
397 name: "multilple glob",
398
399 inputFiles: []string{
400 "a/a/a",
401 "a/a/b",
402 },
403 args: []string{"a/*/*:b"},
404 outputFiles: []string{
405 "b/a/a",
406 "b/a/b",
407 },
408 },
Dan Willemsen82218f22017-06-19 16:35:00 -0700409}
410
411func errorString(e error) string {
412 if e == nil {
413 return ""
414 }
415 return e.Error()
416}
417
418func TestZip2Zip(t *testing.T) {
419 for _, testCase := range testCases {
420 t.Run(testCase.name, func(t *testing.T) {
421 inputBuf := &bytes.Buffer{}
422 outputBuf := &bytes.Buffer{}
423
424 inputWriter := zip.NewWriter(inputBuf)
425 for _, file := range testCase.inputFiles {
426 w, err := inputWriter.Create(file)
427 if err != nil {
428 t.Fatal(err)
429 }
430 fmt.Fprintln(w, "test")
431 }
432 inputWriter.Close()
433 inputBytes := inputBuf.Bytes()
434 inputReader, err := zip.NewReader(bytes.NewReader(inputBytes), int64(len(inputBytes)))
435 if err != nil {
436 t.Fatal(err)
437 }
438
439 outputWriter := zip.NewWriter(outputBuf)
Colin Crossb1a5e9c2018-10-07 21:30:12 -0700440 err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false,
Colin Cross38247712018-10-09 10:19:54 -0700441 testCase.args, testCase.excludes, testCase.includes, testCase.uncompresses)
Dan Willemsen82218f22017-06-19 16:35:00 -0700442 if errorString(testCase.err) != errorString(err) {
443 t.Fatalf("Unexpected error:\n got: %q\nwant: %q", errorString(err), errorString(testCase.err))
444 }
445
446 outputWriter.Close()
447 outputBytes := outputBuf.Bytes()
448 outputReader, err := zip.NewReader(bytes.NewReader(outputBytes), int64(len(outputBytes)))
449 if err != nil {
450 t.Fatal(err)
451 }
452 var outputFiles []string
Colin Crossb1a5e9c2018-10-07 21:30:12 -0700453 var storedFiles []string
Dan Willemsen82218f22017-06-19 16:35:00 -0700454 if len(outputReader.File) > 0 {
455 outputFiles = make([]string, len(outputReader.File))
456 for i, file := range outputReader.File {
457 outputFiles[i] = file.Name
Colin Crossb1a5e9c2018-10-07 21:30:12 -0700458 if file.Method == zip.Store {
459 storedFiles = append(storedFiles, file.Name)
460 }
Dan Willemsen82218f22017-06-19 16:35:00 -0700461 }
462 }
463
464 if !reflect.DeepEqual(testCase.outputFiles, outputFiles) {
Colin Crossb1a5e9c2018-10-07 21:30:12 -0700465 t.Fatalf("Output file list does not match:\nwant: %v\n got: %v", testCase.outputFiles, outputFiles)
466 }
467 if !reflect.DeepEqual(testCase.storedFiles, storedFiles) {
468 t.Fatalf("Stored file list does not match:\nwant: %v\n got: %v", testCase.storedFiles, storedFiles)
Dan Willemsen82218f22017-06-19 16:35:00 -0700469 }
470 })
471 }
472}
Colin Cross714614c2018-11-01 13:27:58 -0700473
474func TestConstantPartOfPattern(t *testing.T) {
475 testCases := []struct{ in, out string }{
476 {
477 in: "",
478 out: "",
479 },
480 {
481 in: "a",
482 out: "a",
483 },
484 {
485 in: "*",
486 out: "",
487 },
488 {
489 in: "a/a",
490 out: "a/a",
491 },
492 {
493 in: "a/*",
494 out: "a",
495 },
496 {
497 in: "a/*/a",
498 out: "a",
499 },
500 {
501 in: "a/**/*",
502 out: "a",
503 },
504 }
505
506 for _, test := range testCases {
507 t.Run(test.in, func(t *testing.T) {
508 got := constantPartOfPattern(test.in)
509 if got != test.out {
510 t.Errorf("want %q, got %q", test.out, got)
511 }
512 })
513 }
514}