blob: f91111f1438e3b3978b8e3ac1849a1d294ea5551 [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 {
91 name: "sort",
92 in: [][]testZipEntry{
93 {be, bc, bDir, bbDir, bbb, A, metainfDir, manifestFile},
94 },
95 out: []testZipEntry{A, metainfDir, manifestFile, bDir, bbDir, bbb, bc, be},
96
97 sort: true,
98 },
99 {
100 name: "jar sort",
101 in: [][]testZipEntry{
102 {be, bc, bDir, A, metainfDir, manifestFile},
103 },
104 out: []testZipEntry{metainfDir, manifestFile, A, bDir, bc, be},
105
106 jar: true,
107 },
108 {
109 name: "jar merge",
110 in: [][]testZipEntry{
111 {metainfDir, manifestFile, bDir, be},
112 {metainfDir, manifestFile2, bDir, bc},
113 {metainfDir, manifestFile2, A},
114 },
115 out: []testZipEntry{metainfDir, manifestFile, A, bDir, bc, be},
116
117 jar: true,
118 },
119 {
120 name: "merge",
121 in: [][]testZipEntry{
122 {bDir, be},
123 {bDir, bc},
124 {A},
125 },
126 out: []testZipEntry{bDir, be, bc, A},
127 },
128 {
129 name: "strip dir entries",
130 in: [][]testZipEntry{
131 {a, bDir, bbDir, bbb, bc, bd, be},
132 },
133 out: []testZipEntry{a, bbb, bc, bd, be},
134
135 stripDirEntries: true,
136 },
137 {
Colin Cross4c03f682018-07-15 08:16:31 -0700138 name: "strip files",
139 in: [][]testZipEntry{
140 {a, bDir, bbDir, bbb, bc, bd, be},
141 },
142 out: []testZipEntry{a, bDir, bbDir, bbb, bc},
143
144 stripFiles: []string{"b/d", "b/e"},
145 },
146 {
147 // merge_zips used to treat -stripFile a as stripping any file named a, it now only strips a in the
148 // root of the zip.
Colin Cross24860652018-07-14 22:19:14 -0700149 name: "strip file name",
150 in: [][]testZipEntry{
151 {a, bDir, ba},
152 },
Colin Cross4c03f682018-07-15 08:16:31 -0700153 out: []testZipEntry{bDir, ba},
154
155 stripFiles: []string{"a"},
156 },
157 {
158 name: "strip files glob",
159 in: [][]testZipEntry{
160 {a, bDir, ba},
161 },
Colin Cross24860652018-07-14 22:19:14 -0700162 out: []testZipEntry{bDir},
163
Colin Cross4c03f682018-07-15 08:16:31 -0700164 stripFiles: []string{"**/a"},
Colin Cross24860652018-07-14 22:19:14 -0700165 },
166 {
167 name: "strip dirs",
168 in: [][]testZipEntry{
169 {a, bDir, bbDir, bbb, bc, bd, be},
170 },
171 out: []testZipEntry{a},
172
173 stripDirs: []string{"b"},
174 },
175 {
Colin Cross4c03f682018-07-15 08:16:31 -0700176 name: "strip dirs glob",
177 in: [][]testZipEntry{
178 {a, bDir, bbDir, bbb, bc, bd, be},
179 },
180 out: []testZipEntry{a, bDir, bc, bd, be},
181
182 stripDirs: []string{"b/*"},
183 },
184 {
Colin Cross24860652018-07-14 22:19:14 -0700185 name: "zips to not strip",
186 in: [][]testZipEntry{
187 {a, bDir, bc},
188 {bDir, bd},
189 {bDir, be},
190 },
191 out: []testZipEntry{a, bDir, bd},
192
193 stripDirs: []string{"b"},
194 zipsToNotStrip: map[string]bool{
195 "in1": true,
196 },
197 },
198 }
199
200 for _, test := range testCases {
201 t.Run(test.name, func(t *testing.T) {
202 var readers []namedZipReader
203 for i, in := range test.in {
204 r := testZipEntriesToZipReader(in)
205 readers = append(readers, namedZipReader{
206 path: "in" + strconv.Itoa(i),
207 reader: r,
208 })
209 }
210
211 want := testZipEntriesToBuf(test.out)
212
213 out := &bytes.Buffer{}
214 writer := zip.NewWriter(out)
215
216 err := mergeZips(readers, writer, "", "", "",
217 test.sort, test.jar, false, test.stripDirEntries, test.ignoreDuplicates,
218 test.stripFiles, test.stripDirs, test.zipsToNotStrip)
219
220 closeErr := writer.Close()
221 if closeErr != nil {
222 t.Fatal(err)
223 }
224
225 if test.err != "" {
226 if err == nil {
227 t.Fatal("missing err, expected: ", test.err)
228 } else if !strings.Contains(strings.ToLower(err.Error()), strings.ToLower(test.err)) {
229 t.Fatal("incorrect err, want:", test.err, "got:", err)
230 }
231 return
232 }
233
234 if !bytes.Equal(want, out.Bytes()) {
235 t.Error("incorrect zip output")
236 t.Errorf("want:\n%s", dumpZip(want))
237 t.Errorf("got:\n%s", dumpZip(out.Bytes()))
238 }
239 })
240 }
241}
242
243func testZipEntriesToBuf(entries []testZipEntry) []byte {
244 b := &bytes.Buffer{}
245 zw := zip.NewWriter(b)
246
247 for _, e := range entries {
248 fh := zip.FileHeader{
249 Name: e.name,
250 }
251 fh.SetMode(e.mode)
252
253 w, err := zw.CreateHeader(&fh)
254 if err != nil {
255 panic(err)
256 }
257
258 _, err = w.Write(e.data)
259 if err != nil {
260 panic(err)
261 }
262 }
263
264 err := zw.Close()
265 if err != nil {
266 panic(err)
267 }
268
269 return b.Bytes()
270}
271
272func testZipEntriesToZipReader(entries []testZipEntry) *zip.Reader {
273 b := testZipEntriesToBuf(entries)
274 r := bytes.NewReader(b)
275
276 zr, err := zip.NewReader(r, int64(len(b)))
277 if err != nil {
278 panic(err)
279 }
280
281 return zr
282}
283
284func dumpZip(buf []byte) string {
285 r := bytes.NewReader(buf)
286 zr, err := zip.NewReader(r, int64(len(buf)))
287 if err != nil {
288 panic(err)
289 }
290
291 var ret string
292
293 for _, f := range zr.File {
294 ret += fmt.Sprintf("%v: %v %v %08x\n", f.Name, f.Mode(), f.UncompressedSize64, f.CRC32)
295 }
296
297 return ret
298}