zip_tricks 4.2.3 → 4.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,100 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ZipTricks::RemoteUncap, webmock: true do
4
- let(:uri) { URI.parse('http://example.com/file.zip') }
5
-
6
- after :each do
7
- File.unlink('temp.zip') rescue Errno::ENOENT
8
- end
9
-
10
- it 'returns an array of remote entries that can be used to fetch the segments from within the ZIP' do
11
- payload1 = Tempfile.new 'payload1'
12
- payload1 << Random.new.bytes((1024 * 1024 * 5) + 10)
13
- payload1.flush; payload1.rewind;
14
-
15
- payload2 = Tempfile.new 'payload2'
16
- payload2 << Random.new.bytes(1024 * 1024 * 3)
17
- payload2.flush; payload2.rewind
18
-
19
- File.open('temp.zip', 'wb') do |f|
20
- ZipTricks::Streamer.open(f) do | zip |
21
- zip.write_stored_file('first-file.bin') { |w| IO.copy_stream(payload1, w) }
22
- zip.write_stored_file('second-file.bin') { |w| IO.copy_stream(payload2, w) }
23
- end
24
- end
25
- payload1.rewind; payload2.rewind
26
-
27
- expect(File).to be_exist('temp.zip')
28
-
29
- allow_any_instance_of(described_class).to receive(:request_object_size) {
30
- File.size('temp.zip')
31
- }
32
- allow_any_instance_of(described_class).to receive(:request_range) {|_instance, range|
33
- File.open('temp.zip', 'rb') do |f|
34
- f.seek(range.begin)
35
- f.read(range.end - range.begin + 1)
36
- end
37
- }
38
-
39
- payload1.rewind; payload2.rewind
40
-
41
- files = described_class.files_within_zip_at('http://fake.example.com')
42
- expect(files).to be_kind_of(Array)
43
- expect(files.length).to eq(2)
44
-
45
- first, second = *files
46
-
47
- expect(first.filename).to eq('first-file.bin')
48
- expect(first.uncompressed_size).to eq(payload1.size)
49
- File.open('temp.zip', 'rb') do |readback|
50
- readback.seek(first.compressed_data_offset, IO::SEEK_SET)
51
- expect(readback.read(12)).to eq(payload1.read(12))
52
- end
53
-
54
- expect(second.filename).to eq('second-file.bin')
55
- expect(second.uncompressed_size).to eq(payload2.size)
56
- File.open('temp.zip', 'rb') do |readback|
57
- readback.seek(second.compressed_data_offset, IO::SEEK_SET)
58
- expect(readback.read(12)).to eq(payload2.read(12))
59
- end
60
- end
61
-
62
- it 'can cope with an empty file within the zip' do
63
- payload1 = Tempfile.new 'payload1'
64
- payload1.flush; payload1.rewind;
65
-
66
- payload2 = Tempfile.new 'payload2'
67
- payload2 << Random.new.bytes(1024)
68
- payload2.flush; payload2.rewind
69
-
70
- payload1_crc = Zlib.crc32(payload1.read).tap { payload1.rewind }
71
- payload2_crc = Zlib.crc32(payload2.read).tap { payload2.rewind }
72
-
73
- readable_zip = Tempfile.new 'somezip'
74
- ZipTricks::Streamer.open(readable_zip) do | zip |
75
- zip.add_stored_entry(filename: 'first-file-zero-size.bin', size: payload1.size, crc32: payload1_crc)
76
- zip.write_stored_file('second-file.bin') {|w| IO.copy_stream(payload2, w) }
77
- end
78
- readable_zip.flush; readable_zip.rewind
79
-
80
- allow_any_instance_of(described_class).to receive(:request_object_size) {
81
- readable_zip.size
82
- }
83
- allow_any_instance_of(described_class).to receive(:request_range) {|_instance, range|
84
- readable_zip.seek(range.begin, IO::SEEK_SET)
85
- readable_zip.read(range.end - range.begin + 1)
86
- }
87
-
88
- payload1.rewind; payload2.rewind
89
-
90
- first, second = described_class.files_within_zip_at('http://fake.example.com')
91
-
92
- expect(first.filename).to eq('first-file-zero-size.bin')
93
- expect(first.compressed_size).to be_zero
94
-
95
- expect(second.filename).to eq('second-file.bin')
96
- expect(second.uncompressed_size).to eq(payload2.size)
97
- readable_zip.seek(second.compressed_data_offset, IO::SEEK_SET)
98
- expect(readable_zip.read(12)).to eq(payload2.read(12))
99
- end
100
- end
@@ -1,31 +0,0 @@
1
- require_relative '../spec_helper'
2
-
3
- describe ZipTricks::SizeEstimator do
4
- it 'accurately predicts the output zip size' do
5
- # Generate a couple of random files
6
- raw_file_1 = SecureRandom.random_bytes(1024 * 20)
7
- raw_file_2 = SecureRandom.random_bytes(1024 * 128)
8
- raw_file_3 = SecureRandom.random_bytes(1258695)
9
-
10
- predicted_size = described_class.estimate do | estimator |
11
- r = estimator.add_stored_entry(filename: "first-file.bin", size: raw_file_1.size)
12
- expect(r).to eq(estimator), "add_stored_entry should return self"
13
-
14
- estimator.add_stored_entry(filename: "second-file.bin", size: raw_file_2.size)
15
-
16
- r = estimator.add_compressed_entry(filename: "second-flie.bin", compressed_size: raw_file_3.size,
17
- uncompressed_size: raw_file_2.size, )
18
- expect(r).to eq(estimator), "add_compressed_entry should return self"
19
-
20
- r = estimator.add_stored_entry(filename: "first-file-with-descriptor.bin", size: raw_file_1.size,
21
- use_data_descriptor: true)
22
- expect(r).to eq(estimator), "add_stored_entry should return self"
23
-
24
- r = estimator.add_compressed_entry(filename: "second-file-with-descriptor.bin", compressed_size: raw_file_3.size,
25
- uncompressed_size: raw_file_2.size, use_data_descriptor: true)
26
- expect(r).to eq(estimator), "add_compressed_entry should return self"
27
- end
28
-
29
- expect(predicted_size).to eq(2690095)
30
- end
31
- end
@@ -1,38 +0,0 @@
1
- require_relative '../spec_helper'
2
-
3
- describe ZipTricks::StreamCRC32 do
4
- it 'computes the CRC32 of a large binary file' do
5
- raw = StringIO.new(SecureRandom.random_bytes(45 * 1024 * 1024))
6
- crc = Zlib.crc32(raw.string)
7
- via_from_io = described_class.from_io(raw)
8
- expect(via_from_io).to eq(crc)
9
- end
10
-
11
- it 'allows in-place updates' do
12
- raw = StringIO.new(SecureRandom.random_bytes(45 * 1024 * 1024))
13
- crc = Zlib.crc32(raw.string)
14
-
15
- stream_crc = described_class.new
16
- stream_crc << raw.read(1024 * 64) until raw.eof?
17
- expect(stream_crc.to_i).to eq(crc)
18
- end
19
-
20
- it 'supports chained shovel' do
21
- str = 'abcdef'
22
- crc = Zlib.crc32(str)
23
-
24
- stream_crc = described_class.new
25
- stream_crc << 'a' << 'b' << 'c' << 'd' << 'e' << 'f'
26
-
27
- expect(stream_crc.to_i).to eq(crc)
28
- end
29
-
30
- it 'allows in-place update with a known value' do
31
- crc = Zlib.crc32
32
-
33
- stream_crc = described_class.new
34
- stream_crc << "This is some data"
35
- stream_crc.append(45678, 12910)
36
- expect(stream_crc.to_i).to eq(1555667875)
37
- end
38
- end
@@ -1,27 +0,0 @@
1
- require_relative '../../spec_helper'
2
-
3
- describe ZipTricks::Streamer::Writable do
4
- describe '#<<' do
5
- it 'writes the given data to the destination and returns self' do
6
- buf = StringIO.new
7
- subject = described_class.new(buf)
8
-
9
- result = subject << 'hello!'
10
-
11
- expect(buf.string).to eq('hello!')
12
- expect(result).to eq(subject)
13
- end
14
- end
15
-
16
- describe '#write' do
17
- it 'writes the given data to the destination and returns the number of bytes written' do
18
- buf = StringIO.new
19
- subject = described_class.new(buf)
20
-
21
- result = subject.write('hello!')
22
-
23
- expect(buf.string).to eq('hello!')
24
- expect(result).to eq(6)
25
- end
26
- end
27
- end
@@ -1,296 +0,0 @@
1
- require_relative '../spec_helper'
2
-
3
- describe ZipTricks::Streamer do
4
- let(:test_text_file_path) {
5
- File.join(__dir__, 'war-and-peace.txt')
6
- }
7
-
8
- # Run each test in a temporady directory, and nuke it afterwards
9
- around(:each) do |example|
10
- wd = Dir.pwd
11
- Dir.mktmpdir do | td |
12
- Dir.chdir(td)
13
- example.run
14
- end
15
- Dir.chdir(wd)
16
- end
17
-
18
- def rewind_after(*ios)
19
- yield.tap { ios.map(&:rewind) }
20
- end
21
-
22
- it 'raises an InvalidOutput if the given object does not support the methods' do
23
- expect {
24
- described_class.new(nil)
25
- }.to raise_error(ZipTricks::Streamer::InvalidOutput)
26
- end
27
-
28
- it 'allows the writer to be injectable' do
29
- fake_writer = double('ZipWriter')
30
- expect(fake_writer).to receive(:write_local_file_header)
31
- expect(fake_writer).to receive(:write_data_descriptor)
32
- expect(fake_writer).to receive(:write_central_directory_file_header)
33
- expect(fake_writer).to receive(:write_end_of_central_directory)
34
-
35
- described_class.open('', writer: fake_writer) do |zip|
36
- zip.write_deflated_file('stored.txt') do |sink|
37
- sink << File.read(__dir__ + '/war-and-peace.txt')
38
- end
39
- end
40
- end
41
-
42
- it 'returns the position in the IO at every call' do
43
- io = StringIO.new
44
- zip = described_class.new(io)
45
- pos = zip.add_compressed_entry(filename: 'file.jpg', uncompressed_size: 182919, compressed_size: 8912, crc32: 8912)
46
- expect(pos).to eq(io.tell)
47
- expect(pos).to eq(38)
48
-
49
- retval = zip << SecureRandom.random_bytes(8912)
50
- expect(retval).to eq(zip)
51
- expect(io.tell).to eq(8950)
52
-
53
- pos = zip.add_stored_entry(filename: 'filf.jpg', size: 8921, crc32: 182919)
54
- expect(pos).to eq(8988)
55
- zip << SecureRandom.random_bytes(8921)
56
- expect(io.tell).to eq(17909)
57
-
58
- pos = zip.close
59
- expect(pos).to eq(io.tell)
60
- expect(pos).to eq(18068)
61
- end
62
-
63
- it 'can write and then read the block-deflated files' do
64
- f = Tempfile.new('raw')
65
- f.binmode
66
-
67
- rewind_after(f) do
68
- f << ('A' * 1024 * 1024)
69
- f << SecureRandom.random_bytes(1248)
70
- f << ('B' * 1024 * 1024)
71
- end
72
-
73
- crc = rewind_after(f) { Zlib.crc32(f.read) }
74
-
75
- compressed_blockwise = StringIO.new
76
- rewind_after(compressed_blockwise, f) do
77
- ZipTricks::BlockDeflate.deflate_in_blocks_and_terminate(f, compressed_blockwise, block_size: 1024)
78
- end
79
-
80
- # Perform the zipping
81
- zip_file = Tempfile.new('z')
82
- zip_file.binmode
83
-
84
- described_class.open(zip_file) do |zip|
85
- zip.add_compressed_entry(filename: "compressed-file.bin", uncompressed_size: f.size,
86
- crc32: crc, compressed_size: compressed_blockwise.size)
87
- zip << compressed_blockwise.read
88
- end
89
- zip_file.flush
90
-
91
- per_filename = {}
92
- Zip::File.open(zip_file.path) do |zip_file|
93
- # Handle entries one by one
94
- zip_file.each do |entry|
95
- # The entry name gets returned with a binary encoding, we have to force it back.
96
- per_filename[entry.name] = entry.get_input_stream.read
97
- end
98
- end
99
-
100
- expect(per_filename['compressed-file.bin'].bytesize).to eq(f.size)
101
- expect(Digest::SHA1.hexdigest(per_filename['compressed-file.bin'])).to eq(Digest::SHA1.hexdigest(f.read))
102
-
103
- inspect_zip_with_external_tool(zip_file.path)
104
- end
105
-
106
- it 'creates an archive that OSX ArchiveUtility can handle' do
107
- outbuf = Tempfile.new('zip')
108
- outbuf.binmode
109
-
110
- zip = ZipTricks::Streamer.new(outbuf)
111
-
112
- File.open(test_text_file_path, 'rb') do | source_f |
113
- crc32 = rewind_after(source_f) { Zlib.crc32(source_f.read) }
114
-
115
- compressed_buffer = StringIO.new
116
-
117
- expect(ZipTricks::BlockDeflate).to receive(:deflate_chunk).at_least(:twice).and_call_original
118
-
119
- # Compress in blocks of 4 Kb
120
- rewind_after(source_f, compressed_buffer) do
121
- ZipTricks::BlockDeflate.deflate_in_blocks_and_terminate(source_f, compressed_buffer, block_size: 1024 * 4)
122
- end
123
-
124
- # Add this file compressed...
125
- zip.add_compressed_entry(filename: 'war-and-peace.txt', uncompressed_size: source_f.size,
126
- crc32: crc32, compressed_size: compressed_buffer.size)
127
- zip << compressed_buffer.string
128
-
129
- # ...and stored.
130
- zip.add_stored_entry(filename: 'war-and-peace-raw.txt', size: source_f.size, crc32: crc32)
131
- zip << source_f.read
132
-
133
- zip.close
134
-
135
- outbuf.flush
136
- File.unlink('test.zip') rescue nil
137
- File.rename(outbuf.path, 'osx-archive-test.zip')
138
-
139
- # Mark this test as skipped if the system does not have the binary
140
- open_zip_with_archive_utility('osx-archive-test.zip', skip_if_missing: true)
141
- end
142
- FileUtils.rm_rf('osx-archive-test')
143
- FileUtils.rm_rf('osx-archive-test.zip')
144
- end
145
-
146
- it 'archives files which can then be read using the usual means with Rubyzip' do
147
- zip_buf = Tempfile.new('zipp')
148
- zip_buf.binmode
149
- output_io = double('IO')
150
-
151
- # Only allow the methods we provide in BlockWrite.
152
- # Will raise an error if other methods are triggered (the ones that
153
- # might try to rewind the IO).
154
- allow(output_io).to receive(:<<) {|data|
155
- zip_buf << data.to_s.force_encoding(Encoding::BINARY)
156
- }
157
-
158
- allow(output_io).to receive(:tell) { zip_buf.tell }
159
- allow(output_io).to receive(:pos) { zip_buf.pos }
160
- allow(output_io).to receive(:close)
161
-
162
- # Generate a couple of random files
163
- raw_file_1 = SecureRandom.random_bytes(1024 * 20)
164
- raw_file_2 = SecureRandom.random_bytes(1024 * 128)
165
-
166
- # Perform the zipping
167
- zip = described_class.new(output_io)
168
- zip.add_stored_entry(filename: "first-file.bin", size: raw_file_1.size, crc32: Zlib.crc32(raw_file_1))
169
- zip << raw_file_1
170
- zip.add_stored_entry(filename: "second-file.bin", size: raw_file_2.size, crc32: Zlib.crc32(raw_file_2))
171
- zip << raw_file_2
172
- zip.close
173
-
174
- zip_buf.flush
175
-
176
- per_filename = {}
177
- Zip::File.open(zip_buf.path) do |zip_file|
178
- # Handle entries one by one
179
- zip_file.each do |entry|
180
- # The entry name gets returned with a binary encoding, we have to force it back.
181
- # Somehow an empty string gets read
182
- per_filename[entry.name] = entry.get_input_stream.read
183
- end
184
- end
185
-
186
- expect(per_filename['first-file.bin'].unpack("C*")).to eq(raw_file_1.unpack("C*"))
187
- expect(per_filename['second-file.bin'].unpack("C*")).to eq(raw_file_2.unpack("C*"))
188
-
189
- wd = Dir.pwd
190
- Dir.mktmpdir do | td |
191
- Dir.chdir(td)
192
- inspect_zip_with_external_tool(zip_buf.path)
193
- end
194
- Dir.chdir(wd)
195
- end
196
-
197
- it 'sets the general-purpose flag for entries with UTF8 names' do
198
- zip_buf = Tempfile.new('zipp')
199
- zip_buf.binmode
200
-
201
- # Generate a couple of random files
202
- raw_file_1 = SecureRandom.random_bytes(1024 * 20)
203
- raw_file_2 = SecureRandom.random_bytes(1024 * 128)
204
-
205
- # Perform the zipping
206
- zip = described_class.new(zip_buf)
207
- zip.add_stored_entry(filename: "first-file.bin", size: raw_file_1.size, crc32: Zlib.crc32(raw_file_1))
208
- zip << raw_file_1
209
- zip.add_stored_entry(filename: "второй-файл.bin", size: raw_file_2.size, crc32: Zlib.crc32(raw_file_2))
210
- IO.copy_stream(StringIO.new(raw_file_2), zip)
211
- zip.close
212
-
213
- zip_buf.flush
214
-
215
- entries = []
216
- Zip::File.open(zip_buf.path) do |zip_file|
217
- # Handle entries one by one
218
- zip_file.each {|entry| entries << entry }
219
- first_entry, second_entry = entries
220
-
221
- expect(first_entry.gp_flags).to eq(0)
222
- expect(first_entry.name).to eq('first-file.bin')
223
-
224
- # Rubyzip does not properly set the encoding of the entries it reads
225
- expect(second_entry.gp_flags).to eq(2048)
226
- expect(second_entry.name).to eq("второй-файл.bin".force_encoding(Encoding::BINARY))
227
- end
228
- end
229
-
230
- it 'creates an archive with data descriptors that can be opened by Rubyzip, with a small number of very tiny text files' do
231
- tf = ManagedTempfile.new('zip')
232
- z = described_class.open(tf) do |zip|
233
- zip.write_stored_file('deflated.txt') do |sink|
234
- sink << File.read(__dir__ + '/war-and-peace.txt')
235
- end
236
- zip.write_deflated_file('stored.txt') do |sink|
237
- sink << File.read(__dir__ + '/war-and-peace.txt')
238
- end
239
- end
240
- tf.flush
241
-
242
- pending 'https://github.com/rubyzip/rubyzip/issues/295'
243
-
244
- Zip::File.foreach(tf.path) do |entry|
245
- # Make sure it is tagged as UNIX
246
- expect(entry.fstype).to eq(3)
247
-
248
- # The CRC
249
- expect(entry.crc).to eq(Zlib.crc32(File.read(__dir__ + '/war-and-peace.txt')))
250
-
251
- # Check the name
252
- expect(entry.name).to match(/\.txt$/)
253
-
254
- # Check the right external attributes (non-executable on UNIX)
255
- expect(entry.external_file_attributes).to eq(2175008768)
256
-
257
- # Check the file contents
258
- readback = entry.get_input_stream.read
259
- readback.force_encoding(Encoding::BINARY)
260
- expect(readback[0..10]).to eq(File.read(__dir__ + '/war-and-peace.txt')[0..10])
261
- end
262
-
263
- inspect_zip_with_external_tool(tf.path)
264
- end
265
-
266
- it 'can create a valid ZIP archive without any files' do
267
- tf = ManagedTempfile.new('zip')
268
-
269
- described_class.open(tf) do |zip|
270
- end
271
-
272
- tf.flush
273
- tf.rewind
274
-
275
- expect { |b|
276
- Zip::File.foreach(tf.path, &b)
277
- }.not_to yield_control
278
- end
279
-
280
- it 'prevents duplicates in the stored files' do
281
- files = ["README", "README", "file.one\\two.jpg", "file_one.jpg", "file_one (1).jpg",
282
- "file\\one.jpg", "My.Super.file.txt.zip", "My.Super.file.txt.zip"]
283
- fake_writer = double('Writer').as_null_object
284
- seen_filenames = []
285
- allow(fake_writer).to receive(:write_local_file_header) {|filename:, **others|
286
- seen_filenames << filename
287
- }
288
- zip_streamer = described_class.new(StringIO.new, writer: fake_writer)
289
- files.each do |fn|
290
- zip_streamer.add_stored_entry(filename: fn, size: 1024, crc32: 0xCC)
291
- end
292
- expect(seen_filenames).to eq(["README", "README (1)", "file.one_two.jpg", "file_one.jpg",
293
- "file_one (1).jpg", "file_one (2).jpg", "My.Super.file.txt.zip",
294
- "My.Super.file (1).txt.zip"])
295
- end
296
- end