zippo 0.2.0

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.
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