Class: Sus::Assertions
- Inherits:
-
Object
- Object
- Sus::Assertions
- Defined in:
- lib/sus/assertions.rb
Defined Under Namespace
Instance Attribute Summary collapse
-
#clock ⇒ Object
readonly
Returns the value of attribute clock.
-
#count ⇒ Object
readonly
The total number of assertions performed:.
-
#deferred ⇒ Object
readonly
Nested assertions have been deferred.
-
#distinct ⇒ Object
readonly
Distinct is used to identify a set of assertions as a single statement for the purpose of user feedback.
-
#errored ⇒ Object
readonly
Returns the value of attribute errored.
-
#failed ⇒ Object
readonly
Nested assertions that have failed.
-
#identity ⇒ Object
readonly
The identity that is used to identify this set of assertions.
-
#inverted ⇒ Object
readonly
Whether this aset of assertions is inverted, i.e.
-
#isolated ⇒ Object
readonly
Whether this set of assertions is isolated from the parent.
-
#level ⇒ Object
readonly
The nesting level of this set of assertions.
-
#orientation ⇒ Object
readonly
The absolute orientation of this set of assertions, i.e.
-
#output ⇒ Object
readonly
The output buffer used to capture output from the assertions.
-
#passed ⇒ Object
readonly
Nested assertions that have passed.
-
#skipped ⇒ Object
readonly
Returns the value of attribute skipped.
-
#target ⇒ Object
readonly
The specific target of the assertions, e.g.
-
#verbose ⇒ Object
readonly
Returns the value of attribute verbose.
Class Method Summary collapse
Instance Method Summary collapse
-
#add(assertions) ⇒ Object
Add the child assertions which were nested to this instance.
- #assert(condition, message = nil) ⇒ Object
-
#defer(&block) ⇒ Object
Add deferred assertions.
-
#deferred? ⇒ Boolean
Whether there are any deferred assertions.
- #each_failure(&block) ⇒ Object
- #empty? ⇒ Boolean
- #error!(error) ⇒ Object
- #errored? ⇒ Boolean
- #failed? ⇒ Boolean
- #inform(message = nil) ⇒ Object
-
#initialize(identity: nil, target: nil, output: Output.buffered, inverted: false, orientation: true, isolated: false, distinct: false, measure: false, verbose: false) ⇒ Assertions
constructor
A new instance of Assertions.
- #inspect ⇒ Object
- #message ⇒ Object
- #nested(target, identity: @identity, isolated: false, distinct: false, inverted: false, **options) ⇒ Object
- #passed? ⇒ Boolean
- #print(output, verbose: @verbose) ⇒ Object
- #puts(*message) ⇒ Object
-
#resolve! ⇒ Object
This resolves all deferred assertions in order.
- #skip(reason) ⇒ Object
- #total ⇒ Object
Constructor Details
#initialize(identity: nil, target: nil, output: Output.buffered, inverted: false, orientation: true, isolated: false, distinct: false, measure: false, verbose: false) ⇒ Assertions
Returns a new instance of Assertions.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/sus/assertions.rb', line 19 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.
71 72 73 |
# File 'lib/sus/assertions.rb', line 71 def clock @clock end |
#count ⇒ Object (readonly)
The total number of assertions performed:
86 87 88 |
# File 'lib/sus/assertions.rb', line 86 def count @count end |
#deferred ⇒ Object (readonly)
Nested assertions have been deferred.
80 81 82 |
# File 'lib/sus/assertions.rb', line 80 def deferred @deferred end |
#distinct ⇒ Object (readonly)
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.
67 68 69 |
# File 'lib/sus/assertions.rb', line 67 def distinct @distinct end |
#errored ⇒ Object (readonly)
Returns the value of attribute errored.
83 84 85 |
# File 'lib/sus/assertions.rb', line 83 def errored @errored end |
#failed ⇒ Object (readonly)
Nested assertions that have failed.
77 78 79 |
# File 'lib/sus/assertions.rb', line 77 def failed @failed end |
#identity ⇒ Object (readonly)
The identity that is used to identify this set of assertions.
46 47 48 |
# File 'lib/sus/assertions.rb', line 46 def identity @identity end |
#inverted ⇒ Object (readonly)
Whether this aset 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.
58 59 60 |
# File 'lib/sus/assertions.rb', line 58 def inverted @inverted end |
#isolated ⇒ Object (readonly)
Whether this set of assertions is isolated from the parent. This is used to ensure that any deferred assertions are competed before the parent is completed. This is used by ‘receive` assertions which are deferred until the user code of the test has completed.
64 65 66 |
# File 'lib/sus/assertions.rb', line 64 def isolated @isolated end |
#level ⇒ Object (readonly)
The nesting level of this set of assertions.
55 56 57 |
# File 'lib/sus/assertions.rb', line 55 def level @level end |
#orientation ⇒ Object (readonly)
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.
61 62 63 |
# File 'lib/sus/assertions.rb', line 61 def orientation @orientation end |
#output ⇒ Object (readonly)
The output buffer used to capture output from the assertions.
52 53 54 |
# File 'lib/sus/assertions.rb', line 52 def output @output end |
#passed ⇒ Object (readonly)
Nested assertions that have passed.
74 75 76 |
# File 'lib/sus/assertions.rb', line 74 def passed @passed end |
#skipped ⇒ Object (readonly)
Returns the value of attribute skipped.
82 83 84 |
# File 'lib/sus/assertions.rb', line 82 def skipped @skipped end |
#target ⇒ Object (readonly)
The specific target of the assertions, e.g. the test case or nested test assertions.
49 50 51 |
# File 'lib/sus/assertions.rb', line 49 def target @target end |
#verbose ⇒ Object (readonly)
Returns the value of attribute verbose.
69 70 71 |
# File 'lib/sus/assertions.rb', line 69 def verbose @verbose end |
Class Method Details
.default(**options) ⇒ Object
13 14 15 |
# File 'lib/sus/assertions.rb', line 13 def self.default(**) self.new(**) end |
Instance Method Details
#add(assertions) ⇒ Object
Add the child assertions which were nested to this instance.
321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/sus/assertions.rb', line 321 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
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/sus/assertions.rb', line 186 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 deferred assertions.
237 238 239 |
# File 'lib/sus/assertions.rb', line 237 def defer(&block) @deferred << block end |
#deferred? ⇒ Boolean
Whether there are any deferred assertions.
242 243 244 |
# File 'lib/sus/assertions.rb', line 242 def deferred? @deferred.any? end |
#each_failure(&block) ⇒ Object
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/sus/assertions.rb', line 202 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
140 141 142 |
# File 'lib/sus/assertions.rb', line 140 def empty? @passed.empty? and @failed.empty? and @deferred.empty? and @skipped.empty? and @errored.empty? end |
#error!(error) ⇒ Object
276 277 278 279 280 281 282 283 |
# File 'lib/sus/assertions.rb', line 276 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
158 159 160 |
# File 'lib/sus/assertions.rb', line 158 def errored? @errored.any? end |
#failed? ⇒ Boolean
154 155 156 |
# File 'lib/sus/assertions.rb', line 154 def failed? !self.passed? end |
#inform(message = nil) ⇒ Object
224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/sus/assertions.rb', line 224 def inform( = nil) if .nil? and block_given? begin = yield rescue => error = error. end end @output.inform(, @identity&.scoped) end |
#inspect ⇒ Object
88 89 90 |
# File 'lib/sus/assertions.rb', line 88 def inspect "\#<#{self.class} #{@passed.size} passed #{@failed.size} failed #{@deferred.size} deferred #{@skipped.size} skipped #{@errored.size} errored>" end |
#message ⇒ Object
92 93 94 95 96 97 |
# File 'lib/sus/assertions.rb', line 92 def { text: @output.string, location: @identity&.to_location } end |
#nested(target, identity: @identity, isolated: false, distinct: false, inverted: false, **options) ⇒ Object
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/sus/assertions.rb', line 285 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
144 145 146 147 148 149 150 151 152 |
# File 'lib/sus/assertions.rb', line 144 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
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/sus/assertions.rb', line 103 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
136 137 138 |
# File 'lib/sus/assertions.rb', line 136 def puts(*) @output.puts(:indent, *) end |
#resolve! ⇒ Object
This resolves all deferred assertions in order.
247 248 249 250 251 252 253 |
# File 'lib/sus/assertions.rb', line 247 def resolve! @output.indented do while block = @deferred.shift block.call(self) end end end |
#skip(reason) ⇒ Object
218 219 220 221 222 |
# File 'lib/sus/assertions.rb', line 218 def skip(reason) @output.skip(reason, @identity&.scoped) @skipped << self end |
#total ⇒ Object
99 100 101 |
# File 'lib/sus/assertions.rb', line 99 def total @passed.size + @failed.size + @deferred.size + @skipped.size + @errored.size end |