require 'timeout' module Spec module DSL class Example def initialize(description, options={}, &example_block) @from = caller(0)[3] @options = options @example_block = example_block @description = description @description_generated_proc = lambda { |desc| @generated_description = desc } end def run(reporter, before_each_block, after_each_block, dry_run, execution_context, timeout=nil) @dry_run = dry_run reporter.example_started(description) return reporter.example_finished(description) if dry_run errors = [] location = nil Timeout.timeout(timeout) do before_each_ok = setup_example(execution_context, errors, &before_each_block) example_ok = run_example(execution_context, errors) if before_each_ok after_each_ok = teardown_example(execution_context, errors, &after_each_block) location = failure_location(before_each_ok, example_ok, after_each_ok) end ExampleShouldRaiseHandler.new(@from, @options).handle(errors) reporter.example_finished(description, errors.first, location, @example_block.nil?) if reporter end def matches?(matcher, specified_examples) matcher.example_desc = description matcher.matches?(specified_examples) end private def description @description == :__generate_description ? generated_description : @description end def generated_description return @generated_description if @generated_description if @dry_run "NO NAME (Because of --dry-run)" else if @failed "NO NAME (Because of Error raised in matcher)" else "NO NAME (Because there were no expectations)" end end end def setup_example(execution_context, errors, &behaviour_before_block) setup_mocks(execution_context) Spec::Matchers.description_generated(@description_generated_proc) builder = CompositeProcBuilder.new before_proc = builder.proc(&append_errors(errors)) execution_context.instance_eval(&before_proc) execution_context.instance_eval(&behaviour_before_block) if behaviour_before_block return errors.empty? rescue => e @failed = true errors << e return false end def run_example(execution_context, errors) begin execution_context.instance_eval(&@example_block) if @example_block return true rescue Exception => e @failed = true errors << e return false end end def teardown_example(execution_context, errors, &behaviour_after_each) execution_context.instance_eval(&behaviour_after_each) if behaviour_after_each begin verify_mocks(execution_context) ensure teardown_mocks(execution_context) end Spec::Matchers.unregister_description_generated(@description_generated_proc) builder = CompositeProcBuilder.new after_proc = builder.proc(&append_errors(errors)) execution_context.instance_eval(&after_proc) return errors.empty? rescue => e @failed = true errors << e return false end def setup_mocks(execution_context) execution_context.setup_mocks_for_rspec if execution_context.respond_to?(:setup_mocks_for_rspec) end def verify_mocks(execution_context) execution_context.verify_mocks_for_rspec if execution_context.respond_to?(:verify_mocks_for_rspec) end def teardown_mocks(execution_context) execution_context.teardown_mocks_for_rspec if execution_context.respond_to?(:teardown_mocks_for_rspec) end def append_errors(errors) proc {|error| errors << error} end def failure_location(before_each_ok, example_ok, after_each_ok) return 'before(:each)' unless before_each_ok return description unless example_ok return 'after(:each)' unless after_each_ok end end end end