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.
@@ -0,0 +1,202 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ module Ole
4
+ module Types
5
+ #
6
+ # The PropertySet class currently supports readonly access to the properties
7
+ # serialized in "property set" streams, such as the file "\005SummaryInformation",
8
+ # in OLE files.
9
+ #
10
+ # Think it has its roots in MFC property set serialization.
11
+ #
12
+ # See http://poi.apache.org/hpsf/internals.html for details
13
+ #
14
+ class PropertySet
15
+ HEADER_SIZE = 28
16
+ HEADER_PACK = "vvVa#{Clsid::SIZE}V"
17
+ OS_MAP = {
18
+ 0 => :win16,
19
+ 1 => :mac,
20
+ 2 => :win32,
21
+ 0x20001 => :ooffice, # open office on linux...
22
+ }
23
+
24
+ # define a smattering of the property set guids.
25
+ DATA = {
26
+ Clsid.parse('{f29f85e0-4ff9-1068-ab91-08002b27b3d9}') => ['FMTID_SummaryInformation', {
27
+ 2 => 'doc_title',
28
+ 3 => 'doc_subject',
29
+ 4 => 'doc_author',
30
+ 5 => 'doc_keywords',
31
+ 6 => 'doc_comments',
32
+ 7 => 'doc_template',
33
+ 8 => 'doc_last_author',
34
+ 9 => 'doc_rev_number',
35
+ 10 => 'doc_edit_time',
36
+ 11 => 'doc_last_printed',
37
+ 12 => 'doc_created_time',
38
+ 13 => 'doc_last_saved_time',
39
+ 14 => 'doc_page_count',
40
+ 15 => 'doc_word_count',
41
+ 16 => 'doc_char_count',
42
+ 18 => 'doc_app_name',
43
+ 19 => 'security'
44
+ }],
45
+ Clsid.parse('{d5cdd502-2e9c-101b-9397-08002b2cf9ae}') => ['FMTID_DocSummaryInfo', {
46
+ 2 => 'doc_category',
47
+ 3 => 'doc_presentation_target',
48
+ 4 => 'doc_byte_count',
49
+ 5 => 'doc_line_count',
50
+ 6 => 'doc_para_count',
51
+ 7 => 'doc_slide_count',
52
+ 8 => 'doc_note_count',
53
+ 9 => 'doc_hidden_count',
54
+ 10 => 'mmclips',
55
+ 11 => 'scale_crop',
56
+ 12 => 'heading_pairs',
57
+ 13 => 'doc_part_titles',
58
+ 14 => 'doc_manager',
59
+ 15 => 'doc_company',
60
+ 16 => 'links_up_to_date'
61
+ }],
62
+ Clsid.parse('{d5cdd505-2e9c-101b-9397-08002b2cf9ae}') => ['FMTID_UserDefinedProperties', {}]
63
+ }
64
+
65
+ # create an inverted map of names to guid/key pairs
66
+ PROPERTY_MAP = DATA.inject({}) do |h1, (guid, data)|
67
+ data[1].inject(h1) { |h2, (id, name)| h2.update name => [guid, id] }
68
+ end
69
+
70
+ module Constants
71
+ DATA.each { |guid, (name, _)| const_set name, guid }
72
+ end
73
+
74
+ include Constants
75
+ include Enumerable
76
+
77
+ class Section
78
+ include Variant::Constants
79
+ include Enumerable
80
+
81
+ SIZE = Clsid::SIZE + 4
82
+ PACK = "a#{Clsid::SIZE}v"
83
+
84
+ attr_accessor :guid, :offset
85
+ attr_reader :length
86
+
87
+ def initialize str, property_set
88
+ @property_set = property_set
89
+ @guid, @offset = str.unpack PACK
90
+ self.guid = Clsid.load guid
91
+ load_header
92
+ end
93
+
94
+ def io
95
+ @property_set.io
96
+ end
97
+
98
+ def load_header
99
+ io.seek offset
100
+ @byte_size, @length = io.read(8).unpack 'V2'
101
+ end
102
+
103
+ def [] key
104
+ each_raw do |id, property_offset|
105
+ return read_property(property_offset).last if key == id
106
+ end
107
+ nil
108
+ end
109
+
110
+ def []= key, value
111
+ raise NotImplementedError, 'section writes not yet implemented'
112
+ end
113
+
114
+ def each
115
+ each_raw do |id, property_offset|
116
+ yield id, read_property(property_offset).last
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ def each_raw
123
+ io.seek offset + 8
124
+ io.read(length * 8).each_chunk(8) { |str| yield(*str.unpack('V2')) }
125
+ end
126
+
127
+ def read_property property_offset
128
+ io.seek offset + property_offset
129
+ type, value = io.read(8).unpack('V2')
130
+ # is the method of serialization here custom?
131
+ case type
132
+ when VT_LPSTR, VT_LPWSTR
133
+ value = Variant.load type, io.read(value)
134
+ # ....
135
+ end
136
+ [type, value]
137
+ end
138
+ end
139
+
140
+ attr_reader :io, :signature, :unknown, :os, :guid, :sections
141
+
142
+ def initialize io
143
+ @io = io
144
+ load_header io.read(HEADER_SIZE)
145
+ load_section_list io.read(@num_sections * Section::SIZE)
146
+ # expect no gap between last section and start of data.
147
+ #Log.warn "gap between section list and property data" unless io.pos == @sections.map(&:offset).min
148
+ end
149
+
150
+ def load_header str
151
+ @signature, @unknown, @os_id, @guid, @num_sections = str.unpack HEADER_PACK
152
+ # should i check that unknown == 0? it usually is. so is the guid actually
153
+ @guid = Clsid.load @guid
154
+ @os = OS_MAP[@os_id] || Log.warn("unknown operating system id #{@os_id}")
155
+ end
156
+
157
+ def load_section_list str
158
+ @sections = str.to_enum(:each_chunk, Section::SIZE).map { |s| Section.new s, self }
159
+ end
160
+
161
+ def [] key
162
+ pair = PROPERTY_MAP[key.to_s] or return nil
163
+ section = @sections.find { |s| s.guid == pair.first } or return nil
164
+ section[pair.last]
165
+ end
166
+
167
+ def []= key, value
168
+ pair = PROPERTY_MAP[key.to_s] or return nil
169
+ section = @sections.find { |s| s.guid == pair.first } or return nil
170
+ section[pair.last] = value
171
+ end
172
+
173
+ def method_missing name, *args, &block
174
+ if name.to_s =~ /(.*)=$/
175
+ return super unless args.length == 1
176
+ return super unless PROPERTY_MAP[$1]
177
+ self[$1] = args.first
178
+ else
179
+ return super unless args.length == 0
180
+ return super unless PROPERTY_MAP[name.to_s]
181
+ self[name]
182
+ end
183
+ end
184
+
185
+ def each
186
+ @sections.each do |section|
187
+ next unless pair = DATA[section.guid]
188
+ map = pair.last
189
+ section.each do |id, value|
190
+ name = map[id] or next
191
+ yield name, value
192
+ end
193
+ end
194
+ end
195
+
196
+ def to_h
197
+ inject({}) { |hash, (name, value)| hash.update name.to_sym => value }
198
+ end
199
+ end
200
+ end
201
+ end
202
+
data/ruby-ole.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ $:.unshift File.dirname(__FILE__) + '/lib'
2
+ require 'ole/storage/version'
3
+
4
+ PKG_NAME = 'keeguon-ruby-ole'
5
+ PKG_VERSION = Ole::Storage::VERSION
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = PKG_NAME
9
+ s.version = PKG_VERSION
10
+ s.summary = %q{Ruby OLE library.}
11
+ s.description = %q{A library for easy read/write access to OLE compound documents for Ruby.}
12
+ s.authors = ['Charles Lowe', 'Félix Bellanger']
13
+ s.email = %q{aquasync@gmail.com}
14
+ s.homepage = %q{http://code.google.com/p/ruby-ole}
15
+ s.rubyforge_project = %q{ruby-ole}
16
+
17
+ s.executables = ['oletool']
18
+ s.files = ['README', 'COPYING', 'Rakefile', 'ChangeLog', 'ruby-ole.gemspec']
19
+ s.files += Dir.glob('lib/**/*.rb')
20
+ s.files += Dir.glob('test/{test_*.rb,*.doc,oleWithDirs.ole,test_SummaryInformation}')
21
+ s.files += Dir.glob('bin/*')
22
+ s.test_files = Dir.glob('test/test_*.rb')
23
+
24
+ s.has_rdoc = true
25
+ s.extra_rdoc_files = ['README', 'ChangeLog']
26
+ s.rdoc_options += [
27
+ '--main', 'README',
28
+ '--title', "#{PKG_NAME} documentation",
29
+ '--tab-width', '2'
30
+ ]
31
+ end
32
+
Binary file
data/test/test.doc ADDED
Binary file
Binary file
@@ -0,0 +1,932 @@
1
+ #! /usr/bin/ruby
2
+ # encoding: ASCII-8BIT
3
+
4
+ #
5
+ # = NOTE
6
+ #
7
+ # This file was originally called "zipfilesystemtest.rb", and was part of
8
+ # the test case for the "rubyzip" project.
9
+ #
10
+ # As I borrowed the smart idea of using a filesystem style interface, it
11
+ # only seemed right that I appropriate the test case in addition :). It is
12
+ # a testament to the cleanliness of the original api & tests as to how
13
+ # easy it was to repurpose it for this project.
14
+ #
15
+ # I have made some modifications to the file due to some differences in the
16
+ # capabilities of zip vs ole, but the majority of the copyright and credit
17
+ # still goes to Thomas. His original copyright message:
18
+ #
19
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
20
+ # rubyzip is free software; you can redistribute it and/or
21
+ # modify it under the terms of the ruby license.
22
+ #
23
+
24
+ TEST_DIR = File.dirname __FILE__
25
+ $:.unshift "#{TEST_DIR}/../lib"
26
+
27
+ require 'ole/storage'
28
+ require 'test/unit'
29
+
30
+ module ExtraAssertions
31
+
32
+ def assert_forwarded(anObject, method, retVal, *expectedArgs)
33
+ callArgs = nil
34
+ setCallArgsProc = proc { |args| callArgs = args }
35
+ anObject.instance_eval <<-"end_eval"
36
+ alias #{method}_org #{method}
37
+ def #{method}(*args)
38
+ ObjectSpace._id2ref(#{setCallArgsProc.object_id}).call(args)
39
+ ObjectSpace._id2ref(#{retVal.object_id})
40
+ end
41
+ end_eval
42
+
43
+ assert_equal(retVal, yield) # Invoke test
44
+ assert_equal(expectedArgs, callArgs)
45
+ ensure
46
+ anObject.instance_eval "alias #{method} #{method}_org"
47
+ end
48
+
49
+ end
50
+
51
+ class OleFsNonmutatingTest < Test::Unit::TestCase
52
+ def setup
53
+ @ole = Ole::Storage.open TEST_DIR + '/oleWithDirs.ole', 'rb'
54
+ end
55
+
56
+ def teardown
57
+ @ole.close if @ole
58
+ end
59
+
60
+ =begin
61
+ def test_umask
62
+ assert_equal(File.umask, @ole.file.umask)
63
+ @ole.file.umask(0006)
64
+ end
65
+ =end
66
+
67
+ def test_exists?
68
+ assert(! @ole.file.exists?("notAFile"))
69
+ assert(@ole.file.exists?("file1"))
70
+ assert(@ole.file.exists?("dir1"))
71
+ assert(@ole.file.exists?("dir1/"))
72
+ assert(@ole.file.exists?("dir1/file12"))
73
+ assert(@ole.file.exist?("dir1/file12")) # notice, tests exist? alias of exists? !
74
+
75
+ @ole.dir.chdir "dir1/"
76
+ assert(!@ole.file.exists?("file1"))
77
+ assert(@ole.file.exists?("file12"))
78
+ end
79
+
80
+ def test_open_read
81
+ blockCalled = false
82
+ @ole.file.open("file1", "r") {
83
+ |f|
84
+ blockCalled = true
85
+ assert_equal("this is the entry 'file1' in my test archive!",
86
+ f.readline.chomp)
87
+ }
88
+ assert(blockCalled)
89
+
90
+ blockCalled = false
91
+ @ole.dir.chdir "dir2"
92
+ @ole.file.open("file21", "r") {
93
+ |f|
94
+ blockCalled = true
95
+ assert_equal("this is the entry 'dir2/file21' in my test archive!",
96
+ f.readline.chomp)
97
+ }
98
+ assert(blockCalled)
99
+ @ole.dir.chdir "/"
100
+
101
+ assert_raise(Errno::ENOENT) {
102
+ @ole.file.open("noSuchEntry")
103
+ }
104
+
105
+ begin
106
+ is = @ole.file.open("file1")
107
+ assert_equal("this is the entry 'file1' in my test archive!",
108
+ is.readline.chomp)
109
+ ensure
110
+ is.close if is
111
+ end
112
+ end
113
+
114
+ def test_new
115
+ begin
116
+ is = @ole.file.new("file1")
117
+ assert_equal("this is the entry 'file1' in my test archive!",
118
+ is.readline.chomp)
119
+ ensure
120
+ is.close if is
121
+ end
122
+ begin
123
+ is = @ole.file.new("file1") {
124
+ fail "should not call block"
125
+ }
126
+ ensure
127
+ is.close if is
128
+ end
129
+ end
130
+
131
+ # currently commented out because I've taken the approach of
132
+ # using implicit NameError rather than explicit NotImplementedError.
133
+ =begin
134
+ def test_symlink
135
+ assert_raise(NotImplementedError) {
136
+ @ole.file.symlink("file1", "aSymlink")
137
+ }
138
+ end
139
+ =end
140
+
141
+ def test_size
142
+ assert_raise(Errno::ENOENT) { @ole.file.size("notAFile") }
143
+ assert_equal(72, @ole.file.size("file1"))
144
+ assert_equal(0, @ole.file.size("dir2/dir21"))
145
+
146
+ assert_equal(72, @ole.file.stat("file1").size)
147
+ assert_equal(0, @ole.file.stat("dir2/dir21").size)
148
+ end
149
+
150
+ def test_size?
151
+ assert_equal(nil, @ole.file.size?("notAFile"))
152
+ assert_equal(72, @ole.file.size?("file1"))
153
+ assert_equal(nil, @ole.file.size?("dir2/dir21"))
154
+
155
+ assert_equal(72, @ole.file.stat("file1").size?)
156
+ assert_equal(nil, @ole.file.stat("dir2/dir21").size?)
157
+ end
158
+
159
+ def test_file?
160
+ assert(@ole.file.file?("file1"))
161
+ assert(@ole.file.file?("dir2/file21"))
162
+ assert(! @ole.file.file?("dir1"))
163
+ assert(! @ole.file.file?("dir1/dir11"))
164
+
165
+ assert(@ole.file.stat("file1").file?)
166
+ assert(@ole.file.stat("dir2/file21").file?)
167
+ assert(! @ole.file.stat("dir1").file?)
168
+ assert(! @ole.file.stat("dir1/dir11").file?)
169
+ end
170
+
171
+ =begin
172
+ include ExtraAssertions
173
+
174
+ def test_dirname
175
+ assert_forwarded(File, :dirname, "retVal", "a/b/c/d") {
176
+ @ole.file.dirname("a/b/c/d")
177
+ }
178
+ end
179
+
180
+ def test_basename
181
+ assert_forwarded(File, :basename, "retVal", "a/b/c/d") {
182
+ @ole.file.basename("a/b/c/d")
183
+ }
184
+ end
185
+
186
+ def test_split
187
+ assert_forwarded(File, :split, "retVal", "a/b/c/d") {
188
+ @ole.file.split("a/b/c/d")
189
+ }
190
+ end
191
+
192
+ def test_join
193
+ assert_equal("a/b/c", @ole.file.join("a/b", "c"))
194
+ assert_equal("a/b/c/d", @ole.file.join("a/b", "c/d"))
195
+ assert_equal("/c/d", @ole.file.join("", "c/d"))
196
+ assert_equal("a/b/c/d", @ole.file.join("a", "b", "c", "d"))
197
+ end
198
+
199
+ def test_utime
200
+ t_now = Time.now
201
+ t_bak = @ole.file.mtime("file1")
202
+ @ole.file.utime(t_now, "file1")
203
+ assert_equal(t_now, @ole.file.mtime("file1"))
204
+ @ole.file.utime(t_bak, "file1")
205
+ assert_equal(t_bak, @ole.file.mtime("file1"))
206
+ end
207
+
208
+
209
+ def assert_always_false(operation)
210
+ assert(! @ole.file.send(operation, "noSuchFile"))
211
+ assert(! @ole.file.send(operation, "file1"))
212
+ assert(! @ole.file.send(operation, "dir1"))
213
+ assert(! @ole.file.stat("file1").send(operation))
214
+ assert(! @ole.file.stat("dir1").send(operation))
215
+ end
216
+
217
+ def assert_true_if_entry_exists(operation)
218
+ assert(! @ole.file.send(operation, "noSuchFile"))
219
+ assert(@ole.file.send(operation, "file1"))
220
+ assert(@ole.file.send(operation, "dir1"))
221
+ assert(@ole.file.stat("file1").send(operation))
222
+ assert(@ole.file.stat("dir1").send(operation))
223
+ end
224
+
225
+ def test_pipe?
226
+ assert_always_false(:pipe?)
227
+ end
228
+
229
+ def test_blockdev?
230
+ assert_always_false(:blockdev?)
231
+ end
232
+
233
+ def test_symlink?
234
+ assert_always_false(:symlink?)
235
+ end
236
+
237
+ def test_socket?
238
+ assert_always_false(:socket?)
239
+ end
240
+
241
+ def test_chardev?
242
+ assert_always_false(:chardev?)
243
+ end
244
+
245
+ def test_truncate
246
+ assert_raise(StandardError, "truncate not supported") {
247
+ @ole.file.truncate("file1", 100)
248
+ }
249
+ end
250
+
251
+ def assert_e_n_o_e_n_t(operation, args = ["NoSuchFile"])
252
+ assert_raise(Errno::ENOENT) {
253
+ @ole.file.send(operation, *args)
254
+ }
255
+ end
256
+
257
+ def test_ftype
258
+ assert_e_n_o_e_n_t(:ftype)
259
+ assert_equal("file", @ole.file.ftype("file1"))
260
+ assert_equal("directory", @ole.file.ftype("dir1/dir11"))
261
+ assert_equal("directory", @ole.file.ftype("dir1/dir11/"))
262
+ end
263
+ =end
264
+
265
+ def test_directory?
266
+ assert(! @ole.file.directory?("notAFile"))
267
+ assert(! @ole.file.directory?("file1"))
268
+ assert(! @ole.file.directory?("dir1/file11"))
269
+ assert(@ole.file.directory?("dir1"))
270
+ assert(@ole.file.directory?("dir1/"))
271
+ assert(@ole.file.directory?("dir2/dir21"))
272
+
273
+ assert(! @ole.file.stat("file1").directory?)
274
+ assert(! @ole.file.stat("dir1/file11").directory?)
275
+ assert(@ole.file.stat("dir1").directory?)
276
+ assert(@ole.file.stat("dir1/").directory?)
277
+ assert(@ole.file.stat("dir2/dir21").directory?)
278
+ end
279
+
280
+ =begin
281
+ def test_chown
282
+ assert_equal(2, @ole.file.chown(1,2, "dir1", "file1"))
283
+ assert_equal(1, @ole.file.stat("dir1").uid)
284
+ assert_equal(2, @ole.file.stat("dir1").gid)
285
+ assert_equal(2, @ole.file.chown(nil, nil, "dir1", "file1"))
286
+ end
287
+
288
+ def test_zero?
289
+ assert(! @ole.file.zero?("notAFile"))
290
+ assert(! @ole.file.zero?("file1"))
291
+ assert(@ole.file.zero?("dir1"))
292
+ blockCalled = false
293
+ ZipFile.open("data/generated/5entry.zip") {
294
+ |zf|
295
+ blockCalled = true
296
+ assert(zf.file.zero?("data/generated/empty.txt"))
297
+ }
298
+ assert(blockCalled)
299
+
300
+ assert(! @ole.file.stat("file1").zero?)
301
+ assert(@ole.file.stat("dir1").zero?)
302
+ blockCalled = false
303
+ ZipFile.open("data/generated/5entry.zip") {
304
+ |zf|
305
+ blockCalled = true
306
+ assert(zf.file.stat("data/generated/empty.txt").zero?)
307
+ }
308
+ assert(blockCalled)
309
+ end
310
+ =end
311
+
312
+ def test_expand_path
313
+ assert_equal("/", @ole.file.expand_path("."))
314
+ @ole.dir.chdir "dir1"
315
+ assert_equal("/dir1", @ole.file.expand_path("."))
316
+ assert_equal("/dir1/file12", @ole.file.expand_path("file12"))
317
+ assert_equal("/", @ole.file.expand_path(".."))
318
+ assert_equal("/dir2/dir21", @ole.file.expand_path("../dir2/dir21"))
319
+ end
320
+
321
+ =begin
322
+ def test_mtime
323
+ assert_equal(Time.at(1027694306),
324
+ @ole.file.mtime("dir2/file21"))
325
+ assert_equal(Time.at(1027690863),
326
+ @ole.file.mtime("dir2/dir21"))
327
+ assert_raise(Errno::ENOENT) {
328
+ @ole.file.mtime("noSuchEntry")
329
+ }
330
+
331
+ assert_equal(Time.at(1027694306),
332
+ @ole.file.stat("dir2/file21").mtime)
333
+ assert_equal(Time.at(1027690863),
334
+ @ole.file.stat("dir2/dir21").mtime)
335
+ end
336
+
337
+ def test_ctime
338
+ assert_nil(@ole.file.ctime("file1"))
339
+ assert_nil(@ole.file.stat("file1").ctime)
340
+ end
341
+
342
+ def test_atime
343
+ assert_nil(@ole.file.atime("file1"))
344
+ assert_nil(@ole.file.stat("file1").atime)
345
+ end
346
+
347
+ def test_readable?
348
+ assert(! @ole.file.readable?("noSuchFile"))
349
+ assert(@ole.file.readable?("file1"))
350
+ assert(@ole.file.readable?("dir1"))
351
+ assert(@ole.file.stat("file1").readable?)
352
+ assert(@ole.file.stat("dir1").readable?)
353
+ end
354
+
355
+ def test_readable_real?
356
+ assert(! @ole.file.readable_real?("noSuchFile"))
357
+ assert(@ole.file.readable_real?("file1"))
358
+ assert(@ole.file.readable_real?("dir1"))
359
+ assert(@ole.file.stat("file1").readable_real?)
360
+ assert(@ole.file.stat("dir1").readable_real?)
361
+ end
362
+
363
+ def test_writable?
364
+ assert(! @ole.file.writable?("noSuchFile"))
365
+ assert(@ole.file.writable?("file1"))
366
+ assert(@ole.file.writable?("dir1"))
367
+ assert(@ole.file.stat("file1").writable?)
368
+ assert(@ole.file.stat("dir1").writable?)
369
+ end
370
+
371
+ def test_writable_real?
372
+ assert(! @ole.file.writable_real?("noSuchFile"))
373
+ assert(@ole.file.writable_real?("file1"))
374
+ assert(@ole.file.writable_real?("dir1"))
375
+ assert(@ole.file.stat("file1").writable_real?)
376
+ assert(@ole.file.stat("dir1").writable_real?)
377
+ end
378
+
379
+ def test_executable?
380
+ assert(! @ole.file.executable?("noSuchFile"))
381
+ assert(! @ole.file.executable?("file1"))
382
+ assert(@ole.file.executable?("dir1"))
383
+ assert(! @ole.file.stat("file1").executable?)
384
+ assert(@ole.file.stat("dir1").executable?)
385
+ end
386
+
387
+ def test_executable_real?
388
+ assert(! @ole.file.executable_real?("noSuchFile"))
389
+ assert(! @ole.file.executable_real?("file1"))
390
+ assert(@ole.file.executable_real?("dir1"))
391
+ assert(! @ole.file.stat("file1").executable_real?)
392
+ assert(@ole.file.stat("dir1").executable_real?)
393
+ end
394
+
395
+ def test_owned?
396
+ assert_true_if_entry_exists(:owned?)
397
+ end
398
+
399
+ def test_grpowned?
400
+ assert_true_if_entry_exists(:grpowned?)
401
+ end
402
+
403
+ def test_setgid?
404
+ assert_always_false(:setgid?)
405
+ end
406
+
407
+ def test_setuid?
408
+ assert_always_false(:setgid?)
409
+ end
410
+
411
+ def test_sticky?
412
+ assert_always_false(:sticky?)
413
+ end
414
+
415
+ def test_stat
416
+ s = @ole.file.stat("file1")
417
+ assert(s.kind_of?(File::Stat)) # It pretends
418
+ assert_raise(Errno::ENOENT, "No such file or directory - noSuchFile") {
419
+ @ole.file.stat("noSuchFile")
420
+ }
421
+ end
422
+
423
+ def test_lstat
424
+ assert(@ole.file.lstat("file1").file?)
425
+ end
426
+
427
+
428
+ def test_chmod
429
+ assert_raise(Errno::ENOENT, "No such file or directory - noSuchFile") {
430
+ @ole.file.chmod(0644, "file1", "NoSuchFile")
431
+ }
432
+ assert_equal(2, @ole.file.chmod(0644, "file1", "dir1"))
433
+ end
434
+
435
+ def test_pipe
436
+ assert_raise(NotImplementedError) {
437
+ @ole.file.pipe
438
+ }
439
+ end
440
+
441
+ def test_foreach
442
+ ZipFile.open("data/generated/zipWithDir.zip") {
443
+ |zf|
444
+ ref = []
445
+ File.foreach("data/file1.txt") { |e| ref << e }
446
+
447
+ index = 0
448
+ zf.file.foreach("data/file1.txt") {
449
+ |l|
450
+ assert_equal(ref[index], l)
451
+ index = index.next
452
+ }
453
+ assert_equal(ref.size, index)
454
+ }
455
+
456
+ ZipFile.open("data/generated/zipWithDir.zip") {
457
+ |zf|
458
+ ref = []
459
+ File.foreach("data/file1.txt", " ") { |e| ref << e }
460
+
461
+ index = 0
462
+ zf.file.foreach("data/file1.txt", " ") {
463
+ |l|
464
+ assert_equal(ref[index], l)
465
+ index = index.next
466
+ }
467
+ assert_equal(ref.size, index)
468
+ }
469
+ end
470
+
471
+ def test_popen
472
+ cmd = /mswin/i =~ RUBY_PLATFORM ? 'dir' : 'ls'
473
+
474
+ assert_equal(File.popen(cmd) { |f| f.read },
475
+ @ole.file.popen(cmd) { |f| f.read })
476
+ end
477
+
478
+ # Can be added later
479
+ # def test_select
480
+ # fail "implement test"
481
+ # end
482
+
483
+ def test_readlines
484
+ ZipFile.open("data/generated/zipWithDir.zip") {
485
+ |zf|
486
+ assert_equal(File.readlines("data/file1.txt"),
487
+ zf.file.readlines("data/file1.txt"))
488
+ }
489
+ end
490
+
491
+ def test_read
492
+ ZipFile.open("data/generated/zipWithDir.zip") {
493
+ |zf|
494
+ assert_equal(File.read("data/file1.txt"),
495
+ zf.file.read("data/file1.txt"))
496
+ }
497
+ end
498
+ =end
499
+ end
500
+
501
+ class OleFsFileStatTest < Test::Unit::TestCase
502
+
503
+ def setup
504
+ @ole = Ole::Storage.open TEST_DIR + '/oleWithDirs.ole', 'rb'
505
+ end
506
+
507
+ def teardown
508
+ @ole.close if @ole
509
+ end
510
+
511
+ def test_blocks
512
+ assert_equal(2, @ole.file.stat("file1").blocks)
513
+ end
514
+
515
+ def test_ino
516
+ assert_equal(0, @ole.file.stat("file1").ino)
517
+ end
518
+
519
+ def test_uid
520
+ assert_equal(0, @ole.file.stat("file1").uid)
521
+ end
522
+
523
+ def test_gid
524
+ assert_equal(0, @ole.file.stat("file1").gid)
525
+ end
526
+
527
+ def test_ftype
528
+ assert_equal("file", @ole.file.stat("file1").ftype)
529
+ assert_equal("directory", @ole.file.stat("dir1").ftype)
530
+ end
531
+
532
+ =begin
533
+ def test_mode
534
+ assert_equal(0600, @ole.file.stat("file1").mode & 0777)
535
+ assert_equal(0600, @ole.file.stat("file1").mode & 0777)
536
+ assert_equal(0755, @ole.file.stat("dir1").mode & 0777)
537
+ assert_equal(0755, @ole.file.stat("dir1").mode & 0777)
538
+ end
539
+ =end
540
+
541
+ def test_dev
542
+ assert_equal(0, @ole.file.stat("file1").dev)
543
+ end
544
+
545
+ def test_rdev
546
+ assert_equal(0, @ole.file.stat("file1").rdev)
547
+ end
548
+
549
+ def test_rdev_major
550
+ assert_equal(0, @ole.file.stat("file1").rdev_major)
551
+ end
552
+
553
+ def test_rdev_minor
554
+ assert_equal(0, @ole.file.stat("file1").rdev_minor)
555
+ end
556
+
557
+ def test_nlink
558
+ assert_equal(1, @ole.file.stat("file1").nlink)
559
+ end
560
+
561
+ def test_blksize
562
+ assert_equal(64, @ole.file.stat("file1").blksize)
563
+ end
564
+
565
+ # an additional test i added for coverage. i've tried to make the inspect
566
+ # string on the ole stat match that of the regular one.
567
+ def test_inspect
568
+ # normalize, as instance_variables order is undefined
569
+ normalize = proc { |s| s[/ (.*)>$/, 1].split(', ').sort.join(', ') }
570
+ assert_match %r{blocks=2.*ftype=file.*size=72}, normalize[@ole.file.stat('file1').inspect]
571
+ end
572
+ end
573
+
574
+ class OleFsFileMutatingTest < Test::Unit::TestCase
575
+ def setup
576
+ # we use an in memory copy of the file instead of the original
577
+ # file based.
578
+ @io = StringIO.new open(TEST_DIR + '/oleWithDirs.ole', 'rb', &:read)
579
+ end
580
+
581
+ def teardown
582
+ @io.close if @io
583
+ end
584
+
585
+ def test_delete
586
+ do_test_delete_or_unlink(:delete)
587
+ end
588
+
589
+ def test_unlink
590
+ do_test_delete_or_unlink(:unlink)
591
+ end
592
+
593
+ def test_open_write
594
+ Ole::Storage.open(@io) {
595
+ |zf|
596
+
597
+ blockCalled = nil
598
+ zf.file.open("test_open_write_entry", "w") {
599
+ |f|
600
+ blockCalled = true
601
+ f.write "This is what I'm writing"
602
+ }
603
+ assert(blockCalled)
604
+ assert_equal("This is what I'm writing",
605
+ zf.file.read("test_open_write_entry"))
606
+
607
+ blockCalled = nil
608
+ # Test with existing entry
609
+ zf.file.open("file1", "w") {
610
+ |f|
611
+ blockCalled = true
612
+ f.write "This is what I'm writing too"
613
+ }
614
+ assert(blockCalled)
615
+ assert_equal("This is what I'm writing too",
616
+ zf.file.read("file1"))
617
+ }
618
+ end
619
+
620
+ def test_rename
621
+ Ole::Storage.open(@io) {
622
+ |zf|
623
+ assert_raise(Errno::ENOENT, "") {
624
+ zf.file.rename("NoSuchFile", "bimse")
625
+ }
626
+ zf.file.rename("file1", "newNameForFile1")
627
+ # lets also try moving a file to a different directory,
628
+ # and renaming a directory
629
+ zf.file.rename('/dir1/file11', '/dir1/dir11/file111')
630
+ zf.file.rename('dir1', 'dir9')
631
+ }
632
+
633
+ Ole::Storage.open(@io) {
634
+ |zf|
635
+ assert(! zf.file.exists?("file1"))
636
+ assert(zf.file.exists?("newNameForFile1"))
637
+ assert(zf.file.exists?("dir9/dir11/file111"))
638
+ }
639
+ end
640
+
641
+ def do_test_delete_or_unlink(symbol)
642
+ Ole::Storage.open(@io) {
643
+ |zf|
644
+ assert(zf.file.exists?("dir2/dir21/dir221/file2221"))
645
+ zf.file.send(symbol, "dir2/dir21/dir221/file2221")
646
+ assert(! zf.file.exists?("dir2/dir21/dir221/file2221"))
647
+
648
+ assert(zf.file.exists?("dir1/file11"))
649
+ assert(zf.file.exists?("dir1/file12"))
650
+ zf.file.send(symbol, "dir1/file11", "dir1/file12")
651
+ assert(! zf.file.exists?("dir1/file11"))
652
+ assert(! zf.file.exists?("dir1/file12"))
653
+
654
+ assert_raise(Errno::ENOENT) { zf.file.send(symbol, "noSuchFile") }
655
+ assert_raise(Errno::EISDIR) { zf.file.send(symbol, "dir1/dir11") }
656
+ assert_raise(Errno::EISDIR) { zf.file.send(symbol, "dir1/dir11/") }
657
+ }
658
+
659
+ Ole::Storage.open(@io) {
660
+ |zf|
661
+ assert(! zf.file.exists?("dir2/dir21/dir221/file2221"))
662
+ assert(! zf.file.exists?("dir1/file11"))
663
+ assert(! zf.file.exists?("dir1/file12"))
664
+
665
+ assert(zf.file.exists?("dir1/dir11"))
666
+ assert(zf.file.exists?("dir1/dir11/"))
667
+ }
668
+ end
669
+
670
+ end
671
+
672
+ class OleFsDirectoryTest < Test::Unit::TestCase
673
+ def setup
674
+ # we use an in memory copy of the file instead of the original
675
+ # file based.
676
+ @io = StringIO.new open(TEST_DIR + '/oleWithDirs.ole', 'rb', &:read)
677
+ end
678
+
679
+ def teardown
680
+ @io.close if @io
681
+ end
682
+
683
+ def test_delete
684
+ Ole::Storage.open(@io) {
685
+ |zf|
686
+ assert_raise(Errno::ENOENT, "No such file or directory - NoSuchFile.txt") {
687
+ zf.dir.delete("NoSuchFile.txt")
688
+ }
689
+ # see explanation below, touch a && ruby -e 'Dir.delete "a"' gives ENOTDIR not EINVAL
690
+ assert_raise(Errno::ENOTDIR, "Invalid argument - file1") {
691
+ zf.dir.delete("file1")
692
+ }
693
+ assert(zf.file.exists?("dir1"))
694
+ #zf.dir.delete("dir1")
695
+ #assert(! zf.file.exists?("dir1"))
696
+ # ^ this was allowed in zipfilesystem, but my code follows Dir.delete, and requires that
697
+ # the directory be empty first. need to delete recursively if you want other behaviour.
698
+ assert_raises(Errno::ENOTEMPTY) { zf.dir.delete('dir1') }
699
+ }
700
+ end
701
+
702
+ def test_mkdir
703
+ Ole::Storage.open(@io) {
704
+ |zf|
705
+ assert_raise(Errno::EEXIST, "File exists - dir1") {
706
+ zf.dir.mkdir("file1")
707
+ }
708
+ assert_raise(Errno::EEXIST, "File exists - dir1") {
709
+ zf.dir.mkdir("dir1")
710
+ }
711
+ assert(!zf.file.exists?("newDir"))
712
+ zf.dir.mkdir("newDir")
713
+ assert(zf.file.directory?("newDir"))
714
+ assert(!zf.file.exists?("newDir2"))
715
+ # FIXME - mode not supported yet
716
+ #zf.dir.mkdir("newDir2", 3485)
717
+ #assert(zf.file.directory?("newDir2"))
718
+ zf.dir.rmdir 'newDir'
719
+ assert(!zf.file.exists?("newDir"))
720
+ }
721
+ end
722
+
723
+ def test_pwd_chdir_entries
724
+ Ole::Storage.open(@io) {
725
+ |zf|
726
+ assert_equal("/", zf.dir.pwd)
727
+
728
+ assert_raise(Errno::ENOENT, "No such file or directory - no such dir") {
729
+ zf.dir.chdir "no such dir"
730
+ }
731
+
732
+ # changed this to ENOTDIR, which is what touch a; ruby -e "Dir.chdir('a')" gives you.
733
+ assert_raise(Errno::ENOTDIR, "Invalid argument - file1") {
734
+ zf.dir.chdir "file1"
735
+ }
736
+
737
+ assert_equal(['.', '..', "dir1", "dir2", "file1"].sort, zf.dir.entries(".").sort)
738
+ zf.dir.chdir "dir1"
739
+ assert_equal("/dir1", zf.dir.pwd)
740
+ zf.dir.chdir('dir11') { assert_equal '/dir1/dir11', zf.dir.pwd }
741
+ assert_equal '/dir1', zf.dir.pwd
742
+ assert_equal(['.', '..', "dir11", "file11", "file12"], zf.dir.entries(".").sort)
743
+
744
+ zf.dir.chdir "../dir2/dir21"
745
+ assert_equal("/dir2/dir21", zf.dir.pwd)
746
+ assert_equal(['.', '..', "dir221"].sort, zf.dir.entries(".").sort)
747
+ }
748
+ end
749
+
750
+ # results here are a bit different from zip/zipfilesystem, as i've chosen to fake '.'
751
+ # and '..'
752
+ def test_foreach
753
+ Ole::Storage.open(@io) {
754
+ |zf|
755
+
756
+ blockCalled = false
757
+ assert_raise(Errno::ENOENT, "No such file or directory - noSuchDir") {
758
+ zf.dir.foreach("noSuchDir") { |e| blockCalled = true }
759
+ }
760
+ assert(! blockCalled)
761
+
762
+ assert_raise(Errno::ENOTDIR, "Not a directory - file1") {
763
+ zf.dir.foreach("file1") { |e| blockCalled = true }
764
+ }
765
+ assert(! blockCalled)
766
+
767
+ entries = []
768
+ zf.dir.foreach(".") { |e| entries << e }
769
+ assert_equal(['.', '..', "dir1", "dir2", "file1"].sort, entries.sort)
770
+
771
+ entries = []
772
+ zf.dir.foreach("dir1") { |e| entries << e }
773
+ assert_equal(['.', '..', "dir11", "file11", "file12"], entries.sort)
774
+ }
775
+ end
776
+
777
+ =begin
778
+ # i've gone for NoMethodError instead.
779
+ def test_chroot
780
+ Ole::Storage.open(@io) {
781
+ |zf|
782
+ assert_raise(NotImplementedError) {
783
+ zf.dir.chroot
784
+ }
785
+ }
786
+ end
787
+ =end
788
+
789
+ # Globbing not supported yet
790
+ #def test_glob
791
+ # # test alias []-operator too
792
+ # fail "implement test"
793
+ #end
794
+
795
+ def test_open_new
796
+ Ole::Storage.open(@io) {
797
+ |zf|
798
+
799
+ assert_raise(Errno::ENOTDIR, "Not a directory - file1") {
800
+ zf.dir.new("file1")
801
+ }
802
+
803
+ assert_raise(Errno::ENOENT, "No such file or directory - noSuchFile") {
804
+ zf.dir.new("noSuchFile")
805
+ }
806
+
807
+ d = zf.dir.new(".")
808
+ assert_equal(['.', '..', "file1", "dir1", "dir2"].sort, d.entries.sort)
809
+ d.close
810
+
811
+ zf.dir.open("dir1") {
812
+ |d2|
813
+ assert_equal(['.', '..', "dir11", "file11", "file12"].sort, d2.entries.sort)
814
+ }
815
+ }
816
+ end
817
+
818
+ end
819
+
820
+ class OleFsDirIteratorTest < Test::Unit::TestCase
821
+
822
+ FILENAME_ARRAY = [ "f1", "f2", "f3", "f4", "f5", "f6" ]
823
+
824
+ def setup
825
+ @dirIt = Ole::Storage::DirClass::Dir.new('/', FILENAME_ARRAY)
826
+ end
827
+
828
+ def test_close
829
+ @dirIt.close
830
+ assert_raise(IOError, "closed directory") {
831
+ @dirIt.each { |e| p e }
832
+ }
833
+ assert_raise(IOError, "closed directory") {
834
+ @dirIt.read
835
+ }
836
+ assert_raise(IOError, "closed directory") {
837
+ @dirIt.rewind
838
+ }
839
+ assert_raise(IOError, "closed directory") {
840
+ @dirIt.seek(0)
841
+ }
842
+ assert_raise(IOError, "closed directory") {
843
+ @dirIt.tell
844
+ }
845
+
846
+ end
847
+
848
+ def test_each
849
+ # Tested through Enumerable.entries
850
+ assert_equal(FILENAME_ARRAY, @dirIt.entries)
851
+ end
852
+
853
+ def test_read
854
+ FILENAME_ARRAY.size.times {
855
+ |i|
856
+ assert_equal(FILENAME_ARRAY[i], @dirIt.read)
857
+ }
858
+ end
859
+
860
+ def test_rewind
861
+ @dirIt.read
862
+ @dirIt.read
863
+ assert_equal(FILENAME_ARRAY[2], @dirIt.read)
864
+ @dirIt.rewind
865
+ assert_equal(FILENAME_ARRAY[0], @dirIt.read)
866
+ end
867
+
868
+ def test_tell_seek
869
+ @dirIt.read
870
+ @dirIt.read
871
+ pos = @dirIt.tell
872
+ valAtPos = @dirIt.read
873
+ @dirIt.read
874
+ @dirIt.seek(pos)
875
+ assert_equal(valAtPos, @dirIt.read)
876
+ end
877
+
878
+ end
879
+
880
+ class OleUnicodeTest < Test::Unit::TestCase
881
+ def setup
882
+ @io = StringIO.new ''
883
+ end
884
+
885
+ def test_unicode
886
+ # in ruby-1.8, encoding is assumed to be UTF-8 (and converted with iconv).
887
+ # in ruby-1.9, UTF-8 should work also, but probably shouldn't be using fixed
888
+ # TO_UTF16 iconv for other encodings.
889
+ resume = "R\xc3\xa9sum\xc3\xa9"
890
+ resume.force_encoding Encoding::UTF_8 if resume.respond_to? :encoding
891
+ Ole::Storage.open @io do |ole|
892
+ ole.file.open(resume, 'w') { |f| f.write 'Skills: writing bad unit tests' }
893
+ end
894
+ Ole::Storage.open @io do |ole|
895
+ assert_equal ['.', '..', resume], ole.dir.entries('.')
896
+ # use internal api to verify utf16 encoding
897
+ assert_equal "R\x00\xE9\x00s\x00u\x00m\x00\xE9\x00", ole.root.children[0].name_utf16[0, 6 * 2]
898
+ # FIXME: there is a bug in ruby-1.9 (at least in p376), which makes encoded
899
+ # strings useless as hash keys. identical bytes, identical encodings, identical
900
+ # according to #==, but different hash.
901
+ temp = File.expand_path("/#{resume}").split('/').last
902
+ if resume == temp and resume.hash != temp.hash
903
+ warn 'skipping assertion due to broken String#hash'
904
+ else
905
+ assert_equal 'Skills', ole.file.read(resume).split(': ', 2).first
906
+ end
907
+ end
908
+ end
909
+
910
+ def test_write_utf8_string
911
+ programmer = "programa\xC3\xA7\xC3\xA3o "
912
+ programmer.force_encoding Encoding::UTF_8 if programmer.respond_to? :encoding
913
+ Ole::Storage.open @io do |ole|
914
+ ole.file.open '1', 'w' do |writer|
915
+ writer.write(programmer)
916
+ writer.write('ruby')
917
+ end
918
+ end
919
+ Ole::Storage.open @io do |ole|
920
+ ole.file.open '1', 'r' do |reader|
921
+ s = reader.read
922
+ s = s.force_encoding('UTF-8') if s.respond_to?(:encoding)
923
+ assert_equal(programmer + 'ruby', s)
924
+ end
925
+ end
926
+ end
927
+ end
928
+
929
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
930
+ # rubyzip is free software; you can redistribute it and/or
931
+ # modify it under the terms of the ruby license.
932
+