mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-22 10:10:12 +01:00
Added Rspec and Webrat plugins and started porting Selenium on Rails tests to Rspec Plain Text Stories driving Webrat driving Selenium.
This commit is contained in:
parent
0600756bbf
commit
0f7d6f7a1d
602 changed files with 47788 additions and 29 deletions
3
vendor/plugins/rspec/lib/autotest/discover.rb
vendored
Normal file
3
vendor/plugins/rspec/lib/autotest/discover.rb
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Autotest.add_discovery do
|
||||
"rspec" if File.exist?('spec')
|
||||
end
|
||||
72
vendor/plugins/rspec/lib/autotest/rspec.rb
vendored
Normal file
72
vendor/plugins/rspec/lib/autotest/rspec.rb
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
require 'autotest'
|
||||
|
||||
Autotest.add_hook :initialize do |at|
|
||||
at.clear_mappings
|
||||
# watch out: Ruby bug (1.8.6):
|
||||
# %r(/) != /\//
|
||||
at.add_mapping(%r%^spec/.*\.rb$%) { |filename, _|
|
||||
filename
|
||||
}
|
||||
at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m|
|
||||
["spec/#{m[1]}_spec.rb"]
|
||||
}
|
||||
at.add_mapping(%r%^spec/(spec_helper|shared/.*)\.rb$%) {
|
||||
at.files_matching %r%^spec/.*_spec\.rb$%
|
||||
}
|
||||
end
|
||||
|
||||
class RspecCommandError < StandardError; end
|
||||
|
||||
class Autotest::Rspec < Autotest
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.failed_results_re = /^\d+\)\n(?:\e\[\d*m)?(?:.*?Error in )?'([^\n]*)'(?: FAILED)?(?:\e\[\d*m)?\n(.*?)\n\n/m
|
||||
self.completed_re = /\n(?:\e\[\d*m)?\d* examples?/m
|
||||
end
|
||||
|
||||
def consolidate_failures(failed)
|
||||
filters = new_hash_of_arrays
|
||||
failed.each do |spec, trace|
|
||||
if trace =~ /\n(\.\/)?(.*spec\.rb):[\d]+:\Z?/
|
||||
filters[$2] << spec
|
||||
end
|
||||
end
|
||||
return filters
|
||||
end
|
||||
|
||||
def make_test_cmd(files_to_test)
|
||||
return "#{ruby} -S #{spec_command} #{add_options_if_present} #{files_to_test.keys.flatten.join(' ')}"
|
||||
end
|
||||
|
||||
def add_options_if_present # :nodoc:
|
||||
File.exist?("spec/spec.opts") ? "-O spec/spec.opts " : ""
|
||||
end
|
||||
|
||||
# Finds the proper spec command to use. Precendence is set in the
|
||||
# lazily-evaluated method spec_commands. Alias + Override that in
|
||||
# ~/.autotest to provide a different spec command then the default
|
||||
# paths provided.
|
||||
def spec_command(separator=File::ALT_SEPARATOR)
|
||||
unless defined? @spec_command then
|
||||
@spec_command = spec_commands.find { |cmd| File.exists? cmd }
|
||||
|
||||
raise RspecCommandError, "No spec command could be found!" unless @spec_command
|
||||
|
||||
@spec_command.gsub! File::SEPARATOR, separator if separator
|
||||
end
|
||||
@spec_command
|
||||
end
|
||||
|
||||
# Autotest will look for spec commands in the following
|
||||
# locations, in this order:
|
||||
#
|
||||
# * bin/spec
|
||||
# * default spec bin/loader installed in Rubygems
|
||||
def spec_commands
|
||||
[
|
||||
File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'bin', 'spec')),
|
||||
File.join(Config::CONFIG['bindir'], 'spec')
|
||||
]
|
||||
end
|
||||
end
|
||||
31
vendor/plugins/rspec/lib/spec.rb
vendored
Normal file
31
vendor/plugins/rspec/lib/spec.rb
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
require 'spec/version'
|
||||
require 'spec/matchers'
|
||||
require 'spec/expectations'
|
||||
require 'spec/example'
|
||||
require 'spec/extensions'
|
||||
require 'spec/runner'
|
||||
require 'spec/adapters'
|
||||
|
||||
if Object.const_defined?(:Test)
|
||||
require 'spec/interop/test'
|
||||
end
|
||||
|
||||
module Spec
|
||||
class << self
|
||||
def run?
|
||||
@run || rspec_options.examples_run?
|
||||
end
|
||||
|
||||
def run
|
||||
return true if run?
|
||||
result = rspec_options.run_examples
|
||||
@run = true
|
||||
result
|
||||
end
|
||||
attr_writer :run
|
||||
|
||||
def exit?
|
||||
!Object.const_defined?(:Test) || Test::Unit.run?
|
||||
end
|
||||
end
|
||||
end
|
||||
1
vendor/plugins/rspec/lib/spec/adapters.rb
vendored
Normal file
1
vendor/plugins/rspec/lib/spec/adapters.rb
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
require 'spec/adapters/ruby_engine'
|
||||
26
vendor/plugins/rspec/lib/spec/adapters/ruby_engine.rb
vendored
Normal file
26
vendor/plugins/rspec/lib/spec/adapters/ruby_engine.rb
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
require 'spec/adapters/ruby_engine/mri'
|
||||
require 'spec/adapters/ruby_engine/rubinius'
|
||||
|
||||
module Spec
|
||||
module Adapters
|
||||
module RubyEngine
|
||||
|
||||
ENGINES = {
|
||||
'mri' => MRI.new,
|
||||
'rbx' => Rubinius.new
|
||||
}
|
||||
|
||||
def self.engine
|
||||
if const_defined?(:RUBY_ENGINE)
|
||||
return RUBY_ENGINE
|
||||
else
|
||||
return 'mri'
|
||||
end
|
||||
end
|
||||
|
||||
def self.adapter
|
||||
return ENGINES[engine]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
8
vendor/plugins/rspec/lib/spec/adapters/ruby_engine/mri.rb
vendored
Normal file
8
vendor/plugins/rspec/lib/spec/adapters/ruby_engine/mri.rb
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
module Spec
|
||||
module Adapters
|
||||
module RubyEngine
|
||||
class MRI
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
8
vendor/plugins/rspec/lib/spec/adapters/ruby_engine/rubinius.rb
vendored
Normal file
8
vendor/plugins/rspec/lib/spec/adapters/ruby_engine/rubinius.rb
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
module Spec
|
||||
module Adapters
|
||||
module RubyEngine
|
||||
class Rubinius
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
12
vendor/plugins/rspec/lib/spec/example.rb
vendored
Normal file
12
vendor/plugins/rspec/lib/spec/example.rb
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
require 'timeout'
|
||||
require 'spec/example/pending'
|
||||
require 'spec/example/module_reopening_fix'
|
||||
require 'spec/example/module_inclusion_warnings'
|
||||
require 'spec/example/example_group_methods'
|
||||
require 'spec/example/example_methods'
|
||||
require 'spec/example/example_group'
|
||||
require 'spec/example/shared_example_group'
|
||||
require 'spec/example/example_group_factory'
|
||||
require 'spec/example/errors'
|
||||
require 'spec/example/configuration'
|
||||
require 'spec/example/example_matcher'
|
||||
158
vendor/plugins/rspec/lib/spec/example/configuration.rb
vendored
Executable file
158
vendor/plugins/rspec/lib/spec/example/configuration.rb
vendored
Executable file
|
|
@ -0,0 +1,158 @@
|
|||
module Spec
|
||||
module Example
|
||||
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 the following
|
||||
# methods:
|
||||
#
|
||||
# setup_mocks_for_rspec
|
||||
# verify_mocks_for_rspec
|
||||
# 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
|
||||
|
||||
# :call-seq:
|
||||
# include(Some::Helpers)
|
||||
# include(Some::Helpers, More::Helpers)
|
||||
# include(My::Helpers, :type => :key)
|
||||
#
|
||||
# Declares modules to be included in multiple example groups
|
||||
# (<tt>describe</tt> blocks). With no :type, the modules listed will be
|
||||
# included in all example groups. Use :type to restrict the inclusion to
|
||||
# a subset of example groups. The value assigned to :type should be a
|
||||
# key that maps to a class that is either a subclass of
|
||||
# Spec::Example::ExampleGroup or extends Spec::Example::ExampleGroupMethods
|
||||
# and includes Spec::Example::ExampleMethods
|
||||
#
|
||||
# config.include(My::Pony, My::Horse, :type => :farm)
|
||||
#
|
||||
# Only example groups that have that type will get the modules included:
|
||||
#
|
||||
# describe "Downtown", :type => :city do
|
||||
# # Will *not* get My::Pony and My::Horse included
|
||||
# end
|
||||
#
|
||||
# describe "Old Mac Donald", :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_example_group = get_type_from_options(options)
|
||||
required_example_group = required_example_group.to_sym if required_example_group
|
||||
modules.each do |mod|
|
||||
ExampleGroupFactory.get(required_example_group).send(:include, mod)
|
||||
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.can_swim? returns true
|
||||
#
|
||||
def predicate_matchers
|
||||
@predicate_matchers ||= {}
|
||||
end
|
||||
|
||||
# Prepends a global <tt>before</tt> block to all example groups.
|
||||
# See #append_before for filtering semantics.
|
||||
def prepend_before(*args, &proc)
|
||||
scope, options = scope_and_options(*args)
|
||||
example_group = ExampleGroupFactory.get(
|
||||
get_type_from_options(options)
|
||||
)
|
||||
example_group.prepend_before(scope, &proc)
|
||||
end
|
||||
|
||||
# Appends a global <tt>before</tt> block to all example groups.
|
||||
#
|
||||
# If you want to restrict the block to a subset of all the example
|
||||
# groups then specify this in a Hash as the last argument:
|
||||
#
|
||||
# config.prepend_before(:all, :type => :farm)
|
||||
#
|
||||
# or
|
||||
#
|
||||
# config.prepend_before(:type => :farm)
|
||||
#
|
||||
def append_before(*args, &proc)
|
||||
scope, options = scope_and_options(*args)
|
||||
example_group = ExampleGroupFactory.get(
|
||||
get_type_from_options(options)
|
||||
)
|
||||
example_group.append_before(scope, &proc)
|
||||
end
|
||||
alias_method :before, :append_before
|
||||
|
||||
# Prepends a global <tt>after</tt> block to all example groups.
|
||||
# See #append_before for filtering semantics.
|
||||
def prepend_after(*args, &proc)
|
||||
scope, options = scope_and_options(*args)
|
||||
example_group = ExampleGroupFactory.get(
|
||||
get_type_from_options(options)
|
||||
)
|
||||
example_group.prepend_after(scope, &proc)
|
||||
end
|
||||
alias_method :after, :prepend_after
|
||||
|
||||
# Appends a global <tt>after</tt> block to all example groups.
|
||||
# See #append_before for filtering semantics.
|
||||
def append_after(*args, &proc)
|
||||
scope, options = scope_and_options(*args)
|
||||
example_group = ExampleGroupFactory.get(
|
||||
get_type_from_options(options)
|
||||
)
|
||||
example_group.append_after(scope, &proc)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def scope_and_options(*args)
|
||||
args, options = args_and_options(*args)
|
||||
scope = (args[0] || :each), options
|
||||
end
|
||||
|
||||
def get_type_from_options(options)
|
||||
options[:type] || options[:behaviour_type]
|
||||
end
|
||||
|
||||
def mock_framework_path(framework_name)
|
||||
File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "plugins", "mock_frameworks", framework_name))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
9
vendor/plugins/rspec/lib/spec/example/errors.rb
vendored
Normal file
9
vendor/plugins/rspec/lib/spec/example/errors.rb
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
module Spec
|
||||
module Example
|
||||
class ExamplePendingError < StandardError
|
||||
end
|
||||
|
||||
class PendingExampleFixedError < StandardError
|
||||
end
|
||||
end
|
||||
end
|
||||
17
vendor/plugins/rspec/lib/spec/example/example_group.rb
vendored
Normal file
17
vendor/plugins/rspec/lib/spec/example/example_group.rb
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
module Spec
|
||||
module Example
|
||||
# Base class for customized example groups. Use this if you
|
||||
# want to make a custom example group.
|
||||
class ExampleGroup
|
||||
extend Spec::Example::ExampleGroupMethods
|
||||
include Spec::Example::ExampleMethods
|
||||
|
||||
def initialize(defined_description, &implementation)
|
||||
@_defined_description = defined_description
|
||||
@_implementation = implementation
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Spec::ExampleGroup = Spec::Example::ExampleGroup
|
||||
64
vendor/plugins/rspec/lib/spec/example/example_group_factory.rb
vendored
Executable file
64
vendor/plugins/rspec/lib/spec/example/example_group_factory.rb
vendored
Executable file
|
|
@ -0,0 +1,64 @@
|
|||
module Spec
|
||||
module Example
|
||||
class ExampleGroupFactory
|
||||
class << self
|
||||
def reset
|
||||
@example_group_types = nil
|
||||
default(ExampleGroup)
|
||||
end
|
||||
|
||||
# Registers an example group class +klass+ with the symbol +type+. For
|
||||
# example:
|
||||
#
|
||||
# Spec::Example::ExampleGroupFactory.register(:farm, FarmExampleGroup)
|
||||
#
|
||||
# With that you can append a hash with :type => :farm to the describe
|
||||
# method and it will load an instance of FarmExampleGroup.
|
||||
#
|
||||
# describe Pig, :type => :farm do
|
||||
# ...
|
||||
#
|
||||
# If you don't use the hash explicitly, <tt>describe</tt> will
|
||||
# implicitly use an instance of FarmExampleGroup for any file loaded
|
||||
# from the <tt>./spec/farm</tt> directory.
|
||||
def register(key, example_group_class)
|
||||
@example_group_types[key] = example_group_class
|
||||
end
|
||||
|
||||
# Sets the default ExampleGroup class
|
||||
def default(example_group_class)
|
||||
old = @example_group_types
|
||||
@example_group_types = Hash.new(example_group_class)
|
||||
@example_group_types.merge!(old) if old
|
||||
end
|
||||
|
||||
def get(key=nil)
|
||||
if @example_group_types.values.include?(key)
|
||||
key
|
||||
else
|
||||
@example_group_types[key]
|
||||
end
|
||||
end
|
||||
|
||||
def create_example_group(*args, &block)
|
||||
opts = Hash === args.last ? args.last : {}
|
||||
superclass = determine_superclass(opts)
|
||||
superclass.describe(*args, &block)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def determine_superclass(opts)
|
||||
key = if opts[:type]
|
||||
opts[:type]
|
||||
elsif opts[:spec_path] =~ /spec(\\|\/)(#{@example_group_types.keys.join('|')})/
|
||||
$2 == '' ? nil : $2.to_sym
|
||||
end
|
||||
get(key)
|
||||
end
|
||||
|
||||
end
|
||||
self.reset
|
||||
end
|
||||
end
|
||||
end
|
||||
440
vendor/plugins/rspec/lib/spec/example/example_group_methods.rb
vendored
Normal file
440
vendor/plugins/rspec/lib/spec/example/example_group_methods.rb
vendored
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
module Spec
|
||||
module Example
|
||||
|
||||
module ExampleGroupMethods
|
||||
class << self
|
||||
attr_accessor :matcher_class
|
||||
|
||||
def description_text(*args)
|
||||
args.inject("") do |result, arg|
|
||||
result << " " unless (result == "" || arg.to_s =~ /^(\s|\.|#)/)
|
||||
result << arg.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :description_text, :description_args, :description_options, :spec_path, :registration_binding_block
|
||||
|
||||
def inherited(klass)
|
||||
super
|
||||
klass.register {}
|
||||
Spec::Runner.register_at_exit_hook
|
||||
end
|
||||
|
||||
# Makes the describe/it syntax available from a class. For example:
|
||||
#
|
||||
# class StackSpec < Spec::ExampleGroup
|
||||
# describe Stack, "with no elements"
|
||||
#
|
||||
# before
|
||||
# @stack = Stack.new
|
||||
# end
|
||||
#
|
||||
# it "should raise on pop" do
|
||||
# lambda{ @stack.pop }.should raise_error
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def describe(*args, &example_group_block)
|
||||
args << {} unless Hash === args.last
|
||||
if example_group_block
|
||||
params = args.last
|
||||
params[:spec_path] = eval("caller(0)[1]", example_group_block) unless params[:spec_path]
|
||||
if params[:shared]
|
||||
SharedExampleGroup.new(*args, &example_group_block)
|
||||
else
|
||||
self.subclass("Subclass") do
|
||||
describe(*args)
|
||||
module_eval(&example_group_block)
|
||||
end
|
||||
end
|
||||
else
|
||||
set_description(*args)
|
||||
before_eval
|
||||
self
|
||||
end
|
||||
end
|
||||
alias :context :describe
|
||||
|
||||
# Use this to pull in examples from shared example groups.
|
||||
# See Spec::Runner for information about shared example groups.
|
||||
def it_should_behave_like(shared_example_group)
|
||||
case shared_example_group
|
||||
when SharedExampleGroup
|
||||
include shared_example_group
|
||||
else
|
||||
example_group = SharedExampleGroup.find_shared_example_group(shared_example_group)
|
||||
unless example_group
|
||||
raise RuntimeError.new("Shared Example Group '#{shared_example_group}' can not be found")
|
||||
end
|
||||
include(example_group)
|
||||
end
|
||||
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 ||= {:an_instance_of => :is_a?}
|
||||
end
|
||||
|
||||
# Creates an instance of Spec::Example::Example and adds
|
||||
# it to a collection of examples of the current example group.
|
||||
def it(description=nil, &implementation)
|
||||
e = new(description, &implementation)
|
||||
example_objects << e
|
||||
e
|
||||
end
|
||||
|
||||
alias_method :specify, :it
|
||||
|
||||
# Use this to temporarily disable an example.
|
||||
def xit(description=nil, opts={}, &block)
|
||||
Kernel.warn("Example disabled: #{description}")
|
||||
end
|
||||
alias_method :xspecify, :xit
|
||||
|
||||
def run
|
||||
examples = examples_to_run
|
||||
reporter.add_example_group(self) unless examples_to_run.empty?
|
||||
return true if examples.empty?
|
||||
return dry_run(examples) if dry_run?
|
||||
|
||||
plugin_mock_framework
|
||||
define_methods_from_predicate_matchers
|
||||
|
||||
success, before_all_instance_variables = run_before_all
|
||||
success, after_all_instance_variables = execute_examples(success, before_all_instance_variables, examples)
|
||||
success = run_after_all(success, after_all_instance_variables)
|
||||
end
|
||||
|
||||
def description
|
||||
result = ExampleGroupMethods.description_text(*description_parts)
|
||||
if result.nil? || result == ""
|
||||
return to_s
|
||||
else
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
def described_type
|
||||
description_parts.find {|part| part.is_a?(Module)}
|
||||
end
|
||||
|
||||
def description_parts #:nodoc:
|
||||
parts = []
|
||||
execute_in_class_hierarchy do |example_group|
|
||||
parts << example_group.description_args
|
||||
end
|
||||
parts.flatten.compact
|
||||
end
|
||||
|
||||
def set_description(*args)
|
||||
args, options = args_and_options(*args)
|
||||
@description_args = args
|
||||
@description_options = options
|
||||
@description_text = ExampleGroupMethods.description_text(*args)
|
||||
@spec_path = File.expand_path(options[:spec_path]) if options[:spec_path]
|
||||
if described_type.class == Module
|
||||
@described_module = described_type
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
attr_reader :described_module
|
||||
|
||||
def examples #:nodoc:
|
||||
examples = example_objects.dup
|
||||
add_method_examples(examples)
|
||||
rspec_options.reverse ? examples.reverse : examples
|
||||
end
|
||||
|
||||
def number_of_examples #:nodoc:
|
||||
examples.length
|
||||
end
|
||||
|
||||
# Registers a block to be executed before each example.
|
||||
# This method prepends +block+ to existing before blocks.
|
||||
def prepend_before(*args, &block)
|
||||
scope, options = scope_and_options(*args)
|
||||
parts = before_parts_from_scope(scope)
|
||||
parts.unshift(block)
|
||||
end
|
||||
|
||||
# Registers a block to be executed before each example.
|
||||
# This method appends +block+ to existing before blocks.
|
||||
def append_before(*args, &block)
|
||||
scope, options = scope_and_options(*args)
|
||||
parts = before_parts_from_scope(scope)
|
||||
parts << block
|
||||
end
|
||||
alias_method :before, :append_before
|
||||
|
||||
# Registers a block to be executed after each example.
|
||||
# This method prepends +block+ to existing after blocks.
|
||||
def prepend_after(*args, &block)
|
||||
scope, options = scope_and_options(*args)
|
||||
parts = after_parts_from_scope(scope)
|
||||
parts.unshift(block)
|
||||
end
|
||||
alias_method :after, :prepend_after
|
||||
|
||||
# Registers a block to be executed after each example.
|
||||
# This method appends +block+ to existing after blocks.
|
||||
def append_after(*args, &block)
|
||||
scope, options = scope_and_options(*args)
|
||||
parts = after_parts_from_scope(scope)
|
||||
parts << block
|
||||
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 # :nodoc:
|
||||
@before_all_parts ||= []
|
||||
end
|
||||
|
||||
def after_all_parts # :nodoc:
|
||||
@after_all_parts ||= []
|
||||
end
|
||||
|
||||
def before_each_parts # :nodoc:
|
||||
@before_each_parts ||= []
|
||||
end
|
||||
|
||||
def after_each_parts # :nodoc:
|
||||
@after_each_parts ||= []
|
||||
end
|
||||
|
||||
# Only used from RSpec's own examples
|
||||
def reset # :nodoc:
|
||||
@before_all_parts = nil
|
||||
@after_all_parts = nil
|
||||
@before_each_parts = nil
|
||||
@after_each_parts = nil
|
||||
end
|
||||
|
||||
def register(®istration_binding_block)
|
||||
@registration_binding_block = registration_binding_block
|
||||
rspec_options.add_example_group self
|
||||
end
|
||||
|
||||
def unregister #:nodoc:
|
||||
rspec_options.remove_example_group self
|
||||
end
|
||||
|
||||
def registration_backtrace
|
||||
eval("caller", registration_binding_block)
|
||||
end
|
||||
|
||||
def run_before_each(example)
|
||||
execute_in_class_hierarchy do |example_group|
|
||||
example.eval_each_fail_fast(example_group.before_each_parts)
|
||||
end
|
||||
end
|
||||
|
||||
def run_after_each(example)
|
||||
execute_in_class_hierarchy(:superclass_first) do |example_group|
|
||||
example.eval_each_fail_slow(example_group.after_each_parts)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def dry_run(examples)
|
||||
examples.each do |example|
|
||||
rspec_options.reporter.example_started(example)
|
||||
rspec_options.reporter.example_finished(example)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def run_before_all
|
||||
before_all = new("before(:all)")
|
||||
begin
|
||||
execute_in_class_hierarchy do |example_group|
|
||||
before_all.eval_each_fail_fast(example_group.before_all_parts)
|
||||
end
|
||||
return [true, before_all.instance_variable_hash]
|
||||
rescue Exception => e
|
||||
reporter.failure(before_all, e)
|
||||
return [false, before_all.instance_variable_hash]
|
||||
end
|
||||
end
|
||||
|
||||
def execute_examples(success, instance_variables, examples)
|
||||
return [success, instance_variables] unless success
|
||||
|
||||
after_all_instance_variables = instance_variables
|
||||
examples.each do |example_group_instance|
|
||||
success &= example_group_instance.execute(rspec_options, instance_variables)
|
||||
after_all_instance_variables = example_group_instance.instance_variable_hash
|
||||
end
|
||||
return [success, after_all_instance_variables]
|
||||
end
|
||||
|
||||
def run_after_all(success, instance_variables)
|
||||
after_all = new("after(:all)")
|
||||
after_all.set_instance_variables_from_hash(instance_variables)
|
||||
execute_in_class_hierarchy(:superclass_first) do |example_group|
|
||||
after_all.eval_each_fail_slow(example_group.after_all_parts)
|
||||
end
|
||||
return success
|
||||
rescue Exception => e
|
||||
reporter.failure(after_all, e)
|
||||
return false
|
||||
end
|
||||
|
||||
def examples_to_run
|
||||
all_examples = examples
|
||||
return all_examples unless specified_examples?
|
||||
all_examples.reject do |example|
|
||||
matcher = ExampleGroupMethods.matcher_class.
|
||||
new(description.to_s, example.description)
|
||||
!matcher.matches?(specified_examples)
|
||||
end
|
||||
end
|
||||
|
||||
def specified_examples?
|
||||
specified_examples && !specified_examples.empty?
|
||||
end
|
||||
|
||||
def specified_examples
|
||||
rspec_options.examples
|
||||
end
|
||||
|
||||
def reporter
|
||||
rspec_options.reporter
|
||||
end
|
||||
|
||||
def dry_run?
|
||||
rspec_options.dry_run
|
||||
end
|
||||
|
||||
def example_objects
|
||||
@example_objects ||= []
|
||||
end
|
||||
|
||||
def execute_in_class_hierarchy(superclass_last=false)
|
||||
classes = []
|
||||
current_class = self
|
||||
while is_example_group?(current_class)
|
||||
superclass_last ? classes << current_class : classes.unshift(current_class)
|
||||
current_class = current_class.superclass
|
||||
end
|
||||
superclass_last ? classes << ExampleMethods : classes.unshift(ExampleMethods)
|
||||
|
||||
classes.each do |example_group|
|
||||
yield example_group
|
||||
end
|
||||
end
|
||||
|
||||
def is_example_group?(klass)
|
||||
Module === klass && klass.kind_of?(ExampleGroupMethods)
|
||||
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 define_methods_from_predicate_matchers # :nodoc:
|
||||
all_predicate_matchers = predicate_matchers.merge(
|
||||
Spec::Runner.configuration.predicate_matchers
|
||||
)
|
||||
all_predicate_matchers.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
|
||||
|
||||
def scope_and_options(*args)
|
||||
args, options = args_and_options(*args)
|
||||
scope = (args[0] || :each), options
|
||||
end
|
||||
|
||||
def before_parts_from_scope(scope)
|
||||
case scope
|
||||
when :each; before_each_parts
|
||||
when :all; before_all_parts
|
||||
when :suite; rspec_options.before_suite_parts
|
||||
end
|
||||
end
|
||||
|
||||
def after_parts_from_scope(scope)
|
||||
case scope
|
||||
when :each; after_each_parts
|
||||
when :all; after_all_parts
|
||||
when :suite; rspec_options.after_suite_parts
|
||||
end
|
||||
end
|
||||
|
||||
def before_eval
|
||||
end
|
||||
|
||||
def add_method_examples(examples)
|
||||
instance_methods.sort.each do |method_name|
|
||||
if example_method?(method_name)
|
||||
examples << new(method_name) do
|
||||
__send__(method_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def example_method?(method_name)
|
||||
should_method?(method_name)
|
||||
end
|
||||
|
||||
def should_method?(method_name)
|
||||
!(method_name =~ /^should(_not)?$/) &&
|
||||
method_name =~ /^should/ && (
|
||||
instance_method(method_name).arity == 0 ||
|
||||
instance_method(method_name).arity == -1
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
44
vendor/plugins/rspec/lib/spec/example/example_matcher.rb
vendored
Executable file
44
vendor/plugins/rspec/lib/spec/example/example_matcher.rb
vendored
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
module Spec
|
||||
module Example
|
||||
class ExampleMatcher
|
||||
def initialize(example_group_description, example_name)
|
||||
@example_group_description = example_group_description
|
||||
@example_name = example_name
|
||||
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
|
||||
|
||||
protected
|
||||
def matches_literal_example?(specified_example)
|
||||
specified_example =~ /(^#{example_group_regex} #{example_regexp}$|^#{example_group_regex}$|^#{example_group_with_before_all_regexp}$|^#{example_regexp}$)/
|
||||
end
|
||||
|
||||
def matches_example_not_considering_modules?(specified_example)
|
||||
specified_example =~ /(^#{example_group_regex_not_considering_modules} #{example_regexp}$|^#{example_group_regex_not_considering_modules}$|^#{example_regexp}$)/
|
||||
end
|
||||
|
||||
def example_group_regex
|
||||
Regexp.escape(@example_group_description)
|
||||
end
|
||||
|
||||
def example_group_with_before_all_regexp
|
||||
Regexp.escape("#{@example_group_description} before(:all)")
|
||||
end
|
||||
|
||||
def example_group_regex_not_considering_modules
|
||||
Regexp.escape(@example_group_description.split('::').last)
|
||||
end
|
||||
|
||||
def example_regexp
|
||||
Regexp.escape(@example_name)
|
||||
end
|
||||
end
|
||||
|
||||
ExampleGroupMethods.matcher_class = ExampleMatcher
|
||||
end
|
||||
end
|
||||
112
vendor/plugins/rspec/lib/spec/example/example_methods.rb
vendored
Normal file
112
vendor/plugins/rspec/lib/spec/example/example_methods.rb
vendored
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
module Spec
|
||||
module Example
|
||||
module ExampleMethods
|
||||
extend ExampleGroupMethods
|
||||
extend ModuleReopeningFix
|
||||
include ModuleInclusionWarnings
|
||||
|
||||
|
||||
PENDING_EXAMPLE_BLOCK = lambda {
|
||||
raise Spec::Example::ExamplePendingError.new("Not Yet Implemented")
|
||||
}
|
||||
|
||||
def execute(options, instance_variables)
|
||||
options.reporter.example_started(self)
|
||||
set_instance_variables_from_hash(instance_variables)
|
||||
|
||||
execution_error = nil
|
||||
Timeout.timeout(options.timeout) do
|
||||
begin
|
||||
before_example
|
||||
run_with_description_capturing
|
||||
rescue Exception => e
|
||||
execution_error ||= e
|
||||
end
|
||||
begin
|
||||
after_example
|
||||
rescue Exception => e
|
||||
execution_error ||= e
|
||||
end
|
||||
end
|
||||
|
||||
options.reporter.example_finished(self, execution_error)
|
||||
success = execution_error.nil? || ExamplePendingError === execution_error
|
||||
end
|
||||
|
||||
def instance_variable_hash
|
||||
instance_variables.inject({}) do |variable_hash, variable_name|
|
||||
variable_hash[variable_name] = instance_variable_get(variable_name)
|
||||
variable_hash
|
||||
end
|
||||
end
|
||||
|
||||
def violated(message="")
|
||||
raise Spec::Expectations::ExpectationNotMetError.new(message)
|
||||
end
|
||||
|
||||
def eval_each_fail_fast(procs) #:nodoc:
|
||||
procs.each do |proc|
|
||||
instance_eval(&proc)
|
||||
end
|
||||
end
|
||||
|
||||
def eval_each_fail_slow(procs) #:nodoc:
|
||||
first_exception = nil
|
||||
procs.each do |proc|
|
||||
begin
|
||||
instance_eval(&proc)
|
||||
rescue Exception => e
|
||||
first_exception ||= e
|
||||
end
|
||||
end
|
||||
raise first_exception if first_exception
|
||||
end
|
||||
|
||||
def description
|
||||
@_defined_description || @_matcher_description || "NO NAME"
|
||||
end
|
||||
|
||||
def __full_description
|
||||
"#{self.class.description} #{self.description}"
|
||||
end
|
||||
|
||||
def set_instance_variables_from_hash(ivars)
|
||||
ivars.each do |variable_name, value|
|
||||
# Ruby 1.9 requires variable.to_s on the next line
|
||||
unless ['@_implementation', '@_defined_description', '@_matcher_description', '@method_name'].include?(variable_name.to_s)
|
||||
instance_variable_set variable_name, value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run_with_description_capturing
|
||||
begin
|
||||
return instance_eval(&(@_implementation || PENDING_EXAMPLE_BLOCK))
|
||||
ensure
|
||||
@_matcher_description = Spec::Matchers.generated_description
|
||||
Spec::Matchers.clear_generated_description
|
||||
end
|
||||
end
|
||||
|
||||
def implementation_backtrace
|
||||
eval("caller", @_implementation)
|
||||
end
|
||||
|
||||
protected
|
||||
include Matchers
|
||||
include Pending
|
||||
|
||||
def before_example
|
||||
setup_mocks_for_rspec
|
||||
self.class.run_before_each(self)
|
||||
end
|
||||
|
||||
def after_example
|
||||
self.class.run_after_each(self)
|
||||
verify_mocks_for_rspec
|
||||
ensure
|
||||
teardown_mocks_for_rspec
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
37
vendor/plugins/rspec/lib/spec/example/module_inclusion_warnings.rb
vendored
Normal file
37
vendor/plugins/rspec/lib/spec/example/module_inclusion_warnings.rb
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
module Spec
|
||||
module Example
|
||||
# In the future, modules will no longer be automatically included
|
||||
# in the Example Group (based on the description name); when that
|
||||
# time comes, this code should be removed.
|
||||
module ModuleInclusionWarnings
|
||||
# Thanks, Francis Hwang.
|
||||
class MethodDispatcher
|
||||
def initialize(mod, target=nil)
|
||||
@mod = mod
|
||||
@target = target
|
||||
end
|
||||
|
||||
def respond_to?(sym)
|
||||
@mod && @mod.instance_methods.include?(sym.to_s)
|
||||
end
|
||||
|
||||
def call(sym, *args, &blk)
|
||||
Kernel.warn("Modules will no longer be automatically included in RSpec version 1.1.4. Called from #{caller[2]}")
|
||||
@target.extend @mod
|
||||
@target.send(sym, *args, &blk)
|
||||
end
|
||||
end
|
||||
|
||||
def respond_to?(sym)
|
||||
MethodDispatcher.new(self.class.described_module).respond_to?(sym) ? true : super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def method_missing(sym, *args, &blk)
|
||||
md = MethodDispatcher.new(self.class.described_module, self)
|
||||
self.respond_to?(sym) ? md.call(sym, *args, &blk) : super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
21
vendor/plugins/rspec/lib/spec/example/module_reopening_fix.rb
vendored
Normal file
21
vendor/plugins/rspec/lib/spec/example/module_reopening_fix.rb
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
module Spec
|
||||
module Example
|
||||
# This is a fix for ...Something in Ruby 1.8.6??... (Someone fill in here please - Aslak)
|
||||
module ModuleReopeningFix
|
||||
def child_modules
|
||||
@child_modules ||= []
|
||||
end
|
||||
|
||||
def included(mod)
|
||||
child_modules << mod
|
||||
end
|
||||
|
||||
def include(mod)
|
||||
super
|
||||
child_modules.each do |child_module|
|
||||
child_module.__send__(:include, mod)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
18
vendor/plugins/rspec/lib/spec/example/pending.rb
vendored
Normal file
18
vendor/plugins/rspec/lib/spec/example/pending.rb
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
module Spec
|
||||
module Example
|
||||
module Pending
|
||||
def pending(message = "TODO")
|
||||
if block_given?
|
||||
begin
|
||||
yield
|
||||
rescue Exception => e
|
||||
raise Spec::Example::ExamplePendingError.new(message)
|
||||
end
|
||||
raise Spec::Example::PendingExampleFixedError.new("Expected pending '#{message}' to fail. No Error was raised.")
|
||||
else
|
||||
raise Spec::Example::ExamplePendingError.new(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
58
vendor/plugins/rspec/lib/spec/example/shared_example_group.rb
vendored
Normal file
58
vendor/plugins/rspec/lib/spec/example/shared_example_group.rb
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
module Spec
|
||||
module Example
|
||||
class SharedExampleGroup < Module
|
||||
class << self
|
||||
def add_shared_example_group(new_example_group)
|
||||
guard_against_redefining_existing_example_group(new_example_group)
|
||||
shared_example_groups << new_example_group
|
||||
end
|
||||
|
||||
def find_shared_example_group(example_group_description)
|
||||
shared_example_groups.find do |b|
|
||||
b.description == example_group_description
|
||||
end
|
||||
end
|
||||
|
||||
def shared_example_groups
|
||||
# TODO - this needs to be global, or at least accessible from
|
||||
# from subclasses of Example in a centralized place. I'm not loving
|
||||
# this as a solution, but it works for now.
|
||||
$shared_example_groups ||= []
|
||||
end
|
||||
|
||||
private
|
||||
def guard_against_redefining_existing_example_group(new_example_group)
|
||||
existing_example_group = find_shared_example_group(new_example_group.description)
|
||||
return unless existing_example_group
|
||||
return if new_example_group.equal?(existing_example_group)
|
||||
return if spec_path(new_example_group) == spec_path(existing_example_group)
|
||||
raise ArgumentError.new("Shared Example '#{existing_example_group.description}' already exists")
|
||||
end
|
||||
|
||||
def spec_path(example_group)
|
||||
File.expand_path(example_group.spec_path)
|
||||
end
|
||||
end
|
||||
include ExampleGroupMethods
|
||||
public :include
|
||||
|
||||
def initialize(*args, &example_group_block)
|
||||
describe(*args)
|
||||
@example_group_block = example_group_block
|
||||
self.class.add_shared_example_group(self)
|
||||
end
|
||||
|
||||
def included(mod) # :nodoc:
|
||||
mod.module_eval(&@example_group_block)
|
||||
end
|
||||
|
||||
def execute_in_class_hierarchy(superclass_last=false)
|
||||
classes = [self]
|
||||
superclass_last ? classes << ExampleMethods : classes.unshift(ExampleMethods)
|
||||
classes.each do |example_group|
|
||||
yield example_group
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
56
vendor/plugins/rspec/lib/spec/expectations.rb
vendored
Normal file
56
vendor/plugins/rspec/lib/spec/expectations.rb
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
require 'spec/matchers'
|
||||
require 'spec/expectations/errors'
|
||||
require 'spec/expectations/extensions'
|
||||
require 'spec/expectations/handler'
|
||||
|
||||
module Spec
|
||||
|
||||
# Spec::Expectations lets you set expectations on your objects.
|
||||
#
|
||||
# result.should == 37
|
||||
# team.should have(11).players_on_the_field
|
||||
#
|
||||
# == How Expectations work.
|
||||
#
|
||||
# Spec::Expectations adds two methods to Object:
|
||||
#
|
||||
# should(matcher=nil)
|
||||
# should_not(matcher=nil)
|
||||
#
|
||||
# Both methods take an optional Expression Matcher (See Spec::Matchers).
|
||||
#
|
||||
# When +should+ receives an Expression Matcher, it calls <tt>matches?(self)</tt>. If
|
||||
# it returns +true+, the spec passes and execution continues. If it returns
|
||||
# +false+, then the spec fails with the message returned by <tt>matcher.failure_message</tt>.
|
||||
#
|
||||
# Similarly, when +should_not+ receives a matcher, it calls <tt>matches?(self)</tt>. If
|
||||
# it returns +false+, the spec passes and execution continues. If it returns
|
||||
# +true+, then the spec fails with the message returned by <tt>matcher.negative_failure_message</tt>.
|
||||
#
|
||||
# RSpec ships with a standard set of useful matchers, and writing your own
|
||||
# matchers is quite simple. See Spec::Matchers for details.
|
||||
module Expectations
|
||||
class << self
|
||||
attr_accessor :differ
|
||||
|
||||
# raises a Spec::Expectations::ExpectationNotMetError with message
|
||||
#
|
||||
# When a differ has been assigned and fail_with is passed
|
||||
# <code>expected</code> and <code>target</code>, passes them
|
||||
# to the differ to append a diff message to the failure message.
|
||||
def fail_with(message, expected=nil, target=nil) # :nodoc:
|
||||
if Array === message && message.length == 3
|
||||
message, expected, target = message[0], message[1], message[2]
|
||||
end
|
||||
unless (differ.nil? || expected.nil? || target.nil?)
|
||||
if expected.is_a?(String)
|
||||
message << "\nDiff:" << self.differ.diff_as_string(target.to_s, expected)
|
||||
elsif !target.is_a?(Proc)
|
||||
message << "\nDiff:" << self.differ.diff_as_object(target, expected)
|
||||
end
|
||||
end
|
||||
Kernel::raise(Spec::Expectations::ExpectationNotMetError.new(message))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
66
vendor/plugins/rspec/lib/spec/expectations/differs/default.rb
vendored
Normal file
66
vendor/plugins/rspec/lib/spec/expectations/differs/default.rb
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
begin
|
||||
require 'rubygems'
|
||||
require 'diff/lcs' #necessary due to loading bug on some machines - not sure why - DaC
|
||||
require 'diff/lcs/hunk'
|
||||
rescue LoadError ; raise "You must gem install diff-lcs to use diffing" ; end
|
||||
|
||||
require 'pp'
|
||||
|
||||
module Spec
|
||||
module Expectations
|
||||
module Differs
|
||||
|
||||
# TODO add some rdoc
|
||||
class Default
|
||||
def initialize(options)
|
||||
@options = options
|
||||
end
|
||||
|
||||
# This is snagged from diff/lcs/ldiff.rb (which is a commandline tool)
|
||||
def diff_as_string(data_new, data_old)
|
||||
data_old = data_old.split(/\n/).map! { |e| e.chomp }
|
||||
data_new = data_new.split(/\n/).map! { |e| e.chomp }
|
||||
output = ""
|
||||
diffs = Diff::LCS.diff(data_old, data_new)
|
||||
return output if diffs.empty?
|
||||
oldhunk = hunk = nil
|
||||
file_length_difference = 0
|
||||
diffs.each do |piece|
|
||||
begin
|
||||
hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, context_lines,
|
||||
file_length_difference)
|
||||
file_length_difference = hunk.file_length_difference
|
||||
next unless oldhunk
|
||||
# Hunks may overlap, which is why we need to be careful when our
|
||||
# diff includes lines of context. Otherwise, we might print
|
||||
# redundant lines.
|
||||
if (context_lines > 0) and hunk.overlaps?(oldhunk)
|
||||
hunk.unshift(oldhunk)
|
||||
else
|
||||
output << oldhunk.diff(format)
|
||||
end
|
||||
ensure
|
||||
oldhunk = hunk
|
||||
output << "\n"
|
||||
end
|
||||
end
|
||||
#Handle the last remaining hunk
|
||||
output << oldhunk.diff(format) << "\n"
|
||||
end
|
||||
|
||||
def diff_as_object(target,expected)
|
||||
diff_as_string(PP.pp(target,""), PP.pp(expected,""))
|
||||
end
|
||||
|
||||
protected
|
||||
def format
|
||||
@options.diff_format
|
||||
end
|
||||
|
||||
def context_lines
|
||||
@options.context_lines
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
12
vendor/plugins/rspec/lib/spec/expectations/errors.rb
vendored
Normal file
12
vendor/plugins/rspec/lib/spec/expectations/errors.rb
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
module Spec
|
||||
module Expectations
|
||||
# If Test::Unit is loaed, we'll use its error as baseclass, so that Test::Unit
|
||||
# will report unmet RSpec expectations as failures rather than errors.
|
||||
superclass = ['Test::Unit::AssertionFailedError', '::StandardError'].map do |c|
|
||||
eval(c) rescue nil
|
||||
end.compact.first
|
||||
|
||||
class ExpectationNotMetError < superclass
|
||||
end
|
||||
end
|
||||
end
|
||||
2
vendor/plugins/rspec/lib/spec/expectations/extensions.rb
vendored
Normal file
2
vendor/plugins/rspec/lib/spec/expectations/extensions.rb
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
require 'spec/expectations/extensions/object'
|
||||
require 'spec/expectations/extensions/string_and_symbol'
|
||||
63
vendor/plugins/rspec/lib/spec/expectations/extensions/object.rb
vendored
Normal file
63
vendor/plugins/rspec/lib/spec/expectations/extensions/object.rb
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
module Spec
|
||||
module Expectations
|
||||
# rspec adds #should and #should_not to every Object (and,
|
||||
# implicitly, every Class).
|
||||
module ObjectExpectations
|
||||
# :call-seq:
|
||||
# should(matcher)
|
||||
# should == expected
|
||||
# should === expected
|
||||
# should =~ expected
|
||||
#
|
||||
# receiver.should(matcher)
|
||||
# => Passes if matcher.matches?(receiver)
|
||||
#
|
||||
# receiver.should == expected #any value
|
||||
# => Passes if (receiver == expected)
|
||||
#
|
||||
# receiver.should === expected #any value
|
||||
# => Passes if (receiver === expected)
|
||||
#
|
||||
# receiver.should =~ regexp
|
||||
# => Passes if (receiver =~ regexp)
|
||||
#
|
||||
# See Spec::Matchers for more information about matchers
|
||||
#
|
||||
# == Warning
|
||||
#
|
||||
# NOTE that this does NOT support receiver.should != expected.
|
||||
# Instead, use receiver.should_not == expected
|
||||
def should(matcher=:use_operator_matcher, &block)
|
||||
ExpectationMatcherHandler.handle_matcher(self, matcher, &block)
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should_not(matcher)
|
||||
# should_not == expected
|
||||
# should_not === expected
|
||||
# should_not =~ expected
|
||||
#
|
||||
# receiver.should_not(matcher)
|
||||
# => Passes unless matcher.matches?(receiver)
|
||||
#
|
||||
# receiver.should_not == expected
|
||||
# => Passes unless (receiver == expected)
|
||||
#
|
||||
# receiver.should_not === expected
|
||||
# => Passes unless (receiver === expected)
|
||||
#
|
||||
# receiver.should_not =~ regexp
|
||||
# => Passes unless (receiver =~ regexp)
|
||||
#
|
||||
# See Spec::Matchers for more information about matchers
|
||||
def should_not(matcher=:use_operator_matcher, &block)
|
||||
NegativeExpectationMatcherHandler.handle_matcher(self, matcher, &block)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Object
|
||||
include Spec::Expectations::ObjectExpectations
|
||||
end
|
||||
17
vendor/plugins/rspec/lib/spec/expectations/extensions/string_and_symbol.rb
vendored
Normal file
17
vendor/plugins/rspec/lib/spec/expectations/extensions/string_and_symbol.rb
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
module Spec
|
||||
module Expectations
|
||||
module StringHelpers
|
||||
def starts_with?(prefix)
|
||||
to_s[0..(prefix.to_s.length - 1)] == prefix.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class String
|
||||
include Spec::Expectations::StringHelpers
|
||||
end
|
||||
|
||||
class Symbol
|
||||
include Spec::Expectations::StringHelpers
|
||||
end
|
||||
60
vendor/plugins/rspec/lib/spec/expectations/handler.rb
vendored
Normal file
60
vendor/plugins/rspec/lib/spec/expectations/handler.rb
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
module Spec
|
||||
module Expectations
|
||||
class InvalidMatcherError < ArgumentError; end
|
||||
|
||||
module MatcherHandlerHelper
|
||||
def describe_matcher(matcher)
|
||||
matcher.respond_to?(:description) ? matcher.description : "[#{matcher.class.name} does not provide a description]"
|
||||
end
|
||||
end
|
||||
|
||||
class ExpectationMatcherHandler
|
||||
class << self
|
||||
include MatcherHandlerHelper
|
||||
def handle_matcher(actual, matcher, &block)
|
||||
if :use_operator_matcher == matcher
|
||||
return Spec::Matchers::PositiveOperatorMatcher.new(actual)
|
||||
end
|
||||
|
||||
unless matcher.respond_to?(:matches?)
|
||||
raise InvalidMatcherError, "Expected a matcher, got #{matcher.inspect}."
|
||||
end
|
||||
|
||||
match = matcher.matches?(actual, &block)
|
||||
::Spec::Matchers.generated_description = "should #{describe_matcher(matcher)}"
|
||||
Spec::Expectations.fail_with(matcher.failure_message) unless match
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class NegativeExpectationMatcherHandler
|
||||
class << self
|
||||
include MatcherHandlerHelper
|
||||
def handle_matcher(actual, matcher, &block)
|
||||
if :use_operator_matcher == matcher
|
||||
return Spec::Matchers::NegativeOperatorMatcher.new(actual)
|
||||
end
|
||||
|
||||
unless matcher.respond_to?(:matches?)
|
||||
raise InvalidMatcherError, "Expected a matcher, got #{matcher.inspect}."
|
||||
end
|
||||
|
||||
unless matcher.respond_to?(:negative_failure_message)
|
||||
Spec::Expectations.fail_with(
|
||||
<<-EOF
|
||||
Matcher does not support should_not.
|
||||
See Spec::Matchers for more information
|
||||
about matchers.
|
||||
EOF
|
||||
)
|
||||
end
|
||||
match = matcher.matches?(actual, &block)
|
||||
::Spec::Matchers.generated_description = "should not #{describe_matcher(matcher)}"
|
||||
Spec::Expectations.fail_with(matcher.negative_failure_message) if match
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
4
vendor/plugins/rspec/lib/spec/extensions.rb
vendored
Executable file
4
vendor/plugins/rspec/lib/spec/extensions.rb
vendored
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
require 'spec/extensions/object'
|
||||
require 'spec/extensions/class'
|
||||
require 'spec/extensions/main'
|
||||
require 'spec/extensions/metaclass'
|
||||
24
vendor/plugins/rspec/lib/spec/extensions/class.rb
vendored
Normal file
24
vendor/plugins/rspec/lib/spec/extensions/class.rb
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
class Class
|
||||
# Creates a new subclass of self, with a name "under" our own name.
|
||||
# Example:
|
||||
#
|
||||
# x = Foo::Bar.subclass('Zap'){}
|
||||
# x.name # => Foo::Bar::Zap_1
|
||||
# x.superclass.name # => Foo::Bar
|
||||
def subclass(base_name, &body)
|
||||
klass = Class.new(self)
|
||||
class_name = "#{base_name}_#{class_count!}"
|
||||
instance_eval do
|
||||
const_set(class_name, klass)
|
||||
end
|
||||
klass.instance_eval(&body)
|
||||
klass
|
||||
end
|
||||
|
||||
private
|
||||
def class_count!
|
||||
@class_count ||= 0
|
||||
@class_count += 1
|
||||
@class_count
|
||||
end
|
||||
end
|
||||
102
vendor/plugins/rspec/lib/spec/extensions/main.rb
vendored
Normal file
102
vendor/plugins/rspec/lib/spec/extensions/main.rb
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
module Spec
|
||||
module Extensions
|
||||
module Main
|
||||
# Creates and returns a class that includes the ExampleGroupMethods
|
||||
# module. Which ExampleGroup type is created depends on the directory of the file
|
||||
# calling this method. For example, Spec::Rails will use different
|
||||
# classes for specs living in <tt>spec/models</tt>,
|
||||
# <tt>spec/helpers</tt>, <tt>spec/views</tt> and
|
||||
# <tt>spec/controllers</tt>.
|
||||
#
|
||||
# It is also possible to override autodiscovery of the example group
|
||||
# type with an options Hash as the last argument:
|
||||
#
|
||||
# describe "name", :type => :something_special do ...
|
||||
#
|
||||
# The reason for using different behaviour classes is to have different
|
||||
# matcher methods available from within the <tt>describe</tt> block.
|
||||
#
|
||||
# See Spec::Example::ExampleFactory#register for details about how to
|
||||
# register special implementations.
|
||||
#
|
||||
def describe(*args, &block)
|
||||
raise ArgumentError if args.empty?
|
||||
raise ArgumentError unless block
|
||||
args << {} unless Hash === args.last
|
||||
args.last[:spec_path] = caller(0)[1]
|
||||
Spec::Example::ExampleGroupFactory.create_example_group(*args, &block)
|
||||
end
|
||||
alias :context :describe
|
||||
|
||||
# Creates an example group that can be shared by other example groups
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# share_examples_for "All Editions" do
|
||||
# it "all editions behaviour" ...
|
||||
# end
|
||||
#
|
||||
# describe SmallEdition do
|
||||
# it_should_behave_like "All Editions"
|
||||
#
|
||||
# it "should do small edition stuff" do
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
def share_examples_for(name, &block)
|
||||
describe(name, :shared => true, &block)
|
||||
end
|
||||
|
||||
alias :shared_examples_for :share_examples_for
|
||||
|
||||
# Creates a Shared Example Group and assigns it to a constant
|
||||
#
|
||||
# share_as :AllEditions do
|
||||
# it "should do all editions stuff" ...
|
||||
# end
|
||||
#
|
||||
# describe SmallEdition do
|
||||
# it_should_behave_like AllEditions
|
||||
#
|
||||
# it "should do small edition stuff" do
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# And, for those of you who prefer to use something more like Ruby, you
|
||||
# can just include the module directly
|
||||
#
|
||||
# describe SmallEdition do
|
||||
# include AllEditions
|
||||
#
|
||||
# it "should do small edition stuff" do
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
def share_as(name, &block)
|
||||
begin
|
||||
Object.const_set(name, share_examples_for(name, &block))
|
||||
rescue NameError => e
|
||||
raise NameError.new(e.message + "\nThe first argument to share_as must be a legal name for a constant\n")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rspec_options
|
||||
$rspec_options ||= begin; \
|
||||
parser = ::Spec::Runner::OptionParser.new(STDERR, STDOUT); \
|
||||
parser.order!(ARGV); \
|
||||
$rspec_options = parser.options; \
|
||||
end
|
||||
$rspec_options
|
||||
end
|
||||
|
||||
def init_rspec_options(options)
|
||||
$rspec_options = options if $rspec_options.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include Spec::Extensions::Main
|
||||
7
vendor/plugins/rspec/lib/spec/extensions/metaclass.rb
vendored
Normal file
7
vendor/plugins/rspec/lib/spec/extensions/metaclass.rb
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module Spec
|
||||
module MetaClass
|
||||
def metaclass
|
||||
class << self; self; end
|
||||
end
|
||||
end
|
||||
end
|
||||
6
vendor/plugins/rspec/lib/spec/extensions/object.rb
vendored
Executable file
6
vendor/plugins/rspec/lib/spec/extensions/object.rb
vendored
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
class Object
|
||||
def args_and_options(*args)
|
||||
options = Hash === args.last ? args.pop : {}
|
||||
return args, options
|
||||
end
|
||||
end
|
||||
12
vendor/plugins/rspec/lib/spec/interop/test.rb
vendored
Normal file
12
vendor/plugins/rspec/lib/spec/interop/test.rb
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
require 'test/unit'
|
||||
require 'test/unit/testresult'
|
||||
|
||||
require 'spec/interop/test/unit/testcase'
|
||||
require 'spec/interop/test/unit/testsuite_adapter'
|
||||
require 'spec/interop/test/unit/autorunner'
|
||||
require 'spec/interop/test/unit/testresult'
|
||||
require 'spec/interop/test/unit/ui/console/testrunner'
|
||||
|
||||
Spec::Example::ExampleGroupFactory.default(Test::Unit::TestCase)
|
||||
|
||||
Test::Unit.run = true
|
||||
6
vendor/plugins/rspec/lib/spec/interop/test/unit/autorunner.rb
vendored
Normal file
6
vendor/plugins/rspec/lib/spec/interop/test/unit/autorunner.rb
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class Test::Unit::AutoRunner
|
||||
remove_method :process_args
|
||||
def process_args(argv)
|
||||
true
|
||||
end
|
||||
end
|
||||
61
vendor/plugins/rspec/lib/spec/interop/test/unit/testcase.rb
vendored
Normal file
61
vendor/plugins/rspec/lib/spec/interop/test/unit/testcase.rb
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
require 'test/unit/testcase'
|
||||
|
||||
module Test
|
||||
module Unit
|
||||
# This extension of the standard Test::Unit::TestCase makes RSpec
|
||||
# available from within, so that you can do things like:
|
||||
#
|
||||
# require 'test/unit'
|
||||
# require 'spec'
|
||||
#
|
||||
# class MyTest < Test::Unit::TestCase
|
||||
# it "should work with Test::Unit assertions" do
|
||||
# assert_equal 4, 2+1
|
||||
# end
|
||||
#
|
||||
# def test_should_work_with_rspec_expectations
|
||||
# (3+1).should == 5
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# See also Spec::Example::ExampleGroup
|
||||
class TestCase
|
||||
extend Spec::Example::ExampleGroupMethods
|
||||
include Spec::Example::ExampleMethods
|
||||
|
||||
before(:each) {setup}
|
||||
after(:each) {teardown}
|
||||
|
||||
class << self
|
||||
def suite
|
||||
Test::Unit::TestSuiteAdapter.new(self)
|
||||
end
|
||||
|
||||
def example_method?(method_name)
|
||||
should_method?(method_name) || test_method?(method_name)
|
||||
end
|
||||
|
||||
def test_method?(method_name)
|
||||
method_name =~ /^test[_A-Z]./ && (
|
||||
instance_method(method_name).arity == 0 ||
|
||||
instance_method(method_name).arity == -1
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(defined_description, &implementation)
|
||||
@_defined_description = defined_description
|
||||
@_implementation = implementation
|
||||
|
||||
@_result = ::Test::Unit::TestResult.new
|
||||
# @method_name is important to set here because it "complies" with Test::Unit's interface.
|
||||
# Some Test::Unit extensions depend on @method_name being present.
|
||||
@method_name = @_defined_description
|
||||
end
|
||||
|
||||
def run(ignore_this_argument=nil)
|
||||
super()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
6
vendor/plugins/rspec/lib/spec/interop/test/unit/testresult.rb
vendored
Normal file
6
vendor/plugins/rspec/lib/spec/interop/test/unit/testresult.rb
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class Test::Unit::TestResult
|
||||
alias_method :tu_passed?, :passed?
|
||||
def passed?
|
||||
return tu_passed? & ::Spec.run
|
||||
end
|
||||
end
|
||||
34
vendor/plugins/rspec/lib/spec/interop/test/unit/testsuite_adapter.rb
vendored
Normal file
34
vendor/plugins/rspec/lib/spec/interop/test/unit/testsuite_adapter.rb
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
module Test
|
||||
module Unit
|
||||
class TestSuiteAdapter < TestSuite
|
||||
attr_reader :example_group, :examples
|
||||
alias_method :tests, :examples
|
||||
def initialize(example_group)
|
||||
@example_group = example_group
|
||||
@examples = example_group.examples
|
||||
end
|
||||
|
||||
def name
|
||||
example_group.description
|
||||
end
|
||||
|
||||
def run(*args)
|
||||
return true unless args.empty?
|
||||
example_group.run
|
||||
end
|
||||
|
||||
def size
|
||||
example_group.number_of_examples
|
||||
end
|
||||
|
||||
def delete(example)
|
||||
examples.delete example
|
||||
end
|
||||
|
||||
def empty?
|
||||
examples.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
61
vendor/plugins/rspec/lib/spec/interop/test/unit/ui/console/testrunner.rb
vendored
Normal file
61
vendor/plugins/rspec/lib/spec/interop/test/unit/ui/console/testrunner.rb
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
require 'test/unit/ui/console/testrunner'
|
||||
|
||||
module Test
|
||||
module Unit
|
||||
module UI
|
||||
module Console
|
||||
class TestRunner
|
||||
|
||||
alias_method :started_without_rspec, :started
|
||||
def started_with_rspec(result)
|
||||
@result = result
|
||||
@need_to_output_started = true
|
||||
end
|
||||
alias_method :started, :started_with_rspec
|
||||
|
||||
alias_method :test_started_without_rspec, :test_started
|
||||
def test_started_with_rspec(name)
|
||||
if @need_to_output_started
|
||||
if @rspec_io
|
||||
@rspec_io.rewind
|
||||
output(@rspec_io.read)
|
||||
end
|
||||
output("Started")
|
||||
@need_to_output_started = false
|
||||
end
|
||||
test_started_without_rspec(name)
|
||||
end
|
||||
alias_method :test_started, :test_started_with_rspec
|
||||
|
||||
alias_method :test_finished_without_rspec, :test_finished
|
||||
def test_finished_with_rspec(name)
|
||||
test_finished_without_rspec(name)
|
||||
@ran_test = true
|
||||
end
|
||||
alias_method :test_finished, :test_finished_with_rspec
|
||||
|
||||
alias_method :finished_without_rspec, :finished
|
||||
def finished_with_rspec(elapsed_time)
|
||||
@ran_test ||= false
|
||||
if @ran_test
|
||||
finished_without_rspec(elapsed_time)
|
||||
end
|
||||
end
|
||||
alias_method :finished, :finished_with_rspec
|
||||
|
||||
alias_method :setup_mediator_without_rspec, :setup_mediator
|
||||
def setup_mediator_with_rspec
|
||||
orig_io = @io
|
||||
@io = StringIO.new
|
||||
setup_mediator_without_rspec
|
||||
ensure
|
||||
@rspec_io = @io
|
||||
@io = orig_io
|
||||
end
|
||||
alias_method :setup_mediator, :setup_mediator_with_rspec
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
156
vendor/plugins/rspec/lib/spec/matchers.rb
vendored
Normal file
156
vendor/plugins/rspec/lib/spec/matchers.rb
vendored
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
require 'spec/matchers/simple_matcher'
|
||||
require 'spec/matchers/be'
|
||||
require 'spec/matchers/be_close'
|
||||
require 'spec/matchers/change'
|
||||
require 'spec/matchers/eql'
|
||||
require 'spec/matchers/equal'
|
||||
require 'spec/matchers/exist'
|
||||
require 'spec/matchers/has'
|
||||
require 'spec/matchers/have'
|
||||
require 'spec/matchers/include'
|
||||
require 'spec/matchers/match'
|
||||
require 'spec/matchers/raise_error'
|
||||
require 'spec/matchers/respond_to'
|
||||
require 'spec/matchers/satisfy'
|
||||
require 'spec/matchers/throw_symbol'
|
||||
require 'spec/matchers/operator_matcher'
|
||||
|
||||
module Spec
|
||||
|
||||
# RSpec ships with a number of useful Expression Matchers. An Expression Matcher
|
||||
# is any object that responds to the following methods:
|
||||
#
|
||||
# matches?(actual)
|
||||
# failure_message
|
||||
# negative_failure_message #optional
|
||||
# description #optional
|
||||
#
|
||||
# See Spec::Expectations to learn how to use these as Expectation Matchers.
|
||||
# See Spec::Mocks to learn how to use them as Mock Argument Constraints.
|
||||
#
|
||||
# == Predicates
|
||||
#
|
||||
# In addition to those Expression Matchers that are defined explicitly, RSpec will
|
||||
# create custom Matchers on the fly for any arbitrary predicate, giving your specs
|
||||
# a much more natural language feel.
|
||||
#
|
||||
# A Ruby predicate is a method that ends with a "?" and returns true or false.
|
||||
# Common examples are +empty?+, +nil?+, and +instance_of?+.
|
||||
#
|
||||
# All you need to do is write +should be_+ followed by the predicate without
|
||||
# the question mark, and RSpec will figure it out from there. For example:
|
||||
#
|
||||
# [].should be_empty => [].empty? #passes
|
||||
# [].should_not be_empty => [].empty? #fails
|
||||
#
|
||||
# In addtion to prefixing the predicate matchers with "be_", you can also use "be_a_"
|
||||
# and "be_an_", making your specs read much more naturally:
|
||||
#
|
||||
# "a string".should be_an_instance_of(String) =>"a string".instance_of?(String) #passes
|
||||
#
|
||||
# 3.should be_a_kind_of(Fixnum) => 3.kind_of?(Numeric) #passes
|
||||
# 3.should be_a_kind_of(Numeric) => 3.kind_of?(Numeric) #passes
|
||||
# 3.should be_an_instance_of(Fixnum) => 3.instance_of?(Fixnum) #passes
|
||||
# 3.should_not be_instance_of(Numeric) => 3.instance_of?(Numeric) #fails
|
||||
#
|
||||
# RSpec will also create custom matchers for predicates like +has_key?+. To
|
||||
# use this feature, just state that the object should have_key(:key) and RSpec will
|
||||
# call has_key?(:key) on the target. For example:
|
||||
#
|
||||
# {:a => "A"}.should have_key(:a) => {:a => "A"}.has_key?(:a) #passes
|
||||
# {:a => "A"}.should have_key(:b) => {:a => "A"}.has_key?(:b) #fails
|
||||
#
|
||||
# You can use this feature to invoke any predicate that begins with "has_", whether it is
|
||||
# part of the Ruby libraries (like +Hash#has_key?+) or a method you wrote on your own class.
|
||||
#
|
||||
# == Custom Expectation Matchers
|
||||
#
|
||||
# When you find that none of the stock Expectation Matchers provide a natural
|
||||
# feeling expectation, you can very easily write your own.
|
||||
#
|
||||
# For example, imagine that you are writing a game in which players can
|
||||
# be in various zones on a virtual board. To specify that bob should
|
||||
# be in zone 4, you could say:
|
||||
#
|
||||
# bob.current_zone.should eql(Zone.new("4"))
|
||||
#
|
||||
# But you might find it more expressive to say:
|
||||
#
|
||||
# bob.should be_in_zone("4")
|
||||
#
|
||||
# and/or
|
||||
#
|
||||
# bob.should_not be_in_zone("3")
|
||||
#
|
||||
# To do this, you would need to write a class like this:
|
||||
#
|
||||
# class BeInZone
|
||||
# def initialize(expected)
|
||||
# @expected = expected
|
||||
# end
|
||||
# def matches?(target)
|
||||
# @target = target
|
||||
# @target.current_zone.eql?(Zone.new(@expected))
|
||||
# end
|
||||
# def failure_message
|
||||
# "expected #{@target.inspect} to be in Zone #{@expected}"
|
||||
# end
|
||||
# def negative_failure_message
|
||||
# "expected #{@target.inspect} not to be in Zone #{@expected}"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# ... and a method like this:
|
||||
#
|
||||
# def be_in_zone(expected)
|
||||
# BeInZone.new(expected)
|
||||
# end
|
||||
#
|
||||
# And then expose the method to your specs. This is normally done
|
||||
# by including the method and the class in a module, which is then
|
||||
# included in your spec:
|
||||
#
|
||||
# module CustomGameMatchers
|
||||
# class BeInZone
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# def be_in_zone(expected)
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# describe "Player behaviour" do
|
||||
# include CustomGameMatchers
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# or you can include in globally in a spec_helper.rb file <tt>require</tt>d
|
||||
# from your spec file(s):
|
||||
#
|
||||
# Spec::Runner.configure do |config|
|
||||
# config.include(CustomGameMatchers)
|
||||
# end
|
||||
#
|
||||
module Matchers
|
||||
module ModuleMethods
|
||||
attr_accessor :generated_description
|
||||
|
||||
def clear_generated_description
|
||||
self.generated_description = nil
|
||||
end
|
||||
end
|
||||
|
||||
extend ModuleMethods
|
||||
|
||||
def method_missing(sym, *args, &block) # :nodoc:
|
||||
return Matchers::Be.new(sym, *args) if sym.starts_with?("be_")
|
||||
return Matchers::Has.new(sym, *args) if sym.starts_with?("have_")
|
||||
super
|
||||
end
|
||||
|
||||
class MatcherError < StandardError
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
224
vendor/plugins/rspec/lib/spec/matchers/be.rb
vendored
Normal file
224
vendor/plugins/rspec/lib/spec/matchers/be.rb
vendored
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class Be #:nodoc:
|
||||
def initialize(*args)
|
||||
if args.empty?
|
||||
@expected = :satisfy_if
|
||||
else
|
||||
@expected = parse_expected(args.shift)
|
||||
end
|
||||
@args = args
|
||||
@comparison = ""
|
||||
end
|
||||
|
||||
def matches?(actual)
|
||||
@actual = actual
|
||||
if handling_predicate?
|
||||
begin
|
||||
return @result = actual.__send__(predicate, *@args)
|
||||
rescue => predicate_error
|
||||
# This clause should be empty, but rcov will not report it as covered
|
||||
# unless something (anything) is executed within the clause
|
||||
rcov_error_report = "http://eigenclass.org/hiki.rb?rcov-0.8.0"
|
||||
end
|
||||
|
||||
# This supports should_exist > target.exists? in the old world.
|
||||
# We should consider deprecating that ability as in the new world
|
||||
# you can't write "should exist" unless you have your own custom matcher.
|
||||
begin
|
||||
return @result = actual.__send__(present_tense_predicate, *@args)
|
||||
rescue
|
||||
raise predicate_error
|
||||
end
|
||||
else
|
||||
return match_or_compare
|
||||
end
|
||||
end
|
||||
|
||||
def failure_message
|
||||
return "expected #{@comparison}#{expected}, got #{@actual.inspect}" unless handling_predicate?
|
||||
return "expected #{predicate}#{args_to_s} to return true, got #{@result.inspect}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
return "expected not #{expected}, got #{@actual.inspect}" unless handling_predicate?
|
||||
return "expected #{predicate}#{args_to_s} to return false, got #{@result.inspect}"
|
||||
end
|
||||
|
||||
def expected
|
||||
return "if to be satisfied" if @expected == :satisfy_if
|
||||
return true if @expected == :true
|
||||
return false if @expected == :false
|
||||
return "nil" if @expected == :nil
|
||||
return @expected.inspect
|
||||
end
|
||||
|
||||
def match_or_compare
|
||||
return @actual ? true : false if @expected == :satisfy_if
|
||||
return @actual == true if @expected == :true
|
||||
return @actual == false if @expected == :false
|
||||
return @actual.nil? if @expected == :nil
|
||||
return @actual < @expected if @less_than
|
||||
return @actual <= @expected if @less_than_or_equal
|
||||
return @actual >= @expected if @greater_than_or_equal
|
||||
return @actual > @expected if @greater_than
|
||||
return @actual == @expected if @double_equal
|
||||
return @actual === @expected if @triple_equal
|
||||
return @actual.equal?(@expected)
|
||||
end
|
||||
|
||||
def ==(expected)
|
||||
@prefix = "be "
|
||||
@double_equal = true
|
||||
@comparison = "== "
|
||||
@expected = expected
|
||||
self
|
||||
end
|
||||
|
||||
def ===(expected)
|
||||
@prefix = "be "
|
||||
@triple_equal = true
|
||||
@comparison = "=== "
|
||||
@expected = expected
|
||||
self
|
||||
end
|
||||
|
||||
def <(expected)
|
||||
@prefix = "be "
|
||||
@less_than = true
|
||||
@comparison = "< "
|
||||
@expected = expected
|
||||
self
|
||||
end
|
||||
|
||||
def <=(expected)
|
||||
@prefix = "be "
|
||||
@less_than_or_equal = true
|
||||
@comparison = "<= "
|
||||
@expected = expected
|
||||
self
|
||||
end
|
||||
|
||||
def >=(expected)
|
||||
@prefix = "be "
|
||||
@greater_than_or_equal = true
|
||||
@comparison = ">= "
|
||||
@expected = expected
|
||||
self
|
||||
end
|
||||
|
||||
def >(expected)
|
||||
@prefix = "be "
|
||||
@greater_than = true
|
||||
@comparison = "> "
|
||||
@expected = expected
|
||||
self
|
||||
end
|
||||
|
||||
def description
|
||||
"#{prefix_to_sentence}#{comparison}#{expected_to_sentence}#{args_to_sentence}"
|
||||
end
|
||||
|
||||
private
|
||||
def parse_expected(expected)
|
||||
if Symbol === expected
|
||||
@handling_predicate = true
|
||||
["be_an_","be_a_","be_"].each do |prefix|
|
||||
if expected.starts_with?(prefix)
|
||||
@prefix = prefix
|
||||
return "#{expected.to_s.sub(@prefix,"")}".to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
@prefix = ""
|
||||
return expected
|
||||
end
|
||||
|
||||
def handling_predicate?
|
||||
return false if [:true, :false, :nil].include?(@expected)
|
||||
return @handling_predicate
|
||||
end
|
||||
|
||||
def predicate
|
||||
"#{@expected.to_s}?".to_sym
|
||||
end
|
||||
|
||||
def present_tense_predicate
|
||||
"#{@expected.to_s}s?".to_sym
|
||||
end
|
||||
|
||||
def args_to_s
|
||||
return "" if @args.empty?
|
||||
inspected_args = @args.collect{|a| a.inspect}
|
||||
return "(#{inspected_args.join(', ')})"
|
||||
end
|
||||
|
||||
def comparison
|
||||
@comparison
|
||||
end
|
||||
|
||||
def expected_to_sentence
|
||||
split_words(@expected)
|
||||
end
|
||||
|
||||
def prefix_to_sentence
|
||||
split_words(@prefix)
|
||||
end
|
||||
|
||||
def split_words(sym)
|
||||
sym.to_s.gsub(/_/,' ')
|
||||
end
|
||||
|
||||
def args_to_sentence
|
||||
case @args.length
|
||||
when 0
|
||||
""
|
||||
when 1
|
||||
" #{@args[0]}"
|
||||
else
|
||||
" #{@args[0...-1].join(', ')} and #{@args[-1]}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should be
|
||||
# should be_true
|
||||
# should be_false
|
||||
# should be_nil
|
||||
# should be_arbitrary_predicate(*args)
|
||||
# should_not be_nil
|
||||
# should_not be_arbitrary_predicate(*args)
|
||||
#
|
||||
# Given true, false, or nil, will pass if actual is
|
||||
# true, false or nil (respectively). Given no args means
|
||||
# the caller should satisfy an if condition (to be or not to be).
|
||||
#
|
||||
# Predicates are any Ruby method that ends in a "?" and returns true or false.
|
||||
# Given be_ followed by arbitrary_predicate (without the "?"), RSpec will match
|
||||
# convert that into a query against the target object.
|
||||
#
|
||||
# The arbitrary_predicate feature will handle any predicate
|
||||
# prefixed with "be_an_" (e.g. be_an_instance_of), "be_a_" (e.g. be_a_kind_of)
|
||||
# or "be_" (e.g. be_empty), letting you choose the prefix that best suits the predicate.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# target.should be
|
||||
# target.should be_true
|
||||
# target.should be_false
|
||||
# target.should be_nil
|
||||
# target.should_not be_nil
|
||||
#
|
||||
# collection.should be_empty #passes if target.empty?
|
||||
# "this string".should be_an_intance_of(String)
|
||||
#
|
||||
# target.should_not be_empty #passes unless target.empty?
|
||||
# target.should_not be_old_enough(16) #passes unless target.old_enough?(16)
|
||||
def be(*args)
|
||||
Matchers::Be.new(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
37
vendor/plugins/rspec/lib/spec/matchers/be_close.rb
vendored
Normal file
37
vendor/plugins/rspec/lib/spec/matchers/be_close.rb
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class BeClose #:nodoc:
|
||||
def initialize(expected, delta)
|
||||
@expected = expected
|
||||
@delta = delta
|
||||
end
|
||||
|
||||
def matches?(actual)
|
||||
@actual = actual
|
||||
(@actual - @expected).abs < @delta
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"expected #{@expected} +/- (< #{@delta}), got #{@actual}"
|
||||
end
|
||||
|
||||
def description
|
||||
"be close to #{@expected} (within +- #{@delta})"
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should be_close(expected, delta)
|
||||
# should_not be_close(expected, delta)
|
||||
#
|
||||
# Passes if actual == expected +/- delta
|
||||
#
|
||||
# == Example
|
||||
#
|
||||
# result.should be_close(3.0, 0.5)
|
||||
def be_close(expected, delta)
|
||||
Matchers::BeClose.new(expected, delta)
|
||||
end
|
||||
end
|
||||
end
|
||||
144
vendor/plugins/rspec/lib/spec/matchers/change.rb
vendored
Normal file
144
vendor/plugins/rspec/lib/spec/matchers/change.rb
vendored
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
#Based on patch from Wilson Bilkovich
|
||||
class Change #:nodoc:
|
||||
def initialize(receiver=nil, message=nil, &block)
|
||||
@receiver = receiver
|
||||
@message = message
|
||||
@block = block
|
||||
end
|
||||
|
||||
def matches?(target, &block)
|
||||
if block
|
||||
raise MatcherError.new(<<-EOF
|
||||
block passed to should or should_not change must use {} instead of do/end
|
||||
EOF
|
||||
)
|
||||
end
|
||||
@target = target
|
||||
execute_change
|
||||
return false if @from && (@from != @before)
|
||||
return false if @to && (@to != @after)
|
||||
return (@before + @amount == @after) if @amount
|
||||
return ((@after - @before) >= @minimum) if @minimum
|
||||
return ((@after - @before) <= @maximum) if @maximum
|
||||
return @before != @after
|
||||
end
|
||||
|
||||
def execute_change
|
||||
@before = @block.nil? ? @receiver.send(@message) : @block.call
|
||||
@target.call
|
||||
@after = @block.nil? ? @receiver.send(@message) : @block.call
|
||||
end
|
||||
|
||||
def failure_message
|
||||
if @to
|
||||
"#{result} should have been changed to #{@to.inspect}, but is now #{@after.inspect}"
|
||||
elsif @from
|
||||
"#{result} should have initially been #{@from.inspect}, but was #{@before.inspect}"
|
||||
elsif @amount
|
||||
"#{result} should have been changed by #{@amount.inspect}, but was changed by #{actual_delta.inspect}"
|
||||
elsif @minimum
|
||||
"#{result} should have been changed by at least #{@minimum.inspect}, but was changed by #{actual_delta.inspect}"
|
||||
elsif @maximum
|
||||
"#{result} should have been changed by at most #{@maximum.inspect}, but was changed by #{actual_delta.inspect}"
|
||||
else
|
||||
"#{result} should have changed, but is still #{@before.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
def result
|
||||
@message || "result"
|
||||
end
|
||||
|
||||
def actual_delta
|
||||
@after - @before
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"#{result} should not have changed, but did change from #{@before.inspect} to #{@after.inspect}"
|
||||
end
|
||||
|
||||
def by(amount)
|
||||
@amount = amount
|
||||
self
|
||||
end
|
||||
|
||||
def by_at_least(minimum)
|
||||
@minimum = minimum
|
||||
self
|
||||
end
|
||||
|
||||
def by_at_most(maximum)
|
||||
@maximum = maximum
|
||||
self
|
||||
end
|
||||
|
||||
def to(to)
|
||||
@to = to
|
||||
self
|
||||
end
|
||||
|
||||
def from (from)
|
||||
@from = from
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should change(receiver, message, &block)
|
||||
# should change(receiver, message, &block).by(value)
|
||||
# should change(receiver, message, &block).from(old).to(new)
|
||||
# should_not change(receiver, message, &block)
|
||||
#
|
||||
# Allows you to specify that a Proc will cause some value to change.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# lambda {
|
||||
# team.add_player(player)
|
||||
# }.should change(roster, :count)
|
||||
#
|
||||
# lambda {
|
||||
# team.add_player(player)
|
||||
# }.should change(roster, :count).by(1)
|
||||
#
|
||||
# lambda {
|
||||
# team.add_player(player)
|
||||
# }.should change(roster, :count).by_at_least(1)
|
||||
#
|
||||
# lambda {
|
||||
# team.add_player(player)
|
||||
# }.should change(roster, :count).by_at_most(1)
|
||||
#
|
||||
# string = "string"
|
||||
# lambda {
|
||||
# string.reverse!
|
||||
# }.should change { string }.from("string").to("gnirts")
|
||||
#
|
||||
# lambda {
|
||||
# person.happy_birthday
|
||||
# }.should change(person, :birthday).from(32).to(33)
|
||||
#
|
||||
# lambda {
|
||||
# employee.develop_great_new_social_networking_app
|
||||
# }.should change(employee, :title).from("Mail Clerk").to("CEO")
|
||||
#
|
||||
# Evaluates +receiver.message+ or +block+ before and
|
||||
# after it evaluates the c object (generated by the lambdas in the examples above).
|
||||
#
|
||||
# Then compares the values before and after the +receiver.message+ and
|
||||
# evaluates the difference compared to the expected difference.
|
||||
#
|
||||
# == Warning
|
||||
# +should_not+ +change+ only supports the form with no subsequent calls to
|
||||
# +by+, +by_at_least+, +by_at_most+, +to+ or +from+.
|
||||
#
|
||||
# blocks passed to +should+ +change+ and +should_not+ +change+
|
||||
# must use the <tt>{}</tt> form (<tt>do/end</tt> is not supported)
|
||||
def change(target=nil, message=nil, &block)
|
||||
Matchers::Change.new(target, message, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
43
vendor/plugins/rspec/lib/spec/matchers/eql.rb
vendored
Normal file
43
vendor/plugins/rspec/lib/spec/matchers/eql.rb
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class Eql #:nodoc:
|
||||
def initialize(expected)
|
||||
@expected = expected
|
||||
end
|
||||
|
||||
def matches?(actual)
|
||||
@actual = actual
|
||||
@actual.eql?(@expected)
|
||||
end
|
||||
|
||||
def failure_message
|
||||
return "expected #{@expected.inspect}, got #{@actual.inspect} (using .eql?)", @expected, @actual
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
return "expected #{@actual.inspect} not to equal #{@expected.inspect} (using .eql?)", @expected, @actual
|
||||
end
|
||||
|
||||
def description
|
||||
"eql #{@expected.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should eql(expected)
|
||||
# should_not eql(expected)
|
||||
#
|
||||
# Passes if actual and expected are of equal value, but not necessarily the same object.
|
||||
#
|
||||
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# 5.should eql(5)
|
||||
# 5.should_not eql(3)
|
||||
def eql(expected)
|
||||
Matchers::Eql.new(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
43
vendor/plugins/rspec/lib/spec/matchers/equal.rb
vendored
Normal file
43
vendor/plugins/rspec/lib/spec/matchers/equal.rb
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class Equal #:nodoc:
|
||||
def initialize(expected)
|
||||
@expected = expected
|
||||
end
|
||||
|
||||
def matches?(actual)
|
||||
@actual = actual
|
||||
@actual.equal?(@expected)
|
||||
end
|
||||
|
||||
def failure_message
|
||||
return "expected #{@expected.inspect}, got #{@actual.inspect} (using .equal?)", @expected, @actual
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
return "expected #{@actual.inspect} not to equal #{@expected.inspect} (using .equal?)", @expected, @actual
|
||||
end
|
||||
|
||||
def description
|
||||
"equal #{@expected.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should equal(expected)
|
||||
# should_not equal(expected)
|
||||
#
|
||||
# Passes if actual and expected are the same object (object identity).
|
||||
#
|
||||
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# 5.should equal(5) #Fixnums are equal
|
||||
# "5".should_not equal("5") #Strings that look the same are not the same object
|
||||
def equal(expected)
|
||||
Matchers::Equal.new(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
17
vendor/plugins/rspec/lib/spec/matchers/exist.rb
vendored
Normal file
17
vendor/plugins/rspec/lib/spec/matchers/exist.rb
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
class Exist
|
||||
def matches? actual
|
||||
@actual = actual
|
||||
@actual.exist?
|
||||
end
|
||||
def failure_message
|
||||
"expected #{@actual.inspect} to exist, but it doesn't."
|
||||
end
|
||||
def negative_failure_message
|
||||
"expected #{@actual.inspect} to not exist, but it does."
|
||||
end
|
||||
end
|
||||
def exist; Exist.new; end
|
||||
end
|
||||
end
|
||||
34
vendor/plugins/rspec/lib/spec/matchers/has.rb
vendored
Normal file
34
vendor/plugins/rspec/lib/spec/matchers/has.rb
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class Has #:nodoc:
|
||||
def initialize(sym, *args)
|
||||
@sym = sym
|
||||
@args = args
|
||||
end
|
||||
|
||||
def matches?(target)
|
||||
target.send(predicate, *@args)
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"expected ##{predicate}(#{@args[0].inspect}) to return true, got false"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"expected ##{predicate}(#{@args[0].inspect}) to return false, got true"
|
||||
end
|
||||
|
||||
def description
|
||||
"have key #{@args[0].inspect}"
|
||||
end
|
||||
|
||||
private
|
||||
def predicate
|
||||
"#{@sym.to_s.sub("have_","has_")}?".to_sym
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
149
vendor/plugins/rspec/lib/spec/matchers/have.rb
vendored
Normal file
149
vendor/plugins/rspec/lib/spec/matchers/have.rb
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class Have #:nodoc:
|
||||
def initialize(expected, relativity=:exactly)
|
||||
@expected = (expected == :no ? 0 : expected)
|
||||
@relativity = relativity
|
||||
end
|
||||
|
||||
def relativities
|
||||
@relativities ||= {
|
||||
:exactly => "",
|
||||
:at_least => "at least ",
|
||||
:at_most => "at most "
|
||||
}
|
||||
end
|
||||
|
||||
def method_missing(sym, *args, &block)
|
||||
@collection_name = sym
|
||||
if defined?(ActiveSupport::Inflector)
|
||||
@plural_collection_name = ActiveSupport::Inflector.pluralize(sym.to_s)
|
||||
elsif Object.const_defined?(:Inflector)
|
||||
@plural_collection_name = Inflector.pluralize(sym.to_s)
|
||||
end
|
||||
@args = args
|
||||
@block = block
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(collection_owner)
|
||||
if collection_owner.respond_to?(@collection_name)
|
||||
collection = collection_owner.send(@collection_name, *@args, &@block)
|
||||
elsif (@plural_collection_name && collection_owner.respond_to?(@plural_collection_name))
|
||||
collection = collection_owner.send(@plural_collection_name, *@args, &@block)
|
||||
elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
|
||||
collection = collection_owner
|
||||
else
|
||||
collection_owner.send(@collection_name, *@args, &@block)
|
||||
end
|
||||
@actual = collection.size if collection.respond_to?(:size)
|
||||
@actual = collection.length if collection.respond_to?(:length)
|
||||
raise not_a_collection if @actual.nil?
|
||||
return @actual >= @expected if @relativity == :at_least
|
||||
return @actual <= @expected if @relativity == :at_most
|
||||
return @actual == @expected
|
||||
end
|
||||
|
||||
def not_a_collection
|
||||
"expected #{@collection_name} to be a collection but it does not respond to #length or #size"
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"expected #{relative_expectation} #{@collection_name}, got #{@actual}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
if @relativity == :exactly
|
||||
return "expected target not to have #{@expected} #{@collection_name}, got #{@actual}"
|
||||
elsif @relativity == :at_most
|
||||
return <<-EOF
|
||||
Isn't life confusing enough?
|
||||
Instead of having to figure out the meaning of this:
|
||||
should_not have_at_most(#{@expected}).#{@collection_name}
|
||||
We recommend that you use this instead:
|
||||
should have_at_least(#{@expected + 1}).#{@collection_name}
|
||||
EOF
|
||||
elsif @relativity == :at_least
|
||||
return <<-EOF
|
||||
Isn't life confusing enough?
|
||||
Instead of having to figure out the meaning of this:
|
||||
should_not have_at_least(#{@expected}).#{@collection_name}
|
||||
We recommend that you use this instead:
|
||||
should have_at_most(#{@expected - 1}).#{@collection_name}
|
||||
EOF
|
||||
end
|
||||
end
|
||||
|
||||
def description
|
||||
"have #{relative_expectation} #{@collection_name}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def relative_expectation
|
||||
"#{relativities[@relativity]}#{@expected}"
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should have(number).named_collection__or__sugar
|
||||
# should_not have(number).named_collection__or__sugar
|
||||
#
|
||||
# Passes if receiver is a collection with the submitted
|
||||
# number of items OR if the receiver OWNS a collection
|
||||
# with the submitted number of items.
|
||||
#
|
||||
# If the receiver OWNS the collection, you must use the name
|
||||
# of the collection. So if a <tt>Team</tt> instance has a
|
||||
# collection named <tt>#players</tt>, you must use that name
|
||||
# to set the expectation.
|
||||
#
|
||||
# If the receiver IS the collection, you can use any name
|
||||
# you like for <tt>named_collection</tt>. We'd recommend using
|
||||
# either "elements", "members", or "items" as these are all
|
||||
# standard ways of describing the things IN a collection.
|
||||
#
|
||||
# This also works for Strings, letting you set an expectation
|
||||
# about its length
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# # Passes if team.players.size == 11
|
||||
# team.should have(11).players
|
||||
#
|
||||
# # Passes if [1,2,3].length == 3
|
||||
# [1,2,3].should have(3).items #"items" is pure sugar
|
||||
#
|
||||
# # Passes if "this string".length == 11
|
||||
# "this string".should have(11).characters #"characters" is pure sugar
|
||||
def have(n)
|
||||
Matchers::Have.new(n)
|
||||
end
|
||||
alias :have_exactly :have
|
||||
|
||||
# :call-seq:
|
||||
# should have_at_least(number).items
|
||||
#
|
||||
# Exactly like have() with >=.
|
||||
#
|
||||
# == Warning
|
||||
#
|
||||
# +should_not+ +have_at_least+ is not supported
|
||||
def have_at_least(n)
|
||||
Matchers::Have.new(n, :at_least)
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should have_at_most(number).items
|
||||
#
|
||||
# Exactly like have() with <=.
|
||||
#
|
||||
# == Warning
|
||||
#
|
||||
# +should_not+ +have_at_most+ is not supported
|
||||
def have_at_most(n)
|
||||
Matchers::Have.new(n, :at_most)
|
||||
end
|
||||
end
|
||||
end
|
||||
70
vendor/plugins/rspec/lib/spec/matchers/include.rb
vendored
Normal file
70
vendor/plugins/rspec/lib/spec/matchers/include.rb
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class Include #:nodoc:
|
||||
|
||||
def initialize(*expecteds)
|
||||
@expecteds = expecteds
|
||||
end
|
||||
|
||||
def matches?(actual)
|
||||
@actual = actual
|
||||
@expecteds.each do |expected|
|
||||
return false unless actual.include?(expected)
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def failure_message
|
||||
_message
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
_message("not ")
|
||||
end
|
||||
|
||||
def description
|
||||
"include #{_pretty_print(@expecteds)}"
|
||||
end
|
||||
|
||||
private
|
||||
def _message(maybe_not="")
|
||||
"expected #{@actual.inspect} #{maybe_not}to include #{_pretty_print(@expecteds)}"
|
||||
end
|
||||
|
||||
def _pretty_print(array)
|
||||
result = ""
|
||||
array.each_with_index do |item, index|
|
||||
if index < (array.length - 2)
|
||||
result << "#{item.inspect}, "
|
||||
elsif index < (array.length - 1)
|
||||
result << "#{item.inspect} and "
|
||||
else
|
||||
result << "#{item.inspect}"
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should include(expected)
|
||||
# should_not include(expected)
|
||||
#
|
||||
# Passes if actual includes expected. This works for
|
||||
# collections and Strings. You can also pass in multiple args
|
||||
# and it will only pass if all args are found in collection.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# [1,2,3].should include(3)
|
||||
# [1,2,3].should include(2,3) #would pass
|
||||
# [1,2,3].should include(2,3,4) #would fail
|
||||
# [1,2,3].should_not include(4)
|
||||
# "spread".should include("read")
|
||||
# "spread".should_not include("red")
|
||||
def include(*expected)
|
||||
Matchers::Include.new(*expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
41
vendor/plugins/rspec/lib/spec/matchers/match.rb
vendored
Normal file
41
vendor/plugins/rspec/lib/spec/matchers/match.rb
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class Match #:nodoc:
|
||||
def initialize(expected)
|
||||
@expected = expected
|
||||
end
|
||||
|
||||
def matches?(actual)
|
||||
@actual = actual
|
||||
return true if actual =~ @expected
|
||||
return false
|
||||
end
|
||||
|
||||
def failure_message
|
||||
return "expected #{@actual.inspect} to match #{@expected.inspect}", @expected, @actual
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
return "expected #{@actual.inspect} not to match #{@expected.inspect}", @expected, @actual
|
||||
end
|
||||
|
||||
def description
|
||||
"match #{@expected.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should match(regexp)
|
||||
# should_not match(regexp)
|
||||
#
|
||||
# Given a Regexp, passes if actual =~ regexp
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# email.should match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i)
|
||||
def match(regexp)
|
||||
Matchers::Match.new(regexp)
|
||||
end
|
||||
end
|
||||
end
|
||||
73
vendor/plugins/rspec/lib/spec/matchers/operator_matcher.rb
vendored
Executable file
73
vendor/plugins/rspec/lib/spec/matchers/operator_matcher.rb
vendored
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
class BaseOperatorMatcher
|
||||
attr_reader :generated_description
|
||||
|
||||
def initialize(target)
|
||||
@target = target
|
||||
end
|
||||
|
||||
def ==(expected)
|
||||
@expected = expected
|
||||
__delegate_method_missing_to_target("==", expected)
|
||||
end
|
||||
|
||||
def ===(expected)
|
||||
@expected = expected
|
||||
__delegate_method_missing_to_target("===", expected)
|
||||
end
|
||||
|
||||
def =~(expected)
|
||||
@expected = expected
|
||||
__delegate_method_missing_to_target("=~", expected)
|
||||
end
|
||||
|
||||
def >(expected)
|
||||
@expected = expected
|
||||
__delegate_method_missing_to_target(">", expected)
|
||||
end
|
||||
|
||||
def >=(expected)
|
||||
@expected = expected
|
||||
__delegate_method_missing_to_target(">=", expected)
|
||||
end
|
||||
|
||||
def <(expected)
|
||||
@expected = expected
|
||||
__delegate_method_missing_to_target("<", expected)
|
||||
end
|
||||
|
||||
def <=(expected)
|
||||
@expected = expected
|
||||
__delegate_method_missing_to_target("<=", expected)
|
||||
end
|
||||
|
||||
def fail_with_message(message)
|
||||
Spec::Expectations.fail_with(message, @expected, @target)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class PositiveOperatorMatcher < BaseOperatorMatcher #:nodoc:
|
||||
|
||||
def __delegate_method_missing_to_target(operator, expected)
|
||||
::Spec::Matchers.generated_description = "should #{operator} #{expected.inspect}"
|
||||
return if @target.send(operator, expected)
|
||||
return fail_with_message("expected: #{expected.inspect},\n got: #{@target.inspect} (using #{operator})") if ['==','===', '=~'].include?(operator)
|
||||
return fail_with_message("expected: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{@target.inspect}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class NegativeOperatorMatcher < BaseOperatorMatcher #:nodoc:
|
||||
|
||||
def __delegate_method_missing_to_target(operator, expected)
|
||||
::Spec::Matchers.generated_description = "should not #{operator} #{expected.inspect}"
|
||||
return unless @target.send(operator, expected)
|
||||
return fail_with_message("expected not: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{@target.inspect}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
132
vendor/plugins/rspec/lib/spec/matchers/raise_error.rb
vendored
Normal file
132
vendor/plugins/rspec/lib/spec/matchers/raise_error.rb
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
class RaiseError #:nodoc:
|
||||
def initialize(error_or_message=Exception, message=nil, &block)
|
||||
@block = block
|
||||
case error_or_message
|
||||
when String, Regexp
|
||||
@expected_error, @expected_message = Exception, error_or_message
|
||||
else
|
||||
@expected_error, @expected_message = error_or_message, message
|
||||
end
|
||||
end
|
||||
|
||||
def matches?(proc)
|
||||
@raised_expected_error = false
|
||||
@with_expected_message = false
|
||||
@eval_block = false
|
||||
@eval_block_passed = false
|
||||
begin
|
||||
proc.call
|
||||
rescue @expected_error => @actual_error
|
||||
@raised_expected_error = true
|
||||
@with_expected_message = verify_message
|
||||
rescue Exception => @actual_error
|
||||
# This clause should be empty, but rcov will not report it as covered
|
||||
# unless something (anything) is executed within the clause
|
||||
rcov_error_report = "http://eigenclass.org/hiki.rb?rcov-0.8.0"
|
||||
end
|
||||
|
||||
unless negative_expectation?
|
||||
eval_block if @raised_expected_error && @with_expected_message && @block
|
||||
end
|
||||
ensure
|
||||
return (@raised_expected_error && @with_expected_message) ? (@eval_block ? @eval_block_passed : true) : false
|
||||
end
|
||||
|
||||
def eval_block
|
||||
@eval_block = true
|
||||
begin
|
||||
@block[@actual_error]
|
||||
@eval_block_passed = true
|
||||
rescue Exception => err
|
||||
@actual_error = err
|
||||
end
|
||||
end
|
||||
|
||||
def verify_message
|
||||
case @expected_message
|
||||
when nil
|
||||
return true
|
||||
when Regexp
|
||||
return @expected_message =~ @actual_error.message
|
||||
else
|
||||
return @expected_message == @actual_error.message
|
||||
end
|
||||
end
|
||||
|
||||
def failure_message
|
||||
if @eval_block
|
||||
return @actual_error.message
|
||||
else
|
||||
return "expected #{expected_error}#{actual_error}"
|
||||
end
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"expected no #{expected_error}#{actual_error}"
|
||||
end
|
||||
|
||||
def description
|
||||
"raise #{expected_error}"
|
||||
end
|
||||
|
||||
private
|
||||
def expected_error
|
||||
case @expected_message
|
||||
when nil
|
||||
@expected_error
|
||||
when Regexp
|
||||
"#{@expected_error} with message matching #{@expected_message.inspect}"
|
||||
else
|
||||
"#{@expected_error} with #{@expected_message.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
def actual_error
|
||||
@actual_error.nil? ? " but nothing was raised" : ", got #{@actual_error.inspect}"
|
||||
end
|
||||
|
||||
def negative_expectation?
|
||||
# YES - I'm a bad person... help me find a better way - ryand
|
||||
caller.first(3).find { |s| s =~ /should_not/ }
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should raise_error()
|
||||
# should raise_error(NamedError)
|
||||
# should raise_error(NamedError, String)
|
||||
# should raise_error(NamedError, Regexp)
|
||||
# should raise_error() { |error| ... }
|
||||
# should raise_error(NamedError) { |error| ... }
|
||||
# should raise_error(NamedError, String) { |error| ... }
|
||||
# should raise_error(NamedError, Regexp) { |error| ... }
|
||||
# should_not raise_error()
|
||||
# should_not raise_error(NamedError)
|
||||
# should_not raise_error(NamedError, String)
|
||||
# should_not raise_error(NamedError, Regexp)
|
||||
#
|
||||
# With no args, matches if any error is raised.
|
||||
# With a named error, matches only if that specific error is raised.
|
||||
# With a named error and messsage specified as a String, matches only if both match.
|
||||
# With a named error and messsage specified as a Regexp, matches only if both match.
|
||||
# Pass an optional block to perform extra verifications on the exception matched
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# lambda { do_something_risky }.should raise_error
|
||||
# lambda { do_something_risky }.should raise_error(PoorRiskDecisionError)
|
||||
# lambda { do_something_risky }.should raise_error(PoorRiskDecisionError) { |error| error.data.should == 42 }
|
||||
# lambda { do_something_risky }.should raise_error(PoorRiskDecisionError, "that was too risky")
|
||||
# lambda { do_something_risky }.should raise_error(PoorRiskDecisionError, /oo ri/)
|
||||
#
|
||||
# lambda { do_something_risky }.should_not raise_error
|
||||
# lambda { do_something_risky }.should_not raise_error(PoorRiskDecisionError)
|
||||
# lambda { do_something_risky }.should_not raise_error(PoorRiskDecisionError, "that was too risky")
|
||||
# lambda { do_something_risky }.should_not raise_error(PoorRiskDecisionError, /oo ri/)
|
||||
def raise_error(error=Exception, message=nil, &block)
|
||||
Matchers::RaiseError.new(error, message, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
45
vendor/plugins/rspec/lib/spec/matchers/respond_to.rb
vendored
Normal file
45
vendor/plugins/rspec/lib/spec/matchers/respond_to.rb
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class RespondTo #:nodoc:
|
||||
def initialize(*names)
|
||||
@names = names
|
||||
@names_not_responded_to = []
|
||||
end
|
||||
|
||||
def matches?(target)
|
||||
@names.each do |name|
|
||||
unless target.respond_to?(name)
|
||||
@names_not_responded_to << name
|
||||
end
|
||||
end
|
||||
return @names_not_responded_to.empty?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"expected target to respond to #{@names_not_responded_to.collect {|name| name.inspect }.join(', ')}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"expected target not to respond to #{@names.collect {|name| name.inspect }.join(', ')}"
|
||||
end
|
||||
|
||||
def description
|
||||
"respond to ##{@names.to_s}"
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should respond_to(*names)
|
||||
# should_not respond_to(*names)
|
||||
#
|
||||
# Matches if the target object responds to all of the names
|
||||
# provided. Names can be Strings or Symbols.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
def respond_to(*names)
|
||||
Matchers::RespondTo.new(*names)
|
||||
end
|
||||
end
|
||||
end
|
||||
47
vendor/plugins/rspec/lib/spec/matchers/satisfy.rb
vendored
Normal file
47
vendor/plugins/rspec/lib/spec/matchers/satisfy.rb
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class Satisfy #:nodoc:
|
||||
def initialize(&block)
|
||||
@block = block
|
||||
end
|
||||
|
||||
def matches?(actual, &block)
|
||||
@block = block if block
|
||||
@actual = actual
|
||||
@block.call(actual)
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"expected #{@actual} to satisfy block"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"expected #{@actual} not to satisfy block"
|
||||
end
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should satisfy {}
|
||||
# should_not satisfy {}
|
||||
#
|
||||
# Passes if the submitted block returns true. Yields target to the
|
||||
# block.
|
||||
#
|
||||
# Generally speaking, this should be thought of as a last resort when
|
||||
# you can't find any other way to specify the behaviour you wish to
|
||||
# specify.
|
||||
#
|
||||
# If you do find yourself in such a situation, you could always write
|
||||
# a custom matcher, which would likely make your specs more expressive.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# 5.should satisfy { |n|
|
||||
# n > 3
|
||||
# }
|
||||
def satisfy(&block)
|
||||
Matchers::Satisfy.new(&block)
|
||||
end
|
||||
end
|
||||
end
|
||||
29
vendor/plugins/rspec/lib/spec/matchers/simple_matcher.rb
vendored
Normal file
29
vendor/plugins/rspec/lib/spec/matchers/simple_matcher.rb
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
class SimpleMatcher
|
||||
attr_reader :description
|
||||
|
||||
def initialize(description, &match_block)
|
||||
@description = description
|
||||
@match_block = match_block
|
||||
end
|
||||
|
||||
def matches?(actual)
|
||||
@actual = actual
|
||||
return @match_block.call(@actual)
|
||||
end
|
||||
|
||||
def failure_message()
|
||||
return %[expected #{@description.inspect} but got #{@actual.inspect}]
|
||||
end
|
||||
|
||||
def negative_failure_message()
|
||||
return %[expected not to get #{@description.inspect}, but got #{@actual.inspect}]
|
||||
end
|
||||
end
|
||||
|
||||
def simple_matcher(message, &match_block)
|
||||
SimpleMatcher.new(message, &match_block)
|
||||
end
|
||||
end
|
||||
end
|
||||
74
vendor/plugins/rspec/lib/spec/matchers/throw_symbol.rb
vendored
Normal file
74
vendor/plugins/rspec/lib/spec/matchers/throw_symbol.rb
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
module Spec
|
||||
module Matchers
|
||||
|
||||
class ThrowSymbol #:nodoc:
|
||||
def initialize(expected=nil)
|
||||
@expected = expected
|
||||
@actual = nil
|
||||
end
|
||||
|
||||
def matches?(proc)
|
||||
begin
|
||||
proc.call
|
||||
rescue NameError => e
|
||||
raise e unless e.message =~ /uncaught throw/
|
||||
@actual = e.name.to_sym
|
||||
ensure
|
||||
if @expected.nil?
|
||||
return @actual.nil? ? false : true
|
||||
else
|
||||
return @actual == @expected
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def failure_message
|
||||
if @actual
|
||||
"expected #{expected}, got #{@actual.inspect}"
|
||||
else
|
||||
"expected #{expected} but nothing was thrown"
|
||||
end
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
if @expected
|
||||
"expected #{expected} not to be thrown"
|
||||
else
|
||||
"expected no Symbol, got :#{@actual}"
|
||||
end
|
||||
end
|
||||
|
||||
def description
|
||||
"throw #{expected}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def expected
|
||||
@expected.nil? ? "a Symbol" : @expected.inspect
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# should throw_symbol()
|
||||
# should throw_symbol(:sym)
|
||||
# should_not throw_symbol()
|
||||
# should_not throw_symbol(:sym)
|
||||
#
|
||||
# Given a Symbol argument, matches if a proc throws the specified Symbol.
|
||||
#
|
||||
# Given no argument, matches if a proc throws any Symbol.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# lambda { do_something_risky }.should throw_symbol
|
||||
# lambda { do_something_risky }.should throw_symbol(:that_was_risky)
|
||||
#
|
||||
# lambda { do_something_risky }.should_not throw_symbol
|
||||
# lambda { do_something_risky }.should_not throw_symbol(:that_was_risky)
|
||||
def throw_symbol(sym=nil)
|
||||
Matchers::ThrowSymbol.new(sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
211
vendor/plugins/rspec/lib/spec/mocks.rb
vendored
Normal file
211
vendor/plugins/rspec/lib/spec/mocks.rb
vendored
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
require 'spec/mocks/framework'
|
||||
require 'spec/mocks/methods'
|
||||
require 'spec/mocks/argument_constraint_matchers'
|
||||
require 'spec/mocks/spec_methods'
|
||||
require 'spec/mocks/proxy'
|
||||
require 'spec/mocks/mock'
|
||||
require 'spec/mocks/argument_expectation'
|
||||
require 'spec/mocks/message_expectation'
|
||||
require 'spec/mocks/order_group'
|
||||
require 'spec/mocks/errors'
|
||||
require 'spec/mocks/error_generator'
|
||||
require 'spec/mocks/extensions/object'
|
||||
require 'spec/mocks/space'
|
||||
|
||||
module Spec
|
||||
# == Mocks and Stubs
|
||||
#
|
||||
# RSpec will create Mock Objects and Stubs for you at runtime, or attach stub/mock behaviour
|
||||
# to any of your real objects (Partial Mock/Stub). Because the underlying implementation
|
||||
# for mocks and stubs is the same, you can intermingle mock and stub
|
||||
# behaviour in either dynamically generated mocks or your pre-existing classes.
|
||||
# There is a semantic difference in how they are created, however,
|
||||
# which can help clarify the role it is playing within a given spec.
|
||||
#
|
||||
# == Mock Objects
|
||||
#
|
||||
# Mocks are objects that allow you to set and verify expectations that they will
|
||||
# receive specific messages during run time. They are very useful for specifying how the subject of
|
||||
# the spec interacts with its collaborators. This approach is widely known as "interaction
|
||||
# testing".
|
||||
#
|
||||
# Mocks are also very powerful as a design tool. As you are
|
||||
# driving the implementation of a given class, Mocks provide an anonymous
|
||||
# collaborator that can change in behaviour as quickly as you can write an expectation in your
|
||||
# spec. This flexibility allows you to design the interface of a collaborator that often
|
||||
# does not yet exist. As the shape of the class being specified becomes more clear, so do the
|
||||
# requirements for its collaborators - often leading to the discovery of new types that are
|
||||
# needed in your system.
|
||||
#
|
||||
# Read Endo-Testing[http://www.mockobjects.com/files/endotesting.pdf] for a much
|
||||
# more in depth description of this process.
|
||||
#
|
||||
# == Stubs
|
||||
#
|
||||
# Stubs are objects that allow you to set "stub" responses to
|
||||
# messages. As Martin Fowler points out on his site,
|
||||
# mocks_arent_stubs[http://www.martinfowler.com/articles/mocksArentStubs.html].
|
||||
# Paraphrasing Fowler's paraphrasing
|
||||
# of Gerard Meszaros: Stubs provide canned responses to messages they might receive in a test, while
|
||||
# mocks allow you to specify and, subsquently, verify that certain messages should be received during
|
||||
# the execution of a test.
|
||||
#
|
||||
# == Partial Mocks/Stubs
|
||||
#
|
||||
# RSpec also supports partial mocking/stubbing, allowing you to add stub/mock behaviour
|
||||
# to instances of your existing classes. This is generally
|
||||
# something to be avoided, because changes to the class can have ripple effects on
|
||||
# seemingly unrelated specs. When specs fail due to these ripple effects, the fact
|
||||
# that some methods are being mocked can make it difficult to understand why a
|
||||
# failure is occurring.
|
||||
#
|
||||
# That said, partials do allow you to expect and
|
||||
# verify interactions with class methods such as +#find+ and +#create+
|
||||
# on Ruby on Rails model classes.
|
||||
#
|
||||
# == Further Reading
|
||||
#
|
||||
# There are many different viewpoints about the meaning of mocks and stubs. If you are interested
|
||||
# in learning more, here is some recommended reading:
|
||||
#
|
||||
# * Mock Objects: http://www.mockobjects.com/
|
||||
# * Endo-Testing: http://www.mockobjects.com/files/endotesting.pdf
|
||||
# * Mock Roles, Not Objects: http://www.mockobjects.com/files/mockrolesnotobjects.pdf
|
||||
# * Test Double Patterns: http://xunitpatterns.com/Test%20Double%20Patterns.html
|
||||
# * Mocks aren't stubs: http://www.martinfowler.com/articles/mocksArentStubs.html
|
||||
#
|
||||
# == Creating a Mock
|
||||
#
|
||||
# You can create a mock in any specification (or setup) using:
|
||||
#
|
||||
# mock(name, options={})
|
||||
#
|
||||
# The optional +options+ argument is a +Hash+. Currently the only supported
|
||||
# option is +:null_object+. Setting this to true instructs the mock to ignore
|
||||
# any messages it hasn’t been told to expect – and quietly return itself. For example:
|
||||
#
|
||||
# mock("person", :null_object => true)
|
||||
#
|
||||
# == Creating a Stub
|
||||
#
|
||||
# You can create a stub in any specification (or setup) using:
|
||||
#
|
||||
# stub(name, stub_methods_and_values_hash)
|
||||
#
|
||||
# For example, if you wanted to create an object that always returns
|
||||
# "More?!?!?!" to "please_sir_may_i_have_some_more" you would do this:
|
||||
#
|
||||
# stub("Mr Sykes", :please_sir_may_i_have_some_more => "More?!?!?!")
|
||||
#
|
||||
# == Creating a Partial Mock
|
||||
#
|
||||
# You don't really "create" a partial mock, you simply add method stubs and/or
|
||||
# mock expectations to existing classes and objects:
|
||||
#
|
||||
# Factory.should_receive(:find).with(id).and_return(value)
|
||||
# obj.stub!(:to_i).and_return(3)
|
||||
# etc ...
|
||||
#
|
||||
# == Expecting Messages
|
||||
#
|
||||
# my_mock.should_receive(:sym)
|
||||
# my_mock.should_not_receive(:sym)
|
||||
#
|
||||
# == Expecting Arguments
|
||||
#
|
||||
# my_mock.should_receive(:sym).with(*args)
|
||||
# my_mock.should_not_receive(:sym).with(*args)
|
||||
#
|
||||
# == Argument Constraints using Expression Matchers
|
||||
#
|
||||
# Arguments that are passed to #with are compared with actual arguments received
|
||||
# using == by default. In cases in which you want to specify things about the arguments
|
||||
# rather than the arguments themselves, you can use any of the Expression Matchers.
|
||||
# They don't all make syntactic sense (they were primarily designed for use with
|
||||
# Spec::Expectations), but you are free to create your own custom Spec::Matchers.
|
||||
#
|
||||
# Spec::Mocks does provide one additional Matcher method named #ducktype.
|
||||
#
|
||||
# In addition, Spec::Mocks adds some keyword Symbols that you can use to
|
||||
# specify certain kinds of arguments:
|
||||
#
|
||||
# my_mock.should_receive(:sym).with(no_args())
|
||||
# my_mock.should_receive(:sym).with(any_args())
|
||||
# my_mock.should_receive(:sym).with(1, an_instance_of(Numeric), "b") #2nd argument can any type of Numeric
|
||||
# my_mock.should_receive(:sym).with(1, boolean(), "b") #2nd argument can true or false
|
||||
# my_mock.should_receive(:sym).with(1, /abc/, "b") #2nd argument can be any String matching the submitted Regexp
|
||||
# my_mock.should_receive(:sym).with(1, anything(), "b") #2nd argument can be anything at all
|
||||
# my_mock.should_receive(:sym).with(1, ducktype(:abs, :div), "b")
|
||||
# #2nd argument can be object that responds to #abs and #div
|
||||
#
|
||||
# == Receive Counts
|
||||
#
|
||||
# my_mock.should_receive(:sym).once
|
||||
# my_mock.should_receive(:sym).twice
|
||||
# my_mock.should_receive(:sym).exactly(n).times
|
||||
# my_mock.should_receive(:sym).at_least(:once)
|
||||
# my_mock.should_receive(:sym).at_least(:twice)
|
||||
# my_mock.should_receive(:sym).at_least(n).times
|
||||
# my_mock.should_receive(:sym).at_most(:once)
|
||||
# my_mock.should_receive(:sym).at_most(:twice)
|
||||
# my_mock.should_receive(:sym).at_most(n).times
|
||||
# my_mock.should_receive(:sym).any_number_of_times
|
||||
#
|
||||
# == Ordering
|
||||
#
|
||||
# my_mock.should_receive(:sym).ordered
|
||||
# my_mock.should_receive(:other_sym).ordered
|
||||
# #This will fail if the messages are received out of order
|
||||
#
|
||||
# == Setting Reponses
|
||||
#
|
||||
# Whether you are setting a mock expectation or a simple stub, you can tell the
|
||||
# object precisely how to respond:
|
||||
#
|
||||
# my_mock.should_receive(:sym).and_return(value)
|
||||
# my_mock.should_receive(:sym).exactly(3).times.and_return(value1, value2, value3)
|
||||
# # returns value1 the first time, value2 the second, etc
|
||||
# my_mock.should_receive(:sym).and_return { ... } #returns value returned by the block
|
||||
# my_mock.should_receive(:sym).and_raise(error)
|
||||
# #error can be an instantiated object or a class
|
||||
# #if it is a class, it must be instantiable with no args
|
||||
# my_mock.should_receive(:sym).and_throw(:sym)
|
||||
# my_mock.should_receive(:sym).and_yield(values,to,yield)
|
||||
# my_mock.should_receive(:sym).and_yield(values,to,yield).and_yield(some,other,values,this,time)
|
||||
# # for methods that yield to a block multiple times
|
||||
#
|
||||
# Any of these responses can be applied to a stub as well, but stubs do
|
||||
# not support any qualifiers about the message received (i.e. you can't specify arguments
|
||||
# or receive counts):
|
||||
#
|
||||
# my_mock.stub!(:sym).and_return(value)
|
||||
# my_mock.stub!(:sym).and_return(value1, value2, value3)
|
||||
# my_mock.stub!(:sym).and_raise(error)
|
||||
# my_mock.stub!(:sym).and_throw(:sym)
|
||||
# my_mock.stub!(:sym).and_yield(values,to,yield)
|
||||
# my_mock.stub!(:sym).and_yield(values,to,yield).and_yield(some,other,values,this,time)
|
||||
#
|
||||
# == Arbitrary Handling
|
||||
#
|
||||
# Once in a while you'll find that the available expectations don't solve the
|
||||
# particular problem you are trying to solve. Imagine that you expect the message
|
||||
# to come with an Array argument that has a specific length, but you don't care
|
||||
# what is in it. You could do this:
|
||||
#
|
||||
# my_mock.should_receive(:sym) do |arg|
|
||||
# arg.should be_an_istance_of(Array)
|
||||
# arg.length.should == 7
|
||||
# end
|
||||
#
|
||||
# Note that this would fail if the number of arguments received was different from
|
||||
# the number of block arguments (in this case 1).
|
||||
#
|
||||
# == Combining Expectation Details
|
||||
#
|
||||
# Combining the message name with specific arguments, receive counts and responses
|
||||
# you can get quite a bit of detail in your expectations:
|
||||
#
|
||||
# my_mock.should_receive(:<<).with("illegal value").once.and_raise(ArgumentError)
|
||||
module Mocks
|
||||
end
|
||||
end
|
||||
31
vendor/plugins/rspec/lib/spec/mocks/argument_constraint_matchers.rb
vendored
Normal file
31
vendor/plugins/rspec/lib/spec/mocks/argument_constraint_matchers.rb
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
module ArgumentConstraintMatchers
|
||||
|
||||
# Shortcut for creating an instance of Spec::Mocks::DuckTypeArgConstraint
|
||||
def duck_type(*args)
|
||||
DuckTypeArgConstraint.new(*args)
|
||||
end
|
||||
|
||||
def any_args
|
||||
AnyArgsConstraint.new
|
||||
end
|
||||
|
||||
def anything
|
||||
AnyArgConstraint.new(nil)
|
||||
end
|
||||
|
||||
def boolean
|
||||
BooleanArgConstraint.new(nil)
|
||||
end
|
||||
|
||||
def hash_including(expected={})
|
||||
HashIncludingConstraint.new(expected)
|
||||
end
|
||||
|
||||
def no_args
|
||||
NoArgsConstraint.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
216
vendor/plugins/rspec/lib/spec/mocks/argument_expectation.rb
vendored
Normal file
216
vendor/plugins/rspec/lib/spec/mocks/argument_expectation.rb
vendored
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
|
||||
class MatcherConstraint
|
||||
def initialize(matcher)
|
||||
@matcher = matcher
|
||||
end
|
||||
|
||||
def matches?(value)
|
||||
@matcher.matches?(value)
|
||||
end
|
||||
end
|
||||
|
||||
class LiteralArgConstraint
|
||||
def initialize(literal)
|
||||
@literal_value = literal
|
||||
end
|
||||
|
||||
def matches?(value)
|
||||
@literal_value == value
|
||||
end
|
||||
end
|
||||
|
||||
class RegexpArgConstraint
|
||||
def initialize(regexp)
|
||||
@regexp = regexp
|
||||
end
|
||||
|
||||
def matches?(value)
|
||||
return value =~ @regexp unless value.is_a?(Regexp)
|
||||
value == @regexp
|
||||
end
|
||||
end
|
||||
|
||||
class AnyArgConstraint
|
||||
def initialize(ignore)
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
true
|
||||
end
|
||||
|
||||
# TODO - need this?
|
||||
def matches?(value)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class AnyArgsConstraint
|
||||
def description
|
||||
"any args"
|
||||
end
|
||||
end
|
||||
|
||||
class NoArgsConstraint
|
||||
def description
|
||||
"no args"
|
||||
end
|
||||
|
||||
def ==(args)
|
||||
args == []
|
||||
end
|
||||
end
|
||||
|
||||
class NumericArgConstraint
|
||||
def initialize(ignore)
|
||||
end
|
||||
|
||||
def matches?(value)
|
||||
value.is_a?(Numeric)
|
||||
end
|
||||
end
|
||||
|
||||
class BooleanArgConstraint
|
||||
def initialize(ignore)
|
||||
end
|
||||
|
||||
def ==(value)
|
||||
matches?(value)
|
||||
end
|
||||
|
||||
def matches?(value)
|
||||
return true if value.is_a?(TrueClass)
|
||||
return true if value.is_a?(FalseClass)
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
class StringArgConstraint
|
||||
def initialize(ignore)
|
||||
end
|
||||
|
||||
def matches?(value)
|
||||
value.is_a?(String)
|
||||
end
|
||||
end
|
||||
|
||||
class DuckTypeArgConstraint
|
||||
def initialize(*methods_to_respond_to)
|
||||
@methods_to_respond_to = methods_to_respond_to
|
||||
end
|
||||
|
||||
def matches?(value)
|
||||
@methods_to_respond_to.all? { |sym| value.respond_to?(sym) }
|
||||
end
|
||||
|
||||
def description
|
||||
"duck_type"
|
||||
end
|
||||
end
|
||||
|
||||
class HashIncludingConstraint
|
||||
def initialize(expected)
|
||||
@expected = expected
|
||||
end
|
||||
|
||||
def ==(actual)
|
||||
@expected.each do | key, value |
|
||||
# check key for case that value evaluates to nil
|
||||
return false unless actual.has_key?(key) && actual[key] == value
|
||||
end
|
||||
true
|
||||
rescue NoMethodError => ex
|
||||
return false
|
||||
end
|
||||
|
||||
def matches?(value)
|
||||
self == value
|
||||
end
|
||||
|
||||
def description
|
||||
"hash_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
class ArgumentExpectation
|
||||
attr_reader :args
|
||||
@@constraint_classes = Hash.new { |hash, key| LiteralArgConstraint}
|
||||
@@constraint_classes[:anything] = AnyArgConstraint
|
||||
@@constraint_classes[:numeric] = NumericArgConstraint
|
||||
@@constraint_classes[:boolean] = BooleanArgConstraint
|
||||
@@constraint_classes[:string] = StringArgConstraint
|
||||
|
||||
def initialize(args, &block)
|
||||
@args = args
|
||||
@constraints_block = block
|
||||
|
||||
if [:any_args] == args
|
||||
@expected_params = nil
|
||||
warn_deprecated(:any_args.inspect, "any_args()")
|
||||
elsif args.length == 1 && args[0].is_a?(AnyArgsConstraint) then @expected_params = nil
|
||||
elsif [:no_args] == args
|
||||
@expected_params = []
|
||||
warn_deprecated(:no_args.inspect, "no_args()")
|
||||
elsif args.length == 1 && args[0].is_a?(NoArgsConstraint) then @expected_params = []
|
||||
else @expected_params = process_arg_constraints(args)
|
||||
end
|
||||
end
|
||||
|
||||
def process_arg_constraints(constraints)
|
||||
constraints.collect do |constraint|
|
||||
convert_constraint(constraint)
|
||||
end
|
||||
end
|
||||
|
||||
def warn_deprecated(deprecated_method, instead)
|
||||
Kernel.warn "The #{deprecated_method} constraint is deprecated. Use #{instead} instead."
|
||||
end
|
||||
|
||||
def convert_constraint(constraint)
|
||||
if [:anything, :numeric, :boolean, :string].include?(constraint)
|
||||
case constraint
|
||||
when :anything
|
||||
instead = "anything()"
|
||||
when :boolean
|
||||
instead = "boolean()"
|
||||
when :numeric
|
||||
instead = "an_instance_of(Numeric)"
|
||||
when :string
|
||||
instead = "an_instance_of(String)"
|
||||
end
|
||||
warn_deprecated(constraint.inspect, instead)
|
||||
return @@constraint_classes[constraint].new(constraint)
|
||||
end
|
||||
return MatcherConstraint.new(constraint) if is_matcher?(constraint)
|
||||
return RegexpArgConstraint.new(constraint) if constraint.is_a?(Regexp)
|
||||
return LiteralArgConstraint.new(constraint)
|
||||
end
|
||||
|
||||
def is_matcher?(obj)
|
||||
return obj.respond_to?(:matches?) && obj.respond_to?(:description)
|
||||
end
|
||||
|
||||
def check_args(args)
|
||||
if @constraints_block
|
||||
@constraints_block.call(*args)
|
||||
return true
|
||||
end
|
||||
|
||||
return true if @expected_params.nil?
|
||||
return true if @expected_params == args
|
||||
return constraints_match?(args)
|
||||
end
|
||||
|
||||
def constraints_match?(args)
|
||||
return false if args.length != @expected_params.length
|
||||
@expected_params.each_index { |i| return false unless @expected_params[i].matches?(args[i]) }
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
84
vendor/plugins/rspec/lib/spec/mocks/error_generator.rb
vendored
Normal file
84
vendor/plugins/rspec/lib/spec/mocks/error_generator.rb
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
class ErrorGenerator
|
||||
attr_writer :opts
|
||||
|
||||
def initialize(target, name)
|
||||
@target = target
|
||||
@name = name
|
||||
end
|
||||
|
||||
def opts
|
||||
@opts ||= {}
|
||||
end
|
||||
|
||||
def raise_unexpected_message_error(sym, *args)
|
||||
__raise "#{intro} received unexpected message :#{sym}#{arg_message(*args)}"
|
||||
end
|
||||
|
||||
def raise_unexpected_message_args_error(expectation, *args)
|
||||
expected_args = format_args(*expectation.expected_args)
|
||||
actual_args = args.empty? ? "(no args)" : format_args(*args)
|
||||
__raise "#{intro} expected #{expectation.sym.inspect} with #{expected_args} but received it with #{actual_args}"
|
||||
end
|
||||
|
||||
def raise_expectation_error(sym, expected_received_count, actual_received_count, *args)
|
||||
__raise "#{intro} expected :#{sym}#{arg_message(*args)} #{count_message(expected_received_count)}, but received it #{count_message(actual_received_count)}"
|
||||
end
|
||||
|
||||
def raise_out_of_order_error(sym)
|
||||
__raise "#{intro} received :#{sym} out of order"
|
||||
end
|
||||
|
||||
def raise_block_failed_error(sym, detail)
|
||||
__raise "#{intro} received :#{sym} but passed block failed with: #{detail}"
|
||||
end
|
||||
|
||||
def raise_missing_block_error(args_to_yield)
|
||||
__raise "#{intro} asked to yield |#{arg_list(*args_to_yield)}| but no block was passed"
|
||||
end
|
||||
|
||||
def raise_wrong_arity_error(args_to_yield, arity)
|
||||
__raise "#{intro} yielded |#{arg_list(*args_to_yield)}| to block with arity of #{arity}"
|
||||
end
|
||||
|
||||
private
|
||||
def intro
|
||||
@name ? "Mock '#{@name}'" : @target.inspect
|
||||
end
|
||||
|
||||
def __raise(message)
|
||||
message = opts[:message] unless opts[:message].nil?
|
||||
Kernel::raise(Spec::Mocks::MockExpectationError, message)
|
||||
end
|
||||
|
||||
def arg_message(*args)
|
||||
" with " + format_args(*args)
|
||||
end
|
||||
|
||||
def format_args(*args)
|
||||
return "(no args)" if args.empty? || args == [:no_args]
|
||||
return "(any args)" if args == [:any_args]
|
||||
"(" + arg_list(*args) + ")"
|
||||
end
|
||||
|
||||
def arg_list(*args)
|
||||
args.collect do |arg|
|
||||
arg.respond_to?(:description) ? arg.description : arg.inspect
|
||||
end.join(", ")
|
||||
end
|
||||
|
||||
def count_message(count)
|
||||
return "at least #{pretty_print(count.abs)}" if count < 0
|
||||
return pretty_print(count)
|
||||
end
|
||||
|
||||
def pretty_print(count)
|
||||
return "once" if count == 1
|
||||
return "twice" if count == 2
|
||||
return "#{count} times"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
10
vendor/plugins/rspec/lib/spec/mocks/errors.rb
vendored
Normal file
10
vendor/plugins/rspec/lib/spec/mocks/errors.rb
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
class MockExpectationError < StandardError
|
||||
end
|
||||
|
||||
class AmbiguousReturnError < StandardError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
1
vendor/plugins/rspec/lib/spec/mocks/extensions.rb
vendored
Normal file
1
vendor/plugins/rspec/lib/spec/mocks/extensions.rb
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
require 'spec/mocks/extensions/object'
|
||||
3
vendor/plugins/rspec/lib/spec/mocks/extensions/object.rb
vendored
Normal file
3
vendor/plugins/rspec/lib/spec/mocks/extensions/object.rb
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
class Object
|
||||
include Spec::Mocks::Methods
|
||||
end
|
||||
15
vendor/plugins/rspec/lib/spec/mocks/framework.rb
vendored
Normal file
15
vendor/plugins/rspec/lib/spec/mocks/framework.rb
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Require everything except the global extensions of class and object. This
|
||||
# supports wrapping rspec's mocking functionality without invading every
|
||||
# object in the system.
|
||||
|
||||
require 'spec/mocks/methods'
|
||||
require 'spec/mocks/argument_constraint_matchers'
|
||||
require 'spec/mocks/spec_methods'
|
||||
require 'spec/mocks/proxy'
|
||||
require 'spec/mocks/mock'
|
||||
require 'spec/mocks/argument_expectation'
|
||||
require 'spec/mocks/message_expectation'
|
||||
require 'spec/mocks/order_group'
|
||||
require 'spec/mocks/errors'
|
||||
require 'spec/mocks/error_generator'
|
||||
require 'spec/mocks/space'
|
||||
290
vendor/plugins/rspec/lib/spec/mocks/message_expectation.rb
vendored
Normal file
290
vendor/plugins/rspec/lib/spec/mocks/message_expectation.rb
vendored
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
|
||||
class BaseExpectation
|
||||
attr_reader :sym
|
||||
|
||||
def initialize(error_generator, expectation_ordering, expected_from, sym, method_block, expected_received_count=1, opts={})
|
||||
@error_generator = error_generator
|
||||
@error_generator.opts = opts
|
||||
@expected_from = expected_from
|
||||
@sym = sym
|
||||
@method_block = method_block
|
||||
@return_block = nil
|
||||
@actual_received_count = 0
|
||||
@expected_received_count = expected_received_count
|
||||
@args_expectation = ArgumentExpectation.new([AnyArgsConstraint.new])
|
||||
@consecutive = false
|
||||
@exception_to_raise = nil
|
||||
@symbol_to_throw = nil
|
||||
@order_group = expectation_ordering
|
||||
@at_least = nil
|
||||
@at_most = nil
|
||||
@args_to_yield = []
|
||||
end
|
||||
|
||||
def expected_args
|
||||
@args_expectation.args
|
||||
end
|
||||
|
||||
def and_return(*values, &return_block)
|
||||
Kernel::raise AmbiguousReturnError unless @method_block.nil?
|
||||
case values.size
|
||||
when 0 then value = nil
|
||||
when 1 then value = values[0]
|
||||
else
|
||||
value = values
|
||||
@consecutive = true
|
||||
@expected_received_count = values.size if !ignoring_args? &&
|
||||
@expected_received_count < values.size
|
||||
end
|
||||
@return_block = block_given? ? return_block : lambda { value }
|
||||
# Ruby 1.9 - see where this is used below
|
||||
@ignore_args = !block_given?
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# and_raise()
|
||||
# and_raise(Exception) #any exception class
|
||||
# and_raise(exception) #any exception object
|
||||
#
|
||||
# == Warning
|
||||
#
|
||||
# When you pass an exception class, the MessageExpectation will
|
||||
# raise an instance of it, creating it with +new+. If the exception
|
||||
# class initializer requires any parameters, you must pass in an
|
||||
# instance and not the class.
|
||||
def and_raise(exception=Exception)
|
||||
@exception_to_raise = exception
|
||||
end
|
||||
|
||||
def and_throw(symbol)
|
||||
@symbol_to_throw = symbol
|
||||
end
|
||||
|
||||
def and_yield(*args)
|
||||
@args_to_yield << args
|
||||
self
|
||||
end
|
||||
|
||||
def matches(sym, args)
|
||||
@sym == sym and @args_expectation.check_args(args)
|
||||
end
|
||||
|
||||
def invoke(args, block)
|
||||
if @expected_received_count == 0
|
||||
@actual_received_count += 1
|
||||
@error_generator.raise_expectation_error @sym, @expected_received_count, @actual_received_count, *args
|
||||
end
|
||||
|
||||
@order_group.handle_order_constraint self
|
||||
|
||||
begin
|
||||
Kernel::raise @exception_to_raise unless @exception_to_raise.nil?
|
||||
Kernel::throw @symbol_to_throw unless @symbol_to_throw.nil?
|
||||
|
||||
|
||||
if !@method_block.nil?
|
||||
default_return_val = invoke_method_block(args)
|
||||
elsif @args_to_yield.size > 0
|
||||
default_return_val = invoke_with_yield(block)
|
||||
else
|
||||
default_return_val = nil
|
||||
end
|
||||
|
||||
if @consecutive
|
||||
return invoke_consecutive_return_block(args, block)
|
||||
elsif @return_block
|
||||
return invoke_return_block(args, block)
|
||||
else
|
||||
return default_return_val
|
||||
end
|
||||
ensure
|
||||
@actual_received_count += 1
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def invoke_method_block(args)
|
||||
begin
|
||||
@method_block.call(*args)
|
||||
rescue => detail
|
||||
@error_generator.raise_block_failed_error @sym, detail.message
|
||||
end
|
||||
end
|
||||
|
||||
def invoke_with_yield(block)
|
||||
if block.nil?
|
||||
@error_generator.raise_missing_block_error @args_to_yield
|
||||
end
|
||||
value = nil
|
||||
@args_to_yield.each do |args_to_yield_this_time|
|
||||
if block.arity > -1 && args_to_yield_this_time.length != block.arity
|
||||
@error_generator.raise_wrong_arity_error args_to_yield_this_time, block.arity
|
||||
end
|
||||
value = block.call(*args_to_yield_this_time)
|
||||
end
|
||||
value
|
||||
end
|
||||
|
||||
def invoke_consecutive_return_block(args, block)
|
||||
args << block unless block.nil?
|
||||
value = @return_block.call(*args)
|
||||
|
||||
index = [@actual_received_count, value.size-1].min
|
||||
value[index]
|
||||
end
|
||||
|
||||
def invoke_return_block(args, block)
|
||||
args << block unless block.nil?
|
||||
# Ruby 1.9 - when we set @return_block to return values
|
||||
# regardless of arguments, any arguments will result in
|
||||
# a "wrong number of arguments" error
|
||||
if @ignore_args
|
||||
@return_block.call()
|
||||
else
|
||||
@return_block.call(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class MessageExpectation < BaseExpectation
|
||||
|
||||
def matches_name_but_not_args(sym, args)
|
||||
@sym == sym and not @args_expectation.check_args(args)
|
||||
end
|
||||
|
||||
def verify_messages_received
|
||||
return if expected_messages_received?
|
||||
|
||||
generate_error
|
||||
rescue Spec::Mocks::MockExpectationError => error
|
||||
error.backtrace.insert(0, @expected_from)
|
||||
Kernel::raise error
|
||||
end
|
||||
|
||||
def expected_messages_received?
|
||||
ignoring_args? || matches_exact_count? ||
|
||||
matches_at_least_count? || matches_at_most_count?
|
||||
end
|
||||
|
||||
def ignoring_args?
|
||||
@expected_received_count == :any
|
||||
end
|
||||
|
||||
def matches_at_least_count?
|
||||
@at_least && @actual_received_count >= @expected_received_count
|
||||
end
|
||||
|
||||
def matches_at_most_count?
|
||||
@at_most && @actual_received_count <= @expected_received_count
|
||||
end
|
||||
|
||||
def matches_exact_count?
|
||||
@expected_received_count == @actual_received_count
|
||||
end
|
||||
|
||||
def similar_messages
|
||||
@similar_messages ||= []
|
||||
end
|
||||
|
||||
def advise(args, block)
|
||||
similar_messages << args
|
||||
end
|
||||
|
||||
def generate_error
|
||||
if similar_messages.empty?
|
||||
@error_generator.raise_expectation_error(@sym, @expected_received_count, @actual_received_count, *@args_expectation.args)
|
||||
else
|
||||
@error_generator.raise_unexpected_message_args_error(self, *@similar_messages.first)
|
||||
end
|
||||
end
|
||||
|
||||
def with(*args, &block)
|
||||
@args_expectation = ArgumentExpectation.new(args, &block)
|
||||
self
|
||||
end
|
||||
|
||||
def exactly(n)
|
||||
set_expected_received_count :exactly, n
|
||||
self
|
||||
end
|
||||
|
||||
def at_least(n)
|
||||
set_expected_received_count :at_least, n
|
||||
self
|
||||
end
|
||||
|
||||
def at_most(n)
|
||||
set_expected_received_count :at_most, n
|
||||
self
|
||||
end
|
||||
|
||||
def times(&block)
|
||||
@method_block = block if block
|
||||
self
|
||||
end
|
||||
|
||||
def any_number_of_times(&block)
|
||||
@method_block = block if block
|
||||
@expected_received_count = :any
|
||||
self
|
||||
end
|
||||
|
||||
def never
|
||||
@expected_received_count = 0
|
||||
self
|
||||
end
|
||||
|
||||
def once(&block)
|
||||
@method_block = block if block
|
||||
@expected_received_count = 1
|
||||
self
|
||||
end
|
||||
|
||||
def twice(&block)
|
||||
@method_block = block if block
|
||||
@expected_received_count = 2
|
||||
self
|
||||
end
|
||||
|
||||
def ordered(&block)
|
||||
@method_block = block if block
|
||||
@order_group.register(self)
|
||||
@ordered = true
|
||||
self
|
||||
end
|
||||
|
||||
def negative_expectation_for?(sym)
|
||||
return false
|
||||
end
|
||||
|
||||
protected
|
||||
def set_expected_received_count(relativity, n)
|
||||
@at_least = (relativity == :at_least)
|
||||
@at_most = (relativity == :at_most)
|
||||
@expected_received_count = case n
|
||||
when Numeric
|
||||
n
|
||||
when :once
|
||||
1
|
||||
when :twice
|
||||
2
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class NegativeMessageExpectation < MessageExpectation
|
||||
def initialize(message, expectation_ordering, expected_from, sym, method_block)
|
||||
super(message, expectation_ordering, expected_from, sym, method_block, 0)
|
||||
end
|
||||
|
||||
def negative_expectation_for?(sym)
|
||||
return @sym == sym
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
39
vendor/plugins/rspec/lib/spec/mocks/methods.rb
vendored
Normal file
39
vendor/plugins/rspec/lib/spec/mocks/methods.rb
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
module Methods
|
||||
def should_receive(sym, opts={}, &block)
|
||||
__mock_proxy.add_message_expectation(opts[:expected_from] || caller(1)[0], sym.to_sym, opts, &block)
|
||||
end
|
||||
|
||||
def should_not_receive(sym, &block)
|
||||
__mock_proxy.add_negative_message_expectation(caller(1)[0], sym.to_sym, &block)
|
||||
end
|
||||
|
||||
def stub!(sym, opts={})
|
||||
__mock_proxy.add_stub(caller(1)[0], sym.to_sym, opts)
|
||||
end
|
||||
|
||||
def received_message?(sym, *args, &block) #:nodoc:
|
||||
__mock_proxy.received_message?(sym.to_sym, *args, &block)
|
||||
end
|
||||
|
||||
def rspec_verify #:nodoc:
|
||||
__mock_proxy.verify
|
||||
end
|
||||
|
||||
def rspec_reset #:nodoc:
|
||||
__mock_proxy.reset
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def __mock_proxy
|
||||
if Mock === self
|
||||
@mock_proxy ||= Proxy.new(self, @name, @options)
|
||||
else
|
||||
@mock_proxy ||= Proxy.new(self, self.class.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
56
vendor/plugins/rspec/lib/spec/mocks/mock.rb
vendored
Normal file
56
vendor/plugins/rspec/lib/spec/mocks/mock.rb
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
class Mock
|
||||
include Methods
|
||||
|
||||
# Creates a new mock with a +name+ (that will be used in error messages
|
||||
# only) == Options:
|
||||
# * <tt>:null_object</tt> - if true, the mock object acts as a forgiving
|
||||
# null object allowing any message to be sent to it.
|
||||
def initialize(name, stubs_and_options={})
|
||||
@name = name
|
||||
@options = parse_options(stubs_and_options)
|
||||
assign_stubs(stubs_and_options)
|
||||
end
|
||||
|
||||
# This allows for comparing the mock to other objects that proxy such as
|
||||
# ActiveRecords belongs_to proxy objects By making the other object run
|
||||
# the comparison, we're sure the call gets delegated to the proxy target
|
||||
# This is an unfortunate side effect from ActiveRecord, but this should
|
||||
# be safe unless the RHS redefines == in a nonsensical manner
|
||||
def ==(other)
|
||||
other == __mock_proxy
|
||||
end
|
||||
|
||||
def method_missing(sym, *args, &block)
|
||||
__mock_proxy.instance_eval {@messages_received << [sym, args, block]}
|
||||
begin
|
||||
return self if __mock_proxy.null_object?
|
||||
super(sym, *args, &block)
|
||||
rescue NameError
|
||||
__mock_proxy.raise_unexpected_message_error sym, *args
|
||||
end
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{self.class}:#{sprintf '0x%x', self.object_id} @name=#{@name.inspect}>"
|
||||
end
|
||||
|
||||
def to_s
|
||||
inspect.gsub('<','[').gsub('>',']')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_options(options)
|
||||
options.has_key?(:null_object) ? {:null_object => options.delete(:null_object)} : {}
|
||||
end
|
||||
|
||||
def assign_stubs(stubs)
|
||||
stubs.each_pair do |message, response|
|
||||
stub!(message).and_return(response)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
29
vendor/plugins/rspec/lib/spec/mocks/order_group.rb
vendored
Normal file
29
vendor/plugins/rspec/lib/spec/mocks/order_group.rb
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
class OrderGroup
|
||||
def initialize error_generator
|
||||
@error_generator = error_generator
|
||||
@ordering = Array.new
|
||||
end
|
||||
|
||||
def register(expectation)
|
||||
@ordering << expectation
|
||||
end
|
||||
|
||||
def ready_for?(expectation)
|
||||
return @ordering.first == expectation
|
||||
end
|
||||
|
||||
def consume
|
||||
@ordering.shift
|
||||
end
|
||||
|
||||
def handle_order_constraint expectation
|
||||
return unless @ordering.include? expectation
|
||||
return consume if ready_for?(expectation)
|
||||
@error_generator.raise_out_of_order_error expectation.sym
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
184
vendor/plugins/rspec/lib/spec/mocks/proxy.rb
vendored
Normal file
184
vendor/plugins/rspec/lib/spec/mocks/proxy.rb
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
class Proxy
|
||||
DEFAULT_OPTIONS = {
|
||||
:null_object => false,
|
||||
}
|
||||
|
||||
def initialize(target, name, options={})
|
||||
@target = target
|
||||
@name = name
|
||||
@error_generator = ErrorGenerator.new target, name
|
||||
@expectation_ordering = OrderGroup.new @error_generator
|
||||
@expectations = []
|
||||
@messages_received = []
|
||||
@stubs = []
|
||||
@proxied_methods = []
|
||||
@options = options ? DEFAULT_OPTIONS.dup.merge(options) : DEFAULT_OPTIONS
|
||||
end
|
||||
|
||||
def null_object?
|
||||
@options[:null_object]
|
||||
end
|
||||
|
||||
def add_message_expectation(expected_from, sym, opts={}, &block)
|
||||
__add sym
|
||||
@expectations << MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil, 1, opts)
|
||||
@expectations.last
|
||||
end
|
||||
|
||||
def add_negative_message_expectation(expected_from, sym, &block)
|
||||
__add sym
|
||||
@expectations << NegativeMessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil)
|
||||
@expectations.last
|
||||
end
|
||||
|
||||
def add_stub(expected_from, sym, opts={})
|
||||
__add sym
|
||||
@stubs.unshift MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, nil, :any, opts)
|
||||
@stubs.first
|
||||
end
|
||||
|
||||
def verify #:nodoc:
|
||||
verify_expectations
|
||||
ensure
|
||||
reset
|
||||
end
|
||||
|
||||
def reset
|
||||
clear_expectations
|
||||
clear_stubs
|
||||
reset_proxied_methods
|
||||
clear_proxied_methods
|
||||
end
|
||||
|
||||
def received_message?(sym, *args, &block)
|
||||
@messages_received.any? {|array| array == [sym, args, block]}
|
||||
end
|
||||
|
||||
def has_negative_expectation?(sym)
|
||||
@expectations.detect {|expectation| expectation.negative_expectation_for?(sym)}
|
||||
end
|
||||
|
||||
def message_received(sym, *args, &block)
|
||||
if expectation = find_matching_expectation(sym, *args)
|
||||
expectation.invoke(args, block)
|
||||
elsif (stub = find_matching_method_stub(sym, *args))
|
||||
if expectation = find_almost_matching_expectation(sym, *args)
|
||||
expectation.advise(args, block) unless expectation.expected_messages_received?
|
||||
end
|
||||
stub.invoke([], block)
|
||||
elsif expectation = find_almost_matching_expectation(sym, *args)
|
||||
expectation.advise(args, block) if null_object? unless expectation.expected_messages_received?
|
||||
raise_unexpected_message_args_error(expectation, *args) unless (has_negative_expectation?(sym) or null_object?)
|
||||
else
|
||||
@target.send :method_missing, sym, *args, &block
|
||||
end
|
||||
end
|
||||
|
||||
def raise_unexpected_message_args_error(expectation, *args)
|
||||
@error_generator.raise_unexpected_message_args_error expectation, *args
|
||||
end
|
||||
|
||||
def raise_unexpected_message_error(sym, *args)
|
||||
@error_generator.raise_unexpected_message_error sym, *args
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def __add(sym)
|
||||
$rspec_mocks.add(@target) unless $rspec_mocks.nil?
|
||||
define_expected_method(sym)
|
||||
end
|
||||
|
||||
def define_expected_method(sym)
|
||||
visibility_string = "#{visibility(sym)} :#{sym}"
|
||||
if target_responds_to?(sym) && !target_metaclass.method_defined?(munge(sym))
|
||||
munged_sym = munge(sym)
|
||||
target_metaclass.instance_eval do
|
||||
alias_method munged_sym, sym if method_defined?(sym.to_s)
|
||||
end
|
||||
@proxied_methods << sym
|
||||
end
|
||||
|
||||
target_metaclass.class_eval(<<-EOF, __FILE__, __LINE__)
|
||||
def #{sym}(*args, &block)
|
||||
__mock_proxy.message_received :#{sym}, *args, &block
|
||||
end
|
||||
#{visibility_string}
|
||||
EOF
|
||||
end
|
||||
|
||||
def target_responds_to?(sym)
|
||||
return @target.send(munge(:respond_to?),sym) if @already_proxied_respond_to
|
||||
return @already_proxied_respond_to = true if sym == :respond_to?
|
||||
return @target.respond_to?(sym)
|
||||
end
|
||||
|
||||
def visibility(sym)
|
||||
if Mock === @target
|
||||
'public'
|
||||
elsif target_metaclass.private_method_defined?(sym)
|
||||
'private'
|
||||
elsif target_metaclass.protected_method_defined?(sym)
|
||||
'protected'
|
||||
else
|
||||
'public'
|
||||
end
|
||||
end
|
||||
|
||||
def munge(sym)
|
||||
"proxied_by_rspec__#{sym.to_s}".to_sym
|
||||
end
|
||||
|
||||
def clear_expectations
|
||||
@expectations.clear
|
||||
end
|
||||
|
||||
def clear_stubs
|
||||
@stubs.clear
|
||||
end
|
||||
|
||||
def clear_proxied_methods
|
||||
@proxied_methods.clear
|
||||
end
|
||||
|
||||
def target_metaclass
|
||||
class << @target; self; end
|
||||
end
|
||||
|
||||
def verify_expectations
|
||||
@expectations.each do |expectation|
|
||||
expectation.verify_messages_received
|
||||
end
|
||||
end
|
||||
|
||||
def reset_proxied_methods
|
||||
@proxied_methods.each do |sym|
|
||||
munged_sym = munge(sym)
|
||||
target_metaclass.instance_eval do
|
||||
if method_defined?(munged_sym.to_s)
|
||||
alias_method sym, munged_sym
|
||||
undef_method munged_sym
|
||||
else
|
||||
undef_method sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def find_matching_expectation(sym, *args)
|
||||
@expectations.find {|expectation| expectation.matches(sym, args)}
|
||||
end
|
||||
|
||||
def find_almost_matching_expectation(sym, *args)
|
||||
@expectations.find {|expectation| expectation.matches_name_but_not_args(sym, args)}
|
||||
end
|
||||
|
||||
def find_matching_method_stub(sym, *args)
|
||||
@stubs.find {|stub| stub.matches(sym, args)}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
28
vendor/plugins/rspec/lib/spec/mocks/space.rb
vendored
Normal file
28
vendor/plugins/rspec/lib/spec/mocks/space.rb
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
class Space
|
||||
def add(obj)
|
||||
mocks << obj unless mocks.detect {|m| m.equal? obj}
|
||||
end
|
||||
|
||||
def verify_all
|
||||
mocks.each do |mock|
|
||||
mock.rspec_verify
|
||||
end
|
||||
end
|
||||
|
||||
def reset_all
|
||||
mocks.each do |mock|
|
||||
mock.rspec_reset
|
||||
end
|
||||
mocks.clear
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def mocks
|
||||
@mocks ||= []
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
38
vendor/plugins/rspec/lib/spec/mocks/spec_methods.rb
vendored
Normal file
38
vendor/plugins/rspec/lib/spec/mocks/spec_methods.rb
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
module Spec
|
||||
module Mocks
|
||||
module ExampleMethods
|
||||
include Spec::Mocks::ArgumentConstraintMatchers
|
||||
|
||||
# Shortcut for creating an instance of Spec::Mocks::Mock.
|
||||
#
|
||||
# +name+ is used for failure reporting, so you should use the
|
||||
# role that the mock is playing in the example.
|
||||
#
|
||||
# +stubs_and_options+ lets you assign options and stub values
|
||||
# at the same time. The only option available is :null_object.
|
||||
# Anything else is treated as a stub value.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# stub_thing = mock("thing", :a => "A")
|
||||
# stub_thing.a == "A" => true
|
||||
#
|
||||
# stub_person = stub("thing", :name => "Joe", :email => "joe@domain.com")
|
||||
# stub_person.name => "Joe"
|
||||
# stub_person.email => "joe@domain.com"
|
||||
def mock(name, stubs_and_options={})
|
||||
Spec::Mocks::Mock.new(name, stubs_and_options)
|
||||
end
|
||||
|
||||
alias :stub :mock
|
||||
|
||||
# Shortcut for creating a mock object that will return itself in response
|
||||
# to any message it receives that it hasn't been explicitly instructed
|
||||
# to respond to.
|
||||
def stub_everything(name = 'stub')
|
||||
mock(name, :null_object => true)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
227
vendor/plugins/rspec/lib/spec/rake/spectask.rb
vendored
Normal file
227
vendor/plugins/rspec/lib/spec/rake/spectask.rb
vendored
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# Define a task library for running RSpec contexts.
|
||||
|
||||
require 'rake'
|
||||
require 'rake/tasklib'
|
||||
|
||||
module Spec
|
||||
module Rake
|
||||
|
||||
# A Rake task that runs a set of specs.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# Spec::Rake::SpecTask.new do |t|
|
||||
# t.warning = true
|
||||
# t.rcov = true
|
||||
# end
|
||||
#
|
||||
# This will create a task that can be run with:
|
||||
#
|
||||
# rake spec
|
||||
#
|
||||
# If rake is invoked with a "SPEC=filename" command line option,
|
||||
# then the list of spec files will be overridden to include only the
|
||||
# filename specified on the command line. This provides an easy way
|
||||
# to run just one spec.
|
||||
#
|
||||
# If rake is invoked with a "SPEC_OPTS=options" command line option,
|
||||
# then the given options will override the value of the +spec_opts+
|
||||
# attribute.
|
||||
#
|
||||
# If rake is invoked with a "RCOV_OPTS=options" command line option,
|
||||
# then the given options will override the value of the +rcov_opts+
|
||||
# attribute.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# rake spec # run specs normally
|
||||
# rake spec SPEC=just_one_file.rb # run just one spec file.
|
||||
# rake spec SPEC_OPTS="--diff" # enable diffing
|
||||
# rake spec RCOV_OPTS="--aggregate myfile.txt" # see rcov --help for details
|
||||
#
|
||||
# Each attribute of this task may be a proc. This allows for lazy evaluation,
|
||||
# which is sometimes handy if you want to defer the evaluation of an attribute value
|
||||
# until the task is run (as opposed to when it is defined).
|
||||
#
|
||||
# This task can also be used to run existing Test::Unit tests and get RSpec
|
||||
# output, for example like this:
|
||||
#
|
||||
# require 'rubygems'
|
||||
# require 'spec/rake/spectask'
|
||||
# Spec::Rake::SpecTask.new do |t|
|
||||
# t.ruby_opts = ['-rtest/unit']
|
||||
# t.spec_files = FileList['test/**/*_test.rb']
|
||||
# end
|
||||
#
|
||||
class SpecTask < ::Rake::TaskLib
|
||||
class << self
|
||||
def attr_accessor(*names)
|
||||
super(*names)
|
||||
names.each do |name|
|
||||
module_eval "def #{name}() evaluate(@#{name}) end" # Allows use of procs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Name of spec task. (default is :spec)
|
||||
attr_accessor :name
|
||||
|
||||
# Array of directories to be added to $LOAD_PATH before running the
|
||||
# specs. Defaults to ['<the absolute path to RSpec's lib directory>']
|
||||
attr_accessor :libs
|
||||
|
||||
# If true, requests that the specs be run with the warning flag set.
|
||||
# E.g. warning=true implies "ruby -w" used to run the specs. Defaults to false.
|
||||
attr_accessor :warning
|
||||
|
||||
# Glob pattern to match spec files. (default is 'spec/**/*_spec.rb')
|
||||
# Setting the SPEC environment variable overrides this.
|
||||
attr_accessor :pattern
|
||||
|
||||
# Array of commandline options to pass to RSpec. Defaults to [].
|
||||
# Setting the SPEC_OPTS environment variable overrides this.
|
||||
attr_accessor :spec_opts
|
||||
|
||||
# Whether or not to use RCov (default is false)
|
||||
# See http://eigenclass.org/hiki.rb?rcov
|
||||
attr_accessor :rcov
|
||||
|
||||
# Array of commandline options to pass to RCov. Defaults to ['--exclude', 'lib\/spec,bin\/spec'].
|
||||
# Ignored if rcov=false
|
||||
# Setting the RCOV_OPTS environment variable overrides this.
|
||||
attr_accessor :rcov_opts
|
||||
|
||||
# Directory where the RCov report is written. Defaults to "coverage"
|
||||
# Ignored if rcov=false
|
||||
attr_accessor :rcov_dir
|
||||
|
||||
# Array of commandline options to pass to ruby. Defaults to [].
|
||||
attr_accessor :ruby_opts
|
||||
|
||||
# Whether or not to fail Rake when an error occurs (typically when specs fail).
|
||||
# Defaults to true.
|
||||
attr_accessor :fail_on_error
|
||||
|
||||
# A message to print to stderr when there are failures.
|
||||
attr_accessor :failure_message
|
||||
|
||||
# Where RSpec's output is written. Defaults to STDOUT.
|
||||
# DEPRECATED. Use --format FORMAT:WHERE in spec_opts.
|
||||
attr_accessor :out
|
||||
|
||||
# Explicitly define the list of spec files to be included in a
|
||||
# spec. +spec_files+ is expected to be an array of file names (a
|
||||
# FileList is acceptable). If both +pattern+ and +spec_files+ are
|
||||
# used, then the list of spec files is the union of the two.
|
||||
# Setting the SPEC environment variable overrides this.
|
||||
attr_accessor :spec_files
|
||||
|
||||
# Use verbose output. If this is set to true, the task will print
|
||||
# the executed spec command to stdout. Defaults to false.
|
||||
attr_accessor :verbose
|
||||
|
||||
# Defines a new task, using the name +name+.
|
||||
def initialize(name=:spec)
|
||||
@name = name
|
||||
@libs = [File.expand_path(File.dirname(__FILE__) + '/../../../lib')]
|
||||
@pattern = nil
|
||||
@spec_files = nil
|
||||
@spec_opts = []
|
||||
@warning = false
|
||||
@ruby_opts = []
|
||||
@fail_on_error = true
|
||||
@rcov = false
|
||||
@rcov_opts = ['--exclude', 'lib\/spec,bin\/spec,config\/boot.rb']
|
||||
@rcov_dir = "coverage"
|
||||
|
||||
yield self if block_given?
|
||||
@pattern = 'spec/**/*_spec.rb' if pattern.nil? && spec_files.nil?
|
||||
define
|
||||
end
|
||||
|
||||
def define # :nodoc:
|
||||
spec_script = File.expand_path(File.dirname(__FILE__) + '/../../../bin/spec')
|
||||
|
||||
lib_path = libs.join(File::PATH_SEPARATOR)
|
||||
actual_name = Hash === name ? name.keys.first : name
|
||||
unless ::Rake.application.last_comment
|
||||
desc "Run specs" + (rcov ? " using RCov" : "")
|
||||
end
|
||||
task name do
|
||||
RakeFileUtils.verbose(verbose) do
|
||||
unless spec_file_list.empty?
|
||||
# ruby [ruby_opts] -Ilib -S rcov [rcov_opts] bin/spec -- examples [spec_opts]
|
||||
# or
|
||||
# ruby [ruby_opts] -Ilib bin/spec examples [spec_opts]
|
||||
cmd_parts = [RUBY]
|
||||
cmd_parts += ruby_opts
|
||||
cmd_parts << %[-I"#{lib_path}"]
|
||||
cmd_parts << "-S rcov" if rcov
|
||||
cmd_parts << "-w" if warning
|
||||
cmd_parts << rcov_option_list
|
||||
cmd_parts << %[-o "#{rcov_dir}"] if rcov
|
||||
cmd_parts << %["#{spec_script}"]
|
||||
cmd_parts << "--" if rcov
|
||||
cmd_parts += spec_file_list.collect { |fn| %["#{fn}"] }
|
||||
cmd_parts << spec_option_list
|
||||
if out
|
||||
cmd_parts << %[> "#{out}"]
|
||||
STDERR.puts "The Spec::Rake::SpecTask#out attribute is DEPRECATED and will be removed in a future version. Use --format FORMAT:WHERE instead."
|
||||
end
|
||||
cmd = cmd_parts.join(" ")
|
||||
puts cmd if verbose
|
||||
unless system(cmd)
|
||||
STDERR.puts failure_message if failure_message
|
||||
raise("Command #{cmd} failed") if fail_on_error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if rcov
|
||||
desc "Remove rcov products for #{actual_name}"
|
||||
task paste("clobber_", actual_name) do
|
||||
rm_r rcov_dir rescue nil
|
||||
end
|
||||
|
||||
clobber_task = paste("clobber_", actual_name)
|
||||
task :clobber => [clobber_task]
|
||||
|
||||
task actual_name => clobber_task
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def rcov_option_list # :nodoc:
|
||||
return "" unless rcov
|
||||
ENV['RCOV_OPTS'] || rcov_opts.join(" ") || ""
|
||||
end
|
||||
|
||||
def spec_option_list # :nodoc:
|
||||
STDERR.puts "RSPECOPTS is DEPRECATED and will be removed in a future version. Use SPEC_OPTS instead." if ENV['RSPECOPTS']
|
||||
ENV['SPEC_OPTS'] || ENV['RSPECOPTS'] || spec_opts.join(" ") || ""
|
||||
end
|
||||
|
||||
def evaluate(o) # :nodoc:
|
||||
case o
|
||||
when Proc then o.call
|
||||
else o
|
||||
end
|
||||
end
|
||||
|
||||
def spec_file_list # :nodoc:
|
||||
if ENV['SPEC']
|
||||
FileList[ ENV['SPEC'] ]
|
||||
else
|
||||
result = []
|
||||
result += spec_files.to_a if spec_files
|
||||
result += FileList[ pattern ].to_a if pattern
|
||||
FileList[result]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
52
vendor/plugins/rspec/lib/spec/rake/verify_rcov.rb
vendored
Normal file
52
vendor/plugins/rspec/lib/spec/rake/verify_rcov.rb
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
module RCov
|
||||
# A task that can verify that the RCov coverage doesn't
|
||||
# drop below a certain threshold. It should be run after
|
||||
# running Spec::Rake::SpecTask.
|
||||
class VerifyTask < Rake::TaskLib
|
||||
# Name of the task. Defaults to :verify_rcov
|
||||
attr_accessor :name
|
||||
|
||||
# Path to the index.html file generated by RCov, which
|
||||
# is the file containing the total coverage.
|
||||
# Defaults to 'coverage/index.html'
|
||||
attr_accessor :index_html
|
||||
|
||||
# Whether or not to output details. Defaults to true.
|
||||
attr_accessor :verbose
|
||||
|
||||
# The threshold value (in percent) for coverage. If the
|
||||
# actual coverage is not equal to this value, the task will raise an
|
||||
# exception.
|
||||
attr_accessor :threshold
|
||||
|
||||
# Require the threshold value be met exactly. This is the default.
|
||||
attr_accessor :require_exact_threshold
|
||||
|
||||
def initialize(name=:verify_rcov)
|
||||
@name = name
|
||||
@index_html = 'coverage/index.html'
|
||||
@verbose = true
|
||||
@require_exact_threshold = true
|
||||
yield self if block_given?
|
||||
raise "Threshold must be set" if @threshold.nil?
|
||||
define
|
||||
end
|
||||
|
||||
def define
|
||||
desc "Verify that rcov coverage is at least #{threshold}%"
|
||||
task @name do
|
||||
total_coverage = nil
|
||||
|
||||
File.open(index_html).each_line do |line|
|
||||
if line =~ /<tt class='coverage_total'>(\d+\.\d+)%<\/tt>/
|
||||
total_coverage = eval($1)
|
||||
break
|
||||
end
|
||||
end
|
||||
puts "Coverage: #{total_coverage}% (threshold: #{threshold}%)" if verbose
|
||||
raise "Coverage must be at least #{threshold}% but was #{total_coverage}%" if total_coverage < threshold
|
||||
raise "Coverage has increased above the threshold of #{threshold}% to #{total_coverage}%. You should update your threshold value." if (total_coverage > threshold) and require_exact_threshold
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
201
vendor/plugins/rspec/lib/spec/runner.rb
vendored
Normal file
201
vendor/plugins/rspec/lib/spec/runner.rb
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
require 'spec/runner/options'
|
||||
require 'spec/runner/option_parser'
|
||||
require 'spec/runner/example_group_runner'
|
||||
require 'spec/runner/command_line'
|
||||
require 'spec/runner/drb_command_line'
|
||||
require 'spec/runner/backtrace_tweaker'
|
||||
require 'spec/runner/reporter'
|
||||
require 'spec/runner/spec_parser'
|
||||
require 'spec/runner/class_and_arguments_parser'
|
||||
|
||||
module Spec
|
||||
# == ExampleGroups and Examples
|
||||
#
|
||||
# Rather than expressing examples in classes, RSpec uses a custom DSLL (DSL light) to
|
||||
# describe groups of examples.
|
||||
#
|
||||
# A ExampleGroup is the equivalent of a fixture in xUnit-speak. It is a metaphor for the context
|
||||
# in which you will run your executable example - a set of known objects in a known starting state.
|
||||
# We begin be describing
|
||||
#
|
||||
# describe Account do
|
||||
#
|
||||
# before do
|
||||
# @account = Account.new
|
||||
# end
|
||||
#
|
||||
# it "should have a balance of $0" do
|
||||
# @account.balance.should == Money.new(0, :dollars)
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# We use the before block to set up the Example (given), and then the #it method to
|
||||
# hold the example code that expresses the event (when) and the expected outcome (then).
|
||||
#
|
||||
# == Helper Methods
|
||||
#
|
||||
# A primary goal of RSpec is to keep the examples clear. We therefore prefer
|
||||
# less indirection than you might see in xUnit examples and in well factored, DRY production code. We feel
|
||||
# that duplication is OK if removing it makes it harder to understand an example without
|
||||
# having to look elsewhere to understand its context.
|
||||
#
|
||||
# That said, RSpec does support some level of encapsulating common code in helper
|
||||
# methods that can exist within a context or within an included module.
|
||||
#
|
||||
# == Setup and Teardown
|
||||
#
|
||||
# You can use before and after within a Example. Both methods take an optional
|
||||
# scope argument so you can run the block before :each example or before :all examples
|
||||
#
|
||||
# describe "..." do
|
||||
# before :all do
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# before :each do
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# it "should do something" do
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# it "should do something else" do
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# after :each do
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# after :all do
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# The <tt>before :each</tt> block will run before each of the examples, once for each example. Likewise,
|
||||
# the <tt>after :each</tt> block will run after each of the examples.
|
||||
#
|
||||
# It is also possible to specify a <tt>before :all</tt> and <tt>after :all</tt>
|
||||
# block that will run only once for each behaviour, respectively before the first <code>before :each</code>
|
||||
# and after the last <code>after :each</code>. The use of these is generally discouraged, because it
|
||||
# introduces dependencies between the examples. Still, it might prove useful for very expensive operations
|
||||
# if you know what you are doing.
|
||||
#
|
||||
# == Local helper methods
|
||||
#
|
||||
# You can include local helper methods by simply expressing them within a context:
|
||||
#
|
||||
# describe "..." do
|
||||
#
|
||||
# it "..." do
|
||||
# helper_method
|
||||
# end
|
||||
#
|
||||
# def helper_method
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# == Included helper methods
|
||||
#
|
||||
# You can include helper methods in multiple contexts by expressing them within
|
||||
# a module, and then including that module in your context:
|
||||
#
|
||||
# module AccountExampleHelperMethods
|
||||
# def helper_method
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# describe "A new account" do
|
||||
# include AccountExampleHelperMethods
|
||||
# before do
|
||||
# @account = Account.new
|
||||
# end
|
||||
#
|
||||
# it "should have a balance of $0" do
|
||||
# helper_method
|
||||
# @account.balance.should eql(Money.new(0, :dollars))
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# == Shared Example Groups
|
||||
#
|
||||
# You can define a shared Example Group, that may be used on other groups
|
||||
#
|
||||
# share_examples_for "All Editions" do
|
||||
# it "all editions behaviour" ...
|
||||
# end
|
||||
#
|
||||
# describe SmallEdition do
|
||||
# it_should_behave_like "All Editions"
|
||||
#
|
||||
# it "should do small edition stuff" do
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# You can also assign the shared group to a module and include that
|
||||
#
|
||||
# share_as :AllEditions do
|
||||
# it "should do all editions stuff" ...
|
||||
# end
|
||||
#
|
||||
# describe SmallEdition do
|
||||
# it_should_behave_like AllEditions
|
||||
#
|
||||
# it "should do small edition stuff" do
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# And, for those of you who prefer to use something more like Ruby, you
|
||||
# can just include the module directly
|
||||
#
|
||||
# describe SmallEdition do
|
||||
# include AllEditions
|
||||
#
|
||||
# it "should do small edition stuff" do
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
module Runner
|
||||
class << self
|
||||
def configuration # :nodoc:
|
||||
@configuration ||= Spec::Example::Configuration.new
|
||||
end
|
||||
|
||||
# Use this to configure various configurable aspects of
|
||||
# RSpec:
|
||||
#
|
||||
# Spec::Runner.configure do |configuration|
|
||||
# # Configure RSpec here
|
||||
# end
|
||||
#
|
||||
# The yielded <tt>configuration</tt> object is a
|
||||
# Spec::Example::Configuration instance. See its RDoc
|
||||
# for details about what you can do with it.
|
||||
#
|
||||
def configure
|
||||
yield configuration
|
||||
end
|
||||
|
||||
def register_at_exit_hook # :nodoc:
|
||||
$spec_runner_at_exit_hook_registered ||= nil
|
||||
unless $spec_runner_at_exit_hook_registered
|
||||
at_exit do
|
||||
unless $! || Spec.run?
|
||||
success = Spec.run
|
||||
exit success if Spec.exit?
|
||||
end
|
||||
end
|
||||
$spec_runner_at_exit_hook_registered = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
57
vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb
vendored
Normal file
57
vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class BacktraceTweaker
|
||||
def clean_up_double_slashes(line)
|
||||
line.gsub!('//','/')
|
||||
end
|
||||
end
|
||||
|
||||
class NoisyBacktraceTweaker < BacktraceTweaker
|
||||
def tweak_backtrace(error)
|
||||
return if error.backtrace.nil?
|
||||
error.backtrace.each do |line|
|
||||
clean_up_double_slashes(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Tweaks raised Exceptions to mask noisy (unneeded) parts of the backtrace
|
||||
class QuietBacktraceTweaker < BacktraceTweaker
|
||||
unless defined?(IGNORE_PATTERNS)
|
||||
root_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', '..'))
|
||||
spec_files = Dir["#{root_dir}/lib/*"].map do |path|
|
||||
subpath = path[root_dir.length..-1]
|
||||
/#{subpath}/
|
||||
end
|
||||
IGNORE_PATTERNS = spec_files + [
|
||||
/\/lib\/ruby\//,
|
||||
/bin\/spec:/,
|
||||
/bin\/rcov:/,
|
||||
/lib\/rspec-rails/,
|
||||
/vendor\/rails/,
|
||||
# TextMate's Ruby and RSpec plugins
|
||||
/Ruby\.tmbundle\/Support\/tmruby.rb:/,
|
||||
/RSpec\.tmbundle\/Support\/lib/,
|
||||
/temp_textmate\./,
|
||||
/mock_frameworks\/rspec/,
|
||||
/spec_server/
|
||||
]
|
||||
end
|
||||
|
||||
def tweak_backtrace(error)
|
||||
return if error.backtrace.nil?
|
||||
error.backtrace.collect! do |line|
|
||||
clean_up_double_slashes(line)
|
||||
IGNORE_PATTERNS.each do |ignore|
|
||||
if line =~ ignore
|
||||
line = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
line
|
||||
end
|
||||
error.backtrace.compact!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
16
vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb
vendored
Normal file
16
vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class ClassAndArgumentsParser
|
||||
class << self
|
||||
def parse(s)
|
||||
if s =~ /([a-zA-Z_]+(?:::[a-zA-Z_]+)*):?(.*)/
|
||||
arg = $2 == "" ? nil : $2
|
||||
[$1, arg]
|
||||
else
|
||||
raise "Couldn't parse #{s.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
28
vendor/plugins/rspec/lib/spec/runner/command_line.rb
vendored
Normal file
28
vendor/plugins/rspec/lib/spec/runner/command_line.rb
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
require 'spec/runner/option_parser'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
# Facade to run specs without having to fork a new ruby process (using `spec ...`)
|
||||
class CommandLine
|
||||
class << self
|
||||
# Runs specs. +argv+ is the commandline args as per the spec commandline API, +err+
|
||||
# and +out+ are the streams output will be written to.
|
||||
def run(instance_rspec_options)
|
||||
# NOTE - this call to init_rspec_options is not spec'd, but neither is any of this
|
||||
# swapping of $rspec_options. That is all here to enable rspec to run against itself
|
||||
# and maintain coverage in a single process. Therefore, DO NOT mess with this stuff
|
||||
# unless you know what you are doing!
|
||||
init_rspec_options(instance_rspec_options)
|
||||
orig_rspec_options = rspec_options
|
||||
begin
|
||||
$rspec_options = instance_rspec_options
|
||||
return $rspec_options.run_examples
|
||||
ensure
|
||||
::Spec.run = true
|
||||
$rspec_options = orig_rspec_options
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
20
vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb
vendored
Normal file
20
vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
require "drb/drb"
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
# Facade to run specs by connecting to a DRB server
|
||||
class DrbCommandLine
|
||||
# Runs specs on a DRB server. Note that this API is similar to that of
|
||||
# CommandLine - making it possible for clients to use both interchangeably.
|
||||
def self.run(options)
|
||||
begin
|
||||
DRb.start_service
|
||||
spec_server = DRbObject.new_with_uri("druby://127.0.0.1:8989")
|
||||
spec_server.run(options.argv, options.error_stream, options.output_stream)
|
||||
rescue DRb::DRbConnError => e
|
||||
options.error_stream.puts "No server is running"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
59
vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb
vendored
Normal file
59
vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class ExampleGroupRunner
|
||||
def initialize(options)
|
||||
@options = options
|
||||
end
|
||||
|
||||
def load_files(files)
|
||||
# It's important that loading files (or choosing not to) stays the
|
||||
# responsibility of the ExampleGroupRunner. Some implementations (like)
|
||||
# the one using DRb may choose *not* to load files, but instead tell
|
||||
# someone else to do it over the wire.
|
||||
files.each do |file|
|
||||
load file
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
prepare
|
||||
success = true
|
||||
example_groups.each do |example_group|
|
||||
success = success & example_group.run
|
||||
end
|
||||
return success
|
||||
ensure
|
||||
finish
|
||||
end
|
||||
|
||||
protected
|
||||
def prepare
|
||||
reporter.start(number_of_examples)
|
||||
example_groups.reverse! if reverse
|
||||
end
|
||||
|
||||
def finish
|
||||
reporter.end
|
||||
reporter.dump
|
||||
end
|
||||
|
||||
def reporter
|
||||
@options.reporter
|
||||
end
|
||||
|
||||
def reverse
|
||||
@options.reverse
|
||||
end
|
||||
|
||||
def example_groups
|
||||
@options.example_groups
|
||||
end
|
||||
|
||||
def number_of_examples
|
||||
@options.number_of_examples
|
||||
end
|
||||
end
|
||||
# TODO: BT - Deprecate BehaviourRunner?
|
||||
BehaviourRunner = ExampleGroupRunner
|
||||
end
|
||||
end
|
||||
77
vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb
vendored
Normal file
77
vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
# Baseclass for formatters that implements all required methods as no-ops.
|
||||
class BaseFormatter
|
||||
attr_accessor :example_group, :options, :where
|
||||
def initialize(options, where)
|
||||
@options = options
|
||||
@where = where
|
||||
end
|
||||
|
||||
# This method is invoked before any examples are run, right after
|
||||
# they have all been collected. This can be useful for special
|
||||
# formatters that need to provide progress on feedback (graphical ones)
|
||||
#
|
||||
# This method will only be invoked once, and the next one to be invoked
|
||||
# is #add_example_group
|
||||
def start(example_count)
|
||||
end
|
||||
|
||||
# This method is invoked at the beginning of the execution of each example_group.
|
||||
# +example_group+ is the example_group.
|
||||
#
|
||||
# The next method to be invoked after this is #example_failed or #example_finished
|
||||
def add_example_group(example_group)
|
||||
@example_group = example_group
|
||||
end
|
||||
|
||||
# This method is invoked when an +example+ starts.
|
||||
def example_started(example)
|
||||
end
|
||||
|
||||
# This method is invoked when an +example+ passes.
|
||||
def example_passed(example)
|
||||
end
|
||||
|
||||
# This method is invoked when an +example+ fails, i.e. an exception occurred
|
||||
# inside it (such as a failed should or other exception). +counter+ is the
|
||||
# sequence number of the failure (starting at 1) and +failure+ is the associated
|
||||
# Failure object.
|
||||
def example_failed(example, counter, failure)
|
||||
end
|
||||
|
||||
# This method is invoked when an example is not yet implemented (i.e. has not
|
||||
# been provided a block), or when an ExamplePendingError is raised.
|
||||
# +message+ is the message from the ExamplePendingError, if it exists, or the
|
||||
# default value of "Not Yet Implemented"
|
||||
def example_pending(example, message)
|
||||
end
|
||||
|
||||
# This method is invoked after all of the examples have executed. The next method
|
||||
# to be invoked after this one is #dump_failure (once for each failed example),
|
||||
def start_dump
|
||||
end
|
||||
|
||||
# Dumps detailed information about an example failure.
|
||||
# This method is invoked for each failed example after all examples have run. +counter+ is the sequence number
|
||||
# of the associated example. +failure+ is a Failure object, which contains detailed
|
||||
# information about the failure.
|
||||
def dump_failure(counter, failure)
|
||||
end
|
||||
|
||||
# This method is invoked after the dumping of examples and failures.
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
end
|
||||
|
||||
# This gets invoked after the summary if option is set to do so.
|
||||
def dump_pending
|
||||
end
|
||||
|
||||
# This method is invoked at the very end. Allows the formatter to clean up, like closing open streams.
|
||||
def close
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
130
vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb
vendored
Normal file
130
vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
require 'spec/runner/formatter/base_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
# Baseclass for text-based formatters. Can in fact be used for
|
||||
# non-text based ones too - just ignore the +output+ constructor
|
||||
# argument.
|
||||
class BaseTextFormatter < BaseFormatter
|
||||
attr_reader :output, :pending_examples
|
||||
# Creates a new instance that will write to +where+. If +where+ is a
|
||||
# String, output will be written to the File with that name, otherwise
|
||||
# +where+ is exected to be an IO (or an object that responds to #puts and #write).
|
||||
def initialize(options, where)
|
||||
super
|
||||
if where.is_a?(String)
|
||||
@output = File.open(where, 'w')
|
||||
elsif where == STDOUT
|
||||
@output = Kernel
|
||||
def @output.flush
|
||||
STDOUT.flush
|
||||
end
|
||||
else
|
||||
@output = where
|
||||
end
|
||||
@pending_examples = []
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
@pending_examples << [example.__full_description, message]
|
||||
end
|
||||
|
||||
def dump_failure(counter, failure)
|
||||
@output.puts
|
||||
@output.puts "#{counter.to_s})"
|
||||
@output.puts colourise("#{failure.header}\n#{failure.exception.message}", failure)
|
||||
@output.puts format_backtrace(failure.exception.backtrace)
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def colourise(s, failure)
|
||||
if(failure.expectation_not_met?)
|
||||
red(s)
|
||||
elsif(failure.pending_fixed?)
|
||||
blue(s)
|
||||
else
|
||||
magenta(s)
|
||||
end
|
||||
end
|
||||
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
return if dry_run?
|
||||
@output.puts
|
||||
@output.puts "Finished in #{duration} seconds"
|
||||
@output.puts
|
||||
|
||||
summary = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
|
||||
summary << ", #{pending_count} pending" if pending_count > 0
|
||||
|
||||
if failure_count == 0
|
||||
if pending_count > 0
|
||||
@output.puts yellow(summary)
|
||||
else
|
||||
@output.puts green(summary)
|
||||
end
|
||||
else
|
||||
@output.puts red(summary)
|
||||
end
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def dump_pending
|
||||
unless @pending_examples.empty?
|
||||
@output.puts
|
||||
@output.puts "Pending:"
|
||||
@pending_examples.each do |pending_example|
|
||||
@output.puts "#{pending_example[0]} (#{pending_example[1]})"
|
||||
end
|
||||
end
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def close
|
||||
if IO === @output
|
||||
@output.close
|
||||
end
|
||||
end
|
||||
|
||||
def format_backtrace(backtrace)
|
||||
return "" if backtrace.nil?
|
||||
backtrace.map { |line| backtrace_line(line) }.join("\n")
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def colour?
|
||||
@options.colour ? true : false
|
||||
end
|
||||
|
||||
def dry_run?
|
||||
@options.dry_run ? true : false
|
||||
end
|
||||
|
||||
def backtrace_line(line)
|
||||
line.sub(/\A([^:]+:\d+)$/, '\\1:')
|
||||
end
|
||||
|
||||
def colour(text, colour_code)
|
||||
return text unless colour? && output_to_tty?
|
||||
"#{colour_code}#{text}\e[0m"
|
||||
end
|
||||
|
||||
def output_to_tty?
|
||||
begin
|
||||
@output == Kernel || @output.tty?
|
||||
rescue NoMethodError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def green(text); colour(text, "\e[32m"); end
|
||||
def red(text); colour(text, "\e[31m"); end
|
||||
def magenta(text); colour(text, "\e[35m"); end
|
||||
def yellow(text); colour(text, "\e[33m"); end
|
||||
def blue(text); colour(text, "\e[34m"); end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
27
vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb
vendored
Normal file
27
vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class FailingExampleGroupsFormatter < BaseTextFormatter
|
||||
def example_failed(example, counter, failure)
|
||||
if @example_group
|
||||
description_parts = @example_group.description_parts.collect do |description|
|
||||
description =~ /(.*) \(druby.*\)$/ ? $1 : description
|
||||
end
|
||||
@output.puts ::Spec::Example::ExampleGroupMethods.description_text(*description_parts)
|
||||
|
||||
@output.flush
|
||||
@example_group = nil
|
||||
end
|
||||
end
|
||||
|
||||
def dump_failure(counter, failure)
|
||||
end
|
||||
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
20
vendor/plugins/rspec/lib/spec/runner/formatter/failing_examples_formatter.rb
vendored
Normal file
20
vendor/plugins/rspec/lib/spec/runner/formatter/failing_examples_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class FailingExamplesFormatter < BaseTextFormatter
|
||||
def example_failed(example, counter, failure)
|
||||
@output.puts "#{example_group.description} #{example.description}"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def dump_failure(counter, failure)
|
||||
end
|
||||
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
337
vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb
vendored
Normal file
337
vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
require 'erb'
|
||||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class HtmlFormatter < BaseTextFormatter
|
||||
include ERB::Util # for the #h method
|
||||
|
||||
def initialize(options, output)
|
||||
super
|
||||
@example_group_number = 0
|
||||
@example_number = 0
|
||||
end
|
||||
|
||||
def method_missing(sym, *args)
|
||||
# no-op
|
||||
end
|
||||
|
||||
# The number of the currently running example_group
|
||||
def example_group_number
|
||||
@example_group_number
|
||||
end
|
||||
|
||||
# The number of the currently running example (a global counter)
|
||||
def example_number
|
||||
@example_number
|
||||
end
|
||||
|
||||
def start(example_count)
|
||||
@example_count = example_count
|
||||
|
||||
@output.puts html_header
|
||||
@output.puts report_header
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def add_example_group(example_group)
|
||||
super
|
||||
@example_group_red = false
|
||||
@example_group_red = false
|
||||
@example_group_number += 1
|
||||
unless example_group_number == 1
|
||||
@output.puts " </dl>"
|
||||
@output.puts "</div>"
|
||||
end
|
||||
@output.puts "<div class=\"example_group\">"
|
||||
@output.puts " <dl>"
|
||||
@output.puts " <dt id=\"example_group_#{example_group_number}\">#{h(example_group.description)}</dt>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def start_dump
|
||||
@output.puts " </dl>"
|
||||
@output.puts "</div>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_started(example)
|
||||
@example_number += 1
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
move_progress
|
||||
@output.puts " <dd class=\"spec passed\"><span class=\"passed_spec_name\">#{h(example.description)}</span></dd>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_failed(example, counter, failure)
|
||||
extra = extra_failure_content(failure)
|
||||
failure_style = failure.pending_fixed? ? 'pending_fixed' : 'failed'
|
||||
@output.puts " <script type=\"text/javascript\">makeRed('rspec-header');</script>" unless @header_red
|
||||
@header_red = true
|
||||
@output.puts " <script type=\"text/javascript\">makeRed('example_group_#{example_group_number}');</script>" unless @example_group_red
|
||||
@example_group_red = true
|
||||
move_progress
|
||||
@output.puts " <dd class=\"spec #{failure_style}\">"
|
||||
@output.puts " <span class=\"failed_spec_name\">#{h(example.description)}</span>"
|
||||
@output.puts " <div class=\"failure\" id=\"failure_#{counter}\">"
|
||||
@output.puts " <div class=\"message\"><pre>#{h(failure.exception.message)}</pre></div>" unless failure.exception.nil?
|
||||
@output.puts " <div class=\"backtrace\"><pre>#{format_backtrace(failure.exception.backtrace)}</pre></div>" unless failure.exception.nil?
|
||||
@output.puts extra unless extra == ""
|
||||
@output.puts " </div>"
|
||||
@output.puts " </dd>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
@output.puts " <script type=\"text/javascript\">makeYellow('rspec-header');</script>" unless @header_red
|
||||
@output.puts " <script type=\"text/javascript\">makeYellow('example_group_#{example_group_number}');</script>" unless @example_group_red
|
||||
move_progress
|
||||
@output.puts " <dd class=\"spec not_implemented\"><span class=\"not_implemented_spec_name\">#{h(example.description)} (PENDING: #{h(message)})</span></dd>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
# Override this method if you wish to output extra HTML for a failed spec. For example, you
|
||||
# could output links to images or other files produced during the specs.
|
||||
#
|
||||
def extra_failure_content(failure)
|
||||
require 'spec/runner/formatter/snippet_extractor'
|
||||
@snippet_extractor ||= SnippetExtractor.new
|
||||
" <pre class=\"ruby\"><code>#{@snippet_extractor.snippet(failure.exception)}</code></pre>"
|
||||
end
|
||||
|
||||
def move_progress
|
||||
@output.puts " <script type=\"text/javascript\">moveProgressBar('#{percent_done}');</script>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def percent_done
|
||||
result = 100.0
|
||||
if @example_count != 0
|
||||
result = ((example_number).to_f / @example_count.to_f * 1000).to_i / 10.0
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def dump_failure(counter, failure)
|
||||
end
|
||||
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
if dry_run?
|
||||
totals = "This was a dry-run"
|
||||
else
|
||||
totals = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
|
||||
totals << ", #{pending_count} pending" if pending_count > 0
|
||||
end
|
||||
@output.puts "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{duration} seconds</strong>\";</script>"
|
||||
@output.puts "<script type=\"text/javascript\">document.getElementById('totals').innerHTML = \"#{totals}\";</script>"
|
||||
@output.puts "</div>"
|
||||
@output.puts "</div>"
|
||||
@output.puts "</body>"
|
||||
@output.puts "</html>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def html_header
|
||||
<<-EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>RSpec results</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Expires" content="-1" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #fff;
|
||||
font-size: 80%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
EOF
|
||||
end
|
||||
|
||||
def report_header
|
||||
<<-EOF
|
||||
<div class="rspec-report">
|
||||
<script type="text/javascript">
|
||||
// <![CDATA[
|
||||
#{global_scripts}
|
||||
// ]]>
|
||||
</script>
|
||||
<style type="text/css">
|
||||
#{global_styles}
|
||||
</style>
|
||||
|
||||
<div id="rspec-header">
|
||||
<h1>RSpec Results</h1>
|
||||
|
||||
<div id="summary">
|
||||
<p id="totals"> </p>
|
||||
<p id="duration"> </p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="results">
|
||||
EOF
|
||||
end
|
||||
|
||||
def global_scripts
|
||||
<<-EOF
|
||||
function moveProgressBar(percentDone) {
|
||||
document.getElementById("rspec-header").style.width = percentDone +"%";
|
||||
}
|
||||
function makeRed(element_id) {
|
||||
document.getElementById(element_id).style.background = '#C40D0D';
|
||||
document.getElementById(element_id).style.color = '#FFFFFF';
|
||||
}
|
||||
|
||||
function makeYellow(element_id) {
|
||||
if (element_id == "rspec-header" && document.getElementById(element_id).style.background != '#C40D0D')
|
||||
{
|
||||
document.getElementById(element_id).style.background = '#FAF834';
|
||||
document.getElementById(element_id).style.color = '#000000';
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById(element_id).style.background = '#FAF834';
|
||||
document.getElementById(element_id).style.color = '#000000';
|
||||
}
|
||||
}
|
||||
EOF
|
||||
end
|
||||
|
||||
def global_styles
|
||||
<<-EOF
|
||||
#rspec-header {
|
||||
background: #65C400; color: #fff;
|
||||
}
|
||||
|
||||
.rspec-report h1 {
|
||||
margin: 0px 10px 0px 10px;
|
||||
padding: 10px;
|
||||
font-family: "Lucida Grande", Helvetica, sans-serif;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
#summary {
|
||||
margin: 0; padding: 5px 10px;
|
||||
font-family: "Lucida Grande", Helvetica, sans-serif;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
#summary p {
|
||||
margin: 0 0 0 2px;
|
||||
}
|
||||
|
||||
#summary #totals {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.example_group {
|
||||
margin: 0 10px 5px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 0; padding: 0 0 5px;
|
||||
font: normal 11px "Lucida Grande", Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
dt {
|
||||
padding: 3px;
|
||||
background: #65C400;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin: 5px 0 5px 5px;
|
||||
padding: 3px 3px 3px 18px;
|
||||
}
|
||||
|
||||
dd.spec.passed {
|
||||
border-left: 5px solid #65C400;
|
||||
border-bottom: 1px solid #65C400;
|
||||
background: #DBFFB4; color: #3D7700;
|
||||
}
|
||||
|
||||
dd.spec.failed {
|
||||
border-left: 5px solid #C20000;
|
||||
border-bottom: 1px solid #C20000;
|
||||
color: #C20000; background: #FFFBD3;
|
||||
}
|
||||
|
||||
dd.spec.not_implemented {
|
||||
border-left: 5px solid #FAF834;
|
||||
border-bottom: 1px solid #FAF834;
|
||||
background: #FCFB98; color: #131313;
|
||||
}
|
||||
|
||||
dd.spec.pending_fixed {
|
||||
border-left: 5px solid #0000C2;
|
||||
border-bottom: 1px solid #0000C2;
|
||||
color: #0000C2; background: #D3FBFF;
|
||||
}
|
||||
|
||||
.backtrace {
|
||||
color: #000;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #BE5C00;
|
||||
}
|
||||
|
||||
/* Ruby code, style similar to vibrant ink */
|
||||
.ruby {
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
color: white;
|
||||
background-color: black;
|
||||
padding: 0.1em 0 0.2em 0;
|
||||
}
|
||||
|
||||
.ruby .keyword { color: #FF6600; }
|
||||
.ruby .constant { color: #339999; }
|
||||
.ruby .attribute { color: white; }
|
||||
.ruby .global { color: white; }
|
||||
.ruby .module { color: white; }
|
||||
.ruby .class { color: white; }
|
||||
.ruby .string { color: #66FF00; }
|
||||
.ruby .ident { color: white; }
|
||||
.ruby .method { color: #FFCC00; }
|
||||
.ruby .number { color: white; }
|
||||
.ruby .char { color: white; }
|
||||
.ruby .comment { color: #9933CC; }
|
||||
.ruby .symbol { color: white; }
|
||||
.ruby .regex { color: #44B4CC; }
|
||||
.ruby .punct { color: white; }
|
||||
.ruby .escape { color: white; }
|
||||
.ruby .interp { color: white; }
|
||||
.ruby .expr { color: white; }
|
||||
|
||||
.ruby .offending { background-color: gray; }
|
||||
.ruby .linenum {
|
||||
width: 75px;
|
||||
padding: 0.1em 1em 0.2em 0;
|
||||
color: #000000;
|
||||
background-color: #FFFBD3;
|
||||
}
|
||||
EOF
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
65
vendor/plugins/rspec/lib/spec/runner/formatter/nested_text_formatter.rb
vendored
Normal file
65
vendor/plugins/rspec/lib/spec/runner/formatter/nested_text_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class NestedTextFormatter < BaseTextFormatter
|
||||
attr_reader :previous_nested_example_groups
|
||||
def initialize(options, where)
|
||||
super
|
||||
@previous_nested_example_groups = []
|
||||
end
|
||||
|
||||
def add_example_group(example_group)
|
||||
super
|
||||
|
||||
current_nested_example_groups = described_example_group_chain
|
||||
current_nested_example_groups.each_with_index do |nested_example_group, i|
|
||||
unless nested_example_group == previous_nested_example_groups[i]
|
||||
output.puts "#{' ' * i}#{nested_example_group.description_args}"
|
||||
end
|
||||
end
|
||||
|
||||
@previous_nested_example_groups = described_example_group_chain
|
||||
end
|
||||
|
||||
def example_failed(example, counter, failure)
|
||||
message = if failure.expectation_not_met?
|
||||
"#{current_indentation}#{example.description} (FAILED - #{counter})"
|
||||
else
|
||||
"#{current_indentation}#{example.description} (ERROR - #{counter})"
|
||||
end
|
||||
|
||||
output.puts(failure.expectation_not_met? ? red(message) : magenta(message))
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
message = "#{current_indentation}#{example.description}"
|
||||
output.puts green(message)
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
super
|
||||
output.puts yellow("#{current_indentation}#{example.description} (PENDING: #{message})")
|
||||
output.flush
|
||||
end
|
||||
|
||||
def current_indentation
|
||||
' ' * previous_nested_example_groups.length
|
||||
end
|
||||
|
||||
def described_example_group_chain
|
||||
example_group_chain = []
|
||||
example_group.send(:execute_in_class_hierarchy) do |parent_example_group|
|
||||
if parent_example_group.description_args && !parent_example_group.description_args.empty?
|
||||
example_group_chain << parent_example_group
|
||||
end
|
||||
end
|
||||
example_group_chain
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
51
vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb
vendored
Normal file
51
vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
require 'spec/runner/formatter/progress_bar_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class ProfileFormatter < ProgressBarFormatter
|
||||
|
||||
def initialize(options, where)
|
||||
super
|
||||
@example_times = []
|
||||
end
|
||||
|
||||
def start(count)
|
||||
@output.puts "Profiling enabled."
|
||||
end
|
||||
|
||||
def example_started(example)
|
||||
@time = Time.now
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
super
|
||||
@example_times << [
|
||||
example_group.description,
|
||||
example.description,
|
||||
Time.now - @time
|
||||
]
|
||||
end
|
||||
|
||||
def start_dump
|
||||
super
|
||||
@output.puts "\n\nTop 10 slowest examples:\n"
|
||||
|
||||
@example_times = @example_times.sort_by do |description, example, time|
|
||||
time
|
||||
end.reverse
|
||||
|
||||
@example_times[0..9].each do |description, example, time|
|
||||
@output.print red(sprintf("%.7f", time))
|
||||
@output.puts " #{description} #{example}"
|
||||
end
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def method_missing(sym, *args)
|
||||
# ignore
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
34
vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb
vendored
Normal file
34
vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class ProgressBarFormatter < BaseTextFormatter
|
||||
def example_failed(example, counter, failure)
|
||||
@output.print colourise('F', failure)
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
@output.print green('.')
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
super
|
||||
@output.print yellow('P')
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def start_dump
|
||||
@output.puts
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def method_missing(sym, *args)
|
||||
# ignore
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
52
vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb
vendored
Normal file
52
vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
# This class extracts code snippets by looking at the backtrace of the passed error
|
||||
class SnippetExtractor #:nodoc:
|
||||
class NullConverter; def convert(code, pre); code; end; end #:nodoc:
|
||||
begin; require 'rubygems'; require 'syntax/convertors/html'; @@converter = Syntax::Convertors::HTML.for_syntax "ruby"; rescue LoadError => e; @@converter = NullConverter.new; end
|
||||
|
||||
def snippet(error)
|
||||
raw_code, line = snippet_for(error.backtrace[0])
|
||||
highlighted = @@converter.convert(raw_code, false)
|
||||
highlighted << "\n<span class=\"comment\"># gem install syntax to get syntax highlighting</span>" if @@converter.is_a?(NullConverter)
|
||||
post_process(highlighted, line)
|
||||
end
|
||||
|
||||
def snippet_for(error_line)
|
||||
if error_line =~ /(.*):(\d+)/
|
||||
file = $1
|
||||
line = $2.to_i
|
||||
[lines_around(file, line), line]
|
||||
else
|
||||
["# Couldn't get snippet for #{error_line}", 1]
|
||||
end
|
||||
end
|
||||
|
||||
def lines_around(file, line)
|
||||
if File.file?(file)
|
||||
lines = File.open(file).read.split("\n")
|
||||
min = [0, line-3].max
|
||||
max = [line+1, lines.length-1].min
|
||||
selected_lines = []
|
||||
selected_lines.join("\n")
|
||||
lines[min..max].join("\n")
|
||||
else
|
||||
"# Couldn't get snippet for #{file}"
|
||||
end
|
||||
end
|
||||
|
||||
def post_process(highlighted, offending_line)
|
||||
new_lines = []
|
||||
highlighted.split("\n").each_with_index do |line, i|
|
||||
new_line = "<span class=\"linenum\">#{offending_line+i-2}</span>#{line}"
|
||||
new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
|
||||
new_lines << new_line
|
||||
end
|
||||
new_lines.join("\n")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
39
vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb
vendored
Normal file
39
vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class SpecdocFormatter < BaseTextFormatter
|
||||
def add_example_group(example_group)
|
||||
super
|
||||
output.puts
|
||||
output.puts example_group.description
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_failed(example, counter, failure)
|
||||
message = if failure.expectation_not_met?
|
||||
"- #{example.description} (FAILED - #{counter})"
|
||||
else
|
||||
"- #{example.description} (ERROR - #{counter})"
|
||||
end
|
||||
|
||||
output.puts(failure.expectation_not_met? ? red(message) : magenta(message))
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
message = "- #{example.description}"
|
||||
output.puts green(message)
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
super
|
||||
output.puts yellow("- #{example.description} (PENDING: #{message})")
|
||||
output.flush
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
161
vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb
vendored
Normal file
161
vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
require 'erb'
|
||||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
module Story
|
||||
class HtmlFormatter < BaseTextFormatter
|
||||
include ERB::Util
|
||||
|
||||
def initialize(options, where)
|
||||
super
|
||||
@previous_type = nil
|
||||
@scenario_text = ""
|
||||
@story_text = ""
|
||||
@scenario_failed = false
|
||||
@story_failed = false
|
||||
end
|
||||
|
||||
def run_started(count)
|
||||
@output.puts <<-EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Stories</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Expires" content="-1" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<script src="javascripts/prototype.js" type="text/javascript"></script>
|
||||
<script src="javascripts/scriptaculous.js" type="text/javascript"></script>
|
||||
<script src="javascripts/rspec.js" type="text/javascript"></script>
|
||||
<link href="stylesheets/rspec.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
EOF
|
||||
end
|
||||
|
||||
def collected_steps(steps)
|
||||
unless steps.empty?
|
||||
@output.puts " <ul id=\"stock_steps\" style=\"display: none;\">"
|
||||
steps.each do |step|
|
||||
@output.puts " <li>#{step}</li>"
|
||||
end
|
||||
@output.puts " </ul>"
|
||||
end
|
||||
end
|
||||
|
||||
def run_ended
|
||||
@output.puts <<-EOF
|
||||
</div>
|
||||
</body>
|
||||
</head>
|
||||
EOF
|
||||
end
|
||||
|
||||
def story_started(title, narrative)
|
||||
@story_failed = false
|
||||
@story_text = <<-EOF
|
||||
<dt>Story: #{h title}</dt>
|
||||
<dd>
|
||||
<p>
|
||||
#{h(narrative).split("\n").join("<br />")}
|
||||
</p>
|
||||
EOF
|
||||
end
|
||||
|
||||
def story_ended(title, narrative)
|
||||
if @story_failed
|
||||
@output.puts <<-EOF
|
||||
<dl class="story failed">
|
||||
EOF
|
||||
else
|
||||
@output.puts <<-EOF
|
||||
<dl class="story passed">
|
||||
EOF
|
||||
end
|
||||
@output.puts <<-EOF
|
||||
#{@story_text}
|
||||
</dd>
|
||||
</dl>
|
||||
EOF
|
||||
end
|
||||
|
||||
def scenario_started(story_title, scenario_name)
|
||||
@scenario_failed = false
|
||||
@scenario_text = <<-EOF
|
||||
<dt>Scenario: #{h scenario_name}</dt>
|
||||
<dd>
|
||||
<ul class="steps">
|
||||
EOF
|
||||
end
|
||||
|
||||
def scenario_ended
|
||||
if @scenario_failed
|
||||
@story_text += <<-EOF
|
||||
<dl class="failed">
|
||||
EOF
|
||||
else
|
||||
@story_text += <<-EOF
|
||||
<dl class="passed">
|
||||
EOF
|
||||
end
|
||||
|
||||
@story_text += <<-EOF
|
||||
#{@scenario_text}
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
EOF
|
||||
end
|
||||
|
||||
def found_scenario(type, description)
|
||||
end
|
||||
|
||||
def scenario_succeeded(story_title, scenario_name)
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_pending(story_title, scenario_name, reason)
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_failed(story_title, scenario_name, err)
|
||||
@scenario_failed = true
|
||||
@story_failed = true
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def step_upcoming(type, description, *args)
|
||||
end
|
||||
|
||||
def step_succeeded(type, description, *args)
|
||||
print_step('passed', type, description, *args) # TODO: uses succeeded CSS class
|
||||
end
|
||||
|
||||
def step_pending(type, description, *args)
|
||||
print_step('pending', type, description, *args)
|
||||
end
|
||||
|
||||
def step_failed(type, description, *args)
|
||||
print_step('failed', type, description, *args)
|
||||
end
|
||||
|
||||
def print_step(klass, type, description, *args)
|
||||
spans = args.map { |arg| "<span class=\"param\">#{arg}</span>" }
|
||||
desc_string = description.step_name
|
||||
arg_regexp = description.arg_regexp
|
||||
i = -1
|
||||
inner = type.to_s.capitalize + ' ' + desc_string.gsub(arg_regexp) { |param| spans[i+=1] }
|
||||
@scenario_text += " <li class=\"#{klass}\">#{inner}</li>\n"
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
188
vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb
vendored
Normal file
188
vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
module Story
|
||||
class PlainTextFormatter < BaseTextFormatter
|
||||
def initialize(options, where)
|
||||
super
|
||||
@successful_scenario_count = 0
|
||||
@pending_scenario_count = 0
|
||||
|
||||
@pre_story_pending_count = 0
|
||||
@pre_story_successful_count = 0
|
||||
|
||||
@failed_scenarios = []
|
||||
@pending_steps = []
|
||||
@previous_type = nil
|
||||
|
||||
@scenario_body_text = ""
|
||||
@story_body_text = ""
|
||||
|
||||
@scenario_head_text = ""
|
||||
@story_head_text = ""
|
||||
|
||||
@scenario_failed = false
|
||||
@story_failed = false
|
||||
end
|
||||
|
||||
def run_started(count)
|
||||
@count = count
|
||||
@output.puts "Running #@count scenarios\n\n"
|
||||
end
|
||||
|
||||
def story_started(title, narrative)
|
||||
@pre_story_pending_count = @pending_scenario_count
|
||||
@pre_story_successful_count = @successful_scenario_count
|
||||
|
||||
@current_story_title = title
|
||||
@story_failed = false
|
||||
@story_body_text = ""
|
||||
@story_head_text = "Story: #{title}\n\n"
|
||||
|
||||
narrative.each_line do |line|
|
||||
@story_head_text += " "
|
||||
@story_head_text += line
|
||||
end
|
||||
end
|
||||
|
||||
def story_ended(title, narrative)
|
||||
if @story_failed
|
||||
@output.print red(@story_head_text)
|
||||
elsif @pre_story_successful_count == @successful_scenario_count &&
|
||||
@pending_scenario_count >= @pre_story_pending_count
|
||||
@output.print yellow(@story_head_text)
|
||||
else
|
||||
@output.print green(@story_head_text)
|
||||
end
|
||||
@output.print @story_body_text
|
||||
@output.puts
|
||||
@output.puts
|
||||
end
|
||||
|
||||
def scenario_started(story_title, scenario_name)
|
||||
@current_scenario_name = scenario_name
|
||||
@scenario_already_failed = false
|
||||
@scenario_head_text = "\n\n Scenario: #{scenario_name}"
|
||||
@scenario_body_text = ""
|
||||
@scenario_ok = true
|
||||
@scenario_pending = false
|
||||
@scenario_failed = false
|
||||
end
|
||||
|
||||
def scenario_succeeded(story_title, scenario_name)
|
||||
@successful_scenario_count += 1
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_failed(story_title, scenario_name, err)
|
||||
@options.backtrace_tweaker.tweak_backtrace(err)
|
||||
@failed_scenarios << [story_title, scenario_name, err] unless @scenario_already_failed
|
||||
@scenario_already_failed = true
|
||||
@story_failed = true
|
||||
@scenario_failed = true
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_pending(story_title, scenario_name, msg)
|
||||
@pending_scenario_count += 1 unless @scenario_already_failed
|
||||
@scenario_pending = true
|
||||
@scenario_already_failed = true
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_ended
|
||||
if @scenario_failed
|
||||
@story_body_text += red(@scenario_head_text)
|
||||
elsif @scenario_pending
|
||||
@story_body_text += yellow(@scenario_head_text)
|
||||
else
|
||||
@story_body_text += green(@scenario_head_text)
|
||||
end
|
||||
@story_body_text += @scenario_body_text
|
||||
end
|
||||
|
||||
def run_ended
|
||||
@output.puts "#@count scenarios: #@successful_scenario_count succeeded, #{@failed_scenarios.size} failed, #@pending_scenario_count pending"
|
||||
unless @pending_steps.empty?
|
||||
@output.puts "\nPending Steps:"
|
||||
@pending_steps.each_with_index do |pending, i|
|
||||
story_name, scenario_name, msg = pending
|
||||
@output.puts "#{i+1}) #{story_name} (#{scenario_name}): #{msg}"
|
||||
end
|
||||
end
|
||||
unless @failed_scenarios.empty?
|
||||
@output.print "\nFAILURES:"
|
||||
@failed_scenarios.each_with_index do |failure, i|
|
||||
title, scenario_name, err = failure
|
||||
@output.print %[
|
||||
#{i+1}) #{title} (#{scenario_name}) FAILED
|
||||
#{err.class}: #{err.message}
|
||||
#{err.backtrace.join("\n")}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def step_upcoming(type, description, *args)
|
||||
end
|
||||
|
||||
def step_succeeded(type, description, *args)
|
||||
found_step(type, description, false, false, *args)
|
||||
end
|
||||
|
||||
def step_pending(type, description, *args)
|
||||
found_step(type, description, false, true, *args)
|
||||
@pending_steps << [@current_story_title, @current_scenario_name, description]
|
||||
@scenario_body_text += yellow(" (PENDING)")
|
||||
@scenario_pending = true
|
||||
@scenario_ok = false
|
||||
end
|
||||
|
||||
def step_failed(type, description, *args)
|
||||
found_step(type, description, true, @scenario_pending, *args)
|
||||
if @scenario_pending
|
||||
@scenario_body_text += yellow(" (SKIPPED)")
|
||||
else
|
||||
@scenario_body_text += red(@scenario_ok ? " (FAILED)" : " (SKIPPED)")
|
||||
end
|
||||
@scenario_ok = false
|
||||
end
|
||||
|
||||
def collected_steps(steps)
|
||||
end
|
||||
|
||||
def method_missing(sym, *args, &block) #:nodoc:
|
||||
# noop - ignore unknown messages
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def found_step(type, description, failed, pending, *args)
|
||||
desc_string = description.step_name
|
||||
arg_regexp = description.arg_regexp
|
||||
text = if(type == @previous_type)
|
||||
"\n And "
|
||||
else
|
||||
"\n\n #{type.to_s.capitalize} "
|
||||
end
|
||||
i = -1
|
||||
text << desc_string.gsub(arg_regexp) { |param| args[i+=1] }
|
||||
if pending
|
||||
@scenario_body_text += yellow(text)
|
||||
else
|
||||
@scenario_body_text += (failed ? red(text) : green(text))
|
||||
end
|
||||
|
||||
if type == :'given scenario'
|
||||
@previous_type = :given
|
||||
else
|
||||
@previous_type = type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
16
vendor/plugins/rspec/lib/spec/runner/formatter/text_mate_formatter.rb
vendored
Normal file
16
vendor/plugins/rspec/lib/spec/runner/formatter/text_mate_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
require 'spec/runner/formatter/html_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
# Formats backtraces so they're clickable by TextMate
|
||||
class TextMateFormatter < HtmlFormatter
|
||||
def backtrace_line(line)
|
||||
line.gsub(/([^:]*\.rb):(\d*)/) do
|
||||
"<a href=\"txmt://open?url=file://#{File.expand_path($1)}&line=#{$2}\">#{$1}:#{$2}</a> "
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
72
vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb
vendored
Normal file
72
vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
begin
|
||||
require 'rubygems'
|
||||
require 'heckle'
|
||||
rescue LoadError ; raise "You must gem install heckle to use --heckle" ; end
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
# Creates a new Heckler configured to heckle all methods in the classes
|
||||
# whose name matches +filter+
|
||||
class HeckleRunner
|
||||
def initialize(filter, heckle_class=Heckler)
|
||||
@filter = filter
|
||||
@heckle_class = heckle_class
|
||||
end
|
||||
|
||||
# Runs all the example groups held by +rspec_options+ once for each of the
|
||||
# methods in the matched classes.
|
||||
def heckle_with
|
||||
if @filter =~ /(.*)[#\.](.*)/
|
||||
heckle_method($1, $2)
|
||||
else
|
||||
heckle_class_or_module(@filter)
|
||||
end
|
||||
end
|
||||
|
||||
def heckle_method(class_name, method_name)
|
||||
verify_constant(class_name)
|
||||
heckle = @heckle_class.new(class_name, method_name, rspec_options)
|
||||
heckle.validate
|
||||
end
|
||||
|
||||
def heckle_class_or_module(class_or_module_name)
|
||||
verify_constant(class_or_module_name)
|
||||
pattern = /^#{class_or_module_name}/
|
||||
classes = []
|
||||
ObjectSpace.each_object(Class) do |klass|
|
||||
classes << klass if klass.name =~ pattern
|
||||
end
|
||||
|
||||
classes.each do |klass|
|
||||
klass.instance_methods(false).each do |method_name|
|
||||
heckle = @heckle_class.new(klass.name, method_name, rspec_options)
|
||||
heckle.validate
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def verify_constant(name)
|
||||
begin
|
||||
# This is defined in Heckle
|
||||
name.to_class
|
||||
rescue
|
||||
raise "Heckling failed - \"#{name}\" is not a known class or module"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#Supports Heckle 1.2 and prior (earlier versions used Heckle::Base)
|
||||
class Heckler < (Heckle.const_defined?(:Base) ? Heckle::Base : Heckle)
|
||||
def initialize(klass_name, method_name, rspec_options)
|
||||
super(klass_name, method_name)
|
||||
@rspec_options = rspec_options
|
||||
end
|
||||
|
||||
def tests_pass?
|
||||
success = @rspec_options.run_examples
|
||||
success
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
10
vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb
vendored
Normal file
10
vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
module Spec
|
||||
module Runner
|
||||
# Dummy implementation for Windows that just fails (Heckle is not supported on Windows)
|
||||
class HeckleRunner
|
||||
def initialize(filter)
|
||||
raise "Heckle not supported on Windows"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
203
vendor/plugins/rspec/lib/spec/runner/option_parser.rb
vendored
Normal file
203
vendor/plugins/rspec/lib/spec/runner/option_parser.rb
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
require 'optparse'
|
||||
require 'stringio'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
class OptionParser < ::OptionParser
|
||||
class << self
|
||||
def parse(args, err, out)
|
||||
parser = new(err, out)
|
||||
parser.parse(args)
|
||||
parser.options
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :options
|
||||
|
||||
OPTIONS = {
|
||||
:pattern => ["-p", "--pattern [PATTERN]","Limit files loaded to those matching this pattern. Defaults to '**/*_spec.rb'",
|
||||
"Separate multiple patterns with commas.",
|
||||
"Applies only to directories named on the command line (files",
|
||||
"named explicitly on the command line will be loaded regardless)."],
|
||||
:diff => ["-D", "--diff [FORMAT]","Show diff of objects that are expected to be equal when they are not",
|
||||
"Builtin formats: unified|u|context|c",
|
||||
"You can also specify a custom differ class",
|
||||
"(in which case you should also specify --require)"],
|
||||
:colour => ["-c", "--colour", "--color", "Show coloured (red/green) output"],
|
||||
:example => ["-e", "--example [NAME|FILE_NAME]", "Execute example(s) with matching name(s). If the argument is",
|
||||
"the path to an existing file (typically generated by a previous",
|
||||
"run using --format failing_examples:file.txt), then the examples",
|
||||
"on each line of thatfile will be executed. If the file is empty,",
|
||||
"all examples will be run (as if --example was not specified).",
|
||||
" ",
|
||||
"If the argument is not an existing file, then it is treated as",
|
||||
"an example name directly, causing RSpec to run just the example",
|
||||
"matching that name"],
|
||||
:specification => ["-s", "--specification [NAME]", "DEPRECATED - use -e instead", "(This will be removed when autotest works with -e)"],
|
||||
:line => ["-l", "--line LINE_NUMBER", Integer, "Execute behaviout or specification at given line.",
|
||||
"(does not work for dynamically generated specs)"],
|
||||
:format => ["-f", "--format FORMAT[:WHERE]","Specifies what format to use for output. Specify WHERE to tell",
|
||||
"the formatter where to write the output. All built-in formats",
|
||||
"expect WHERE to be a file name, and will write to STDOUT if it's",
|
||||
"not specified. The --format option may be specified several times",
|
||||
"if you want several outputs",
|
||||
" ",
|
||||
"Builtin formats for examples: ",
|
||||
"progress|p : Text progress",
|
||||
"profile|o : Text progress with profiling of 10 slowest examples",
|
||||
"specdoc|s : Example doc as text",
|
||||
"indented|i : Example doc as indented text",
|
||||
"html|h : A nice HTML report",
|
||||
"failing_examples|e : Write all failing examples - input for --example",
|
||||
"failing_example_groups|g : Write all failing example groups - input for --example",
|
||||
" ",
|
||||
"Builtin formats for stories: ",
|
||||
"plain|p : Plain Text",
|
||||
"html|h : A nice HTML report",
|
||||
" ",
|
||||
"FORMAT can also be the name of a custom formatter class",
|
||||
"(in which case you should also specify --require to load it)"],
|
||||
:require => ["-r", "--require FILE", "Require FILE before running specs",
|
||||
"Useful for loading custom formatters or other extensions.",
|
||||
"If this option is used it must come before the others"],
|
||||
:backtrace => ["-b", "--backtrace", "Output full backtrace"],
|
||||
:loadby => ["-L", "--loadby STRATEGY", "Specify the strategy by which spec files should be loaded.",
|
||||
"STRATEGY can currently only be 'mtime' (File modification time)",
|
||||
"By default, spec files are loaded in alphabetical order if --loadby",
|
||||
"is not specified."],
|
||||
:reverse => ["-R", "--reverse", "Run examples in reverse order"],
|
||||
:timeout => ["-t", "--timeout FLOAT", "Interrupt and fail each example that doesn't complete in the",
|
||||
"specified time"],
|
||||
:heckle => ["-H", "--heckle CODE", "If all examples pass, this will mutate the classes and methods",
|
||||
"identified by CODE little by little and run all the examples again",
|
||||
"for each mutation. The intent is that for each mutation, at least",
|
||||
"one example *should* fail, and RSpec will tell you if this is not the",
|
||||
"case. CODE should be either Some::Module, Some::Class or",
|
||||
"Some::Fabulous#method}"],
|
||||
:dry_run => ["-d", "--dry-run", "Invokes formatters without executing the examples."],
|
||||
:options_file => ["-O", "--options PATH", "Read options from a file"],
|
||||
:generate_options => ["-G", "--generate-options PATH", "Generate an options file for --options"],
|
||||
:runner => ["-U", "--runner RUNNER", "Use a custom Runner."],
|
||||
:drb => ["-X", "--drb", "Run examples via DRb. (For example against script/spec_server)"],
|
||||
:version => ["-v", "--version", "Show version"],
|
||||
:help => ["-h", "--help", "You're looking at it"]
|
||||
}
|
||||
|
||||
def initialize(err, out)
|
||||
super()
|
||||
@error_stream = err
|
||||
@out_stream = out
|
||||
@options = Options.new(@error_stream, @out_stream)
|
||||
|
||||
@file_factory = File
|
||||
|
||||
self.banner = "Usage: spec (FILE|DIRECTORY|GLOB)+ [options]"
|
||||
self.separator ""
|
||||
on(*OPTIONS[:pattern]) {|pattern| @options.filename_pattern = pattern}
|
||||
on(*OPTIONS[:diff]) {|diff| @options.parse_diff(diff)}
|
||||
on(*OPTIONS[:colour]) {@options.colour = true}
|
||||
on(*OPTIONS[:example]) {|example| @options.parse_example(example)}
|
||||
on(*OPTIONS[:specification]) {|example| @options.parse_example(example)}
|
||||
on(*OPTIONS[:line]) {|line_number| @options.line_number = line_number.to_i}
|
||||
on(*OPTIONS[:format]) {|format| @options.parse_format(format)}
|
||||
on(*OPTIONS[:require]) {|requires| invoke_requires(requires)}
|
||||
on(*OPTIONS[:backtrace]) {@options.backtrace_tweaker = NoisyBacktraceTweaker.new}
|
||||
on(*OPTIONS[:loadby]) {|loadby| @options.loadby = loadby}
|
||||
on(*OPTIONS[:reverse]) {@options.reverse = true}
|
||||
on(*OPTIONS[:timeout]) {|timeout| @options.timeout = timeout.to_f}
|
||||
on(*OPTIONS[:heckle]) {|heckle| @options.load_heckle_runner(heckle)}
|
||||
on(*OPTIONS[:dry_run]) {@options.dry_run = true}
|
||||
on(*OPTIONS[:options_file]) {|options_file| parse_options_file(options_file)}
|
||||
on(*OPTIONS[:generate_options]) {|options_file|}
|
||||
on(*OPTIONS[:runner]) {|runner| @options.user_input_for_runner = runner}
|
||||
on(*OPTIONS[:drb]) {}
|
||||
on(*OPTIONS[:version]) {parse_version}
|
||||
on_tail(*OPTIONS[:help]) {parse_help}
|
||||
end
|
||||
|
||||
def order!(argv, &blk)
|
||||
@argv = argv
|
||||
@options.argv = @argv.dup
|
||||
return if parse_generate_options
|
||||
return if parse_drb
|
||||
|
||||
super(@argv) do |file|
|
||||
@options.files << file
|
||||
blk.call(file) if blk
|
||||
end
|
||||
|
||||
@options
|
||||
end
|
||||
|
||||
protected
|
||||
def invoke_requires(requires)
|
||||
requires.split(",").each do |file|
|
||||
require file
|
||||
end
|
||||
end
|
||||
|
||||
def parse_options_file(options_file)
|
||||
option_file_args = IO.readlines(options_file).map {|l| l.chomp.split " "}.flatten
|
||||
@argv.push(*option_file_args)
|
||||
# TODO - this is a brute force solution to http://rspec.lighthouseapp.com/projects/5645/tickets/293.
|
||||
# Let's look for a cleaner way. Might not be one. But let's look. If not, perhaps
|
||||
# this can be moved to a different method to indicate the special handling for drb?
|
||||
parse_drb(@argv)
|
||||
end
|
||||
|
||||
def parse_generate_options
|
||||
# Remove the --generate-options option and the argument before writing to file
|
||||
options_file = nil
|
||||
['-G', '--generate-options'].each do |option|
|
||||
if index = @argv.index(option)
|
||||
@argv.delete_at(index)
|
||||
options_file = @argv.delete_at(index)
|
||||
end
|
||||
end
|
||||
|
||||
if options_file
|
||||
write_generated_options(options_file)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def write_generated_options(options_file)
|
||||
File.open(options_file, 'w') do |io|
|
||||
io.puts @argv.join("\n")
|
||||
end
|
||||
@out_stream.puts "\nOptions written to #{options_file}. You can now use these options with:"
|
||||
@out_stream.puts "spec --options #{options_file}"
|
||||
@options.examples_should_not_be_run
|
||||
end
|
||||
|
||||
def parse_drb(argv = nil)
|
||||
argv ||= @options.argv # TODO - see note about about http://rspec.lighthouseapp.com/projects/5645/tickets/293
|
||||
is_drb = false
|
||||
is_drb ||= argv.delete(OPTIONS[:drb][0])
|
||||
is_drb ||= argv.delete(OPTIONS[:drb][1])
|
||||
return false unless is_drb
|
||||
@options.examples_should_not_be_run
|
||||
DrbCommandLine.run(
|
||||
self.class.parse(argv, @error_stream, @out_stream)
|
||||
)
|
||||
true
|
||||
end
|
||||
|
||||
def parse_version
|
||||
@out_stream.puts ::Spec::VERSION::DESCRIPTION
|
||||
exit if stdout?
|
||||
end
|
||||
|
||||
def parse_help
|
||||
@out_stream.puts self
|
||||
exit if stdout?
|
||||
end
|
||||
|
||||
def stdout?
|
||||
@out_stream == $stdout
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
309
vendor/plugins/rspec/lib/spec/runner/options.rb
vendored
Normal file
309
vendor/plugins/rspec/lib/spec/runner/options.rb
vendored
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class Options
|
||||
FILE_SORTERS = {
|
||||
'mtime' => lambda {|file_a, file_b| File.mtime(file_b) <=> File.mtime(file_a)}
|
||||
}
|
||||
|
||||
EXAMPLE_FORMATTERS = { # Load these lazily for better speed
|
||||
'specdoc' => ['spec/runner/formatter/specdoc_formatter', 'Formatter::SpecdocFormatter'],
|
||||
's' => ['spec/runner/formatter/specdoc_formatter', 'Formatter::SpecdocFormatter'],
|
||||
'nested' => ['spec/runner/formatter/nested_text_formatter', 'Formatter::NestedTextFormatter'],
|
||||
'n' => ['spec/runner/formatter/nested_text_formatter', 'Formatter::NestedTextFormatter'],
|
||||
'html' => ['spec/runner/formatter/html_formatter', 'Formatter::HtmlFormatter'],
|
||||
'h' => ['spec/runner/formatter/html_formatter', 'Formatter::HtmlFormatter'],
|
||||
'progress' => ['spec/runner/formatter/progress_bar_formatter', 'Formatter::ProgressBarFormatter'],
|
||||
'p' => ['spec/runner/formatter/progress_bar_formatter', 'Formatter::ProgressBarFormatter'],
|
||||
'failing_examples' => ['spec/runner/formatter/failing_examples_formatter', 'Formatter::FailingExamplesFormatter'],
|
||||
'e' => ['spec/runner/formatter/failing_examples_formatter', 'Formatter::FailingExamplesFormatter'],
|
||||
'failing_example_groups' => ['spec/runner/formatter/failing_example_groups_formatter', 'Formatter::FailingExampleGroupsFormatter'],
|
||||
'g' => ['spec/runner/formatter/failing_example_groups_formatter', 'Formatter::FailingExampleGroupsFormatter'],
|
||||
'profile' => ['spec/runner/formatter/profile_formatter', 'Formatter::ProfileFormatter'],
|
||||
'o' => ['spec/runner/formatter/profile_formatter', 'Formatter::ProfileFormatter'],
|
||||
'textmate' => ['spec/runner/formatter/text_mate_formatter', 'Formatter::TextMateFormatter']
|
||||
}
|
||||
|
||||
STORY_FORMATTERS = {
|
||||
'plain' => ['spec/runner/formatter/story/plain_text_formatter', 'Formatter::Story::PlainTextFormatter'],
|
||||
'p' => ['spec/runner/formatter/story/plain_text_formatter', 'Formatter::Story::PlainTextFormatter'],
|
||||
'html' => ['spec/runner/formatter/story/html_formatter', 'Formatter::Story::HtmlFormatter'],
|
||||
'h' => ['spec/runner/formatter/story/html_formatter', 'Formatter::Story::HtmlFormatter']
|
||||
}
|
||||
|
||||
attr_accessor(
|
||||
:filename_pattern,
|
||||
:backtrace_tweaker,
|
||||
:context_lines,
|
||||
:diff_format,
|
||||
:dry_run,
|
||||
:profile,
|
||||
:examples,
|
||||
:heckle_runner,
|
||||
:line_number,
|
||||
:loadby,
|
||||
:reporter,
|
||||
:reverse,
|
||||
:timeout,
|
||||
:verbose,
|
||||
:user_input_for_runner,
|
||||
:error_stream,
|
||||
:output_stream,
|
||||
:before_suite_parts,
|
||||
:after_suite_parts,
|
||||
# TODO: BT - Figure out a better name
|
||||
:argv
|
||||
)
|
||||
attr_reader :colour, :differ_class, :files, :example_groups
|
||||
|
||||
def initialize(error_stream, output_stream)
|
||||
@error_stream = error_stream
|
||||
@output_stream = output_stream
|
||||
@filename_pattern = "**/*_spec.rb"
|
||||
@backtrace_tweaker = QuietBacktraceTweaker.new
|
||||
@examples = []
|
||||
@colour = false
|
||||
@profile = false
|
||||
@dry_run = false
|
||||
@reporter = Reporter.new(self)
|
||||
@context_lines = 3
|
||||
@diff_format = :unified
|
||||
@files = []
|
||||
@example_groups = []
|
||||
@result = nil
|
||||
@examples_run = false
|
||||
@examples_should_be_run = nil
|
||||
@user_input_for_runner = nil
|
||||
@before_suite_parts = []
|
||||
@after_suite_parts = []
|
||||
end
|
||||
|
||||
def add_example_group(example_group)
|
||||
@example_groups << example_group
|
||||
end
|
||||
|
||||
def remove_example_group(example_group)
|
||||
@example_groups.delete(example_group)
|
||||
end
|
||||
|
||||
def run_examples
|
||||
return true unless examples_should_be_run?
|
||||
success = true
|
||||
begin
|
||||
before_suite_parts.each do |part|
|
||||
part.call
|
||||
end
|
||||
runner = custom_runner || ExampleGroupRunner.new(self)
|
||||
|
||||
unless @files_loaded
|
||||
runner.load_files(files_to_load)
|
||||
@files_loaded = true
|
||||
end
|
||||
|
||||
if example_groups.empty?
|
||||
true
|
||||
else
|
||||
set_spec_from_line_number if line_number
|
||||
success = runner.run
|
||||
@examples_run = true
|
||||
heckle if heckle_runner
|
||||
success
|
||||
end
|
||||
ensure
|
||||
after_suite_parts.each do |part|
|
||||
part.call(success)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def examples_run?
|
||||
@examples_run
|
||||
end
|
||||
|
||||
def examples_should_not_be_run
|
||||
@examples_should_be_run = false
|
||||
end
|
||||
|
||||
def colour=(colour)
|
||||
@colour = colour
|
||||
if @colour && RUBY_PLATFORM =~ /win32/ ;\
|
||||
begin ;\
|
||||
require 'rubygems' ;\
|
||||
require 'Win32/Console/ANSI' ;\
|
||||
rescue LoadError ;\
|
||||
warn "You must 'gem install win32console' to use colour on Windows" ;\
|
||||
@colour = false ;\
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def parse_diff(format)
|
||||
case format
|
||||
when :context, 'context', 'c'
|
||||
@diff_format = :context
|
||||
default_differ
|
||||
when :unified, 'unified', 'u', '', nil
|
||||
@diff_format = :unified
|
||||
default_differ
|
||||
else
|
||||
@diff_format = :custom
|
||||
self.differ_class = load_class(format, 'differ', '--diff')
|
||||
end
|
||||
end
|
||||
|
||||
def parse_example(example)
|
||||
if(File.file?(example))
|
||||
@examples = File.open(example).read.split("\n")
|
||||
else
|
||||
@examples = [example]
|
||||
end
|
||||
end
|
||||
|
||||
def parse_format(format_arg)
|
||||
format, where = ClassAndArgumentsParser.parse(format_arg)
|
||||
unless where
|
||||
raise "When using several --format options only one of them can be without a file" if @out_used
|
||||
where = @output_stream
|
||||
@out_used = true
|
||||
end
|
||||
@format_options ||= []
|
||||
@format_options << [format, where]
|
||||
end
|
||||
|
||||
def formatters
|
||||
@format_options ||= [['progress', @output_stream]]
|
||||
@formatters ||= load_formatters(@format_options, EXAMPLE_FORMATTERS)
|
||||
end
|
||||
|
||||
def story_formatters
|
||||
@format_options ||= [['plain', @output_stream]]
|
||||
@formatters ||= load_formatters(@format_options, STORY_FORMATTERS)
|
||||
end
|
||||
|
||||
def load_formatters(format_options, formatters)
|
||||
format_options.map do |format, where|
|
||||
formatter_type = if formatters[format]
|
||||
require formatters[format][0]
|
||||
eval(formatters[format][1], binding, __FILE__, __LINE__)
|
||||
else
|
||||
load_class(format, 'formatter', '--format')
|
||||
end
|
||||
formatter_type.new(self, where)
|
||||
end
|
||||
end
|
||||
|
||||
def load_heckle_runner(heckle)
|
||||
suffix = [/mswin/, /java/].detect{|p| p =~ RUBY_PLATFORM} ? '_unsupported' : ''
|
||||
require "spec/runner/heckle_runner#{suffix}"
|
||||
@heckle_runner = HeckleRunner.new(heckle)
|
||||
end
|
||||
|
||||
def number_of_examples
|
||||
total = 0
|
||||
@example_groups.each do |example_group|
|
||||
total += example_group.number_of_examples
|
||||
end
|
||||
total
|
||||
end
|
||||
|
||||
def files_to_load
|
||||
result = []
|
||||
sorted_files.each do |file|
|
||||
if File.directory?(file)
|
||||
filename_pattern.split(",").each do |pattern|
|
||||
result += Dir[File.expand_path("#{file}/#{pattern.strip}")]
|
||||
end
|
||||
elsif File.file?(file)
|
||||
result << file
|
||||
else
|
||||
raise "File or directory not found: #{file}"
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
protected
|
||||
def examples_should_be_run?
|
||||
return @examples_should_be_run unless @examples_should_be_run.nil?
|
||||
@examples_should_be_run = true
|
||||
end
|
||||
|
||||
def differ_class=(klass)
|
||||
return unless klass
|
||||
@differ_class = klass
|
||||
Spec::Expectations.differ = self.differ_class.new(self)
|
||||
end
|
||||
|
||||
def load_class(name, kind, option)
|
||||
if name =~ /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/
|
||||
arg = $2 == "" ? nil : $2
|
||||
[$1, arg]
|
||||
else
|
||||
m = "#{name.inspect} is not a valid class name"
|
||||
@error_stream.puts m
|
||||
raise m
|
||||
end
|
||||
begin
|
||||
eval(name, binding, __FILE__, __LINE__)
|
||||
rescue NameError => e
|
||||
@error_stream.puts "Couldn't find #{kind} class #{name}"
|
||||
@error_stream.puts "Make sure the --require option is specified *before* #{option}"
|
||||
if $_spec_spec ; raise e ; else exit(1) ; end
|
||||
end
|
||||
end
|
||||
|
||||
def custom_runner
|
||||
return nil unless custom_runner?
|
||||
klass_name, arg = ClassAndArgumentsParser.parse(user_input_for_runner)
|
||||
runner_type = load_class(klass_name, 'behaviour runner', '--runner')
|
||||
return runner_type.new(self, arg)
|
||||
end
|
||||
|
||||
def custom_runner?
|
||||
return user_input_for_runner ? true : false
|
||||
end
|
||||
|
||||
def heckle
|
||||
heckle_runner = self.heckle_runner
|
||||
self.heckle_runner = nil
|
||||
heckle_runner.heckle_with
|
||||
end
|
||||
|
||||
def sorted_files
|
||||
return sorter ? files.sort(&sorter) : files
|
||||
end
|
||||
|
||||
def sorter
|
||||
FILE_SORTERS[loadby]
|
||||
end
|
||||
|
||||
def default_differ
|
||||
require 'spec/expectations/differs/default'
|
||||
self.differ_class = Spec::Expectations::Differs::Default
|
||||
end
|
||||
|
||||
def set_spec_from_line_number
|
||||
if examples.empty?
|
||||
if files.length == 1
|
||||
if File.directory?(files[0])
|
||||
error_stream.puts "You must specify one file, not a directory when using the --line option"
|
||||
exit(1) if stderr?
|
||||
else
|
||||
example = SpecParser.new.spec_name_for(files[0], line_number)
|
||||
@examples = [example]
|
||||
end
|
||||
else
|
||||
error_stream.puts "Only one file can be specified when using the --line option: #{files.inspect}"
|
||||
exit(3) if stderr?
|
||||
end
|
||||
else
|
||||
error_stream.puts "You cannot use both --line and --example"
|
||||
exit(4) if stderr?
|
||||
end
|
||||
end
|
||||
|
||||
def stderr?
|
||||
@error_stream == $stderr
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
147
vendor/plugins/rspec/lib/spec/runner/reporter.rb
vendored
Normal file
147
vendor/plugins/rspec/lib/spec/runner/reporter.rb
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class Reporter
|
||||
attr_reader :options, :example_groups
|
||||
|
||||
def initialize(options)
|
||||
@options = options
|
||||
@options.reporter = self
|
||||
clear
|
||||
end
|
||||
|
||||
def add_example_group(example_group)
|
||||
formatters.each do |f|
|
||||
f.add_example_group(example_group)
|
||||
end
|
||||
example_groups << example_group
|
||||
end
|
||||
|
||||
def example_started(example)
|
||||
formatters.each{|f| f.example_started(example)}
|
||||
end
|
||||
|
||||
def example_finished(example, error=nil)
|
||||
@examples << example
|
||||
|
||||
if error.nil?
|
||||
example_passed(example)
|
||||
elsif Spec::Example::ExamplePendingError === error
|
||||
example_pending(example, error.message)
|
||||
else
|
||||
example_failed(example, error)
|
||||
end
|
||||
end
|
||||
|
||||
def failure(example, error)
|
||||
backtrace_tweaker.tweak_backtrace(error)
|
||||
failure = Failure.new(example, error)
|
||||
@failures << failure
|
||||
formatters.each do |f|
|
||||
f.example_failed(example, @failures.length, failure)
|
||||
end
|
||||
end
|
||||
alias_method :example_failed, :failure
|
||||
|
||||
def start(number_of_examples)
|
||||
clear
|
||||
@start_time = Time.new
|
||||
formatters.each{|f| f.start(number_of_examples)}
|
||||
end
|
||||
|
||||
def end
|
||||
@end_time = Time.new
|
||||
end
|
||||
|
||||
# Dumps the summary and returns the total number of failures
|
||||
def dump
|
||||
formatters.each{|f| f.start_dump}
|
||||
dump_pending
|
||||
dump_failures
|
||||
formatters.each do |f|
|
||||
f.dump_summary(duration, @examples.length, @failures.length, @pending_count)
|
||||
f.close
|
||||
end
|
||||
@failures.length
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def formatters
|
||||
@options.formatters
|
||||
end
|
||||
|
||||
def backtrace_tweaker
|
||||
@options.backtrace_tweaker
|
||||
end
|
||||
|
||||
def clear
|
||||
@example_groups = []
|
||||
@failures = []
|
||||
@pending_count = 0
|
||||
@examples = []
|
||||
@start_time = nil
|
||||
@end_time = nil
|
||||
end
|
||||
|
||||
def dump_failures
|
||||
return if @failures.empty?
|
||||
@failures.inject(1) do |index, failure|
|
||||
formatters.each{|f| f.dump_failure(index, failure)}
|
||||
index + 1
|
||||
end
|
||||
end
|
||||
|
||||
def dump_pending
|
||||
formatters.each{|f| f.dump_pending}
|
||||
end
|
||||
|
||||
def duration
|
||||
return @end_time - @start_time unless (@end_time.nil? or @start_time.nil?)
|
||||
return "0.0"
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
formatters.each{|f| f.example_passed(example)}
|
||||
end
|
||||
|
||||
def example_pending(example, message="Not Yet Implemented")
|
||||
@pending_count += 1
|
||||
formatters.each do |f|
|
||||
f.example_pending(example, message)
|
||||
end
|
||||
end
|
||||
|
||||
class Failure
|
||||
attr_reader :example, :exception
|
||||
|
||||
def initialize(example, exception)
|
||||
@example = example
|
||||
@exception = exception
|
||||
end
|
||||
|
||||
def header
|
||||
if expectation_not_met?
|
||||
"'#{example_name}' FAILED"
|
||||
elsif pending_fixed?
|
||||
"'#{example_name}' FIXED"
|
||||
else
|
||||
"#{@exception.class.name} in '#{example_name}'"
|
||||
end
|
||||
end
|
||||
|
||||
def pending_fixed?
|
||||
@exception.is_a?(Spec::Example::PendingExampleFixedError)
|
||||
end
|
||||
|
||||
def expectation_not_met?
|
||||
@exception.is_a?(Spec::Expectations::ExpectationNotMetError)
|
||||
end
|
||||
|
||||
protected
|
||||
def example_name
|
||||
@example.__full_description
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
71
vendor/plugins/rspec/lib/spec/runner/spec_parser.rb
vendored
Normal file
71
vendor/plugins/rspec/lib/spec/runner/spec_parser.rb
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
module Spec
|
||||
module Runner
|
||||
# Parses a spec file and finds the nearest example for a given line number.
|
||||
class SpecParser
|
||||
attr_reader :best_match
|
||||
|
||||
def initialize
|
||||
@best_match = {}
|
||||
end
|
||||
|
||||
def spec_name_for(file, line_number)
|
||||
best_match.clear
|
||||
file = File.expand_path(file)
|
||||
rspec_options.example_groups.each do |example_group|
|
||||
consider_example_groups_for_best_match example_group, file, line_number
|
||||
|
||||
example_group.examples.each do |example|
|
||||
consider_example_for_best_match example, example_group, file, line_number
|
||||
end
|
||||
end
|
||||
if best_match[:example_group]
|
||||
if best_match[:example]
|
||||
"#{best_match[:example_group].description} #{best_match[:example].description}"
|
||||
else
|
||||
best_match[:example_group].description
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def consider_example_groups_for_best_match(example_group, file, line_number)
|
||||
parsed_backtrace = parse_backtrace(example_group.registration_backtrace)
|
||||
parsed_backtrace.each do |example_file, example_line|
|
||||
if is_best_match?(file, line_number, example_file, example_line)
|
||||
best_match.clear
|
||||
best_match[:example_group] = example_group
|
||||
best_match[:line] = example_line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def consider_example_for_best_match(example, example_group, file, line_number)
|
||||
parsed_backtrace = parse_backtrace(example.implementation_backtrace)
|
||||
parsed_backtrace.each do |example_file, example_line|
|
||||
if is_best_match?(file, line_number, example_file, example_line)
|
||||
best_match.clear
|
||||
best_match[:example_group] = example_group
|
||||
best_match[:example] = example
|
||||
best_match[:line] = example_line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def is_best_match?(file, line_number, example_file, example_line)
|
||||
file == File.expand_path(example_file) &&
|
||||
example_line <= line_number &&
|
||||
example_line > best_match[:line].to_i
|
||||
end
|
||||
|
||||
def parse_backtrace(backtrace)
|
||||
backtrace.collect do |trace_line|
|
||||
split_line = trace_line.split(':')
|
||||
[split_line[0], Integer(split_line[1])]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
10
vendor/plugins/rspec/lib/spec/story.rb
vendored
Normal file
10
vendor/plugins/rspec/lib/spec/story.rb
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
require 'spec'
|
||||
require 'spec/story/extensions'
|
||||
require 'spec/story/given_scenario'
|
||||
require 'spec/story/runner'
|
||||
require 'spec/story/scenario'
|
||||
require 'spec/story/step'
|
||||
require 'spec/story/step_group'
|
||||
require 'spec/story/step_mother'
|
||||
require 'spec/story/story'
|
||||
require 'spec/story/world'
|
||||
3
vendor/plugins/rspec/lib/spec/story/extensions.rb
vendored
Normal file
3
vendor/plugins/rspec/lib/spec/story/extensions.rb
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
require 'spec/story/extensions/main'
|
||||
require 'spec/story/extensions/string'
|
||||
require 'spec/story/extensions/regexp'
|
||||
86
vendor/plugins/rspec/lib/spec/story/extensions/main.rb
vendored
Normal file
86
vendor/plugins/rspec/lib/spec/story/extensions/main.rb
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
module Spec
|
||||
module Story
|
||||
module Extensions
|
||||
module Main
|
||||
def Story(title, narrative, params = {}, &body)
|
||||
::Spec::Story::Runner.story_runner.Story(title, narrative, params, &body)
|
||||
end
|
||||
|
||||
# Calling this deprecated is silly, since it hasn't been released yet. But, for
|
||||
# those who are reading this - this will be deleted before the 1.1 release.
|
||||
def run_story(*args, &block)
|
||||
runner = Spec::Story::Runner::PlainTextStoryRunner.new(*args)
|
||||
runner.instance_eval(&block) if block
|
||||
runner.run
|
||||
end
|
||||
|
||||
# Creates (or appends to an existing) a namespaced group of steps for use in Stories
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# # Creating a new group
|
||||
# steps_for :forms do
|
||||
# When("user enters $value in the $field field") do ... end
|
||||
# When("user submits the $form form") do ... end
|
||||
# end
|
||||
def steps_for(tag, &block)
|
||||
steps = rspec_story_steps[tag]
|
||||
steps.instance_eval(&block) if block
|
||||
steps
|
||||
end
|
||||
|
||||
# Creates a context for running a Plain Text Story with specific groups of Steps.
|
||||
# Also supports adding arbitrary steps that will only be accessible to
|
||||
# the Story being run.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# # Run a Story with one group of steps
|
||||
# with_steps_for :checking_accounts do
|
||||
# run File.dirname(__FILE__) + "/withdraw_cash"
|
||||
# end
|
||||
#
|
||||
# # Run a Story, adding steps that are only available for this Story
|
||||
# with_steps_for :accounts do
|
||||
# Given "user is logged in as account administrator"
|
||||
# run File.dirname(__FILE__) + "/reconcile_accounts"
|
||||
# end
|
||||
#
|
||||
# # Run a Story with steps from two groups
|
||||
# with_steps_for :checking_accounts, :savings_accounts do
|
||||
# run File.dirname(__FILE__) + "/transfer_money"
|
||||
# end
|
||||
#
|
||||
# # Run a Story with a specific Story extension
|
||||
# with_steps_for :login, :navigation do
|
||||
# run File.dirname(__FILE__) + "/user_changes_password", :type => RailsStory
|
||||
# end
|
||||
def with_steps_for(*tags, &block)
|
||||
steps = Spec::Story::StepGroup.new do
|
||||
extend StoryRunnerStepGroupAdapter
|
||||
end
|
||||
tags.each {|tag| steps << rspec_story_steps[tag]}
|
||||
steps.instance_eval(&block) if block
|
||||
steps
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
module StoryRunnerStepGroupAdapter
|
||||
def run(path, options={})
|
||||
runner = Spec::Story::Runner::PlainTextStoryRunner.new(path, options)
|
||||
runner.steps << self
|
||||
runner.run
|
||||
end
|
||||
end
|
||||
|
||||
def rspec_story_steps # :nodoc:
|
||||
$rspec_story_steps ||= Spec::Story::StepGroupHash.new
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include Spec::Story::Extensions::Main
|
||||
9
vendor/plugins/rspec/lib/spec/story/extensions/regexp.rb
vendored
Normal file
9
vendor/plugins/rspec/lib/spec/story/extensions/regexp.rb
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
class Regexp
|
||||
def step_name
|
||||
self.source.gsub '\\$', '$$'
|
||||
end
|
||||
|
||||
def arg_regexp
|
||||
::Spec::Story::Step::PARAM_OR_GROUP_PATTERN
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue