mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-21 17:50:13 +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
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue