dfect 0.0.0
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/LICENSE +15 -0
- data/doc/api/classes/Dfect.html +872 -0
- data/doc/api/classes/Object.html +72 -0
- data/doc/api/created.rid +1 -0
- data/doc/api/css/main.css +263 -0
- data/doc/api/css/panel.css +383 -0
- data/doc/api/css/reset.css +53 -0
- data/doc/api/files/ANN_txt.html +80 -0
- data/doc/api/files/LICENSE.html +74 -0
- data/doc/api/files/lib/dfect/auto_rb.html +78 -0
- data/doc/api/files/lib/dfect_rb.html +72 -0
- data/doc/api/i/arrows.png +0 -0
- data/doc/api/i/results_bg.png +0 -0
- data/doc/api/i/tree_bg.png +0 -0
- data/doc/api/index.html +14 -0
- data/doc/api/js/jquery-1.3.2.min.js +19 -0
- data/doc/api/js/jquery-effect.js +593 -0
- data/doc/api/js/main.js +22 -0
- data/doc/api/js/searchdoc.js +606 -0
- data/doc/api/panel/index.html +63 -0
- data/doc/api/panel/search_index.js +1 -0
- data/doc/api/panel/tree.js +1 -0
- data/doc/history.erb +4 -0
- data/doc/index.erb +6 -0
- data/doc/intro.erb +78 -0
- data/doc/setup.erb +34 -0
- data/doc/usage.erb +186 -0
- data/lib/dfect/auto.rb +24 -0
- data/lib/dfect.rb +621 -0
- data/rakefile +19 -0
- data/test/dfect.rb +146 -0
- metadata +95 -0
data/lib/dfect.rb
ADDED
@@ -0,0 +1,621 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 Suraj N. Kurapati
|
3
|
+
# See the LICENSE file for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
# load interactive debugger
|
9
|
+
begin
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'rubygems'
|
13
|
+
rescue LoadError
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'ruby-debug'
|
17
|
+
|
18
|
+
rescue LoadError
|
19
|
+
require 'irb'
|
20
|
+
end
|
21
|
+
|
22
|
+
module Dfect
|
23
|
+
class << self
|
24
|
+
##
|
25
|
+
# Hash of test results, assembled by #run.
|
26
|
+
#
|
27
|
+
# [:execution]
|
28
|
+
# Hierarchical trace of all tests executed, where each test is
|
29
|
+
# represented by its description, is mapped to an Array of
|
30
|
+
# nested tests, and may contain zero or more assertion failures.
|
31
|
+
#
|
32
|
+
# Assertion failures are represented as a Hash:
|
33
|
+
#
|
34
|
+
# ["fail"]
|
35
|
+
# Description of the assertion failure.
|
36
|
+
#
|
37
|
+
# ["code"]
|
38
|
+
# Source code surrounding the point of failure.
|
39
|
+
#
|
40
|
+
# ["vars"]
|
41
|
+
# Local variables visible at the point of failure.
|
42
|
+
#
|
43
|
+
# ["call"]
|
44
|
+
# Stack trace leading to the point of failure.
|
45
|
+
#
|
46
|
+
# [:statistics]
|
47
|
+
# Hash of counts of major events in test execution:
|
48
|
+
#
|
49
|
+
# [:passed_assertions]
|
50
|
+
# Number of assertions that held true.
|
51
|
+
#
|
52
|
+
# [:failed_assertions]
|
53
|
+
# Number of assertions that did not hold true.
|
54
|
+
#
|
55
|
+
# [:uncaught_exceptions]
|
56
|
+
# Number of exceptions that were not rescued.
|
57
|
+
#
|
58
|
+
attr_reader :report
|
59
|
+
|
60
|
+
##
|
61
|
+
# Hash of choices that affect how Dfect operates.
|
62
|
+
#
|
63
|
+
# [:debug]
|
64
|
+
# Launch an interactive debugger
|
65
|
+
# during assertion failures so
|
66
|
+
# the user can investigate them.
|
67
|
+
#
|
68
|
+
# The default value is $DEBUG.
|
69
|
+
#
|
70
|
+
# [:quiet]
|
71
|
+
# Do not print the report
|
72
|
+
# after executing all tests.
|
73
|
+
#
|
74
|
+
# The default value is false.
|
75
|
+
#
|
76
|
+
attr_accessor :options
|
77
|
+
|
78
|
+
##
|
79
|
+
# Defines a new test, composed of the given
|
80
|
+
# description and the given block to execute.
|
81
|
+
#
|
82
|
+
# A test may contain nested tests.
|
83
|
+
#
|
84
|
+
# ==== Parameters
|
85
|
+
#
|
86
|
+
# [description]
|
87
|
+
# A short summary of the test being defined.
|
88
|
+
#
|
89
|
+
# ==== Examples
|
90
|
+
#
|
91
|
+
# D "a new array" do
|
92
|
+
# D .< { @array = [] }
|
93
|
+
#
|
94
|
+
# D "must be empty" do
|
95
|
+
# T { @array.empty? }
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# D "when populated" do
|
99
|
+
# D .< { @array.push 55 }
|
100
|
+
#
|
101
|
+
# D "must not be empty" do
|
102
|
+
# F { @array.empty? }
|
103
|
+
# end
|
104
|
+
# end
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
def D description = caller.first, &block
|
108
|
+
raise ArgumentError, 'block must be given' unless block
|
109
|
+
@curr_suite.tests << Suite::Test.new(description.to_s, block)
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Registers the given block to be executed
|
114
|
+
# before each nested test inside this test.
|
115
|
+
#
|
116
|
+
# ==== Examples
|
117
|
+
#
|
118
|
+
# D .< { puts "before each nested test" }
|
119
|
+
#
|
120
|
+
# D .< do
|
121
|
+
# puts "before each nested test"
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
def < &block
|
125
|
+
raise ArgumentError, 'block must be given' unless block
|
126
|
+
@curr_suite.before_each << block
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Registers the given block to be executed
|
131
|
+
# after each nested test inside this test.
|
132
|
+
#
|
133
|
+
# ==== Examples
|
134
|
+
#
|
135
|
+
# D .> { puts "after each nested test" }
|
136
|
+
#
|
137
|
+
# D .> do
|
138
|
+
# puts "after each nested test"
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
def > &block
|
142
|
+
raise ArgumentError, 'block must be given' unless block
|
143
|
+
@curr_suite.after_each << block
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Registers the given block to be executed
|
148
|
+
# before all nested tests inside this test.
|
149
|
+
#
|
150
|
+
# ==== Examples
|
151
|
+
#
|
152
|
+
# D .<< { puts "before all nested tests" }
|
153
|
+
#
|
154
|
+
# D .<< do
|
155
|
+
# puts "before all nested tests"
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
def << &block
|
159
|
+
raise ArgumentError, 'block must be given' unless block
|
160
|
+
@curr_suite.before_all << block
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# Registers the given block to be executed
|
165
|
+
# after all nested tests inside this test.
|
166
|
+
#
|
167
|
+
# ==== Examples
|
168
|
+
#
|
169
|
+
# D .>> { puts "after all nested tests" }
|
170
|
+
#
|
171
|
+
# D .>> do
|
172
|
+
# puts "after all nested tests"
|
173
|
+
# end
|
174
|
+
#
|
175
|
+
def >> &block
|
176
|
+
raise ArgumentError, 'block must be given' unless block
|
177
|
+
@curr_suite.after_all << block
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Asserts that the result of the given block is
|
182
|
+
# neither nil nor false and returns that result.
|
183
|
+
#
|
184
|
+
# ==== Parameters
|
185
|
+
#
|
186
|
+
# [message]
|
187
|
+
# Optional message to show in the
|
188
|
+
# report if this assertion fails.
|
189
|
+
#
|
190
|
+
# ==== Examples
|
191
|
+
#
|
192
|
+
# # no message specified:
|
193
|
+
#
|
194
|
+
# T { true } # passes
|
195
|
+
#
|
196
|
+
# T { false } # fails
|
197
|
+
# T { nil } # fails
|
198
|
+
#
|
199
|
+
# # message specified:
|
200
|
+
#
|
201
|
+
# T( "computers do not doublethink" ) { 2 + 2 != 5 } # passes
|
202
|
+
#
|
203
|
+
def T message = 'block must yield true (!nil && !false)', &block
|
204
|
+
raise ArgumentError, 'block must be given' unless block
|
205
|
+
|
206
|
+
if result = call(block)
|
207
|
+
@exec_stats[:passed_assertions] += 1
|
208
|
+
else
|
209
|
+
@exec_stats[:failed_assertions] += 1
|
210
|
+
debug block, message
|
211
|
+
end
|
212
|
+
|
213
|
+
result
|
214
|
+
end
|
215
|
+
|
216
|
+
##
|
217
|
+
# Asserts that the result of the given block is
|
218
|
+
# either nil or false and returns that result.
|
219
|
+
#
|
220
|
+
# ==== Parameters
|
221
|
+
#
|
222
|
+
# [message]
|
223
|
+
# Optional message to show in the
|
224
|
+
# report if this assertion fails.
|
225
|
+
#
|
226
|
+
# ==== Examples
|
227
|
+
#
|
228
|
+
# # no message specified:
|
229
|
+
#
|
230
|
+
# F { true } # fails
|
231
|
+
#
|
232
|
+
# F { false } # passes
|
233
|
+
# F { nil } # passes
|
234
|
+
#
|
235
|
+
# # message specified:
|
236
|
+
#
|
237
|
+
# F( "computers do not doublethink" ) { 2 + 2 == 5 } # passes
|
238
|
+
#
|
239
|
+
def F message = 'block must yield false (nil || false)', &block
|
240
|
+
raise ArgumentError, 'block must be given' unless block
|
241
|
+
|
242
|
+
if result = call(block)
|
243
|
+
@exec_stats[:failed_assertions] += 1
|
244
|
+
debug block, message
|
245
|
+
else
|
246
|
+
@exec_stats[:passed_assertions] += 1
|
247
|
+
end
|
248
|
+
|
249
|
+
result
|
250
|
+
end
|
251
|
+
|
252
|
+
##
|
253
|
+
# Asserts that one of the given kinds of exceptions is raised when the
|
254
|
+
# given block is executed, and returns the exception that was raised.
|
255
|
+
#
|
256
|
+
# ==== Parameters
|
257
|
+
#
|
258
|
+
# [message]
|
259
|
+
# Optional message to show in the
|
260
|
+
# report if this assertion fails.
|
261
|
+
#
|
262
|
+
# [kinds]
|
263
|
+
# Exception classes that must be raised by the given block.
|
264
|
+
#
|
265
|
+
# If none are given, then StandardError is assumed (similar to how a
|
266
|
+
# plain 'rescue' statement without any arguments catches StandardError).
|
267
|
+
#
|
268
|
+
# ==== Examples
|
269
|
+
#
|
270
|
+
# # no exceptions specified:
|
271
|
+
#
|
272
|
+
# E { } # fails
|
273
|
+
# E { raise } # passes
|
274
|
+
#
|
275
|
+
# # single exception specified:
|
276
|
+
#
|
277
|
+
# E( ArgumentError ) { raise ArgumentError }
|
278
|
+
# E( "argument must be invalid", ArgumentError ) { raise ArgumentError }
|
279
|
+
#
|
280
|
+
# # multiple exceptions specified:
|
281
|
+
#
|
282
|
+
# E( SyntaxError, NameError ) { eval "..." }
|
283
|
+
# E( "string must compile", SyntaxError, NameError ) { eval "..." }
|
284
|
+
#
|
285
|
+
def E message = nil, *kinds, &block
|
286
|
+
raise ArgumentError, 'block must be given' unless block
|
287
|
+
|
288
|
+
if message.is_a? Class
|
289
|
+
kinds.unshift message
|
290
|
+
message = nil
|
291
|
+
end
|
292
|
+
|
293
|
+
kinds << StandardError if kinds.empty?
|
294
|
+
message ||= "block must raise #{kinds.join ' or '}"
|
295
|
+
|
296
|
+
begin
|
297
|
+
block.call
|
298
|
+
|
299
|
+
rescue *kinds => raised
|
300
|
+
@exec_stats[:passed_assertions] += 1
|
301
|
+
|
302
|
+
rescue Exception => raised
|
303
|
+
@exec_stats[:failed_assertions] += 1
|
304
|
+
|
305
|
+
# debug the uncaught exception...
|
306
|
+
debug_uncaught_exception block, raised
|
307
|
+
|
308
|
+
# ...in addition to debugging this assertion
|
309
|
+
debug block, [message, {'block raised' => raised}]
|
310
|
+
end
|
311
|
+
|
312
|
+
raised
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# Asserts that the given symbol is thrown when
|
317
|
+
# the given block is executed, and returns the
|
318
|
+
# value that was thrown along with the symbol.
|
319
|
+
#
|
320
|
+
# ==== Parameters
|
321
|
+
#
|
322
|
+
# [message]
|
323
|
+
# Optional message to show in the
|
324
|
+
# report if this assertion fails.
|
325
|
+
#
|
326
|
+
# [symbol]
|
327
|
+
# Symbol that must be thrown by the given block.
|
328
|
+
#
|
329
|
+
# ==== Examples
|
330
|
+
#
|
331
|
+
# # no message specified:
|
332
|
+
#
|
333
|
+
# C(:foo) { throw :foo } # passes
|
334
|
+
#
|
335
|
+
# C(:foo) { throw :bar } # fails
|
336
|
+
# C(:foo) { } # fails
|
337
|
+
#
|
338
|
+
# # message specified:
|
339
|
+
#
|
340
|
+
# C( ":foo must be thrown", :foo ) { throw :bar } # fails
|
341
|
+
#
|
342
|
+
def C message = nil, symbol = nil, &block
|
343
|
+
raise ArgumentError, 'block must be given' unless block
|
344
|
+
|
345
|
+
if message.is_a? Symbol and not symbol
|
346
|
+
symbol = message
|
347
|
+
message = nil
|
348
|
+
end
|
349
|
+
|
350
|
+
raise ArgumentError, 'symbol must be given' unless symbol
|
351
|
+
|
352
|
+
symbol = symbol.to_sym
|
353
|
+
message ||= "block must throw #{symbol.inspect}"
|
354
|
+
|
355
|
+
# if nothing was thrown, the result of catch()
|
356
|
+
# is simply the result of executing the block
|
357
|
+
result = catch(symbol) { call block; self }
|
358
|
+
|
359
|
+
if result == self
|
360
|
+
@exec_stats[:failed_assertions] += 1
|
361
|
+
debug block, message
|
362
|
+
else
|
363
|
+
@exec_stats[:passed_assertions] += 1
|
364
|
+
result
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
##
|
369
|
+
# Executes all tests defined thus far and stores the results in #report.
|
370
|
+
#
|
371
|
+
def run
|
372
|
+
# clear previous results
|
373
|
+
@exec_stats.clear
|
374
|
+
@exec_trace.clear
|
375
|
+
@test_stack.clear
|
376
|
+
|
377
|
+
# make new results
|
378
|
+
catch :stop_dfect_execution do
|
379
|
+
execute
|
380
|
+
end
|
381
|
+
|
382
|
+
# print new results
|
383
|
+
puts @report.to_yaml unless @options[:quiet]
|
384
|
+
end
|
385
|
+
|
386
|
+
##
|
387
|
+
# Stops the execution of the #run method or raises an
|
388
|
+
# exception if that method is not currently executing.
|
389
|
+
#
|
390
|
+
def stop
|
391
|
+
throw :stop_dfect_execution
|
392
|
+
end
|
393
|
+
|
394
|
+
private
|
395
|
+
|
396
|
+
##
|
397
|
+
# Executes the current test suite recursively.
|
398
|
+
#
|
399
|
+
def execute
|
400
|
+
suite = @curr_suite
|
401
|
+
trace = @exec_trace
|
402
|
+
|
403
|
+
suite.before_all.each {|b| call b }
|
404
|
+
|
405
|
+
suite.tests.each do |test|
|
406
|
+
suite.before_each.each {|b| call b }
|
407
|
+
|
408
|
+
@test_stack.push test
|
409
|
+
|
410
|
+
begin
|
411
|
+
# create nested suite
|
412
|
+
@curr_suite = Suite.new
|
413
|
+
@exec_trace = []
|
414
|
+
|
415
|
+
# populate nested suite
|
416
|
+
call test.block
|
417
|
+
|
418
|
+
# execute nested suite
|
419
|
+
execute
|
420
|
+
|
421
|
+
ensure
|
422
|
+
# restore outer values
|
423
|
+
@curr_suite = suite
|
424
|
+
|
425
|
+
trace << build_trace(@exec_trace)
|
426
|
+
@exec_trace = trace
|
427
|
+
end
|
428
|
+
|
429
|
+
@test_stack.pop
|
430
|
+
|
431
|
+
suite.after_each.each {|b| call b }
|
432
|
+
end
|
433
|
+
|
434
|
+
suite.after_all.each {|b| call b }
|
435
|
+
end
|
436
|
+
|
437
|
+
##
|
438
|
+
# Invokes the given block and debugs any
|
439
|
+
# exceptions that may arise as a result.
|
440
|
+
#
|
441
|
+
def call block
|
442
|
+
begin
|
443
|
+
block.call
|
444
|
+
rescue Exception => e
|
445
|
+
debug_uncaught_exception block, e
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
INTERNALS = File.dirname(__FILE__) #:nodoc:
|
450
|
+
|
451
|
+
##
|
452
|
+
# Adds debugging information to the report.
|
453
|
+
#
|
454
|
+
# ==== Parameters
|
455
|
+
#
|
456
|
+
# [context]
|
457
|
+
# Binding of code being debugged. This
|
458
|
+
# can be either a Binding or Proc object.
|
459
|
+
#
|
460
|
+
# [message]
|
461
|
+
# Message describing the failure
|
462
|
+
# in the code being debugged.
|
463
|
+
#
|
464
|
+
# [backtrace]
|
465
|
+
# Stack trace corresponding to point of
|
466
|
+
# failure in the code being debugged.
|
467
|
+
#
|
468
|
+
def debug context, message = nil, backtrace = caller
|
469
|
+
# allow a Proc to be passed instead of a binding
|
470
|
+
if context.respond_to? :binding
|
471
|
+
context = context.binding
|
472
|
+
end
|
473
|
+
|
474
|
+
# omit internals from failure details
|
475
|
+
backtrace = backtrace.reject {|s| s.include? INTERNALS }
|
476
|
+
|
477
|
+
# record failure details in the report
|
478
|
+
#
|
479
|
+
# NOTE: using string keys here instead
|
480
|
+
# of symbols because they make
|
481
|
+
# the YAML output easier to read
|
482
|
+
#
|
483
|
+
details = {
|
484
|
+
# user message
|
485
|
+
'fail' => message,
|
486
|
+
|
487
|
+
# code snippet
|
488
|
+
'code' => (
|
489
|
+
if frame = backtrace.first
|
490
|
+
file, line = frame.scan(/(.+?):(\d+(?=:|\z))/).first
|
491
|
+
|
492
|
+
if source = @file_cache[file]
|
493
|
+
line = line.to_i
|
494
|
+
|
495
|
+
radius = 5 # number of surrounding lines to show
|
496
|
+
region = [line - radius, 1].max ..
|
497
|
+
[line + radius, source.length].min
|
498
|
+
|
499
|
+
# ensure proper alignment by zero-padding line numbers
|
500
|
+
format = "%2s %0#{region.last.to_s.length}d %s"
|
501
|
+
|
502
|
+
pretty = region.map do |n|
|
503
|
+
format % [('=>' if n == line), n, source[n-1].chomp]
|
504
|
+
end
|
505
|
+
|
506
|
+
pretty.unshift "[#{region.inspect}] in #{file}"
|
507
|
+
|
508
|
+
# to_yaml will render the paragraph without escaping newlines
|
509
|
+
# ONLY IF the first and last character are non-whitespace
|
510
|
+
pretty.join("\n").strip
|
511
|
+
end
|
512
|
+
end
|
513
|
+
),
|
514
|
+
|
515
|
+
# variable values
|
516
|
+
'vars' => (
|
517
|
+
locals = eval('::Kernel.local_variables.map {|v| [v.to_s, ::Kernel.eval(v.to_s)] }', context, __FILE__, __LINE__)
|
518
|
+
|
519
|
+
Hash[*locals.flatten]
|
520
|
+
),
|
521
|
+
|
522
|
+
# stack trace
|
523
|
+
'call' => backtrace,
|
524
|
+
}
|
525
|
+
|
526
|
+
@exec_trace << details
|
527
|
+
|
528
|
+
# allow user to investigate the failure
|
529
|
+
if @options[:debug]
|
530
|
+
# show the failure to the user
|
531
|
+
puts build_trace(details).to_yaml
|
532
|
+
|
533
|
+
# start the investigation
|
534
|
+
if Kernel.respond_to? :debugger
|
535
|
+
eval '::Kernel.debugger', context, __FILE__, __LINE__
|
536
|
+
else
|
537
|
+
IRB.setup nil
|
538
|
+
|
539
|
+
env = IRB::WorkSpace.new(context)
|
540
|
+
irb = IRB::Irb.new(env)
|
541
|
+
IRB.conf[:MAIN_CONTEXT] = irb.context
|
542
|
+
|
543
|
+
catch :IRB_EXIT do
|
544
|
+
irb.eval_input
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
nil
|
550
|
+
end
|
551
|
+
|
552
|
+
##
|
553
|
+
# Debugs the given uncaught exception inside the given context.
|
554
|
+
#
|
555
|
+
def debug_uncaught_exception context, exception
|
556
|
+
@exec_stats[:uncaught_exceptions] += 1
|
557
|
+
debug context, exception, exception.backtrace
|
558
|
+
end
|
559
|
+
|
560
|
+
##
|
561
|
+
# Returns a report that associates the given
|
562
|
+
# failure details with the currently running test.
|
563
|
+
#
|
564
|
+
def build_trace details
|
565
|
+
if @test_stack.empty?
|
566
|
+
details
|
567
|
+
else
|
568
|
+
{ @test_stack.last.desc => details }
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
#:stopdoc:
|
573
|
+
|
574
|
+
class Suite
|
575
|
+
attr_reader :tests, :before_each, :after_each, :before_all, :after_all
|
576
|
+
|
577
|
+
def initialize
|
578
|
+
@tests = []
|
579
|
+
@before_each = []
|
580
|
+
@after_each = []
|
581
|
+
@before_all = []
|
582
|
+
@after_all = []
|
583
|
+
end
|
584
|
+
|
585
|
+
Test = Struct.new :desc, :block
|
586
|
+
end
|
587
|
+
|
588
|
+
#:startdoc:
|
589
|
+
end
|
590
|
+
|
591
|
+
@options = {:debug => $DEBUG, :quiet => false}
|
592
|
+
|
593
|
+
@exec_stats = Hash.new {|h,k| h[k] = 0 }
|
594
|
+
@exec_trace = []
|
595
|
+
@report = {:execution => @exec_trace, :statistics => @exec_stats}.freeze
|
596
|
+
|
597
|
+
@curr_suite = class << self; Suite.new; end
|
598
|
+
|
599
|
+
@test_stack = []
|
600
|
+
@file_cache = Hash.new {|h,k| h[k] = File.readlines(k) rescue nil }
|
601
|
+
|
602
|
+
##
|
603
|
+
# Allows before and after hooks to be specified via
|
604
|
+
# the D() method syntax when this module is mixed-in:
|
605
|
+
#
|
606
|
+
# D .< { puts "before each nested test" }
|
607
|
+
# D .> { puts "after each nested test" }
|
608
|
+
# D .<< { puts "before all nested tests" }
|
609
|
+
# D .>> { puts "after all nested tests" }
|
610
|
+
#
|
611
|
+
D = self
|
612
|
+
|
613
|
+
# provide mixin-able assertion methods
|
614
|
+
methods(false).grep(/^[[:upper:]]$/).each do |name|
|
615
|
+
#
|
616
|
+
# XXX: using eval() on a string because Ruby 1.8's
|
617
|
+
# define_method() cannot take a block parameter
|
618
|
+
#
|
619
|
+
eval "def #{name}(*a, &b) ::#{self}.#{name}(*a, &b) end", binding, __FILE__, __LINE__
|
620
|
+
end
|
621
|
+
end
|
data/rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 Suraj N. Kurapati
|
3
|
+
# See the LICENSE file for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'inochi'
|
7
|
+
|
8
|
+
Inochi.init :Dfect,
|
9
|
+
:version => '0.0.0',
|
10
|
+
:release => '2009-04-13',
|
11
|
+
:website => 'http://snk.tuxfamily.org/lib/dfect',
|
12
|
+
:tagline => 'Assertion testing library for Ruby'
|
13
|
+
|
14
|
+
Inochi.rake :Dfect,
|
15
|
+
:test_with => :dfect,
|
16
|
+
:rubyforge_project => 'sunaku',
|
17
|
+
:upload_target => File.expand_path('~/www/lib/dfect/'),
|
18
|
+
:upload_delete => true,
|
19
|
+
:inochi_consumer => false
|