Class: Sus::Assertions
- Inherits:
-
Object
- Object
- Sus::Assertions
- Defined in:
- lib/sus/assertions.rb
Overview
Represents a collection of test assertions and their results. Tracks passed, failed, skipped, and errored assertions.
Defined Under Namespace
Instance Attribute Summary collapse
-
#clock ⇒ Object
readonly
Returns the value of attribute clock.
-
#count ⇒ Object
readonly
Returns the value of attribute count.
-
#deferred ⇒ Object
readonly
Returns the value of attribute deferred.
-
#distinct ⇒ Object
readonly
Returns the value of attribute distinct.
-
#errored ⇒ Object
readonly
Returns the value of attribute errored.
-
#failed ⇒ Object
readonly
Returns the value of attribute failed.
-
#identity ⇒ Object
readonly
Returns the value of attribute identity.
-
#inverted ⇒ Object
readonly
Returns the value of attribute inverted.
-
#isolated ⇒ Object
readonly
Returns the value of attribute isolated.
-
#level ⇒ Object
readonly
Returns the value of attribute level.
- #Nested assertions that have been deferred.(assertionsthathavebeendeferred.) ⇒ Object readonly
- #Nested assertions that have been skipped.(assertionsthathavebeenskipped.) ⇒ Object readonly
- #Nested assertions that have errored.(assertionsthathaveerrored.) ⇒ Object readonly
- #Nested assertions that have failed.(assertionsthathavefailed.) ⇒ Object readonly
- #Nested assertions that have passed.(assertionsthathavepassed.) ⇒ Object readonly
-
#orientation ⇒ Object
readonly
Returns the value of attribute orientation.
-
#output ⇒ Object
readonly
Returns the value of attribute output.
-
#passed ⇒ Object
readonly
Returns the value of attribute passed.
-
#skipped ⇒ Object
readonly
Returns the value of attribute skipped.
-
#target ⇒ Object
readonly
Returns the value of attribute target.
- #The nesting level of this set of assertions.(nestinglevelofthissetofassertions.) ⇒ Object readonly
- #The total number of assertions performed.(totalnumberofassertionsperformed.) ⇒ Object readonly
-
#verbose ⇒ Object
readonly
Returns the value of attribute verbose.
Class Method Summary collapse
-
.default(**options) ⇒ Object
Create a new assertions instance with default options.
Instance Method Summary collapse
-
#add(assertions) ⇒ Object
Add child assertions that were nested to this instance.
-
#assert(condition, message = nil) ⇒ Object
Make an assertion about a condition.
-
#defer(&block) ⇒ Object
Add a deferred assertion that will be resolved later.
- #deferred? ⇒ Boolean
- #Distinct is used to identify a set of assertions as a single statement for the purpose of user feedback. It's used by top level ensure statements to ensure that error messages are captured and reported on those statements.=(isusedtoidentifyasetofassertionsasasinglestatement) ⇒ Object
-
#each_failure(&block) ⇒ Object
Iterate over all failures in this assertions instance.
- #empty? ⇒ Boolean
-
#error!(error) ⇒ Object
Record an error that occurred during test execution.
- #errored? ⇒ Boolean
- #failed? ⇒ Boolean
-
#inform(message = nil) ⇒ Object
Print an informational message during test execution.
-
#initialize(identity: nil, target: nil, output: Output.buffered, inverted: false, orientation: true, isolated: false, distinct: false, measure: false, verbose: false) ⇒ Assertions
constructor
Initialize a new assertions instance.
- #inspect ⇒ Object
- #message ⇒ Object
-
#nested(target, identity: @identity, isolated: false, distinct: false, inverted: false, **options) ⇒ Object
Create a nested set of assertions.
- #passed? ⇒ Boolean
-
#print(output, verbose: @verbose) ⇒ Object
Print a summary of the assertions to the output.
-
#puts(*message) ⇒ Object
Print a message to the output buffer.
-
#resolve! ⇒ Object
Resolve all deferred assertions in order.
-
#skip(reason) ⇒ Object
Skip this set of assertions with a reason.
- #The absolute orientation of this set of assertions, i.e. whether the assertions are expected to pass or fail regardless of the parent. Used for correctly formatting the output.=(absoluteorientationofthissetofassertions, i.e.whethertheassertionsareexpectedtopass) ⇒ Object
- #The clock used to measure execution time, if measurement is enabled.=(clockusedtomeasureexecutiontime) ⇒ Object
- #The identity that is used to identify this set of assertions.=(identitythatisusedtoidentifythissetofassertions. = (value)) ⇒ Object
- #The output buffer used to capture output from the assertions.=(outputbufferusedtocaptureoutputfromtheassertions. = (value)) ⇒ Object
- #The specific target of the assertions, e.g. the test case or nested test assertions.=(specifictargetoftheassertions, e.g.thetest) ⇒ Object
- #total ⇒ Object
- #Whether this set of assertions is inverted, i.e. the assertions are expected to fail relative to the parent. Used for grouping assertions and ensuring they are added to the parent passed/failed array correctly.=(thissetofassertionsisinverted, i.e.theassertionsareexpectedtofailrelativetotheparent.Used) ⇒ Object
- #Whether this set of assertions is isolated from the parent. This is used to ensure that any deferred assertions are completed before the parent is completed. This is used by `receive` assertions which are deferred until the user code of the test has completed.=(thissetofassertionsisisolatedfromtheparent.Thisisusedto) ⇒ Object
- #Whether to output verbose information.=(tooutputverboseinformation. = (value)) ⇒ Object
Constructor Details
#initialize(identity: nil, target: nil, output: Output.buffered, inverted: false, orientation: true, isolated: false, distinct: false, measure: false, verbose: false) ⇒ Assertions
Initialize a new assertions instance.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/sus/assertions.rb', line 31 def initialize(identity: nil, target: nil, output: Output.buffered, inverted: false, orientation: true, isolated: false, distinct: false, measure: false, verbose: false) # In theory, the target could carry the identity of the assertion group, but it's not really necessary, so we just handle it explicitly and pass it into any nested assertions. @identity = identity @target = target @output = output @inverted = inverted @orientation = orientation @isolated = isolated @distinct = distinct @verbose = verbose if measure @clock = Clock.start! else @clock = nil end @passed = Array.new @failed = Array.new @deferred = Array.new @skipped = Array.new @errored = Array.new @count = 0 end |
Instance Attribute Details
#clock ⇒ Object (readonly)
Returns the value of attribute clock.
85 86 87 |
# File 'lib/sus/assertions.rb', line 85 def clock @clock end |
#count ⇒ Object (readonly)
Returns the value of attribute count.
103 104 105 |
# File 'lib/sus/assertions.rb', line 103 def count @count end |
#deferred ⇒ Object (readonly)
Returns the value of attribute deferred.
94 95 96 |
# File 'lib/sus/assertions.rb', line 94 def deferred @deferred end |
#distinct ⇒ Object (readonly)
Returns the value of attribute distinct.
79 80 81 |
# File 'lib/sus/assertions.rb', line 79 def distinct @distinct end |
#errored ⇒ Object (readonly)
Returns the value of attribute errored.
100 101 102 |
# File 'lib/sus/assertions.rb', line 100 def errored @errored end |
#failed ⇒ Object (readonly)
Returns the value of attribute failed.
91 92 93 |
# File 'lib/sus/assertions.rb', line 91 def failed @failed end |
#identity ⇒ Object (readonly)
Returns the value of attribute identity.
58 59 60 |
# File 'lib/sus/assertions.rb', line 58 def identity @identity end |
#inverted ⇒ Object (readonly)
Returns the value of attribute inverted.
70 71 72 |
# File 'lib/sus/assertions.rb', line 70 def inverted @inverted end |
#isolated ⇒ Object (readonly)
Returns the value of attribute isolated.
76 77 78 |
# File 'lib/sus/assertions.rb', line 76 def isolated @isolated end |
#level ⇒ Object (readonly)
Returns the value of attribute level.
67 68 69 |
# File 'lib/sus/assertions.rb', line 67 def level @level end |
#Nested assertions that have been deferred.(assertionsthathavebeendeferred.) ⇒ Object (readonly)
94 |
# File 'lib/sus/assertions.rb', line 94 attr :deferred |
#Nested assertions that have been skipped.(assertionsthathavebeenskipped.) ⇒ Object (readonly)
97 |
# File 'lib/sus/assertions.rb', line 97 attr :skipped |
#Nested assertions that have errored.(assertionsthathaveerrored.) ⇒ Object (readonly)
100 |
# File 'lib/sus/assertions.rb', line 100 attr :errored |
#Nested assertions that have failed.(assertionsthathavefailed.) ⇒ Object (readonly)
91 |
# File 'lib/sus/assertions.rb', line 91 attr :failed |
#Nested assertions that have passed.(assertionsthathavepassed.) ⇒ Object (readonly)
88 |
# File 'lib/sus/assertions.rb', line 88 attr :passed |
#orientation ⇒ Object (readonly)
Returns the value of attribute orientation.
73 74 75 |
# File 'lib/sus/assertions.rb', line 73 def orientation @orientation end |
#output ⇒ Object (readonly)
Returns the value of attribute output.
64 65 66 |
# File 'lib/sus/assertions.rb', line 64 def output @output end |
#passed ⇒ Object (readonly)
Returns the value of attribute passed.
88 89 90 |
# File 'lib/sus/assertions.rb', line 88 def passed @passed end |
#skipped ⇒ Object (readonly)
Returns the value of attribute skipped.
97 98 99 |
# File 'lib/sus/assertions.rb', line 97 def skipped @skipped end |
#target ⇒ Object (readonly)
Returns the value of attribute target.
61 62 63 |
# File 'lib/sus/assertions.rb', line 61 def target @target end |
#The nesting level of this set of assertions.(nestinglevelofthissetofassertions.) ⇒ Object (readonly)
67 |
# File 'lib/sus/assertions.rb', line 67 attr :level |
#The total number of assertions performed.(totalnumberofassertionsperformed.) ⇒ Object (readonly)
103 |
# File 'lib/sus/assertions.rb', line 103 attr :count |
#verbose ⇒ Object (readonly)
Returns the value of attribute verbose.
82 83 84 |
# File 'lib/sus/assertions.rb', line 82 def verbose @verbose end |
Class Method Details
.default(**options) ⇒ Object
Create a new assertions instance with default options.
17 18 19 |
# File 'lib/sus/assertions.rb', line 17 def self.default(**) self.new(**) end |
Instance Method Details
#add(assertions) ⇒ Object
Add child assertions that were nested to this instance.
394 395 396 397 398 399 400 401 402 403 404 405 |
# File 'lib/sus/assertions.rb', line 394 def add(assertions) # All child assertions should be resolved by this point: raise "Nested assertions must be fully resolved!" if assertions.deferred? if assertions.append? # If we are isolated, we merge all child assertions into the parent as a single entity: append!(assertions) else # Otherwise, we append all child assertions into the parent assertions: merge!(assertions) end end |
#assert(condition, message = nil) ⇒ Object
Make an assertion about a condition.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/sus/assertions.rb', line 230 def assert(condition, = nil) @count += 1 identity = @identity&.scoped backtrace = Output::Backtrace.first(identity) assert = Assert.new(identity, backtrace, self) if condition @passed << assert @output.assert(condition, @orientation, || "assertion passed", backtrace) else @failed << assert @output.assert(condition, @orientation, || "assertion failed", backtrace) end end |
#defer(&block) ⇒ Object
Add a deferred assertion that will be resolved later.
289 290 291 |
# File 'lib/sus/assertions.rb', line 289 def defer(&block) @deferred << block end |
#deferred? ⇒ Boolean
294 295 296 |
# File 'lib/sus/assertions.rb', line 294 def deferred? @deferred.any? end |
#Distinct is used to identify a set of assertions as a single statement for the purpose of user feedback. It's used by top level ensure statements to ensure that error messages are captured and reported on those statements.=(isusedtoidentifyasetofassertionsasasinglestatement) ⇒ Object
79 |
# File 'lib/sus/assertions.rb', line 79 attr :distinct |
#each_failure(&block) ⇒ Object
Iterate over all failures in this assertions instance.
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/sus/assertions.rb', line 249 def each_failure(&block) return to_enum(__method__) unless block_given? if self.failed? and @distinct return yield(self) end @failed.each do |assertions| assertions.each_failure(&block) end @errored.each do |assertions| assertions.each_failure(&block) end end |
#empty? ⇒ Boolean
166 167 168 |
# File 'lib/sus/assertions.rb', line 166 def empty? @passed.empty? and @failed.empty? and @deferred.empty? and @skipped.empty? and @errored.empty? end |
#error!(error) ⇒ Object
Record an error that occurred during test execution.
339 340 341 342 343 344 345 346 |
# File 'lib/sus/assertions.rb', line 339 def error!(error) identity = @identity&.scoped(error.backtrace_locations) @errored << Error.new(identity, error) # TODO consider passing `identity`. @output.error(error, @identity) end |
#errored? ⇒ Boolean
187 188 189 |
# File 'lib/sus/assertions.rb', line 187 def errored? @errored.any? end |
#failed? ⇒ Boolean
182 183 184 |
# File 'lib/sus/assertions.rb', line 182 def failed? !self.passed? end |
#inform(message = nil) ⇒ Object
Print an informational message during test execution.
275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/sus/assertions.rb', line 275 def inform( = nil) if .nil? and block_given? begin = yield rescue => error = error. end end @output.inform(, @identity&.scoped) end |
#inspect ⇒ Object
106 107 108 |
# File 'lib/sus/assertions.rb', line 106 def inspect "\#<#{self.class} #{@passed.size} passed #{@failed.size} failed #{@deferred.size} deferred #{@skipped.size} skipped #{@errored.size} errored>" end |
#message ⇒ Object
111 112 113 114 115 116 |
# File 'lib/sus/assertions.rb', line 111 def { text: @output.string, location: @identity&.to_location } end |
#nested(target, identity: @identity, isolated: false, distinct: false, inverted: false, **options) ⇒ Object
Create a nested set of assertions.
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 |
# File 'lib/sus/assertions.rb', line 357 def nested(target, identity: @identity, isolated: false, distinct: false, inverted: false, **) result = nil # Isolated assertions need to have buffered output so they can be replayed if they fail: if isolated or distinct output = @output.buffered else output = @output end # Inverting a nested assertions causes the orientation to flip: if inverted orientation = !@orientation else orientation = @orientation end output.puts(:indent, target) assertions = self.class.new(identity: identity, target: target, output: output, isolated: isolated, inverted: inverted, orientation: orientation, distinct: distinct, verbose: @verbose, **) output.indented do begin result = yield(assertions) rescue StandardError => error assertions.error!(error) end end # Some assertions are deferred until the end of the test, e.g. expecting a method to be called. This scope is managed by the {add} method. If there are no deferred assertions, then we can add the child assertions right away. Otherwise, we append the child assertions to our own list of deferred assertions. When an assertions instance is marked as `isolated`, it will force all deferred assertions to be resolved. It's also at this time, we should conclude measuring the duration of the test. assertions.resolve_into(self) return result end |
#passed? ⇒ Boolean
171 172 173 174 175 176 177 178 179 |
# File 'lib/sus/assertions.rb', line 171 def passed? if @inverted # Inverted assertions: @failed.any? and @errored.empty? else # Normal assertions: @failed.empty? and @errored.empty? end end |
#print(output, verbose: @verbose) ⇒ Object
Print a summary of the assertions to the output.
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 |
# File 'lib/sus/assertions.rb', line 126 def print(output, verbose: @verbose) if verbose && @target @target.print(output) output.write(": ") end if @count.zero? output.write("0 assertions") else if @passed.any? output.write(:passed, @passed.size, " passed", :reset, " ") end if @failed.any? output.write(:failed, @failed.size, " failed", :reset, " ") end if @deferred.any? output.write(:deferred, @deferred.size, " deferred", :reset, " ") end if @skipped.any? output.write(:skipped, @skipped.size, " skipped", :reset, " ") end if @errored.any? output.write(:errored, @errored.size, " errored", :reset, " ") end output.write("out of ", self.total, " total (", @count, " assertions)") end end |
#puts(*message) ⇒ Object
Print a message to the output buffer.
161 162 163 |
# File 'lib/sus/assertions.rb', line 161 def puts(*) @output.puts(:indent, *) end |
#resolve! ⇒ Object
Resolve all deferred assertions in order.
299 300 301 302 303 304 305 |
# File 'lib/sus/assertions.rb', line 299 def resolve! @output.indented do while block = @deferred.shift block.call(self) end end end |
#skip(reason) ⇒ Object
Skip this set of assertions with a reason.
267 268 269 270 271 |
# File 'lib/sus/assertions.rb', line 267 def skip(reason) @output.skip(reason, @identity&.scoped) @skipped << self end |
#The absolute orientation of this set of assertions, i.e. whether the assertions are expected to pass or fail regardless of the parent. Used for correctly formatting the output.=(absoluteorientationofthissetofassertions, i.e.whethertheassertionsareexpectedtopass) ⇒ Object
73 |
# File 'lib/sus/assertions.rb', line 73 attr :orientation |
#The clock used to measure execution time, if measurement is enabled.=(clockusedtomeasureexecutiontime) ⇒ Object
85 |
# File 'lib/sus/assertions.rb', line 85 attr :clock |
#The identity that is used to identify this set of assertions.=(identitythatisusedtoidentifythissetofassertions. = (value)) ⇒ Object
58 |
# File 'lib/sus/assertions.rb', line 58 attr :identity |
#The output buffer used to capture output from the assertions.=(outputbufferusedtocaptureoutputfromtheassertions. = (value)) ⇒ Object
64 |
# File 'lib/sus/assertions.rb', line 64 attr :output |
#The specific target of the assertions, e.g. the test case or nested test assertions.=(specifictargetoftheassertions, e.g.thetest) ⇒ Object
61 |
# File 'lib/sus/assertions.rb', line 61 attr :target |
#total ⇒ Object
119 120 121 |
# File 'lib/sus/assertions.rb', line 119 def total @passed.size + @failed.size + @deferred.size + @skipped.size + @errored.size end |
#Whether this set of assertions is inverted, i.e. the assertions are expected to fail relative to the parent. Used for grouping assertions and ensuring they are added to the parent passed/failed array correctly.=(thissetofassertionsisinverted, i.e.theassertionsareexpectedtofailrelativetotheparent.Used) ⇒ Object
70 |
# File 'lib/sus/assertions.rb', line 70 attr :inverted |
#Whether this set of assertions is isolated from the parent. This is used to ensure that any deferred assertions are completed before the parent is completed. This is used by `receive` assertions which are deferred until the user code of the test has completed.=(thissetofassertionsisisolatedfromtheparent.Thisisusedto) ⇒ Object
76 |
# File 'lib/sus/assertions.rb', line 76 attr :isolated |
#Whether to output verbose information.=(tooutputverboseinformation. = (value)) ⇒ Object
82 |
# File 'lib/sus/assertions.rb', line 82 attr :verbose |