zip-container 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,88 @@
1
+ # Copyright (c) 2013 The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ require 'zip/zip_entry'
34
+
35
+ module ZipContainer
36
+
37
+ # This module provides support for reserved names.
38
+ module ReservedNames
39
+
40
+ # :call-seq:
41
+ # reserved_names -> Array
42
+ #
43
+ # Return a list of reserved file and directory names for this ZipContainer
44
+ # file.
45
+ #
46
+ # Reserved files and directories must be accessed directly by methods
47
+ # within Container (or subclasses of Container). This is because they are
48
+ # fundamental to the format and might need to exhibit certain properties
49
+ # (such as no compression) that must be preserved. The "mimetype" file is
50
+ # an example of such a reserved entry.
51
+ #
52
+ # To add a reserved name to a subclass of Container simply add it to the
53
+ # list in the constructor (you must call the super constructor first!):
54
+ #
55
+ # class MyContainer < ZipContainer::Container
56
+ # def initialize(filename)
57
+ # super(filename)
58
+ #
59
+ # register_reserved_name("my_reserved_name")
60
+ # end
61
+ # end
62
+ def reserved_names
63
+ @reserved_names ||= []
64
+ end
65
+
66
+ # :call-seq:
67
+ # reserved_entry?(entry) -> boolean
68
+ #
69
+ # Is the given entry in the reserved list of names? A String or a
70
+ # Zip::ZipEntry object can be passed in here.
71
+ def reserved_entry?(entry)
72
+ name = entry.kind_of?(::Zip::ZipEntry) ? entry.name : entry
73
+ name.chop! if name.end_with? "/"
74
+ reserved_names.map { |n| n.downcase }.include? name.downcase
75
+ end
76
+
77
+ protected
78
+
79
+ # :call-seq:
80
+ # register_reserved_name(name)
81
+ #
82
+ # Add a reserved name to the list.
83
+ def register_reserved_name(name)
84
+ @reserved_names ||= []
85
+ @reserved_names << name unless @reserved_names.include? name
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,70 @@
1
+ # Copyright (c) 2013 The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ #
34
+ module ZipContainer
35
+
36
+ # The base class of all other exceptions raised by this library.
37
+ class ZipContainerError < RuntimeError
38
+ end
39
+
40
+ # This exception is raised when a bad ZipContainer is detected.
41
+ class MalformedZipContainerError < ZipContainerError
42
+
43
+ # :call-seq:
44
+ # new(reason = "")
45
+ #
46
+ # Create a new MalformedZipContainerError with an optional reason for why
47
+ # the ZipContainer file is malformed.
48
+ def initialize(reason = nil)
49
+ if reason.nil?
50
+ super("Malformed ZipContainer File.")
51
+ else
52
+ super("Malformed ZipContainer File: #{reason}")
53
+ end
54
+ end
55
+ end
56
+
57
+ # This exception is raised when a clash occurs with a reserved or managed
58
+ # name.
59
+ class ReservedNameClashError < ZipContainerError
60
+
61
+ # :call-seq:
62
+ # new(name)
63
+ #
64
+ # Create a new ReservedNameClashError with the name of the clash supplied.
65
+ def initialize(name)
66
+ super("'#{name}' is reserved for internal use in this ZipContainer file.")
67
+ end
68
+ end
69
+
70
+ end
Binary file
Binary file
File without changes
@@ -0,0 +1,140 @@
1
+ # Copyright (c) 2013 The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ require 'test/unit'
34
+ require 'tmpdir'
35
+ require 'zip-container'
36
+
37
+ class TestCreation < Test::Unit::TestCase
38
+
39
+ # Check creation of standard empty container files.
40
+ def test_create_standard_file
41
+ Dir.mktmpdir do |dir|
42
+ filename = File.join(dir, "test.container")
43
+
44
+ assert_nothing_raised do
45
+ ZipContainer::Container.create(filename, $mimetype) do |c|
46
+ assert(c.on_disk?)
47
+ refute(c.in_memory?)
48
+
49
+ assert(c.find_entry("mimetype").localHeaderOffset == 0)
50
+ end
51
+ end
52
+
53
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError, Zip::ZipError) do
54
+ ZipContainer::Container.verify!(filename)
55
+ end
56
+ end
57
+ end
58
+
59
+ # Check creation of empty container files with a different mimetype.
60
+ def test_create_mimetype_file
61
+ mimetype = "application/x-something-really-odd"
62
+
63
+ Dir.mktmpdir do |dir|
64
+ filename = File.join(dir, "test.container")
65
+
66
+ assert_nothing_raised do
67
+ ZipContainer::Container.create(filename, mimetype) do |c|
68
+ assert(c.on_disk?)
69
+ refute(c.in_memory?)
70
+
71
+ assert(c.find_entry("mimetype").localHeaderOffset == 0)
72
+ end
73
+ end
74
+
75
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError, Zip::ZipError) do
76
+ ZipContainer::Container.verify!(filename)
77
+ end
78
+ end
79
+ end
80
+
81
+ # Check creation of stuff in container files. Check the commit status a few
82
+ # times to ensure that what we expect to happen, happens.
83
+ def test_create_contents_file
84
+ Dir.mktmpdir do |dir|
85
+ filename = File.join(dir, "test.container")
86
+
87
+ assert_nothing_raised do
88
+ ZipContainer::Container.create(filename, $mimetype) do |c|
89
+ assert(c.on_disk?)
90
+ refute(c.in_memory?)
91
+
92
+ c.file.open("test.txt", "w") do |f|
93
+ f.print "testing"
94
+ end
95
+
96
+ assert(c.commit_required?)
97
+ assert(c.commit)
98
+ refute(c.commit_required?)
99
+ refute(c.commit)
100
+
101
+ c.dir.mkdir("dir1")
102
+ c.mkdir("dir2")
103
+
104
+ assert(c.commit_required?)
105
+ assert(c.commit)
106
+ refute(c.commit_required?)
107
+ refute(c.commit)
108
+
109
+ c.comment = "A comment!"
110
+
111
+ assert(c.commit_required?)
112
+ assert(c.commit)
113
+ refute(c.commit_required?)
114
+ refute(c.commit)
115
+ end
116
+ end
117
+
118
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError, Zip::ZipError) do
119
+ ZipContainer::Container.open(filename) do |c|
120
+ assert(c.on_disk?)
121
+ refute(c.in_memory?)
122
+
123
+ assert(c.file.exists?("test.txt"))
124
+ assert(c.file.exists?("dir1"))
125
+ assert(c.file.exists?("dir2"))
126
+ refute(c.file.exists?("dir3"))
127
+
128
+ text = c.file.read("test.txt")
129
+ assert_equal("testing", text)
130
+
131
+ assert_equal("A comment!", c.comment)
132
+
133
+ refute(c.commit_required?)
134
+ refute(c.commit)
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ end
@@ -0,0 +1,230 @@
1
+ # Copyright (c) 2013 The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ require 'test/unit'
34
+ require 'tmpdir'
35
+ require 'zip-container'
36
+
37
+ # Classes to test managed entries.
38
+ class ManagedZipContainer < ZipContainer::Container
39
+
40
+ private_class_method :new
41
+
42
+ def initialize(filename)
43
+ super(filename)
44
+ register_managed_entry(ZipContainer::ManagedDirectory.new("src", true))
45
+ register_managed_entry(ZipContainer::ManagedDirectory.new("test"))
46
+ register_managed_entry(ZipContainer::ManagedDirectory.new("lib"))
47
+ register_managed_entry(ZipContainer::ManagedFile.new("index.html", true))
48
+ end
49
+
50
+ end
51
+
52
+ class ExampleZipContainer < ZipContainer::Container
53
+
54
+ private_class_method :new
55
+
56
+ def initialize(filename)
57
+ super(filename)
58
+ register_managed_entry(ZipContainer::ManagedDirectory.new("dir", true))
59
+ register_managed_entry(ZipContainer::ManagedFile.new("greeting.txt", true))
60
+ end
61
+
62
+ end
63
+
64
+ class ExampleZipContainer2 < ZipContainer::Container
65
+
66
+ private_class_method :new
67
+
68
+ def initialize(filename)
69
+ super(filename)
70
+
71
+ valid = Proc.new { |contents| contents.match(/[Hh]ello/) }
72
+ register_managed_entry(ZipContainer::ManagedFile.new("greeting.txt",
73
+ true, valid))
74
+ end
75
+
76
+ def ExampleZipContainer2.create(filename, &block)
77
+ super(filename, "application/example+zip", &block)
78
+ end
79
+
80
+ end
81
+
82
+ class TestManagedEntries < Test::Unit::TestCase
83
+
84
+ # Check that the example ZipContainer file does not validate as a
85
+ # ManagedZipContainer.
86
+ def test_fail_verification
87
+ refute(ManagedZipContainer.verify($example))
88
+
89
+ assert_raises(ZipContainer::MalformedZipContainerError) do
90
+ ManagedZipContainer.verify!($example)
91
+ end
92
+ end
93
+
94
+ # Check that the example ZipContainer file does validate as an
95
+ # ExampleZipContainer.
96
+ def test_pass_verification
97
+ assert(ExampleZipContainer.verify($example))
98
+
99
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
100
+ ExampleZipContainer.verify!($example)
101
+ end
102
+ end
103
+
104
+ # Check that the example ZipContainer file does validate as an
105
+ # ExampleZipContainer2.
106
+ def test_pass_verification_2
107
+ assert(ExampleZipContainer2.verify($example))
108
+
109
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
110
+ ExampleZipContainer2.verify!($example)
111
+ end
112
+ end
113
+
114
+ # Check that a standard Container can be created
115
+ def test_create_standard_container
116
+ Dir.mktmpdir do |dir|
117
+ filename = File.join(dir, "test.container")
118
+
119
+ assert_nothing_raised do
120
+ ZipContainer::Container.create(filename, $mimetype) do |c|
121
+ c.mkdir("META-INF")
122
+ assert(c.file.exists?("META-INF"))
123
+
124
+ c.file.open("META-INF/container.xml", "w") do |f|
125
+ f.puts "<?xml version=\"1.0\"?>"
126
+ end
127
+ assert(c.file.exists?("META-INF/container.xml"))
128
+ end
129
+ end
130
+
131
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
132
+ ZipContainer::Container.verify!(filename)
133
+ end
134
+ end
135
+ end
136
+
137
+ # Check that a ManagedZipContainer does not verify immediately after
138
+ # creation.
139
+ def test_create_bad_subclassed_container
140
+ Dir.mktmpdir do |dir|
141
+ filename = File.join(dir, "test.container")
142
+
143
+ assert_nothing_raised do
144
+ ManagedZipContainer.create(filename, $mimetype) do |c|
145
+ assert_raises(ZipContainer::MalformedZipContainerError) do
146
+ c.verify!
147
+ end
148
+ end
149
+ end
150
+
151
+ refute(ManagedZipContainer.verify(filename))
152
+ assert_raises(ZipContainer::MalformedZipContainerError) do
153
+ ManagedZipContainer.verify!(filename)
154
+ end
155
+ end
156
+ end
157
+
158
+ # Check that a ManagedZipContainer does verify when required objects are
159
+ # added.
160
+ def test_create_subclassed_container
161
+ Dir.mktmpdir do |dir|
162
+ filename = File.join(dir, "test.container")
163
+
164
+ assert_nothing_raised do
165
+ ManagedZipContainer.create(filename, $mimetype) do |c|
166
+ c.dir.mkdir("src")
167
+ c.file.open("index.html", "w") do |f|
168
+ f.puts "<html />"
169
+ end
170
+ end
171
+ end
172
+
173
+ assert(ManagedZipContainer.verify(filename))
174
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
175
+ ManagedZipContainer.verify!(filename)
176
+ end
177
+ end
178
+ end
179
+
180
+ def test_create_subclassed_mimetype
181
+ Dir.mktmpdir do |dir|
182
+ filename = File.join(dir, "test.container")
183
+
184
+ assert_nothing_raised do
185
+ ExampleZipContainer2.create(filename) do |c|
186
+ assert(c.file.exists?("mimetype"))
187
+ assert_equal("application/example+zip", c.file.read("mimetype"))
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ # Check that a ExampleZipContainer2 will only verify when required objects
194
+ # are added with the correct contents.
195
+ def test_create_subclassed_container_with_content_verification
196
+ Dir.mktmpdir do |dir|
197
+ filename = File.join(dir, "test.container")
198
+
199
+ assert_nothing_raised do
200
+ ExampleZipContainer2.create(filename) do |c|
201
+ assert_raises(ZipContainer::MalformedZipContainerError) do
202
+ c.verify!
203
+ end
204
+
205
+ c.file.open("greeting.txt", "w") do |f|
206
+ f.puts "Goodbye!"
207
+ end
208
+
209
+ assert_raises(ZipContainer::MalformedZipContainerError) do
210
+ c.verify!
211
+ end
212
+
213
+ c.file.open("greeting.txt", "w") do |f|
214
+ f.puts "Hello, Y'All!"
215
+ end
216
+
217
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
218
+ c.verify!
219
+ end
220
+ end
221
+ end
222
+
223
+ assert(ExampleZipContainer2.verify(filename))
224
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
225
+ ExampleZipContainer2.verify!(filename)
226
+ end
227
+ end
228
+ end
229
+
230
+ end