zip2zip_test.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. // 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. package main
  15. import (
  16. "bytes"
  17. "fmt"
  18. "reflect"
  19. "testing"
  20. "android/soong/third_party/zip"
  21. )
  22. var testCases = []struct {
  23. name string
  24. inputFiles []string
  25. sortGlobs bool
  26. sortJava bool
  27. args []string
  28. excludes []string
  29. includes []string
  30. uncompresses []string
  31. outputFiles []string
  32. storedFiles []string
  33. err error
  34. }{
  35. {
  36. name: "unsupported \\",
  37. args: []string{"a\\b:b"},
  38. err: fmt.Errorf("\\ characters are not currently supported"),
  39. },
  40. { // This is modelled after the update package build rules in build/make/core/Makefile
  41. name: "filter globs",
  42. inputFiles: []string{
  43. "RADIO/a",
  44. "IMAGES/system.img",
  45. "IMAGES/b.txt",
  46. "IMAGES/recovery.img",
  47. "IMAGES/vendor.img",
  48. "OTA/android-info.txt",
  49. "OTA/b",
  50. },
  51. args: []string{"OTA/android-info.txt:android-info.txt", "IMAGES/*.img:."},
  52. outputFiles: []string{
  53. "android-info.txt",
  54. "system.img",
  55. "recovery.img",
  56. "vendor.img",
  57. },
  58. },
  59. {
  60. name: "sorted filter globs",
  61. inputFiles: []string{
  62. "RADIO/a",
  63. "IMAGES/system.img",
  64. "IMAGES/b.txt",
  65. "IMAGES/recovery.img",
  66. "IMAGES/vendor.img",
  67. "OTA/android-info.txt",
  68. "OTA/b",
  69. },
  70. sortGlobs: true,
  71. args: []string{"IMAGES/*.img:.", "OTA/android-info.txt:android-info.txt"},
  72. outputFiles: []string{
  73. "recovery.img",
  74. "system.img",
  75. "vendor.img",
  76. "android-info.txt",
  77. },
  78. },
  79. {
  80. name: "sort all",
  81. inputFiles: []string{
  82. "RADIO/",
  83. "RADIO/a",
  84. "IMAGES/",
  85. "IMAGES/system.img",
  86. "IMAGES/b.txt",
  87. "IMAGES/recovery.img",
  88. "IMAGES/vendor.img",
  89. "OTA/",
  90. "OTA/b",
  91. "OTA/android-info.txt",
  92. },
  93. sortGlobs: true,
  94. args: []string{"**/*"},
  95. outputFiles: []string{
  96. "IMAGES/b.txt",
  97. "IMAGES/recovery.img",
  98. "IMAGES/system.img",
  99. "IMAGES/vendor.img",
  100. "OTA/android-info.txt",
  101. "OTA/b",
  102. "RADIO/a",
  103. },
  104. },
  105. {
  106. name: "sort all implicit",
  107. inputFiles: []string{
  108. "RADIO/",
  109. "RADIO/a",
  110. "IMAGES/",
  111. "IMAGES/system.img",
  112. "IMAGES/b.txt",
  113. "IMAGES/recovery.img",
  114. "IMAGES/vendor.img",
  115. "OTA/",
  116. "OTA/b",
  117. "OTA/android-info.txt",
  118. },
  119. sortGlobs: true,
  120. args: nil,
  121. outputFiles: []string{
  122. "IMAGES/",
  123. "IMAGES/b.txt",
  124. "IMAGES/recovery.img",
  125. "IMAGES/system.img",
  126. "IMAGES/vendor.img",
  127. "OTA/",
  128. "OTA/android-info.txt",
  129. "OTA/b",
  130. "RADIO/",
  131. "RADIO/a",
  132. },
  133. },
  134. {
  135. name: "sort jar",
  136. inputFiles: []string{
  137. "MANIFEST.MF",
  138. "META-INF/MANIFEST.MF",
  139. "META-INF/aaa/",
  140. "META-INF/aaa/aaa",
  141. "META-INF/AAA",
  142. "META-INF.txt",
  143. "META-INF/",
  144. "AAA",
  145. "aaa",
  146. },
  147. sortJava: true,
  148. args: nil,
  149. outputFiles: []string{
  150. "META-INF/",
  151. "META-INF/MANIFEST.MF",
  152. "META-INF/AAA",
  153. "META-INF/aaa/",
  154. "META-INF/aaa/aaa",
  155. "AAA",
  156. "MANIFEST.MF",
  157. "META-INF.txt",
  158. "aaa",
  159. },
  160. },
  161. {
  162. name: "double input",
  163. inputFiles: []string{
  164. "b",
  165. "a",
  166. },
  167. args: []string{"a:a2", "**/*"},
  168. outputFiles: []string{
  169. "a2",
  170. "b",
  171. "a",
  172. },
  173. },
  174. {
  175. name: "multiple matches",
  176. inputFiles: []string{
  177. "a/a",
  178. },
  179. args: []string{"a/a", "a/*"},
  180. outputFiles: []string{
  181. "a/a",
  182. },
  183. },
  184. {
  185. name: "multiple conflicting matches",
  186. inputFiles: []string{
  187. "a/a",
  188. "a/b",
  189. },
  190. args: []string{"a/b:a/a", "a/*"},
  191. err: fmt.Errorf(`multiple entries for "a/a" with different contents`),
  192. },
  193. {
  194. name: "excludes",
  195. inputFiles: []string{
  196. "a/a",
  197. "a/b",
  198. },
  199. args: nil,
  200. excludes: []string{"a/a"},
  201. outputFiles: []string{
  202. "a/b",
  203. },
  204. },
  205. {
  206. name: "excludes with args",
  207. inputFiles: []string{
  208. "a/a",
  209. "a/b",
  210. },
  211. args: []string{"a/*"},
  212. excludes: []string{"a/a"},
  213. outputFiles: []string{
  214. "a/b",
  215. },
  216. },
  217. {
  218. name: "excludes over args",
  219. inputFiles: []string{
  220. "a/a",
  221. "a/b",
  222. },
  223. args: []string{"a/a"},
  224. excludes: []string{"a/*"},
  225. outputFiles: nil,
  226. },
  227. {
  228. name: "excludes with includes",
  229. inputFiles: []string{
  230. "a/a",
  231. "a/b",
  232. },
  233. args: nil,
  234. excludes: []string{"a/*"},
  235. includes: []string{"a/b"},
  236. outputFiles: []string{"a/b"},
  237. },
  238. {
  239. name: "excludes with glob",
  240. inputFiles: []string{
  241. "a/a",
  242. "a/b",
  243. },
  244. args: []string{"a/*"},
  245. excludes: []string{"a/*"},
  246. outputFiles: nil,
  247. },
  248. {
  249. name: "uncompress one",
  250. inputFiles: []string{
  251. "a/a",
  252. "a/b",
  253. },
  254. uncompresses: []string{"a/a"},
  255. outputFiles: []string{
  256. "a/a",
  257. "a/b",
  258. },
  259. storedFiles: []string{
  260. "a/a",
  261. },
  262. },
  263. {
  264. name: "uncompress two",
  265. inputFiles: []string{
  266. "a/a",
  267. "a/b",
  268. },
  269. uncompresses: []string{"a/a", "a/b"},
  270. outputFiles: []string{
  271. "a/a",
  272. "a/b",
  273. },
  274. storedFiles: []string{
  275. "a/a",
  276. "a/b",
  277. },
  278. },
  279. {
  280. name: "uncompress glob",
  281. inputFiles: []string{
  282. "a/a",
  283. "a/b",
  284. "a/c.so",
  285. "a/d.so",
  286. },
  287. uncompresses: []string{"a/*.so"},
  288. outputFiles: []string{
  289. "a/a",
  290. "a/b",
  291. "a/c.so",
  292. "a/d.so",
  293. },
  294. storedFiles: []string{
  295. "a/c.so",
  296. "a/d.so",
  297. },
  298. },
  299. {
  300. name: "uncompress rename",
  301. inputFiles: []string{
  302. "a/a",
  303. },
  304. args: []string{"a/a:a/b"},
  305. uncompresses: []string{"a/b"},
  306. outputFiles: []string{
  307. "a/b",
  308. },
  309. storedFiles: []string{
  310. "a/b",
  311. },
  312. },
  313. {
  314. name: "recursive glob",
  315. inputFiles: []string{
  316. "a/a/a",
  317. "a/a/b",
  318. },
  319. args: []string{"a/**/*:b"},
  320. outputFiles: []string{
  321. "b/a/a",
  322. "b/a/b",
  323. },
  324. },
  325. {
  326. name: "glob",
  327. inputFiles: []string{
  328. "a/a/a",
  329. "a/a/b",
  330. "a/b",
  331. "a/c",
  332. },
  333. args: []string{"a/*:b"},
  334. outputFiles: []string{
  335. "b/b",
  336. "b/c",
  337. },
  338. },
  339. {
  340. name: "top level glob",
  341. inputFiles: []string{
  342. "a",
  343. "b",
  344. },
  345. args: []string{"*:b"},
  346. outputFiles: []string{
  347. "b/a",
  348. "b/b",
  349. },
  350. },
  351. {
  352. name: "multilple glob",
  353. inputFiles: []string{
  354. "a/a/a",
  355. "a/a/b",
  356. },
  357. args: []string{"a/*/*:b"},
  358. outputFiles: []string{
  359. "b/a/a",
  360. "b/a/b",
  361. },
  362. },
  363. }
  364. func errorString(e error) string {
  365. if e == nil {
  366. return ""
  367. }
  368. return e.Error()
  369. }
  370. func TestZip2Zip(t *testing.T) {
  371. for _, testCase := range testCases {
  372. t.Run(testCase.name, func(t *testing.T) {
  373. inputBuf := &bytes.Buffer{}
  374. outputBuf := &bytes.Buffer{}
  375. inputWriter := zip.NewWriter(inputBuf)
  376. for _, file := range testCase.inputFiles {
  377. w, err := inputWriter.Create(file)
  378. if err != nil {
  379. t.Fatal(err)
  380. }
  381. fmt.Fprintln(w, "test")
  382. }
  383. inputWriter.Close()
  384. inputBytes := inputBuf.Bytes()
  385. inputReader, err := zip.NewReader(bytes.NewReader(inputBytes), int64(len(inputBytes)))
  386. if err != nil {
  387. t.Fatal(err)
  388. }
  389. outputWriter := zip.NewWriter(outputBuf)
  390. err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false,
  391. testCase.args, testCase.excludes, testCase.includes, testCase.uncompresses)
  392. if errorString(testCase.err) != errorString(err) {
  393. t.Fatalf("Unexpected error:\n got: %q\nwant: %q", errorString(err), errorString(testCase.err))
  394. }
  395. outputWriter.Close()
  396. outputBytes := outputBuf.Bytes()
  397. outputReader, err := zip.NewReader(bytes.NewReader(outputBytes), int64(len(outputBytes)))
  398. if err != nil {
  399. t.Fatal(err)
  400. }
  401. var outputFiles []string
  402. var storedFiles []string
  403. if len(outputReader.File) > 0 {
  404. outputFiles = make([]string, len(outputReader.File))
  405. for i, file := range outputReader.File {
  406. outputFiles[i] = file.Name
  407. if file.Method == zip.Store {
  408. storedFiles = append(storedFiles, file.Name)
  409. }
  410. }
  411. }
  412. if !reflect.DeepEqual(testCase.outputFiles, outputFiles) {
  413. t.Fatalf("Output file list does not match:\nwant: %v\n got: %v", testCase.outputFiles, outputFiles)
  414. }
  415. if !reflect.DeepEqual(testCase.storedFiles, storedFiles) {
  416. t.Fatalf("Stored file list does not match:\nwant: %v\n got: %v", testCase.storedFiles, storedFiles)
  417. }
  418. })
  419. }
  420. }
  421. func TestConstantPartOfPattern(t *testing.T) {
  422. testCases := []struct{ in, out string }{
  423. {
  424. in: "",
  425. out: "",
  426. },
  427. {
  428. in: "a",
  429. out: "a",
  430. },
  431. {
  432. in: "*",
  433. out: "",
  434. },
  435. {
  436. in: "a/a",
  437. out: "a/a",
  438. },
  439. {
  440. in: "a/*",
  441. out: "a",
  442. },
  443. {
  444. in: "a/*/a",
  445. out: "a",
  446. },
  447. {
  448. in: "a/**/*",
  449. out: "a",
  450. },
  451. }
  452. for _, test := range testCases {
  453. t.Run(test.in, func(t *testing.T) {
  454. got := constantPartOfPattern(test.in)
  455. if got != test.out {
  456. t.Errorf("want %q, got %q", test.out, got)
  457. }
  458. })
  459. }
  460. }