Class: AE::Assertor
- Inherits:
- BasicObject
- Includes:
- Subjunctive
- Defined in:
- lib/ae/assertor.rb,
lib/ae/subjunctive.rb,
lib/ae/adapters/testunit.rb
Overview
:nodoc:
Constant Summary collapse
- ZERO_COUNTS =
Initial settings of assertion counts.
{:total=>0,:pass=>0,:fail=>0}
Class Method Summary collapse
-
.assert(pass, error = nil, negated = nil, backtrace = nil) ⇒ Object
Basic assertion.
-
.assertion_error ⇒ Object
Returns the Exception class to be raised when an assertion fails.
-
.counts ⇒ Object
Returns Hash used to track assertion counts.
-
.increment_counts(pass) ⇒ Object
Increment assertion counts.
-
.raise_assertion(error, negated, backtrace = nil) ⇒ Object
The intent of the method is to raise an assertion failure class that the test framework supports.
-
.recount(reset = nil) ⇒ Object
Reset assertion counts.
Instance Method Summary collapse
-
#=~(match) ⇒ Object
Ruby seems to have a quark in it’s implementation whereby this must be defined explicitly, otherwise it somehow skips #method_missing.
-
#assert(*args, &block) ⇒ Object
Internal assert, provides all functionality associated with external #assert method.
-
#expect(*args, &block) ⇒ Object
Internal expect, provides all functionality associated with external #expect method.
- #flunk(message = nil, backtrace = nil) ⇒ Object
-
#initialize(delegate, opts = {}) ⇒ Assertor
constructor
New Assertor.
- #inspect ⇒ Object
-
#not(msg = nil) ⇒ Object
Negate the meaning of the assertion.
- #send(op, *a, &b) ⇒ Object
Methods included from Subjunctive
Methods inherited from BasicObject
find_hidden_method, hide, reveal
Constructor Details
#initialize(delegate, opts = {}) ⇒ Assertor
New Assertor.
112 113 114 115 116 117 |
# File 'lib/ae/assertor.rb', line 112 def initialize(delegate, opts={}) #, backtrace) @delegate = delegate @message = opts[:message] @backtrace = opts[:backtrace] || caller #[1..-1] @negated = !!opts[:negated] end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(sym, *args, &block) ⇒ Object (private)
Converts a missing method into an Assertion.
TODO: In future should probably be ‘@delegate.public_send(sym, *a, &b)`.
277 278 279 280 281 282 283 |
# File 'lib/ae/assertor.rb', line 277 def method_missing(sym, *args, &block) error = @message || (sym, *args, &block) || (sym, *args, &block) pass = @delegate.__send__(sym, *args, &block) __assert__(pass, error) end |
Class Method Details
.assert(pass, error = nil, negated = nil, backtrace = nil) ⇒ Object
Basic assertion. This method by-passes all the Assertor fluent constructs and performs the underlying assertion procedure. It is used by Assertor as the end call of an assertion.
62 63 64 65 66 67 68 69 70 |
# File 'lib/ae/assertor.rb', line 62 def self.assert(pass, error=nil, negated=nil, backtrace=nil) pass = negated ^ !!pass increment_counts(pass) if !pass backtrace = backtrace || caller raise_assertion(error, negated, backtrace) end return pass end |
.assertion_error ⇒ Object
Returns the Exception class to be raised when an assertion fails.
85 86 87 |
# File 'lib/ae/assertor.rb', line 85 def self.assertion_error ::Assertion end |
.counts ⇒ Object
Returns Hash used to track assertion counts.
25 26 27 |
# File 'lib/ae/assertor.rb', line 25 def self.counts $assertion_counts end |
.increment_counts(pass) ⇒ Object
Increment assertion counts. If pass
is true
then :total
and :pass
are increased. If pass
if false
then :total
and :fail
are incremented.
49 50 51 52 53 54 55 56 57 |
# File 'lib/ae/assertor.rb', line 49 def self.increment_counts(pass) counts[:total] += 1 if pass counts[:pass] += 1 else counts[:fail] += 1 end return counts end |
.raise_assertion(error, negated, backtrace = nil) ⇒ Object
The intent of the method is to raise an assertion failure class that the test framework supports.
74 75 76 77 78 79 80 81 82 |
# File 'lib/ae/assertor.rb', line 74 def self.raise_assertion(error, negated, backtrace=nil) if not ::Exception === error error = assertion_error.new(error) end error.set_negative(negated) error.set_backtrace(backtrace || caller) error.set_assertion(true) fail error end |
.recount(reset = nil) ⇒ Object
Reset assertion counts.
reset - Hash which can be used to set counts manually (optional).
Returns the Hash of previous counts.
34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/ae/assertor.rb', line 34 def self.recount(reset=nil) old_counts = counts.dup if reset reset.each do |type, value| counts[type.to_sym] = value end else counts.replace(ZERO_COUNTS.dup) end return old_counts end |
Instance Method Details
#=~(match) ⇒ Object
Ruby seems to have a quark in it’s implementation whereby this must be defined explicitly, otherwise it somehow skips #method_missing.
249 250 251 |
# File 'lib/ae/assertor.rb', line 249 def =~(match) method_missing(:"=~", match) end |
#assert(*args, &block) ⇒ Object
Internal assert, provides all functionality associated with external #assert method. (See Assert#assert)
NOTE: I’m calling YAGNI on using extra arguments to pass to the block. The interface is much nicer if a macro is created to handle any neccessry arguments. Eg.
assert something(parameter)
instead of
assert something, parameter
Returns true
or false
based on assertions success. – The use of #to_proc and #matches? as sepcial cases is not a robust solution. ++
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 |
# File 'lib/ae/assertor.rb', line 148 def assert(*args, &block) return self if args.empty? && !block target = block || args.shift error = nil # Lambda if ::Proc === target || target.respond_to?(:to_proc) block = target.to_proc match = args.shift result = block.arity > 0 ? block.call(@delegate) : block.call if match pass = (match == result) error = @message || "#{match.inspect} == #{result.inspect}" else pass = result error = @message || block.inspect # "#{result.inspect}" end # Matcher elsif target.respond_to?(:matches?) # Matchers pass = target.matches?(@delegate) error = @message || (target) #|| target.inspect if target.respond_to?(:exception) #error_class = target.failure_class error = target.exception #(:backtrace=>@backtrace, :negated=>@negated) end # Truthiness else pass = target # truthiness error = args.shift # optional message for TestUnit compatiability end __assert__(pass, error) end |
#expect(*args, &block) ⇒ Object
Internal expect, provides all functionality associated with external #expect method. (See Expect#expect)
– TODO: Should we deprecate the receiver matches in favor of #expected ? In other words, should the || @delegate
be dropped? ++
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/ae/assertor.rb', line 192 def expect(*args, &block) return self if args.empty? && !block # same as #assert target = block || args.shift error = nil # Lambda if ::Proc === target #|| target.respond_to?(:to_proc) #block = target.to_proc match = args.shift || @delegate if exception?(match) $DEBUG, debug = false, $DEBUG # b/c it always spits-out a NameError begin block.arity > 0 ? block.call(@delegate) : block.call pass = false error = "#{match} not raised" rescue match => error pass = true error = "#{match} raised" rescue ::Exception => error pass = false error = "#{match} expected but #{error.class} was raised" ensure $DEBUG = debug end else result = block.arity > 0 ? block.call(@delegte) : block.call pass = (match === result) error = @message || "#{match.inspect} === #{result.inspect}" end # Matcher elsif target.respond_to?(:matches?) pass = target.matches?(@delegate) error = @message || (target) #|| target.inspect if target.respond_to?(:exception) #error_class = target.failure_class error = target.exception #failure(:backtrace=>@backtrace, :negated=>@negated) end # Case Equals else pass = (target === @delegate) error = @message || "#{target.inspect} === #{@delegate.inspect}" end __assert__(pass, error) end |
#flunk(message = nil, backtrace = nil) ⇒ Object
242 243 244 |
# File 'lib/ae/assertor.rb', line 242 def flunk(=nil, backtrace=nil) __assert__(false, || @message) end |
#inspect ⇒ Object
259 260 261 |
# File 'lib/ae/assertor.rb', line 259 def inspect @delegate.inspect end |
#not(msg = nil) ⇒ Object
Negate the meaning of the assertion.
– TODO: Should this return a new Assertor instead of in place negation? ++
124 125 126 127 128 |
# File 'lib/ae/assertor.rb', line 124 def not(msg=nil) @negated = !@negated @message = msg if msg self end |
#send(op, *a, &b) ⇒ Object
254 255 256 |
# File 'lib/ae/assertor.rb', line 254 def send(op, *a, &b) method_missing(op, *a, &b) end |