zip_tricks 4.2.3 → 4.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +53 -0
- data/Gemfile +3 -13
- data/README.md +36 -0
- data/Rakefile +3 -48
- data/lib/zip_tricks.rb +0 -2
- data/lib/zip_tricks/block_deflate.rb +2 -0
- data/lib/zip_tricks/version.rb +3 -0
- data/lib/zip_tricks/zip_writer.rb +59 -13
- data/testing/README_TESTING.md +12 -0
- data/testing/generate_test_files.rb +86 -0
- data/testing/in/VTYL8830.jpg +0 -0
- data/{spec/zip_tricks → testing/in}/war-and-peace.txt +0 -0
- data/testing/support.rb +83 -0
- data/testing/test-report-2016-07-28.txt +156 -0
- data/testing/test-report-2016-12-12.txt +156 -0
- data/testing/test-report.txt +28 -0
- data/zip_tricks.gemspec +36 -109
- metadata +40 -65
- data/spec/spec_helper.rb +0 -91
- data/spec/zip_tricks/block_deflate_spec.rb +0 -111
- data/spec/zip_tricks/block_write_spec.rb +0 -95
- data/spec/zip_tricks/cdir_entry_with_partial_use_of_zip64_extra_fields.bin +0 -0
- data/spec/zip_tricks/file_reader_spec.rb +0 -287
- data/spec/zip_tricks/rack_body_spec.rb +0 -34
- data/spec/zip_tricks/remote_io_spec.rb +0 -125
- data/spec/zip_tricks/remote_uncap_spec.rb +0 -100
- data/spec/zip_tricks/size_estimator_spec.rb +0 -31
- data/spec/zip_tricks/stream_crc32_spec.rb +0 -38
- data/spec/zip_tricks/streamer/writable_spec.rb +0 -27
- data/spec/zip_tricks/streamer_spec.rb +0 -296
- data/spec/zip_tricks/write_and_tell_spec.rb +0 -43
- data/spec/zip_tricks/zip_writer_spec.rb +0 -419
@@ -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
|