blob: 21a7e9a03c96630317744d60276fad03d37a467d [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 {
138 name: "strip file name",
139 in: [][]testZipEntry{
140 {a, bDir, ba},
141 },
142 out: []testZipEntry{bDir},
143
144 stripFiles: []string{"a"},
145 },
146 {
147 name: "strip dirs",
148 in: [][]testZipEntry{
149 {a, bDir, bbDir, bbb, bc, bd, be},
150 },
151 out: []testZipEntry{a},
152
153 stripDirs: []string{"b"},
154 },
155 {
156 name: "zips to not strip",
157 in: [][]testZipEntry{
158 {a, bDir, bc},
159 {bDir, bd},
160 {bDir, be},
161 },
162 out: []testZipEntry{a, bDir, bd},
163
164 stripDirs: []string{"b"},
165 zipsToNotStrip: map[string]bool{
166 "in1": true,
167 },
168 },
169 }
170
171 for _, test := range testCases {
172 t.Run(test.name, func(t *testing.T) {
173 var readers []namedZipReader
174 for i, in := range test.in {
175 r := testZipEntriesToZipReader(in)
176 readers = append(readers, namedZipReader{
177 path: "in" + strconv.Itoa(i),
178 reader: r,
179 })
180 }
181
182 want := testZipEntriesToBuf(test.out)
183
184 out := &bytes.Buffer{}
185 writer := zip.NewWriter(out)
186
187 err := mergeZips(readers, writer, "", "", "",
188 test.sort, test.jar, false, test.stripDirEntries, test.ignoreDuplicates,
189 test.stripFiles, test.stripDirs, test.zipsToNotStrip)
190
191 closeErr := writer.Close()
192 if closeErr != nil {
193 t.Fatal(err)
194 }
195
196 if test.err != "" {
197 if err == nil {
198 t.Fatal("missing err, expected: ", test.err)
199 } else if !strings.Contains(strings.ToLower(err.Error()), strings.ToLower(test.err)) {
200 t.Fatal("incorrect err, want:", test.err, "got:", err)
201 }
202 return
203 }
204
205 if !bytes.Equal(want, out.Bytes()) {
206 t.Error("incorrect zip output")
207 t.Errorf("want:\n%s", dumpZip(want))
208 t.Errorf("got:\n%s", dumpZip(out.Bytes()))
209 }
210 })
211 }
212}
213
214func testZipEntriesToBuf(entries []testZipEntry) []byte {
215 b := &bytes.Buffer{}
216 zw := zip.NewWriter(b)
217
218 for _, e := range entries {
219 fh := zip.FileHeader{
220 Name: e.name,
221 }
222 fh.SetMode(e.mode)
223
224 w, err := zw.CreateHeader(&fh)
225 if err != nil {
226 panic(err)
227 }
228
229 _, err = w.Write(e.data)
230 if err != nil {
231 panic(err)
232 }
233 }
234
235 err := zw.Close()
236 if err != nil {
237 panic(err)
238 }
239
240 return b.Bytes()
241}
242
243func testZipEntriesToZipReader(entries []testZipEntry) *zip.Reader {
244 b := testZipEntriesToBuf(entries)
245 r := bytes.NewReader(b)
246
247 zr, err := zip.NewReader(r, int64(len(b)))
248 if err != nil {
249 panic(err)
250 }
251
252 return zr
253}
254
255func dumpZip(buf []byte) string {
256 r := bytes.NewReader(buf)
257 zr, err := zip.NewReader(r, int64(len(buf)))
258 if err != nil {
259 panic(err)
260 }
261
262 var ret string
263
264 for _, f := range zr.File {
265 ret += fmt.Sprintf("%v: %v %v %08x\n", f.Name, f.Mode(), f.UncompressedSize64, f.CRC32)
266 }
267
268 return ret
269}