diff options
author | louise <louise> | 2007-10-16 19:10:21 +0000 |
---|---|---|
committer | louise <louise> | 2007-10-16 19:10:21 +0000 |
commit | d350850897a5ee7a994d3c618529cf5beecf71ea (patch) | |
tree | 39de7013d0a3377f063fbd53da7c89f207eeedd0 /vendor/plugins/rspec/lib/spec/dsl | |
parent | 3b1d8bfdeea68da1ad083a305d0df8f458c362a0 (diff) |
Adding rspec plugin
Diffstat (limited to 'vendor/plugins/rspec/lib/spec/dsl')
-rw-r--r-- | vendor/plugins/rspec/lib/spec/dsl/behaviour.rb | 220 | ||||
-rw-r--r-- | vendor/plugins/rspec/lib/spec/dsl/behaviour_callbacks.rb | 82 | ||||
-rw-r--r-- | vendor/plugins/rspec/lib/spec/dsl/behaviour_eval.rb | 231 | ||||
-rwxr-xr-x | vendor/plugins/rspec/lib/spec/dsl/behaviour_factory.rb | 42 | ||||
-rw-r--r-- | vendor/plugins/rspec/lib/spec/dsl/composite_proc_builder.rb | 33 | ||||
-rwxr-xr-x | vendor/plugins/rspec/lib/spec/dsl/configuration.rb | 135 | ||||
-rwxr-xr-x | vendor/plugins/rspec/lib/spec/dsl/description.rb | 76 | ||||
-rw-r--r-- | vendor/plugins/rspec/lib/spec/dsl/errors.rb | 9 | ||||
-rw-r--r-- | vendor/plugins/rspec/lib/spec/dsl/example.rb | 135 | ||||
-rwxr-xr-x | vendor/plugins/rspec/lib/spec/dsl/example_matcher.rb | 40 | ||||
-rw-r--r-- | vendor/plugins/rspec/lib/spec/dsl/example_should_raise_handler.rb | 74 |
11 files changed, 1077 insertions, 0 deletions
diff --git a/vendor/plugins/rspec/lib/spec/dsl/behaviour.rb b/vendor/plugins/rspec/lib/spec/dsl/behaviour.rb new file mode 100644 index 000000000..5158bb673 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/behaviour.rb @@ -0,0 +1,220 @@ +module Spec + module DSL + class EvalModule < Module; end + class Behaviour + extend BehaviourCallbacks + + class << self + def add_shared_behaviour(behaviour) + return if behaviour.equal?(found_behaviour = find_shared_behaviour(behaviour.description)) + return if found_behaviour and File.expand_path(behaviour.description[:spec_path]) == File.expand_path(found_behaviour.description[:spec_path]) + raise ArgumentError.new("Shared Behaviour '#{behaviour.description}' already exists") if found_behaviour + shared_behaviours << behaviour + end + + def find_shared_behaviour(behaviour_description) + shared_behaviours.find { |b| b.description == behaviour_description } + end + + def shared_behaviours + # TODO - this needs to be global, or at least accessible from + # from subclasses of Behaviour in a centralized place. I'm not loving + # this as a solution, but it works for now. + $shared_behaviours ||= [] + end + end + + def initialize(*args, &behaviour_block) + init_description(*args) + init_eval_module + before_eval + eval_behaviour(&behaviour_block) + end + + private + + def init_description(*args) + unless self.class == Behaviour + args << {} unless Hash === args.last + args.last[:behaviour_class] = self.class + end + @description = Description.new(*args) + end + + def init_eval_module + @eval_module = EvalModule.new + @eval_module.extend BehaviourEval::ModuleMethods + @eval_module.include BehaviourEval::InstanceMethods + @eval_module.include described_type if described_type.class == Module + @eval_module.behaviour = self + @eval_module.description = @description + end + + def eval_behaviour(&behaviour_block) + @eval_module.class_eval(&behaviour_block) + end + + protected + + def before_eval + end + + public + + def run(reporter, dry_run=false, reverse=false, timeout=nil) + raise "shared behaviours should never run" if shared? + # TODO - change add_behaviour to add_description ?????? + reporter.add_behaviour(@description) + prepare_execution_context_class + before_all_errors = run_before_all(reporter, dry_run) + + exs = reverse ? examples.reverse : examples + example_execution_context = nil + + if before_all_errors.empty? + exs.each do |example| + example_execution_context = execution_context(example) + example_execution_context.copy_instance_variables_from(@before_and_after_all_context_instance) unless before_all_proc(behaviour_type).nil? + + befores = before_each_proc(behaviour_type) {|e| raise e} + afters = after_each_proc(behaviour_type) + example.run(reporter, befores, afters, dry_run, example_execution_context, timeout) + end + end + + @before_and_after_all_context_instance.copy_instance_variables_from(example_execution_context) unless after_all_proc(behaviour_type).nil? + run_after_all(reporter, dry_run) + end + + def number_of_examples + examples.length + end + + def matches?(specified_examples) + matcher ||= ExampleMatcher.new(description) + + examples.each do |example| + return true if example.matches?(matcher, specified_examples) + end + return false + end + + def shared? + @description[:shared] + end + + def retain_examples_matching!(specified_examples) + return if specified_examples.index(description) + matcher = ExampleMatcher.new(description) + examples.reject! do |example| + !example.matches?(matcher, specified_examples) + end + end + + def methods + my_methods = super + my_methods |= @eval_module.methods + my_methods + end + + # Includes modules in the Behaviour (the <tt>describe</tt> block). + def include(*args) + @eval_module.include(*args) + end + + def behaviour_type #:nodoc: + @description[:behaviour_type] + end + + # Sets the #number on each Example and returns the next number + def set_sequence_numbers(number, reverse) #:nodoc: + exs = reverse ? examples.reverse : examples + exs.each do |example| + example.number = number + number += 1 + end + number + end + + protected + + # Messages that this class does not understand + # are passed directly to the @eval_module. + def method_missing(sym, *args, &block) + @eval_module.send(sym, *args, &block) + end + + def prepare_execution_context_class + plugin_mock_framework + weave_in_included_modules + define_predicate_matchers #this is in behaviour_eval + execution_context_class + end + + def weave_in_included_modules + mods = [@eval_module] + mods << included_modules.dup + mods << Spec::Runner.configuration.modules_for(behaviour_type) + execution_context_class.class_eval do + # WARNING - the following can be executed in the context of any + # class, and should never pass more than one module to include + # even though we redefine include in this class. This is NOT + # tested anywhere, hence this comment. + mods.flatten.each {|mod| include mod} + end + end + + def execution_context(example) + execution_context_class.new(example) + end + + def run_before_all(reporter, dry_run) + errors = [] + unless dry_run + begin + @before_and_after_all_context_instance = execution_context(nil) + @before_and_after_all_context_instance.instance_eval(&before_all_proc(behaviour_type)) + rescue Exception => e + errors << e + location = "before(:all)" + # The easiest is to report this as an example failure. We don't have an Example + # at this point, so we'll just create a placeholder. + reporter.example_finished(Example.new(location), e, location) if reporter + end + end + errors + end + + def run_after_all(reporter, dry_run) + unless dry_run + begin + @before_and_after_all_context_instance ||= execution_context(nil) + @before_and_after_all_context_instance.instance_eval(&after_all_proc(behaviour_type)) + rescue Exception => e + location = "after(:all)" + reporter.example_finished(Example.new(location), e, location) if reporter + end + end + end + + def plugin_mock_framework + case mock_framework = Spec::Runner.configuration.mock_framework + when Module + include mock_framework + else + require Spec::Runner.configuration.mock_framework + include Spec::Plugins::MockFramework + end + end + + def description + @description.to_s + end + + def described_type + @description.described_type + end + + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/dsl/behaviour_callbacks.rb b/vendor/plugins/rspec/lib/spec/dsl/behaviour_callbacks.rb new file mode 100644 index 000000000..8b69ad9e5 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/behaviour_callbacks.rb @@ -0,0 +1,82 @@ +module Spec + module DSL + # See http://rspec.rubyforge.org/documentation/before_and_after.html + module BehaviourCallbacks + def prepend_before(*args, &block) + scope, options = scope_and_options(*args) + add(scope, options, :before, :unshift, &block) + end + def append_before(*args, &block) + scope, options = scope_and_options(*args) + add(scope, options, :before, :<<, &block) + end + alias_method :before, :append_before + + def prepend_after(*args, &block) + scope, options = scope_and_options(*args) + add(scope, options, :after, :unshift, &block) + end + alias_method :after, :prepend_after + def append_after(*args, &block) + scope, options = scope_and_options(*args) + add(scope, options, :after, :<<, &block) + end + + def scope_and_options(*args) + args, options = args_and_options(*args) + scope = (args[0] || :each), options + end + + def add(scope, options, where, how, &block) + scope ||= :each + options ||= {} + behaviour_type = options[:behaviour_type] + case scope + when :each; self.__send__("#{where}_each_parts", behaviour_type).__send__(how, block) + when :all; self.__send__("#{where}_all_parts", behaviour_type).__send__(how, block) + end + end + + def remove_after(scope, &block) + after_each_parts.delete(block) + end + + # Deprecated. Use before(:each) + def setup(&block) + before(:each, &block) + end + + # Deprecated. Use after(:each) + def teardown(&block) + after(:each, &block) + end + + def before_all_parts(behaviour_type=nil) # :nodoc: + @before_all_parts ||= {} + @before_all_parts[behaviour_type] ||= [] + end + + def after_all_parts(behaviour_type=nil) # :nodoc: + @after_all_parts ||= {} + @after_all_parts[behaviour_type] ||= [] + end + + def before_each_parts(behaviour_type=nil) # :nodoc: + @before_each_parts ||= {} + @before_each_parts[behaviour_type] ||= [] + end + + def after_each_parts(behaviour_type=nil) # :nodoc: + @after_each_parts ||= {} + @after_each_parts[behaviour_type] ||= [] + end + + def clear_before_and_after! # :nodoc: + @before_all_parts = nil + @after_all_parts = nil + @before_each_parts = nil + @after_each_parts = nil + end + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/dsl/behaviour_eval.rb b/vendor/plugins/rspec/lib/spec/dsl/behaviour_eval.rb new file mode 100644 index 000000000..9f7b8281e --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/behaviour_eval.rb @@ -0,0 +1,231 @@ +module Spec + module DSL + module BehaviourEval + module ModuleMethods + include BehaviourCallbacks + + attr_writer :behaviour + attr_accessor :description + + # RSpec runs every example in a new instance of Object, mixing in + # the behaviour necessary to run examples. Because this behaviour gets + # mixed in, it can get mixed in to an instance of any class at all. + # + # This is something that you would hardly ever use, but there is one + # common use case for it - inheriting from Test::Unit::TestCase. RSpec's + # Rails plugin uses this feature to provide access to all of the features + # that are available for Test::Unit within RSpec examples. + def inherit(klass) + raise ArgumentError.new("Shared behaviours cannot inherit from classes") if @behaviour.shared? + @behaviour_superclass = klass + derive_execution_context_class_from_behaviour_superclass + end + + # You can pass this one or many modules. Each module will subsequently + # be included in the each object in which an example is run. Use this + # to provide global helper methods to your examples. + # + # == Example + # + # module HelperMethods + # def helper_method + # ... + # end + # end + # + # describe Thing do + # include HelperMethods + # it "should do stuff" do + # helper_method + # end + # end + def include(*mods) + mods.each do |mod| + included_modules << mod + mod.send :included, self + end + end + + # Use this to pull in examples from shared behaviours. + # See Spec::Runner for information about shared behaviours. + def it_should_behave_like(behaviour_description) + behaviour = @behaviour.class.find_shared_behaviour(behaviour_description) + if behaviour.nil? + raise RuntimeError.new("Shared Behaviour '#{behaviour_description}' can not be found") + end + behaviour.copy_to(self) + end + + def copy_to(eval_module) # :nodoc: + examples.each { |e| eval_module.examples << e; } + before_each_parts.each { |p| eval_module.before_each_parts << p } + after_each_parts.each { |p| eval_module.after_each_parts << p } + before_all_parts.each { |p| eval_module.before_all_parts << p } + after_all_parts.each { |p| eval_module.after_all_parts << p } + included_modules.each { |m| eval_module.included_modules << m } + eval_module.included_modules << self + end + + # :call-seq: + # predicate_matchers[matcher_name] = method_on_object + # predicate_matchers[matcher_name] = [method1_on_object, method2_on_object] + # + # Dynamically generates a custom matcher that will match + # a predicate on your class. RSpec provides a couple of these + # out of the box: + # + # exist (or state expectations) + # File.should exist("path/to/file") + # + # an_instance_of (for mock argument constraints) + # mock.should_receive(:message).with(an_instance_of(String)) + # + # == Examples + # + # class Fish + # def can_swim? + # true + # end + # end + # + # describe Fish do + # predicate_matchers[:swim] = :can_swim? + # it "should swim" do + # Fish.new.should swim + # end + # end + def predicate_matchers + @predicate_matchers ||= {:exist => :exist?, :an_instance_of => :is_a?} + end + + def define_predicate_matchers(hash=nil) # :nodoc: + if hash.nil? + define_predicate_matchers(predicate_matchers) + define_predicate_matchers(Spec::Runner.configuration.predicate_matchers) + else + hash.each_pair do |matcher_method, method_on_object| + define_method matcher_method do |*args| + eval("be_#{method_on_object.to_s.gsub('?','')}(*args)") + end + end + end + end + + # Creates an instance of Spec::DSL::Example and adds + # it to a collection of examples of the current behaviour. + def it(description=:__generate_description, opts={}, &block) + examples << Example.new(description, opts, &block) + end + + # Alias for it. + def specify(description=:__generate_description, opts={}, &block) + it(description, opts, &block) + end + + def methods # :nodoc: + my_methods = super + my_methods |= behaviour_superclass.methods + my_methods + end + + protected + + def method_missing(method_name, *args) + if behaviour_superclass.respond_to?(method_name) + return execution_context_class.send(method_name, *args) + end + super + end + + def before_each_proc(behaviour_type, &error_handler) + parts = [] + parts.push(*Behaviour.before_each_parts(nil)) + parts.push(*Behaviour.before_each_parts(behaviour_type)) unless behaviour_type.nil? + parts.push(*before_each_parts(nil)) + parts.push(*before_each_parts(behaviour_type)) unless behaviour_type.nil? + CompositeProcBuilder.new(parts).proc(&error_handler) + end + + def before_all_proc(behaviour_type, &error_handler) + parts = [] + parts.push(*Behaviour.before_all_parts(nil)) + parts.push(*Behaviour.before_all_parts(behaviour_type)) unless behaviour_type.nil? + parts.push(*before_all_parts(nil)) + parts.push(*before_all_parts(behaviour_type)) unless behaviour_type.nil? + CompositeProcBuilder.new(parts).proc(&error_handler) + end + + def after_all_proc(behaviour_type) + parts = [] + parts.push(*after_all_parts(behaviour_type)) unless behaviour_type.nil? + parts.push(*after_all_parts(nil)) + parts.push(*Behaviour.after_all_parts(behaviour_type)) unless behaviour_type.nil? + parts.push(*Behaviour.after_all_parts(nil)) + CompositeProcBuilder.new(parts).proc + end + + def after_each_proc(behaviour_type) + parts = [] + parts.push(*after_each_parts(behaviour_type)) unless behaviour_type.nil? + parts.push(*after_each_parts(nil)) + parts.push(*Behaviour.after_each_parts(behaviour_type)) unless behaviour_type.nil? + parts.push(*Behaviour.after_each_parts(nil)) + CompositeProcBuilder.new(parts).proc + end + + private + + def execution_context_class + @execution_context_class ||= derive_execution_context_class_from_behaviour_superclass + end + + def derive_execution_context_class_from_behaviour_superclass + @execution_context_class = Class.new(behaviour_superclass) + behaviour_superclass.spec_inherited(self) if behaviour_superclass.respond_to?(:spec_inherited) + @execution_context_class + end + + def behaviour_superclass + @behaviour_superclass ||= Object + end + + protected + def included_modules + @included_modules ||= [::Spec::Matchers] + end + + def examples + @examples ||= [] + end + end + + module InstanceMethods + def initialize(*args, &block) #:nodoc: + # TODO - inheriting from TestUnit::TestCase fails without this + # - let's figure out why and move this somewhere else + end + + def violated(message="") + raise Spec::Expectations::ExpectationNotMetError.new(message) + end + + def inspect + "[RSpec example]" + end + + def pending(message) + if block_given? + begin + yield + rescue Exception => e + raise Spec::DSL::ExamplePendingError.new(message) + end + raise Spec::DSL::PendingFixedError.new("Expected pending '#{message}' to fail. No Error was raised.") + else + raise Spec::DSL::ExamplePendingError.new(message) + end + end + end + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/dsl/behaviour_factory.rb b/vendor/plugins/rspec/lib/spec/dsl/behaviour_factory.rb new file mode 100755 index 000000000..44b60c641 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/behaviour_factory.rb @@ -0,0 +1,42 @@ +module Spec + module DSL + class BehaviourFactory + + class << self + + BEHAVIOUR_CLASSES = {:default => Spec::DSL::Behaviour} + + # Registers a behaviour class +klass+ with the symbol + # +behaviour_type+. For example: + # + # Spec::DSL::BehaviourFactory.add_behaviour_class(:farm, Spec::Farm::DSL::FarmBehaviour) + # + # This will cause Kernel#describe from a file living in + # <tt>spec/farm</tt> to create behaviour instances of type + # Spec::Farm::DSL::FarmBehaviour. + def add_behaviour_class(behaviour_type, klass) + BEHAVIOUR_CLASSES[behaviour_type] = klass + end + + def remove_behaviour_class(behaviour_type) + BEHAVIOUR_CLASSES.delete(behaviour_type) + end + + def create(*args, &block) + opts = Hash === args.last ? args.last : {} + if opts[:shared] + behaviour_type = :default + elsif opts[:behaviour_type] + behaviour_type = opts[:behaviour_type] + elsif opts[:spec_path] =~ /spec(\\|\/)(#{BEHAVIOUR_CLASSES.keys.join('|')})/ + behaviour_type = $2.to_sym + else + behaviour_type = :default + end + return BEHAVIOUR_CLASSES[behaviour_type].new(*args, &block) + end + + end + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/dsl/composite_proc_builder.rb b/vendor/plugins/rspec/lib/spec/dsl/composite_proc_builder.rb new file mode 100644 index 000000000..373f44953 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/composite_proc_builder.rb @@ -0,0 +1,33 @@ +module Spec + module DSL + class CompositeProcBuilder < Array + def initialize(callbacks=[]) + push(*callbacks) + end + + def proc(&error_handler) + parts = self + errors = [] + Proc.new do + result = parts.collect do |part| + begin + if part.is_a?(UnboundMethod) + part.bind(self).call + else + instance_eval(&part) + end + rescue Exception => e + if error_handler + error_handler.call(e) + else + errors << e + end + end + end + raise errors.first unless errors.empty? + result + end + end + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/dsl/configuration.rb b/vendor/plugins/rspec/lib/spec/dsl/configuration.rb new file mode 100755 index 000000000..709574ded --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/configuration.rb @@ -0,0 +1,135 @@ +module Spec + module DSL + class Configuration + + # Chooses what mock framework to use. Example: + # + # Spec::Runner.configure do |config| + # config.mock_with :rspec, :mocha, :flexmock, or :rr + # end + # + # To use any other mock framework, you'll have to provide + # your own adapter. This is simply a module that responds to + # setup_mocks_for_rspec, verify_mocks_for_rspec and teardown_mocks_for_rspec. + # These are your hooks into the lifecycle of a given example. RSpec will + # call setup_mocks_for_rspec before running anything else in each Example. + # After executing the #after methods, RSpec will then call verify_mocks_for_rspec + # and teardown_mocks_for_rspec (this is guaranteed to run even if there are + # failures in verify_mocks_for_rspec). + # + # Once you've defined this module, you can pass that to mock_with: + # + # Spec::Runner.configure do |config| + # config.mock_with MyMockFrameworkAdapter + # end + # + def mock_with(mock_framework) + @mock_framework = case mock_framework + when Symbol + mock_framework_path(mock_framework.to_s) + else + mock_framework + end + end + + def mock_framework # :nodoc: + @mock_framework ||= mock_framework_path("rspec") + end + + # Declares modules to be included in all behaviours (<tt>describe</tt> blocks). + # + # config.include(My::Bottle, My::Cup) + # + # If you want to restrict the inclusion to a subset of all the behaviours then + # specify this in a Hash as the last argument: + # + # config.include(My::Pony, My::Horse, :behaviour_type => :farm) + # + # Only behaviours that have that type will get the modules included: + # + # describe "Downtown", :behaviour_type => :city do + # # Will *not* get My::Pony and My::Horse included + # end + # + # describe "Old Mac Donald", :behaviour_type => :farm do + # # *Will* get My::Pony and My::Horse included + # end + # + def include(*args) + args << {} unless Hash === args.last + modules, options = args_and_options(*args) + required_behaviour_type = options[:behaviour_type] + required_behaviour_type = required_behaviour_type.to_sym unless required_behaviour_type.nil? + @modules ||= {} + @modules[required_behaviour_type] ||= [] + @modules[required_behaviour_type] += modules + end + + def modules_for(required_behaviour_type) #:nodoc: + @modules ||= {} + modules = @modules[nil] || [] # general ones + modules << @modules[required_behaviour_type.to_sym] unless required_behaviour_type.nil? + modules.uniq.compact + end + + # This is just for cleanup in RSpec's own examples + def exclude(*modules) #:nodoc: + @modules.each do |behaviour_type, mods| + modules.each{|m| mods.delete(m)} + end + end + + # Defines global predicate matchers. Example: + # + # config.predicate_matchers[:swim] = :can_swim? + # + # This makes it possible to say: + # + # person.should swim # passes if person.should_swim? returns true + # + def predicate_matchers + @predicate_matchers ||= {} + end + + # Prepends a global <tt>before</tt> block to all behaviours. + # See #append_before for filtering semantics. + def prepend_before(*args, &proc) + Behaviour.prepend_before(*args, &proc) + end + # Appends a global <tt>before</tt> block to all behaviours. + # + # If you want to restrict the block to a subset of all the behaviours then + # specify this in a Hash as the last argument: + # + # config.prepend_before(:all, :behaviour_type => :farm) + # + # or + # + # config.prepend_before(:behaviour_type => :farm) + # + def append_before(*args, &proc) + Behaviour.append_before(*args, &proc) + end + alias_method :before, :append_before + + # Prepends a global <tt>after</tt> block to all behaviours. + # See #append_before for filtering semantics. + def prepend_after(*args, &proc) + Behaviour.prepend_after(*args, &proc) + end + alias_method :after, :prepend_after + # Appends a global <tt>after</tt> block to all behaviours. + # See #append_before for filtering semantics. + def append_after(*args, &proc) + Behaviour.append_after(*args, &proc) + end + + private + + def mock_framework_path(framework_name) + File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "plugins", "mock_frameworks", framework_name)) + end + + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/dsl/description.rb b/vendor/plugins/rspec/lib/spec/dsl/description.rb new file mode 100755 index 000000000..fe8c9b0c9 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/description.rb @@ -0,0 +1,76 @@ +module Spec + module DSL + class Description + module ClassMethods + def generate_description(*args) + description = args.shift.to_s + unless args.empty? + suffix = args.shift.to_s + description << " " unless suffix =~ /^\s|\.|#/ + description << suffix + end + description + end + end + extend ClassMethods + + attr_reader :description, :described_type + + def initialize(*args) + args, @options = args_and_options(*args) + init_behaviour_type(@options) + init_spec_path(@options) + init_described_type(args) + init_description(*args) + end + + def [](key) + @options[key] + end + + def []=(key, value) + @options[key] = value + end + + def to_s; @description; end + + def ==(value) + case value + when Description + @description == value.description + else + @description == value + end + end + + private + def init_behaviour_type(options) + # NOTE - BE CAREFUL IF CHANGING THIS NEXT LINE: + # this line is as it is to satisfy JRuby - the original version + # read, simply: "if options[:behaviour_class]", which passed against ruby, but failed against jruby + if options[:behaviour_class] && options[:behaviour_class].ancestors.include?(Behaviour) + options[:behaviour_type] = parse_behaviour_type(@options[:behaviour_class]) + end + end + + def init_spec_path(options) + if options.has_key?(:spec_path) + options[:spec_path] = File.expand_path(@options[:spec_path]) + end + end + + def init_description(*args) + @description = self.class.generate_description(*args) + end + + def init_described_type(args) + @described_type = args.first unless args.first.is_a?(String) + end + + def parse_behaviour_type(behaviour_class) + behaviour_class.to_s.split("::").reverse[0].gsub!('Behaviour', '').downcase.to_sym + end + + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/dsl/errors.rb b/vendor/plugins/rspec/lib/spec/dsl/errors.rb new file mode 100644 index 000000000..ba7046a89 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/errors.rb @@ -0,0 +1,9 @@ +module Spec + module DSL + class ExamplePendingError < StandardError + end + + class PendingFixedError < StandardError + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/dsl/example.rb b/vendor/plugins/rspec/lib/spec/dsl/example.rb new file mode 100644 index 000000000..d04073f7e --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/example.rb @@ -0,0 +1,135 @@ +require 'timeout' + +module Spec + module DSL + class Example + # The global sequence number of this example + attr_accessor :number + + 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(self) + return reporter.example_finished(self) if dry_run + + errors = [] + location = nil + Timeout.timeout(timeout) do + before_each_ok = before_example(execution_context, errors, &before_each_block) + example_ok = run_example(execution_context, errors) if before_each_ok + after_each_ok = after_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(self, errors.first, location, @example_block.nil?) if reporter + end + + def matches?(matcher, specified_examples) + matcher.example_desc = description + matcher.matches?(specified_examples) + end + + def description + @description == :__generate_description ? generated_description : @description + end + + def to_s + description + end + + private + + 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 before_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 Exception => 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 after_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 Exception => 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 diff --git a/vendor/plugins/rspec/lib/spec/dsl/example_matcher.rb b/vendor/plugins/rspec/lib/spec/dsl/example_matcher.rb new file mode 100755 index 000000000..18cc47409 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/example_matcher.rb @@ -0,0 +1,40 @@ +module Spec + module DSL + class ExampleMatcher + + attr_writer :example_desc + def initialize(behaviour_desc, example_desc=nil) + @behaviour_desc = behaviour_desc + @example_desc = example_desc + end + + def matches?(specified_examples) + specified_examples.each do |specified_example| + return true if matches_literal_example?(specified_example) || matches_example_not_considering_modules?(specified_example) + end + false + end + + private + def matches_literal_example?(specified_example) + specified_example =~ /(^#{context_regexp} #{example_regexp}$|^#{context_regexp}$|^#{example_regexp}$)/ + end + + def matches_example_not_considering_modules?(specified_example) + specified_example =~ /(^#{context_regexp_not_considering_modules} #{example_regexp}$|^#{context_regexp_not_considering_modules}$|^#{example_regexp}$)/ + end + + def context_regexp + Regexp.escape(@behaviour_desc) + end + + def context_regexp_not_considering_modules + Regexp.escape(@behaviour_desc.split('::').last) + end + + def example_regexp + Regexp.escape(@example_desc) + end + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/dsl/example_should_raise_handler.rb b/vendor/plugins/rspec/lib/spec/dsl/example_should_raise_handler.rb new file mode 100644 index 000000000..942327317 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/dsl/example_should_raise_handler.rb @@ -0,0 +1,74 @@ +module Spec + module DSL + class ExampleShouldRaiseHandler + def initialize(file_and_line_number, opts) + @file_and_line_number = file_and_line_number + @options = opts + @expected_error_class = determine_error_class(opts) + @expected_error_message = determine_error_message(opts) + end + + def determine_error_class(opts) + if candidate = opts[:should_raise] + if candidate.is_a?(Class) + return candidate + elsif candidate.is_a?(Array) + return candidate[0] + else + return Exception + end + end + end + + def determine_error_message(opts) + if candidate = opts[:should_raise] + if candidate.is_a?(Array) + return candidate[1] + end + end + return nil + end + + def build_message(exception=nil) + if @expected_error_message.nil? + message = "example block expected #{@expected_error_class.to_s}" + else + message = "example block expected #{@expected_error_class.new(@expected_error_message.to_s).inspect}" + end + message << " but raised #{exception.inspect}" if exception + message << " but nothing was raised" unless exception + message << "\n" + message << @file_and_line_number + end + + def error_matches?(error) + return false unless error.kind_of?(@expected_error_class) + unless @expected_error_message.nil? + if @expected_error_message.is_a?(Regexp) + return false unless error.message =~ @expected_error_message + else + return false unless error.message == @expected_error_message + end + end + return true + end + + def handle(errors) + if @expected_error_class + if errors.empty? + errors << Spec::Expectations::ExpectationNotMetError.new(build_message) + else + error_to_remove = errors.detect do |error| + error_matches?(error) + end + if error_to_remove.nil? + errors.insert(0,Spec::Expectations::ExpectationNotMetError.new(build_message(errors[0]))) + else + errors.delete(error_to_remove) + end + end + end + end + end + end +end |