Class: Whitestone::Assertion::Custom
- Defined in:
- lib/whitestone/custom_assertions.rb
Overview
Whitestone::Assertion::Custom – custom assertions
This class is responsible for creating and running custom assertions.
Creating:
Whitestone.custom :circle, {
:description => "Circle equality",
:parameters => [ [:circle, Circle], [:values, Array] ],
:run => lambda {
x, y, r, label = values
test('x') { Ft circle.centre.x, x }
test('y') { Ft circle.centre.y, y }
test('r') { Ft circle.radius, r }
test('label') { Eq circle.label, Label[label] }
}
}
-
(Whitestone.custom passes its arguments straight through to Custom.define, which is surprisingly a very lightweight method.)
Running:
T :circle, circle, [4,1, 10, nil]
--> assertion = Custom.new(:custom, :assert, :circle, circle, [4,1, 10, nil]
--> assertion.run
Custom is an assertion (Assertion::Base) object, just like True, Equality, Catch, etc. It follows the same methods and life-cycle:
-
initialize: check arguments are sound; store instance variables for later
-
run: use the instance variables to perform the necessary assertion
-
message: return a message to be displayed upon failure
run is a lot more complicated than a normal assertion because all the logic is in the Config object (compare Equality#run: == @expected). The block that is specified (the lambda above) needs to be run in a special context for those test calls to work.
Defined Under Namespace
Classes: Config, CustomTestContext
Constant Summary collapse
- @@config =
{ :circle => Config.new(…), :square => Config.new(…) }
Hash.new
Class Method Summary collapse
-
.define(name, definition) ⇒ Object
Custom.define.
Instance Method Summary collapse
-
#initialize(mode, *args, &block) ⇒ Custom
constructor
Custom#initialize.
-
#message ⇒ Object
Custom#message.
-
#run ⇒ Object
Custom#run.
Methods inherited from Base
Methods included from Guards
#args_or_block_one_only, #block_required, #no_block_allowed, #one_argument, #two_arguments, #two_or_three_arguments, #type_check
Constructor Details
#initialize(mode, *args, &block) ⇒ Custom
Custom#initialize
Retrieves the config for the named custom assertion and checks the arguments against the configured parameters.
Sets up a context (CustomTestContext) for running the assertion when #run is called.
89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/whitestone/custom_assertions.rb', line 89 def initialize(mode, *args, &block) name = args.shift super(mode, *args, &block) no_block_allowed @config = @@config[name] if @config.nil? = "Non-existent custom assertion: #{name.inspect}" raise AssertionSpecificationError, end check_args_against_parameters(args) @context = CustomTestContext.new(@config.parameters, args) end |
Class Method Details
.define(name, definition) ⇒ Object
Custom.define
Defines a new custom assertion – just stores the configuration away for retrieval when the assertion is run.
78 79 80 |
# File 'lib/whitestone/custom_assertions.rb', line 78 def self.define(name, definition) @@config[name] = Config.new(name, definition) end |
Instance Method Details
#message ⇒ Object
Custom#message
If a failure occurred, a failure message was prepared when the exception was caught in #run.
151 152 153 |
# File 'lib/whitestone/custom_assertions.rb', line 151 def @message end |
#run ⇒ Object
Custom#run
Returns true or false for pass or fail, just like other assertions.
The Config object provides the block to run, while @context provides the context in which to run it.
We trap FailureOccurred errors because as a custom assertion we need to take responsibility for the errors, and wrap some information around the error message.
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 |
# File 'lib/whitestone/custom_assertions.rb', line 112 def run test_code = @config.run_block @context.instance_eval &test_code # ^^^ This gives the test code access to the 'test' method that is so # important for running a custom assertion. # See the notes on CustomTestContext for an example. return true # the custom test passed rescue FailureOccurred => f # We are here because an assertion failed. That means _this_ (custom) # assertion has failed. We need to build an error message and raise # FailureOccurred ourselves. @message = String.new.tap { |str| str << Col["#{@config.description} test failed: "].yb str << Col[@context.context_label].cb str << Col[" (details below)\n", f..___indent(4)].fmt(:yb, :yb) } return false rescue AssertionSpecificationError => e # While running the test block, we got an AssertionSpecificationError. # This probably means some bad data was put in, like # T :circle, c, [4,1, "radius", nil] # (The radius needs to be a number, not a string.) # We will still raise the AssertionSpecificationError but we want it to # look like it comes from the _custom_ assertion, not the _primitive_ # one. Essentially, we are acting like it's a failure: constructing the # message that includes the context label (in this case, 'r' for # radius). = String.new.tap { |str| str << Col["#{@config.description} test -- error: "].yb str << Col[@context.context_label].cb str << Col[" details below\n", e..___indent(4)].fmt(:yb, :yb) } raise AssertionSpecificationError, end |