Sutto-perennial 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,57 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class LoggerTest < Test::Unit::TestCase
4
+ context 'logger tests' do
5
+
6
+ setup do
7
+ @root_path = Perennial::Settings.root / "log"
8
+ Perennial::Logger.log_name = "example.log"
9
+ FileUtils.mkdir_p @root_path
10
+ end
11
+
12
+ context 'setting up a logger' do
13
+
14
+ setup { Perennial::Logger.setup! }
15
+
16
+ should 'create the log file file after writing' do
17
+ Perennial::Logger.fatal "Blergh."
18
+ assert File.exist?(@root_path / "example.log")
19
+ end
20
+
21
+ Perennial::Logger::LEVELS.each_key do |level_name|
22
+ should "define a method for the #{level_name} log level" do
23
+ assert Perennial::Logger.respond_to?(level_name)
24
+ assert Perennial::Logger.logger.respond_to?(level_name)
25
+ assert_equal 1, Perennial::Logger.logger.method(level_name).arity
26
+ end
27
+ end
28
+
29
+ should 'have a log exception method' do
30
+ assert Perennial::Logger.respond_to?(:log_exception)
31
+ assert Perennial::Logger.logger.respond_to?(:log_exception)
32
+ end
33
+
34
+ end
35
+
36
+ context 'writing to the log' do
37
+
38
+ Perennial::Logger::LEVELS.each_key do |level_name|
39
+ should "let you write to the #{level_name} log level" do
40
+ Perennial::Logger.verbose = false
41
+ Perennial::Logger.level = level_name
42
+ assert_nothing_raised do
43
+ Perennial::Logger.logger.send(level_name, "An Example Message No. 1")
44
+ end
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ teardown do
51
+ log_path = @root_path / "example.log"
52
+ FileUtils.rm_rf(log_path) if File.exist?(log_path)
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,99 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class SettingsTest < Test::Unit::TestCase
4
+
5
+ context 'default settings' do
6
+
7
+ setup do
8
+ Perennial::Settings.setup!
9
+ end
10
+
11
+ should "default the application root to the parent folder of perennial" do
12
+ assert_equal __FILE__.to_pathname.dirname.join("..").expand_path,
13
+ Perennial::Settings.root.to_pathname
14
+ Perennial::Settings.root = "/awesome/sauce"
15
+ assert_equal "/awesome/sauce", Perennial::Settings.root
16
+ end
17
+
18
+ should "default daemonized to false" do
19
+ assert !Perennial::Settings.daemon?
20
+ Perennial::Settings.daemon = true
21
+ assert Perennial::Settings.daemon?
22
+ Perennial::Settings.daemon = false
23
+ assert !Perennial::Settings.daemon?
24
+ end
25
+
26
+ should "default the log level to :info" do
27
+ assert_equal :info, Perennial::Settings.log_level
28
+ Perennial::Settings.log_level = :debug
29
+ assert_equal :debug, Perennial::Settings.log_level
30
+ end
31
+
32
+ should "default verbose to false" do
33
+ assert !Perennial::Settings.verbose?
34
+ Perennial::Settings.verbose = true
35
+ assert Perennial::Settings.verbose?
36
+ Perennial::Settings.verbose = false
37
+ assert !Perennial::Settings.verbose?
38
+ end
39
+
40
+ end
41
+
42
+ context 'loading settings' do
43
+
44
+ setup do
45
+ config_folder = Perennial::Settings.root / "config"
46
+ @default_settings = {
47
+ "default" => {
48
+ "introduction" => true,
49
+ "description" => "Ninjas are Totally Awesome",
50
+ "channel" => "#offrails",
51
+ "users" => ["Sutto", "njero", "zapnap"]
52
+ }
53
+ }
54
+ FileUtils.mkdir_p(config_folder)
55
+ File.open(config_folder / "settings.yml", "w+") do |file|
56
+ file.write(@default_settings.to_yaml)
57
+ end
58
+ Perennial::Settings.setup!
59
+ end
60
+
61
+ should 'load settings from the file' do
62
+ assert Perennial::Settings.setup?
63
+ assert_equal @default_settings["default"].symbolize_keys, Perennial::Settings.to_hash
64
+ end
65
+
66
+ should 'define readers for the settings' do
67
+ instance = Perennial::Settings.new
68
+ @default_settings["default"].each_pair do |key, value|
69
+ assert Perennial::Settings.respond_to?(key.to_sym)
70
+ assert_equal value, Perennial::Settings.send(key)
71
+ assert instance.respond_to?(key.to_sym)
72
+ assert_equal value, instance.send(key)
73
+ end
74
+ end
75
+
76
+ should 'let you access settings via hash-style accessors' do
77
+ @default_settings["default"].each_pair do |key, value|
78
+ assert_equal value, Perennial::Settings[key]
79
+ Perennial::Settings[key] = "a-new-value from #{value.inspect}"
80
+ assert_equal "a-new-value from #{value.inspect}", Perennial::Settings[key]
81
+ end
82
+ end
83
+
84
+ should 'define writers for the settings' do
85
+ instance = Perennial::Settings.new
86
+ @default_settings["default"].each_pair do |key, value|
87
+ setter = :"#{key}="
88
+ assert Perennial::Settings.respond_to?(setter)
89
+ Perennial::Settings.send(setter, "value #{value.inspect} on class")
90
+ assert_equal "value #{value.inspect} on class", Perennial::Settings.send(key)
91
+ assert instance.respond_to?(setter)
92
+ instance.send(setter, "value #{value.inspect} on instance")
93
+ assert_equal "value #{value.inspect} on instance", instance.send(key)
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+
3
+ # Testing dependencies
4
+ require 'test/unit'
5
+ require 'shoulda'
6
+ require 'rr'
7
+ # RedGreen doesn't seem to be needed under 1.9
8
+ require 'redgreen' if RUBY_VERSION < "1.9"
9
+
10
+ require 'pathname'
11
+ root_directory = Pathname.new(__FILE__).dirname.join("..").expand_path
12
+ require root_directory.join("lib", "perennial")
13
+ require root_directory.join("vendor", "fakefs", "lib", "fakefs")
14
+
15
+ class Test::Unit::TestCase
16
+ include RR::Adapters::TestUnit
17
+
18
+ protected
19
+
20
+ # Short hand for creating a class with
21
+ # a given class_eval block.
22
+ def class_via(*args, &blk)
23
+ klass = Class.new(*args)
24
+ klass.class_eval(&blk) unless blk.blank?
25
+ return klass
26
+ end
27
+
28
+ # Short hand for creating a test class
29
+ # for a set of mixins - give it the modules
30
+ # and it will include them all.
31
+ def test_class_for(*mods, &blk)
32
+ klass = Class.new
33
+ klass.class_eval { include(*mods) }
34
+ klass.class_eval(&blk) unless blk.blank?
35
+ return klass
36
+ end
37
+
38
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Chris Wanstrath
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,37 @@
1
+ FakeFS
2
+ ======
3
+
4
+ Mocha is great. But when your library is all about manipulating the
5
+ filesystem, you really want to test the behavior and not the implementation.
6
+
7
+ If you're mocking and stubbing every call to FileUtils or File, you're
8
+ tightly coupling your tests with the implementation.
9
+
10
+ def test_creates_directory
11
+ FileUtils.expects(:mkdir).with("directory").once
12
+ Library.add "directory"
13
+ end
14
+
15
+ The above test will break if we decide to use `mkdir_p` in our code. Refactoring
16
+ code shouldn't necessitate refactoring tests.
17
+
18
+ With FakeFS:
19
+
20
+ def test_creates_directory
21
+ Library.add "directory"
22
+ assert File.directory?("directory")
23
+ end
24
+
25
+ Woot.
26
+
27
+ How is this different than MockFS?
28
+ ----------------------------------
29
+
30
+ FakeFS provides a test suite and works with symlinks. It's also strictly a
31
+ test-time dependency: your actual library does not need to use or know about
32
+ FakeFS.
33
+
34
+ Authors
35
+ -------
36
+
37
+ Chris Wanstrath [chris@ozmm.org]
@@ -0,0 +1,3 @@
1
+ task :default do
2
+ exec "ruby test/fakefs_test.rb"
3
+ end
@@ -0,0 +1,448 @@
1
+ require 'fileutils'
2
+ require 'pathname'
3
+
4
+ RealFile = File
5
+ RealFileUtils = FileUtils
6
+ RealDir = Dir
7
+ RealFileUtils::Dir = RealDir
8
+ RealFileUtils::File = RealFile
9
+
10
+ module FakeFS
11
+ module FileUtils
12
+ extend self
13
+
14
+ def mkdir_p(path)
15
+ FileSystem.add(path, MockDir.new)
16
+ end
17
+
18
+ def rm(path)
19
+ FileSystem.delete(path)
20
+ end
21
+ alias_method :rm_rf, :rm
22
+
23
+ def ln_s(target, path)
24
+ raise Errno::EEXIST, path if FileSystem.find(path)
25
+ FileSystem.add(path, MockSymlink.new(target))
26
+ end
27
+
28
+ def cp(src, dest)
29
+ dst_file = FileSystem.find(dest)
30
+ src_file = FileSystem.find(src)
31
+
32
+ if !src_file
33
+ raise Errno::ENOENT, src
34
+ end
35
+
36
+ if File.directory? src_file
37
+ raise Errno::EISDIR, src
38
+ end
39
+
40
+ if dst_file and File.directory?(dst_file)
41
+ FileSystem.add(File.join(dest, src), src_file.entry.clone(dst_file))
42
+ else
43
+ FileSystem.delete(dest)
44
+ FileSystem.add(dest, src_file.entry.clone)
45
+ end
46
+ end
47
+
48
+ def cp_r(src, dest)
49
+ # This error sucks, but it conforms to the original Ruby
50
+ # method.
51
+ raise "unknown file type: #{src}" unless dir = FileSystem.find(src)
52
+
53
+ new_dir = FileSystem.find(dest)
54
+
55
+ if new_dir && !File.directory?(dest)
56
+ raise Errno::EEXIST, dest
57
+ end
58
+
59
+ if !new_dir && !FileSystem.find(dest+'/../')
60
+ raise Errno::ENOENT, dest
61
+ end
62
+
63
+ # This last bit is a total abuse and should be thought hard
64
+ # about and cleaned up.
65
+ if new_dir
66
+ if src[-2..-1] == '/.'
67
+ dir.values.each{|f| new_dir[f.name] = f.clone(new_dir) }
68
+ else
69
+ new_dir[dir.name] = dir.entry.clone(new_dir)
70
+ end
71
+ else
72
+ FileSystem.add(dest, dir.entry.clone)
73
+ end
74
+ end
75
+
76
+ def mv(src, dest)
77
+ if target = FileSystem.find(src)
78
+ FileSystem.add(dest, target.entry.clone)
79
+ FileSystem.delete(src)
80
+ else
81
+ raise Errno::ENOENT, src
82
+ end
83
+ end
84
+
85
+ def chown(user, group, list, options={})
86
+ list = Array(list)
87
+ list.each do |f|
88
+ unless File.exists?(f)
89
+ raise Errno::ENOENT, f
90
+ end
91
+ end
92
+ list
93
+ end
94
+
95
+ def chown_R(user, group, list, options={})
96
+ chown(user, group, list, options={})
97
+ end
98
+
99
+ def touch(list, options={})
100
+ Array(list).each do |f|
101
+ directory = File.dirname(f)
102
+ # FIXME this explicit check for '.' shouldn't need to happen
103
+ if File.exists?(directory) || directory == '.'
104
+ FileSystem.add(f, MockFile.new)
105
+ else
106
+ raise Errno::ENOENT, f
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ class File
113
+ PATH_SEPARATOR = '/'
114
+
115
+ def self.join(*parts)
116
+ parts * PATH_SEPARATOR
117
+ end
118
+
119
+ def self.exist?(path)
120
+ FileSystem.find(path) || false
121
+ end
122
+
123
+ class << self
124
+ alias_method :exists?, :exist?
125
+ end
126
+
127
+ def self.directory?(path)
128
+ if path.respond_to? :entry
129
+ path.entry.is_a? MockDir
130
+ else
131
+ result = FileSystem.find(path)
132
+ result ? result.entry.is_a?(MockDir) : false
133
+ end
134
+ end
135
+
136
+ def self.symlink?(path)
137
+ if path.respond_to? :entry
138
+ path.is_a? MockSymlink
139
+ else
140
+ FileSystem.find(path).is_a? MockSymlink
141
+ end
142
+ end
143
+
144
+ def self.file?(path)
145
+ if path.respond_to? :entry
146
+ path.entry.is_a? MockFile
147
+ else
148
+ result = FileSystem.find(path)
149
+ result ? result.entry.is_a?(MockFile) : false
150
+ end
151
+ end
152
+
153
+ def self.expand_path(*args)
154
+ RealFile.expand_path(*args)
155
+ end
156
+
157
+ def self.basename(*args)
158
+ RealFile.basename(*args)
159
+ end
160
+
161
+ def self.dirname(path)
162
+ RealFile.dirname(path)
163
+ end
164
+
165
+ def self.readlink(path)
166
+ symlink = FileSystem.find(path)
167
+ FileSystem.find(symlink.target).to_s
168
+ end
169
+
170
+ def self.open(path, mode='r')
171
+ if block_given?
172
+ yield new(path, mode)
173
+ else
174
+ new(path, mode)
175
+ end
176
+ end
177
+
178
+ def self.read(path)
179
+ file = new(path)
180
+ if file.exists?
181
+ file.read
182
+ else
183
+ raise Errno::ENOENT
184
+ end
185
+ end
186
+
187
+ def self.readlines(path)
188
+ read(path).split("\n")
189
+ end
190
+
191
+ attr_reader :path
192
+ def initialize(path, mode = nil)
193
+ @path = path
194
+ @mode = mode
195
+ @file = FileSystem.find(path)
196
+ @open = true
197
+ end
198
+
199
+ def close
200
+ @open = false
201
+ end
202
+
203
+ def read
204
+ raise IOError.new('closed stream') unless @open
205
+ @file.content
206
+ end
207
+
208
+ def exists?
209
+ @file
210
+ end
211
+
212
+ def puts(content)
213
+ write(content + "\n")
214
+ end
215
+
216
+ def write(content)
217
+ raise IOError.new('closed stream') unless @open
218
+
219
+ if !File.exists?(@path)
220
+ @file = FileSystem.add(path, MockFile.new)
221
+ end
222
+
223
+ @file.content += content
224
+ end
225
+ alias_method :print, :write
226
+ alias_method :<<, :write
227
+
228
+ def flush; self; end
229
+ end
230
+
231
+ class Dir
232
+ def self.glob(pattern)
233
+ if pattern[-1,1] == '*'
234
+ blk = proc { |entry| entry.to_s }
235
+ else
236
+ blk = proc { |entry| entry[1].parent.to_s }
237
+ end
238
+ (FileSystem.find(pattern) || []).map(&blk).uniq.sort
239
+ end
240
+
241
+ def self.[](pattern)
242
+ glob(pattern)
243
+ end
244
+
245
+ def self.chdir(dir, &blk)
246
+ FileSystem.chdir(dir, &blk)
247
+ end
248
+ end
249
+
250
+ module FileSystem
251
+ extend self
252
+
253
+ def dir_levels
254
+ @dir_levels ||= []
255
+ end
256
+
257
+ def fs
258
+ @fs ||= MockDir.new('.')
259
+ end
260
+
261
+ def clear
262
+ @dir_levels = nil
263
+ @fs = nil
264
+ end
265
+
266
+ def files
267
+ fs.values
268
+ end
269
+
270
+ def find(path)
271
+ parts = path_parts(normalize_path(path))
272
+
273
+ target = parts[0...-1].inject(fs) do |dir, part|
274
+ dir[part] || {}
275
+ end
276
+
277
+ case parts.last
278
+ when '*'
279
+ target.values
280
+ else
281
+ target[parts.last]
282
+ end
283
+ end
284
+
285
+ def add(path, object=MockDir.new)
286
+ parts = path_parts(normalize_path(path))
287
+
288
+ d = parts[0...-1].inject(fs) do |dir, part|
289
+ dir[part] ||= MockDir.new(part, dir)
290
+ end
291
+
292
+ object.name = parts.last
293
+ object.parent = d
294
+ d[parts.last] ||= object
295
+ end
296
+
297
+ # copies directories and files from the real filesystem
298
+ # into our fake one
299
+ def clone(path)
300
+ path = File.expand_path(path)
301
+ pattern = File.join(path, '**', '*')
302
+ files = RealFile.file?(path) ? [path] : [path] + RealDir.glob(pattern, RealFile::FNM_DOTMATCH)
303
+
304
+ files.each do |f|
305
+ if RealFile.file?(f)
306
+ FileUtils.mkdir_p(File.dirname(f))
307
+ File.open(f, 'w') do |g|
308
+ g.print RealFile.open(f){|h| h.read }
309
+ end
310
+ elsif RealFile.directory?(f)
311
+ FileUtils.mkdir_p(f)
312
+ elsif RealFile.symlink?(f)
313
+ FileUtils.ln_s()
314
+ end
315
+ end
316
+ end
317
+
318
+ def delete(path)
319
+ if dir = FileSystem.find(path)
320
+ dir.parent.delete(dir.name)
321
+ end
322
+ end
323
+
324
+ def chdir(dir, &blk)
325
+ new_dir = find(dir)
326
+ dir_levels.push dir if blk
327
+
328
+ raise Errno::ENOENT, dir unless new_dir
329
+
330
+ dir_levels.push dir if !blk
331
+ blk.call if blk
332
+ ensure
333
+ dir_levels.pop if blk
334
+ end
335
+
336
+ def path_parts(path)
337
+ path.split(File::PATH_SEPARATOR).reject { |part| part.empty? }
338
+ end
339
+
340
+ def normalize_path(path)
341
+ if Pathname.new(path).absolute?
342
+ File.expand_path(path)
343
+ else
344
+ parts = dir_levels + [path]
345
+ File.expand_path(File.join(*parts))
346
+ end
347
+ end
348
+
349
+ def current_dir
350
+ find(normalize_path('.'))
351
+ end
352
+ end
353
+
354
+ class MockFile
355
+ attr_accessor :name, :parent, :content
356
+
357
+ def initialize(name = nil, parent = nil)
358
+ @name = name
359
+ @parent = parent
360
+ @content = ''
361
+ end
362
+
363
+ def clone(parent = nil)
364
+ clone = super()
365
+ clone.parent = parent if parent
366
+ clone
367
+ end
368
+
369
+ def entry
370
+ self
371
+ end
372
+
373
+ def inspect
374
+ "(MockFile name:#{name.inspect} parent:#{parent.to_s.inspect} size:#{content.size})"
375
+ end
376
+
377
+ def to_s
378
+ File.join(parent.to_s, name)
379
+ end
380
+ end
381
+
382
+ class MockDir < Hash
383
+ attr_accessor :name, :parent
384
+
385
+ def initialize(name = nil, parent = nil)
386
+ @name = name
387
+ @parent = parent
388
+ end
389
+
390
+ def entry
391
+ self
392
+ end
393
+
394
+ def inspect
395
+ "(MockDir name:#{name.inspect} parent:#{parent.to_s.inspect} size:#{size})"
396
+ end
397
+
398
+ def clone(parent = nil)
399
+ clone = Marshal.load(Marshal.dump(self))
400
+ clone.each do |key, value|
401
+ value.parent = clone
402
+ end
403
+ clone.parent = parent if parent
404
+ clone
405
+ end
406
+
407
+ def to_s
408
+ if parent && parent.to_s != '.'
409
+ File.join(parent.to_s, name)
410
+ elsif parent && parent.to_s == '.'
411
+ "#{File::PATH_SEPARATOR}#{name}"
412
+ else
413
+ name
414
+ end
415
+ end
416
+ end
417
+
418
+ class MockSymlink
419
+ attr_accessor :name, :target
420
+ alias_method :to_s, :name
421
+
422
+ def initialize(target)
423
+ @target = target
424
+ end
425
+
426
+ def inspect
427
+ "symlink(#{target.split('/').last})"
428
+ end
429
+
430
+ def entry
431
+ FileSystem.find(target)
432
+ end
433
+
434
+ def method_missing(*args, &block)
435
+ entry.send(*args, &block)
436
+ end
437
+ end
438
+ end
439
+
440
+ Object.class_eval do
441
+ remove_const(:Dir)
442
+ remove_const(:File)
443
+ remove_const(:FileUtils)
444
+ end
445
+
446
+ File = FakeFS::File
447
+ FileUtils = FakeFS::FileUtils
448
+ Dir = FakeFS::Dir