zippo 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +22 -0
  7. data/README.md +83 -0
  8. data/Rakefile +11 -0
  9. data/lib/zippo/binary_structure/base.rb +119 -0
  10. data/lib/zippo/binary_structure/binary_packer.rb +17 -0
  11. data/lib/zippo/binary_structure/binary_unpacker.rb +32 -0
  12. data/lib/zippo/binary_structure/meta.rb +146 -0
  13. data/lib/zippo/binary_structure/structure.rb +24 -0
  14. data/lib/zippo/binary_structure/structure_member.rb +31 -0
  15. data/lib/zippo/binary_structure.rb +6 -0
  16. data/lib/zippo/cd_file_header.rb +36 -0
  17. data/lib/zippo/central_directory_entries_unpacker.rb +23 -0
  18. data/lib/zippo/central_directory_reader.rb +44 -0
  19. data/lib/zippo/end_cd_record.rb +21 -0
  20. data/lib/zippo/filter/base.rb +29 -0
  21. data/lib/zippo/filter/compressor/deflate.rb +23 -0
  22. data/lib/zippo/filter/compressor/store.rb +12 -0
  23. data/lib/zippo/filter/compressor.rb +42 -0
  24. data/lib/zippo/filter/compressors.rb +3 -0
  25. data/lib/zippo/filter/null_filters.rb +15 -0
  26. data/lib/zippo/filter/uncompressor/deflate.rb +25 -0
  27. data/lib/zippo/filter/uncompressor/store.rb +12 -0
  28. data/lib/zippo/filter/uncompressor.rb +59 -0
  29. data/lib/zippo/filter/uncompressors.rb +3 -0
  30. data/lib/zippo/io_zip_member.rb +24 -0
  31. data/lib/zippo/local_file_header.rb +28 -0
  32. data/lib/zippo/version.rb +3 -0
  33. data/lib/zippo/zip_directory.rb +80 -0
  34. data/lib/zippo/zip_file.rb +121 -0
  35. data/lib/zippo/zip_file_writer.rb +57 -0
  36. data/lib/zippo/zip_member.rb +85 -0
  37. data/lib/zippo.rb +18 -0
  38. data/spec/binary_structure_spec.rb +132 -0
  39. data/spec/central_directory_entries_unpacker_spec.rb +29 -0
  40. data/spec/central_directory_parser_spec.rb +50 -0
  41. data/spec/central_directory_unpacker_spec.rb +31 -0
  42. data/spec/compressor_spec.rb +14 -0
  43. data/spec/data/comment.zip +0 -0
  44. data/spec/data/deflate.zip +0 -0
  45. data/spec/data/multi.zip +0 -0
  46. data/spec/data/not_a.zip +1 -0
  47. data/spec/data/test.zip +0 -0
  48. data/spec/deflate_compressor_spec.rb +21 -0
  49. data/spec/deflate_uncompressor_spec.rb +23 -0
  50. data/spec/integration/compressors_spec.rb +21 -0
  51. data/spec/integration/zippo_spec.rb +55 -0
  52. data/spec/io_zip_member_spec.rb +32 -0
  53. data/spec/local_file_header_spec.rb +18 -0
  54. data/spec/spec_helper.rb +12 -0
  55. data/spec/store_compressor_spec.rb +19 -0
  56. data/spec/store_uncompressor_spec.rb +19 -0
  57. data/spec/uncompressor_spec.rb +14 -0
  58. data/spec/zip_directory_spec.rb +63 -0
  59. data/spec/zip_file_spec.rb +50 -0
  60. data/spec/zip_file_writer_spec.rb +42 -0
  61. data/spec/zip_member_spec.rb +42 -0
  62. data/yard_extensions.rb +10 -0
  63. data/zippo.gemspec +23 -0
  64. metadata +163 -0
@@ -0,0 +1,132 @@
1
+ require "spec_helper"
2
+
3
+ # TODO - spec that unpackers can take strings
4
+
5
+ require 'zippo/binary_structure'
6
+
7
+ module Zippo
8
+ describe BinaryStructure do
9
+ let(:klass) { Class.new }
10
+ let(:obj) { klass.new }
11
+ let(:unpacker) { klass::Unpacker }
12
+ before(:each) do
13
+ klass.send :extend, BinaryStructure
14
+ end
15
+ context "when used to configure a class as a binary structure" do
16
+ before(:each) do
17
+ klass.class_eval do
18
+ binary_structure do
19
+ field :foo, 'L'
20
+ field :yay, 'a4', :signature => "baz"
21
+ field :bar, 'S'
22
+ field :quux, 'a*', :size => :foo
23
+ end
24
+ end
25
+ end
26
+ it "should store field information in the class" do
27
+ klass.structure.should have(4).fields
28
+ klass.structure.fields[0].name.should eq :foo
29
+ klass.structure.fields[3].options[:size].should eq :foo
30
+ klass.structure.fields[1].should be_signature
31
+ end
32
+ it "should have dependent fields" do
33
+ obj.quux = "foobar"
34
+ obj.foo.should eq 6
35
+ obj.quux.should eq "foobar"
36
+ end
37
+ it "should not allow mutation of dependent fields" do
38
+ -> { obj.foo = 5 }.should raise_error
39
+ end
40
+ it "should have regular fields" do
41
+ obj.bar = 10
42
+ obj.bar.should eq 10
43
+ end
44
+ it "should have an unpacker" do
45
+ array = [10,"baz", 42,"foobar baz"]
46
+ packed = array.pack 'La4Sa*'
47
+ io = StringIO.new packed
48
+ obj = klass::Unpacker.new(io).unpack
49
+ obj.foo.should eq 10
50
+ obj.bar.should eq 42
51
+ obj.quux.should eq "foobar baz"
52
+ end
53
+ it "should unpack oversized strings correctly" do
54
+ array = [3,"baz", 42,"foobar baz"]
55
+ packed = array.pack 'La4Sa*'
56
+ io = StringIO.new packed
57
+ obj = klass::Unpacker.new(io).unpack
58
+ obj.quux.should eq "foo"
59
+ end
60
+ it "should have a packer" do
61
+ array = [10,"baz", 42,"foobar baz"]
62
+ packed = array.pack 'La4Sa*'
63
+ io = StringIO.new
64
+ obj.bar = 42
65
+ obj.yay = "baz"
66
+ obj.quux = "foobar baz"
67
+ klass::Packer.new(io).pack obj
68
+ io.string.should eq packed
69
+ end
70
+ it "should have a .size method" do
71
+ obj.bar = 42
72
+ obj.quux = "foobar baz"
73
+ obj.size.should eq 20
74
+ end
75
+ context "when there is another class" do
76
+ let(:other_klass) { Class.new }
77
+ before(:each) do
78
+ other_klass.send :extend, BinaryStructure
79
+ other_klass.class_eval do
80
+ binary_structure do
81
+ field :bar, 'S'
82
+ field :yay, 'a4', :signature => "quux"
83
+ end
84
+ end
85
+ end
86
+ describe ".convert_to" do
87
+ it "should convert to the other class" do
88
+ obj.quux = "foobar"
89
+ obj.bar = 5
90
+ other_obj = obj.convert_to other_klass
91
+ other_obj.bar.should eq 5
92
+ end
93
+ it "should not convert a signature" do
94
+ obj.quux = "foobar"
95
+ obj.bar = 5
96
+ obj.yay = "baz"
97
+ other_obj = obj.convert_to other_klass
98
+ other_obj.bar.should eq 5
99
+ other_obj.yay.should eq "quux"
100
+ end
101
+ end
102
+ end
103
+ end
104
+ pending "should handle binary structures with multiple lots of fixed fields interspersed with variable length fields"
105
+ # none of the current binary structures use a
106
+ # feature like this, they're all a bunch of fixed
107
+ # fields followed by some variable length fields.
108
+ # need to test a few fixed fields, followed by a
109
+ # variable length field, then a few more fixed
110
+ # fields
111
+ =begin
112
+ it "should complain if the order is bad" do
113
+ pending
114
+ klass = Class.new BinaryStructure
115
+ lambda { klass.class_eval do
116
+ field :foo, 'S'
117
+ field :bar, 'a*', :size => :baz
118
+ field :baz, 'S'
119
+ end }.should raise_error "size not found"
120
+ end
121
+ it "should remain silent if the order is ok" do
122
+ pending
123
+ klass = Class.new BinaryStructure
124
+ lambda { klass.class_eval do
125
+ field :foo, 'S'
126
+ field :baz, 'S'
127
+ field :bar, 'a*', :size => :baz
128
+ end }.should_not raise_error
129
+ end
130
+ =end
131
+ end
132
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/central_directory_entries_unpacker"
4
+
5
+ module Zippo
6
+ describe CentralDirectoryEntriesUnpacker do
7
+ subject { CentralDirectoryEntriesUnpacker.new(io, size, offset).unpack }
8
+
9
+ context "when it's a simple file" do
10
+ let(:io) { File.open(test_file "test.zip") }
11
+ let(:offset) { 112 }
12
+ let(:size) { 79 }
13
+
14
+ specify { subject.should have(1).items }
15
+ specify { subject.first.name.should eq "test.file" }
16
+ end
17
+
18
+ context "when it's a complex file" do
19
+ let(:io) { File.open(test_file "multi.zip") }
20
+ let(:offset) { 242 }
21
+ let(:size) { 158 }
22
+
23
+ specify { subject.should have(2).items }
24
+ specify { subject[0].name.should eq "test.file" }
25
+ specify { subject[1].name.should eq "other.test" }
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/central_directory_reader"
4
+ require "zippo/zip_file"
5
+
6
+ module Zippo
7
+ describe CentralDirectoryReader do
8
+ let(:io) { File.open(file, "rb:ASCII-8BIT") }
9
+ let(:file) { test_file "test.zip" }
10
+ let(:parser) { CentralDirectoryReader.new(io) }
11
+ after(:each) { io.close }
12
+
13
+ context "when parsing a simple file" do
14
+ let(:file) { test_file "test.zip" }
15
+ it "should parse the End of Central Directory Record" do
16
+ parser.end_of_cd_record.total_records.should eq 1
17
+ end
18
+
19
+ specify { parser.end_of_cd_record_position.should eq 0xbf }
20
+ specify { parser.should have(1).cd_file_headers }
21
+ end
22
+
23
+ context "when parsing a file with a comment" do
24
+ let(:file) { test_file "comment.zip" }
25
+ specify { parser.end_of_cd_record_position.should eq 0xbf }
26
+ specify { parser.end_of_cd_record.comment.should eq "this is a comment to make things tricky" }
27
+ end
28
+
29
+ context "when parsing a multi-entry file" do
30
+ let(:file) { test_file "multi.zip" }
31
+ specify { parser.end_of_cd_record_position.should eq 0x191 }
32
+ end
33
+
34
+ context "when parsing a file that is not a zip" do
35
+ let(:file) { test_file "not_a.zip" }
36
+ specify { -> {parser.end_of_cd_record_position}.should raise_error(/not found/) }
37
+ end
38
+
39
+ context "when parsing a zip file larger than the maximum comment size" do
40
+ it "should not barf" do
41
+ in_working_directory do
42
+ Zippo::ZipFile.open("large.zip", "w") do |v|
43
+ v["test.file"] = "a" * 65535
44
+ end
45
+ Zippo::ZipFile.open("large.zip") {|v| v["test.file"].read }.should eq "a" * 65535
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/end_cd_record"
4
+
5
+ module Zippo
6
+ describe "EndCdRecord::Unpacker" do
7
+ subject { EndCdRecord::Unpacker.new(str).unpack }
8
+
9
+ context "when it's a simple file" do
10
+ let(:str) { File.binread(test_file("test.zip"))[-22..-1] }
11
+
12
+ specify { subject.comment.should eq "" }
13
+ specify { subject.total_records.should eq 1 }
14
+ specify { subject.cd_offset.should eq 112 }
15
+ end
16
+
17
+ context "when it's a multi entry file" do
18
+ let(:str) { File.binread(test_file("multi.zip"))[-22..-1] }
19
+
20
+ specify { subject.total_records.should eq 2 }
21
+ end
22
+
23
+ context "when there is a comment" do
24
+ let(:str) { File.binread(test_file("comment.zip"))[-61..-1] }
25
+
26
+ specify { subject.total_records.should eq 1 }
27
+ specify { subject.comment.should eq "this is a comment to make things tricky" }
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/filter/compressor"
4
+ require "zippo/filter/compressors"
5
+
6
+ module Zippo::Filter
7
+ describe Compressor do
8
+ it "should be a factory for compressors" do
9
+ Compressor.for(StoreCompressor::METHOD).should eq StoreCompressor
10
+ Compressor.for(DeflateCompressor::METHOD).should eq DeflateCompressor
11
+ -> { Compressor.for(113) }.should raise_error(/unknown compression method/)
12
+ end
13
+ end
14
+ end
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ this is not a zip file
Binary file
@@ -0,0 +1,21 @@
1
+ # Encoding: BINARY
2
+ require "spec_helper"
3
+
4
+ require "zippo/filter/compressor/deflate"
5
+
6
+ module Zippo::Filter
7
+ describe DeflateCompressor do
8
+ let (:data) { "a" * 20 }
9
+ let (:zdata) { "KL\xC4\u0004\u0000" }
10
+ let (:io) { StringIO.new data }
11
+ let (:out) { StringIO.new "" }
12
+ it "should write the data" do
13
+ compressor = DeflateCompressor.new(io)
14
+ csize, size, crc32 = compressor.compress_to out
15
+ size.should eq 20
16
+ csize.should eq zdata.size
17
+ crc32.should eq Zlib.crc32(data)
18
+ out.string.should eq zdata
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/filter/uncompressor/deflate"
4
+
5
+ module Zippo::Filter
6
+ describe DeflateUncompressor do
7
+
8
+ let (:zstring) { Zlib::Deflate.new(Zlib::BEST_COMPRESSION, -Zlib::MAX_WBITS).deflate("a" * 20, Zlib::FINISH) }
9
+ let (:size) { zstring.size }
10
+ let (:string) { "aaa" + zstring + "bbb" }
11
+ let (:out) { StringIO.new }
12
+ let (:io) { StringIO.new string }
13
+ it "should deflate only the compressed string" do
14
+ io.seek 3
15
+ DeflateUncompressor.new(io, size).uncompress.should eq "a" * 20
16
+ end
17
+ it "should deflate to an IO" do
18
+ io.seek 3
19
+ DeflateUncompressor.new(io, size).uncompress_to(out)
20
+ out.string.should eq "a" * 20
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/filter/uncompressor"
4
+ require "zippo/filter/uncompressors"
5
+ require "zippo/filter/compressor"
6
+ require 'zippo/filter/compressors'
7
+
8
+ module Zippo::Filter
9
+ describe Uncompressor do
10
+ let (:zstring) { Zlib::Deflate.new(Zlib::BEST_COMPRESSION, -Zlib::MAX_WBITS).deflate("a" * 20, Zlib::FINISH) }
11
+ it "should allow uncompressors to work with compressors" do
12
+ stream = StringIO.new zstring
13
+ deflater = DeflateUncompressor.new(stream, zstring.size)
14
+ storer = StoreCompressor.new(deflater)
15
+ out = StringIO.new
16
+ out.set_encoding "BINARY"
17
+ storer.compress_to(out)
18
+ out.string.should eq "a" * 20
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,55 @@
1
+ # Encoding: BINARY
2
+ require 'spec_helper'
3
+
4
+ require 'zippo'
5
+
6
+ module Zippo
7
+ describe ZipFile do
8
+ let(:file) { test_file "test.zip" }
9
+ let(:member_data) { "The quick brown fox jumps over the lazy dog.\n" }
10
+ let(:zip) { Zippo::ZipFile.open(file) }
11
+ describe "when reading a zip file" do
12
+ after(:each) do
13
+ zip.close
14
+ end
15
+ it "should be able to read a member of the file" do
16
+ data = zip["test.file"].read
17
+ data.should eq member_data
18
+ end
19
+
20
+ it "should read a compressed file" do
21
+ zip = Zippo::ZipFile.open(test_file("deflate.zip"))
22
+ zip["weasels.txt"].read.should eq "Methinks it is like a weasel.\n" * 10
23
+ end
24
+
25
+ it "should work like File.open" do
26
+ io = File.open(file)
27
+ File.should_receive(:open).with(file, 'r:ASCII-8BIT').and_return(io)
28
+ s = Zippo.open(file) { |v| v['test.file'].read }
29
+ s.should eq member_data
30
+ io.should be_closed
31
+ end
32
+
33
+ it "should create zip files" do
34
+ in_working_directory do
35
+ File.write "xyzzy.txt", "plugh"
36
+ Zippo.open("new.zip", "w") {|v| v['xyzzy.txt'] = "plugh" }
37
+ Pathname.new("new.zip").should exist
38
+ Zippo.open("new.zip") {|v| v['xyzzy.txt'].read }.should eq "plugh"
39
+ end
40
+ end
41
+
42
+ it "should update in place with mode rw" do
43
+ in_working_directory do
44
+ Zippo.open("out.zip", "w") { |v| v['foo1'] = "data1" }
45
+ Zippo.open("out.zip", "rw") { |v| v['foo2'] = "data2" }
46
+ IO.write "/tmp/bar.zip", IO.read("out.zip")
47
+ Zippo.open("out.zip") do |v|
48
+ v['foo1'].read.should eq "data1"
49
+ v['foo2'].read.should eq "data2"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/io_zip_member"
4
+ require "zippo/filter/compressor/store"
5
+
6
+ module Zippo
7
+ describe IOZipMember do
8
+ let(:io) { StringIO.new "foobar" }
9
+ let(:out) { StringIO.new "" }
10
+ let(:name) { "name" }
11
+ subject { IOZipMember.new name, io }
12
+ specify { subject.name.should eq "name" }
13
+ specify { subject.read.should eq "foobar" }
14
+ context "when writing" do
15
+ before(:each) do
16
+ @size, @csize, @crc32 = subject.write_to out, 0
17
+ end
18
+ it "should write to the io" do
19
+ out.string.should eq "foobar"
20
+ end
21
+ it "should have returned the original size" do
22
+ @size.should eq 6
23
+ end
24
+ it "should return the compressed size" do
25
+ @csize.should eq 6
26
+ end
27
+ it "should return the CRC32" do
28
+ @crc32.should eq Zlib.crc32("foobar")
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/local_file_header"
4
+
5
+ module Zippo
6
+ describe "LocalFileHeader::Unpacker" do
7
+ before(:each) do
8
+ @io = File.open test_file("test.zip"), "rb:ASCII-8BIT"
9
+ @io.seek 0
10
+ end
11
+ after(:each) do
12
+ @io.close
13
+ end
14
+ it "should unpack from an io" do
15
+ LocalFileHeader::Unpacker.new(@io.read).unpack.name.should eq "test.file"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ def io_for(filename)
2
+ File.open test_file(filename), "rb:ASCII-8BIT"
3
+ end
4
+ def test_file(filename)
5
+ File.join(File.join(File.dirname(__FILE__), 'data'), filename)
6
+ end
7
+ require 'tmpdir'
8
+ def in_working_directory
9
+ Dir.mktmpdir do |dir|
10
+ Dir.chdir(dir) { yield }
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/filter/compressor/store"
4
+
5
+ module Zippo::Filter
6
+ describe StoreCompressor do
7
+ let (:data) { "a" * 20 }
8
+ let (:io) { StringIO.new data }
9
+ let (:out) { StringIO.new }
10
+ it "should write the data" do
11
+ compressor = StoreCompressor.new(io)
12
+ size, csize, crc32 = compressor.compress_to out
13
+ size.should eq 20
14
+ csize.should eq 20
15
+ crc32.should eq Zlib.crc32(data)
16
+ out.string.should eq data
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/filter/uncompressor/store"
4
+
5
+ module Zippo::Filter
6
+ describe StoreUncompressor do
7
+ let(:io) { StringIO.new "foobarbazquux" }
8
+ let (:out) { StringIO.new }
9
+ it "should read only the specified amount" do
10
+ io.seek 3
11
+ StoreUncompressor.new(io, 3).uncompress.should eq "bar"
12
+ end
13
+ it "should deflate to an IO" do
14
+ io.seek 3
15
+ StoreUncompressor.new(io, 3).uncompress_to(out)
16
+ out.string.should eq "bar"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/filter/uncompressor"
4
+ require "zippo/filter/uncompressors"
5
+
6
+ module Zippo::Filter
7
+ describe Uncompressor do
8
+ it "should be a factory for uncompressors" do
9
+ Uncompressor.for(0).should eq StoreUncompressor
10
+ Uncompressor.for(8).should eq DeflateUncompressor
11
+ -> { Uncompressor.for(113) }.should raise_error(/unknown compression method/)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ require 'zippo/zip_file'
4
+
5
+ module Zippo
6
+ describe ZipDirectory do
7
+ context "when opening a file" do
8
+ let(:io) { File.open(file, "rb:ASCII-8BIT") }
9
+ after(:each) { io.close }
10
+ subject { ZipDirectory.new io }
11
+ context "when reading a simple file" do
12
+ let(:file) { test_file "test.zip" }
13
+ it { should have(1).entries }
14
+ specify { subject["test.file"].should_not be_nil }
15
+ it { should_not be_empty }
16
+ end
17
+ context "when reading a larger zip" do
18
+ let(:file) { test_file "multi.zip" }
19
+ it { should have(2).entries }
20
+ specify { subject["test.file"].should_not be_nil }
21
+ specify { subject["other.test"].should_not be_nil }
22
+ end
23
+ end
24
+ context "when inserting" do
25
+ let(:io) { StringIO.new "" }
26
+ it "should allow the insertion of new members" do
27
+ subject["new.file"] = "file data"
28
+ subject["new.file"].read.should eq "file data"
29
+ subject["new.file"].write_to io, 0
30
+ io.string.should eq "file data"
31
+ end
32
+ it "should allow the insertion of IO objects" do
33
+ in_working_directory do
34
+ File.write "xyzzy.txt", "plugh"
35
+ file = File.open "xyzzy.txt"
36
+ subject.insert "woo.txt", file
37
+ subject["woo.txt"].read.should eq "plugh"
38
+ subject["woo.txt"].write_to io, 0
39
+ file.close
40
+ io.string.should eq "plugh"
41
+ end
42
+ end
43
+ it "should allow insertion of file contents" do
44
+ in_working_directory do
45
+ File.write "xyzzy.txt", "plugh"
46
+ subject.insert "woo.txt", "xyzzy.txt"
47
+ subject["woo.txt"].read.should eq "plugh"
48
+ subject["woo.txt"].write_to io, 0
49
+ io.string.should eq "plugh"
50
+ end
51
+ end
52
+ it "should allow the insertion of ZipMember contents" do
53
+ zip = Zippo::ZipFile.open test_file "test.zip"
54
+ subject.insert "hmm.txt", zip['test.file']
55
+ subject["hmm.txt"].read.should eq "The quick brown fox jumps over the lazy dog.\n"
56
+ subject["hmm.txt"].write_to io, 0
57
+ zip.close
58
+ io.string.should eq "The quick brown fox jumps over the lazy dog.\n"
59
+ -> { subject["hmm.txt"].read }.should raise_error # after closing original zip
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo/zip_file"
4
+ require "zippo/filter/uncompressors"
5
+ require "zippo/filter/compressors"
6
+
7
+ module Zippo
8
+ describe ZipFile do
9
+ # XXX unit test for open
10
+ describe ".open" do
11
+ let(:zip) { ZipFile.open(file, mode) }
12
+ let(:file) { test_file "test.zip" }
13
+ context "when in read mode" do
14
+ let(:mode) { "r" }
15
+ it "should allow reading of zip members" do
16
+ zip['test.file'].should be_a ZipMember
17
+ zip['test.file'].read.should eq "The quick brown fox jumps over the lazy dog.\n"
18
+ end
19
+ it "should allow iterating over the directory" do
20
+ files = []
21
+ zip.each { |m| files << m.name }
22
+ files.should include("test.file")
23
+ end
24
+ end
25
+ context "when in write mode" do
26
+ let(:mode) { "w" }
27
+ let(:file) { "/tmp/foo.zip" }
28
+ it "should not allow reading of zip members that haven't been written" do
29
+ zip['test.file'].should be_nil
30
+ end
31
+ context "when a member is inserted" do
32
+ before(:each) do
33
+ zip['new.file'] = "foo"
34
+ end
35
+ it "should write the file when closed" do
36
+ zip.close
37
+ Pathname.new(file).should exist
38
+ Zippo::ZipFile.open(file) {|f| f["new.file"].read }.should eq "foo"
39
+ end
40
+ end
41
+ end
42
+ context "when in update mode" do
43
+ let(:mode) { "rw" }
44
+ it "should read the zip file" do
45
+ zip.directory.should_not be_empty
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ require "spec_helper"
2
+
3
+ require "zippo" #
4
+ require "zippo/zip_file_writer"
5
+ require "zippo/zip_directory"
6
+
7
+ module Zippo
8
+ describe ZipFileWriter do
9
+ describe ".write" do
10
+ it "should write the zip file" do
11
+ in_working_directory do
12
+ directory = ZipDirectory.new
13
+ directory["file.ext"] = "foo"
14
+ writer = ZipFileWriter.new directory, "out.zip"
15
+ writer.write
16
+ File.open("/home/jma/yay.zip","w") {|f| f.write File.read("out.zip") }
17
+ Zippo.open("out.zip") do |f|
18
+ f['file.ext'].crc32.should eq 0x8c736521
19
+ f['file.ext'].compressed_size.should eq 5
20
+ f['file.ext'].uncompressed_size.should eq 3
21
+ f['file.ext'].read.should eq "foo"
22
+ end
23
+ end
24
+ end
25
+ it "should perform direct zip copying" do
26
+ in_working_directory do
27
+ zip = Zippo.open(test_file "test.zip")
28
+ Zippo.open("out.zip", "w") do |out|
29
+ out.directory.insert 'out.file', zip['test.file']
30
+ end
31
+ zip.close
32
+
33
+ IO.write "/tmp/out.zip", IO.read("out.zip")
34
+
35
+ Zippo.open("out.zip") { |v| v['out.file'].read }.should eq "The quick brown fox jumps over the lazy dog.\n"
36
+ end
37
+ end
38
+ pending "should be able to peform direct zip copying after the source zip is closed"
39
+ pending "should be configurable in terms of compression method and effort"
40
+ end
41
+ end
42
+ end