ruby-ole-patched-for-home_run 1.2.10.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/test/test_mbat.rb ADDED
@@ -0,0 +1,41 @@
1
+ #! /usr/bin/ruby
2
+
3
+ $: << File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'test/unit'
6
+ require 'ole/storage/base'
7
+ require 'ole/storage/file_system'
8
+ require 'tempfile'
9
+
10
+ class TestWriteMbat < Test::Unit::TestCase
11
+ def test_write_mbat
12
+ Tempfile.open 'myolefile' do |temp|
13
+ temp.binmode
14
+
15
+ # this used to raise an error at flush time, due to failure to write the mbat
16
+ Ole::Storage.open temp do |ole|
17
+ # create a 10mb file
18
+ ole.file.open 'myfile', 'w' do |f|
19
+ s = 0.chr * 1_000_000
20
+ 10.times { f.write s }
21
+ end
22
+ end
23
+
24
+ assert((10_000_000..10_100_000) === temp.size, 'check file size')
25
+
26
+ Ole::Storage.open temp do |ole|
27
+ assert_equal 10_000_000, ole.file.size('myfile')
28
+ compare = ole.bbat.truncate[(0...ole.bbat.length).find { |i| ole.bbat[i] > 50_000 }..-1]
29
+ c = Ole::Storage::AllocationTable
30
+ # 10_000_000 * 4 / 512 / 512 rounded up is 153. but then there is room needed to store the
31
+ # bat in the bat, and the mbat too. hence 154.
32
+ expect = [c::EOC] * 2 + [c::BAT] * 154 + [c::META_BAT]
33
+ assert_equal expect, compare, 'allocation table structure'
34
+ # the sbat should be empty. in fact the file shouldn't exist at all, so the root's first
35
+ # block should be EOC
36
+ assert ole.sbat.empty?
37
+ assert_equal c::EOC, ole.root.first_block
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ #! /usr/bin/ruby
2
+
3
+ $: << File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'test/unit'
6
+ require 'ole/storage/base'
7
+ require 'ole/storage/meta_data'
8
+ require 'ole/storage/file_system'
9
+
10
+ class TestMetaData < Test::Unit::TestCase
11
+ def test_meta_data
12
+ Ole::Storage.open File.dirname(__FILE__) + '/test.doc', 'rb' do |ole|
13
+ assert_equal 'Charles Lowe', ole.meta_data[:doc_author]
14
+ assert_equal 'Charles Lowe', ole.meta_data['doc_author']
15
+ assert_equal 'Charles Lowe', ole.meta_data.to_h[:doc_author]
16
+ assert_equal 'Title', ole.meta_data.doc_title
17
+ assert_equal 'MSWordDoc', ole.meta_data.file_format
18
+ assert_equal 'application/msword', ole.meta_data.mime_type
19
+ assert_raises NotImplementedError do
20
+ ole.meta_data[:doc_author] = 'New Author'
21
+ end
22
+ end
23
+ end
24
+
25
+ # this tests the other ways of getting the mime_type, than using "\001CompObj",
26
+ # ie, relying on root clsid, and on the heuristics
27
+ def test_mime_type
28
+ ole = Ole::Storage.new StringIO.new
29
+ ole.root.clsid = Ole::Storage::MetaData::CLSID_EXCEL97.to_s
30
+ assert_equal nil, ole.meta_data.file_format
31
+ assert_equal 'application/vnd.ms-excel', ole.meta_data.mime_type
32
+
33
+ ole.root.clsid = 0.chr * Ole::Types::Clsid::SIZE
34
+ assert_equal nil, ole.meta_data.file_format
35
+ assert_equal 'application/x-ole-storage', ole.meta_data.mime_type
36
+
37
+ ole.file.open('Book', 'w') { |f| }
38
+ assert_equal 'application/vnd.ms-excel', ole.meta_data.mime_type
39
+ ole.file.open('WordDocument', 'w') { |f| }
40
+ assert_equal 'application/msword', ole.meta_data.mime_type
41
+ ole.file.open('__properties_version1.0', 'w') { |f| }
42
+ assert_equal 'application/vnd.ms-outlook', ole.meta_data.mime_type
43
+ end
44
+ end
45
+
@@ -0,0 +1,40 @@
1
+ #! /usr/bin/ruby
2
+
3
+ $: << File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'test/unit'
6
+ require 'ole/types/property_set'
7
+
8
+ class TestPropertySet < Test::Unit::TestCase
9
+ include Ole::Types
10
+
11
+ def setup
12
+ @io = open File.dirname(__FILE__) + '/test_SummaryInformation', 'rb'
13
+ end
14
+
15
+ def teardown
16
+ @io.close
17
+ end
18
+
19
+ def test_property_set
20
+ propset = PropertySet.new @io
21
+ assert_equal :mac, propset.os
22
+ assert_equal 1, propset.sections.length
23
+ section = propset.sections.first
24
+ assert_equal 14, section.length
25
+ assert_equal 'f29f85e0-4ff9-1068-ab91-08002b27b3d9', section.guid.format
26
+ assert_equal PropertySet::FMTID_SummaryInformation, section.guid
27
+ assert_equal 'Charles Lowe', section.to_a.assoc(4).last
28
+ assert_equal 'Charles Lowe', propset.doc_author
29
+ assert_equal 'Charles Lowe', propset.to_h[:doc_author]
30
+
31
+ # knows the difference between existent and non-existent properties
32
+ assert_raise(NoMethodError) { propset.non_existent_key }
33
+ assert_raise(NotImplementedError) { propset.doc_author = 'New Author'}
34
+ assert_raise(NoMethodError) { propset.non_existent_key = 'Value'}
35
+
36
+ # a valid property that has no value in this property set
37
+ assert_equal nil, propset.security
38
+ end
39
+ end
40
+
@@ -0,0 +1,103 @@
1
+ #! /usr/bin/ruby
2
+
3
+ $: << File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'test/unit'
6
+ require 'ole/ranges_io'
7
+ require 'stringio'
8
+
9
+ class TestRangesIO < Test::Unit::TestCase
10
+ TEST_DIR = File.dirname __FILE__
11
+
12
+ def setup
13
+ # read from ourself, also using overlaps.
14
+ ranges = [100..200, 0..10, 100..150]
15
+ @io = RangesIO.new open("#{TEST_DIR}/test_ranges_io.rb"), :ranges => ranges, :close_parent => true
16
+ end
17
+
18
+ def teardown
19
+ @io.close
20
+ end
21
+
22
+ def test_open
23
+ # block form
24
+ f = open("#{TEST_DIR}/test_ranges_io.rb")
25
+ assert_equal false, f.closed?
26
+ RangesIO.open f, :ranges => []
27
+ assert_equal false, f.closed?
28
+ RangesIO.open(f, :ranges => [], :close_parent => true) {}
29
+ assert_equal true, f.closed?
30
+ end
31
+
32
+ def test_basics
33
+ assert_equal 160, @io.size
34
+ assert_match %r{size=160}, @io.inspect
35
+ end
36
+
37
+ def test_truncate
38
+ assert_raises(NotImplementedError) { @io.size += 10 }
39
+ end
40
+
41
+ def test_seek
42
+ @io.pos = 10
43
+ @io.seek(-100, IO::SEEK_END)
44
+ @io.seek(-10, IO::SEEK_CUR)
45
+ @io.pos += 20
46
+ assert_equal 70, @io.pos
47
+ # seeking past the end doesn't throw an exception for normal
48
+ # files, even in read mode, but RangesIO does
49
+ assert_raises(Errno::EINVAL) { @io.seek 500 }
50
+ assert_raises(Errno::EINVAL) { @io.seek(-500, IO::SEEK_END) }
51
+ assert_raises(Errno::EINVAL) { @io.seek 1, 10 }
52
+ end
53
+
54
+ def test_read
55
+ # this will map to the start of the file:
56
+ @io.pos = 100
57
+ assert_equal '#! /usr/bi', @io.read(10)
58
+ # test selection of initial range, offset within that range
59
+ pos = 80
60
+ @io.seek pos
61
+ # test advancing of pos properly, by...
62
+ chunked = (0...10).map { @io.read 10 }.join
63
+ # given the file is 160 long:
64
+ assert_equal 80, chunked.length
65
+ @io.seek pos
66
+ # comparing with a flat read
67
+ assert_equal chunked, @io.read(80)
68
+ end
69
+
70
+ # should test gets, lineno, and other IO methods we want to have
71
+ def test_gets
72
+ assert_equal "io'\n", @io.gets
73
+ end
74
+
75
+ def test_write
76
+ str = File.read "#{TEST_DIR}/test_ranges_io.rb"
77
+ @io = RangesIO.new StringIO.new(str), :ranges => @io.ranges
78
+ assert_equal "io'\nrequir", str[100, 10]
79
+ @io.write 'testing testing'
80
+ assert_equal 'testing te', str[100, 10]
81
+ @io.seek 0
82
+ assert_equal 'testing te', @io.read(10)
83
+ # lets write over a range barrier
84
+ assert_equal '#! /usr/bi', str[0, 10]
85
+ assert_equal "LE__\n\n\tdef", str[195, 10]
86
+ @io.write 'x' * 100
87
+ assert_equal 'x' * 10, str[0, 10]
88
+ assert_equal "xxxxx\n\tdef", str[195, 10]
89
+ # write enough to overflow the file
90
+ assert_raises(IOError) { @io.write 'x' * 60 }
91
+ end
92
+
93
+ def test_non_resizeable
94
+ # will try to truncate, which will fail
95
+ assert_raises NotImplementedError do
96
+ @io = RangesIO.new(StringIO.new, 'w', :ranges => [])
97
+ end
98
+ # will be fine
99
+ @io = RangesIONonResizeable.new(StringIO.new, 'w', :ranges => [])
100
+ assert_equal '#<IO::Mode wronly|creat>', @io.instance_variable_get(:@mode).inspect
101
+ end
102
+ end
103
+
@@ -0,0 +1,220 @@
1
+ #! /usr/bin/ruby
2
+
3
+ $: << File.dirname(__FILE__) + '/../lib'
4
+ #require 'rubygems'
5
+
6
+ require 'test/unit'
7
+ require 'ole/storage'
8
+ require 'digest/sha1'
9
+ require 'stringio'
10
+ require 'tempfile'
11
+
12
+ #
13
+ # = TODO
14
+ #
15
+ # These tests could be a lot more complete.
16
+ #
17
+
18
+ # should test resizeable and migrateable IO.
19
+
20
+ class TestStorageRead < Test::Unit::TestCase
21
+ TEST_DIR = File.dirname __FILE__
22
+
23
+ def setup
24
+ @ole = Ole::Storage.open "#{TEST_DIR}/test_word_6.doc", 'rb'
25
+ end
26
+
27
+ def teardown
28
+ @ole.close
29
+ end
30
+
31
+ def test_header
32
+ # should have further header tests, testing the validation etc.
33
+ assert_equal 17, @ole.header.to_a.length
34
+ assert_equal 117, @ole.header.dirent_start
35
+ assert_equal 1, @ole.header.num_bat
36
+ assert_equal 1, @ole.header.num_sbat
37
+ assert_equal 0, @ole.header.num_mbat
38
+ end
39
+
40
+ def test_new_without_explicit_mode
41
+ open "#{TEST_DIR}/test_word_6.doc", 'rb' do |f|
42
+ assert_equal false, Ole::Storage.new(f).writeable
43
+ end
44
+ end
45
+
46
+ def capture_warnings
47
+ @warn = []
48
+ outer_warn = @warn
49
+ old_log = Ole::Log
50
+ old_verbose = $VERBOSE
51
+ begin
52
+ $VERBOSE = nil
53
+ Ole.const_set :Log, Object.new
54
+ # restore for the yield
55
+ $VERBOSE = old_verbose
56
+ (class << Ole::Log; self; end).send :define_method, :warn do |message|
57
+ outer_warn << message
58
+ end
59
+ yield
60
+ ensure
61
+ $VERBOSE = nil
62
+ Ole.const_set :Log, old_log
63
+ $VERBOSE = old_verbose
64
+ end
65
+ end
66
+
67
+ def test_invalid
68
+ assert_raises Ole::Storage::FormatError do
69
+ Ole::Storage.open StringIO.new(0.chr * 1024)
70
+ end
71
+ assert_raises Ole::Storage::FormatError do
72
+ Ole::Storage.open StringIO.new(Ole::Storage::Header::MAGIC + 0.chr * 1024)
73
+ end
74
+ capture_warnings do
75
+ head = Ole::Storage::Header.new
76
+ head.threshold = 1024
77
+ assert_raises NoMethodError do
78
+ Ole::Storage.open StringIO.new(head.to_s + 0.chr * 1024)
79
+ end
80
+ end
81
+ assert_equal ['may not be a valid OLE2 structured storage file'], @warn
82
+ end
83
+
84
+ def test_inspect
85
+ assert_match(/#<Ole::Storage io=#<File:.*?test_word_6.doc> root=#<Dirent:"Root Entry">>/, @ole.inspect)
86
+ end
87
+
88
+ def test_fat
89
+ # the fat block has all the numbers from 5..118 bar 117
90
+ bbat_table = [112] + ((5..118).to_a - [112, 117])
91
+ assert_equal bbat_table, @ole.bbat.reject { |i| i >= (1 << 32) - 3 }, 'bbat'
92
+ sbat_table = (1..43).to_a - [2, 3]
93
+ assert_equal sbat_table, @ole.sbat.reject { |i| i >= (1 << 32) - 3 }, 'sbat'
94
+ end
95
+
96
+ def test_directories
97
+ assert_equal 5, @ole.dirents.length, 'have all directories'
98
+ # a more complicated one would be good for this
99
+ assert_equal 4, @ole.root.children.length, 'properly nested directories'
100
+ end
101
+
102
+ def test_utf16_conversion
103
+ assert_equal 'Root Entry', @ole.root.name
104
+ assert_equal 'WordDocument', @ole.root.children[2].name
105
+ end
106
+
107
+ def test_read
108
+ # the regular String#hash was different on the mac, so asserting
109
+ # against full strings. switch this to sha1 instead of this fugly blob
110
+ sha1sums = %w[
111
+ d3d1cde9eb43ed4b77d197af879f5ca8b8837577
112
+ 65b75cbdd1f94ade632baeeb0848dec2a342c844
113
+ cfc230ec7515892cfdb85e4a173e0ce364094970
114
+ ffd859d94647a11b693f06f092d1a2bccc59d50d
115
+ ]
116
+
117
+ # test the ole storage type
118
+ type = 'Microsoft Word 6.0-Dokument'
119
+ assert_equal type, (@ole.root/"\001CompObj").read[32..-1][/([^\x00]+)/m, 1]
120
+ # i was actually not loading data correctly before, so carefully check everything here
121
+ assert_equal sha1sums, @ole.root.children.map { |child| Digest::SHA1.hexdigest child.read }
122
+ end
123
+
124
+ def test_dirent
125
+ dirent = @ole.root.children.first
126
+ assert_equal "\001Ole", dirent.name
127
+ assert_equal 20, dirent.size
128
+ assert_equal '#<Dirent:"Root Entry">', @ole.root.inspect
129
+
130
+ # exercise Dirent#[]. note that if you use a number, you get the Struct
131
+ # fields.
132
+ assert_equal dirent, @ole.root["\001Ole"]
133
+ assert_equal dirent.name_utf16, dirent[0]
134
+ assert_equal nil, @ole.root.time
135
+
136
+ assert_equal @ole.root.children, @ole.root.to_enum(:each_child).to_a
137
+
138
+ dirent.open('r') { |f| assert_equal 2, f.first_block }
139
+ dirent.open('w') { |f| }
140
+ dirent.open('a') { |f| }
141
+ end
142
+
143
+ def test_delete
144
+ dirent = @ole.root.children.first
145
+ assert_raises(ArgumentError) { @ole.root.delete nil }
146
+ assert_equal [dirent], @ole.root.children & [dirent]
147
+ assert_equal 20, dirent.size
148
+ @ole.root.delete dirent
149
+ assert_equal [], @ole.root.children & [dirent]
150
+ assert_equal 0, dirent.size
151
+ end
152
+ end
153
+
154
+ class TestStorageWrite < Test::Unit::TestCase
155
+ TEST_DIR = File.dirname __FILE__
156
+
157
+ def sha1 str
158
+ Digest::SHA1.hexdigest str
159
+ end
160
+
161
+ # try and test all the various things the #flush function does
162
+ def test_flush
163
+ end
164
+
165
+ # FIXME
166
+ # don't really want to lock down the actual internal api's yet. this will just
167
+ # ensure for the time being that #flush continues to work properly. need a host
168
+ # of checks involving writes that resize their file bigger/smaller, that resize
169
+ # the bats to more blocks, that resizes the sb_blocks, that has migration etc.
170
+ def test_write_hash
171
+ io = StringIO.open open("#{TEST_DIR}/test_word_6.doc", 'rb', &:read)
172
+ assert_equal '9974e354def8471225f548f82b8d81c701221af7', sha1(io.string)
173
+ Ole::Storage.open(io, :update_timestamps => false) { }
174
+ # hash changed. used to be efa8cfaf833b30b1d1d9381771ddaafdfc95305c
175
+ # thats because i now truncate the io, and am probably removing some trailing
176
+ # allocated available blocks.
177
+ assert_equal 'a39e3c4041b8a893c753d50793af8d21ca8f0a86', sha1(io.string)
178
+ # add a repack test here
179
+ Ole::Storage.open io, :update_timestamps => false, &:repack
180
+ assert_equal 'c8bb9ccacf0aaad33677e1b2a661ee6e66a48b5a', sha1(io.string)
181
+ end
182
+
183
+ def test_plain_repack
184
+ io = StringIO.open open("#{TEST_DIR}/test_word_6.doc", 'rb', &:read)
185
+ assert_equal '9974e354def8471225f548f82b8d81c701221af7', sha1(io.string)
186
+ Ole::Storage.open io, :update_timestamps => false, &:repack
187
+ # note equivalence to the above flush, repack, flush
188
+ assert_equal 'c8bb9ccacf0aaad33677e1b2a661ee6e66a48b5a', sha1(io.string)
189
+ # lets do it again using memory backing
190
+ Ole::Storage.open(io, :update_timestamps => false) { |ole| ole.repack :mem }
191
+ # note equivalence to the above flush, repack, flush
192
+ assert_equal 'c8bb9ccacf0aaad33677e1b2a661ee6e66a48b5a', sha1(io.string)
193
+ assert_raises ArgumentError do
194
+ Ole::Storage.open(io, :update_timestamps => false) { |ole| ole.repack :typo }
195
+ end
196
+ end
197
+
198
+ def test_create_from_scratch_hash
199
+ io = StringIO.new('')
200
+ Ole::Storage.open(io) { }
201
+ assert_equal '6bb9d6c1cdf1656375e30991948d70c5fff63d57', sha1(io.string)
202
+ # more repack test, note invariance
203
+ Ole::Storage.open io, :update_timestamps => false, &:repack
204
+ assert_equal '6bb9d6c1cdf1656375e30991948d70c5fff63d57', sha1(io.string)
205
+ end
206
+
207
+ def test_create_dirent
208
+ Ole::Storage.open StringIO.new do |ole|
209
+ dirent = Ole::Storage::Dirent.new ole, :name => 'test name', :type => :dir
210
+ assert_equal 'test name', dirent.name
211
+ assert_equal :dir, dirent.type
212
+ # for a dirent created from scratch, type_id is currently not set until serialization:
213
+ assert_equal 0, dirent.type_id
214
+ dirent.to_s
215
+ assert_equal 1, dirent.type_id
216
+ assert_raises(ArgumentError) { Ole::Storage::Dirent.new ole, :type => :bogus }
217
+ end
218
+ end
219
+ end
220
+