Method: Whitestone.action
- Defined in:
- lib/whitestone.rb
.action(base, assert_negate_query, *args, &block) ⇒ Object
Whitestone.action
This is an absolutely key method. It implements T, F, Eq, T!, F?, Eq?, etc. After some sanity checking, it creates an assertion object, runs it, and sees whether it passed or failed.
If the assertion fails, we raise FailureOccurred, with the necessary information about the failure. If an error happens while the assertion is run, we don’t catch it. Both the error and the failure are handled upstream, in Whitestone.call.
It’s worth noting that errors can occur while tests are run that are unconnected to this method. Consider these two examples:
T { "foo".frobnosticate? } -- error occurs on our watch
T "foo".frobnosticate? -- error occurs before T() is called
By letting errors from here escape, the two cases can be dealt with together.
T and F are special cases: they can be called with custom assertions.
T :circle, c, [4,1, 10, :H]
-> run_custom_test(:circle, :assert, [4,1,10,:H])
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/whitestone.rb', line 317 def action(base, assert_negate_query, *args, &block) mode = assert_negate_query # :assert, :negate or :query # Sanity checks: these should never fail! unless [:assert, :negate, :query].include? mode raise AssertionSpecificationError, "Invalid mode: #{mode.inspect}" end unless ASSERTION_CLASSES.key? base raise AssertionSpecificationError, "Invalid base: #{base.inspect}" end # Special case: T may be used to invoke custom assertions. # We catch the use of F as well, even though it's disallowed, so that # we can give an appropriate error message. if base == :T or base == :F and args.size > 1 and args.first.is_a? Symbol if base == :T and mode == :assert # Run a custom assertion. inside_custom_assertion do action(:custom, :assert, *args) end return nil else = "You are attempting to run a custom assertion.\n" << "These can only be run with T, not F, T?, T!, F? etc." raise AssertionSpecificationError, end end assertion = ASSERTION_CLASSES[base].new(mode, *args, &block) # e.g. assertion = Assertion::Equality(:assert, 4, 4) # no block # assertion = Assertion::Nil(:query) { names.find "Tobias" } # assertion = Assertion::Custom(...) stats[:assertions] += 1 unless @inside_custom_assertion # We run the assertion (returns true for pass and false for fail). passed = assertion.run # We negate the result if neccesary... case mode when :negate then passed = ! passed when :query then return passed end # ...and report a failure if necessary. if passed # We do this here because we only want the test to pass if it actually # runs an assertion; otherwise its result is 'blank'. If a later # assertion in the test fails or errors, the result will be rewritten. @current_test.result = :pass if @current_test else calling_context = assertion.block || @calls.last backtrace = caller raise FailureOccurred.new(calling_context, assertion., backtrace) end end |