rubyzip 0.9.9 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +284 -41
  3. data/Rakefile +11 -6
  4. data/TODO +0 -1
  5. data/lib/zip/central_directory.rb +208 -0
  6. data/lib/zip/compressor.rb +1 -2
  7. data/lib/zip/constants.rb +59 -7
  8. data/lib/zip/crypto/encryption.rb +11 -0
  9. data/lib/zip/crypto/null_encryption.rb +43 -0
  10. data/lib/zip/crypto/traditional_encryption.rb +99 -0
  11. data/lib/zip/decompressor.rb +4 -4
  12. data/lib/zip/deflater.rb +17 -13
  13. data/lib/zip/dos_time.rb +13 -14
  14. data/lib/zip/entry.rb +700 -0
  15. data/lib/zip/entry_set.rb +86 -0
  16. data/lib/zip/errors.rb +18 -0
  17. data/lib/zip/extra_field/generic.rb +43 -0
  18. data/lib/zip/extra_field/ntfs.rb +90 -0
  19. data/lib/zip/extra_field/old_unix.rb +44 -0
  20. data/lib/zip/extra_field/universal_time.rb +47 -0
  21. data/lib/zip/extra_field/unix.rb +37 -0
  22. data/lib/zip/extra_field/zip64.rb +68 -0
  23. data/lib/zip/extra_field/zip64_placeholder.rb +15 -0
  24. data/lib/zip/extra_field.rb +101 -0
  25. data/lib/zip/file.rb +443 -0
  26. data/lib/zip/{zipfilesystem.rb → filesystem.rb} +162 -157
  27. data/lib/zip/inflater.rb +29 -28
  28. data/lib/zip/input_stream.rb +173 -0
  29. data/lib/zip/ioextras/abstract_input_stream.rb +111 -0
  30. data/lib/zip/ioextras/abstract_output_stream.rb +43 -0
  31. data/lib/zip/ioextras.rb +21 -149
  32. data/lib/zip/null_compressor.rb +2 -2
  33. data/lib/zip/null_decompressor.rb +8 -6
  34. data/lib/zip/null_input_stream.rb +3 -2
  35. data/lib/zip/output_stream.rb +189 -0
  36. data/lib/zip/pass_thru_compressor.rb +6 -6
  37. data/lib/zip/pass_thru_decompressor.rb +19 -19
  38. data/lib/zip/{zip_streamable_directory.rb → streamable_directory.rb} +3 -3
  39. data/lib/zip/streamable_stream.rb +56 -0
  40. data/lib/zip/version.rb +3 -0
  41. data/lib/zip.rb +71 -0
  42. data/samples/example.rb +44 -32
  43. data/samples/example_filesystem.rb +16 -18
  44. data/samples/example_recursive.rb +33 -28
  45. data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +26 -28
  46. data/samples/qtzip.rb +22 -31
  47. data/samples/write_simple.rb +12 -13
  48. data/samples/zipfind.rb +31 -39
  49. data/test/basic_zip_file_test.rb +60 -0
  50. data/test/case_sensitivity_test.rb +69 -0
  51. data/test/central_directory_entry_test.rb +69 -0
  52. data/test/central_directory_test.rb +100 -0
  53. data/test/crypto/null_encryption_test.rb +57 -0
  54. data/test/crypto/traditional_encryption_test.rb +80 -0
  55. data/test/data/WarnInvalidDate.zip +0 -0
  56. data/test/data/file1.txt +46 -0
  57. data/test/data/file1.txt.deflatedData +0 -0
  58. data/test/data/file2.txt +1504 -0
  59. data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
  60. data/test/data/globTest/foo.txt +0 -0
  61. data/test/data/globTest/food.txt +0 -0
  62. data/test/data/globTest.zip +0 -0
  63. data/test/data/gpbit3stored.zip +0 -0
  64. data/test/data/mimetype +1 -0
  65. data/test/data/notzippedruby.rb +7 -0
  66. data/test/data/ntfs.zip +0 -0
  67. data/test/data/oddExtraField.zip +0 -0
  68. data/test/data/path_traversal/Makefile +10 -0
  69. data/test/data/path_traversal/jwilk/README.md +5 -0
  70. data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
  71. data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
  72. data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
  73. data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
  74. data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
  75. data/test/data/path_traversal/jwilk/relative0.zip +0 -0
  76. data/test/data/path_traversal/jwilk/relative2.zip +0 -0
  77. data/test/data/path_traversal/jwilk/symlink.zip +0 -0
  78. data/test/data/path_traversal/relative1.zip +0 -0
  79. data/test/data/path_traversal/tilde.zip +0 -0
  80. data/test/data/path_traversal/tuzovakaoff/README.md +3 -0
  81. data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
  82. data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
  83. data/test/data/rubycode.zip +0 -0
  84. data/test/data/rubycode2.zip +0 -0
  85. data/test/data/test.xls +0 -0
  86. data/test/data/testDirectory.bin +0 -0
  87. data/test/data/zip64-sample.zip +0 -0
  88. data/test/data/zipWithDirs.zip +0 -0
  89. data/test/data/zipWithEncryption.zip +0 -0
  90. data/test/deflater_test.rb +65 -0
  91. data/test/encryption_test.rb +42 -0
  92. data/test/entry_set_test.rb +163 -0
  93. data/test/entry_test.rb +154 -0
  94. data/test/errors_test.rb +35 -0
  95. data/test/extra_field_test.rb +76 -0
  96. data/test/file_extract_directory_test.rb +54 -0
  97. data/test/file_extract_test.rb +145 -0
  98. data/test/file_permissions_test.rb +65 -0
  99. data/test/file_split_test.rb +57 -0
  100. data/test/file_test.rb +666 -0
  101. data/test/filesystem/dir_iterator_test.rb +58 -0
  102. data/test/filesystem/directory_test.rb +139 -0
  103. data/test/filesystem/file_mutating_test.rb +87 -0
  104. data/test/filesystem/file_nonmutating_test.rb +508 -0
  105. data/test/filesystem/file_stat_test.rb +64 -0
  106. data/test/gentestfiles.rb +126 -0
  107. data/test/inflater_test.rb +14 -0
  108. data/test/input_stream_test.rb +182 -0
  109. data/test/ioextras/abstract_input_stream_test.rb +102 -0
  110. data/test/ioextras/abstract_output_stream_test.rb +106 -0
  111. data/test/ioextras/fake_io_test.rb +18 -0
  112. data/test/local_entry_test.rb +154 -0
  113. data/test/output_stream_test.rb +128 -0
  114. data/test/pass_thru_compressor_test.rb +30 -0
  115. data/test/pass_thru_decompressor_test.rb +14 -0
  116. data/test/path_traversal_test.rb +141 -0
  117. data/test/samples/example_recursive_test.rb +37 -0
  118. data/test/settings_test.rb +95 -0
  119. data/test/test_helper.rb +234 -0
  120. data/test/unicode_file_names_and_comments_test.rb +62 -0
  121. data/test/zip64_full_test.rb +51 -0
  122. data/test/zip64_support_test.rb +14 -0
  123. metadata +274 -41
  124. data/NEWS +0 -172
  125. data/lib/zip/settings.rb +0 -10
  126. data/lib/zip/tempfile_bugfixed.rb +0 -195
  127. data/lib/zip/zip.rb +0 -56
  128. data/lib/zip/zip_central_directory.rb +0 -135
  129. data/lib/zip/zip_entry.rb +0 -638
  130. data/lib/zip/zip_entry_set.rb +0 -77
  131. data/lib/zip/zip_extra_field.rb +0 -213
  132. data/lib/zip/zip_file.rb +0 -340
  133. data/lib/zip/zip_input_stream.rb +0 -144
  134. data/lib/zip/zip_output_stream.rb +0 -173
  135. data/lib/zip/zip_streamable_stream.rb +0 -47
@@ -0,0 +1,1504 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $VERBOSE = true
4
+
5
+ require 'rubyunit'
6
+ require 'zip'
7
+
8
+ include Zip
9
+
10
+ Dir.chdir "test"
11
+
12
+ class AbstractInputStreamTest < RUNIT::TestCase
13
+ # AbstractInputStream subclass that provides a read method
14
+
15
+ TEST_LINES = [ "Hello world#{$/}",
16
+ "this is the second line#{$/}",
17
+ "this is the last line"]
18
+ TEST_STRING = TEST_LINES.join
19
+ class TestAbstractInputStream
20
+ include AbstractInputStream
21
+ def initialize(aString)
22
+ @contents = aString
23
+ @readPointer = 0
24
+ end
25
+
26
+ def read(charsToRead)
27
+ retVal=@contents[@readPointer, charsToRead]
28
+ @readPointer+=charsToRead
29
+ return retVal
30
+ end
31
+
32
+ def produceInput
33
+ read(100)
34
+ end
35
+
36
+ def inputFinished?
37
+ @contents[@readPointer] == nil
38
+ end
39
+ end
40
+
41
+ def setup
42
+ @io = TestAbstractInputStream.new(TEST_STRING)
43
+ end
44
+
45
+ def test_gets
46
+ assert_equals(TEST_LINES[0], @io.gets)
47
+ assert_equals(TEST_LINES[1], @io.gets)
48
+ assert_equals(TEST_LINES[2], @io.gets)
49
+ assert_equals(nil, @io.gets)
50
+ end
51
+
52
+ def test_getsMultiCharSeperator
53
+ assert_equals("Hell", @io.gets("ll"))
54
+ assert_equals("o world#{$/}this is the second l", @io.gets("d l"))
55
+ end
56
+
57
+ def test_each_line
58
+ lineNumber=0
59
+ @io.each_line {
60
+ |line|
61
+ assert_equals(TEST_LINES[lineNumber], line)
62
+ lineNumber+=1
63
+ }
64
+ end
65
+
66
+ def test_readlines
67
+ assert_equals(TEST_LINES, @io.readlines)
68
+ end
69
+
70
+ def test_readline
71
+ test_gets
72
+ begin
73
+ @io.readline
74
+ fail "EOFError expected"
75
+ rescue EOFError
76
+ end
77
+ end
78
+ end
79
+
80
+ class ZipEntryTest < RUNIT::TestCase
81
+ TEST_ZIPFILE = "someZipFile.zip"
82
+ TEST_COMMENT = "a comment"
83
+ TEST_COMPRESSED_SIZE = 1234
84
+ TEST_CRC = 325324
85
+ TEST_EXTRA = "Some data here"
86
+ TEST_COMPRESSIONMETHOD = ZipEntry::DEFLATED
87
+ TEST_NAME = "entry name"
88
+ TEST_SIZE = 8432
89
+ TEST_ISDIRECTORY = false
90
+
91
+ def test_constructorAndGetters
92
+ entry = ZipEntry.new(TEST_ZIPFILE,
93
+ TEST_NAME,
94
+ TEST_COMMENT,
95
+ TEST_EXTRA,
96
+ TEST_COMPRESSED_SIZE,
97
+ TEST_CRC,
98
+ TEST_COMPRESSIONMETHOD,
99
+ TEST_SIZE)
100
+
101
+ assert_equals(TEST_COMMENT, entry.comment)
102
+ assert_equals(TEST_COMPRESSED_SIZE, entry.compressedSize)
103
+ assert_equals(TEST_CRC, entry.crc)
104
+ assert_equals(TEST_EXTRA, entry.extra)
105
+ assert_equals(TEST_COMPRESSIONMETHOD, entry.compressionMethod)
106
+ assert_equals(TEST_NAME, entry.name)
107
+ assert_equals(TEST_SIZE, entry.size)
108
+ assert_equals(TEST_ISDIRECTORY, entry.isDirectory)
109
+ end
110
+
111
+ def test_equality
112
+ entry1 = ZipEntry.new("file.zip", "name", "isNotCompared",
113
+ "something extra", 123, 1234,
114
+ ZipEntry::DEFLATED, 10000)
115
+ entry2 = ZipEntry.new("file.zip", "name", "isNotComparedXXX",
116
+ "something extra", 123, 1234,
117
+ ZipEntry::DEFLATED, 10000)
118
+ entry3 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
119
+ "something extra", 123, 1234,
120
+ ZipEntry::DEFLATED, 10000)
121
+ entry4 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
122
+ "something extraXX", 123, 1234,
123
+ ZipEntry::DEFLATED, 10000)
124
+ entry5 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
125
+ "something extraXX", 12, 1234,
126
+ ZipEntry::DEFLATED, 10000)
127
+ entry6 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
128
+ "something extraXX", 12, 123,
129
+ ZipEntry::DEFLATED, 10000)
130
+ entry7 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
131
+ "something extraXX", 12, 123,
132
+ ZipEntry::STORED, 10000)
133
+ entry8 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
134
+ "something extraXX", 12, 123,
135
+ ZipEntry::STORED, 100000)
136
+
137
+ assert_equals(entry1, entry1)
138
+ assert_equals(entry1, entry2)
139
+
140
+ assert(entry2 != entry3)
141
+ assert(entry3 != entry4)
142
+ assert(entry4 != entry5)
143
+ assert(entry5 != entry6)
144
+ assert(entry6 != entry7)
145
+ assert(entry7 != entry8)
146
+
147
+ assert(entry7 != "hello")
148
+ assert(entry7 != 12)
149
+ end
150
+ end
151
+
152
+ module IOizeString
153
+ attr_reader :tell
154
+
155
+ def read(count = nil)
156
+ @tell ||= 0
157
+ count = size unless count
158
+ retVal = slice(@tell, count)
159
+ @tell += count
160
+ return retVal
161
+ end
162
+
163
+ def seek(index, offset)
164
+ @tell ||= 0
165
+ case offset
166
+ when IO::SEEK_END
167
+ newPos = size + index
168
+ when IO::SEEK_SET
169
+ newPos = index
170
+ when IO::SEEK_CUR
171
+ newPos = @tell + index
172
+ else
173
+ raise "Error in test method IOizeString::seek"
174
+ end
175
+ if (newPos < 0 || newPos >= size)
176
+ raise Errno::EINVAL
177
+ else
178
+ @tell=newPos
179
+ end
180
+ end
181
+
182
+ def reset
183
+ @tell = 0
184
+ end
185
+ end
186
+
187
+ class ZipLocalEntryTest < RUNIT::TestCase
188
+ def test_readLocalEntryHeaderOfFirstTestZipEntry
189
+ File.open(TestZipFile::TEST_ZIP3.zipName) {
190
+ |file|
191
+ entry = ZipEntry.readLocalEntry(file)
192
+
193
+ assert_equal("", entry.comment)
194
+ # Differs from windows and unix because of CR LF
195
+ # assert_equal(480, entry.compressedSize)
196
+ # assert_equal(0x2a27930f, entry.crc)
197
+ # extra field is 21 bytes long
198
+ # probably contains some unix attrutes or something
199
+ # disabled: assert_equal(nil, entry.extra)
200
+ assert_equal(ZipEntry::DEFLATED, entry.compressionMethod)
201
+ assert_equal(TestZipFile::TEST_ZIP3.entryNames[0], entry.name)
202
+ assert_equal(File.size(TestZipFile::TEST_ZIP3.entryNames[0]), entry.size)
203
+ assert(! entry.isDirectory)
204
+ }
205
+ end
206
+
207
+ def test_readLocalEntryFromNonZipFile
208
+ File.open("ziptest.rb") {
209
+ |file|
210
+ assert_equals(nil, ZipEntry.readLocalEntry(file))
211
+ }
212
+ end
213
+
214
+ def test_readLocalEntryFromTruncatedZipFile
215
+ zipFragment=""
216
+ File.open(TestZipFile::TEST_ZIP2.zipName) { |f| zipFragment = f.read(12) } # local header is at least 30 bytes
217
+ zipFragment.extend(IOizeString).reset
218
+ entry = ZipEntry.new
219
+ entry.readLocalEntry(zipFragment)
220
+ fail "ZipError expected"
221
+ rescue ZipError
222
+ end
223
+
224
+ def test_writeEntry
225
+ entry = ZipEntry.new("file.zip", "entryName", "my little comment",
226
+ "thisIsSomeExtraInformation", 100, 987654,
227
+ ZipEntry::DEFLATED, 400)
228
+ writeToFile("localEntryHeader.bin", "centralEntryHeader.bin", entry)
229
+ entryReadLocal, entryReadCentral = readFromFile("localEntryHeader.bin", "centralEntryHeader.bin")
230
+ compareLocalEntryHeaders(entry, entryReadLocal)
231
+ compareCDirEntryHeaders(entry, entryReadCentral)
232
+ end
233
+
234
+ private
235
+ def compareLocalEntryHeaders(entry1, entry2)
236
+ assert_equals(entry1.compressedSize , entry2.compressedSize)
237
+ assert_equals(entry1.crc , entry2.crc)
238
+ assert_equals(entry1.extra , entry2.extra)
239
+ assert_equals(entry1.compressionMethod, entry2.compressionMethod)
240
+ assert_equals(entry1.name , entry2.name)
241
+ assert_equals(entry1.size , entry2.size)
242
+ assert_equals(entry1.localHeaderOffset, entry2.localHeaderOffset)
243
+ end
244
+
245
+ def compareCDirEntryHeaders(entry1, entry2)
246
+ compareLocalEntryHeaders(entry1, entry2)
247
+ assert_equals(entry1.comment, entry2.comment)
248
+ end
249
+
250
+ def writeToFile(localFileName, centralFileName, entry)
251
+ File.open(localFileName, "wb") { |f| entry.writeLocalEntry(f) }
252
+ File.open(centralFileName, "wb") { |f| entry.writeCDirEntry(f) }
253
+ end
254
+
255
+ def readFromFile(localFileName, centralFileName)
256
+ localEntry = nil
257
+ cdirEntry = nil
258
+ File.open(localFileName, "rb") { |f| localEntry = ZipEntry.readLocalEntry(f) }
259
+ File.open(centralFileName, "rb") { |f| cdirEntry = ZipEntry.readCDirEntry(f) }
260
+ return [localEntry, cdirEntry]
261
+ end
262
+ end
263
+
264
+
265
+ module DecompressorTests
266
+ # expects @refText and @decompressor
267
+
268
+ def test_readEverything
269
+ assert_equals(@refText, @decompressor.read)
270
+ end
271
+
272
+ def test_readInChunks
273
+ chunkSize = 5
274
+ while (decompressedChunk = @decompressor.read(chunkSize))
275
+ assert_equals(@refText.slice!(0, chunkSize), decompressedChunk)
276
+ end
277
+ assert_equals(0, @refText.size)
278
+ end
279
+ end
280
+
281
+ class InflaterTest < RUNIT::TestCase
282
+ include DecompressorTests
283
+
284
+ def setup
285
+ @file = File.new("file1.txt.deflatedData", "rb")
286
+ @refText=""
287
+ File.open("file1.txt") { |f| @refText = f.read }
288
+ @decompressor = Inflater.new(@file)
289
+ end
290
+
291
+ def teardown
292
+ @file.close
293
+ end
294
+ end
295
+
296
+
297
+ class PassThruDecompressorTest < RUNIT::TestCase
298
+ include DecompressorTests
299
+ TEST_FILE="file1.txt"
300
+ def setup
301
+ @file = File.new(TEST_FILE)
302
+ @refText=""
303
+ File.open(TEST_FILE) { |f| @refText = f.read }
304
+ @decompressor = PassThruDecompressor.new(@file, File.size(TEST_FILE))
305
+ end
306
+
307
+ def teardown
308
+ @file.close
309
+ end
310
+ end
311
+
312
+
313
+ module AssertEntry
314
+ def assertNextEntry(filename, zis)
315
+ assertEntry(filename, zis, zis.getNextEntry.name)
316
+ end
317
+
318
+ def assertEntry(filename, zis, entryName)
319
+ assert_equals(filename, entryName)
320
+ assertEntryContentsForStream(filename, zis, entryName)
321
+ end
322
+
323
+ def assertEntryContentsForStream(filename, zis, entryName)
324
+ File.open(filename, "rb") {
325
+ |file|
326
+ expected = file.read
327
+ actual = zis.read
328
+ if (expected != actual)
329
+ if (expected.length > 400 || actual.length > 400)
330
+ zipEntryFilename=entryName+".zipEntry"
331
+ File.open(zipEntryFilename, "wb") { |file| file << actual }
332
+ fail("File '#{filename}' is different from '#{zipEntryFilename}'")
333
+ else
334
+ assert_equals(expected, actual)
335
+ end
336
+ end
337
+ }
338
+ end
339
+
340
+ def AssertEntry.assertContents(filename, aString)
341
+ fileContents = ""
342
+ File.open(filename, "rb") { |f| fileContents = f.read }
343
+ if (fileContents != aString)
344
+ if (expected.length > 400 || actual.length > 400)
345
+ stringFile = filename + ".other"
346
+ File.open(stringFile, "wb") { |f| f << aString }
347
+ fail("File '#{filename}' is different from contents of string stored in '#{stringFile}'")
348
+ else
349
+ assert_equals(expected, actual)
350
+ end
351
+ end
352
+ end
353
+
354
+ def assertStreamContents(zis, testZipFile)
355
+ assert(zis != nil)
356
+ testZipFile.entryNames.each {
357
+ |entryName|
358
+ assertNextEntry(entryName, zis)
359
+ }
360
+ assert_equals(nil, zis.getNextEntry)
361
+ end
362
+
363
+ def assertTestZipContents(testZipFile)
364
+ ZipInputStream.open(testZipFile.zipName) {
365
+ |zis|
366
+ assertStreamContents(zis, testZipFile)
367
+ }
368
+ end
369
+
370
+ def assertEntryContents(zipFile, entryName, filename = entryName.to_s)
371
+ zis = zipFile.getInputStream(entryName)
372
+ assertEntryContentsForStream(filename, zis, entryName)
373
+ ensure
374
+ zis.close if zis
375
+ end
376
+ end
377
+
378
+
379
+
380
+ class ZipInputStreamTest < RUNIT::TestCase
381
+ include AssertEntry
382
+
383
+ def test_new
384
+ zis = ZipInputStream.new(TestZipFile::TEST_ZIP2.zipName)
385
+ assertStreamContents(zis, TestZipFile::TEST_ZIP2)
386
+ zis.close
387
+ end
388
+
389
+ def test_openWithBlock
390
+ ZipInputStream.open(TestZipFile::TEST_ZIP2.zipName) {
391
+ |zis|
392
+ assertStreamContents(zis, TestZipFile::TEST_ZIP2)
393
+ }
394
+ end
395
+
396
+ def test_openWithoutBlock
397
+ zis = ZipInputStream.open(TestZipFile::TEST_ZIP2.zipName)
398
+ assertStreamContents(zis, TestZipFile::TEST_ZIP2)
399
+ end
400
+
401
+ def test_incompleteReads
402
+ ZipInputStream.open(TestZipFile::TEST_ZIP2.zipName) {
403
+ |zis|
404
+ entry = zis.getNextEntry
405
+ assert_equals(TestZipFile::TEST_ZIP2.entryNames[0], entry.name)
406
+ assert zis.gets.length > 0
407
+ entry = zis.getNextEntry
408
+ assert_equals(TestZipFile::TEST_ZIP2.entryNames[1], entry.name)
409
+ assert_equals(0, entry.size)
410
+ assert_equals(nil, zis.gets)
411
+ entry = zis.getNextEntry
412
+ assert_equals(TestZipFile::TEST_ZIP2.entryNames[2], entry.name)
413
+ assert zis.gets.length > 0
414
+ entry = zis.getNextEntry
415
+ assert_equals(TestZipFile::TEST_ZIP2.entryNames[3], entry.name)
416
+ assert zis.gets.length > 0
417
+ }
418
+ end
419
+
420
+ end
421
+
422
+ class TestFiles
423
+ RANDOM_ASCII_FILE1 = "randomAscii1.txt"
424
+ RANDOM_ASCII_FILE2 = "randomAscii2.txt"
425
+ RANDOM_ASCII_FILE3 = "randomAscii3.txt"
426
+ RANDOM_BINARY_FILE1 = "randomBinary1.bin"
427
+ RANDOM_BINARY_FILE2 = "randomBinary2.bin"
428
+
429
+ EMPTY_TEST_DIR = "emptytestdir"
430
+
431
+ ASCII_TEST_FILES = [ RANDOM_ASCII_FILE1, RANDOM_ASCII_FILE2, RANDOM_ASCII_FILE3 ]
432
+ BINARY_TEST_FILES = [ RANDOM_BINARY_FILE1, RANDOM_BINARY_FILE2 ]
433
+ TEST_DIRECTORIES = [ EMPTY_TEST_DIR ]
434
+ TEST_FILES = [ ASCII_TEST_FILES, BINARY_TEST_FILES, EMPTY_TEST_DIR ].flatten!
435
+
436
+ def TestFiles.createTestFiles(recreate)
437
+ if (recreate ||
438
+ ! (TEST_FILES.inject(true) { |accum, element| accum && File.exists?(element) }))
439
+
440
+ ASCII_TEST_FILES.each_with_index {
441
+ |filename, index|
442
+ createRandomAscii(filename, 1E4 * (index+1))
443
+ }
444
+
445
+ BINARY_TEST_FILES.each_with_index {
446
+ |filename, index|
447
+ createRandomBinary(filename, 1E4 * (index+1))
448
+ }
449
+
450
+ ensureDir(EMPTY_TEST_DIR)
451
+ end
452
+ end
453
+
454
+ private
455
+ def TestFiles.createRandomAscii(filename, size)
456
+ File.open(filename, "wb") {
457
+ |file|
458
+ while (file.tell < size)
459
+ file << rand
460
+ end
461
+ }
462
+ end
463
+
464
+ def TestFiles.createRandomBinary(filename, size)
465
+ File.open(filename, "wb") {
466
+ |file|
467
+ while (file.tell < size)
468
+ file << rand.to_a.pack("V")
469
+ end
470
+ }
471
+ end
472
+
473
+ def TestFiles.ensureDir(name)
474
+ if File.exists?(name)
475
+ return if File.stat(name).directory?
476
+ File.delete(name)
477
+ end
478
+ Dir.mkdir(name)
479
+ end
480
+
481
+ end
482
+
483
+ # For representation and creation of
484
+ # test data
485
+ class TestZipFile
486
+ attr_accessor :zipName, :entryNames, :comment
487
+
488
+ def initialize(zipName, entryNames, comment = "")
489
+ @zipName=zipName
490
+ @entryNames=entryNames
491
+ @comment = comment
492
+ end
493
+
494
+ def TestZipFile.createTestZips(recreate)
495
+ files = Dir.entries(".")
496
+ if (recreate ||
497
+ ! (files.index(TEST_ZIP1.zipName) &&
498
+ files.index(TEST_ZIP2.zipName) &&
499
+ files.index(TEST_ZIP3.zipName) &&
500
+ files.index(TEST_ZIP4.zipName) &&
501
+ files.index("empty.txt") &&
502
+ files.index("short.txt") &&
503
+ files.index("longAscii.txt") &&
504
+ files.index("longBinary.bin") ))
505
+ raise "failed to create test zip '#{TEST_ZIP1.zipName}'" unless
506
+ system("zip #{TEST_ZIP1.zipName} ziptest.rb")
507
+ raise "failed to remove entry from '#{TEST_ZIP1.zipName}'" unless
508
+ system("zip #{TEST_ZIP1.zipName} -d ziptest.rb")
509
+
510
+ File.open("empty.txt", "w") {}
511
+
512
+ File.open("short.txt", "w") { |file| file << "ABCDEF" }
513
+ ziptestTxt=""
514
+ File.open("ziptest.rb") { |file| ziptestTxt=file.read }
515
+ File.open("longAscii.txt", "w") {
516
+ |file|
517
+ while (file.tell < 1E5)
518
+ file << ziptestTxt
519
+ end
520
+ }
521
+
522
+ testBinaryPattern=""
523
+ File.open("empty.zip") { |file| testBinaryPattern=file.read }
524
+ testBinaryPattern *= 4
525
+
526
+ File.open("longBinary.bin", "wb") {
527
+ |file|
528
+ while (file.tell < 3E5)
529
+ file << testBinaryPattern << rand
530
+ end
531
+ }
532
+ raise "failed to create test zip '#{TEST_ZIP2.zipName}'" unless
533
+ system("zip #{TEST_ZIP2.zipName} #{TEST_ZIP2.entryNames.join(' ')}")
534
+
535
+ # without bash system interprets everything after echo as parameters to
536
+ # echo including | zip -z ...
537
+ raise "failed to add comment to test zip '#{TEST_ZIP2.zipName}'" unless
538
+ system("bash -c \"echo #{TEST_ZIP2.comment} | zip -z #{TEST_ZIP2.zipName}\"")
539
+
540
+ raise "failed to create test zip '#{TEST_ZIP3.zipName}'" unless
541
+ system("zip #{TEST_ZIP3.zipName} #{TEST_ZIP3.entryNames.join(' ')}")
542
+
543
+ raise "failed to create test zip '#{TEST_ZIP4.zipName}'" unless
544
+ system("zip #{TEST_ZIP4.zipName} #{TEST_ZIP4.entryNames.join(' ')}")
545
+ end
546
+ rescue
547
+ raise $!.to_s +
548
+ "\n\nziptest.rb requires the Info-ZIP program 'zip' in the path\n" +
549
+ "to create test data. If you don't have it you can download\n" +
550
+ "the necessary test files at http://sf.net/projects/rubyzip."
551
+ end
552
+
553
+ TEST_ZIP1 = TestZipFile.new("empty.zip", [])
554
+ TEST_ZIP2 = TestZipFile.new("4entry.zip", %w{ longAscii.txt empty.txt short.txt longBinary.bin},
555
+ "my zip comment")
556
+ TEST_ZIP3 = TestZipFile.new("test1.zip", %w{ file1.txt })
557
+ TEST_ZIP4 = TestZipFile.new("zipWithDir.zip", [ "file1.txt",
558
+ TestFiles::EMPTY_TEST_DIR])
559
+ end
560
+
561
+
562
+ class AbstractOutputStreamTest < RUNIT::TestCase
563
+ class TestOutputStream
564
+ include AbstractOutputStream
565
+
566
+ attr_accessor :buffer
567
+
568
+ def initialize
569
+ @buffer = ""
570
+ end
571
+
572
+ def << (data)
573
+ @buffer << data
574
+ self
575
+ end
576
+ end
577
+
578
+ def setup
579
+ @outputStream = TestOutputStream.new
580
+
581
+ @origCommaSep = $,
582
+ @origOutputSep = $\
583
+ end
584
+
585
+ def teardown
586
+ $, = @origCommaSep
587
+ $\ = @origOutputSep
588
+ end
589
+
590
+ def test_write
591
+ count = @outputStream.write("a little string")
592
+ assert_equals("a little string", @outputStream.buffer)
593
+ assert_equals("a little string".length, count)
594
+
595
+ count = @outputStream.write(". a little more")
596
+ assert_equals("a little string. a little more", @outputStream.buffer)
597
+ assert_equals(". a little more".length, count)
598
+ end
599
+
600
+ def test_print
601
+ $\ = nil # record separator set to nil
602
+ @outputStream.print("hello")
603
+ assert_equals("hello", @outputStream.buffer)
604
+
605
+ @outputStream.print(" world.")
606
+ assert_equals("hello world.", @outputStream.buffer)
607
+
608
+ @outputStream.print(" You ok ", "out ", "there?")
609
+ assert_equals("hello world. You ok out there?", @outputStream.buffer)
610
+
611
+ $\ = "\n"
612
+ @outputStream.print
613
+ assert_equals("hello world. You ok out there?\n", @outputStream.buffer)
614
+
615
+ @outputStream.print("I sure hope so!")
616
+ assert_equals("hello world. You ok out there?\nI sure hope so!\n", @outputStream.buffer)
617
+
618
+ $, = "X"
619
+ @outputStream.buffer = ""
620
+ @outputStream.print("monkey", "duck", "zebra")
621
+ assert_equals("monkeyXduckXzebra\n", @outputStream.buffer)
622
+
623
+ $\ = nil
624
+ @outputStream.buffer = ""
625
+ @outputStream.print(20)
626
+ assert_equals("20", @outputStream.buffer)
627
+ end
628
+
629
+ def test_printf
630
+ @outputStream.printf("%d %04x", 123, 123)
631
+ assert_equals("123 007b", @outputStream.buffer)
632
+ end
633
+
634
+ def test_putc
635
+ @outputStream.putc("A")
636
+ assert_equals("A", @outputStream.buffer)
637
+ @outputStream.putc(65)
638
+ assert_equals("AA", @outputStream.buffer)
639
+ end
640
+
641
+ def test_puts
642
+ @outputStream.puts
643
+ assert_equals("\n", @outputStream.buffer)
644
+
645
+ @outputStream.puts("hello", "world")
646
+ assert_equals("\nhello\nworld\n", @outputStream.buffer)
647
+
648
+ @outputStream.buffer = ""
649
+ @outputStream.puts("hello\n", "world\n")
650
+ assert_equals("hello\nworld\n", @outputStream.buffer)
651
+
652
+ @outputStream.buffer = ""
653
+ @outputStream.puts(["hello\n", "world\n"])
654
+ assert_equals("hello\nworld\n", @outputStream.buffer)
655
+
656
+ @outputStream.buffer = ""
657
+ @outputStream.puts(["hello\n", "world\n"], "bingo")
658
+ assert_equals("hello\nworld\nbingo\n", @outputStream.buffer)
659
+
660
+ @outputStream.buffer = ""
661
+ @outputStream.puts(16, 20, 50, "hello")
662
+ assert_equals("16\n20\n50\nhello\n", @outputStream.buffer)
663
+ end
664
+ end
665
+
666
+
667
+ module CrcTest
668
+ def runCrcTest(compressorClass)
669
+ str = "Here's a nice little text to compute the crc for! Ho hum, it is nice nice nice nice indeed."
670
+ fakeOut = AbstractOutputStreamTest::TestOutputStream.new
671
+
672
+ deflater = compressorClass.new(fakeOut)
673
+ deflater << str
674
+ assert_equals(0x919920fc, deflater.crc)
675
+ end
676
+ end
677
+
678
+
679
+
680
+ class PassThruCompressorTest < RUNIT::TestCase
681
+ include CrcTest
682
+
683
+ def test_size
684
+ File.open("dummy.txt", "wb") {
685
+ |file|
686
+ compressor = PassThruCompressor.new(file)
687
+
688
+ assert_equals(0, compressor.size)
689
+
690
+ t1 = "hello world"
691
+ t2 = ""
692
+ t3 = "bingo"
693
+
694
+ compressor << t1
695
+ assert_equals(compressor.size, t1.size)
696
+
697
+ compressor << t2
698
+ assert_equals(compressor.size, t1.size + t2.size)
699
+
700
+ compressor << t3
701
+ assert_equals(compressor.size, t1.size + t2.size + t3.size)
702
+ }
703
+ end
704
+
705
+ def test_crc
706
+ runCrcTest(PassThruCompressor)
707
+ end
708
+ end
709
+
710
+ class DeflaterTest < RUNIT::TestCase
711
+ include CrcTest
712
+
713
+ def test_outputOperator
714
+ txt = loadFile("ziptest.rb")
715
+ deflate(txt, "deflatertest.bin")
716
+ inflatedTxt = inflate("deflatertest.bin")
717
+ assert_equals(txt, inflatedTxt)
718
+ end
719
+
720
+ private
721
+ def loadFile(fileName)
722
+ txt = nil
723
+ File.open(fileName, "rb") { |f| txt = f.read }
724
+ end
725
+
726
+ def deflate(data, fileName)
727
+ File.open(fileName, "wb") {
728
+ |file|
729
+ deflater = Deflater.new(file)
730
+ deflater << data
731
+ deflater.finish
732
+ assert_equals(deflater.size, data.size)
733
+ file << "trailing data for zlib with -MAX_WBITS"
734
+ }
735
+ end
736
+
737
+ def inflate(fileName)
738
+ txt = nil
739
+ File.open(fileName, "rb") {
740
+ |file|
741
+ inflater = Inflater.new(file)
742
+ txt = inflater.read
743
+ }
744
+ end
745
+
746
+ def test_crc
747
+ runCrcTest(Deflater)
748
+ end
749
+ end
750
+
751
+ class ZipOutputStreamTest < RUNIT::TestCase
752
+ include AssertEntry
753
+
754
+ TEST_ZIP = TestZipFile::TEST_ZIP2.clone
755
+ TEST_ZIP.zipName = "output.zip"
756
+
757
+ def test_new
758
+ zos = ZipOutputStream.new(TEST_ZIP.zipName)
759
+ zos.comment = TEST_ZIP.comment
760
+ writeTestZip(zos)
761
+ zos.close
762
+ assertTestZipContents(TEST_ZIP)
763
+ end
764
+
765
+ def test_open
766
+ ZipOutputStream.open(TEST_ZIP.zipName) {
767
+ |zos|
768
+ zos.comment = TEST_ZIP.comment
769
+ writeTestZip(zos)
770
+ }
771
+ assertTestZipContents(TEST_ZIP)
772
+ end
773
+
774
+ def test_writingToClosedStream
775
+ assertIOErrorInClosedStream { |zos| zos << "hello world" }
776
+ assertIOErrorInClosedStream { |zos| zos.puts "hello world" }
777
+ assertIOErrorInClosedStream { |zos| zos.write "hello world" }
778
+ end
779
+
780
+ def test_cannotOpenFile
781
+ name = TestFiles::EMPTY_TEST_DIR
782
+ begin
783
+ zos = ZipOutputStream.open(name)
784
+ rescue Exception
785
+ assert($!.kind_of?(Errno::EISDIR) || # Linux
786
+ $!.kind_of?(Errno::EEXIST) || # Windows/cygwin
787
+ $!.kind_of?(Errno::EACCES), # Windows
788
+ "Expected Errno::EISDIR (or on win/cygwin: Errno::EEXIST), but was: #{$!.type}")
789
+ end
790
+ end
791
+
792
+ def assertIOErrorInClosedStream
793
+ assert_exception(IOError) {
794
+ zos = ZipOutputStream.new("test_putOnClosedStream.zip")
795
+ zos.close
796
+ yield zos
797
+ }
798
+ end
799
+
800
+ def writeTestZip(zos)
801
+ TEST_ZIP.entryNames.each {
802
+ |entryName|
803
+ zos.putNextEntry(entryName)
804
+ File.open(entryName, "rb") { |f| zos.write(f.read) }
805
+ }
806
+ end
807
+ end
808
+
809
+
810
+
811
+ module Enumerable
812
+ def compareEnumerables(otherEnumerable)
813
+ otherAsArray = otherEnumerable.to_a
814
+ index=0
815
+ each_with_index {
816
+ |element, index|
817
+ return false unless yield(element, otherAsArray[index])
818
+ }
819
+ return index+1 == otherAsArray.size
820
+ end
821
+ end
822
+
823
+
824
+ class ZipCentralDirectoryEntryTest < RUNIT::TestCase
825
+
826
+ def test_readFromStream
827
+ File.open("testDirectory.bin", "rb") {
828
+ |file|
829
+ entry = ZipEntry.readCDirEntry(file)
830
+
831
+ assert_equals("longAscii.txt", entry.name)
832
+ assert_equals(ZipEntry::DEFLATED, entry.compressionMethod)
833
+ assert_equals(106490, entry.size)
834
+ assert_equals(3784, entry.compressedSize)
835
+ assert_equals(0xfcd1799c, entry.crc)
836
+ assert_equals("", entry.comment)
837
+
838
+ entry = ZipEntry.readCDirEntry(file)
839
+ assert_equals("empty.txt", entry.name)
840
+ assert_equals(ZipEntry::STORED, entry.compressionMethod)
841
+ assert_equals(0, entry.size)
842
+ assert_equals(0, entry.compressedSize)
843
+ assert_equals(0x0, entry.crc)
844
+ assert_equals("", entry.comment)
845
+
846
+ entry = ZipEntry.readCDirEntry(file)
847
+ assert_equals("short.txt", entry.name)
848
+ assert_equals(ZipEntry::STORED, entry.compressionMethod)
849
+ assert_equals(6, entry.size)
850
+ assert_equals(6, entry.compressedSize)
851
+ assert_equals(0xbb76fe69, entry.crc)
852
+ assert_equals("", entry.comment)
853
+
854
+ entry = ZipEntry.readCDirEntry(file)
855
+ assert_equals("longBinary.bin", entry.name)
856
+ assert_equals(ZipEntry::DEFLATED, entry.compressionMethod)
857
+ assert_equals(1000024, entry.size)
858
+ assert_equals(70847, entry.compressedSize)
859
+ assert_equals(0x10da7d59, entry.crc)
860
+ assert_equals("", entry.comment)
861
+
862
+ entry = ZipEntry.readCDirEntry(file)
863
+ assert_equals(nil, entry)
864
+ # Fields that are not check by this test:
865
+ # version made by 2 bytes
866
+ # version needed to extract 2 bytes
867
+ # general purpose bit flag 2 bytes
868
+ # last mod file time 2 bytes
869
+ # last mod file date 2 bytes
870
+ # compressed size 4 bytes
871
+ # uncompressed size 4 bytes
872
+ # disk number start 2 bytes
873
+ # internal file attributes 2 bytes
874
+ # external file attributes 4 bytes
875
+ # relative offset of local header 4 bytes
876
+
877
+ # file name (variable size)
878
+ # extra field (variable size)
879
+ # file comment (variable size)
880
+
881
+ }
882
+ end
883
+
884
+ def test_ReadEntryFromTruncatedZipFile
885
+ fragment=""
886
+ File.open("testDirectory.bin") { |f| fragment = f.read(12) } # cdir entry header is at least 46 bytes
887
+ fragment.extend(IOizeString)
888
+ entry = ZipEntry.new
889
+ entry.readCDirEntry(fragment)
890
+ fail "ZipError expected"
891
+ rescue ZipError
892
+ end
893
+
894
+ end
895
+
896
+ class ZipCentralDirectoryTest < RUNIT::TestCase
897
+
898
+ def test_readFromStream
899
+ File.open(TestZipFile::TEST_ZIP2.zipName, "rb") {
900
+ |zipFile|
901
+ cdir = ZipCentralDirectory.readFromStream(zipFile)
902
+
903
+ assert_equals(TestZipFile::TEST_ZIP2.entryNames.size, cdir.size)
904
+ assert(cdir.compareEnumerables(TestZipFile::TEST_ZIP2.entryNames) {
905
+ |cdirEntry, testEntryName|
906
+ cdirEntry.name == testEntryName
907
+ })
908
+ assert_equals(TestZipFile::TEST_ZIP2.comment, cdir.comment)
909
+ }
910
+ end
911
+
912
+ def test_readFromInvalidStream
913
+ File.open("ziptest.rb", "rb") {
914
+ |zipFile|
915
+ cdir = ZipCentralDirectory.new
916
+ cdir.readFromStream(zipFile)
917
+ }
918
+ fail "ZipError expected!"
919
+ rescue ZipError
920
+ end
921
+
922
+ def test_ReadFromTruncatedZipFile
923
+ fragment=""
924
+ File.open("testDirectory.bin") { |f| fragment = f.read }
925
+ fragment.slice!(12) # removed part of first cdir entry. eocd structure still complete
926
+ fragment.extend(IOizeString)
927
+ entry = ZipCentralDirectory.new
928
+ entry.readFromStream(fragment)
929
+ fail "ZipError expected"
930
+ rescue ZipError
931
+ end
932
+
933
+ def test_writeToStream
934
+ entries = [ ZipEntry.new("file.zip", "flimse", "myComment", "somethingExtra"),
935
+ ZipEntry.new("file.zip", "secondEntryName"),
936
+ ZipEntry.new("file.zip", "lastEntry.txt", "Has a comment too") ]
937
+ cdir = ZipCentralDirectory.new(entries, "my zip comment")
938
+ File.open("cdirtest.bin", "wb") { |f| cdir.writeToStream(f) }
939
+ cdirReadback = ZipCentralDirectory.new
940
+ File.open("cdirtest.bin", "rb") { |f| cdirReadback.readFromStream(f) }
941
+
942
+ assert_equals(cdir.entries, cdirReadback.entries)
943
+ end
944
+
945
+ def test_equality
946
+ cdir1 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil,
947
+ "somethingExtra"),
948
+ ZipEntry.new("file.zip", "secondEntryName"),
949
+ ZipEntry.new("file.zip", "lastEntry.txt") ],
950
+ "my zip comment")
951
+ cdir2 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil,
952
+ "somethingExtra"),
953
+ ZipEntry.new("file.zip", "secondEntryName"),
954
+ ZipEntry.new("file.zip", "lastEntry.txt") ],
955
+ "my zip comment")
956
+ cdir3 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil,
957
+ "somethingExtra"),
958
+ ZipEntry.new("file.zip", "secondEntryName"),
959
+ ZipEntry.new("file.zip", "lastEntry.txt") ],
960
+ "comment?")
961
+ cdir4 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil,
962
+ "somethingExtra"),
963
+ ZipEntry.new("file.zip", "lastEntry.txt") ],
964
+ "comment?")
965
+ assert_equals(cdir1, cdir1)
966
+ assert_equals(cdir1, cdir2)
967
+
968
+ assert(cdir1 != cdir3)
969
+ assert(cdir2 != cdir3)
970
+ assert(cdir2 != cdir3)
971
+ assert(cdir3 != cdir4)
972
+
973
+ assert(cdir3 != "hello")
974
+ end
975
+ end
976
+
977
+
978
+ class BasicZipFileTest < RUNIT::TestCase
979
+ include AssertEntry
980
+
981
+ def setup
982
+ @zipFile = ZipFile.new(TestZipFile::TEST_ZIP2.zipName)
983
+ @testEntryNameIndex=0
984
+ end
985
+
986
+ def nextTestEntryName
987
+ retVal=TestZipFile::TEST_ZIP2.entryNames[@testEntryNameIndex]
988
+ @testEntryNameIndex+=1
989
+ return retVal
990
+ end
991
+
992
+ def test_entries
993
+ assert_equals(TestZipFile::TEST_ZIP2.entryNames, @zipFile.entries.map {|e| e.name} )
994
+ end
995
+
996
+ def test_each
997
+ @zipFile.each {
998
+ |entry|
999
+ assert_equals(nextTestEntryName, entry.name)
1000
+ }
1001
+ assert_equals(4, @testEntryNameIndex)
1002
+ end
1003
+
1004
+ def test_foreach
1005
+ ZipFile.foreach(TestZipFile::TEST_ZIP2.zipName) {
1006
+ |entry|
1007
+ assert_equals(nextTestEntryName, entry.name)
1008
+ }
1009
+ assert_equals(4, @testEntryNameIndex)
1010
+ end
1011
+
1012
+ def test_getInputStream
1013
+ @zipFile.each {
1014
+ |entry|
1015
+ assertEntry(nextTestEntryName, @zipFile.getInputStream(entry),
1016
+ entry.name)
1017
+ }
1018
+ assert_equals(4, @testEntryNameIndex)
1019
+ end
1020
+
1021
+ def test_getInputStreamBlock
1022
+ fileAndEntryName = @zipFile.entries.first.name
1023
+ @zipFile.getInputStream(fileAndEntryName) {
1024
+ |zis|
1025
+ assertEntryContentsForStream(fileAndEntryName,
1026
+ zis,
1027
+ fileAndEntryName)
1028
+ }
1029
+ end
1030
+ end
1031
+
1032
+ class CommonZipFileFixture < RUNIT::TestCase
1033
+ include AssertEntry
1034
+
1035
+ EMPTY_FILENAME = "emptyZipFile.zip"
1036
+
1037
+ TEST_ZIP = TestZipFile::TEST_ZIP2.clone
1038
+ TEST_ZIP.zipName = "4entry_copy.zip"
1039
+
1040
+ def setup
1041
+ File.delete(EMPTY_FILENAME) if File.exists?(EMPTY_FILENAME)
1042
+ File.copy(TestZipFile::TEST_ZIP2.zipName, TEST_ZIP.zipName)
1043
+ end
1044
+ end
1045
+
1046
+ class ZipFileTest < CommonZipFileFixture
1047
+
1048
+ def test_createFromScratch
1049
+ comment = "a short comment"
1050
+
1051
+ zf = ZipFile.new(EMPTY_FILENAME, ZipFile::CREATE)
1052
+ zf.comment = comment
1053
+ zf.close
1054
+
1055
+ zfRead = ZipFile.new(EMPTY_FILENAME)
1056
+ assert_equals(comment, zfRead.comment)
1057
+ assert_equals(0, zfRead.entries.length)
1058
+ end
1059
+
1060
+ def test_add
1061
+ srcFile = "ziptest.rb"
1062
+ entryName = "newEntryName.rb"
1063
+ assert(File.exists? srcFile)
1064
+ zf = ZipFile.new(EMPTY_FILENAME, ZipFile::CREATE)
1065
+ zf.add(entryName, srcFile)
1066
+ zf.close
1067
+
1068
+ zfRead = ZipFile.new(EMPTY_FILENAME)
1069
+ assert_equals("", zfRead.comment)
1070
+ assert_equals(1, zfRead.entries.length)
1071
+ assert_equals(entryName, zfRead.entries.first.name)
1072
+ AssertEntry.assertContents(srcFile,
1073
+ zfRead.getInputStream(entryName) { |zis| zis.read })
1074
+ end
1075
+
1076
+ def test_addExistingEntryName
1077
+ assert_exception(ZipEntryExistsError) {
1078
+ ZipFile.open(TEST_ZIP.zipName) {
1079
+ |zf|
1080
+ zf.add(zf.entries.first.name, "ziptest.rb")
1081
+ }
1082
+ }
1083
+ end
1084
+
1085
+ def test_addExistingEntryNameReplace
1086
+ gotCalled = false
1087
+ replacedEntry = nil
1088
+ ZipFile.open(TEST_ZIP.zipName) {
1089
+ |zf|
1090
+ replacedEntry = zf.entries.first.name
1091
+ zf.add(replacedEntry, "ziptest.rb") { gotCalled = true; true }
1092
+ }
1093
+ assert(gotCalled)
1094
+ ZipFile.open(TEST_ZIP.zipName) {
1095
+ |zf|
1096
+ assertContains(zf, replacedEntry, "ziptest.rb")
1097
+ }
1098
+ end
1099
+
1100
+ def test_addDirectory
1101
+ ZipFile.open(TEST_ZIP.zipName) {
1102
+ |zf|
1103
+ zf.add(TestFiles::EMPTY_TEST_DIR, TestFiles::EMPTY_TEST_DIR)
1104
+ }
1105
+ ZipFile.open(TEST_ZIP.zipName) {
1106
+ |zf|
1107
+ dirEntry = zf.entries.detect { |e| e.name == TestFiles::EMPTY_TEST_DIR+"/" }
1108
+ assert(dirEntry.isDirectory)
1109
+ }
1110
+ end
1111
+
1112
+ def test_remove
1113
+ entryToRemove, *remainingEntries = TEST_ZIP.entryNames
1114
+
1115
+ File.copy(TestZipFile::TEST_ZIP2.zipName, TEST_ZIP.zipName)
1116
+
1117
+ zf = ZipFile.new(TEST_ZIP.zipName)
1118
+ assert(zf.entries.map { |e| e.name }.include?(entryToRemove))
1119
+ zf.remove(entryToRemove)
1120
+ assert(! zf.entries.map { |e| e.name }.include?(entryToRemove))
1121
+ assert_equals(zf.entries.map {|x| x.name }.sort, remainingEntries.sort)
1122
+ zf.close
1123
+
1124
+ zfRead = ZipFile.new(TEST_ZIP.zipName)
1125
+ assert(! zfRead.entries.map { |e| e.name }.include?(entryToRemove))
1126
+ assert_equals(zfRead.entries.map {|x| x.name }.sort, remainingEntries.sort)
1127
+ zfRead.close
1128
+ end
1129
+
1130
+
1131
+ def test_rename
1132
+ entryToRename, *remainingEntries = TEST_ZIP.entryNames
1133
+
1134
+ zf = ZipFile.new(TEST_ZIP.zipName)
1135
+ assert(zf.entries.map { |e| e.name }.include? entryToRename)
1136
+
1137
+ newName = "changed name"
1138
+ assert(! zf.entries.map { |e| e.name }.include?(newName))
1139
+
1140
+ zf.rename(entryToRename, newName)
1141
+ assert(zf.entries.map { |e| e.name }.include? newName)
1142
+
1143
+ zf.close
1144
+
1145
+ zfRead = ZipFile.new(TEST_ZIP.zipName)
1146
+ assert(zfRead.entries.map { |e| e.name }.include? newName)
1147
+ zfRead.close
1148
+ end
1149
+
1150
+ def test_renameToExistingEntry
1151
+ oldEntries = nil
1152
+ ZipFile.open(TEST_ZIP.zipName) { |zf| oldEntries = zf.entries }
1153
+
1154
+ assert_exception(ZipEntryExistsError) {
1155
+ ZipFile.open(TEST_ZIP.zipName) {
1156
+ |zf|
1157
+ zf.rename(zf.entries[0], zf.entries[1].name)
1158
+ }
1159
+ }
1160
+
1161
+ ZipFile.open(TEST_ZIP.zipName) {
1162
+ |zf|
1163
+ assert_equals(oldEntries.map{ |e| e.name }, zf.entries.map{ |e| e.name })
1164
+ }
1165
+ end
1166
+
1167
+ def test_renameToExistingEntryOverwrite
1168
+ oldEntries = nil
1169
+ ZipFile.open(TEST_ZIP.zipName) { |zf| oldEntries = zf.entries }
1170
+
1171
+ gotCalled = false
1172
+ ZipFile.open(TEST_ZIP.zipName) {
1173
+ |zf|
1174
+ zf.rename(zf.entries[0], zf.entries[1].name) { gotCalled = true; true }
1175
+ }
1176
+
1177
+ assert(gotCalled)
1178
+ oldEntries.delete_at(0)
1179
+ ZipFile.open(TEST_ZIP.zipName) {
1180
+ |zf|
1181
+ assert_equals(oldEntries.map{ |e| e.name },
1182
+ zf.entries.map{ |e| e.name })
1183
+ }
1184
+ end
1185
+
1186
+ def test_renameNonEntry
1187
+ nonEntry = "bogusEntry"
1188
+ targetEntry = "targetEntryName"
1189
+ zf = ZipFile.new(TEST_ZIP.zipName)
1190
+ assert(! zf.entries.include?(nonEntry))
1191
+ assert_exception(ZipNoSuchEntryError) {
1192
+ zf.rename(nonEntry, targetEntry)
1193
+ }
1194
+ zf.commit
1195
+ assert(! zf.entries.include?(targetEntry))
1196
+ ensure
1197
+ zf.close
1198
+ end
1199
+
1200
+ def test_renameEntryToExistingEntry
1201
+ entry1, entry2, *remaining = TEST_ZIP.entryNames
1202
+ zf = ZipFile.new(TEST_ZIP.zipName)
1203
+ assert_exception(ZipEntryExistsError) {
1204
+ zf.rename(entry1, entry2)
1205
+ }
1206
+ ensure
1207
+ zf.close
1208
+ end
1209
+
1210
+ def test_replace
1211
+ unchangedEntries = TEST_ZIP.entryNames.dup
1212
+ entryToReplace = unchangedEntries.delete_at(2)
1213
+ newEntrySrcFilename = "ziptest.rb"
1214
+
1215
+ zf = ZipFile.new(TEST_ZIP.zipName)
1216
+ zf.replace(entryToReplace, newEntrySrcFilename)
1217
+
1218
+ zf.close
1219
+
1220
+ zfRead = ZipFile.new(TEST_ZIP.zipName)
1221
+ AssertEntry::assertContents(newEntrySrcFilename,
1222
+ zfRead.getInputStream(entryToReplace) { |is| is.read })
1223
+ zfRead.close
1224
+ end
1225
+
1226
+ def test_replaceNonEntry
1227
+ entryToReplace = "nonExistingEntryname"
1228
+ ZipFile.open(TEST_ZIP.zipName) {
1229
+ |zf|
1230
+ assert_exception(ZipNoSuchEntryError) {
1231
+ zf.replace(entryToReplace, "ziptest.rb")
1232
+ }
1233
+ }
1234
+ end
1235
+
1236
+ def test_commit
1237
+ newName = "renamedFirst"
1238
+ zf = ZipFile.new(TEST_ZIP.zipName)
1239
+ oldName = zf.entries.first
1240
+ zf.rename(oldName, newName)
1241
+ zf.commit
1242
+
1243
+ zfRead = ZipFile.new(TEST_ZIP.zipName)
1244
+ assert(zfRead.entries.detect { |e| e.name == newName } != nil)
1245
+ assert(zfRead.entries.detect { |e| e.name == oldName } == nil)
1246
+ zfRead.close
1247
+
1248
+ zf.close
1249
+ end
1250
+
1251
+ # This test tests that after commit, you
1252
+ # can delete the file you used to add the entry to the zip file
1253
+ # with
1254
+ def test_commitUseZipEntry
1255
+ File.copy(TestFiles::RANDOM_ASCII_FILE1, "okToDelete.txt")
1256
+ zf = ZipFile.open(TEST_ZIP.zipName)
1257
+ zf.add("okToDelete.txt", "okToDelete.txt")
1258
+ assertContains(zf, "okToDelete.txt")
1259
+ zf.commit
1260
+ File.move("okToDelete.txt", "okToDeleteMoved.txt")
1261
+ assertContains(zf, "okToDelete.txt", "okToDeleteMoved.txt")
1262
+ end
1263
+
1264
+ # def test_close
1265
+ # zf = ZipFile.new(TEST_ZIP.zipName)
1266
+ # zf.close
1267
+ # assert_exception(IOError) {
1268
+ # zf.extract(TEST_ZIP.entryNames.first, "hullubullu")
1269
+ # }
1270
+ # end
1271
+
1272
+ def test_compound1
1273
+ renamedName = "renamedName"
1274
+ originalEntries = []
1275
+ begin
1276
+ zf = ZipFile.new(TEST_ZIP.zipName)
1277
+ originalEntries = zf.entries.dup
1278
+
1279
+ assertNotContains(zf, TestFiles::RANDOM_ASCII_FILE1)
1280
+ zf.add(TestFiles::RANDOM_ASCII_FILE1,
1281
+ TestFiles::RANDOM_ASCII_FILE1)
1282
+ assertContains(zf, TestFiles::RANDOM_ASCII_FILE1)
1283
+
1284
+ zf.rename(zf.entries[0], renamedName)
1285
+ assertContains(zf, renamedName)
1286
+
1287
+ TestFiles::BINARY_TEST_FILES.each {
1288
+ |filename|
1289
+ zf.add(filename, filename)
1290
+ assertContains(zf, filename)
1291
+ }
1292
+
1293
+ assertContains(zf, originalEntries.last.to_s)
1294
+ zf.remove(originalEntries.last.to_s)
1295
+ assertNotContains(zf, originalEntries.last.to_s)
1296
+
1297
+ ensure
1298
+ zf.close
1299
+ end
1300
+ begin
1301
+ zfRead = ZipFile.new(TEST_ZIP.zipName)
1302
+ assertContains(zfRead, TestFiles::RANDOM_ASCII_FILE1)
1303
+ assertContains(zfRead, renamedName)
1304
+ TestFiles::BINARY_TEST_FILES.each {
1305
+ |filename|
1306
+ assertContains(zfRead, filename)
1307
+ }
1308
+ assertNotContains(zfRead, originalEntries.last.to_s)
1309
+ ensure
1310
+ zfRead.close
1311
+ end
1312
+ end
1313
+
1314
+ def test_compound2
1315
+ begin
1316
+ zf = ZipFile.new(TEST_ZIP.zipName)
1317
+ originalEntries = zf.entries.dup
1318
+
1319
+ originalEntries.each {
1320
+ |entry|
1321
+ zf.remove(entry)
1322
+ assertNotContains(zf, entry)
1323
+ }
1324
+ assert(zf.entries.empty?)
1325
+
1326
+ TestFiles::ASCII_TEST_FILES.each {
1327
+ |filename|
1328
+ zf.add(filename, filename)
1329
+ assertContains(zf, filename)
1330
+ }
1331
+ assert_equals(zf.entries.map { |e| e.name }, TestFiles::ASCII_TEST_FILES)
1332
+
1333
+ zf.rename(TestFiles::ASCII_TEST_FILES[0], "newName")
1334
+ assertNotContains(zf, TestFiles::ASCII_TEST_FILES[0])
1335
+ assertContains(zf, "newName")
1336
+ ensure
1337
+ zf.close
1338
+ end
1339
+ begin
1340
+ zfRead = ZipFile.new(TEST_ZIP.zipName)
1341
+ asciiTestFiles = TestFiles::ASCII_TEST_FILES.dup
1342
+ asciiTestFiles.shift
1343
+ asciiTestFiles.each {
1344
+ |filename|
1345
+ assertContains(zf, filename)
1346
+ }
1347
+
1348
+ assertContains(zf, "newName")
1349
+ ensure
1350
+ zfRead.close
1351
+ end
1352
+ end
1353
+
1354
+ private
1355
+ def assertContains(zf, entryName, filename = entryName)
1356
+ assert(zf.entries.detect { |e| e.name == entryName} != nil, "entry #{entryName} not in #{zf.entries.join(', ')} in zip file #{zf}")
1357
+ assertEntryContents(zf, entryName, filename) if File.exists?(filename)
1358
+ end
1359
+
1360
+ def assertNotContains(zf, entryName)
1361
+ assert(zf.entries.detect { |e| e.name == entryName} == nil, "entry #{entryName} in #{zf.entries.join(', ')} in zip file #{zf}")
1362
+ end
1363
+ end
1364
+
1365
+ class ZipFileExtractTest < CommonZipFileFixture
1366
+ EXTRACTED_FILENAME = "extEntry"
1367
+ ENTRY_TO_EXTRACT, *REMAINING_ENTRIES = TEST_ZIP.entryNames.reverse
1368
+
1369
+ def setup
1370
+ super
1371
+ File.delete(EXTRACTED_FILENAME) if File.exists?(EXTRACTED_FILENAME)
1372
+ end
1373
+
1374
+ def test_extract
1375
+ ZipFile.open(TEST_ZIP.zipName) {
1376
+ |zf|
1377
+ zf.extract(ENTRY_TO_EXTRACT, EXTRACTED_FILENAME)
1378
+
1379
+ assert(File.exists? EXTRACTED_FILENAME)
1380
+ AssertEntry::assertContents(EXTRACTED_FILENAME,
1381
+ zf.getInputStream(ENTRY_TO_EXTRACT) { |is| is.read })
1382
+ }
1383
+ end
1384
+
1385
+ def test_extractExists
1386
+ writtenText = "written text"
1387
+ File.open(EXTRACTED_FILENAME, "w") { |f| f.write(writtenText) }
1388
+
1389
+ assert_exception(ZipDestinationFileExistsError) {
1390
+ ZipFile.open(TEST_ZIP.zipName) {
1391
+ |zf|
1392
+ zf.extract(zf.entries.first, EXTRACTED_FILENAME)
1393
+ }
1394
+ }
1395
+ File.open(EXTRACTED_FILENAME, "r") {
1396
+ |f|
1397
+ assert_equals(writtenText, f.read)
1398
+ }
1399
+ end
1400
+
1401
+ def test_extractExistsOverwrite
1402
+ writtenText = "written text"
1403
+ File.open(EXTRACTED_FILENAME, "w") { |f| f.write(writtenText) }
1404
+
1405
+ gotCalled = false
1406
+ ZipFile.open(TEST_ZIP.zipName) {
1407
+ |zf|
1408
+ zf.extract(zf.entries.first, EXTRACTED_FILENAME) { gotCalled = true; true }
1409
+ }
1410
+
1411
+ assert(gotCalled)
1412
+ File.open(EXTRACTED_FILENAME, "r") {
1413
+ |f|
1414
+ assert(writtenText != f.read)
1415
+ }
1416
+ end
1417
+
1418
+ def test_extractNonEntry
1419
+ zf = ZipFile.new(TEST_ZIP.zipName)
1420
+ assert_exception(ZipNoSuchEntryError) { zf.extract("nonExistingEntry", "nonExistingEntry") }
1421
+ ensure
1422
+ zf.close if zf
1423
+ end
1424
+
1425
+ def test_extractNonEntry2
1426
+ outFile = "outfile"
1427
+ assert_exception(ZipNoSuchEntryError) {
1428
+ zf = ZipFile.new(TEST_ZIP.zipName)
1429
+ nonEntry = "hotdog-diddelidoo"
1430
+ assert(! zf.entries.include?(nonEntry))
1431
+ zf.extract(nonEntry, outFile)
1432
+ zf.close
1433
+ }
1434
+ assert(! File.exists?(outFile))
1435
+ end
1436
+
1437
+ end
1438
+
1439
+ class ZipFileExtractDirectoryTest < CommonZipFileFixture
1440
+ TEST_OUT_NAME = "emptyOutDir"
1441
+
1442
+ def openZip(&aProc)
1443
+ assert(aProc != nil)
1444
+ ZipFile.open(TestZipFile::TEST_ZIP4.zipName, &aProc)
1445
+ end
1446
+
1447
+ def extractTestDir(&aProc)
1448
+ openZip {
1449
+ |zf|
1450
+ zf.extract(TestFiles::EMPTY_TEST_DIR, TEST_OUT_NAME, &aProc)
1451
+ }
1452
+ end
1453
+
1454
+ def setup
1455
+ super
1456
+
1457
+ Dir.rmdir(TEST_OUT_NAME) if File.directory? TEST_OUT_NAME
1458
+ File.delete(TEST_OUT_NAME) if File.exists? TEST_OUT_NAME
1459
+ end
1460
+
1461
+ def test_extractDirectory
1462
+ extractTestDir
1463
+ assert(File.directory? TEST_OUT_NAME)
1464
+ end
1465
+
1466
+ def test_extractDirectoryExistsAsDir
1467
+ Dir.mkdir TEST_OUT_NAME
1468
+ extractTestDir
1469
+ assert(File.directory? TEST_OUT_NAME)
1470
+ end
1471
+
1472
+ def test_extractDirectoryExistsAsFile
1473
+ File.open(TEST_OUT_NAME, "w") { |f| f.puts "something" }
1474
+ assert_exception(ZipDestinationFileExistsError) { extractTestDir }
1475
+ end
1476
+
1477
+ def test_extractDirectoryExistsAsFileOverwrite
1478
+ File.open(TEST_OUT_NAME, "w") { |f| f.puts "something" }
1479
+ gotCalled = false
1480
+ extractTestDir {
1481
+ |entry, destPath|
1482
+ gotCalled = true
1483
+ assert_equals(TEST_OUT_NAME, destPath)
1484
+ assert(entry.isDirectory)
1485
+ true
1486
+ }
1487
+ assert(gotCalled)
1488
+ assert(File.directory? TEST_OUT_NAME)
1489
+ end
1490
+ end
1491
+
1492
+
1493
+ TestFiles::createTestFiles(ARGV.index("recreate") != nil ||
1494
+ ARGV.index("recreateonly") != nil)
1495
+ TestZipFile::createTestZips(ARGV.index("recreate") != nil ||
1496
+ ARGV.index("recreateonly") != nil)
1497
+ exit if ARGV.index("recreateonly") != nil
1498
+
1499
+ #require 'runit/cui/testrunner'
1500
+ #RUNIT::CUI::TestRunner.run(ZipFileTest.suite)
1501
+
1502
+ # Copyright (C) 2002 Thomas Sondergaard
1503
+ # rubyzip is free software; you can redistribute it and/or
1504
+ # modify it under the terms of the ruby license.