assert2 0.3.2 → 0.3.3
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/lib/assert2.rb +323 -216
- data/lib/assert2/flunk.rb +87 -0
- data/lib/assert2/null_reflector.rb +0 -0
- data/lib/assert2/ripdoc.html.erb +182 -0
- data/lib/assert2/ripdoc.rb +413 -0
- data/lib/assert2/ripper_reflector.rb +726 -0
- data/lib/{ruby_reflector.rb → assert2/rubynode_reflector.rb} +100 -71
- data/lib/assert2/xpath.rb +159 -0
- metadata +47 -41
data/lib/assert2.rb
CHANGED
@@ -1,216 +1,323 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
#
|
50
|
-
#
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
#
|
67
|
-
#
|
68
|
-
# - +
|
69
|
-
# - +
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
#
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
end
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
# FIXME the first failing assertion of a batch should suggest you get with Ruby1.9...
|
4
|
+
# TODO install Coulor
|
5
|
+
# TODO add :verbose => option to assert{}
|
6
|
+
# TODO pay for Staff Benda Bilili ALBUM: Tr�s Tr�s Fort (Promo Sampler) !
|
7
|
+
# TODO evaluate parts[3]
|
8
|
+
# ERGO if the block is a block, decorate with do-end
|
9
|
+
# ERGO decorate assert_latest's block at fault time
|
10
|
+
|
11
|
+
#~ if RUBY_VERSION > '1.8.6'
|
12
|
+
#~ puts "\nWarning: This version of assert{ 2.0 } requires\n" +
|
13
|
+
#~ "RubyNode, which only works on Ruby versions < 1.8.7.\n" +
|
14
|
+
#~ "Upgrade to Ruby1.9, and try 'gem install assert21'\n\n"
|
15
|
+
#~ end
|
16
|
+
|
17
|
+
#~ def colorize(whatever)
|
18
|
+
#~ # FIXME stop ignoring this and start colorizing v2.1!
|
19
|
+
#~ end
|
20
|
+
|
21
|
+
if RUBY_VERSION < '1.9.0'
|
22
|
+
require 'assert2/rubynode_reflector' # FIXME default to null_reflector if rubynode not available
|
23
|
+
else
|
24
|
+
require 'assert2/ripper_reflector'
|
25
|
+
end
|
26
|
+
|
27
|
+
# CONSIDER fix if an assertion contains more than one command - reflect it all!
|
28
|
+
|
29
|
+
module Test; module Unit; module Assertions
|
30
|
+
|
31
|
+
FlunkError = if defined? Test::Unit::AssertionFailedError
|
32
|
+
Test::Unit::AssertionFailedError
|
33
|
+
else
|
34
|
+
MiniTest::Assertion
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_diagnostic(whatever = nil, &block)
|
38
|
+
@__additional_diagnostics ||= []
|
39
|
+
|
40
|
+
if whatever == :clear
|
41
|
+
@__additional_diagnostics = []
|
42
|
+
whatever = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
@__additional_diagnostics += [whatever, block] # note .compact will take care of them if they don't exist
|
46
|
+
end
|
47
|
+
|
48
|
+
def assert(*args, &block)
|
49
|
+
# This assertion calls a block, and faults if it returns
|
50
|
+
# +false+ or +nil+. The fault diagnostic will reflect the
|
51
|
+
# assertion's complete source - with comments - and will
|
52
|
+
# reevaluate the every variable and expression in the
|
53
|
+
# block.
|
54
|
+
#
|
55
|
+
# The first argument can be a diagnostic string:
|
56
|
+
#
|
57
|
+
# assert("foo failed"){ foo() }
|
58
|
+
#
|
59
|
+
# The fault diagnostic will print that line.
|
60
|
+
#
|
61
|
+
# The next time you think to write any of these assertions...
|
62
|
+
#
|
63
|
+
# - +assert+
|
64
|
+
# - +assert_equal+
|
65
|
+
# - +assert_instance_of+
|
66
|
+
# - +assert_kind_of+
|
67
|
+
# - +assert_operator+
|
68
|
+
# - +assert_match+
|
69
|
+
# - +assert_not_nil+
|
70
|
+
#
|
71
|
+
# use <code>assert{ 2.1 }</code> instead.
|
72
|
+
#
|
73
|
+
# If no block is provided, the assertion calls +assert_classic+,
|
74
|
+
# which simulates RubyUnit's standard <code>assert()</code>.
|
75
|
+
if block
|
76
|
+
assert_ *args, &block
|
77
|
+
else
|
78
|
+
assert_classic *args
|
79
|
+
end
|
80
|
+
return true # or die trying ;-)
|
81
|
+
end
|
82
|
+
|
83
|
+
module Coulor #:nodoc:
|
84
|
+
def colorize(we_color)
|
85
|
+
@@we_color = we_color
|
86
|
+
end
|
87
|
+
unless defined? BOLD
|
88
|
+
BOLD = "\e[1m"
|
89
|
+
CLEAR = "\e[0m"
|
90
|
+
end # ERGO modularize these; anneal with Win32
|
91
|
+
def colour(text, colour_code)
|
92
|
+
return colour_code + text + CLEAR if colorize?
|
93
|
+
return text
|
94
|
+
end
|
95
|
+
def colorize? # ERGO how other libraries set these options transparent??
|
96
|
+
we_color = (@@we_color rescue true) # ERGO parens needed?
|
97
|
+
return false if ENV['EMACS'] == 't'
|
98
|
+
return (we_color == :always or we_color && $stdout.tty?)
|
99
|
+
end
|
100
|
+
def bold(text)
|
101
|
+
return BOLD + text + CLEAR if colorize?
|
102
|
+
return text
|
103
|
+
end
|
104
|
+
def green(text); colour(text, "\e[32m"); end
|
105
|
+
def red(text); colour(text, "\e[31m"); end
|
106
|
+
def magenta(text); colour(text, "\e[35m"); end
|
107
|
+
def blue(text); colour(text, "\e[34m"); end
|
108
|
+
def orange(text); colour(text, "\e[3Bm"); end
|
109
|
+
end
|
110
|
+
|
111
|
+
class RubyReflector
|
112
|
+
attr_accessor :captured_block_vars,
|
113
|
+
:args
|
114
|
+
|
115
|
+
include Coulor
|
116
|
+
|
117
|
+
def split_and_read(called)
|
118
|
+
if called =~ /([^:]+):(\d+):/
|
119
|
+
file, line = $1, $2.to_i
|
120
|
+
return File.readlines(file)[line - 1 .. -1]
|
121
|
+
end
|
122
|
+
|
123
|
+
return nil
|
124
|
+
end
|
125
|
+
|
126
|
+
def __evaluate_diagnostics
|
127
|
+
@__additional_diagnostics.each_with_index do |d, x|
|
128
|
+
@__additional_diagnostics[x] = d.call if d.respond_to? :call
|
129
|
+
end
|
130
|
+
end # CONSIDER pass the same args as blocks take?
|
131
|
+
|
132
|
+
def __build_message(reflection)
|
133
|
+
__evaluate_diagnostics
|
134
|
+
return (@__additional_diagnostics.uniq + [reflection]).compact.join("\n")
|
135
|
+
end # TODO move this fluff to the ruby_reflector!
|
136
|
+
|
137
|
+
def format_inspection(inspection, spaces)
|
138
|
+
spaces = ' ' * spaces
|
139
|
+
inspection = inspection.gsub('\n'){ "\\n\" +\n \"" } if inspection =~ /^".*"$/
|
140
|
+
inspection = inspection.gsub("\n"){ "\n" + spaces }
|
141
|
+
return inspection.lstrip
|
142
|
+
end
|
143
|
+
|
144
|
+
def format_assertion_result(assertion_source, inspection)
|
145
|
+
spaces = " --> ".length
|
146
|
+
inspection = format_inspection(inspection, spaces)
|
147
|
+
return assertion_source.rstrip + "\n --> #{inspection.lstrip}\n"
|
148
|
+
end
|
149
|
+
|
150
|
+
def format_capture(width, snip, value)
|
151
|
+
return "#{ format_snip(width, snip) } --> #{ format_value(width, value) }"
|
152
|
+
end
|
153
|
+
|
154
|
+
def format_value(width, value) # TODO width is a de-facto instance variable
|
155
|
+
width += 4
|
156
|
+
source = value.pretty_inspect.rstrip
|
157
|
+
return format_inspection(source, width)
|
158
|
+
end
|
159
|
+
|
160
|
+
def measure_capture(kap)
|
161
|
+
return kap.split("\n").inject(0){|x, v| v.strip.length > x ? v.strip.length : x } if kap.match("\n")
|
162
|
+
kap.length
|
163
|
+
# TODO need the if?
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
def colorize(to_color)
|
169
|
+
RubyReflector.new.colorize(to_color)
|
170
|
+
end
|
171
|
+
|
172
|
+
# TODO work with raw MiniTest
|
173
|
+
|
174
|
+
# This is a copy of the classic assert, so your pre-existing
|
175
|
+
# +assert+ calls will not change their behavior
|
176
|
+
#
|
177
|
+
if defined? MiniTest::Assertion
|
178
|
+
def assert_classic(test, msg=nil)
|
179
|
+
msg ||= "Failed assertion, no message given."
|
180
|
+
self._assertions += 1
|
181
|
+
unless test then
|
182
|
+
msg = msg.call if Proc === msg
|
183
|
+
raise MiniTest::Assertion, msg
|
184
|
+
end
|
185
|
+
true
|
186
|
+
end
|
187
|
+
|
188
|
+
def add_assertion
|
189
|
+
self._assertions += 1
|
190
|
+
end
|
191
|
+
else
|
192
|
+
def assert_classic(boolean, message=nil)
|
193
|
+
#_wrap_assertion do
|
194
|
+
assert_block("assert<classic> should not be called with a block.") { !block_given? }
|
195
|
+
assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
|
196
|
+
#end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# The new <code>assert()</code> calls this to interpret
|
201
|
+
# blocks of assertive statements.
|
202
|
+
#
|
203
|
+
def assert_(diagnostic = nil, options = {}, &block)
|
204
|
+
options[:keep_diagnostics] or add_diagnostic :clear
|
205
|
+
|
206
|
+
begin
|
207
|
+
got = block.call(*options[:args]) and add_assertion and return got
|
208
|
+
rescue FlunkError
|
209
|
+
raise # asserts inside assertions that fail do not decorate the outer assertion
|
210
|
+
rescue => got
|
211
|
+
add_exception got
|
212
|
+
end
|
213
|
+
|
214
|
+
flunk diagnose(diagnostic, got, caller[1], options, block)
|
215
|
+
end
|
216
|
+
|
217
|
+
def add_exception(ex)
|
218
|
+
ex.backtrace[0..10].each do |line|
|
219
|
+
add_diagnostic ' ' + line
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# This assertion replaces:
|
224
|
+
#
|
225
|
+
# - +assert_nil+
|
226
|
+
# - +assert_no_match+
|
227
|
+
# - +assert_not_equal+
|
228
|
+
#
|
229
|
+
# It faults, and prints its block's contents and values,
|
230
|
+
# if its block returns non-+false+ and non-+nil+.
|
231
|
+
#
|
232
|
+
def deny(diagnostic = nil, options = {}, &block)
|
233
|
+
# "None shall pass!" --the Black Knight
|
234
|
+
|
235
|
+
options[:keep_diagnostics] or add_diagnostic :clear
|
236
|
+
|
237
|
+
begin
|
238
|
+
got = block.call(*options[:args]) or (add_assertion and return true)
|
239
|
+
rescue FlunkError
|
240
|
+
raise
|
241
|
+
rescue => got
|
242
|
+
add_exception got
|
243
|
+
end
|
244
|
+
|
245
|
+
flunk diagnose(diagnostic, got, caller[0], options, block)
|
246
|
+
end # "You're a looney!" -- King Arthur
|
247
|
+
|
248
|
+
alias denigh deny # to line assert{ ... } and
|
249
|
+
# denigh{ ... } statements up neatly!
|
250
|
+
|
251
|
+
#~ def __reflect_assertion(called, options, block, got)
|
252
|
+
#~ effect = RubyReflector.new(called)
|
253
|
+
#~ effect.args = *options[:args]
|
254
|
+
#~ return effect.reflect_assertion(block, got)
|
255
|
+
#~ end
|
256
|
+
|
257
|
+
#~ def __reflect_assertion(called, options, block, got)
|
258
|
+
#~ effect = RubyReflector.new(called)
|
259
|
+
#~ effect.args = *options[:args]
|
260
|
+
#~ effect.block = block
|
261
|
+
#~ return effect.reflect_assertion(block, got) # TODO merge this and its copies into assert2_utilities
|
262
|
+
#~ end
|
263
|
+
|
264
|
+
#!doc!
|
265
|
+
def diagnose(diagnostic = nil, got = nil, called = caller[0],
|
266
|
+
options = {}, block = nil) # TODO make this directly callable
|
267
|
+
rf = RubyReflector.new
|
268
|
+
rf.diagnose(diagnostic, got, called, options, block, @__additional_diagnostics)
|
269
|
+
#~ options = { :args => [] }.merge(options)
|
270
|
+
#~ # CONSIDER only capture the block_vars if there be args?
|
271
|
+
#~ @__additional_diagnostics.unshift diagnostic
|
272
|
+
#~ return __build_message(__reflect_assertion(called, options, block, got))
|
273
|
+
end
|
274
|
+
|
275
|
+
if RubyReflector::HAS_RUBYNODE
|
276
|
+
# wrap this common idiom:
|
277
|
+
# foo = assemble()
|
278
|
+
# deny{ foo.bar() }
|
279
|
+
# foo.activate()
|
280
|
+
# assert{ foo.bar() }
|
281
|
+
#
|
282
|
+
# that becomes:
|
283
|
+
# foo = assemble()
|
284
|
+
#
|
285
|
+
# assert_yin_yang proc{ foo.bar() } do
|
286
|
+
# foo.activate()
|
287
|
+
# end
|
288
|
+
#
|
289
|
+
def assert_yin_yang(*args, &block)
|
290
|
+
# prock(s), diagnostic = nil, &block)
|
291
|
+
procks, diagnostic = args.partition{|p| p.respond_to? :call }
|
292
|
+
block ||= procks.shift
|
293
|
+
source = reflect_source(&block)
|
294
|
+
fuss = [diagnostic, "fault before calling:", source].compact.join("\n")
|
295
|
+
procks.each do |prock| deny(fuss, &prock); end
|
296
|
+
block.call
|
297
|
+
fuss = [diagnostic, "fault after calling:", source].compact.join("\n")
|
298
|
+
procks.each do |prock| assert(fuss, &prock); end
|
299
|
+
end
|
300
|
+
|
301
|
+
# the prock assertion must pass on both sides of the called block
|
302
|
+
#
|
303
|
+
def deny_yin_yang(*args, &block)
|
304
|
+
# prock(s), diagnostic = nil, &block)
|
305
|
+
procks, diagnostic = args.partition{|p| p.respond_to? :call }
|
306
|
+
block ||= procks.shift
|
307
|
+
source = reflect_source(&block)
|
308
|
+
fuss = [diagnostic, "fault before calling:", source].compact.join("\n")
|
309
|
+
procks.each do |prock| assert(fuss, &prock); end
|
310
|
+
block.call
|
311
|
+
fuss = [diagnostic, "fault after calling:", source].compact.join("\n")
|
312
|
+
procks.each do |prock| assert(fuss, &prock); end
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
|
317
|
+
end ; end ; end
|
318
|
+
|
319
|
+
class File
|
320
|
+
def self.write(filename, contents)
|
321
|
+
open(filename, 'w'){|f| f.write(contents) }
|
322
|
+
end
|
323
|
+
end
|