1// Copyright 2018 The Bazel Authors. 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 repack 16 17import ( 18 "archive/zip" 19 "bytes" 20 "io/ioutil" 21 "log" 22 "os" 23 "path/filepath" 24 "testing" 25) 26 27type test struct { 28 name string 29 testData []testData 30 filter filterFunc 31} 32 33type testData struct { 34 name string 35 match bool 36} 37 38var ( 39 filterNoneData = []testData{ 40 { 41 name: "META-INF/MANIFEST.MF", 42 match: false, 43 }, 44 { 45 name: "com/google/android/test/TestActivity.class", 46 match: false, 47 }, 48 { 49 name: "googledata/data.txt", 50 match: false, 51 }, 52 } 53 filterJarResData = []testData{ 54 { 55 name: "META-INF/MANIFEST.MF", 56 match: false, 57 }, 58 { 59 name: "com/google/android/test/TestActivity.class", 60 match: false, 61 }, 62 { 63 name: "googledata/data.txt", 64 match: true, 65 }, 66 } 67 filterRData = []testData{ 68 { 69 name: "META-INF/MANIFEST.MF", 70 match: false, 71 }, 72 { 73 name: "com/google/android/test/TestActivity.class", 74 match: false, 75 }, 76 { 77 name: "com/google/android/test/R.class", 78 match: true, 79 }, 80 { 81 name: "com/google/android/test/R$string.class", 82 match: true, 83 }, 84 { 85 name: "com/google/android/test/R$attr.class", 86 match: true, 87 }, 88 } 89 filterManifestData = []testData{ 90 { 91 name: "AndroidManifest.xml", 92 match: true, 93 }, 94 { 95 name: "res/drawable/icon.png", 96 match: false, 97 }, 98 { 99 name: "res/layout/skeleton_activity.xml", 100 match: false, 101 }, 102 { 103 name: "resources.arsc", 104 match: false, 105 }, 106 } 107 tests = []test{ 108 { 109 name: "filterNone", 110 testData: filterNoneData, 111 filter: filterNone, 112 }, 113 { 114 name: "isJavaRes", 115 testData: filterJarResData, 116 filter: isJavaRes, 117 }, 118 { 119 name: "isRClass", 120 testData: filterRData, 121 filter: isRClass, 122 }, 123 { 124 name: "isManifest", 125 testData: filterManifestData, 126 filter: isManifest, 127 }, 128 } 129) 130 131func TestRepackZip(t *testing.T) { 132 for _, test := range tests { 133 t.Run(test.name, func(t *testing.T) { 134 bufIn := new(bytes.Buffer) 135 zipIn := zip.NewWriter(bufIn) 136 createZip(zipIn, test.testData) 137 138 if err := zipIn.Close(); err != nil { 139 log.Fatal(err) 140 } 141 142 inReader, err := zip.NewReader(bytes.NewReader(bufIn.Bytes()), int64(bufIn.Len())) 143 if err != nil { 144 t.Fatal(err) 145 } 146 147 in := &zip.ReadCloser{ 148 Reader: *inReader, 149 } 150 151 repackZipTest(t, in, test) 152 repackZipWithFiletedOutTest(t, in, test) 153 }) 154 } 155} 156 157func TestFilterZip(t *testing.T) { 158 for _, test := range tests { 159 t.Run(test.name, func(t *testing.T) { 160 for _, testData := range test.testData { 161 if test.filter(testData.name) != testData.match { 162 t.Errorf("Filter applied on: %q got: %v wanted: %v", testData.name, test.filter(testData.name), testData.match) 163 } 164 } 165 }) 166 } 167} 168 169func TestRepackDir(t *testing.T) { 170 for _, test := range tests { 171 t.Run(test.name, func(t *testing.T) { 172 dir, err := ioutil.TempDir("", "repack_dir_") 173 if err != nil { 174 log.Fatal(err) 175 } 176 defer os.RemoveAll(dir) 177 178 createDir(dir, test.testData) 179 repackDirTest(t, dir, test) 180 }) 181 } 182} 183 184func repackZipTest(t *testing.T, in *zip.ReadCloser, test test) { 185 bufOut := new(bytes.Buffer) 186 zipOut := zip.NewWriter(bufOut) 187 188 seen = make(map[string]bool) 189 if err := repackZip(&in.Reader, zipOut, nil, test.filter, zip.Store); err != nil { 190 t.Fatal(err) 191 } 192 193 if err := zipOut.Close(); err != nil { 194 log.Fatal(err) 195 } 196 197 r, err := zip.NewReader(bytes.NewReader(bufOut.Bytes()), int64(bufOut.Len())) 198 if err != nil { 199 t.Fatal(err) 200 } 201 202 files := []string{} 203 for _, testData := range test.testData { 204 if !testData.match { 205 files = append(files, testData.name) 206 } 207 } 208 209 if len(r.File) != len(files) { 210 t.Fatalf("Output file number differ, got: %v wanted: %v", len(r.File), len(files)) 211 } 212 213 for i, fileName := range files { 214 if r.File[i].Name != fileName { 215 t.Errorf("Filename differ, got: %q wanted: %q", r.File[i].Name, fileName) 216 } 217 } 218} 219 220func repackZipWithFiletedOutTest(t *testing.T, in *zip.ReadCloser, test test) { 221 bufOut := new(bytes.Buffer) 222 zipOut := zip.NewWriter(bufOut) 223 224 buffilteredOut := new(bytes.Buffer) 225 zipfilteredOut := zip.NewWriter(buffilteredOut) 226 227 seen = make(map[string]bool) 228 if err := repackZip(&in.Reader, zipOut, zipfilteredOut, test.filter, zip.Store); err != nil { 229 t.Fatal(err) 230 } 231 232 if err := zipOut.Close(); err != nil { 233 log.Fatal(err) 234 } 235 if err := zipfilteredOut.Close(); err != nil { 236 log.Fatal(err) 237 } 238 239 r, err := zip.NewReader(bytes.NewReader(bufOut.Bytes()), int64(bufOut.Len())) 240 if err != nil { 241 t.Fatal(err) 242 } 243 rfiltered, err := zip.NewReader(bytes.NewReader(buffilteredOut.Bytes()), int64(buffilteredOut.Len())) 244 if err != nil { 245 t.Fatal(err) 246 } 247 248 files := []string{} 249 filesfiltered := []string{} 250 for _, testData := range test.testData { 251 if !testData.match { 252 files = append(files, testData.name) 253 } else { 254 filesfiltered = append(filesfiltered, testData.name) 255 } 256 } 257 258 if len(r.File) != len(files) { 259 t.Fatalf("Output file number differ, got: %v wanted: %v", len(r.File), len(files)) 260 } 261 262 if len(rfiltered.File) != (len(filesfiltered)) { 263 t.Fatalf("Filtered output file number differ, got: %v wanted: %v", len(rfiltered.File), len(files)) 264 } 265 266 for i, fileName := range files { 267 if r.File[i].Name != fileName { 268 t.Errorf("Filename differ, got: %q wanted: %q", r.File[i].Name, fileName) 269 } 270 } 271 272 for i, fileName := range filesfiltered { 273 if rfiltered.File[i].Name != fileName { 274 t.Errorf("Filtered filename differ, got: %q wanted: %q", rfiltered.File[i].Name, fileName) 275 } 276 } 277} 278 279func repackDirTest(t *testing.T, dir string, test test) { 280 removeDirs = true 281 bufOut := new(bytes.Buffer) 282 zipOut := zip.NewWriter(bufOut) 283 284 seen = make(map[string]bool) 285 if err := repackDir(dir, zipOut, nil, test.filter, zip.Store); err != nil { 286 log.Fatal(err) 287 } 288 289 if err := zipOut.Close(); err != nil { 290 log.Fatal(err) 291 } 292 293 r, err := zip.NewReader(bytes.NewReader(bufOut.Bytes()), int64(bufOut.Len())) 294 if err != nil { 295 t.Fatal(err) 296 } 297 298 files := []string{} 299 for _, testData := range test.testData { 300 if !testData.match { 301 files = append(files, testData.name) 302 } 303 } 304 305 if len(r.File) != len(files) { 306 t.Fatalf("Output file number differ, got: %v wanted: %v", len(r.File), len(files)) 307 } 308 309 for i, fileName := range files { 310 if r.File[i].Name != fileName { 311 t.Errorf("Filename differ, got: %q wanted: %q", r.File[i].Name, fileName) 312 } 313 } 314} 315 316func createZip(w *zip.Writer, testDatas []testData) { 317 for _, testData := range testDatas { 318 f, err := w.Create(testData.name) 319 if err != nil { 320 log.Fatal(err) 321 } 322 _, err = f.Write([]byte{42}) 323 if err != nil { 324 log.Fatal(err) 325 } 326 } 327} 328 329func createDir(base string, testDatas []testData) { 330 for _, testData := range testDatas { 331 path := filepath.Join(base, testData.name) 332 if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil { 333 log.Fatal(err) 334 } 335 if err := ioutil.WriteFile(path, []byte{1, 2, 3}, 0777); err != nil { 336 log.Fatal(err) 337 } 338 } 339} 340