ae 1.7.4 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby +38 -39
- data/.yardopts +7 -0
- data/HISTORY.rdoc +31 -16
- data/NOTICE.rdoc +33 -15
- data/README.rdoc +14 -19
- data/lib/ae.rb +12 -33
- data/lib/ae.yml +38 -39
- data/lib/ae/adapters/minitest.rb +25 -15
- data/lib/ae/adapters/testunit.rb +1 -1
- data/lib/ae/assert.rb +20 -9
- data/lib/ae/assertion.rb +8 -5
- data/lib/ae/assertor.rb +127 -68
- data/lib/ae/basic_object.rb +0 -1
- data/lib/ae/check.rb +138 -10
- data/lib/ae/expect.rb +3 -6
- data/lib/ae/legacy.rb +84 -8
- data/lib/ae/must.rb +20 -12
- data/lib/ae/pry.rb +9 -8
- data/lib/ae/should.rb +14 -9
- data/lib/ae/subjunctive.rb +5 -6
- data/lib/ae/version.rb +3 -1
- data/qed/03_assert.rdoc +12 -6
- metadata +63 -69
- data/APACHE2.txt +0 -206
- data/lib/ae/ok.rb +0 -38
data/lib/ae/adapters/minitest.rb
CHANGED
@@ -4,33 +4,43 @@ AE.assertion_error = ::MiniTest::Assertion
|
|
4
4
|
|
5
5
|
module MiniTest #:nodoc:
|
6
6
|
class Unit #:nodoc:
|
7
|
+
|
7
8
|
# MiniTest tracks assertion counts internally in it's Unit class via the
|
8
9
|
# +assertion_count+ attribute. To work with AE we need add in AE's assertion
|
9
10
|
# total by overriding the +assertion_count+ method.
|
11
|
+
#
|
12
|
+
# @return [Integer] Number of assertions made.
|
10
13
|
def assertion_count
|
11
14
|
@assertion_count + AE::Assertor.counts[:total]
|
12
15
|
end
|
16
|
+
|
13
17
|
# To teach MiniTest to recognize AE's expanded concept of assertions
|
14
|
-
# we add in an extra capture clause to
|
15
|
-
|
16
|
-
|
18
|
+
# we add in an extra capture clause to it's #puke method.
|
19
|
+
#
|
20
|
+
# @return [String] Status code is `S`, `F`, or `E`.
|
21
|
+
def puke k, m, e
|
22
|
+
case e
|
17
23
|
when MiniTest::Skip
|
18
|
-
@skips
|
19
|
-
|
24
|
+
@skips += 1
|
25
|
+
return "S" unless @verbose
|
26
|
+
e = "Skipped:\n#{m}(#{k}) [#{location e}]:\n#{e.message}\n"
|
20
27
|
when MiniTest::Assertion
|
21
|
-
@failures
|
22
|
-
|
23
|
-
when x.respond_to?(:assertion?) && x.assertion?
|
24
|
-
@failures = @failures + 1
|
25
|
-
x = "Failure:\n#{m}(#{c}) [#{location x}]:\n#{x.message}\n"
|
28
|
+
@failures += 1
|
29
|
+
e = "Failure:\n#{m}(#{k}) [#{location e}]:\n#{e.message}\n"
|
26
30
|
else
|
27
|
-
|
28
|
-
|
29
|
-
|
31
|
+
if e.respond_to?(:assertion?) && e.assertion?
|
32
|
+
@failures += 1
|
33
|
+
e = "Failure:\n#{m}(#{c}) [#{location e}]:\n#{e.message}\n"
|
34
|
+
else
|
35
|
+
@errors += 1
|
36
|
+
b = MiniTest::filter_backtrace(e.backtrace).join "\n "
|
37
|
+
e = "Error:\n#{m}(#{k}):\n#{e.class}: #{e.message}\n #{b}\n"
|
38
|
+
end
|
30
39
|
end
|
31
|
-
@report <<
|
32
|
-
|
40
|
+
@report << e
|
41
|
+
e[0, 1]
|
33
42
|
end
|
43
|
+
|
34
44
|
end
|
35
45
|
end
|
36
46
|
|
data/lib/ae/adapters/testunit.rb
CHANGED
@@ -10,7 +10,7 @@ AE.assertion_error = ::Test::Unit::AssertionFailedError
|
|
10
10
|
# In addition we teach #run to recognize any Exception class that
|
11
11
|
# responds to #assertion? in the affirmative as an assertion
|
12
12
|
# rather than an error.
|
13
|
-
|
13
|
+
#
|
14
14
|
module Test #:nodoc:
|
15
15
|
module Unit #:nodoc:
|
16
16
|
class TestCase #:nodoc:
|
data/lib/ae/assert.rb
CHANGED
@@ -12,10 +12,10 @@ module AE
|
|
12
12
|
#
|
13
13
|
# 4.assert == 3
|
14
14
|
#
|
15
|
-
# If only a single test argument is given then
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
15
|
+
# If only a single test argument is given then #assert
|
16
|
+
# simply validates that it evalutate to true. An optional
|
17
|
+
# message argument can be given in this case which will
|
18
|
+
# be used instead of the deafult message.
|
19
19
|
#
|
20
20
|
# assert(4==3, "not the same thing")
|
21
21
|
#
|
@@ -24,11 +24,14 @@ module AE
|
|
24
24
|
#
|
25
25
|
# assert{ 4==3 }
|
26
26
|
#
|
27
|
+
# @return [Assertor] Assertion functor.
|
27
28
|
def assert(*args, &block)
|
28
29
|
Assertor.new(self, :backtrace=>caller).assert(*args, &block)
|
29
30
|
end
|
30
31
|
|
31
32
|
# Same as 'object.assert == other'.
|
33
|
+
#
|
34
|
+
# @return [Assertor] Assertion functor.
|
32
35
|
def assert=(cmp)
|
33
36
|
Assertor.new(self, :backtrace=>caller).assert == cmp
|
34
37
|
end
|
@@ -37,11 +40,14 @@ module AE
|
|
37
40
|
#
|
38
41
|
# 4.refute == 4 #=> Assertion Error
|
39
42
|
#
|
43
|
+
# @return [Assertor] Assertion functor.
|
40
44
|
def refute(*args, &block)
|
41
45
|
Assertor.new(self, :backtrace=>caller).not.assert(*args, &block)
|
42
46
|
end
|
43
47
|
|
44
48
|
# Same as 'object.refute == other'.
|
49
|
+
#
|
50
|
+
# @return [Assertor] Assertion functor.
|
45
51
|
def refute=(cmp)
|
46
52
|
Assertor.new(self, :backtrace=>caller).not.assert == cmp
|
47
53
|
end
|
@@ -57,6 +63,15 @@ module AE
|
|
57
63
|
alias_method :assert!, :refute
|
58
64
|
|
59
65
|
# Directly raise an Assertion failure.
|
66
|
+
#
|
67
|
+
# @param message [String]
|
68
|
+
# Error message.
|
69
|
+
#
|
70
|
+
# @param backtrace [String]
|
71
|
+
# Backtrace, used to pass up an error from lower in the stack.
|
72
|
+
#
|
73
|
+
# @raise [Assertion]
|
74
|
+
# Assertion error with given `message`.
|
60
75
|
def flunk(message=nil, backtrace=nil)
|
61
76
|
#Assertor.new(self, :backtrace=>caller).assert(false, message)
|
62
77
|
Assertor.assert(false, message, backtrace || caller)
|
@@ -66,8 +81,4 @@ module AE
|
|
66
81
|
|
67
82
|
end
|
68
83
|
|
69
|
-
|
70
|
-
include AE::Assert
|
71
|
-
end
|
72
|
-
|
73
|
-
# Copyright (c) 2008,2009 Thomas Sawyer
|
84
|
+
# Copyright (c) 2008 Thomas Sawyer
|
data/lib/ae/assertion.rb
CHANGED
@@ -13,15 +13,16 @@ module AE
|
|
13
13
|
#
|
14
14
|
class Assertion < Exception
|
15
15
|
|
16
|
-
#
|
16
|
+
# @deprecated
|
17
|
+
# This will be removed in favor of `AE::Assertor.counts`.
|
17
18
|
def self.counts
|
18
19
|
AE::Assertor.counts
|
19
20
|
end
|
20
21
|
|
21
22
|
# New assertion (failure).
|
22
23
|
#
|
23
|
-
# message
|
24
|
-
# options
|
24
|
+
# @param message [String] the failure message
|
25
|
+
# @param options [Hash] options such as :backtrace
|
25
26
|
#
|
26
27
|
def initialize(message=nil, options={})
|
27
28
|
super(message)
|
@@ -38,7 +39,9 @@ module AE
|
|
38
39
|
true
|
39
40
|
end
|
40
41
|
|
42
|
+
# Parents error message prefixed with "(assertion)".
|
41
43
|
#
|
44
|
+
# @return [String] error message
|
42
45
|
def to_s
|
43
46
|
'(assertion) ' + super
|
44
47
|
end
|
@@ -47,5 +50,5 @@ module AE
|
|
47
50
|
|
48
51
|
end
|
49
52
|
|
50
|
-
# Set top-level Assertion to AE::Assertion
|
51
|
-
Assertion = AE::Assertion
|
53
|
+
# Set top-level Assertion to AE::Assertion if not already present.
|
54
|
+
Assertion = AE::Assertion unless defined?(Assertion)
|
data/lib/ae/assertor.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'ae/assertion'
|
2
2
|
require 'ae/basic_object'
|
3
|
-
require 'ansi
|
3
|
+
require 'ae/ansi'
|
4
4
|
|
5
5
|
module AE
|
6
6
|
|
@@ -91,7 +91,6 @@ module AE
|
|
91
91
|
#def self.assay?
|
92
92
|
# @_assay ||= defined?(::Assay)
|
93
93
|
#end
|
94
|
-
|
95
94
|
#
|
96
95
|
#def self.message(sym, neg, *args, &blk)
|
97
96
|
# if method = Message.lookup(sym)
|
@@ -116,11 +115,10 @@ module AE
|
|
116
115
|
@negated = !!opts[:negated]
|
117
116
|
end
|
118
117
|
|
118
|
+
# TODO: Should #not return a new Assertor instead of in place negation?
|
119
|
+
|
119
120
|
# Negate the meaning of the assertion.
|
120
121
|
#
|
121
|
-
#--
|
122
|
-
# TODO: Should this return a new Assertor instead of in place negation?
|
123
|
-
#++
|
124
122
|
def not(msg=nil)
|
125
123
|
@negated = !@negated
|
126
124
|
@message = msg if msg
|
@@ -141,19 +139,15 @@ module AE
|
|
141
139
|
# assert something, parameter
|
142
140
|
#
|
143
141
|
# Returns +true+ or +false+ based on assertions success.
|
144
|
-
|
145
|
-
# The use of #to_proc and #matches? as sepcial cases is not
|
146
|
-
# a robust solution.
|
147
|
-
#++
|
142
|
+
#
|
148
143
|
def assert(*args, &block)
|
149
|
-
return self if args.empty?
|
144
|
+
return self if !block && args.empty?
|
150
145
|
|
151
|
-
target =
|
146
|
+
target = args.shift unless block
|
152
147
|
error = nil
|
153
148
|
|
154
|
-
#
|
155
|
-
if
|
156
|
-
block = target.to_proc
|
149
|
+
# Block
|
150
|
+
if block
|
157
151
|
match = args.shift
|
158
152
|
result = block.arity > 0 ? block.call(@delegate) : block.call
|
159
153
|
if match
|
@@ -164,14 +158,17 @@ module AE
|
|
164
158
|
error = @message || block.inspect # "#{result.inspect}"
|
165
159
|
end
|
166
160
|
|
167
|
-
#
|
168
|
-
elsif
|
169
|
-
pass
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
161
|
+
# Proc-style
|
162
|
+
elsif proc_assertion?(target)
|
163
|
+
pass, error = proc_apply(target)
|
164
|
+
|
165
|
+
# Assay-style assertions
|
166
|
+
#elsif assay_assertion?(target)
|
167
|
+
# pass, error = assay_assertion_apply(target)
|
168
|
+
|
169
|
+
# RSpec-style matchers
|
170
|
+
elsif rspec_matcher?(target)
|
171
|
+
pass, error = rspec_matcher_apply(target)
|
175
172
|
|
176
173
|
# Truthiness
|
177
174
|
else
|
@@ -182,23 +179,20 @@ module AE
|
|
182
179
|
__assert__(pass, error)
|
183
180
|
end
|
184
181
|
|
182
|
+
# TODO: Should we deprecate the receiver matches in favor of #expected ?
|
183
|
+
# In other words, should <code>|| @delegate</code> be dropped?
|
184
|
+
|
185
185
|
# Internal expect, provides all functionality associated
|
186
186
|
# with external #expect method. (See Expect#expect)
|
187
187
|
#
|
188
|
-
#--
|
189
|
-
# TODO: Should we deprecate the receiver matches in favor of #expected ?
|
190
|
-
# In other words, should the <code>|| @delegate</code> be dropped?
|
191
|
-
#++
|
192
188
|
def expect(*args, &block)
|
193
|
-
return self if args.empty?
|
189
|
+
return self if !block && args.empty? # same as #assert
|
194
190
|
|
195
|
-
|
196
|
-
error
|
191
|
+
pass = false
|
192
|
+
error = nil
|
197
193
|
|
198
|
-
|
199
|
-
|
200
|
-
#block = target.to_proc
|
201
|
-
match = args.shift || @delegate
|
194
|
+
if block
|
195
|
+
match = args.shift || @delegate # TODO: see above
|
202
196
|
if exception?(match)
|
203
197
|
$DEBUG, debug = false, $DEBUG # b/c it always spits-out a NameError
|
204
198
|
begin
|
@@ -220,19 +214,20 @@ module AE
|
|
220
214
|
error = @message || "#{match.inspect} === #{result.inspect}"
|
221
215
|
end
|
222
216
|
|
223
|
-
|
224
|
-
elsif target.respond_to?(:matches?)
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
217
|
+
## Matcher
|
218
|
+
#elsif target.respond_to?(:matches?)
|
219
|
+
# pass = target.matches?(@delegate)
|
220
|
+
# error = @message || matcher_message(target) #|| target.inspect
|
221
|
+
# if target.respond_to?(:exception)
|
222
|
+
# #error_class = target.failure_class
|
223
|
+
# error = target.exception #failure(:backtrace=>@backtrace, :negated=>@negated)
|
224
|
+
# end
|
231
225
|
|
232
|
-
# Case
|
226
|
+
# Case Equality
|
233
227
|
else
|
234
|
-
|
235
|
-
|
228
|
+
target = args.shift
|
229
|
+
pass = (target === @delegate)
|
230
|
+
error = @message || "#{target.inspect} === #{@delegate.inspect}"
|
236
231
|
end
|
237
232
|
|
238
233
|
__assert__(pass, error)
|
@@ -260,20 +255,94 @@ module AE
|
|
260
255
|
@delegate.inspect
|
261
256
|
end
|
262
257
|
|
263
|
-
|
258
|
+
private
|
259
|
+
|
260
|
+
# AE-STYLE ASSERTIONS
|
261
|
+
|
262
|
+
#
|
263
|
+
def proc_assertion?(target)
|
264
|
+
::Proc === target || target.respond_to?(:call) || target.respond_to?(:to_proc)
|
265
|
+
end
|
266
|
+
|
267
|
+
#
|
268
|
+
def proc_apply(target)
|
269
|
+
call = target.method(:call) rescue target.to_proc
|
270
|
+
pass = call.arity != 0 ? call.call(@delegate) : call.call
|
271
|
+
error = @message || (
|
272
|
+
to_s = target.method(:to_s)
|
273
|
+
to_s.arity == 0 ? to_s.call : to_s.call(@negated)
|
274
|
+
)
|
275
|
+
return pass, error
|
276
|
+
end
|
277
|
+
|
278
|
+
# ASSAY-STYLE ASSERTIONS
|
279
|
+
# (not yet supported b/c api is not 100%)
|
280
|
+
|
281
|
+
# Is the `assertion` object an assay-style assertion?
|
282
|
+
def assay_assertion?(assertion)
|
283
|
+
assertion.respond_to?(:exception) && assertion.respond_to?(:pass?)
|
284
|
+
end
|
285
|
+
|
286
|
+
#
|
287
|
+
def assay_assertion_apply(assay)
|
288
|
+
if @negated
|
289
|
+
pass = assay.fail?(@delegate)
|
290
|
+
error = assay #.exception(@message || )
|
291
|
+
else
|
292
|
+
pass = assay.pass?(@delegate)
|
293
|
+
error = assay #.exception(@message || )
|
294
|
+
end
|
295
|
+
return pass, error
|
296
|
+
end
|
297
|
+
|
298
|
+
# RSPEC-STYLE MATCHERS
|
299
|
+
|
300
|
+
# Is `target` an Rspec-style Matcher?
|
301
|
+
def rspec_matcher?(target)
|
302
|
+
target.respond_to?(:matches?)
|
303
|
+
end
|
304
|
+
|
305
|
+
#
|
306
|
+
def rspec_matcher_apply(matcher)
|
307
|
+
pass = matcher.matches?(@delegate)
|
308
|
+
error = @message || rspec_matcher_message(matcher)
|
309
|
+
return pass, error
|
310
|
+
end
|
311
|
+
|
312
|
+
# TODO: Is there anything to be done with matcher.description?
|
313
|
+
|
314
|
+
#
|
315
|
+
def rspec_matcher_message(matcher)
|
316
|
+
if @negated
|
317
|
+
if matcher.respond_to?(:failure_message_for_should_not)
|
318
|
+
return matcher.failure_message_for_should_not
|
319
|
+
end
|
320
|
+
if matcher.respond_to?(:negative_failure_message)
|
321
|
+
return matcher.negative_failure_message
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
if matcher.respond_to?(:failure_message_for_should)
|
326
|
+
return matcher.failure_message_for_should
|
327
|
+
end
|
328
|
+
if matcher.respond_to?(:failure_message)
|
329
|
+
return matcher.failure_message
|
330
|
+
end
|
331
|
+
|
332
|
+
return matcher.to_s # TODO: or just `nil` ?
|
333
|
+
end
|
264
334
|
|
265
|
-
# Is the +object+ an Exception or an instance of one?
|
266
|
-
#--
|
267
335
|
# TODO: Should we use a more libreral determination of exception.
|
268
336
|
# e.g. <code>respond_to?(:exception)</code>.
|
269
|
-
|
337
|
+
|
338
|
+
# Is the +object+ an Exception or an instance of one?
|
270
339
|
def exception?(object)
|
271
340
|
::Exception === object or ::Class === object and object.ancestors.include?(::Exception)
|
272
341
|
end
|
273
342
|
|
274
|
-
# Converts a missing method into an Assertion.
|
275
|
-
#
|
276
343
|
# TODO: In future should probably be `@delegate.public_send(sym, *a, &b)`.
|
344
|
+
|
345
|
+
# Converts a missing method into an Assertion.
|
277
346
|
def method_missing(sym, *args, &block)
|
278
347
|
error = @message || compare_message(sym, *args, &block) || generic_message(sym, *args, &block)
|
279
348
|
|
@@ -282,29 +351,14 @@ module AE
|
|
282
351
|
__assert__(pass, error)
|
283
352
|
end
|
284
353
|
|
354
|
+
# TODO: Can the handling of the message be simplified/improved?
|
285
355
|
|
286
356
|
# Simple assert.
|
287
|
-
#--
|
288
|
-
# TODO: Can the handling of the message be simplified/improved?
|
289
|
-
#++
|
290
357
|
def __assert__(pass, error=nil)
|
291
358
|
Assertor.assert(pass, error, @negated, @backtrace)
|
292
359
|
end
|
293
360
|
|
294
361
|
#
|
295
|
-
def matcher_message(matcher)
|
296
|
-
if @negated
|
297
|
-
if matcher.respond_to?(:negative_failure_message)
|
298
|
-
return matcher.failure_message
|
299
|
-
end
|
300
|
-
else
|
301
|
-
if matcher.respond_to?(:failure_message)
|
302
|
-
return matcher.failure_message
|
303
|
-
end
|
304
|
-
end
|
305
|
-
return nil
|
306
|
-
end
|
307
|
-
|
308
362
|
COMPARISON_OPERATORS = { :"==" => :"!=" }
|
309
363
|
|
310
364
|
# Message to use when making a comparion assertion.
|
@@ -314,7 +368,9 @@ module AE
|
|
314
368
|
# terminals) you can either set `AE.ansi = false` or use the
|
315
369
|
# ANSI library's master switch to deactive all ANSI codes,
|
316
370
|
# which can be set in your test helper.
|
317
|
-
#
|
371
|
+
#
|
372
|
+
# @param operator [Symbol] operator/method
|
373
|
+
#
|
318
374
|
# @see http://rubyworks.github.com/ansi
|
319
375
|
def compare_message(operator, *args, &blk)
|
320
376
|
return nil unless COMPARISON_OPERATORS.key?(operator)
|
@@ -342,6 +398,9 @@ module AE
|
|
342
398
|
|
343
399
|
# Puts together a suitable error message.
|
344
400
|
#
|
401
|
+
# @param op [Symbol] operator/method
|
402
|
+
#
|
403
|
+
# @return [String] message
|
345
404
|
def generic_message(op, *a, &b)
|
346
405
|
inspection = @delegate.send(:inspect)
|
347
406
|
if @negated
|
@@ -366,4 +425,4 @@ end
|
|
366
425
|
# end
|
367
426
|
#end
|
368
427
|
|
369
|
-
# Copyright (c) 2008
|
428
|
+
# Copyright (c) 2008 Thomas Sawyer
|