opal-rspec-cj 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.gitmodules +15 -0
- data/.travis.yml +13 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile +8 -0
- data/README.md +147 -0
- data/Rakefile +26 -0
- data/config.ru +10 -0
- data/example/Gemfile +4 -0
- data/example/README.md +13 -0
- data/example/Rakefile +8 -0
- data/example/opal/user.rb +11 -0
- data/example/spec/user_spec.rb +15 -0
- data/lib/opal-rspec.rb +2 -0
- data/lib/opal/rspec.rb +20 -0
- data/lib/opal/rspec/rake_task.rb +63 -0
- data/lib/opal/rspec/version.rb +5 -0
- data/opal-rspec.gemspec +21 -0
- data/opal/opal-rspec.rb +1 -0
- data/opal/opal/rspec.rb +25 -0
- data/opal/opal/rspec/async.rb +289 -0
- data/opal/opal/rspec/browser_formatter.rb +188 -0
- data/opal/opal/rspec/fixes.rb +116 -0
- data/opal/opal/rspec/requires.rb +45 -0
- data/opal/opal/rspec/runner.rb +69 -0
- data/opal/opal/rspec/sprockets_runner.rb.erb +11 -0
- data/opal/opal/rspec/text_formatter.rb +74 -0
- data/spec/async_spec.rb +38 -0
- data/spec/example_spec.rb +163 -0
- data/spec/matchers_spec.rb +201 -0
- data/spec/mock_spec.rb +63 -0
- data/spec/named_subject_spec.rb +11 -0
- data/spec/should_syntax_spec.rb +17 -0
- data/vendor/spec_runner.js +50 -0
- data/vendor_lib/rspec-expectations.rb +1 -0
- data/vendor_lib/rspec.rb +3 -0
- data/vendor_lib/rspec/autorun.rb +2 -0
- data/vendor_lib/rspec/core.rb +203 -0
- data/vendor_lib/rspec/core/backport_random.rb +302 -0
- data/vendor_lib/rspec/core/backtrace_formatter.rb +65 -0
- data/vendor_lib/rspec/core/command_line.rb +36 -0
- data/vendor_lib/rspec/core/configuration.rb +1129 -0
- data/vendor_lib/rspec/core/configuration_options.rb +143 -0
- data/vendor_lib/rspec/core/drb_command_line.rb +26 -0
- data/vendor_lib/rspec/core/drb_options.rb +87 -0
- data/vendor_lib/rspec/core/dsl.rb +26 -0
- data/vendor_lib/rspec/core/example.rb +312 -0
- data/vendor_lib/rspec/core/example_group.rb +540 -0
- data/vendor_lib/rspec/core/filter_manager.rb +224 -0
- data/vendor_lib/rspec/core/flat_map.rb +17 -0
- data/vendor_lib/rspec/core/formatters.rb +54 -0
- data/vendor_lib/rspec/core/formatters/base_formatter.rb +291 -0
- data/vendor_lib/rspec/core/formatters/base_text_formatter.rb +307 -0
- data/vendor_lib/rspec/core/formatters/deprecation_formatter.rb +193 -0
- data/vendor_lib/rspec/core/formatters/documentation_formatter.rb +67 -0
- data/vendor_lib/rspec/core/formatters/helpers.rb +82 -0
- data/vendor_lib/rspec/core/formatters/html_formatter.rb +155 -0
- data/vendor_lib/rspec/core/formatters/html_printer.rb +408 -0
- data/vendor_lib/rspec/core/formatters/json_formatter.rb +99 -0
- data/vendor_lib/rspec/core/formatters/progress_formatter.rb +32 -0
- data/vendor_lib/rspec/core/formatters/snippet_extractor.rb +101 -0
- data/vendor_lib/rspec/core/hooks.rb +535 -0
- data/vendor_lib/rspec/core/memoized_helpers.rb +431 -0
- data/vendor_lib/rspec/core/metadata.rb +313 -0
- data/vendor_lib/rspec/core/mocking/with_absolutely_nothing.rb +11 -0
- data/vendor_lib/rspec/core/mocking/with_flexmock.rb +27 -0
- data/vendor_lib/rspec/core/mocking/with_mocha.rb +52 -0
- data/vendor_lib/rspec/core/mocking/with_rr.rb +27 -0
- data/vendor_lib/rspec/core/mocking/with_rspec.rb +27 -0
- data/vendor_lib/rspec/core/option_parser.rb +234 -0
- data/vendor_lib/rspec/core/ordering.rb +154 -0
- data/vendor_lib/rspec/core/pending.rb +110 -0
- data/vendor_lib/rspec/core/project_initializer.rb +88 -0
- data/vendor_lib/rspec/core/rake_task.rb +128 -0
- data/vendor_lib/rspec/core/reporter.rb +132 -0
- data/vendor_lib/rspec/core/ruby_project.rb +44 -0
- data/vendor_lib/rspec/core/runner.rb +97 -0
- data/vendor_lib/rspec/core/shared_context.rb +53 -0
- data/vendor_lib/rspec/core/shared_example_group.rb +146 -0
- data/vendor_lib/rspec/core/shared_example_group/collection.rb +27 -0
- data/vendor_lib/rspec/core/version.rb +7 -0
- data/vendor_lib/rspec/core/warnings.rb +22 -0
- data/vendor_lib/rspec/core/world.rb +131 -0
- data/vendor_lib/rspec/expectations.rb +75 -0
- data/vendor_lib/rspec/expectations/differ.rb +154 -0
- data/vendor_lib/rspec/expectations/errors.rb +9 -0
- data/vendor_lib/rspec/expectations/expectation_target.rb +87 -0
- data/vendor_lib/rspec/expectations/extensions.rb +1 -0
- data/vendor_lib/rspec/expectations/extensions/object.rb +29 -0
- data/vendor_lib/rspec/expectations/fail_with.rb +79 -0
- data/vendor_lib/rspec/expectations/handler.rb +68 -0
- data/vendor_lib/rspec/expectations/syntax.rb +182 -0
- data/vendor_lib/rspec/expectations/version.rb +8 -0
- data/vendor_lib/rspec/matchers.rb +633 -0
- data/vendor_lib/rspec/matchers/built_in.rb +39 -0
- data/vendor_lib/rspec/matchers/built_in/base_matcher.rb +68 -0
- data/vendor_lib/rspec/matchers/built_in/be.rb +213 -0
- data/vendor_lib/rspec/matchers/built_in/be_instance_of.rb +15 -0
- data/vendor_lib/rspec/matchers/built_in/be_kind_of.rb +11 -0
- data/vendor_lib/rspec/matchers/built_in/be_within.rb +55 -0
- data/vendor_lib/rspec/matchers/built_in/change.rb +141 -0
- data/vendor_lib/rspec/matchers/built_in/cover.rb +21 -0
- data/vendor_lib/rspec/matchers/built_in/eq.rb +22 -0
- data/vendor_lib/rspec/matchers/built_in/eql.rb +23 -0
- data/vendor_lib/rspec/matchers/built_in/equal.rb +48 -0
- data/vendor_lib/rspec/matchers/built_in/exist.rb +26 -0
- data/vendor_lib/rspec/matchers/built_in/has.rb +48 -0
- data/vendor_lib/rspec/matchers/built_in/include.rb +61 -0
- data/vendor_lib/rspec/matchers/built_in/match.rb +17 -0
- data/vendor_lib/rspec/matchers/built_in/match_array.rb +51 -0
- data/vendor_lib/rspec/matchers/built_in/raise_error.rb +154 -0
- data/vendor_lib/rspec/matchers/built_in/respond_to.rb +74 -0
- data/vendor_lib/rspec/matchers/built_in/satisfy.rb +30 -0
- data/vendor_lib/rspec/matchers/built_in/start_and_end_with.rb +48 -0
- data/vendor_lib/rspec/matchers/built_in/throw_symbol.rb +94 -0
- data/vendor_lib/rspec/matchers/built_in/yield.rb +297 -0
- data/vendor_lib/rspec/matchers/compatibility.rb +14 -0
- data/vendor_lib/rspec/matchers/configuration.rb +113 -0
- data/vendor_lib/rspec/matchers/dsl.rb +23 -0
- data/vendor_lib/rspec/matchers/generated_descriptions.rb +35 -0
- data/vendor_lib/rspec/matchers/matcher.rb +301 -0
- data/vendor_lib/rspec/matchers/method_missing.rb +12 -0
- data/vendor_lib/rspec/matchers/operator_matcher.rb +99 -0
- data/vendor_lib/rspec/matchers/pretty.rb +70 -0
- data/vendor_lib/rspec/matchers/test_unit_integration.rb +11 -0
- data/vendor_lib/rspec/mocks.rb +100 -0
- data/vendor_lib/rspec/mocks/any_instance/chain.rb +92 -0
- data/vendor_lib/rspec/mocks/any_instance/expectation_chain.rb +47 -0
- data/vendor_lib/rspec/mocks/any_instance/message_chains.rb +75 -0
- data/vendor_lib/rspec/mocks/any_instance/recorder.rb +200 -0
- data/vendor_lib/rspec/mocks/any_instance/stub_chain.rb +45 -0
- data/vendor_lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
- data/vendor_lib/rspec/mocks/argument_list_matcher.rb +104 -0
- data/vendor_lib/rspec/mocks/argument_matchers.rb +264 -0
- data/vendor_lib/rspec/mocks/arity_calculator.rb +66 -0
- data/vendor_lib/rspec/mocks/configuration.rb +111 -0
- data/vendor_lib/rspec/mocks/error_generator.rb +203 -0
- data/vendor_lib/rspec/mocks/errors.rb +12 -0
- data/vendor_lib/rspec/mocks/example_methods.rb +201 -0
- data/vendor_lib/rspec/mocks/extensions/marshal.rb +17 -0
- data/vendor_lib/rspec/mocks/framework.rb +36 -0
- data/vendor_lib/rspec/mocks/instance_method_stasher.rb +112 -0
- data/vendor_lib/rspec/mocks/matchers/have_received.rb +99 -0
- data/vendor_lib/rspec/mocks/matchers/receive.rb +112 -0
- data/vendor_lib/rspec/mocks/matchers/receive_messages.rb +72 -0
- data/vendor_lib/rspec/mocks/message_expectation.rb +643 -0
- data/vendor_lib/rspec/mocks/method_double.rb +209 -0
- data/vendor_lib/rspec/mocks/method_reference.rb +95 -0
- data/vendor_lib/rspec/mocks/mock.rb +7 -0
- data/vendor_lib/rspec/mocks/mutate_const.rb +406 -0
- data/vendor_lib/rspec/mocks/object_reference.rb +90 -0
- data/vendor_lib/rspec/mocks/order_group.rb +82 -0
- data/vendor_lib/rspec/mocks/proxy.rb +269 -0
- data/vendor_lib/rspec/mocks/proxy_for_nil.rb +37 -0
- data/vendor_lib/rspec/mocks/space.rb +95 -0
- data/vendor_lib/rspec/mocks/standalone.rb +3 -0
- data/vendor_lib/rspec/mocks/stub_chain.rb +51 -0
- data/vendor_lib/rspec/mocks/syntax.rb +374 -0
- data/vendor_lib/rspec/mocks/targets.rb +90 -0
- data/vendor_lib/rspec/mocks/test_double.rb +109 -0
- data/vendor_lib/rspec/mocks/verifying_double.rb +77 -0
- data/vendor_lib/rspec/mocks/verifying_message_expecation.rb +60 -0
- data/vendor_lib/rspec/mocks/verifying_proxy.rb +151 -0
- data/vendor_lib/rspec/mocks/version.rb +7 -0
- data/vendor_lib/rspec/support.rb +6 -0
- data/vendor_lib/rspec/support/caller_filter.rb +56 -0
- data/vendor_lib/rspec/support/spec.rb +14 -0
- data/vendor_lib/rspec/support/spec/deprecation_helpers.rb +29 -0
- data/vendor_lib/rspec/support/spec/in_sub_process.rb +40 -0
- data/vendor_lib/rspec/support/spec/stderr_splitter.rb +50 -0
- data/vendor_lib/rspec/support/version.rb +7 -0
- data/vendor_lib/rspec/support/warnings.rb +41 -0
- data/vendor_lib/rspec/version.rb +5 -0
- metadata +268 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
UnsupportedMatcherError = Class.new(StandardError)
|
|
4
|
+
NegationUnsupportedError = Class.new(StandardError)
|
|
5
|
+
|
|
6
|
+
class TargetBase
|
|
7
|
+
def initialize(target)
|
|
8
|
+
@target = target
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.delegate_to(matcher_method)
|
|
12
|
+
define_method(:to) do |matcher, &block|
|
|
13
|
+
unless Matchers::Receive === matcher || Matchers::ReceiveMessages === matcher
|
|
14
|
+
raise_unsupported_matcher(:to, matcher)
|
|
15
|
+
end
|
|
16
|
+
define_matcher(matcher, matcher_method, &block)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.delegate_not_to(matcher_method, options = {})
|
|
21
|
+
method_name = options.fetch(:from)
|
|
22
|
+
define_method(method_name) do |matcher, &block|
|
|
23
|
+
case matcher
|
|
24
|
+
when Matchers::Receive then define_matcher(matcher, matcher_method, &block)
|
|
25
|
+
when Matchers::ReceiveMessages then raise_negation_unsupported(method_name, matcher)
|
|
26
|
+
else
|
|
27
|
+
raise_unsupported_matcher(method_name, matcher)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.disallow_negation(method_name)
|
|
33
|
+
define_method(method_name) do |matcher, *args|
|
|
34
|
+
raise_negation_unsupported(method_name, matcher)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def define_matcher(matcher, name, &block)
|
|
41
|
+
matcher.__send__(name, @target, &block)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def raise_unsupported_matcher(method_name, matcher)
|
|
45
|
+
raise UnsupportedMatcherError,
|
|
46
|
+
"only the `receive` or `receive_messages` matchers are supported " +
|
|
47
|
+
"with `#{expression}(...).#{method_name}`, but you have provided: #{matcher}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def raise_negation_unsupported(method_name, matcher)
|
|
51
|
+
raise NegationUnsupportedError,
|
|
52
|
+
"`#{expression}(...).#{method_name} #{matcher.name}` is not supported since it " +
|
|
53
|
+
"doesn't really make sense. What would it even mean?"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def expression
|
|
57
|
+
self.class::EXPRESSION
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class AllowanceTarget < TargetBase
|
|
62
|
+
EXPRESSION = :allow
|
|
63
|
+
delegate_to :setup_allowance
|
|
64
|
+
disallow_negation :not_to
|
|
65
|
+
disallow_negation :to_not
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class ExpectationTarget < TargetBase
|
|
69
|
+
EXPRESSION = :expect
|
|
70
|
+
delegate_to :setup_expectation
|
|
71
|
+
delegate_not_to :setup_negative_expectation, :from => :not_to
|
|
72
|
+
delegate_not_to :setup_negative_expectation, :from => :to_not
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class AnyInstanceAllowanceTarget < TargetBase
|
|
76
|
+
EXPRESSION = :allow_any_instance_of
|
|
77
|
+
delegate_to :setup_any_instance_allowance
|
|
78
|
+
disallow_negation :not_to
|
|
79
|
+
disallow_negation :to_not
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class AnyInstanceExpectationTarget < TargetBase
|
|
83
|
+
EXPRESSION = :expect_any_instance_of
|
|
84
|
+
delegate_to :setup_any_instance_expectation
|
|
85
|
+
delegate_not_to :setup_any_instance_negative_expectation, :from => :not_to
|
|
86
|
+
delegate_not_to :setup_any_instance_negative_expectation, :from => :to_not
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
# Implements the methods needed for a pure test double. RSpec::Mocks::Mock
|
|
4
|
+
# includes this module, and it is provided for cases where you want a
|
|
5
|
+
# pure test double without subclassing RSpec::Mocks::Mock.
|
|
6
|
+
module TestDouble
|
|
7
|
+
# Extends the TestDouble module onto the given object and
|
|
8
|
+
# initializes it as a test double.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
#
|
|
12
|
+
# module = Module.new
|
|
13
|
+
# RSpec::Mocks::TestDouble.extend_onto(module, "MyMixin", :foo => "bar")
|
|
14
|
+
# module.foo #=> "bar"
|
|
15
|
+
def self.extend_onto(object, name=nil, stubs={})
|
|
16
|
+
object.extend self
|
|
17
|
+
object.send(:__initialize_as_test_double, name, stubs)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Creates a new test double with a `name` (that will be used in error
|
|
21
|
+
# messages only)
|
|
22
|
+
def initialize(name=nil, stubs={})
|
|
23
|
+
__initialize_as_test_double(name, stubs)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Tells the object to respond to all messages. If specific stub values
|
|
27
|
+
# are declared, they'll work as expected. If not, the receiver is
|
|
28
|
+
# returned.
|
|
29
|
+
def as_null_object
|
|
30
|
+
__mock_proxy.as_null_object
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns true if this object has received `as_null_object`
|
|
34
|
+
def null_object?
|
|
35
|
+
__mock_proxy.null_object?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# This allows for comparing the mock to other objects that proxy such as
|
|
39
|
+
# ActiveRecords belongs_to proxy objects. By making the other object run
|
|
40
|
+
# the comparison, we're sure the call gets delegated to the proxy
|
|
41
|
+
# target.
|
|
42
|
+
def ==(other)
|
|
43
|
+
other == __mock_proxy
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @private
|
|
47
|
+
def inspect
|
|
48
|
+
"#<#{self.class}:#{sprintf '0x%x', self.object_id} @name=#{@name.inspect}>"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @private
|
|
52
|
+
def to_s
|
|
53
|
+
inspect.gsub('<','[').gsub('>',']')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
alias_method :to_str, :to_s
|
|
57
|
+
|
|
58
|
+
# @private
|
|
59
|
+
def respond_to?(message, incl_private=false)
|
|
60
|
+
__mock_proxy.null_object? ? true : super
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @private
|
|
64
|
+
def __build_mock_proxy(order_group)
|
|
65
|
+
Proxy.new(self, order_group, @name)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def __initialize_as_test_double(name=nil, stubs={})
|
|
71
|
+
if Hash === name && stubs.empty?
|
|
72
|
+
stubs = name
|
|
73
|
+
@name = nil
|
|
74
|
+
else
|
|
75
|
+
@name = name
|
|
76
|
+
end
|
|
77
|
+
assign_stubs(stubs)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def method_missing(message, *args, &block)
|
|
81
|
+
if __mock_proxy.null_object?
|
|
82
|
+
case message
|
|
83
|
+
when :to_int then return 0
|
|
84
|
+
when :to_a, :to_ary then return nil
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
__mock_proxy.record_message_received(message, *args, &block)
|
|
88
|
+
|
|
89
|
+
begin
|
|
90
|
+
__mock_proxy.null_object? ? self : super
|
|
91
|
+
rescue NameError
|
|
92
|
+
# Required wrapping doubles in an Array on Ruby 1.9.2
|
|
93
|
+
raise NoMethodError if [:to_a, :to_ary].include? message
|
|
94
|
+
__mock_proxy.raise_unexpected_message_error(message, *args)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def assign_stubs(stubs)
|
|
99
|
+
stubs.each_pair do |message, response|
|
|
100
|
+
__mock_proxy.add_simple_stub(message, response)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def __mock_proxy
|
|
105
|
+
::RSpec::Mocks.proxy_for(self)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'rspec/mocks/mock'
|
|
2
|
+
require 'rspec/mocks/verifying_proxy'
|
|
3
|
+
|
|
4
|
+
module RSpec
|
|
5
|
+
module Mocks
|
|
6
|
+
|
|
7
|
+
module VerifyingDouble
|
|
8
|
+
def method_missing(message, *args, &block)
|
|
9
|
+
# Null object conditional is an optimization. If not a null object,
|
|
10
|
+
# validity of method expectations will have been checked at definition
|
|
11
|
+
# time.
|
|
12
|
+
__mock_proxy.ensure_implemented(message) if null_object?
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# A mock providing a custom proxy that can verify the validity of any
|
|
18
|
+
# method stubs or expectations against the public instance methods of the
|
|
19
|
+
# given class.
|
|
20
|
+
class InstanceVerifyingDouble
|
|
21
|
+
include TestDouble
|
|
22
|
+
include VerifyingDouble
|
|
23
|
+
|
|
24
|
+
def initialize(doubled_module, *args)
|
|
25
|
+
@doubled_module = doubled_module
|
|
26
|
+
|
|
27
|
+
__initialize_as_test_double(doubled_module, *args)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def __build_mock_proxy(order_group)
|
|
31
|
+
VerifyingProxy.new(self, order_group,
|
|
32
|
+
@doubled_module,
|
|
33
|
+
InstanceMethodReference
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# An awkward module necessary because we cannot otherwise have
|
|
39
|
+
# ClassVerifyingDouble inherit from Module and still share these methods.
|
|
40
|
+
module ObjectVerifyingDoubleMethods
|
|
41
|
+
include TestDouble
|
|
42
|
+
include VerifyingDouble
|
|
43
|
+
|
|
44
|
+
def initialize(doubled_module, *args)
|
|
45
|
+
@doubled_module = doubled_module
|
|
46
|
+
|
|
47
|
+
__initialize_as_test_double(doubled_module, *args)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def __build_mock_proxy(order_group)
|
|
51
|
+
VerifyingProxy.new(self, order_group,
|
|
52
|
+
@doubled_module,
|
|
53
|
+
ObjectMethodReference
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def as_stubbed_const(options = {})
|
|
58
|
+
ConstantMutator.stub(@doubled_module.const_to_replace, self, options)
|
|
59
|
+
self
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Similar to an InstanceVerifyingDouble, except that it verifies against
|
|
64
|
+
# public methods of the given object.
|
|
65
|
+
class ObjectVerifyingDouble
|
|
66
|
+
include ObjectVerifyingDoubleMethods
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Effectively the same as an ObjectVerifyingDouble (since a class is a type
|
|
70
|
+
# of object), except with Module in the inheritance chain so that
|
|
71
|
+
# transferring nested constants to work.
|
|
72
|
+
class ClassVerifyingDouble < Module
|
|
73
|
+
include ObjectVerifyingDoubleMethods
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'rspec/mocks/arity_calculator'
|
|
2
|
+
|
|
3
|
+
module RSpec
|
|
4
|
+
module Mocks
|
|
5
|
+
|
|
6
|
+
# A message expectation that knows about the real implementation of the
|
|
7
|
+
# message being expected, so that it can verify that any expectations
|
|
8
|
+
# have the correct arity.
|
|
9
|
+
class VerifyingMessageExpectation < MessageExpectation
|
|
10
|
+
|
|
11
|
+
# A level of indirection is used here rather than just passing in the
|
|
12
|
+
# method itself, since method look up is expensive and we only want to
|
|
13
|
+
# do it if actually needed.
|
|
14
|
+
#
|
|
15
|
+
# Conceptually the method reference makes more sense as a constructor
|
|
16
|
+
# argument since it should be immutable, but it is significantly more
|
|
17
|
+
# straight forward to build the object in pieces so for now it stays as
|
|
18
|
+
# an accessor.
|
|
19
|
+
attr_accessor :method_reference
|
|
20
|
+
|
|
21
|
+
def initialize(*args)
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @override
|
|
26
|
+
def with(*args, &block)
|
|
27
|
+
unless ArgumentMatchers::AnyArgsMatcher === args.first
|
|
28
|
+
expected_arity = if ArgumentMatchers::NoArgsMatcher === args.first
|
|
29
|
+
0
|
|
30
|
+
elsif args.length > 0
|
|
31
|
+
args.length
|
|
32
|
+
else
|
|
33
|
+
# No arguments given, this will raise.
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
ensure_arity!(expected_arity)
|
|
38
|
+
end
|
|
39
|
+
super
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def ensure_arity!(actual)
|
|
45
|
+
return if method_reference.nil?
|
|
46
|
+
|
|
47
|
+
method_reference.when_defined do |method|
|
|
48
|
+
calculator = ArityCalculator.new(method)
|
|
49
|
+
unless calculator.within_range?(actual)
|
|
50
|
+
# Fail fast is required, otherwise the message expecation will fail
|
|
51
|
+
# as well ("expected method not called") and clobber this one.
|
|
52
|
+
@failed_fast = true
|
|
53
|
+
@error_generator.raise_arity_error(calculator, actual)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
require 'rspec/mocks/verifying_message_expecation'
|
|
2
|
+
require 'rspec/mocks/method_reference'
|
|
3
|
+
|
|
4
|
+
module RSpec
|
|
5
|
+
module Mocks
|
|
6
|
+
|
|
7
|
+
module VerifyingProxyMethods
|
|
8
|
+
def add_stub(location, method_name, opts={}, &implementation)
|
|
9
|
+
ensure_implemented(method_name)
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def add_simple_stub(method_name, *args)
|
|
14
|
+
ensure_implemented(method_name)
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add_message_expectation(location, method_name, opts={}, &block)
|
|
19
|
+
ensure_implemented(method_name)
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def ensure_implemented(method_name)
|
|
24
|
+
return unless @doubled_module.defined?
|
|
25
|
+
|
|
26
|
+
method_reference[method_name].when_unimplemented do
|
|
27
|
+
@error_generator.raise_unimplemented_error(
|
|
28
|
+
@doubled_module,
|
|
29
|
+
method_name
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# A verifying proxy mostly acts like a normal proxy, except that it
|
|
36
|
+
# contains extra logic to try and determine the validity of any expectation
|
|
37
|
+
# set on it. This includes whether or not methods have been defined and the
|
|
38
|
+
# arity of method calls.
|
|
39
|
+
#
|
|
40
|
+
# In all other ways this behaves like a normal proxy. It only adds the
|
|
41
|
+
# verification behaviour to specific methods then delegates to the parent
|
|
42
|
+
# implementation.
|
|
43
|
+
#
|
|
44
|
+
# These checks are only activated if the doubled class has already been
|
|
45
|
+
# loaded, otherwise they are disabled. This allows for testing in
|
|
46
|
+
# isolation.
|
|
47
|
+
#
|
|
48
|
+
# @api private
|
|
49
|
+
class VerifyingProxy < Proxy
|
|
50
|
+
include VerifyingProxyMethods
|
|
51
|
+
|
|
52
|
+
def initialize(object, order_group, name, method_reference_class)
|
|
53
|
+
super(object, order_group)
|
|
54
|
+
@object = object
|
|
55
|
+
@doubled_module = name
|
|
56
|
+
@method_reference_class = method_reference_class
|
|
57
|
+
|
|
58
|
+
# A custom method double is required to pass through a way to lookup
|
|
59
|
+
# methods to determine their arity. This is only relevant if the doubled
|
|
60
|
+
# class is loaded.
|
|
61
|
+
@method_doubles = Hash.new do |h, k|
|
|
62
|
+
h[k] = VerifyingMethodDouble.new(@object, k, self, method_reference[k])
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def method_reference
|
|
67
|
+
@method_reference ||= Hash.new do |h, k|
|
|
68
|
+
h[k] = @method_reference_class.new(@doubled_module, k)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class VerifyingPartialMockProxy < PartialMockProxy
|
|
74
|
+
include VerifyingProxyMethods
|
|
75
|
+
|
|
76
|
+
def initialize(object, expectation_ordering)
|
|
77
|
+
super(object, expectation_ordering)
|
|
78
|
+
@doubled_module = DirectObjectReference.new(object)
|
|
79
|
+
|
|
80
|
+
# A custom method double is required to pass through a way to lookup
|
|
81
|
+
# methods to determine their arity.
|
|
82
|
+
@method_doubles = Hash.new do |h, k|
|
|
83
|
+
h[k] = VerifyingExistingMethodDouble.new(object, k, self)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def method_reference
|
|
88
|
+
@method_doubles
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @api private
|
|
93
|
+
class VerifyingMethodDouble < MethodDouble
|
|
94
|
+
def initialize(object, method_name, proxy, method_reference)
|
|
95
|
+
super(object, method_name, proxy)
|
|
96
|
+
@method_reference = method_reference
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def message_expectation_class
|
|
100
|
+
VerifyingMessageExpectation
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def add_expectation(*arg)
|
|
104
|
+
super.tap { |x| x.method_reference = @method_reference }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def proxy_method_invoked(obj, *args, &block)
|
|
108
|
+
ensure_arity!(args.length)
|
|
109
|
+
super
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
def ensure_arity!(arity)
|
|
115
|
+
@method_reference.when_defined do |method|
|
|
116
|
+
calculator = ArityCalculator.new(method)
|
|
117
|
+
unless calculator.within_range?(arity)
|
|
118
|
+
raise ArgumentError, "wrong number of arguments (#{arity} for #{method.arity})"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @api private
|
|
125
|
+
#
|
|
126
|
+
# A VerifyingMethodDouble fetches the method to verify against from the
|
|
127
|
+
# original object, using a MethodReference. This works for pure doubles,
|
|
128
|
+
# but when the original object is itself the one being modified we need to
|
|
129
|
+
# collapse the reference and the method double into a single object so that
|
|
130
|
+
# we can access the original pristine method definition.
|
|
131
|
+
class VerifyingExistingMethodDouble < VerifyingMethodDouble
|
|
132
|
+
def initialize(object, method_name, proxy)
|
|
133
|
+
super(object, method_name, proxy, self)
|
|
134
|
+
|
|
135
|
+
@valid_method = object.respond_to?(method_name)
|
|
136
|
+
|
|
137
|
+
# Trigger an eager find of the original method since if we find it any
|
|
138
|
+
# later we end up getting a stubbed method with incorrect arity.
|
|
139
|
+
save_original_method!
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def when_defined
|
|
143
|
+
yield original_method
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def when_unimplemented
|
|
147
|
+
yield unless @valid_method
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|