rubyzip 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubyzip might be problematic. Click here for more details.
- data/ChangeLog +1265 -0
- data/NEWS +106 -0
- data/README +69 -0
- data/Rakefile +110 -0
- data/TODO +9 -0
- data/install.rb +22 -0
- data/lib/zip/ioextras.rb +117 -0
- data/lib/zip/stdrubyext.rb +111 -0
- data/lib/zip/tempfile_bugfixed.rb +195 -0
- data/lib/zip/zip.rb +1543 -0
- data/lib/zip/zipfilesystem.rb +609 -0
- data/lib/zip/ziprequire.rb +90 -0
- data/samples/example.rb +69 -0
- data/samples/example_filesystem.rb +34 -0
- data/samples/gtkRubyzip.rb +86 -0
- data/samples/write_simple.rb +13 -0
- data/samples/zipfind.rb +74 -0
- data/test/alltests.rb +9 -0
- data/test/data/file1.txt +46 -0
- data/test/data/file1.txt.deflatedData +0 -0
- data/test/data/file2.txt +1504 -0
- data/test/data/notzippedruby.rb +7 -0
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/testDirectory.bin +0 -0
- data/test/data/zipWithDirs.zip +0 -0
- data/test/gentestfiles.rb +155 -0
- data/test/ioextrastest.rb +208 -0
- data/test/stdrubyexttest.rb +52 -0
- data/test/zipfilesystemtest.rb +829 -0
- data/test/ziprequiretest.rb +43 -0
- data/test/ziptest.rb +1557 -0
- metadata +68 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
# With ziprequire you can load ruby modules from a zip file. This means
|
2
|
+
# ruby's module include path can include zip-files.
|
3
|
+
#
|
4
|
+
# The following example creates a zip file with a single entry
|
5
|
+
# <code>log/simplelog.rb</code> that contains a single function
|
6
|
+
# <code>simpleLog</code>:
|
7
|
+
#
|
8
|
+
# require 'zip/zipfilesystem'
|
9
|
+
#
|
10
|
+
# Zip::ZipFile.open("my.zip", true) {
|
11
|
+
# |zf|
|
12
|
+
# zf.file.open("log/simplelog.rb", "w") {
|
13
|
+
# |f|
|
14
|
+
# f.puts "def simpleLog(v)"
|
15
|
+
# f.puts ' Kernel.puts "INFO: #{v}"'
|
16
|
+
# f.puts "end"
|
17
|
+
# }
|
18
|
+
# }
|
19
|
+
#
|
20
|
+
# To use the ruby module stored in the zip archive simply require
|
21
|
+
# <code>zip/ziprequire</code> and include the <code>my.zip</code> zip
|
22
|
+
# file in the module search path. The following command shows one
|
23
|
+
# way to do this:
|
24
|
+
#
|
25
|
+
# ruby -rzip/ziprequire -Imy.zip -e " require 'log/simplelog'; simpleLog 'Hello world' "
|
26
|
+
|
27
|
+
#$: << 'data/rubycode.zip' << 'data/rubycode2.zip'
|
28
|
+
|
29
|
+
|
30
|
+
require 'zip/zip'
|
31
|
+
|
32
|
+
class ZipList #:nodoc:all
|
33
|
+
def initialize(zipFileList)
|
34
|
+
@zipFileList = zipFileList
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_input_stream(entry, &aProc)
|
38
|
+
@zipFileList.each {
|
39
|
+
|zfName|
|
40
|
+
Zip::ZipFile.open(zfName) {
|
41
|
+
|zf|
|
42
|
+
begin
|
43
|
+
return zf.get_input_stream(entry, &aProc)
|
44
|
+
rescue Errno::ENOENT
|
45
|
+
end
|
46
|
+
}
|
47
|
+
}
|
48
|
+
raise Errno::ENOENT,
|
49
|
+
"No matching entry found in zip files '#{@zipFileList.join(', ')}' "+
|
50
|
+
" for '#{entry}'"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
module Kernel #:nodoc:all
|
56
|
+
alias :oldRequire :require
|
57
|
+
|
58
|
+
def require(moduleName)
|
59
|
+
zip_require(moduleName) || oldRequire(moduleName)
|
60
|
+
end
|
61
|
+
|
62
|
+
def zip_require(moduleName)
|
63
|
+
return false if already_loaded?(moduleName)
|
64
|
+
get_resource(ensure_rb_extension(moduleName)) {
|
65
|
+
|zis|
|
66
|
+
eval(zis.read); $" << moduleName
|
67
|
+
}
|
68
|
+
return true
|
69
|
+
rescue Errno::ENOENT => ex
|
70
|
+
return false
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_resource(resourceName, &aProc)
|
74
|
+
zl = ZipList.new($:.grep(/\.zip$/))
|
75
|
+
zl.get_input_stream(resourceName, &aProc)
|
76
|
+
end
|
77
|
+
|
78
|
+
def already_loaded?(moduleName)
|
79
|
+
moduleRE = Regexp.new("^"+moduleName+"(\.rb|\.so|\.dll|\.o)?$")
|
80
|
+
$".detect { |e| e =~ moduleRE } != nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def ensure_rb_extension(aString)
|
84
|
+
aString.sub(/(\.rb)?$/i, ".rb")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Copyright (C) 2002 Thomas Sondergaard
|
89
|
+
# rubyzip is free software; you can redistribute it and/or
|
90
|
+
# modify it under the terms of the ruby license.
|
data/samples/example.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << "../lib"
|
4
|
+
system("zip example.zip example.rb gtkRubyzip.rb")
|
5
|
+
|
6
|
+
require 'zip/zip'
|
7
|
+
|
8
|
+
####### Using ZipInputStream alone: #######
|
9
|
+
|
10
|
+
Zip::ZipInputStream.open("example.zip") {
|
11
|
+
|zis|
|
12
|
+
entry = zis.get_next_entry
|
13
|
+
print "First line of '#{entry.name} (#{entry.size} bytes): "
|
14
|
+
puts "'#{zis.gets.chomp}'"
|
15
|
+
entry = zis.get_next_entry
|
16
|
+
print "First line of '#{entry.name} (#{entry.size} bytes): "
|
17
|
+
puts "'#{zis.gets.chomp}'"
|
18
|
+
}
|
19
|
+
|
20
|
+
|
21
|
+
####### Using ZipFile to read the directory of a zip file: #######
|
22
|
+
|
23
|
+
zf = Zip::ZipFile.new("example.zip")
|
24
|
+
zf.each_with_index {
|
25
|
+
|entry, index|
|
26
|
+
|
27
|
+
puts "entry #{index} is #{entry.name}, size = #{entry.size}, compressed size = #{entry.compressed_size}"
|
28
|
+
# use zf.get_input_stream(entry) to get a ZipInputStream for the entry
|
29
|
+
# entry can be the ZipEntry object or any object which has a to_s method that
|
30
|
+
# returns the name of the entry.
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
####### Using ZipOutputStream to write a zip file: #######
|
35
|
+
|
36
|
+
Zip::ZipOutputStream.open("exampleout.zip") {
|
37
|
+
|zos|
|
38
|
+
zos.put_next_entry("the first little entry")
|
39
|
+
zos.puts "Hello hello hello hello hello hello hello hello hello"
|
40
|
+
|
41
|
+
zos.put_next_entry("the second little entry")
|
42
|
+
zos.puts "Hello again"
|
43
|
+
|
44
|
+
# Use rubyzip or your zip client of choice to verify
|
45
|
+
# the contents of exampleout.zip
|
46
|
+
}
|
47
|
+
|
48
|
+
####### Using ZipFile to change a zip file: #######
|
49
|
+
|
50
|
+
Zip::ZipFile.open("exampleout.zip") {
|
51
|
+
|zf|
|
52
|
+
zf.add("thisFile.rb", "example.rb")
|
53
|
+
zf.rename("thisFile.rb", "ILikeThisName.rb")
|
54
|
+
zf.add("Again", "example.rb")
|
55
|
+
}
|
56
|
+
|
57
|
+
# Lets check
|
58
|
+
Zip::ZipFile.open("exampleout.zip") {
|
59
|
+
|zf|
|
60
|
+
puts "Changed zip file contains: #{zf.entries.join(', ')}"
|
61
|
+
zf.remove("Again")
|
62
|
+
puts "Without 'Again': #{zf.entries.join(', ')}"
|
63
|
+
}
|
64
|
+
|
65
|
+
# For other examples, look at zip.rb and ziptest.rb
|
66
|
+
|
67
|
+
# Copyright (C) 2002 Thomas Sondergaard
|
68
|
+
# rubyzip is free software; you can redistribute it and/or
|
69
|
+
# modify it under the terms of the ruby license.
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << "../lib"
|
4
|
+
|
5
|
+
require 'zip/zipfilesystem'
|
6
|
+
require 'ftools'
|
7
|
+
|
8
|
+
EXAMPLE_ZIP = "filesystem.zip"
|
9
|
+
|
10
|
+
File.delete(EXAMPLE_ZIP) if File.exists?(EXAMPLE_ZIP)
|
11
|
+
|
12
|
+
Zip::ZipFile.open(EXAMPLE_ZIP, Zip::ZipFile::CREATE) {
|
13
|
+
|zf|
|
14
|
+
zf.file.open("file1.txt", "w") { |os| os.write "first file1.txt" }
|
15
|
+
zf.dir.mkdir("dir1")
|
16
|
+
zf.dir.chdir("dir1")
|
17
|
+
zf.file.open("file1.txt", "w") { |os| os.write "second file1.txt" }
|
18
|
+
puts zf.file.read("file1.txt")
|
19
|
+
puts zf.file.read("../file1.txt")
|
20
|
+
zf.dir.chdir("..")
|
21
|
+
zf.file.open("file2.txt", "w") { |os| os.write "first file2.txt" }
|
22
|
+
puts "Entries: #{zf.entries.join(', ')}"
|
23
|
+
}
|
24
|
+
|
25
|
+
Zip::ZipFile.open(EXAMPLE_ZIP) {
|
26
|
+
|zf|
|
27
|
+
puts "Entries from reloaded zip: #{zf.entries.join(', ')}"
|
28
|
+
}
|
29
|
+
|
30
|
+
# For other examples, look at zip.rb and ziptest.rb
|
31
|
+
|
32
|
+
# Copyright (C) 2003 Thomas Sondergaard
|
33
|
+
# rubyzip is free software; you can redistribute it and/or
|
34
|
+
# modify it under the terms of the ruby license.
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << "../lib"
|
4
|
+
|
5
|
+
$VERBOSE = true
|
6
|
+
|
7
|
+
require 'gtk'
|
8
|
+
require 'zip/zip'
|
9
|
+
|
10
|
+
class MainApp < Gtk::Window
|
11
|
+
def initialize
|
12
|
+
super()
|
13
|
+
set_usize(400, 256)
|
14
|
+
set_title("rubyzip")
|
15
|
+
signal_connect(Gtk::Window::SIGNAL_DESTROY) { Gtk.main_quit }
|
16
|
+
|
17
|
+
box = Gtk::VBox.new(false, 0)
|
18
|
+
add(box)
|
19
|
+
|
20
|
+
@zipfile = nil
|
21
|
+
@buttonPanel = ButtonPanel.new
|
22
|
+
@buttonPanel.openButton.signal_connect(Gtk::Button::SIGNAL_CLICKED) {
|
23
|
+
show_file_selector
|
24
|
+
}
|
25
|
+
@buttonPanel.extractButton.signal_connect(Gtk::Button::SIGNAL_CLICKED) {
|
26
|
+
puts "Not implemented!"
|
27
|
+
}
|
28
|
+
box.pack_start(@buttonPanel, false, false, 0)
|
29
|
+
|
30
|
+
sw = Gtk::ScrolledWindow.new
|
31
|
+
sw.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
|
32
|
+
box.pack_start(sw, true, true, 0)
|
33
|
+
|
34
|
+
@clist = Gtk::CList.new(["Name", "Size", "Compression"])
|
35
|
+
@clist.set_selection_mode(Gtk::SELECTION_BROWSE)
|
36
|
+
@clist.set_column_width(0, 120)
|
37
|
+
@clist.set_column_width(1, 120)
|
38
|
+
@clist.signal_connect(Gtk::CList::SIGNAL_SELECT_ROW) {
|
39
|
+
|w, row, column, event|
|
40
|
+
@selected_row = row
|
41
|
+
}
|
42
|
+
sw.add(@clist)
|
43
|
+
end
|
44
|
+
|
45
|
+
class ButtonPanel < Gtk::HButtonBox
|
46
|
+
attr_reader :openButton, :extractButton
|
47
|
+
def initialize
|
48
|
+
super
|
49
|
+
set_layout(Gtk::BUTTONBOX_START)
|
50
|
+
set_spacing(0)
|
51
|
+
@openButton = Gtk::Button.new("Open archive")
|
52
|
+
@extractButton = Gtk::Button.new("Extract entry")
|
53
|
+
pack_start(@openButton)
|
54
|
+
pack_start(@extractButton)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def show_file_selector
|
59
|
+
@fileSelector = Gtk::FileSelection.new("Open zip file")
|
60
|
+
@fileSelector.show
|
61
|
+
@fileSelector.ok_button.signal_connect(Gtk::Button::SIGNAL_CLICKED) {
|
62
|
+
open_zip(@fileSelector.filename)
|
63
|
+
@fileSelector.destroy
|
64
|
+
}
|
65
|
+
@fileSelector.cancel_button.signal_connect(Gtk::Button::SIGNAL_CLICKED) {
|
66
|
+
@fileSelector.destroy
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def open_zip(filename)
|
71
|
+
@zipfile = Zip::ZipFile.open(filename)
|
72
|
+
@clist.clear
|
73
|
+
@zipfile.each {
|
74
|
+
|entry|
|
75
|
+
@clist.append([ entry.name,
|
76
|
+
entry.size.to_s,
|
77
|
+
(100.0*entry.compressedSize/entry.size).to_s+"%" ])
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
mainApp = MainApp.new()
|
83
|
+
|
84
|
+
mainApp.show_all
|
85
|
+
|
86
|
+
Gtk.main
|
data/samples/zipfind.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$VERBOSE = true
|
4
|
+
|
5
|
+
$: << "../lib"
|
6
|
+
|
7
|
+
require 'zip/zip'
|
8
|
+
require 'find'
|
9
|
+
|
10
|
+
module Zip
|
11
|
+
module ZipFind
|
12
|
+
def self.find(path, zipFilePattern = /\.zip$/i)
|
13
|
+
Find.find(path) {
|
14
|
+
|fileName|
|
15
|
+
yield(fileName)
|
16
|
+
if zipFilePattern.match(fileName) && File.file?(fileName)
|
17
|
+
begin
|
18
|
+
Zip::ZipFile.foreach(fileName) {
|
19
|
+
|zipEntry|
|
20
|
+
yield(fileName + File::SEPARATOR + zipEntry.to_s)
|
21
|
+
}
|
22
|
+
rescue Errno::EACCES => ex
|
23
|
+
puts ex
|
24
|
+
end
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.find_file(path, fileNamePattern, zipFilePattern = /\.zip$/i)
|
30
|
+
self.find(path, zipFilePattern) {
|
31
|
+
|fileName|
|
32
|
+
yield(fileName) if fileNamePattern.match(fileName)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if __FILE__ == $0
|
40
|
+
module ZipFindConsoleRunner
|
41
|
+
|
42
|
+
PATH_ARG_INDEX = 0;
|
43
|
+
FILENAME_PATTERN_ARG_INDEX = 1;
|
44
|
+
ZIPFILE_PATTERN_ARG_INDEX = 2;
|
45
|
+
|
46
|
+
def self.run(args)
|
47
|
+
check_args(args)
|
48
|
+
Zip::ZipFind.find_file(args[PATH_ARG_INDEX],
|
49
|
+
args[FILENAME_PATTERN_ARG_INDEX],
|
50
|
+
args[ZIPFILE_PATTERN_ARG_INDEX]) {
|
51
|
+
|fileName|
|
52
|
+
report_entry_found fileName
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.check_args(args)
|
57
|
+
if (args.size != 3)
|
58
|
+
usage
|
59
|
+
exit
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.usage
|
64
|
+
puts "Usage: #{$0} PATH ZIPFILENAME_PATTERN FILNAME_PATTERN"
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.report_entry_found(fileName)
|
68
|
+
puts fileName
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
ZipFindConsoleRunner.run(ARGV)
|
74
|
+
end
|
data/test/alltests.rb
ADDED
data/test/data/file1.txt
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
AUTOMAKE_OPTIONS = gnu
|
3
|
+
|
4
|
+
EXTRA_DIST = test.zip
|
5
|
+
|
6
|
+
CXXFLAGS= -g
|
7
|
+
|
8
|
+
noinst_LIBRARIES = libzipios.a
|
9
|
+
|
10
|
+
bin_PROGRAMS = test_zip test_izipfilt test_izipstream
|
11
|
+
# test_flist
|
12
|
+
|
13
|
+
libzipios_a_SOURCES = backbuffer.h fcol.cpp fcol.h \
|
14
|
+
fcol_common.h fcolexceptions.cpp fcolexceptions.h \
|
15
|
+
fileentry.cpp fileentry.h flist.cpp \
|
16
|
+
flist.h flistentry.cpp flistentry.h \
|
17
|
+
flistscanner.h ifiltstreambuf.cpp ifiltstreambuf.h \
|
18
|
+
inflatefilt.cpp inflatefilt.h izipfilt.cpp \
|
19
|
+
izipfilt.h izipstream.cpp izipstream.h \
|
20
|
+
zipfile.cpp zipfile.h ziphead.cpp \
|
21
|
+
ziphead.h flistscanner.ll
|
22
|
+
|
23
|
+
# test_flist_SOURCES = test_flist.cpp
|
24
|
+
|
25
|
+
test_izipfilt_SOURCES = test_izipfilt.cpp
|
26
|
+
|
27
|
+
test_izipstream_SOURCES = test_izipstream.cpp
|
28
|
+
|
29
|
+
test_zip_SOURCES = test_zip.cpp
|
30
|
+
|
31
|
+
# Notice that libzipios.a is not specified as -L. -lzipios
|
32
|
+
# If it was, automake would not include it as a dependency.
|
33
|
+
|
34
|
+
# test_flist_LDADD = libzipios.a
|
35
|
+
|
36
|
+
test_izipfilt_LDADD = libzipios.a -lz
|
37
|
+
|
38
|
+
test_zip_LDADD = libzipios.a -lz
|
39
|
+
|
40
|
+
test_izipstream_LDADD = libzipios.a -lz
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
flistscanner.cc : flistscanner.ll
|
45
|
+
$(LEX) -+ -PFListScanner -o$@ $^
|
46
|
+
|
Binary file
|
data/test/data/file2.txt
ADDED
@@ -0,0 +1,1504 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$VERBOSE = true
|
4
|
+
|
5
|
+
require 'rubyunit'
|
6
|
+
require 'zip'
|
7
|
+
|
8
|
+
include Zip
|
9
|
+
|
10
|
+
Dir.chdir "test"
|
11
|
+
|
12
|
+
class AbstractInputStreamTest < RUNIT::TestCase
|
13
|
+
# AbstractInputStream subclass that provides a read method
|
14
|
+
|
15
|
+
TEST_LINES = [ "Hello world#{$/}",
|
16
|
+
"this is the second line#{$/}",
|
17
|
+
"this is the last line"]
|
18
|
+
TEST_STRING = TEST_LINES.join
|
19
|
+
class TestAbstractInputStream
|
20
|
+
include AbstractInputStream
|
21
|
+
def initialize(aString)
|
22
|
+
@contents = aString
|
23
|
+
@readPointer = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def read(charsToRead)
|
27
|
+
retVal=@contents[@readPointer, charsToRead]
|
28
|
+
@readPointer+=charsToRead
|
29
|
+
return retVal
|
30
|
+
end
|
31
|
+
|
32
|
+
def produceInput
|
33
|
+
read(100)
|
34
|
+
end
|
35
|
+
|
36
|
+
def inputFinished?
|
37
|
+
@contents[@readPointer] == nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
@io = TestAbstractInputStream.new(TEST_STRING)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_gets
|
46
|
+
assert_equals(TEST_LINES[0], @io.gets)
|
47
|
+
assert_equals(TEST_LINES[1], @io.gets)
|
48
|
+
assert_equals(TEST_LINES[2], @io.gets)
|
49
|
+
assert_equals(nil, @io.gets)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_getsMultiCharSeperator
|
53
|
+
assert_equals("Hell", @io.gets("ll"))
|
54
|
+
assert_equals("o world#{$/}this is the second l", @io.gets("d l"))
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_each_line
|
58
|
+
lineNumber=0
|
59
|
+
@io.each_line {
|
60
|
+
|line|
|
61
|
+
assert_equals(TEST_LINES[lineNumber], line)
|
62
|
+
lineNumber+=1
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_readlines
|
67
|
+
assert_equals(TEST_LINES, @io.readlines)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_readline
|
71
|
+
test_gets
|
72
|
+
begin
|
73
|
+
@io.readline
|
74
|
+
fail "EOFError expected"
|
75
|
+
rescue EOFError
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class ZipEntryTest < RUNIT::TestCase
|
81
|
+
TEST_ZIPFILE = "someZipFile.zip"
|
82
|
+
TEST_COMMENT = "a comment"
|
83
|
+
TEST_COMPRESSED_SIZE = 1234
|
84
|
+
TEST_CRC = 325324
|
85
|
+
TEST_EXTRA = "Some data here"
|
86
|
+
TEST_COMPRESSIONMETHOD = ZipEntry::DEFLATED
|
87
|
+
TEST_NAME = "entry name"
|
88
|
+
TEST_SIZE = 8432
|
89
|
+
TEST_ISDIRECTORY = false
|
90
|
+
|
91
|
+
def test_constructorAndGetters
|
92
|
+
entry = ZipEntry.new(TEST_ZIPFILE,
|
93
|
+
TEST_NAME,
|
94
|
+
TEST_COMMENT,
|
95
|
+
TEST_EXTRA,
|
96
|
+
TEST_COMPRESSED_SIZE,
|
97
|
+
TEST_CRC,
|
98
|
+
TEST_COMPRESSIONMETHOD,
|
99
|
+
TEST_SIZE)
|
100
|
+
|
101
|
+
assert_equals(TEST_COMMENT, entry.comment)
|
102
|
+
assert_equals(TEST_COMPRESSED_SIZE, entry.compressedSize)
|
103
|
+
assert_equals(TEST_CRC, entry.crc)
|
104
|
+
assert_equals(TEST_EXTRA, entry.extra)
|
105
|
+
assert_equals(TEST_COMPRESSIONMETHOD, entry.compressionMethod)
|
106
|
+
assert_equals(TEST_NAME, entry.name)
|
107
|
+
assert_equals(TEST_SIZE, entry.size)
|
108
|
+
assert_equals(TEST_ISDIRECTORY, entry.isDirectory)
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_equality
|
112
|
+
entry1 = ZipEntry.new("file.zip", "name", "isNotCompared",
|
113
|
+
"something extra", 123, 1234,
|
114
|
+
ZipEntry::DEFLATED, 10000)
|
115
|
+
entry2 = ZipEntry.new("file.zip", "name", "isNotComparedXXX",
|
116
|
+
"something extra", 123, 1234,
|
117
|
+
ZipEntry::DEFLATED, 10000)
|
118
|
+
entry3 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
|
119
|
+
"something extra", 123, 1234,
|
120
|
+
ZipEntry::DEFLATED, 10000)
|
121
|
+
entry4 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
|
122
|
+
"something extraXX", 123, 1234,
|
123
|
+
ZipEntry::DEFLATED, 10000)
|
124
|
+
entry5 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
|
125
|
+
"something extraXX", 12, 1234,
|
126
|
+
ZipEntry::DEFLATED, 10000)
|
127
|
+
entry6 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
|
128
|
+
"something extraXX", 12, 123,
|
129
|
+
ZipEntry::DEFLATED, 10000)
|
130
|
+
entry7 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
|
131
|
+
"something extraXX", 12, 123,
|
132
|
+
ZipEntry::STORED, 10000)
|
133
|
+
entry8 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX",
|
134
|
+
"something extraXX", 12, 123,
|
135
|
+
ZipEntry::STORED, 100000)
|
136
|
+
|
137
|
+
assert_equals(entry1, entry1)
|
138
|
+
assert_equals(entry1, entry2)
|
139
|
+
|
140
|
+
assert(entry2 != entry3)
|
141
|
+
assert(entry3 != entry4)
|
142
|
+
assert(entry4 != entry5)
|
143
|
+
assert(entry5 != entry6)
|
144
|
+
assert(entry6 != entry7)
|
145
|
+
assert(entry7 != entry8)
|
146
|
+
|
147
|
+
assert(entry7 != "hello")
|
148
|
+
assert(entry7 != 12)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
module IOizeString
|
153
|
+
attr_reader :tell
|
154
|
+
|
155
|
+
def read(count = nil)
|
156
|
+
@tell ||= 0
|
157
|
+
count = size unless count
|
158
|
+
retVal = slice(@tell, count)
|
159
|
+
@tell += count
|
160
|
+
return retVal
|
161
|
+
end
|
162
|
+
|
163
|
+
def seek(index, offset)
|
164
|
+
@tell ||= 0
|
165
|
+
case offset
|
166
|
+
when IO::SEEK_END
|
167
|
+
newPos = size + index
|
168
|
+
when IO::SEEK_SET
|
169
|
+
newPos = index
|
170
|
+
when IO::SEEK_CUR
|
171
|
+
newPos = @tell + index
|
172
|
+
else
|
173
|
+
raise "Error in test method IOizeString::seek"
|
174
|
+
end
|
175
|
+
if (newPos < 0 || newPos >= size)
|
176
|
+
raise Errno::EINVAL
|
177
|
+
else
|
178
|
+
@tell=newPos
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def reset
|
183
|
+
@tell = 0
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class ZipLocalEntryTest < RUNIT::TestCase
|
188
|
+
def test_readLocalEntryHeaderOfFirstTestZipEntry
|
189
|
+
File.open(TestZipFile::TEST_ZIP3.zipName) {
|
190
|
+
|file|
|
191
|
+
entry = ZipEntry.readLocalEntry(file)
|
192
|
+
|
193
|
+
assert_equal("", entry.comment)
|
194
|
+
# Differs from windows and unix because of CR LF
|
195
|
+
# assert_equal(480, entry.compressedSize)
|
196
|
+
# assert_equal(0x2a27930f, entry.crc)
|
197
|
+
# extra field is 21 bytes long
|
198
|
+
# probably contains some unix attrutes or something
|
199
|
+
# disabled: assert_equal(nil, entry.extra)
|
200
|
+
assert_equal(ZipEntry::DEFLATED, entry.compressionMethod)
|
201
|
+
assert_equal(TestZipFile::TEST_ZIP3.entryNames[0], entry.name)
|
202
|
+
assert_equal(File.size(TestZipFile::TEST_ZIP3.entryNames[0]), entry.size)
|
203
|
+
assert(! entry.isDirectory)
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_readLocalEntryFromNonZipFile
|
208
|
+
File.open("ziptest.rb") {
|
209
|
+
|file|
|
210
|
+
assert_equals(nil, ZipEntry.readLocalEntry(file))
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_readLocalEntryFromTruncatedZipFile
|
215
|
+
zipFragment=""
|
216
|
+
File.open(TestZipFile::TEST_ZIP2.zipName) { |f| zipFragment = f.read(12) } # local header is at least 30 bytes
|
217
|
+
zipFragment.extend(IOizeString).reset
|
218
|
+
entry = ZipEntry.new
|
219
|
+
entry.readLocalEntry(zipFragment)
|
220
|
+
fail "ZipError expected"
|
221
|
+
rescue ZipError
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_writeEntry
|
225
|
+
entry = ZipEntry.new("file.zip", "entryName", "my little comment",
|
226
|
+
"thisIsSomeExtraInformation", 100, 987654,
|
227
|
+
ZipEntry::DEFLATED, 400)
|
228
|
+
writeToFile("localEntryHeader.bin", "centralEntryHeader.bin", entry)
|
229
|
+
entryReadLocal, entryReadCentral = readFromFile("localEntryHeader.bin", "centralEntryHeader.bin")
|
230
|
+
compareLocalEntryHeaders(entry, entryReadLocal)
|
231
|
+
compareCDirEntryHeaders(entry, entryReadCentral)
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
def compareLocalEntryHeaders(entry1, entry2)
|
236
|
+
assert_equals(entry1.compressedSize , entry2.compressedSize)
|
237
|
+
assert_equals(entry1.crc , entry2.crc)
|
238
|
+
assert_equals(entry1.extra , entry2.extra)
|
239
|
+
assert_equals(entry1.compressionMethod, entry2.compressionMethod)
|
240
|
+
assert_equals(entry1.name , entry2.name)
|
241
|
+
assert_equals(entry1.size , entry2.size)
|
242
|
+
assert_equals(entry1.localHeaderOffset, entry2.localHeaderOffset)
|
243
|
+
end
|
244
|
+
|
245
|
+
def compareCDirEntryHeaders(entry1, entry2)
|
246
|
+
compareLocalEntryHeaders(entry1, entry2)
|
247
|
+
assert_equals(entry1.comment, entry2.comment)
|
248
|
+
end
|
249
|
+
|
250
|
+
def writeToFile(localFileName, centralFileName, entry)
|
251
|
+
File.open(localFileName, "wb") { |f| entry.writeLocalEntry(f) }
|
252
|
+
File.open(centralFileName, "wb") { |f| entry.writeCDirEntry(f) }
|
253
|
+
end
|
254
|
+
|
255
|
+
def readFromFile(localFileName, centralFileName)
|
256
|
+
localEntry = nil
|
257
|
+
cdirEntry = nil
|
258
|
+
File.open(localFileName, "rb") { |f| localEntry = ZipEntry.readLocalEntry(f) }
|
259
|
+
File.open(centralFileName, "rb") { |f| cdirEntry = ZipEntry.readCDirEntry(f) }
|
260
|
+
return [localEntry, cdirEntry]
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
|
265
|
+
module DecompressorTests
|
266
|
+
# expects @refText and @decompressor
|
267
|
+
|
268
|
+
def test_readEverything
|
269
|
+
assert_equals(@refText, @decompressor.read)
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_readInChunks
|
273
|
+
chunkSize = 5
|
274
|
+
while (decompressedChunk = @decompressor.read(chunkSize))
|
275
|
+
assert_equals(@refText.slice!(0, chunkSize), decompressedChunk)
|
276
|
+
end
|
277
|
+
assert_equals(0, @refText.size)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
class InflaterTest < RUNIT::TestCase
|
282
|
+
include DecompressorTests
|
283
|
+
|
284
|
+
def setup
|
285
|
+
@file = File.new("file1.txt.deflatedData", "rb")
|
286
|
+
@refText=""
|
287
|
+
File.open("file1.txt") { |f| @refText = f.read }
|
288
|
+
@decompressor = Inflater.new(@file)
|
289
|
+
end
|
290
|
+
|
291
|
+
def teardown
|
292
|
+
@file.close
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
|
297
|
+
class PassThruDecompressorTest < RUNIT::TestCase
|
298
|
+
include DecompressorTests
|
299
|
+
TEST_FILE="file1.txt"
|
300
|
+
def setup
|
301
|
+
@file = File.new(TEST_FILE)
|
302
|
+
@refText=""
|
303
|
+
File.open(TEST_FILE) { |f| @refText = f.read }
|
304
|
+
@decompressor = PassThruDecompressor.new(@file, File.size(TEST_FILE))
|
305
|
+
end
|
306
|
+
|
307
|
+
def teardown
|
308
|
+
@file.close
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
|
313
|
+
module AssertEntry
|
314
|
+
def assertNextEntry(filename, zis)
|
315
|
+
assertEntry(filename, zis, zis.getNextEntry.name)
|
316
|
+
end
|
317
|
+
|
318
|
+
def assertEntry(filename, zis, entryName)
|
319
|
+
assert_equals(filename, entryName)
|
320
|
+
assertEntryContentsForStream(filename, zis, entryName)
|
321
|
+
end
|
322
|
+
|
323
|
+
def assertEntryContentsForStream(filename, zis, entryName)
|
324
|
+
File.open(filename, "rb") {
|
325
|
+
|file|
|
326
|
+
expected = file.read
|
327
|
+
actual = zis.read
|
328
|
+
if (expected != actual)
|
329
|
+
if (expected.length > 400 || actual.length > 400)
|
330
|
+
zipEntryFilename=entryName+".zipEntry"
|
331
|
+
File.open(zipEntryFilename, "wb") { |file| file << actual }
|
332
|
+
fail("File '#{filename}' is different from '#{zipEntryFilename}'")
|
333
|
+
else
|
334
|
+
assert_equals(expected, actual)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
}
|
338
|
+
end
|
339
|
+
|
340
|
+
def AssertEntry.assertContents(filename, aString)
|
341
|
+
fileContents = ""
|
342
|
+
File.open(filename, "rb") { |f| fileContents = f.read }
|
343
|
+
if (fileContents != aString)
|
344
|
+
if (expected.length > 400 || actual.length > 400)
|
345
|
+
stringFile = filename + ".other"
|
346
|
+
File.open(stringFile, "wb") { |f| f << aString }
|
347
|
+
fail("File '#{filename}' is different from contents of string stored in '#{stringFile}'")
|
348
|
+
else
|
349
|
+
assert_equals(expected, actual)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
def assertStreamContents(zis, testZipFile)
|
355
|
+
assert(zis != nil)
|
356
|
+
testZipFile.entryNames.each {
|
357
|
+
|entryName|
|
358
|
+
assertNextEntry(entryName, zis)
|
359
|
+
}
|
360
|
+
assert_equals(nil, zis.getNextEntry)
|
361
|
+
end
|
362
|
+
|
363
|
+
def assertTestZipContents(testZipFile)
|
364
|
+
ZipInputStream.open(testZipFile.zipName) {
|
365
|
+
|zis|
|
366
|
+
assertStreamContents(zis, testZipFile)
|
367
|
+
}
|
368
|
+
end
|
369
|
+
|
370
|
+
def assertEntryContents(zipFile, entryName, filename = entryName.to_s)
|
371
|
+
zis = zipFile.getInputStream(entryName)
|
372
|
+
assertEntryContentsForStream(filename, zis, entryName)
|
373
|
+
ensure
|
374
|
+
zis.close if zis
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
|
379
|
+
|
380
|
+
class ZipInputStreamTest < RUNIT::TestCase
|
381
|
+
include AssertEntry
|
382
|
+
|
383
|
+
def test_new
|
384
|
+
zis = ZipInputStream.new(TestZipFile::TEST_ZIP2.zipName)
|
385
|
+
assertStreamContents(zis, TestZipFile::TEST_ZIP2)
|
386
|
+
zis.close
|
387
|
+
end
|
388
|
+
|
389
|
+
def test_openWithBlock
|
390
|
+
ZipInputStream.open(TestZipFile::TEST_ZIP2.zipName) {
|
391
|
+
|zis|
|
392
|
+
assertStreamContents(zis, TestZipFile::TEST_ZIP2)
|
393
|
+
}
|
394
|
+
end
|
395
|
+
|
396
|
+
def test_openWithoutBlock
|
397
|
+
zis = ZipInputStream.open(TestZipFile::TEST_ZIP2.zipName)
|
398
|
+
assertStreamContents(zis, TestZipFile::TEST_ZIP2)
|
399
|
+
end
|
400
|
+
|
401
|
+
def test_incompleteReads
|
402
|
+
ZipInputStream.open(TestZipFile::TEST_ZIP2.zipName) {
|
403
|
+
|zis|
|
404
|
+
entry = zis.getNextEntry
|
405
|
+
assert_equals(TestZipFile::TEST_ZIP2.entryNames[0], entry.name)
|
406
|
+
assert zis.gets.length > 0
|
407
|
+
entry = zis.getNextEntry
|
408
|
+
assert_equals(TestZipFile::TEST_ZIP2.entryNames[1], entry.name)
|
409
|
+
assert_equals(0, entry.size)
|
410
|
+
assert_equals(nil, zis.gets)
|
411
|
+
entry = zis.getNextEntry
|
412
|
+
assert_equals(TestZipFile::TEST_ZIP2.entryNames[2], entry.name)
|
413
|
+
assert zis.gets.length > 0
|
414
|
+
entry = zis.getNextEntry
|
415
|
+
assert_equals(TestZipFile::TEST_ZIP2.entryNames[3], entry.name)
|
416
|
+
assert zis.gets.length > 0
|
417
|
+
}
|
418
|
+
end
|
419
|
+
|
420
|
+
end
|
421
|
+
|
422
|
+
class TestFiles
|
423
|
+
RANDOM_ASCII_FILE1 = "randomAscii1.txt"
|
424
|
+
RANDOM_ASCII_FILE2 = "randomAscii2.txt"
|
425
|
+
RANDOM_ASCII_FILE3 = "randomAscii3.txt"
|
426
|
+
RANDOM_BINARY_FILE1 = "randomBinary1.bin"
|
427
|
+
RANDOM_BINARY_FILE2 = "randomBinary2.bin"
|
428
|
+
|
429
|
+
EMPTY_TEST_DIR = "emptytestdir"
|
430
|
+
|
431
|
+
ASCII_TEST_FILES = [ RANDOM_ASCII_FILE1, RANDOM_ASCII_FILE2, RANDOM_ASCII_FILE3 ]
|
432
|
+
BINARY_TEST_FILES = [ RANDOM_BINARY_FILE1, RANDOM_BINARY_FILE2 ]
|
433
|
+
TEST_DIRECTORIES = [ EMPTY_TEST_DIR ]
|
434
|
+
TEST_FILES = [ ASCII_TEST_FILES, BINARY_TEST_FILES, EMPTY_TEST_DIR ].flatten!
|
435
|
+
|
436
|
+
def TestFiles.createTestFiles(recreate)
|
437
|
+
if (recreate ||
|
438
|
+
! (TEST_FILES.inject(true) { |accum, element| accum && File.exists?(element) }))
|
439
|
+
|
440
|
+
ASCII_TEST_FILES.each_with_index {
|
441
|
+
|filename, index|
|
442
|
+
createRandomAscii(filename, 1E4 * (index+1))
|
443
|
+
}
|
444
|
+
|
445
|
+
BINARY_TEST_FILES.each_with_index {
|
446
|
+
|filename, index|
|
447
|
+
createRandomBinary(filename, 1E4 * (index+1))
|
448
|
+
}
|
449
|
+
|
450
|
+
ensureDir(EMPTY_TEST_DIR)
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
private
|
455
|
+
def TestFiles.createRandomAscii(filename, size)
|
456
|
+
File.open(filename, "wb") {
|
457
|
+
|file|
|
458
|
+
while (file.tell < size)
|
459
|
+
file << rand
|
460
|
+
end
|
461
|
+
}
|
462
|
+
end
|
463
|
+
|
464
|
+
def TestFiles.createRandomBinary(filename, size)
|
465
|
+
File.open(filename, "wb") {
|
466
|
+
|file|
|
467
|
+
while (file.tell < size)
|
468
|
+
file << rand.to_a.pack("V")
|
469
|
+
end
|
470
|
+
}
|
471
|
+
end
|
472
|
+
|
473
|
+
def TestFiles.ensureDir(name)
|
474
|
+
if File.exists?(name)
|
475
|
+
return if File.stat(name).directory?
|
476
|
+
File.delete(name)
|
477
|
+
end
|
478
|
+
Dir.mkdir(name)
|
479
|
+
end
|
480
|
+
|
481
|
+
end
|
482
|
+
|
483
|
+
# For representation and creation of
|
484
|
+
# test data
|
485
|
+
class TestZipFile
|
486
|
+
attr_accessor :zipName, :entryNames, :comment
|
487
|
+
|
488
|
+
def initialize(zipName, entryNames, comment = "")
|
489
|
+
@zipName=zipName
|
490
|
+
@entryNames=entryNames
|
491
|
+
@comment = comment
|
492
|
+
end
|
493
|
+
|
494
|
+
def TestZipFile.createTestZips(recreate)
|
495
|
+
files = Dir.entries(".")
|
496
|
+
if (recreate ||
|
497
|
+
! (files.index(TEST_ZIP1.zipName) &&
|
498
|
+
files.index(TEST_ZIP2.zipName) &&
|
499
|
+
files.index(TEST_ZIP3.zipName) &&
|
500
|
+
files.index(TEST_ZIP4.zipName) &&
|
501
|
+
files.index("empty.txt") &&
|
502
|
+
files.index("short.txt") &&
|
503
|
+
files.index("longAscii.txt") &&
|
504
|
+
files.index("longBinary.bin") ))
|
505
|
+
raise "failed to create test zip '#{TEST_ZIP1.zipName}'" unless
|
506
|
+
system("zip #{TEST_ZIP1.zipName} ziptest.rb")
|
507
|
+
raise "failed to remove entry from '#{TEST_ZIP1.zipName}'" unless
|
508
|
+
system("zip #{TEST_ZIP1.zipName} -d ziptest.rb")
|
509
|
+
|
510
|
+
File.open("empty.txt", "w") {}
|
511
|
+
|
512
|
+
File.open("short.txt", "w") { |file| file << "ABCDEF" }
|
513
|
+
ziptestTxt=""
|
514
|
+
File.open("ziptest.rb") { |file| ziptestTxt=file.read }
|
515
|
+
File.open("longAscii.txt", "w") {
|
516
|
+
|file|
|
517
|
+
while (file.tell < 1E5)
|
518
|
+
file << ziptestTxt
|
519
|
+
end
|
520
|
+
}
|
521
|
+
|
522
|
+
testBinaryPattern=""
|
523
|
+
File.open("empty.zip") { |file| testBinaryPattern=file.read }
|
524
|
+
testBinaryPattern *= 4
|
525
|
+
|
526
|
+
File.open("longBinary.bin", "wb") {
|
527
|
+
|file|
|
528
|
+
while (file.tell < 3E5)
|
529
|
+
file << testBinaryPattern << rand
|
530
|
+
end
|
531
|
+
}
|
532
|
+
raise "failed to create test zip '#{TEST_ZIP2.zipName}'" unless
|
533
|
+
system("zip #{TEST_ZIP2.zipName} #{TEST_ZIP2.entryNames.join(' ')}")
|
534
|
+
|
535
|
+
# without bash system interprets everything after echo as parameters to
|
536
|
+
# echo including | zip -z ...
|
537
|
+
raise "failed to add comment to test zip '#{TEST_ZIP2.zipName}'" unless
|
538
|
+
system("bash -c \"echo #{TEST_ZIP2.comment} | zip -z #{TEST_ZIP2.zipName}\"")
|
539
|
+
|
540
|
+
raise "failed to create test zip '#{TEST_ZIP3.zipName}'" unless
|
541
|
+
system("zip #{TEST_ZIP3.zipName} #{TEST_ZIP3.entryNames.join(' ')}")
|
542
|
+
|
543
|
+
raise "failed to create test zip '#{TEST_ZIP4.zipName}'" unless
|
544
|
+
system("zip #{TEST_ZIP4.zipName} #{TEST_ZIP4.entryNames.join(' ')}")
|
545
|
+
end
|
546
|
+
rescue
|
547
|
+
raise $!.to_s +
|
548
|
+
"\n\nziptest.rb requires the Info-ZIP program 'zip' in the path\n" +
|
549
|
+
"to create test data. If you don't have it you can download\n" +
|
550
|
+
"the necessary test files at http://sf.net/projects/rubyzip."
|
551
|
+
end
|
552
|
+
|
553
|
+
TEST_ZIP1 = TestZipFile.new("empty.zip", [])
|
554
|
+
TEST_ZIP2 = TestZipFile.new("4entry.zip", %w{ longAscii.txt empty.txt short.txt longBinary.bin},
|
555
|
+
"my zip comment")
|
556
|
+
TEST_ZIP3 = TestZipFile.new("test1.zip", %w{ file1.txt })
|
557
|
+
TEST_ZIP4 = TestZipFile.new("zipWithDir.zip", [ "file1.txt",
|
558
|
+
TestFiles::EMPTY_TEST_DIR])
|
559
|
+
end
|
560
|
+
|
561
|
+
|
562
|
+
class AbstractOutputStreamTest < RUNIT::TestCase
|
563
|
+
class TestOutputStream
|
564
|
+
include AbstractOutputStream
|
565
|
+
|
566
|
+
attr_accessor :buffer
|
567
|
+
|
568
|
+
def initialize
|
569
|
+
@buffer = ""
|
570
|
+
end
|
571
|
+
|
572
|
+
def << (data)
|
573
|
+
@buffer << data
|
574
|
+
self
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
def setup
|
579
|
+
@outputStream = TestOutputStream.new
|
580
|
+
|
581
|
+
@origCommaSep = $,
|
582
|
+
@origOutputSep = $\
|
583
|
+
end
|
584
|
+
|
585
|
+
def teardown
|
586
|
+
$, = @origCommaSep
|
587
|
+
$\ = @origOutputSep
|
588
|
+
end
|
589
|
+
|
590
|
+
def test_write
|
591
|
+
count = @outputStream.write("a little string")
|
592
|
+
assert_equals("a little string", @outputStream.buffer)
|
593
|
+
assert_equals("a little string".length, count)
|
594
|
+
|
595
|
+
count = @outputStream.write(". a little more")
|
596
|
+
assert_equals("a little string. a little more", @outputStream.buffer)
|
597
|
+
assert_equals(". a little more".length, count)
|
598
|
+
end
|
599
|
+
|
600
|
+
def test_print
|
601
|
+
$\ = nil # record separator set to nil
|
602
|
+
@outputStream.print("hello")
|
603
|
+
assert_equals("hello", @outputStream.buffer)
|
604
|
+
|
605
|
+
@outputStream.print(" world.")
|
606
|
+
assert_equals("hello world.", @outputStream.buffer)
|
607
|
+
|
608
|
+
@outputStream.print(" You ok ", "out ", "there?")
|
609
|
+
assert_equals("hello world. You ok out there?", @outputStream.buffer)
|
610
|
+
|
611
|
+
$\ = "\n"
|
612
|
+
@outputStream.print
|
613
|
+
assert_equals("hello world. You ok out there?\n", @outputStream.buffer)
|
614
|
+
|
615
|
+
@outputStream.print("I sure hope so!")
|
616
|
+
assert_equals("hello world. You ok out there?\nI sure hope so!\n", @outputStream.buffer)
|
617
|
+
|
618
|
+
$, = "X"
|
619
|
+
@outputStream.buffer = ""
|
620
|
+
@outputStream.print("monkey", "duck", "zebra")
|
621
|
+
assert_equals("monkeyXduckXzebra\n", @outputStream.buffer)
|
622
|
+
|
623
|
+
$\ = nil
|
624
|
+
@outputStream.buffer = ""
|
625
|
+
@outputStream.print(20)
|
626
|
+
assert_equals("20", @outputStream.buffer)
|
627
|
+
end
|
628
|
+
|
629
|
+
def test_printf
|
630
|
+
@outputStream.printf("%d %04x", 123, 123)
|
631
|
+
assert_equals("123 007b", @outputStream.buffer)
|
632
|
+
end
|
633
|
+
|
634
|
+
def test_putc
|
635
|
+
@outputStream.putc("A")
|
636
|
+
assert_equals("A", @outputStream.buffer)
|
637
|
+
@outputStream.putc(65)
|
638
|
+
assert_equals("AA", @outputStream.buffer)
|
639
|
+
end
|
640
|
+
|
641
|
+
def test_puts
|
642
|
+
@outputStream.puts
|
643
|
+
assert_equals("\n", @outputStream.buffer)
|
644
|
+
|
645
|
+
@outputStream.puts("hello", "world")
|
646
|
+
assert_equals("\nhello\nworld\n", @outputStream.buffer)
|
647
|
+
|
648
|
+
@outputStream.buffer = ""
|
649
|
+
@outputStream.puts("hello\n", "world\n")
|
650
|
+
assert_equals("hello\nworld\n", @outputStream.buffer)
|
651
|
+
|
652
|
+
@outputStream.buffer = ""
|
653
|
+
@outputStream.puts(["hello\n", "world\n"])
|
654
|
+
assert_equals("hello\nworld\n", @outputStream.buffer)
|
655
|
+
|
656
|
+
@outputStream.buffer = ""
|
657
|
+
@outputStream.puts(["hello\n", "world\n"], "bingo")
|
658
|
+
assert_equals("hello\nworld\nbingo\n", @outputStream.buffer)
|
659
|
+
|
660
|
+
@outputStream.buffer = ""
|
661
|
+
@outputStream.puts(16, 20, 50, "hello")
|
662
|
+
assert_equals("16\n20\n50\nhello\n", @outputStream.buffer)
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
|
667
|
+
module CrcTest
|
668
|
+
def runCrcTest(compressorClass)
|
669
|
+
str = "Here's a nice little text to compute the crc for! Ho hum, it is nice nice nice nice indeed."
|
670
|
+
fakeOut = AbstractOutputStreamTest::TestOutputStream.new
|
671
|
+
|
672
|
+
deflater = compressorClass.new(fakeOut)
|
673
|
+
deflater << str
|
674
|
+
assert_equals(0x919920fc, deflater.crc)
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
|
679
|
+
|
680
|
+
class PassThruCompressorTest < RUNIT::TestCase
|
681
|
+
include CrcTest
|
682
|
+
|
683
|
+
def test_size
|
684
|
+
File.open("dummy.txt", "wb") {
|
685
|
+
|file|
|
686
|
+
compressor = PassThruCompressor.new(file)
|
687
|
+
|
688
|
+
assert_equals(0, compressor.size)
|
689
|
+
|
690
|
+
t1 = "hello world"
|
691
|
+
t2 = ""
|
692
|
+
t3 = "bingo"
|
693
|
+
|
694
|
+
compressor << t1
|
695
|
+
assert_equals(compressor.size, t1.size)
|
696
|
+
|
697
|
+
compressor << t2
|
698
|
+
assert_equals(compressor.size, t1.size + t2.size)
|
699
|
+
|
700
|
+
compressor << t3
|
701
|
+
assert_equals(compressor.size, t1.size + t2.size + t3.size)
|
702
|
+
}
|
703
|
+
end
|
704
|
+
|
705
|
+
def test_crc
|
706
|
+
runCrcTest(PassThruCompressor)
|
707
|
+
end
|
708
|
+
end
|
709
|
+
|
710
|
+
class DeflaterTest < RUNIT::TestCase
|
711
|
+
include CrcTest
|
712
|
+
|
713
|
+
def test_outputOperator
|
714
|
+
txt = loadFile("ziptest.rb")
|
715
|
+
deflate(txt, "deflatertest.bin")
|
716
|
+
inflatedTxt = inflate("deflatertest.bin")
|
717
|
+
assert_equals(txt, inflatedTxt)
|
718
|
+
end
|
719
|
+
|
720
|
+
private
|
721
|
+
def loadFile(fileName)
|
722
|
+
txt = nil
|
723
|
+
File.open(fileName, "rb") { |f| txt = f.read }
|
724
|
+
end
|
725
|
+
|
726
|
+
def deflate(data, fileName)
|
727
|
+
File.open(fileName, "wb") {
|
728
|
+
|file|
|
729
|
+
deflater = Deflater.new(file)
|
730
|
+
deflater << data
|
731
|
+
deflater.finish
|
732
|
+
assert_equals(deflater.size, data.size)
|
733
|
+
file << "trailing data for zlib with -MAX_WBITS"
|
734
|
+
}
|
735
|
+
end
|
736
|
+
|
737
|
+
def inflate(fileName)
|
738
|
+
txt = nil
|
739
|
+
File.open(fileName, "rb") {
|
740
|
+
|file|
|
741
|
+
inflater = Inflater.new(file)
|
742
|
+
txt = inflater.read
|
743
|
+
}
|
744
|
+
end
|
745
|
+
|
746
|
+
def test_crc
|
747
|
+
runCrcTest(Deflater)
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
class ZipOutputStreamTest < RUNIT::TestCase
|
752
|
+
include AssertEntry
|
753
|
+
|
754
|
+
TEST_ZIP = TestZipFile::TEST_ZIP2.clone
|
755
|
+
TEST_ZIP.zipName = "output.zip"
|
756
|
+
|
757
|
+
def test_new
|
758
|
+
zos = ZipOutputStream.new(TEST_ZIP.zipName)
|
759
|
+
zos.comment = TEST_ZIP.comment
|
760
|
+
writeTestZip(zos)
|
761
|
+
zos.close
|
762
|
+
assertTestZipContents(TEST_ZIP)
|
763
|
+
end
|
764
|
+
|
765
|
+
def test_open
|
766
|
+
ZipOutputStream.open(TEST_ZIP.zipName) {
|
767
|
+
|zos|
|
768
|
+
zos.comment = TEST_ZIP.comment
|
769
|
+
writeTestZip(zos)
|
770
|
+
}
|
771
|
+
assertTestZipContents(TEST_ZIP)
|
772
|
+
end
|
773
|
+
|
774
|
+
def test_writingToClosedStream
|
775
|
+
assertIOErrorInClosedStream { |zos| zos << "hello world" }
|
776
|
+
assertIOErrorInClosedStream { |zos| zos.puts "hello world" }
|
777
|
+
assertIOErrorInClosedStream { |zos| zos.write "hello world" }
|
778
|
+
end
|
779
|
+
|
780
|
+
def test_cannotOpenFile
|
781
|
+
name = TestFiles::EMPTY_TEST_DIR
|
782
|
+
begin
|
783
|
+
zos = ZipOutputStream.open(name)
|
784
|
+
rescue Exception
|
785
|
+
assert($!.kind_of?(Errno::EISDIR) || # Linux
|
786
|
+
$!.kind_of?(Errno::EEXIST) || # Windows/cygwin
|
787
|
+
$!.kind_of?(Errno::EACCES), # Windows
|
788
|
+
"Expected Errno::EISDIR (or on win/cygwin: Errno::EEXIST), but was: #{$!.type}")
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
def assertIOErrorInClosedStream
|
793
|
+
assert_exception(IOError) {
|
794
|
+
zos = ZipOutputStream.new("test_putOnClosedStream.zip")
|
795
|
+
zos.close
|
796
|
+
yield zos
|
797
|
+
}
|
798
|
+
end
|
799
|
+
|
800
|
+
def writeTestZip(zos)
|
801
|
+
TEST_ZIP.entryNames.each {
|
802
|
+
|entryName|
|
803
|
+
zos.putNextEntry(entryName)
|
804
|
+
File.open(entryName, "rb") { |f| zos.write(f.read) }
|
805
|
+
}
|
806
|
+
end
|
807
|
+
end
|
808
|
+
|
809
|
+
|
810
|
+
|
811
|
+
module Enumerable
|
812
|
+
def compareEnumerables(otherEnumerable)
|
813
|
+
otherAsArray = otherEnumerable.to_a
|
814
|
+
index=0
|
815
|
+
each_with_index {
|
816
|
+
|element, index|
|
817
|
+
return false unless yield(element, otherAsArray[index])
|
818
|
+
}
|
819
|
+
return index+1 == otherAsArray.size
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
|
824
|
+
class ZipCentralDirectoryEntryTest < RUNIT::TestCase
|
825
|
+
|
826
|
+
def test_readFromStream
|
827
|
+
File.open("testDirectory.bin", "rb") {
|
828
|
+
|file|
|
829
|
+
entry = ZipEntry.readCDirEntry(file)
|
830
|
+
|
831
|
+
assert_equals("longAscii.txt", entry.name)
|
832
|
+
assert_equals(ZipEntry::DEFLATED, entry.compressionMethod)
|
833
|
+
assert_equals(106490, entry.size)
|
834
|
+
assert_equals(3784, entry.compressedSize)
|
835
|
+
assert_equals(0xfcd1799c, entry.crc)
|
836
|
+
assert_equals("", entry.comment)
|
837
|
+
|
838
|
+
entry = ZipEntry.readCDirEntry(file)
|
839
|
+
assert_equals("empty.txt", entry.name)
|
840
|
+
assert_equals(ZipEntry::STORED, entry.compressionMethod)
|
841
|
+
assert_equals(0, entry.size)
|
842
|
+
assert_equals(0, entry.compressedSize)
|
843
|
+
assert_equals(0x0, entry.crc)
|
844
|
+
assert_equals("", entry.comment)
|
845
|
+
|
846
|
+
entry = ZipEntry.readCDirEntry(file)
|
847
|
+
assert_equals("short.txt", entry.name)
|
848
|
+
assert_equals(ZipEntry::STORED, entry.compressionMethod)
|
849
|
+
assert_equals(6, entry.size)
|
850
|
+
assert_equals(6, entry.compressedSize)
|
851
|
+
assert_equals(0xbb76fe69, entry.crc)
|
852
|
+
assert_equals("", entry.comment)
|
853
|
+
|
854
|
+
entry = ZipEntry.readCDirEntry(file)
|
855
|
+
assert_equals("longBinary.bin", entry.name)
|
856
|
+
assert_equals(ZipEntry::DEFLATED, entry.compressionMethod)
|
857
|
+
assert_equals(1000024, entry.size)
|
858
|
+
assert_equals(70847, entry.compressedSize)
|
859
|
+
assert_equals(0x10da7d59, entry.crc)
|
860
|
+
assert_equals("", entry.comment)
|
861
|
+
|
862
|
+
entry = ZipEntry.readCDirEntry(file)
|
863
|
+
assert_equals(nil, entry)
|
864
|
+
# Fields that are not check by this test:
|
865
|
+
# version made by 2 bytes
|
866
|
+
# version needed to extract 2 bytes
|
867
|
+
# general purpose bit flag 2 bytes
|
868
|
+
# last mod file time 2 bytes
|
869
|
+
# last mod file date 2 bytes
|
870
|
+
# compressed size 4 bytes
|
871
|
+
# uncompressed size 4 bytes
|
872
|
+
# disk number start 2 bytes
|
873
|
+
# internal file attributes 2 bytes
|
874
|
+
# external file attributes 4 bytes
|
875
|
+
# relative offset of local header 4 bytes
|
876
|
+
|
877
|
+
# file name (variable size)
|
878
|
+
# extra field (variable size)
|
879
|
+
# file comment (variable size)
|
880
|
+
|
881
|
+
}
|
882
|
+
end
|
883
|
+
|
884
|
+
def test_ReadEntryFromTruncatedZipFile
|
885
|
+
fragment=""
|
886
|
+
File.open("testDirectory.bin") { |f| fragment = f.read(12) } # cdir entry header is at least 46 bytes
|
887
|
+
fragment.extend(IOizeString)
|
888
|
+
entry = ZipEntry.new
|
889
|
+
entry.readCDirEntry(fragment)
|
890
|
+
fail "ZipError expected"
|
891
|
+
rescue ZipError
|
892
|
+
end
|
893
|
+
|
894
|
+
end
|
895
|
+
|
896
|
+
class ZipCentralDirectoryTest < RUNIT::TestCase
|
897
|
+
|
898
|
+
def test_readFromStream
|
899
|
+
File.open(TestZipFile::TEST_ZIP2.zipName, "rb") {
|
900
|
+
|zipFile|
|
901
|
+
cdir = ZipCentralDirectory.readFromStream(zipFile)
|
902
|
+
|
903
|
+
assert_equals(TestZipFile::TEST_ZIP2.entryNames.size, cdir.size)
|
904
|
+
assert(cdir.compareEnumerables(TestZipFile::TEST_ZIP2.entryNames) {
|
905
|
+
|cdirEntry, testEntryName|
|
906
|
+
cdirEntry.name == testEntryName
|
907
|
+
})
|
908
|
+
assert_equals(TestZipFile::TEST_ZIP2.comment, cdir.comment)
|
909
|
+
}
|
910
|
+
end
|
911
|
+
|
912
|
+
def test_readFromInvalidStream
|
913
|
+
File.open("ziptest.rb", "rb") {
|
914
|
+
|zipFile|
|
915
|
+
cdir = ZipCentralDirectory.new
|
916
|
+
cdir.readFromStream(zipFile)
|
917
|
+
}
|
918
|
+
fail "ZipError expected!"
|
919
|
+
rescue ZipError
|
920
|
+
end
|
921
|
+
|
922
|
+
def test_ReadFromTruncatedZipFile
|
923
|
+
fragment=""
|
924
|
+
File.open("testDirectory.bin") { |f| fragment = f.read }
|
925
|
+
fragment.slice!(12) # removed part of first cdir entry. eocd structure still complete
|
926
|
+
fragment.extend(IOizeString)
|
927
|
+
entry = ZipCentralDirectory.new
|
928
|
+
entry.readFromStream(fragment)
|
929
|
+
fail "ZipError expected"
|
930
|
+
rescue ZipError
|
931
|
+
end
|
932
|
+
|
933
|
+
def test_writeToStream
|
934
|
+
entries = [ ZipEntry.new("file.zip", "flimse", "myComment", "somethingExtra"),
|
935
|
+
ZipEntry.new("file.zip", "secondEntryName"),
|
936
|
+
ZipEntry.new("file.zip", "lastEntry.txt", "Has a comment too") ]
|
937
|
+
cdir = ZipCentralDirectory.new(entries, "my zip comment")
|
938
|
+
File.open("cdirtest.bin", "wb") { |f| cdir.writeToStream(f) }
|
939
|
+
cdirReadback = ZipCentralDirectory.new
|
940
|
+
File.open("cdirtest.bin", "rb") { |f| cdirReadback.readFromStream(f) }
|
941
|
+
|
942
|
+
assert_equals(cdir.entries, cdirReadback.entries)
|
943
|
+
end
|
944
|
+
|
945
|
+
def test_equality
|
946
|
+
cdir1 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil,
|
947
|
+
"somethingExtra"),
|
948
|
+
ZipEntry.new("file.zip", "secondEntryName"),
|
949
|
+
ZipEntry.new("file.zip", "lastEntry.txt") ],
|
950
|
+
"my zip comment")
|
951
|
+
cdir2 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil,
|
952
|
+
"somethingExtra"),
|
953
|
+
ZipEntry.new("file.zip", "secondEntryName"),
|
954
|
+
ZipEntry.new("file.zip", "lastEntry.txt") ],
|
955
|
+
"my zip comment")
|
956
|
+
cdir3 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil,
|
957
|
+
"somethingExtra"),
|
958
|
+
ZipEntry.new("file.zip", "secondEntryName"),
|
959
|
+
ZipEntry.new("file.zip", "lastEntry.txt") ],
|
960
|
+
"comment?")
|
961
|
+
cdir4 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil,
|
962
|
+
"somethingExtra"),
|
963
|
+
ZipEntry.new("file.zip", "lastEntry.txt") ],
|
964
|
+
"comment?")
|
965
|
+
assert_equals(cdir1, cdir1)
|
966
|
+
assert_equals(cdir1, cdir2)
|
967
|
+
|
968
|
+
assert(cdir1 != cdir3)
|
969
|
+
assert(cdir2 != cdir3)
|
970
|
+
assert(cdir2 != cdir3)
|
971
|
+
assert(cdir3 != cdir4)
|
972
|
+
|
973
|
+
assert(cdir3 != "hello")
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
977
|
+
|
978
|
+
class BasicZipFileTest < RUNIT::TestCase
|
979
|
+
include AssertEntry
|
980
|
+
|
981
|
+
def setup
|
982
|
+
@zipFile = ZipFile.new(TestZipFile::TEST_ZIP2.zipName)
|
983
|
+
@testEntryNameIndex=0
|
984
|
+
end
|
985
|
+
|
986
|
+
def nextTestEntryName
|
987
|
+
retVal=TestZipFile::TEST_ZIP2.entryNames[@testEntryNameIndex]
|
988
|
+
@testEntryNameIndex+=1
|
989
|
+
return retVal
|
990
|
+
end
|
991
|
+
|
992
|
+
def test_entries
|
993
|
+
assert_equals(TestZipFile::TEST_ZIP2.entryNames, @zipFile.entries.map {|e| e.name} )
|
994
|
+
end
|
995
|
+
|
996
|
+
def test_each
|
997
|
+
@zipFile.each {
|
998
|
+
|entry|
|
999
|
+
assert_equals(nextTestEntryName, entry.name)
|
1000
|
+
}
|
1001
|
+
assert_equals(4, @testEntryNameIndex)
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
def test_foreach
|
1005
|
+
ZipFile.foreach(TestZipFile::TEST_ZIP2.zipName) {
|
1006
|
+
|entry|
|
1007
|
+
assert_equals(nextTestEntryName, entry.name)
|
1008
|
+
}
|
1009
|
+
assert_equals(4, @testEntryNameIndex)
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
def test_getInputStream
|
1013
|
+
@zipFile.each {
|
1014
|
+
|entry|
|
1015
|
+
assertEntry(nextTestEntryName, @zipFile.getInputStream(entry),
|
1016
|
+
entry.name)
|
1017
|
+
}
|
1018
|
+
assert_equals(4, @testEntryNameIndex)
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def test_getInputStreamBlock
|
1022
|
+
fileAndEntryName = @zipFile.entries.first.name
|
1023
|
+
@zipFile.getInputStream(fileAndEntryName) {
|
1024
|
+
|zis|
|
1025
|
+
assertEntryContentsForStream(fileAndEntryName,
|
1026
|
+
zis,
|
1027
|
+
fileAndEntryName)
|
1028
|
+
}
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
|
1032
|
+
class CommonZipFileFixture < RUNIT::TestCase
|
1033
|
+
include AssertEntry
|
1034
|
+
|
1035
|
+
EMPTY_FILENAME = "emptyZipFile.zip"
|
1036
|
+
|
1037
|
+
TEST_ZIP = TestZipFile::TEST_ZIP2.clone
|
1038
|
+
TEST_ZIP.zipName = "4entry_copy.zip"
|
1039
|
+
|
1040
|
+
def setup
|
1041
|
+
File.delete(EMPTY_FILENAME) if File.exists?(EMPTY_FILENAME)
|
1042
|
+
File.copy(TestZipFile::TEST_ZIP2.zipName, TEST_ZIP.zipName)
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
class ZipFileTest < CommonZipFileFixture
|
1047
|
+
|
1048
|
+
def test_createFromScratch
|
1049
|
+
comment = "a short comment"
|
1050
|
+
|
1051
|
+
zf = ZipFile.new(EMPTY_FILENAME, ZipFile::CREATE)
|
1052
|
+
zf.comment = comment
|
1053
|
+
zf.close
|
1054
|
+
|
1055
|
+
zfRead = ZipFile.new(EMPTY_FILENAME)
|
1056
|
+
assert_equals(comment, zfRead.comment)
|
1057
|
+
assert_equals(0, zfRead.entries.length)
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
def test_add
|
1061
|
+
srcFile = "ziptest.rb"
|
1062
|
+
entryName = "newEntryName.rb"
|
1063
|
+
assert(File.exists? srcFile)
|
1064
|
+
zf = ZipFile.new(EMPTY_FILENAME, ZipFile::CREATE)
|
1065
|
+
zf.add(entryName, srcFile)
|
1066
|
+
zf.close
|
1067
|
+
|
1068
|
+
zfRead = ZipFile.new(EMPTY_FILENAME)
|
1069
|
+
assert_equals("", zfRead.comment)
|
1070
|
+
assert_equals(1, zfRead.entries.length)
|
1071
|
+
assert_equals(entryName, zfRead.entries.first.name)
|
1072
|
+
AssertEntry.assertContents(srcFile,
|
1073
|
+
zfRead.getInputStream(entryName) { |zis| zis.read })
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
def test_addExistingEntryName
|
1077
|
+
assert_exception(ZipEntryExistsError) {
|
1078
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1079
|
+
|zf|
|
1080
|
+
zf.add(zf.entries.first.name, "ziptest.rb")
|
1081
|
+
}
|
1082
|
+
}
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
def test_addExistingEntryNameReplace
|
1086
|
+
gotCalled = false
|
1087
|
+
replacedEntry = nil
|
1088
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1089
|
+
|zf|
|
1090
|
+
replacedEntry = zf.entries.first.name
|
1091
|
+
zf.add(replacedEntry, "ziptest.rb") { gotCalled = true; true }
|
1092
|
+
}
|
1093
|
+
assert(gotCalled)
|
1094
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1095
|
+
|zf|
|
1096
|
+
assertContains(zf, replacedEntry, "ziptest.rb")
|
1097
|
+
}
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
def test_addDirectory
|
1101
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1102
|
+
|zf|
|
1103
|
+
zf.add(TestFiles::EMPTY_TEST_DIR, TestFiles::EMPTY_TEST_DIR)
|
1104
|
+
}
|
1105
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1106
|
+
|zf|
|
1107
|
+
dirEntry = zf.entries.detect { |e| e.name == TestFiles::EMPTY_TEST_DIR+"/" }
|
1108
|
+
assert(dirEntry.isDirectory)
|
1109
|
+
}
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
def test_remove
|
1113
|
+
entryToRemove, *remainingEntries = TEST_ZIP.entryNames
|
1114
|
+
|
1115
|
+
File.copy(TestZipFile::TEST_ZIP2.zipName, TEST_ZIP.zipName)
|
1116
|
+
|
1117
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1118
|
+
assert(zf.entries.map { |e| e.name }.include?(entryToRemove))
|
1119
|
+
zf.remove(entryToRemove)
|
1120
|
+
assert(! zf.entries.map { |e| e.name }.include?(entryToRemove))
|
1121
|
+
assert_equals(zf.entries.map {|x| x.name }.sort, remainingEntries.sort)
|
1122
|
+
zf.close
|
1123
|
+
|
1124
|
+
zfRead = ZipFile.new(TEST_ZIP.zipName)
|
1125
|
+
assert(! zfRead.entries.map { |e| e.name }.include?(entryToRemove))
|
1126
|
+
assert_equals(zfRead.entries.map {|x| x.name }.sort, remainingEntries.sort)
|
1127
|
+
zfRead.close
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
|
1131
|
+
def test_rename
|
1132
|
+
entryToRename, *remainingEntries = TEST_ZIP.entryNames
|
1133
|
+
|
1134
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1135
|
+
assert(zf.entries.map { |e| e.name }.include? entryToRename)
|
1136
|
+
|
1137
|
+
newName = "changed name"
|
1138
|
+
assert(! zf.entries.map { |e| e.name }.include?(newName))
|
1139
|
+
|
1140
|
+
zf.rename(entryToRename, newName)
|
1141
|
+
assert(zf.entries.map { |e| e.name }.include? newName)
|
1142
|
+
|
1143
|
+
zf.close
|
1144
|
+
|
1145
|
+
zfRead = ZipFile.new(TEST_ZIP.zipName)
|
1146
|
+
assert(zfRead.entries.map { |e| e.name }.include? newName)
|
1147
|
+
zfRead.close
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
def test_renameToExistingEntry
|
1151
|
+
oldEntries = nil
|
1152
|
+
ZipFile.open(TEST_ZIP.zipName) { |zf| oldEntries = zf.entries }
|
1153
|
+
|
1154
|
+
assert_exception(ZipEntryExistsError) {
|
1155
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1156
|
+
|zf|
|
1157
|
+
zf.rename(zf.entries[0], zf.entries[1].name)
|
1158
|
+
}
|
1159
|
+
}
|
1160
|
+
|
1161
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1162
|
+
|zf|
|
1163
|
+
assert_equals(oldEntries.map{ |e| e.name }, zf.entries.map{ |e| e.name })
|
1164
|
+
}
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
def test_renameToExistingEntryOverwrite
|
1168
|
+
oldEntries = nil
|
1169
|
+
ZipFile.open(TEST_ZIP.zipName) { |zf| oldEntries = zf.entries }
|
1170
|
+
|
1171
|
+
gotCalled = false
|
1172
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1173
|
+
|zf|
|
1174
|
+
zf.rename(zf.entries[0], zf.entries[1].name) { gotCalled = true; true }
|
1175
|
+
}
|
1176
|
+
|
1177
|
+
assert(gotCalled)
|
1178
|
+
oldEntries.delete_at(0)
|
1179
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1180
|
+
|zf|
|
1181
|
+
assert_equals(oldEntries.map{ |e| e.name },
|
1182
|
+
zf.entries.map{ |e| e.name })
|
1183
|
+
}
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
def test_renameNonEntry
|
1187
|
+
nonEntry = "bogusEntry"
|
1188
|
+
targetEntry = "targetEntryName"
|
1189
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1190
|
+
assert(! zf.entries.include?(nonEntry))
|
1191
|
+
assert_exception(ZipNoSuchEntryError) {
|
1192
|
+
zf.rename(nonEntry, targetEntry)
|
1193
|
+
}
|
1194
|
+
zf.commit
|
1195
|
+
assert(! zf.entries.include?(targetEntry))
|
1196
|
+
ensure
|
1197
|
+
zf.close
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
def test_renameEntryToExistingEntry
|
1201
|
+
entry1, entry2, *remaining = TEST_ZIP.entryNames
|
1202
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1203
|
+
assert_exception(ZipEntryExistsError) {
|
1204
|
+
zf.rename(entry1, entry2)
|
1205
|
+
}
|
1206
|
+
ensure
|
1207
|
+
zf.close
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
def test_replace
|
1211
|
+
unchangedEntries = TEST_ZIP.entryNames.dup
|
1212
|
+
entryToReplace = unchangedEntries.delete_at(2)
|
1213
|
+
newEntrySrcFilename = "ziptest.rb"
|
1214
|
+
|
1215
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1216
|
+
zf.replace(entryToReplace, newEntrySrcFilename)
|
1217
|
+
|
1218
|
+
zf.close
|
1219
|
+
|
1220
|
+
zfRead = ZipFile.new(TEST_ZIP.zipName)
|
1221
|
+
AssertEntry::assertContents(newEntrySrcFilename,
|
1222
|
+
zfRead.getInputStream(entryToReplace) { |is| is.read })
|
1223
|
+
zfRead.close
|
1224
|
+
end
|
1225
|
+
|
1226
|
+
def test_replaceNonEntry
|
1227
|
+
entryToReplace = "nonExistingEntryname"
|
1228
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1229
|
+
|zf|
|
1230
|
+
assert_exception(ZipNoSuchEntryError) {
|
1231
|
+
zf.replace(entryToReplace, "ziptest.rb")
|
1232
|
+
}
|
1233
|
+
}
|
1234
|
+
end
|
1235
|
+
|
1236
|
+
def test_commit
|
1237
|
+
newName = "renamedFirst"
|
1238
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1239
|
+
oldName = zf.entries.first
|
1240
|
+
zf.rename(oldName, newName)
|
1241
|
+
zf.commit
|
1242
|
+
|
1243
|
+
zfRead = ZipFile.new(TEST_ZIP.zipName)
|
1244
|
+
assert(zfRead.entries.detect { |e| e.name == newName } != nil)
|
1245
|
+
assert(zfRead.entries.detect { |e| e.name == oldName } == nil)
|
1246
|
+
zfRead.close
|
1247
|
+
|
1248
|
+
zf.close
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
# This test tests that after commit, you
|
1252
|
+
# can delete the file you used to add the entry to the zip file
|
1253
|
+
# with
|
1254
|
+
def test_commitUseZipEntry
|
1255
|
+
File.copy(TestFiles::RANDOM_ASCII_FILE1, "okToDelete.txt")
|
1256
|
+
zf = ZipFile.open(TEST_ZIP.zipName)
|
1257
|
+
zf.add("okToDelete.txt", "okToDelete.txt")
|
1258
|
+
assertContains(zf, "okToDelete.txt")
|
1259
|
+
zf.commit
|
1260
|
+
File.move("okToDelete.txt", "okToDeleteMoved.txt")
|
1261
|
+
assertContains(zf, "okToDelete.txt", "okToDeleteMoved.txt")
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
# def test_close
|
1265
|
+
# zf = ZipFile.new(TEST_ZIP.zipName)
|
1266
|
+
# zf.close
|
1267
|
+
# assert_exception(IOError) {
|
1268
|
+
# zf.extract(TEST_ZIP.entryNames.first, "hullubullu")
|
1269
|
+
# }
|
1270
|
+
# end
|
1271
|
+
|
1272
|
+
def test_compound1
|
1273
|
+
renamedName = "renamedName"
|
1274
|
+
originalEntries = []
|
1275
|
+
begin
|
1276
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1277
|
+
originalEntries = zf.entries.dup
|
1278
|
+
|
1279
|
+
assertNotContains(zf, TestFiles::RANDOM_ASCII_FILE1)
|
1280
|
+
zf.add(TestFiles::RANDOM_ASCII_FILE1,
|
1281
|
+
TestFiles::RANDOM_ASCII_FILE1)
|
1282
|
+
assertContains(zf, TestFiles::RANDOM_ASCII_FILE1)
|
1283
|
+
|
1284
|
+
zf.rename(zf.entries[0], renamedName)
|
1285
|
+
assertContains(zf, renamedName)
|
1286
|
+
|
1287
|
+
TestFiles::BINARY_TEST_FILES.each {
|
1288
|
+
|filename|
|
1289
|
+
zf.add(filename, filename)
|
1290
|
+
assertContains(zf, filename)
|
1291
|
+
}
|
1292
|
+
|
1293
|
+
assertContains(zf, originalEntries.last.to_s)
|
1294
|
+
zf.remove(originalEntries.last.to_s)
|
1295
|
+
assertNotContains(zf, originalEntries.last.to_s)
|
1296
|
+
|
1297
|
+
ensure
|
1298
|
+
zf.close
|
1299
|
+
end
|
1300
|
+
begin
|
1301
|
+
zfRead = ZipFile.new(TEST_ZIP.zipName)
|
1302
|
+
assertContains(zfRead, TestFiles::RANDOM_ASCII_FILE1)
|
1303
|
+
assertContains(zfRead, renamedName)
|
1304
|
+
TestFiles::BINARY_TEST_FILES.each {
|
1305
|
+
|filename|
|
1306
|
+
assertContains(zfRead, filename)
|
1307
|
+
}
|
1308
|
+
assertNotContains(zfRead, originalEntries.last.to_s)
|
1309
|
+
ensure
|
1310
|
+
zfRead.close
|
1311
|
+
end
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
def test_compound2
|
1315
|
+
begin
|
1316
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1317
|
+
originalEntries = zf.entries.dup
|
1318
|
+
|
1319
|
+
originalEntries.each {
|
1320
|
+
|entry|
|
1321
|
+
zf.remove(entry)
|
1322
|
+
assertNotContains(zf, entry)
|
1323
|
+
}
|
1324
|
+
assert(zf.entries.empty?)
|
1325
|
+
|
1326
|
+
TestFiles::ASCII_TEST_FILES.each {
|
1327
|
+
|filename|
|
1328
|
+
zf.add(filename, filename)
|
1329
|
+
assertContains(zf, filename)
|
1330
|
+
}
|
1331
|
+
assert_equals(zf.entries.map { |e| e.name }, TestFiles::ASCII_TEST_FILES)
|
1332
|
+
|
1333
|
+
zf.rename(TestFiles::ASCII_TEST_FILES[0], "newName")
|
1334
|
+
assertNotContains(zf, TestFiles::ASCII_TEST_FILES[0])
|
1335
|
+
assertContains(zf, "newName")
|
1336
|
+
ensure
|
1337
|
+
zf.close
|
1338
|
+
end
|
1339
|
+
begin
|
1340
|
+
zfRead = ZipFile.new(TEST_ZIP.zipName)
|
1341
|
+
asciiTestFiles = TestFiles::ASCII_TEST_FILES.dup
|
1342
|
+
asciiTestFiles.shift
|
1343
|
+
asciiTestFiles.each {
|
1344
|
+
|filename|
|
1345
|
+
assertContains(zf, filename)
|
1346
|
+
}
|
1347
|
+
|
1348
|
+
assertContains(zf, "newName")
|
1349
|
+
ensure
|
1350
|
+
zfRead.close
|
1351
|
+
end
|
1352
|
+
end
|
1353
|
+
|
1354
|
+
private
|
1355
|
+
def assertContains(zf, entryName, filename = entryName)
|
1356
|
+
assert(zf.entries.detect { |e| e.name == entryName} != nil, "entry #{entryName} not in #{zf.entries.join(', ')} in zip file #{zf}")
|
1357
|
+
assertEntryContents(zf, entryName, filename) if File.exists?(filename)
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
def assertNotContains(zf, entryName)
|
1361
|
+
assert(zf.entries.detect { |e| e.name == entryName} == nil, "entry #{entryName} in #{zf.entries.join(', ')} in zip file #{zf}")
|
1362
|
+
end
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
class ZipFileExtractTest < CommonZipFileFixture
|
1366
|
+
EXTRACTED_FILENAME = "extEntry"
|
1367
|
+
ENTRY_TO_EXTRACT, *REMAINING_ENTRIES = TEST_ZIP.entryNames.reverse
|
1368
|
+
|
1369
|
+
def setup
|
1370
|
+
super
|
1371
|
+
File.delete(EXTRACTED_FILENAME) if File.exists?(EXTRACTED_FILENAME)
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
def test_extract
|
1375
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1376
|
+
|zf|
|
1377
|
+
zf.extract(ENTRY_TO_EXTRACT, EXTRACTED_FILENAME)
|
1378
|
+
|
1379
|
+
assert(File.exists? EXTRACTED_FILENAME)
|
1380
|
+
AssertEntry::assertContents(EXTRACTED_FILENAME,
|
1381
|
+
zf.getInputStream(ENTRY_TO_EXTRACT) { |is| is.read })
|
1382
|
+
}
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
def test_extractExists
|
1386
|
+
writtenText = "written text"
|
1387
|
+
File.open(EXTRACTED_FILENAME, "w") { |f| f.write(writtenText) }
|
1388
|
+
|
1389
|
+
assert_exception(ZipDestinationFileExistsError) {
|
1390
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1391
|
+
|zf|
|
1392
|
+
zf.extract(zf.entries.first, EXTRACTED_FILENAME)
|
1393
|
+
}
|
1394
|
+
}
|
1395
|
+
File.open(EXTRACTED_FILENAME, "r") {
|
1396
|
+
|f|
|
1397
|
+
assert_equals(writtenText, f.read)
|
1398
|
+
}
|
1399
|
+
end
|
1400
|
+
|
1401
|
+
def test_extractExistsOverwrite
|
1402
|
+
writtenText = "written text"
|
1403
|
+
File.open(EXTRACTED_FILENAME, "w") { |f| f.write(writtenText) }
|
1404
|
+
|
1405
|
+
gotCalled = false
|
1406
|
+
ZipFile.open(TEST_ZIP.zipName) {
|
1407
|
+
|zf|
|
1408
|
+
zf.extract(zf.entries.first, EXTRACTED_FILENAME) { gotCalled = true; true }
|
1409
|
+
}
|
1410
|
+
|
1411
|
+
assert(gotCalled)
|
1412
|
+
File.open(EXTRACTED_FILENAME, "r") {
|
1413
|
+
|f|
|
1414
|
+
assert(writtenText != f.read)
|
1415
|
+
}
|
1416
|
+
end
|
1417
|
+
|
1418
|
+
def test_extractNonEntry
|
1419
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1420
|
+
assert_exception(ZipNoSuchEntryError) { zf.extract("nonExistingEntry", "nonExistingEntry") }
|
1421
|
+
ensure
|
1422
|
+
zf.close if zf
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
def test_extractNonEntry2
|
1426
|
+
outFile = "outfile"
|
1427
|
+
assert_exception(ZipNoSuchEntryError) {
|
1428
|
+
zf = ZipFile.new(TEST_ZIP.zipName)
|
1429
|
+
nonEntry = "hotdog-diddelidoo"
|
1430
|
+
assert(! zf.entries.include?(nonEntry))
|
1431
|
+
zf.extract(nonEntry, outFile)
|
1432
|
+
zf.close
|
1433
|
+
}
|
1434
|
+
assert(! File.exists?(outFile))
|
1435
|
+
end
|
1436
|
+
|
1437
|
+
end
|
1438
|
+
|
1439
|
+
class ZipFileExtractDirectoryTest < CommonZipFileFixture
|
1440
|
+
TEST_OUT_NAME = "emptyOutDir"
|
1441
|
+
|
1442
|
+
def openZip(&aProc)
|
1443
|
+
assert(aProc != nil)
|
1444
|
+
ZipFile.open(TestZipFile::TEST_ZIP4.zipName, &aProc)
|
1445
|
+
end
|
1446
|
+
|
1447
|
+
def extractTestDir(&aProc)
|
1448
|
+
openZip {
|
1449
|
+
|zf|
|
1450
|
+
zf.extract(TestFiles::EMPTY_TEST_DIR, TEST_OUT_NAME, &aProc)
|
1451
|
+
}
|
1452
|
+
end
|
1453
|
+
|
1454
|
+
def setup
|
1455
|
+
super
|
1456
|
+
|
1457
|
+
Dir.rmdir(TEST_OUT_NAME) if File.directory? TEST_OUT_NAME
|
1458
|
+
File.delete(TEST_OUT_NAME) if File.exists? TEST_OUT_NAME
|
1459
|
+
end
|
1460
|
+
|
1461
|
+
def test_extractDirectory
|
1462
|
+
extractTestDir
|
1463
|
+
assert(File.directory? TEST_OUT_NAME)
|
1464
|
+
end
|
1465
|
+
|
1466
|
+
def test_extractDirectoryExistsAsDir
|
1467
|
+
Dir.mkdir TEST_OUT_NAME
|
1468
|
+
extractTestDir
|
1469
|
+
assert(File.directory? TEST_OUT_NAME)
|
1470
|
+
end
|
1471
|
+
|
1472
|
+
def test_extractDirectoryExistsAsFile
|
1473
|
+
File.open(TEST_OUT_NAME, "w") { |f| f.puts "something" }
|
1474
|
+
assert_exception(ZipDestinationFileExistsError) { extractTestDir }
|
1475
|
+
end
|
1476
|
+
|
1477
|
+
def test_extractDirectoryExistsAsFileOverwrite
|
1478
|
+
File.open(TEST_OUT_NAME, "w") { |f| f.puts "something" }
|
1479
|
+
gotCalled = false
|
1480
|
+
extractTestDir {
|
1481
|
+
|entry, destPath|
|
1482
|
+
gotCalled = true
|
1483
|
+
assert_equals(TEST_OUT_NAME, destPath)
|
1484
|
+
assert(entry.isDirectory)
|
1485
|
+
true
|
1486
|
+
}
|
1487
|
+
assert(gotCalled)
|
1488
|
+
assert(File.directory? TEST_OUT_NAME)
|
1489
|
+
end
|
1490
|
+
end
|
1491
|
+
|
1492
|
+
|
1493
|
+
TestFiles::createTestFiles(ARGV.index("recreate") != nil ||
|
1494
|
+
ARGV.index("recreateonly") != nil)
|
1495
|
+
TestZipFile::createTestZips(ARGV.index("recreate") != nil ||
|
1496
|
+
ARGV.index("recreateonly") != nil)
|
1497
|
+
exit if ARGV.index("recreateonly") != nil
|
1498
|
+
|
1499
|
+
#require 'runit/cui/testrunner'
|
1500
|
+
#RUNIT::CUI::TestRunner.run(ZipFileTest.suite)
|
1501
|
+
|
1502
|
+
# Copyright (C) 2002 Thomas Sondergaard
|
1503
|
+
# rubyzip is free software; you can redistribute it and/or
|
1504
|
+
# modify it under the terms of the ruby license.
|