Class: Scampi::Context
Overview
A test context created by describe. Holds specs, hooks, and child contexts.
Operates in two phases:
- Register -- evaluates the block to discover
itspecs and nested children. - Execute -- runs all registered specs in order, emitting TAP subtests.
Instance Attribute Summary collapse
-
#block ⇒ Object
readonly
Returns the value of attribute block.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
- #The block that defines this context's specs and children.(blockthatdefinesthiscontext's specs and children.) ⇒ Object readonly
- #The context name (passed to `describe`).(contextname(passed to `describe`)) ⇒ Object readonly
Instance Method Summary collapse
-
#after(&block) ⇒ Object
Register an after hook that runs after each spec in this context.
-
#before(&block) ⇒ Object
Register a before hook that runs before each spec in this context.
-
#behaves_like(*names) ⇒ Object
Include shared context blocks by name.
-
#change?(&block) ⇒ Boolean
Assert that the block changes the result of an expression.
-
#count ⇒ Object
Count total specs recursively across this context and its children.
-
#describe(*args, &block) ⇒ Object
Create a nested child context (TAP subtest).
-
#execute(indent = 0) ⇒ Object
Phase 2: run all registered specs in order, emitting TAP subtests.
-
#initialize(name, &block) ⇒ Context
constructor
Create a new context.
-
#it(description, &block) ⇒ Object
Define a spec within this context.
-
#raise?(*args, &block) ⇒ Boolean
Assert that the block raises an exception.
-
#register ⇒ Object
Phase 1: evaluate block to discover specs and children.
-
#run_requirement(description, spec, befores, afters, indent = 0, local_n = 1) ⇒ Object
Run a single spec with before/after hooks and emit TAP output.
-
#should(*args, &block) ⇒ Object
When called at the context level (outside a spec body), acts as a shortcut for
it('should ...'). -
#throw?(*args, &block) ⇒ Boolean
Assert that the block throws a symbol.
Constructor Details
#initialize(name, &block) ⇒ Context
Create a new context.
17 18 19 20 21 22 23 |
# File 'lib/scampi/context.rb', line 17 def initialize(name, &block) @name = name @block = block @items = [] @before = [] @after = [] end |
Instance Attribute Details
#block ⇒ Object (readonly)
Returns the value of attribute block.
12 13 14 |
# File 'lib/scampi/context.rb', line 12 def block @block end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
9 10 11 |
# File 'lib/scampi/context.rb', line 9 def name @name end |
#The block that defines this context's specs and children.(blockthatdefinesthiscontext's specs and children.) ⇒ Object (readonly)
12 |
# File 'lib/scampi/context.rb', line 12 attr_reader :block |
#The context name (passed to `describe`).(contextname(passed to `describe`)) ⇒ Object (readonly)
9 |
# File 'lib/scampi/context.rb', line 9 attr_reader :name |
Instance Method Details
#after(&block) ⇒ Object
Register an after hook that runs after each spec in this context.
98 |
# File 'lib/scampi/context.rb', line 98 def after(&block); @items << [:after, block]; @after << block; end |
#before(&block) ⇒ Object
Register a before hook that runs before each spec in this context.
95 |
# File 'lib/scampi/context.rb', line 95 def before(&block); @items << [:before, block]; @before << block; end |
#behaves_like(*names) ⇒ Object
Include shared context blocks by name.
103 104 105 |
# File 'lib/scampi/context.rb', line 103 def behaves_like(*names) names.each { |name| instance_eval(&Shared[name]) } end |
#change?(&block) ⇒ Boolean
Assert that the block changes the result of an expression.
209 |
# File 'lib/scampi/context.rb', line 209 def change?(&block) = lambda{}.change?(&block) |
#count ⇒ Object
Count total specs recursively across this context and its children.
40 41 42 43 44 45 46 47 48 |
# File 'lib/scampi/context.rb', line 40 def count @items.sum { |item| case item[0] when :spec then 1 when :child then item[1].count else 0 end } end |
#describe(*args, &block) ⇒ Object
Create a nested child context (TAP subtest).
Methods defined on the parent context are copied to the child so helper methods remain accessible.
188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/scampi/context.rb', line 188 def describe(*args, &block) context = Scampi::Context.new(args.join(' '), &block) (parent_context = self).methods(false).each { |e| (class << context; self; end).send(:define_method, e) { |*args2, &block2| parent_context.send(e, *args2, &block2) } } @before.each { |b| context.before(&b) } @after.each { |b| context.after(&b) } context.register @items << [:child, context] context end |
#execute(indent = 0) ⇒ Object
Phase 2: run all registered specs in order, emitting TAP subtests.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/scampi/context.rb', line 54 def execute(indent = 0) prefix = " " * indent inner = " " * (indent + 1) plan = @items.count { |item| item[0] == :spec || item[0] == :child } puts "#{prefix}# Subtest: #{@name}" puts "#{inner}1..#{plan}" befores = [] afters = [] local_n = 0 all_passed = true @items.each { |item| case item[0] when :before befores << item[1] when :after afters << item[1] when :spec Counter[:specifications] += 1 local_n += 1 passed = run_requirement(item[1], item[2], befores, afters, indent + 1, local_n) all_passed = false unless passed when :child local_n += 1 child_passed = item[1].execute(indent + 1) if child_passed puts "#{inner}#{"ok".green} #{local_n} - #{item[1].name}" else puts "#{inner}#{"not ok".red} #{local_n} - #{item[1].name}" end all_passed = false unless child_passed end } all_passed end |
#it(description, &block) ⇒ Object
Define a spec within this context.
110 111 112 113 114 |
# File 'lib/scampi/context.rb', line 110 def it(description, &block) return unless description =~ RestrictName block ||= proc { should.flunk "not implemented" } @items << [:spec, description, block] end |
#raise?(*args, &block) ⇒ Boolean
Assert that the block raises an exception.
203 |
# File 'lib/scampi/context.rb', line 203 def raise?(*args, &block) = block.raise?(*args) |
#register ⇒ Object
Phase 1: evaluate block to discover specs and children.
Nothing is executed -- it and describe just queue items.
27 28 29 30 31 32 33 34 35 |
# File 'lib/scampi/context.rb', line 27 def register tap do if name =~ RestrictContext instance_eval(&block) else self end end end |
#run_requirement(description, spec, befores, afters, indent = 0, local_n = 1) ⇒ Object
Run a single spec with before/after hooks and emit TAP output.
136 137 138 139 140 141 142 143 144 145 146 147 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 |
# File 'lib/scampi/context.rb', line 136 def run_requirement(description, spec, befores, afters, indent = 0, local_n = 1) Scampi.handle_requirement(description, indent, local_n) do begin Counter[:depth] += 1 rescued = false begin befores.each { |block| instance_eval(&block) } prev_req = Counter[:requirements] instance_eval(&spec) rescue Object => e rescued = true raise e ensure if Counter[:requirements] == prev_req and not rescued raise Error.new(:missing, "empty specification: #{@name} #{description}") end begin afters.each { |block| instance_eval(&block) } rescue Object => e raise e unless rescued end end rescue SystemExit, Interrupt raise rescue Object => e ErrorLog << "#{e.class}: #{e.}\n" e.backtrace.find_all { |line| line !~ /bin\/scampi|\/scampi\.rb:\d+/ }. each_with_index { |line, i| ErrorLog << "\t#{line}#{i==0 ? ": #@name - #{description}" : ""}\n" } ErrorLog << "\n" if e.kind_of? Error Counter[e.count_as] += 1 e.count_as.to_s.upcase else Counter[:errors] += 1 "ERROR: #{e.class}" end else "" ensure Counter[:depth] -= 1 end end end |
#should(*args, &block) ⇒ Object
When called at the context level (outside a spec body), acts as a
shortcut for it('should ...'). Inside a spec body, delegates to
the standard Object#should.
119 120 121 122 123 124 125 |
# File 'lib/scampi/context.rb', line 119 def should(*args, &block) if Counter[:depth] == 0 it('should ' + args.first, &block) else super(*args, &block) end end |
#throw?(*args, &block) ⇒ Boolean
Assert that the block throws a symbol.
206 |
# File 'lib/scampi/context.rb', line 206 def throw?(*args, &block) = block.throw?(*args) |