0
@@ -13,84 +13,170 @@ require 'mspec/runner/example'
0
# is evaluated, just as +it+ refers to the example itself.
0
+ attr_reader :state, :parent, :parents, :children, :examples, :to_s
0
+ def initialize(mod, options=nil)
0
+ @to_s += "#{".:#".include?(options[0,1]) ? "" : " "}#{options}" if options
0
+ @options[:shared] ||= false
0
+ @before = { :all => [], :each => [] }
0
+ @after = { :all => [], :each => [] }
0
@mock_verify = lambda { Mock.verify_count }
0
@mock_cleanup = lambda { Mock.cleanup }
0
@expectation_missing = lambda { raise ExpectationNotFoundError }
0
- def before(at=:each, &block)
0
+ # Returns true if this is a shared +ContextState+. Essentially, when
0
+ # created with: describe "Something", :shared => true { ... }
0
+ return @options[:shared]
0
- def after(at=:each, &block)
0
+ # Set the parent (enclosing) +ContextState+ for this state. Creates
0
+ parent.child self if parent and not shared?
0
+ # Add the ContextState instance +child+ to the list of nested
0
+ # Returns a list of all before(+what+) blocks from self and any parents.
0
+ @pre[what] ||= parents.inject([]) { |l, s| l.push(*s.before(what)) }
0
+ # Returns a list of all after(+what+) blocks from self and any parents.
0
+ # The list is in reverse order. In other words, the blocks defined in
0
+ # inner describes are in the list before those defined in outer describes,
0
+ # and in a particular describe block those defined later are in the list
0
+ # before those defined earlier.
0
+ @post[what] ||= parents.inject([]) { |l, s| l.unshift(*s.after(what)) }
0
+ # Records before(:each) and before(:all) blocks.
0
+ def before(what, &block)
0
+ block ? @before[what].push(block) : @before[what]
0
+ # Records after(:each) and after(:all) blocks.
0
+ def after(what, &block)
0
+ block ? @after[what].unshift(block) : @after[what]
0
+ # Creates an ExampleState instance for the block and stores it
0
+ # in a list of examples to evaluate unless the example is filtered.
0
- state = ExampleState.new @describe, desc
0
- @spec << [desc, block, state] unless state.filtered?
0
+ @examples << ExampleState.new(self, desc, block)
0
+ # Evaluates the block and resets the toplevel +ContextState+ to #parent.
0
+ @parsed = protect @to_s, block, false
0
+ MSpec.register_current parent
0
+ MSpec.register_shared self if shared?
0
+ # Returns a description string generated from self and all parents
0
+ @description ||= parents.inject([]) { |l,s| l << s.to_s }.join(" ")
0
- def describe(mod, desc=nil, &block)
0
- @describe = desc ? "#{mod} #{desc}" : mod.to_s
0
+ # Injects the before/after blocks and examples from the shared
0
+ # describe block into this +ContextState+ instance.
0
+ def it_should_behave_like(desc)
0
+ unless state = MSpec.retrieve_shared(desc)
0
+ raise Exception, "Unable to find shared 'describe' for #{desc}"
0
+ state.examples.each { |ex| ex.context = self; @examples << ex }
0
+ state.before(:all).each { |b| before :all, &b }
0
+ state.before(:each).each { |b| before :each, &b }
0
+ state.after(:each).each { |b| after :each, &b }
0
+ state.after(:all).each { |b| after :all, &b }
0
+ # Evaluates each block in +blocks+ using the +MSpec.protect+ method
0
+ # so that exceptions are handled and tallied. Returns true and does
0
+ # NOT evaluate any blocks if +check+ is true and +MSpec.pretend_mode?+
0
def protect(what, blocks, check=true)
0
return true if check and MSpec.pretend_mode?
0
Array(blocks).all? { |block| MSpec.protect what, &block }
0
+ # Removes filtered examples. Returns true if there are examples
0
+ @examples.reject! { |ex| ex.filtered? }
0
+ # Evaluates the examples in a +ContextState+. Invokes the MSpec events
0
+ # for :enter, :before, :after, :leave.
0
- protect @describe, @block, false
0
- return unless @spec.any? { |desc, spec, state| state.unfiltered? }
0
- MSpec.shuffle @spec if MSpec.randomize?
0
- MSpec.actions :enter, @describe
0
- if protect "before :all", @start
0
- @spec.each do |desc, spec, state|
0
- MSpec.actions :before, state
0
- if protect("before :each", @before)
0
- MSpec.clear_expectations
0
- passed = protect nil, spec
0
- MSpec.actions :example, state, spec
0
- protect nil, @expectation_missing unless MSpec.expectation? or not passed
0
+ MSpec.register_current self
0
+ if @parsed and filter_examples
0
+ MSpec.shuffle @examples if MSpec.randomize?
0
+ MSpec.actions :enter, description
0
+ if protect "before :all", pre(:all)
0
+ @examples.each do |state|
0
+ example = state.example
0
+ MSpec.actions :before, state
0
+ if protect "before :each", pre(:each)
0
+ MSpec.clear_expectations
0
+ passed = protect nil, example
0
+ MSpec.actions :example, state, example
0
+ protect nil, @expectation_missing unless MSpec.expectation? or not passed
0
+ protect "after :each", post(:each)
0
+ protect "Mock.verify_count", @mock_verify
0
- protect "after :each", @after
0
- protect "Mock.verify_count", @mock_verify
0
+ protect "Mock.cleanup", @mock_cleanup
0
+ MSpec.actions :after, state
0
+ protect "after :all", post(:all)
0
protect "Mock.cleanup", @mock_cleanup
0
- MSpec.actions :after, state
0
- protect "after :all", @finish
0
- protect "Mock.cleanup", @mock_cleanup
0
+ MSpec.register_current nil
0
+ children.each { |child| child.process }