zip_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. // 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. package zip
  15. import (
  16. "bytes"
  17. "encoding/hex"
  18. "hash/crc32"
  19. "io"
  20. "os"
  21. "reflect"
  22. "syscall"
  23. "testing"
  24. "android/soong/third_party/zip"
  25. "github.com/google/blueprint/pathtools"
  26. )
  27. var (
  28. fileA = []byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
  29. fileB = []byte("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB")
  30. fileC = []byte("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC")
  31. fileEmpty = []byte("")
  32. fileManifest = []byte("Manifest-Version: 1.0\nCreated-By: soong_zip\n\n")
  33. sha256FileA = "d53eda7a637c99cc7fb566d96e9fa109bf15c478410a3f5eb4d4c4e26cd081f6"
  34. sha256FileB = "430c56c5818e62bcb6d478901ef86284e97714c138f3c86aa14fd6a84b7ce5d3"
  35. sha256FileC = "31c5ab6111f1d6aa13c2c4e92bb3c0f7c76b61b42d141af1e846eb7f6586a51c"
  36. fileCustomManifest = []byte("Custom manifest: true\n")
  37. customManifestAfter = []byte("Manifest-Version: 1.0\nCreated-By: soong_zip\nCustom manifest: true\n\n")
  38. )
  39. var mockFs = pathtools.MockFs(map[string][]byte{
  40. "a/a/a": fileA,
  41. "a/a/b": fileB,
  42. "a/a/c -> ../../c": nil,
  43. "dangling -> missing": nil,
  44. "a/a/d -> b": nil,
  45. "c": fileC,
  46. "d/a/a": nil,
  47. "l_nl": []byte("a/a/a\na/a/b\nc\n\\[\n"),
  48. "l_sp": []byte("a/a/a a/a/b c \\["),
  49. "l2": []byte("missing\n"),
  50. "rsp": []byte("'a/a/a'\na/a/b\n'@'\n'foo'\\''bar'\n'['"),
  51. "@ -> c": nil,
  52. "foo'bar -> c": nil,
  53. "manifest.txt": fileCustomManifest,
  54. "[": fileEmpty,
  55. })
  56. func fh(name string, contents []byte, method uint16) zip.FileHeader {
  57. return zip.FileHeader{
  58. Name: name,
  59. Method: method,
  60. CRC32: crc32.ChecksumIEEE(contents),
  61. UncompressedSize64: uint64(len(contents)),
  62. ExternalAttrs: (syscall.S_IFREG | 0644) << 16,
  63. }
  64. }
  65. func fhWithSHA256(name string, contents []byte, method uint16, sha256 string) zip.FileHeader {
  66. h := fh(name, contents, method)
  67. // The extra field contains 38 bytes, including 2 bytes of header ID, 2 bytes
  68. // of size, 2 bytes of signature, and 32 bytes of checksum data block.
  69. var extra [38]byte
  70. // The first 6 bytes contains Sha256HeaderID (0x4967), size (unit(34)) and
  71. // Sha256HeaderSignature (0x9514)
  72. copy(extra[0:], []byte{103, 73, 34, 0, 20, 149})
  73. sha256Bytes, _ := hex.DecodeString(sha256)
  74. copy(extra[6:], sha256Bytes)
  75. h.Extra = append(h.Extra, extra[:]...)
  76. return h
  77. }
  78. func fhManifest(contents []byte) zip.FileHeader {
  79. return zip.FileHeader{
  80. Name: "META-INF/MANIFEST.MF",
  81. Method: zip.Store,
  82. CRC32: crc32.ChecksumIEEE(contents),
  83. UncompressedSize64: uint64(len(contents)),
  84. ExternalAttrs: (syscall.S_IFREG | 0644) << 16,
  85. }
  86. }
  87. func fhLink(name string, to string) zip.FileHeader {
  88. return zip.FileHeader{
  89. Name: name,
  90. Method: zip.Store,
  91. CRC32: crc32.ChecksumIEEE([]byte(to)),
  92. UncompressedSize64: uint64(len(to)),
  93. ExternalAttrs: (syscall.S_IFLNK | 0777) << 16,
  94. }
  95. }
  96. type fhDirOptions struct {
  97. extra []byte
  98. }
  99. func fhDir(name string, opts fhDirOptions) zip.FileHeader {
  100. return zip.FileHeader{
  101. Name: name,
  102. Method: zip.Store,
  103. CRC32: crc32.ChecksumIEEE(nil),
  104. UncompressedSize64: 0,
  105. ExternalAttrs: (syscall.S_IFDIR|0755)<<16 | 0x10,
  106. Extra: opts.extra,
  107. }
  108. }
  109. func fileArgsBuilder() *FileArgsBuilder {
  110. return &FileArgsBuilder{
  111. fs: mockFs,
  112. }
  113. }
  114. func TestZip(t *testing.T) {
  115. testCases := []struct {
  116. name string
  117. args *FileArgsBuilder
  118. compressionLevel int
  119. emulateJar bool
  120. nonDeflatedFiles map[string]bool
  121. dirEntries bool
  122. manifest string
  123. storeSymlinks bool
  124. ignoreMissingFiles bool
  125. sha256Checksum bool
  126. files []zip.FileHeader
  127. err error
  128. }{
  129. {
  130. name: "empty args",
  131. args: fileArgsBuilder(),
  132. files: []zip.FileHeader{},
  133. },
  134. {
  135. name: "files",
  136. args: fileArgsBuilder().
  137. File("a/a/a").
  138. File("a/a/b").
  139. File("c").
  140. File(`\[`),
  141. compressionLevel: 9,
  142. files: []zip.FileHeader{
  143. fh("a/a/a", fileA, zip.Deflate),
  144. fh("a/a/b", fileB, zip.Deflate),
  145. fh("c", fileC, zip.Deflate),
  146. fh("[", fileEmpty, zip.Store),
  147. },
  148. },
  149. {
  150. name: "files glob",
  151. args: fileArgsBuilder().
  152. SourcePrefixToStrip("a").
  153. File("a/**/*"),
  154. compressionLevel: 9,
  155. storeSymlinks: true,
  156. files: []zip.FileHeader{
  157. fh("a/a", fileA, zip.Deflate),
  158. fh("a/b", fileB, zip.Deflate),
  159. fhLink("a/c", "../../c"),
  160. fhLink("a/d", "b"),
  161. },
  162. },
  163. {
  164. name: "dir",
  165. args: fileArgsBuilder().
  166. SourcePrefixToStrip("a").
  167. Dir("a"),
  168. compressionLevel: 9,
  169. storeSymlinks: true,
  170. files: []zip.FileHeader{
  171. fh("a/a", fileA, zip.Deflate),
  172. fh("a/b", fileB, zip.Deflate),
  173. fhLink("a/c", "../../c"),
  174. fhLink("a/d", "b"),
  175. },
  176. },
  177. {
  178. name: "stored files",
  179. args: fileArgsBuilder().
  180. File("a/a/a").
  181. File("a/a/b").
  182. File("c"),
  183. compressionLevel: 0,
  184. files: []zip.FileHeader{
  185. fh("a/a/a", fileA, zip.Store),
  186. fh("a/a/b", fileB, zip.Store),
  187. fh("c", fileC, zip.Store),
  188. },
  189. },
  190. {
  191. name: "symlinks in zip",
  192. args: fileArgsBuilder().
  193. File("a/a/a").
  194. File("a/a/b").
  195. File("a/a/c").
  196. File("a/a/d"),
  197. compressionLevel: 9,
  198. storeSymlinks: true,
  199. files: []zip.FileHeader{
  200. fh("a/a/a", fileA, zip.Deflate),
  201. fh("a/a/b", fileB, zip.Deflate),
  202. fhLink("a/a/c", "../../c"),
  203. fhLink("a/a/d", "b"),
  204. },
  205. },
  206. {
  207. name: "follow symlinks",
  208. args: fileArgsBuilder().
  209. File("a/a/a").
  210. File("a/a/b").
  211. File("a/a/c").
  212. File("a/a/d"),
  213. compressionLevel: 9,
  214. storeSymlinks: false,
  215. files: []zip.FileHeader{
  216. fh("a/a/a", fileA, zip.Deflate),
  217. fh("a/a/b", fileB, zip.Deflate),
  218. fh("a/a/c", fileC, zip.Deflate),
  219. fh("a/a/d", fileB, zip.Deflate),
  220. },
  221. },
  222. {
  223. name: "dangling symlinks",
  224. args: fileArgsBuilder().
  225. File("dangling"),
  226. compressionLevel: 9,
  227. storeSymlinks: true,
  228. files: []zip.FileHeader{
  229. fhLink("dangling", "missing"),
  230. },
  231. },
  232. {
  233. name: "list",
  234. args: fileArgsBuilder().
  235. List("l_nl"),
  236. compressionLevel: 9,
  237. files: []zip.FileHeader{
  238. fh("a/a/a", fileA, zip.Deflate),
  239. fh("a/a/b", fileB, zip.Deflate),
  240. fh("c", fileC, zip.Deflate),
  241. fh("[", fileEmpty, zip.Store),
  242. },
  243. },
  244. {
  245. name: "list",
  246. args: fileArgsBuilder().
  247. List("l_sp"),
  248. compressionLevel: 9,
  249. files: []zip.FileHeader{
  250. fh("a/a/a", fileA, zip.Deflate),
  251. fh("a/a/b", fileB, zip.Deflate),
  252. fh("c", fileC, zip.Deflate),
  253. fh("[", fileEmpty, zip.Store),
  254. },
  255. },
  256. {
  257. name: "rsp",
  258. args: fileArgsBuilder().
  259. RspFile("rsp"),
  260. compressionLevel: 9,
  261. files: []zip.FileHeader{
  262. fh("a/a/a", fileA, zip.Deflate),
  263. fh("a/a/b", fileB, zip.Deflate),
  264. fh("@", fileC, zip.Deflate),
  265. fh("foo'bar", fileC, zip.Deflate),
  266. fh("[", fileEmpty, zip.Store),
  267. },
  268. },
  269. {
  270. name: "prefix in zip",
  271. args: fileArgsBuilder().
  272. PathPrefixInZip("foo").
  273. File("a/a/a").
  274. File("a/a/b").
  275. File("c"),
  276. compressionLevel: 9,
  277. files: []zip.FileHeader{
  278. fh("foo/a/a/a", fileA, zip.Deflate),
  279. fh("foo/a/a/b", fileB, zip.Deflate),
  280. fh("foo/c", fileC, zip.Deflate),
  281. },
  282. },
  283. {
  284. name: "relative root",
  285. args: fileArgsBuilder().
  286. SourcePrefixToStrip("a").
  287. File("a/a/a").
  288. File("a/a/b"),
  289. compressionLevel: 9,
  290. files: []zip.FileHeader{
  291. fh("a/a", fileA, zip.Deflate),
  292. fh("a/b", fileB, zip.Deflate),
  293. },
  294. },
  295. {
  296. name: "multiple relative root",
  297. args: fileArgsBuilder().
  298. SourcePrefixToStrip("a").
  299. File("a/a/a").
  300. SourcePrefixToStrip("a/a").
  301. File("a/a/b"),
  302. compressionLevel: 9,
  303. files: []zip.FileHeader{
  304. fh("a/a", fileA, zip.Deflate),
  305. fh("b", fileB, zip.Deflate),
  306. },
  307. },
  308. {
  309. name: "emulate jar",
  310. args: fileArgsBuilder().
  311. File("a/a/a").
  312. File("a/a/b"),
  313. compressionLevel: 9,
  314. emulateJar: true,
  315. files: []zip.FileHeader{
  316. fhDir("META-INF/", fhDirOptions{extra: []byte{254, 202, 0, 0}}),
  317. fhManifest(fileManifest),
  318. fhDir("a/", fhDirOptions{}),
  319. fhDir("a/a/", fhDirOptions{}),
  320. fh("a/a/a", fileA, zip.Deflate),
  321. fh("a/a/b", fileB, zip.Deflate),
  322. },
  323. },
  324. {
  325. name: "emulate jar with manifest",
  326. args: fileArgsBuilder().
  327. File("a/a/a").
  328. File("a/a/b"),
  329. compressionLevel: 9,
  330. emulateJar: true,
  331. manifest: "manifest.txt",
  332. files: []zip.FileHeader{
  333. fhDir("META-INF/", fhDirOptions{extra: []byte{254, 202, 0, 0}}),
  334. fhManifest(customManifestAfter),
  335. fhDir("a/", fhDirOptions{}),
  336. fhDir("a/a/", fhDirOptions{}),
  337. fh("a/a/a", fileA, zip.Deflate),
  338. fh("a/a/b", fileB, zip.Deflate),
  339. },
  340. },
  341. {
  342. name: "dir entries",
  343. args: fileArgsBuilder().
  344. File("a/a/a").
  345. File("a/a/b"),
  346. compressionLevel: 9,
  347. dirEntries: true,
  348. files: []zip.FileHeader{
  349. fhDir("a/", fhDirOptions{}),
  350. fhDir("a/a/", fhDirOptions{}),
  351. fh("a/a/a", fileA, zip.Deflate),
  352. fh("a/a/b", fileB, zip.Deflate),
  353. },
  354. },
  355. {
  356. name: "junk paths",
  357. args: fileArgsBuilder().
  358. JunkPaths(true).
  359. File("a/a/a").
  360. File("a/a/b"),
  361. compressionLevel: 9,
  362. files: []zip.FileHeader{
  363. fh("a", fileA, zip.Deflate),
  364. fh("b", fileB, zip.Deflate),
  365. },
  366. },
  367. {
  368. name: "non deflated files",
  369. args: fileArgsBuilder().
  370. File("a/a/a").
  371. File("a/a/b"),
  372. compressionLevel: 9,
  373. nonDeflatedFiles: map[string]bool{"a/a/a": true},
  374. files: []zip.FileHeader{
  375. fh("a/a/a", fileA, zip.Store),
  376. fh("a/a/b", fileB, zip.Deflate),
  377. },
  378. },
  379. {
  380. name: "ignore missing files",
  381. args: fileArgsBuilder().
  382. File("a/a/a").
  383. File("a/a/b").
  384. File("missing"),
  385. compressionLevel: 9,
  386. ignoreMissingFiles: true,
  387. files: []zip.FileHeader{
  388. fh("a/a/a", fileA, zip.Deflate),
  389. fh("a/a/b", fileB, zip.Deflate),
  390. },
  391. },
  392. {
  393. name: "duplicate sources",
  394. args: fileArgsBuilder().
  395. File("a/a/a").
  396. File("a/a/a"),
  397. compressionLevel: 9,
  398. files: []zip.FileHeader{
  399. fh("a/a/a", fileA, zip.Deflate),
  400. },
  401. },
  402. {
  403. name: "generate SHA256 checksum",
  404. args: fileArgsBuilder().
  405. File("a/a/a").
  406. File("a/a/b").
  407. File("a/a/c").
  408. File("c"),
  409. compressionLevel: 9,
  410. sha256Checksum: true,
  411. files: []zip.FileHeader{
  412. fhWithSHA256("a/a/a", fileA, zip.Deflate, sha256FileA),
  413. fhWithSHA256("a/a/b", fileB, zip.Deflate, sha256FileB),
  414. fhWithSHA256("a/a/c", fileC, zip.Deflate, sha256FileC),
  415. fhWithSHA256("c", fileC, zip.Deflate, sha256FileC),
  416. },
  417. },
  418. {
  419. name: "explicit path",
  420. args: fileArgsBuilder().
  421. ExplicitPathInZip("foo").
  422. File("a/a/a").
  423. File("a/a/b"),
  424. compressionLevel: 9,
  425. files: []zip.FileHeader{
  426. fh("foo", fileA, zip.Deflate),
  427. fh("a/a/b", fileB, zip.Deflate),
  428. },
  429. },
  430. {
  431. name: "explicit path with prefix",
  432. args: fileArgsBuilder().
  433. PathPrefixInZip("prefix").
  434. ExplicitPathInZip("foo").
  435. File("a/a/a").
  436. File("a/a/b"),
  437. compressionLevel: 9,
  438. files: []zip.FileHeader{
  439. fh("prefix/foo", fileA, zip.Deflate),
  440. fh("prefix/a/a/b", fileB, zip.Deflate),
  441. },
  442. },
  443. {
  444. name: "explicit path with glob",
  445. args: fileArgsBuilder().
  446. ExplicitPathInZip("foo").
  447. File("a/a/a*").
  448. File("a/a/b"),
  449. compressionLevel: 9,
  450. files: []zip.FileHeader{
  451. fh("foo", fileA, zip.Deflate),
  452. fh("a/a/b", fileB, zip.Deflate),
  453. },
  454. },
  455. {
  456. name: "explicit path with junk paths",
  457. args: fileArgsBuilder().
  458. JunkPaths(true).
  459. ExplicitPathInZip("foo/bar").
  460. File("a/a/a*").
  461. File("a/a/b"),
  462. compressionLevel: 9,
  463. files: []zip.FileHeader{
  464. fh("foo/bar", fileA, zip.Deflate),
  465. fh("b", fileB, zip.Deflate),
  466. },
  467. },
  468. // errors
  469. {
  470. name: "error missing file",
  471. args: fileArgsBuilder().
  472. File("missing"),
  473. err: os.ErrNotExist,
  474. },
  475. {
  476. name: "error missing dir",
  477. args: fileArgsBuilder().
  478. Dir("missing"),
  479. err: os.ErrNotExist,
  480. },
  481. {
  482. name: "error missing file in list",
  483. args: fileArgsBuilder().
  484. List("l2"),
  485. err: os.ErrNotExist,
  486. },
  487. {
  488. name: "error incorrect relative root",
  489. args: fileArgsBuilder().
  490. SourcePrefixToStrip("b").
  491. File("a/a/a"),
  492. err: IncorrectRelativeRootError{},
  493. },
  494. {
  495. name: "error conflicting file",
  496. args: fileArgsBuilder().
  497. SourcePrefixToStrip("a").
  498. File("a/a/a").
  499. SourcePrefixToStrip("d").
  500. File("d/a/a"),
  501. err: ConflictingFileError{},
  502. },
  503. {
  504. name: "error explicit path conflicting",
  505. args: fileArgsBuilder().
  506. ExplicitPathInZip("foo").
  507. File("a/a/a").
  508. ExplicitPathInZip("foo").
  509. File("a/a/b"),
  510. err: ConflictingFileError{},
  511. },
  512. {
  513. name: "error explicit path conflicting glob",
  514. args: fileArgsBuilder().
  515. ExplicitPathInZip("foo").
  516. File("a/a/*"),
  517. err: ConflictingFileError{},
  518. },
  519. }
  520. for _, test := range testCases {
  521. t.Run(test.name, func(t *testing.T) {
  522. if test.args.Error() != nil {
  523. t.Fatal(test.args.Error())
  524. }
  525. args := ZipArgs{}
  526. args.FileArgs = test.args.FileArgs()
  527. args.CompressionLevel = test.compressionLevel
  528. args.EmulateJar = test.emulateJar
  529. args.AddDirectoryEntriesToZip = test.dirEntries
  530. args.NonDeflatedFiles = test.nonDeflatedFiles
  531. args.ManifestSourcePath = test.manifest
  532. args.StoreSymlinks = test.storeSymlinks
  533. args.IgnoreMissingFiles = test.ignoreMissingFiles
  534. args.Sha256Checksum = test.sha256Checksum
  535. args.Filesystem = mockFs
  536. args.Stderr = &bytes.Buffer{}
  537. buf := &bytes.Buffer{}
  538. err := zipTo(args, buf)
  539. if (err != nil) != (test.err != nil) {
  540. t.Fatalf("want error %v, got %v", test.err, err)
  541. } else if test.err != nil {
  542. if os.IsNotExist(test.err) {
  543. if !os.IsNotExist(err) {
  544. t.Fatalf("want error %v, got %v", test.err, err)
  545. }
  546. } else if _, wantRelativeRootErr := test.err.(IncorrectRelativeRootError); wantRelativeRootErr {
  547. if _, gotRelativeRootErr := err.(IncorrectRelativeRootError); !gotRelativeRootErr {
  548. t.Fatalf("want error %v, got %v", test.err, err)
  549. }
  550. } else if _, wantConflictingFileError := test.err.(ConflictingFileError); wantConflictingFileError {
  551. if _, gotConflictingFileError := err.(ConflictingFileError); !gotConflictingFileError {
  552. t.Fatalf("want error %v, got %v", test.err, err)
  553. }
  554. } else {
  555. t.Fatalf("want error %v, got %v", test.err, err)
  556. }
  557. return
  558. }
  559. br := bytes.NewReader(buf.Bytes())
  560. zr, err := zip.NewReader(br, int64(br.Len()))
  561. if err != nil {
  562. t.Fatal(err)
  563. }
  564. var files []zip.FileHeader
  565. for _, f := range zr.File {
  566. r, err := f.Open()
  567. if err != nil {
  568. t.Fatalf("error when opening %s: %s", f.Name, err)
  569. }
  570. crc := crc32.NewIEEE()
  571. len, err := io.Copy(crc, r)
  572. r.Close()
  573. if err != nil {
  574. t.Fatalf("error when reading %s: %s", f.Name, err)
  575. }
  576. if uint64(len) != f.UncompressedSize64 {
  577. t.Errorf("incorrect length for %s, want %d got %d", f.Name, f.UncompressedSize64, len)
  578. }
  579. if crc.Sum32() != f.CRC32 {
  580. t.Errorf("incorrect crc for %s, want %x got %x", f.Name, f.CRC32, crc)
  581. }
  582. files = append(files, f.FileHeader)
  583. }
  584. if len(files) != len(test.files) {
  585. t.Fatalf("want %d files, got %d", len(test.files), len(files))
  586. }
  587. for i := range files {
  588. want := test.files[i]
  589. got := files[i]
  590. if want.Name != got.Name {
  591. t.Errorf("incorrect file %d want %q got %q", i, want.Name, got.Name)
  592. continue
  593. }
  594. if want.UncompressedSize64 != got.UncompressedSize64 {
  595. t.Errorf("incorrect file %s length want %v got %v", want.Name,
  596. want.UncompressedSize64, got.UncompressedSize64)
  597. }
  598. if want.ExternalAttrs != got.ExternalAttrs {
  599. t.Errorf("incorrect file %s attrs want %x got %x", want.Name,
  600. want.ExternalAttrs, got.ExternalAttrs)
  601. }
  602. if want.CRC32 != got.CRC32 {
  603. t.Errorf("incorrect file %s crc want %v got %v", want.Name,
  604. want.CRC32, got.CRC32)
  605. }
  606. if want.Method != got.Method {
  607. t.Errorf("incorrect file %s method want %v got %v", want.Name,
  608. want.Method, got.Method)
  609. }
  610. if !bytes.Equal(want.Extra, got.Extra) {
  611. t.Errorf("incorrect file %s extra want %v got %v", want.Name,
  612. want.Extra, got.Extra)
  613. }
  614. }
  615. })
  616. }
  617. }
  618. func TestSrcJar(t *testing.T) {
  619. mockFs := pathtools.MockFs(map[string][]byte{
  620. "wrong_package.java": []byte("package foo;"),
  621. "foo/correct_package.java": []byte("package foo;"),
  622. "src/no_package.java": nil,
  623. "src2/parse_error.java": []byte("error"),
  624. })
  625. want := []string{
  626. "foo/",
  627. "foo/wrong_package.java",
  628. "foo/correct_package.java",
  629. "no_package.java",
  630. "src2/",
  631. "src2/parse_error.java",
  632. }
  633. args := ZipArgs{}
  634. args.FileArgs = NewFileArgsBuilder().File("**/*.java").FileArgs()
  635. args.SrcJar = true
  636. args.AddDirectoryEntriesToZip = true
  637. args.Filesystem = mockFs
  638. args.Stderr = &bytes.Buffer{}
  639. buf := &bytes.Buffer{}
  640. err := zipTo(args, buf)
  641. if err != nil {
  642. t.Fatalf("got error %v", err)
  643. }
  644. br := bytes.NewReader(buf.Bytes())
  645. zr, err := zip.NewReader(br, int64(br.Len()))
  646. if err != nil {
  647. t.Fatal(err)
  648. }
  649. var got []string
  650. for _, f := range zr.File {
  651. r, err := f.Open()
  652. if err != nil {
  653. t.Fatalf("error when opening %s: %s", f.Name, err)
  654. }
  655. crc := crc32.NewIEEE()
  656. len, err := io.Copy(crc, r)
  657. r.Close()
  658. if err != nil {
  659. t.Fatalf("error when reading %s: %s", f.Name, err)
  660. }
  661. if uint64(len) != f.UncompressedSize64 {
  662. t.Errorf("incorrect length for %s, want %d got %d", f.Name, f.UncompressedSize64, len)
  663. }
  664. if crc.Sum32() != f.CRC32 {
  665. t.Errorf("incorrect crc for %s, want %x got %x", f.Name, f.CRC32, crc)
  666. }
  667. got = append(got, f.Name)
  668. }
  669. if !reflect.DeepEqual(want, got) {
  670. t.Errorf("want files %q, got %q", want, got)
  671. }
  672. }