rubyzip 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubyzip might be problematic. Click here for more details.

Files changed (107) hide show
  1. checksums.yaml +6 -14
  2. data/README.md +173 -42
  3. data/Rakefile +10 -5
  4. data/TODO +0 -1
  5. data/lib/zip/central_directory.rb +55 -24
  6. data/lib/zip/compressor.rb +0 -0
  7. data/lib/zip/constants.rb +4 -2
  8. data/lib/zip/crypto/encryption.rb +11 -0
  9. data/lib/zip/crypto/null_encryption.rb +45 -0
  10. data/lib/zip/crypto/traditional_encryption.rb +99 -0
  11. data/lib/zip/decompressor.rb +2 -2
  12. data/lib/zip/deflater.rb +11 -6
  13. data/lib/zip/dos_time.rb +4 -5
  14. data/lib/zip/entry.rb +159 -97
  15. data/lib/zip/entry_set.rb +18 -18
  16. data/lib/zip/errors.rb +15 -6
  17. data/lib/zip/extra_field/generic.rb +8 -8
  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 +14 -14
  21. data/lib/zip/extra_field/unix.rb +8 -9
  22. data/lib/zip/extra_field/zip64.rb +44 -6
  23. data/lib/zip/extra_field/zip64_placeholder.rb +16 -0
  24. data/lib/zip/extra_field.rb +20 -8
  25. data/lib/zip/file.rb +126 -114
  26. data/lib/zip/filesystem.rb +140 -139
  27. data/lib/zip/inflater.rb +10 -9
  28. data/lib/zip/input_stream.rb +105 -80
  29. data/lib/zip/ioextras/abstract_input_stream.rb +15 -12
  30. data/lib/zip/ioextras/abstract_output_stream.rb +0 -2
  31. data/lib/zip/ioextras.rb +1 -3
  32. data/lib/zip/null_compressor.rb +2 -2
  33. data/lib/zip/null_decompressor.rb +4 -4
  34. data/lib/zip/null_input_stream.rb +2 -1
  35. data/lib/zip/output_stream.rb +57 -43
  36. data/lib/zip/pass_thru_compressor.rb +4 -4
  37. data/lib/zip/pass_thru_decompressor.rb +4 -5
  38. data/lib/zip/streamable_directory.rb +2 -2
  39. data/lib/zip/streamable_stream.rb +22 -13
  40. data/lib/zip/version.rb +1 -1
  41. data/lib/zip.rb +11 -2
  42. data/samples/example.rb +30 -40
  43. data/samples/example_filesystem.rb +16 -18
  44. data/samples/example_recursive.rb +35 -27
  45. data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +25 -27
  46. data/samples/qtzip.rb +19 -28
  47. data/samples/write_simple.rb +12 -13
  48. data/samples/zipfind.rb +29 -37
  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 +53 -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/mimetype +1 -0
  64. data/test/data/notzippedruby.rb +7 -0
  65. data/test/data/ntfs.zip +0 -0
  66. data/test/data/oddExtraField.zip +0 -0
  67. data/test/data/rubycode.zip +0 -0
  68. data/test/data/rubycode2.zip +0 -0
  69. data/test/data/test.xls +0 -0
  70. data/test/data/testDirectory.bin +0 -0
  71. data/test/data/zip64-sample.zip +0 -0
  72. data/test/data/zipWithDirs.zip +0 -0
  73. data/test/data/zipWithEncryption.zip +0 -0
  74. data/test/deflater_test.rb +65 -0
  75. data/test/encryption_test.rb +42 -0
  76. data/test/entry_set_test.rb +152 -0
  77. data/test/entry_test.rb +163 -0
  78. data/test/errors_test.rb +34 -0
  79. data/test/extra_field_test.rb +76 -0
  80. data/test/file_extract_directory_test.rb +54 -0
  81. data/test/file_extract_test.rb +83 -0
  82. data/test/file_permissions_test.rb +69 -0
  83. data/test/file_split_test.rb +57 -0
  84. data/test/file_test.rb +563 -0
  85. data/test/filesystem/dir_iterator_test.rb +58 -0
  86. data/test/filesystem/directory_test.rb +121 -0
  87. data/test/filesystem/file_mutating_test.rb +88 -0
  88. data/test/filesystem/file_nonmutating_test.rb +508 -0
  89. data/test/filesystem/file_stat_test.rb +64 -0
  90. data/test/gentestfiles.rb +122 -0
  91. data/test/inflater_test.rb +14 -0
  92. data/test/input_stream_test.rb +182 -0
  93. data/test/ioextras/abstract_input_stream_test.rb +102 -0
  94. data/test/ioextras/abstract_output_stream_test.rb +106 -0
  95. data/test/ioextras/fake_io_test.rb +18 -0
  96. data/test/local_entry_test.rb +154 -0
  97. data/test/output_stream_test.rb +128 -0
  98. data/test/pass_thru_compressor_test.rb +30 -0
  99. data/test/pass_thru_decompressor_test.rb +14 -0
  100. data/test/samples/example_recursive_test.rb +37 -0
  101. data/test/settings_test.rb +95 -0
  102. data/test/test_helper.rb +221 -0
  103. data/test/unicode_file_names_and_comments_test.rb +50 -0
  104. data/test/zip64_full_test.rb +51 -0
  105. data/test/zip64_support_test.rb +14 -0
  106. metadata +198 -22
  107. data/NEWS +0 -182
@@ -0,0 +1,14 @@
1
+ require 'test_helper'
2
+ class InflaterTest < MiniTest::Test
3
+ include DecompressorTests
4
+
5
+ def setup
6
+ super
7
+ @file = File.new('test/data/file1.txt.deflatedData', 'rb')
8
+ @decompressor = ::Zip::Inflater.new(@file)
9
+ end
10
+
11
+ def teardown
12
+ @file.close
13
+ end
14
+ end
@@ -0,0 +1,182 @@
1
+ require 'test_helper'
2
+
3
+ class ZipInputStreamTest < MiniTest::Test
4
+ include AssertEntry
5
+
6
+ class IOLike
7
+ extend Forwardable
8
+
9
+ def initialize(path, mode)
10
+ @file = File.new(path, mode)
11
+ end
12
+
13
+ delegate ::Zip::File::IO_METHODS => :@file
14
+ end
15
+
16
+ def test_new
17
+ zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name)
18
+ assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
19
+ assert_equal(true, zis.eof?)
20
+ zis.close
21
+ end
22
+
23
+ def test_open_with_block
24
+ ::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) do |zis|
25
+ assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
26
+ assert_equal(true, zis.eof?)
27
+ end
28
+ end
29
+
30
+ def test_open_without_block
31
+ zis = ::Zip::InputStream.open(File.new(TestZipFile::TEST_ZIP2.zip_name, 'rb'))
32
+ assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
33
+ end
34
+
35
+ def test_open_buffer_with_block
36
+ ::Zip::InputStream.open(File.new(TestZipFile::TEST_ZIP2.zip_name, 'rb')) do |zis|
37
+ assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
38
+ assert_equal(true, zis.eof?)
39
+ end
40
+ end
41
+
42
+ def test_open_string_io_without_block
43
+ string_io = ::StringIO.new(::File.read(TestZipFile::TEST_ZIP2.zip_name))
44
+ zis = ::Zip::InputStream.open(string_io)
45
+ assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
46
+ end
47
+
48
+ def test_open_string_io_with_block
49
+ string_io = ::StringIO.new(::File.read(TestZipFile::TEST_ZIP2.zip_name))
50
+ ::Zip::InputStream.open(string_io) do |zis|
51
+ assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
52
+ assert_equal(true, zis.eof?)
53
+ end
54
+ end
55
+
56
+ def test_open_buffer_without_block
57
+ zis = ::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name)
58
+ assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
59
+ end
60
+
61
+ def test_open_io_like_with_block
62
+ ::Zip::InputStream.open(IOLike.new(TestZipFile::TEST_ZIP2.zip_name, 'rb')) do |zis|
63
+ assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
64
+ assert_equal(true, zis.eof?)
65
+ end
66
+ end
67
+
68
+ def test_incomplete_reads
69
+ ::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) do |zis|
70
+ entry = zis.get_next_entry # longAscii.txt
71
+ assert_equal(false, zis.eof?)
72
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], entry.name)
73
+ assert zis.gets.length > 0
74
+ assert_equal(false, zis.eof?)
75
+ entry = zis.get_next_entry # empty.txt
76
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[1], entry.name)
77
+ assert_equal(0, entry.size)
78
+ assert_equal(nil, zis.gets)
79
+ assert_equal(true, zis.eof?)
80
+ entry = zis.get_next_entry # empty_chmod640.txt
81
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[2], entry.name)
82
+ assert_equal(0, entry.size)
83
+ assert_equal(nil, zis.gets)
84
+ assert_equal(true, zis.eof?)
85
+ entry = zis.get_next_entry # short.txt
86
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[3], entry.name)
87
+ assert zis.gets.length > 0
88
+ entry = zis.get_next_entry # longBinary.bin
89
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[4], entry.name)
90
+ assert zis.gets.length > 0
91
+ end
92
+ end
93
+
94
+ def test_incomplete_reads_from_string_io
95
+ string_io = ::StringIO.new(::File.read(TestZipFile::TEST_ZIP2.zip_name))
96
+ ::Zip::InputStream.open(string_io) do |zis|
97
+ entry = zis.get_next_entry # longAscii.txt
98
+ assert_equal(false, zis.eof?)
99
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], entry.name)
100
+ assert zis.gets.length > 0
101
+ assert_equal(false, zis.eof?)
102
+ entry = zis.get_next_entry # empty.txt
103
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[1], entry.name)
104
+ assert_equal(0, entry.size)
105
+ assert_equal(nil, zis.gets)
106
+ assert_equal(true, zis.eof?)
107
+ entry = zis.get_next_entry # empty_chmod640.txt
108
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[2], entry.name)
109
+ assert_equal(0, entry.size)
110
+ assert_equal(nil, zis.gets)
111
+ assert_equal(true, zis.eof?)
112
+ entry = zis.get_next_entry # short.txt
113
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[3], entry.name)
114
+ assert zis.gets.length > 0
115
+ entry = zis.get_next_entry # longBinary.bin
116
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[4], entry.name)
117
+ assert zis.gets.length > 0
118
+ end
119
+ end
120
+
121
+ def test_read_with_number_of_bytes_returns_nil_at_eof
122
+ ::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) do |zis|
123
+ entry = zis.get_next_entry # longAscii.txt
124
+ zis.read(entry.size)
125
+ assert_equal(true, zis.eof?)
126
+ assert_nil(zis.read(1))
127
+ assert_nil(zis.read(1))
128
+ end
129
+ end
130
+
131
+ def test_rewind
132
+ ::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) do |zis|
133
+ e = zis.get_next_entry
134
+ assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], e.name)
135
+
136
+ # Do a little reading
137
+ buf = ''
138
+ buf << zis.read(100)
139
+ assert_equal(100, zis.pos)
140
+ buf << (zis.gets || '')
141
+ buf << (zis.gets || '')
142
+ assert_equal(false, zis.eof?)
143
+
144
+ zis.rewind
145
+
146
+ buf2 = ''
147
+ buf2 << zis.read(100)
148
+ buf2 << (zis.gets || '')
149
+ buf2 << (zis.gets || '')
150
+
151
+ assert_equal(buf, buf2)
152
+
153
+ zis.rewind
154
+ assert_equal(false, zis.eof?)
155
+ assert_equal(0, zis.pos)
156
+
157
+ assert_entry(e.name, zis, e.name)
158
+ end
159
+ end
160
+
161
+ def test_mix_read_and_gets
162
+ ::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) do |zis|
163
+ zis.get_next_entry
164
+ assert_equal('#!/usr/bin/env ruby', zis.gets.chomp)
165
+ assert_equal(false, zis.eof?)
166
+ assert_equal('', zis.gets.chomp)
167
+ assert_equal(false, zis.eof?)
168
+ assert_equal('$VERBOSE =', zis.read(10))
169
+ assert_equal(false, zis.eof?)
170
+ end
171
+ end
172
+
173
+ def test_ungetc
174
+ ::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) do |zis|
175
+ zis.get_next_entry
176
+ first_line = zis.gets.chomp
177
+ first_line.reverse.bytes.each { |b| zis.ungetc(b) }
178
+ assert_equal('#!/usr/bin/env ruby', zis.gets.chomp)
179
+ assert_equal('$VERBOSE =', zis.read(10))
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,102 @@
1
+ require 'test_helper'
2
+ require 'zip/ioextras'
3
+
4
+ class AbstractInputStreamTest < MiniTest::Test
5
+ # AbstractInputStream subclass that provides a read method
6
+
7
+ TEST_LINES = ["Hello world#{$/}",
8
+ "this is the second line#{$/}",
9
+ 'this is the last line']
10
+ TEST_STRING = TEST_LINES.join
11
+ class TestAbstractInputStream
12
+ include ::Zip::IOExtras::AbstractInputStream
13
+
14
+ def initialize(aString)
15
+ super()
16
+ @contents = aString
17
+ @readPointer = 0
18
+ end
19
+
20
+ def sysread(charsToRead, _buf = nil)
21
+ retVal = @contents[@readPointer, charsToRead]
22
+ @readPointer += charsToRead
23
+ retVal
24
+ end
25
+
26
+ def produce_input
27
+ sysread(100)
28
+ end
29
+
30
+ def input_finished?
31
+ @contents[@readPointer].nil?
32
+ end
33
+ end
34
+
35
+ def setup
36
+ @io = TestAbstractInputStream.new(TEST_STRING)
37
+ end
38
+
39
+ def test_gets
40
+ assert_equal(TEST_LINES[0], @io.gets)
41
+ assert_equal(1, @io.lineno)
42
+ assert_equal(TEST_LINES[0].length, @io.pos)
43
+ assert_equal(TEST_LINES[1], @io.gets)
44
+ assert_equal(2, @io.lineno)
45
+ assert_equal(TEST_LINES[2], @io.gets)
46
+ assert_equal(3, @io.lineno)
47
+ assert_equal(nil, @io.gets)
48
+ assert_equal(4, @io.lineno)
49
+ end
50
+
51
+ def test_gets_multi_char_seperator
52
+ assert_equal('Hell', @io.gets('ll'))
53
+ assert_equal("o world#{$/}this is the second l", @io.gets('d l'))
54
+ end
55
+
56
+ LONG_LINES = [
57
+ 'x' * 48 + "\r\n",
58
+ 'y' * 49 + "\r\n",
59
+ 'rest'
60
+ ]
61
+
62
+ def test_gets_mulit_char_seperator_split
63
+ io = TestAbstractInputStream.new(LONG_LINES.join)
64
+ assert_equal(LONG_LINES[0], io.gets("\r\n"))
65
+ assert_equal(LONG_LINES[1], io.gets("\r\n"))
66
+ assert_equal(LONG_LINES[2], io.gets("\r\n"))
67
+ end
68
+
69
+ def test_gets_with_sep_and_index
70
+ io = TestAbstractInputStream.new(LONG_LINES.join)
71
+ assert_equal('x', io.gets("\r\n", 1))
72
+ assert_equal('x' * 47 + "\r", io.gets("\r\n", 48))
73
+ assert_equal("\n", io.gets(nil, 1))
74
+ assert_equal('yy', io.gets(nil, 2))
75
+ end
76
+
77
+ def test_gets_with_index
78
+ assert_equal(TEST_LINES[0], @io.gets(100))
79
+ assert_equal('this', @io.gets(4))
80
+ end
81
+
82
+ def test_each_line
83
+ lineNumber = 0
84
+ @io.each_line do |line|
85
+ assert_equal(TEST_LINES[lineNumber], line)
86
+ lineNumber += 1
87
+ end
88
+ end
89
+
90
+ def test_readlines
91
+ assert_equal(TEST_LINES, @io.readlines)
92
+ end
93
+
94
+ def test_readline
95
+ test_gets
96
+ begin
97
+ @io.readline
98
+ fail 'EOFError expected'
99
+ rescue EOFError
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,106 @@
1
+ require 'test_helper'
2
+ require 'zip/ioextras'
3
+
4
+ class AbstractOutputStreamTest < MiniTest::Test
5
+ class TestOutputStream
6
+ include ::Zip::IOExtras::AbstractOutputStream
7
+
8
+ attr_accessor :buffer
9
+
10
+ def initialize
11
+ @buffer = ''
12
+ end
13
+
14
+ def <<(data)
15
+ @buffer << data
16
+ self
17
+ end
18
+ end
19
+
20
+ def setup
21
+ @output_stream = TestOutputStream.new
22
+
23
+ @origCommaSep = $,
24
+ @origOutputSep = $\
25
+ end
26
+
27
+ def teardown
28
+ $, = @origCommaSep
29
+ $\ = @origOutputSep
30
+ end
31
+
32
+ def test_write
33
+ count = @output_stream.write('a little string')
34
+ assert_equal('a little string', @output_stream.buffer)
35
+ assert_equal('a little string'.length, count)
36
+
37
+ count = @output_stream.write('. a little more')
38
+ assert_equal('a little string. a little more', @output_stream.buffer)
39
+ assert_equal('. a little more'.length, count)
40
+ end
41
+
42
+ def test_print
43
+ $\ = nil # record separator set to nil
44
+ @output_stream.print('hello')
45
+ assert_equal('hello', @output_stream.buffer)
46
+
47
+ @output_stream.print(' world.')
48
+ assert_equal('hello world.', @output_stream.buffer)
49
+
50
+ @output_stream.print(' You ok ', 'out ', 'there?')
51
+ assert_equal('hello world. You ok out there?', @output_stream.buffer)
52
+
53
+ $\ = "\n"
54
+ @output_stream.print
55
+ assert_equal("hello world. You ok out there?\n", @output_stream.buffer)
56
+
57
+ @output_stream.print('I sure hope so!')
58
+ assert_equal("hello world. You ok out there?\nI sure hope so!\n", @output_stream.buffer)
59
+
60
+ $, = 'X'
61
+ @output_stream.buffer = ''
62
+ @output_stream.print('monkey', 'duck', 'zebra')
63
+ assert_equal("monkeyXduckXzebra\n", @output_stream.buffer)
64
+
65
+ $\ = nil
66
+ @output_stream.buffer = ''
67
+ @output_stream.print(20)
68
+ assert_equal('20', @output_stream.buffer)
69
+ end
70
+
71
+ def test_printf
72
+ @output_stream.printf('%d %04x', 123, 123)
73
+ assert_equal('123 007b', @output_stream.buffer)
74
+ end
75
+
76
+ def test_putc
77
+ @output_stream.putc('A')
78
+ assert_equal('A', @output_stream.buffer)
79
+ @output_stream.putc(65)
80
+ assert_equal('AA', @output_stream.buffer)
81
+ end
82
+
83
+ def test_puts
84
+ @output_stream.puts
85
+ assert_equal("\n", @output_stream.buffer)
86
+
87
+ @output_stream.puts('hello', 'world')
88
+ assert_equal("\nhello\nworld\n", @output_stream.buffer)
89
+
90
+ @output_stream.buffer = ''
91
+ @output_stream.puts("hello\n", "world\n")
92
+ assert_equal("hello\nworld\n", @output_stream.buffer)
93
+
94
+ @output_stream.buffer = ''
95
+ @output_stream.puts(["hello\n", "world\n"])
96
+ assert_equal("hello\nworld\n", @output_stream.buffer)
97
+
98
+ @output_stream.buffer = ''
99
+ @output_stream.puts(["hello\n", "world\n"], 'bingo')
100
+ assert_equal("hello\nworld\nbingo\n", @output_stream.buffer)
101
+
102
+ @output_stream.buffer = ''
103
+ @output_stream.puts(16, 20, 50, 'hello')
104
+ assert_equal("16\n20\n50\nhello\n", @output_stream.buffer)
105
+ end
106
+ end
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+ require 'zip/ioextras'
3
+
4
+ class FakeIOTest < MiniTest::Test
5
+ class FakeIOUsingClass
6
+ include ::Zip::IOExtras::FakeIO
7
+ end
8
+
9
+ def test_kind_of?
10
+ obj = FakeIOUsingClass.new
11
+
12
+ assert(obj.kind_of?(Object))
13
+ assert(obj.kind_of?(FakeIOUsingClass))
14
+ assert(obj.kind_of?(IO))
15
+ assert(!obj.kind_of?(Fixnum))
16
+ assert(!obj.kind_of?(String))
17
+ end
18
+ end
@@ -0,0 +1,154 @@
1
+ require 'test_helper'
2
+
3
+ class ZipLocalEntryTest < MiniTest::Test
4
+ CEH_FILE = 'test/data/generated/centralEntryHeader.bin'
5
+ LEH_FILE = 'test/data/generated/localEntryHeader.bin'
6
+
7
+ def teardown
8
+ ::Zip.write_zip64_support = false
9
+ end
10
+
11
+ def test_read_local_entry_header_of_first_test_zip_entry
12
+ ::File.open(TestZipFile::TEST_ZIP3.zip_name, 'rb') do |file|
13
+ entry = ::Zip::Entry.read_local_entry(file)
14
+
15
+ assert_equal('', entry.comment)
16
+ # Differs from windows and unix because of CR LF
17
+ # assert_equal(480, entry.compressed_size)
18
+ # assert_equal(0x2a27930f, entry.crc)
19
+ # extra field is 21 bytes long
20
+ # probably contains some unix attrutes or something
21
+ # disabled: assert_equal(nil, entry.extra)
22
+ assert_equal(::Zip::Entry::DEFLATED, entry.compression_method)
23
+ assert_equal(TestZipFile::TEST_ZIP3.entry_names[0], entry.name)
24
+ assert_equal(::File.size(TestZipFile::TEST_ZIP3.entry_names[0]), entry.size)
25
+ assert(!entry.directory?)
26
+ end
27
+ end
28
+
29
+ def test_read_date_time
30
+ ::File.open('test/data/rubycode.zip', 'rb') do |file|
31
+ entry = ::Zip::Entry.read_local_entry(file)
32
+ assert_equal('zippedruby1.rb', entry.name)
33
+ assert_equal(::Zip::DOSTime.at(1_019_261_638), entry.time)
34
+ end
35
+ end
36
+
37
+ def test_read_local_entry_from_non_zip_file
38
+ ::File.open('test/data/file2.txt') do |file|
39
+ assert_equal(nil, ::Zip::Entry.read_local_entry(file))
40
+ end
41
+ end
42
+
43
+ def test_read_local_entry_from_truncated_zip_file
44
+ zipFragment = ''
45
+ ::File.open(TestZipFile::TEST_ZIP2.zip_name) { |f| zipFragment = f.read(12) } # local header is at least 30 bytes
46
+ zipFragment.extend(IOizeString).reset
47
+ entry = ::Zip::Entry.new
48
+ entry.read_local_entry(zipFragment)
49
+ fail 'ZipError expected'
50
+ rescue ::Zip::Error
51
+ end
52
+
53
+ def test_write_entry
54
+ entry = ::Zip::Entry.new('file.zip', 'entryName', 'my little comment',
55
+ 'thisIsSomeExtraInformation', 100, 987_654,
56
+ ::Zip::Entry::DEFLATED, 400)
57
+ write_to_file(LEH_FILE, CEH_FILE, entry)
58
+ entryReadLocal, entryReadCentral = read_from_file(LEH_FILE, CEH_FILE)
59
+ assert(entryReadCentral.extra['Zip64Placeholder'].nil?, 'zip64 placeholder should not be used in central directory')
60
+ compare_local_entry_headers(entry, entryReadLocal)
61
+ compare_c_dir_entry_headers(entry, entryReadCentral)
62
+ end
63
+
64
+ def test_write_entry_with_zip64
65
+ ::Zip.write_zip64_support = true
66
+ entry = ::Zip::Entry.new('file.zip', 'entryName', 'my little comment',
67
+ 'thisIsSomeExtraInformation', 100, 987_654,
68
+ ::Zip::Entry::DEFLATED, 400)
69
+ write_to_file(LEH_FILE, CEH_FILE, entry)
70
+ entryReadLocal, entryReadCentral = read_from_file(LEH_FILE, CEH_FILE)
71
+ assert(entryReadLocal.extra['Zip64Placeholder'], 'zip64 placeholder should be used in local file header')
72
+ entryReadLocal.extra.delete('Zip64Placeholder') # it was removed when writing the c_dir_entry, so remove from compare
73
+ assert(entryReadCentral.extra['Zip64Placeholder'].nil?, 'zip64 placeholder should not be used in central directory')
74
+ compare_local_entry_headers(entry, entryReadLocal)
75
+ compare_c_dir_entry_headers(entry, entryReadCentral)
76
+ end
77
+
78
+ def test_write_64entry
79
+ ::Zip.write_zip64_support = true
80
+ entry = ::Zip::Entry.new('bigfile.zip', 'entryName', 'my little equine',
81
+ 'malformed extra field because why not',
82
+ 0x7766554433221100, 0xDEADBEEF, ::Zip::Entry::DEFLATED,
83
+ 0x9988776655443322)
84
+ write_to_file(LEH_FILE, CEH_FILE, entry)
85
+ entryReadLocal, entryReadCentral = read_from_file(LEH_FILE, CEH_FILE)
86
+ compare_local_entry_headers(entry, entryReadLocal)
87
+ compare_c_dir_entry_headers(entry, entryReadCentral)
88
+ end
89
+
90
+ def test_rewrite_local_header64
91
+ ::Zip.write_zip64_support = true
92
+ buf1 = StringIO.new
93
+ entry = ::Zip::Entry.new('file.zip', 'entryName')
94
+ entry.write_local_entry(buf1)
95
+ assert(entry.extra['Zip64'].nil?, 'zip64 extra is unnecessarily present')
96
+
97
+ buf2 = StringIO.new
98
+ entry.size = 0x123456789ABCDEF0
99
+ entry.compressed_size = 0x0123456789ABCDEF
100
+ entry.write_local_entry(buf2, true)
101
+ refute_nil(entry.extra['Zip64'])
102
+ refute_equal(buf1.size, 0)
103
+ assert_equal(buf1.size, buf2.size) # it can't grow, or we'd clobber file data
104
+ end
105
+
106
+ def test_read_local_offset
107
+ entry = ::Zip::Entry.new('file.zip', 'entryName')
108
+ entry.local_header_offset = 12_345
109
+ ::File.open(CEH_FILE, 'wb') { |f| entry.write_c_dir_entry(f) }
110
+ read_entry = nil
111
+ ::File.open(CEH_FILE, 'rb') { |f| read_entry = ::Zip::Entry.read_c_dir_entry(f) }
112
+ compare_c_dir_entry_headers(entry, read_entry)
113
+ end
114
+
115
+ def test_read64_local_offset
116
+ ::Zip.write_zip64_support = true
117
+ entry = ::Zip::Entry.new('file.zip', 'entryName')
118
+ entry.local_header_offset = 0x0123456789ABCDEF
119
+ ::File.open(CEH_FILE, 'wb') { |f| entry.write_c_dir_entry(f) }
120
+ read_entry = nil
121
+ ::File.open(CEH_FILE, 'rb') { |f| read_entry = ::Zip::Entry.read_c_dir_entry(f) }
122
+ compare_c_dir_entry_headers(entry, read_entry)
123
+ end
124
+
125
+ private
126
+
127
+ def compare_local_entry_headers(entry1, entry2)
128
+ assert_equal(entry1.compressed_size, entry2.compressed_size)
129
+ assert_equal(entry1.crc, entry2.crc)
130
+ assert_equal(entry1.extra, entry2.extra)
131
+ assert_equal(entry1.compression_method, entry2.compression_method)
132
+ assert_equal(entry1.name, entry2.name)
133
+ assert_equal(entry1.size, entry2.size)
134
+ assert_equal(entry1.local_header_offset, entry2.local_header_offset)
135
+ end
136
+
137
+ def compare_c_dir_entry_headers(entry1, entry2)
138
+ compare_local_entry_headers(entry1, entry2)
139
+ assert_equal(entry1.comment, entry2.comment)
140
+ end
141
+
142
+ def write_to_file(localFileName, centralFileName, entry)
143
+ ::File.open(localFileName, 'wb') { |f| entry.write_local_entry(f) }
144
+ ::File.open(centralFileName, 'wb') { |f| entry.write_c_dir_entry(f) }
145
+ end
146
+
147
+ def read_from_file(localFileName, centralFileName)
148
+ localEntry = nil
149
+ cdirEntry = nil
150
+ ::File.open(localFileName, 'rb') { |f| localEntry = ::Zip::Entry.read_local_entry(f) }
151
+ ::File.open(centralFileName, 'rb') { |f| cdirEntry = ::Zip::Entry.read_c_dir_entry(f) }
152
+ [localEntry, cdirEntry]
153
+ end
154
+ end
@@ -0,0 +1,128 @@
1
+ require 'test_helper'
2
+
3
+ class ZipOutputStreamTest < MiniTest::Test
4
+ include AssertEntry
5
+
6
+ TEST_ZIP = TestZipFile::TEST_ZIP2.clone
7
+ TEST_ZIP.zip_name = 'test/data/generated/output.zip'
8
+
9
+ def test_new
10
+ zos = ::Zip::OutputStream.new(TEST_ZIP.zip_name)
11
+ zos.comment = TEST_ZIP.comment
12
+ write_test_zip(zos)
13
+ zos.close
14
+ assert_test_zip_contents(TEST_ZIP)
15
+ end
16
+
17
+ def test_open
18
+ ::Zip::OutputStream.open(TEST_ZIP.zip_name) do |zos|
19
+ zos.comment = TEST_ZIP.comment
20
+ write_test_zip(zos)
21
+ end
22
+ assert_test_zip_contents(TEST_ZIP)
23
+ end
24
+
25
+ def test_write_buffer
26
+ io = ::StringIO.new('')
27
+ buffer = ::Zip::OutputStream.write_buffer(io) do |zos|
28
+ zos.comment = TEST_ZIP.comment
29
+ write_test_zip(zos)
30
+ end
31
+ File.open(TEST_ZIP.zip_name, 'wb') { |f| f.write buffer.string }
32
+ assert_test_zip_contents(TEST_ZIP)
33
+ end
34
+
35
+ def test_write_buffer_with_temp_file
36
+ tmp_file = Tempfile.new('')
37
+
38
+ ::Zip::OutputStream.write_buffer(tmp_file) do |zos|
39
+ zos.comment = TEST_ZIP.comment
40
+ write_test_zip(zos)
41
+ end
42
+
43
+ tmp_file.rewind
44
+ File.open(TEST_ZIP.zip_name, 'wb') { |f| f.write(tmp_file.read) }
45
+ tmp_file.unlink
46
+
47
+ assert_test_zip_contents(TEST_ZIP)
48
+ end
49
+
50
+ def test_writing_to_closed_stream
51
+ assert_i_o_error_in_closed_stream { |zos| zos << 'hello world' }
52
+ assert_i_o_error_in_closed_stream { |zos| zos.puts 'hello world' }
53
+ assert_i_o_error_in_closed_stream { |zos| zos.write 'hello world' }
54
+ end
55
+
56
+ def test_cannot_open_file
57
+ name = TestFiles::EMPTY_TEST_DIR
58
+ begin
59
+ ::Zip::OutputStream.open(name)
60
+ rescue Exception
61
+ assert($!.kind_of?(Errno::EISDIR) || # Linux
62
+ $!.kind_of?(Errno::EEXIST) || # Windows/cygwin
63
+ $!.kind_of?(Errno::EACCES), # Windows
64
+ "Expected Errno::EISDIR (or on win/cygwin: Errno::EEXIST), but was: #{$!.class}")
65
+ end
66
+ end
67
+
68
+ def test_put_next_entry
69
+ stored_text = 'hello world in stored text'
70
+ entry_name = 'file1'
71
+ comment = 'my comment'
72
+ ::Zip::OutputStream.open(TEST_ZIP.zip_name) do |zos|
73
+ zos.put_next_entry(entry_name, comment, nil, ::Zip::Entry::STORED)
74
+ zos << stored_text
75
+ end
76
+
77
+ assert(File.read(TEST_ZIP.zip_name)[stored_text])
78
+ ::Zip::File.open(TEST_ZIP.zip_name) do |zf|
79
+ assert_equal(stored_text, zf.read(entry_name))
80
+ end
81
+ end
82
+
83
+ def test_put_next_entry_using_zip_entry_creates_entries_with_correct_timestamps
84
+ file = ::File.open('test/data/file2.txt', 'rb')
85
+ ::Zip::OutputStream.open(TEST_ZIP.zip_name) do |zos|
86
+ zip_entry = ::Zip::Entry.new(zos, file.path, '', '', 0, 0, ::Zip::Entry::DEFLATED, 0, ::Zip::DOSTime.at(file.mtime))
87
+ zos.put_next_entry(zip_entry)
88
+ zos << file.read
89
+ end
90
+
91
+ ::Zip::InputStream.open(TEST_ZIP.zip_name) do |io|
92
+ while (entry = io.get_next_entry)
93
+ assert(::Zip::DOSTime.at(file.mtime).dos_equals(::Zip::DOSTime.at(entry.mtime))) # Compare DOS Times, since they are stored with two seconds accuracy
94
+ end
95
+ end
96
+ end
97
+
98
+ def test_chained_put_into_next_entry
99
+ stored_text = 'hello world in stored text'
100
+ stored_text2 = 'with chain'
101
+ entry_name = 'file1'
102
+ comment = 'my comment'
103
+ ::Zip::OutputStream.open(TEST_ZIP.zip_name) do |zos|
104
+ zos.put_next_entry(entry_name, comment, nil, ::Zip::Entry::STORED)
105
+ zos << stored_text << stored_text2
106
+ end
107
+
108
+ assert(File.read(TEST_ZIP.zip_name)[stored_text])
109
+ ::Zip::File.open(TEST_ZIP.zip_name) do |zf|
110
+ assert_equal(stored_text + stored_text2, zf.read(entry_name))
111
+ end
112
+ end
113
+
114
+ def assert_i_o_error_in_closed_stream
115
+ assert_raises(IOError) do
116
+ zos = ::Zip::OutputStream.new('test/data/generated/test_putOnClosedStream.zip')
117
+ zos.close
118
+ yield zos
119
+ end
120
+ end
121
+
122
+ def write_test_zip(zos)
123
+ TEST_ZIP.entry_names.each do |entryName|
124
+ zos.put_next_entry(entryName)
125
+ File.open(entryName, 'rb') { |f| zos.write(f.read) }
126
+ end
127
+ end
128
+ end