keeguon-ruby-ole 1.2.11.7

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