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.
Files changed (176) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.gitmodules +15 -0
  4. data/.travis.yml +13 -0
  5. data/.yardopts +5 -0
  6. data/CHANGELOG.md +25 -0
  7. data/Gemfile +8 -0
  8. data/README.md +147 -0
  9. data/Rakefile +26 -0
  10. data/config.ru +10 -0
  11. data/example/Gemfile +4 -0
  12. data/example/README.md +13 -0
  13. data/example/Rakefile +8 -0
  14. data/example/opal/user.rb +11 -0
  15. data/example/spec/user_spec.rb +15 -0
  16. data/lib/opal-rspec.rb +2 -0
  17. data/lib/opal/rspec.rb +20 -0
  18. data/lib/opal/rspec/rake_task.rb +63 -0
  19. data/lib/opal/rspec/version.rb +5 -0
  20. data/opal-rspec.gemspec +21 -0
  21. data/opal/opal-rspec.rb +1 -0
  22. data/opal/opal/rspec.rb +25 -0
  23. data/opal/opal/rspec/async.rb +289 -0
  24. data/opal/opal/rspec/browser_formatter.rb +188 -0
  25. data/opal/opal/rspec/fixes.rb +116 -0
  26. data/opal/opal/rspec/requires.rb +45 -0
  27. data/opal/opal/rspec/runner.rb +69 -0
  28. data/opal/opal/rspec/sprockets_runner.rb.erb +11 -0
  29. data/opal/opal/rspec/text_formatter.rb +74 -0
  30. data/spec/async_spec.rb +38 -0
  31. data/spec/example_spec.rb +163 -0
  32. data/spec/matchers_spec.rb +201 -0
  33. data/spec/mock_spec.rb +63 -0
  34. data/spec/named_subject_spec.rb +11 -0
  35. data/spec/should_syntax_spec.rb +17 -0
  36. data/vendor/spec_runner.js +50 -0
  37. data/vendor_lib/rspec-expectations.rb +1 -0
  38. data/vendor_lib/rspec.rb +3 -0
  39. data/vendor_lib/rspec/autorun.rb +2 -0
  40. data/vendor_lib/rspec/core.rb +203 -0
  41. data/vendor_lib/rspec/core/backport_random.rb +302 -0
  42. data/vendor_lib/rspec/core/backtrace_formatter.rb +65 -0
  43. data/vendor_lib/rspec/core/command_line.rb +36 -0
  44. data/vendor_lib/rspec/core/configuration.rb +1129 -0
  45. data/vendor_lib/rspec/core/configuration_options.rb +143 -0
  46. data/vendor_lib/rspec/core/drb_command_line.rb +26 -0
  47. data/vendor_lib/rspec/core/drb_options.rb +87 -0
  48. data/vendor_lib/rspec/core/dsl.rb +26 -0
  49. data/vendor_lib/rspec/core/example.rb +312 -0
  50. data/vendor_lib/rspec/core/example_group.rb +540 -0
  51. data/vendor_lib/rspec/core/filter_manager.rb +224 -0
  52. data/vendor_lib/rspec/core/flat_map.rb +17 -0
  53. data/vendor_lib/rspec/core/formatters.rb +54 -0
  54. data/vendor_lib/rspec/core/formatters/base_formatter.rb +291 -0
  55. data/vendor_lib/rspec/core/formatters/base_text_formatter.rb +307 -0
  56. data/vendor_lib/rspec/core/formatters/deprecation_formatter.rb +193 -0
  57. data/vendor_lib/rspec/core/formatters/documentation_formatter.rb +67 -0
  58. data/vendor_lib/rspec/core/formatters/helpers.rb +82 -0
  59. data/vendor_lib/rspec/core/formatters/html_formatter.rb +155 -0
  60. data/vendor_lib/rspec/core/formatters/html_printer.rb +408 -0
  61. data/vendor_lib/rspec/core/formatters/json_formatter.rb +99 -0
  62. data/vendor_lib/rspec/core/formatters/progress_formatter.rb +32 -0
  63. data/vendor_lib/rspec/core/formatters/snippet_extractor.rb +101 -0
  64. data/vendor_lib/rspec/core/hooks.rb +535 -0
  65. data/vendor_lib/rspec/core/memoized_helpers.rb +431 -0
  66. data/vendor_lib/rspec/core/metadata.rb +313 -0
  67. data/vendor_lib/rspec/core/mocking/with_absolutely_nothing.rb +11 -0
  68. data/vendor_lib/rspec/core/mocking/with_flexmock.rb +27 -0
  69. data/vendor_lib/rspec/core/mocking/with_mocha.rb +52 -0
  70. data/vendor_lib/rspec/core/mocking/with_rr.rb +27 -0
  71. data/vendor_lib/rspec/core/mocking/with_rspec.rb +27 -0
  72. data/vendor_lib/rspec/core/option_parser.rb +234 -0
  73. data/vendor_lib/rspec/core/ordering.rb +154 -0
  74. data/vendor_lib/rspec/core/pending.rb +110 -0
  75. data/vendor_lib/rspec/core/project_initializer.rb +88 -0
  76. data/vendor_lib/rspec/core/rake_task.rb +128 -0
  77. data/vendor_lib/rspec/core/reporter.rb +132 -0
  78. data/vendor_lib/rspec/core/ruby_project.rb +44 -0
  79. data/vendor_lib/rspec/core/runner.rb +97 -0
  80. data/vendor_lib/rspec/core/shared_context.rb +53 -0
  81. data/vendor_lib/rspec/core/shared_example_group.rb +146 -0
  82. data/vendor_lib/rspec/core/shared_example_group/collection.rb +27 -0
  83. data/vendor_lib/rspec/core/version.rb +7 -0
  84. data/vendor_lib/rspec/core/warnings.rb +22 -0
  85. data/vendor_lib/rspec/core/world.rb +131 -0
  86. data/vendor_lib/rspec/expectations.rb +75 -0
  87. data/vendor_lib/rspec/expectations/differ.rb +154 -0
  88. data/vendor_lib/rspec/expectations/errors.rb +9 -0
  89. data/vendor_lib/rspec/expectations/expectation_target.rb +87 -0
  90. data/vendor_lib/rspec/expectations/extensions.rb +1 -0
  91. data/vendor_lib/rspec/expectations/extensions/object.rb +29 -0
  92. data/vendor_lib/rspec/expectations/fail_with.rb +79 -0
  93. data/vendor_lib/rspec/expectations/handler.rb +68 -0
  94. data/vendor_lib/rspec/expectations/syntax.rb +182 -0
  95. data/vendor_lib/rspec/expectations/version.rb +8 -0
  96. data/vendor_lib/rspec/matchers.rb +633 -0
  97. data/vendor_lib/rspec/matchers/built_in.rb +39 -0
  98. data/vendor_lib/rspec/matchers/built_in/base_matcher.rb +68 -0
  99. data/vendor_lib/rspec/matchers/built_in/be.rb +213 -0
  100. data/vendor_lib/rspec/matchers/built_in/be_instance_of.rb +15 -0
  101. data/vendor_lib/rspec/matchers/built_in/be_kind_of.rb +11 -0
  102. data/vendor_lib/rspec/matchers/built_in/be_within.rb +55 -0
  103. data/vendor_lib/rspec/matchers/built_in/change.rb +141 -0
  104. data/vendor_lib/rspec/matchers/built_in/cover.rb +21 -0
  105. data/vendor_lib/rspec/matchers/built_in/eq.rb +22 -0
  106. data/vendor_lib/rspec/matchers/built_in/eql.rb +23 -0
  107. data/vendor_lib/rspec/matchers/built_in/equal.rb +48 -0
  108. data/vendor_lib/rspec/matchers/built_in/exist.rb +26 -0
  109. data/vendor_lib/rspec/matchers/built_in/has.rb +48 -0
  110. data/vendor_lib/rspec/matchers/built_in/include.rb +61 -0
  111. data/vendor_lib/rspec/matchers/built_in/match.rb +17 -0
  112. data/vendor_lib/rspec/matchers/built_in/match_array.rb +51 -0
  113. data/vendor_lib/rspec/matchers/built_in/raise_error.rb +154 -0
  114. data/vendor_lib/rspec/matchers/built_in/respond_to.rb +74 -0
  115. data/vendor_lib/rspec/matchers/built_in/satisfy.rb +30 -0
  116. data/vendor_lib/rspec/matchers/built_in/start_and_end_with.rb +48 -0
  117. data/vendor_lib/rspec/matchers/built_in/throw_symbol.rb +94 -0
  118. data/vendor_lib/rspec/matchers/built_in/yield.rb +297 -0
  119. data/vendor_lib/rspec/matchers/compatibility.rb +14 -0
  120. data/vendor_lib/rspec/matchers/configuration.rb +113 -0
  121. data/vendor_lib/rspec/matchers/dsl.rb +23 -0
  122. data/vendor_lib/rspec/matchers/generated_descriptions.rb +35 -0
  123. data/vendor_lib/rspec/matchers/matcher.rb +301 -0
  124. data/vendor_lib/rspec/matchers/method_missing.rb +12 -0
  125. data/vendor_lib/rspec/matchers/operator_matcher.rb +99 -0
  126. data/vendor_lib/rspec/matchers/pretty.rb +70 -0
  127. data/vendor_lib/rspec/matchers/test_unit_integration.rb +11 -0
  128. data/vendor_lib/rspec/mocks.rb +100 -0
  129. data/vendor_lib/rspec/mocks/any_instance/chain.rb +92 -0
  130. data/vendor_lib/rspec/mocks/any_instance/expectation_chain.rb +47 -0
  131. data/vendor_lib/rspec/mocks/any_instance/message_chains.rb +75 -0
  132. data/vendor_lib/rspec/mocks/any_instance/recorder.rb +200 -0
  133. data/vendor_lib/rspec/mocks/any_instance/stub_chain.rb +45 -0
  134. data/vendor_lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
  135. data/vendor_lib/rspec/mocks/argument_list_matcher.rb +104 -0
  136. data/vendor_lib/rspec/mocks/argument_matchers.rb +264 -0
  137. data/vendor_lib/rspec/mocks/arity_calculator.rb +66 -0
  138. data/vendor_lib/rspec/mocks/configuration.rb +111 -0
  139. data/vendor_lib/rspec/mocks/error_generator.rb +203 -0
  140. data/vendor_lib/rspec/mocks/errors.rb +12 -0
  141. data/vendor_lib/rspec/mocks/example_methods.rb +201 -0
  142. data/vendor_lib/rspec/mocks/extensions/marshal.rb +17 -0
  143. data/vendor_lib/rspec/mocks/framework.rb +36 -0
  144. data/vendor_lib/rspec/mocks/instance_method_stasher.rb +112 -0
  145. data/vendor_lib/rspec/mocks/matchers/have_received.rb +99 -0
  146. data/vendor_lib/rspec/mocks/matchers/receive.rb +112 -0
  147. data/vendor_lib/rspec/mocks/matchers/receive_messages.rb +72 -0
  148. data/vendor_lib/rspec/mocks/message_expectation.rb +643 -0
  149. data/vendor_lib/rspec/mocks/method_double.rb +209 -0
  150. data/vendor_lib/rspec/mocks/method_reference.rb +95 -0
  151. data/vendor_lib/rspec/mocks/mock.rb +7 -0
  152. data/vendor_lib/rspec/mocks/mutate_const.rb +406 -0
  153. data/vendor_lib/rspec/mocks/object_reference.rb +90 -0
  154. data/vendor_lib/rspec/mocks/order_group.rb +82 -0
  155. data/vendor_lib/rspec/mocks/proxy.rb +269 -0
  156. data/vendor_lib/rspec/mocks/proxy_for_nil.rb +37 -0
  157. data/vendor_lib/rspec/mocks/space.rb +95 -0
  158. data/vendor_lib/rspec/mocks/standalone.rb +3 -0
  159. data/vendor_lib/rspec/mocks/stub_chain.rb +51 -0
  160. data/vendor_lib/rspec/mocks/syntax.rb +374 -0
  161. data/vendor_lib/rspec/mocks/targets.rb +90 -0
  162. data/vendor_lib/rspec/mocks/test_double.rb +109 -0
  163. data/vendor_lib/rspec/mocks/verifying_double.rb +77 -0
  164. data/vendor_lib/rspec/mocks/verifying_message_expecation.rb +60 -0
  165. data/vendor_lib/rspec/mocks/verifying_proxy.rb +151 -0
  166. data/vendor_lib/rspec/mocks/version.rb +7 -0
  167. data/vendor_lib/rspec/support.rb +6 -0
  168. data/vendor_lib/rspec/support/caller_filter.rb +56 -0
  169. data/vendor_lib/rspec/support/spec.rb +14 -0
  170. data/vendor_lib/rspec/support/spec/deprecation_helpers.rb +29 -0
  171. data/vendor_lib/rspec/support/spec/in_sub_process.rb +40 -0
  172. data/vendor_lib/rspec/support/spec/stderr_splitter.rb +50 -0
  173. data/vendor_lib/rspec/support/version.rb +7 -0
  174. data/vendor_lib/rspec/support/warnings.rb +41 -0
  175. data/vendor_lib/rspec/version.rb +5 -0
  176. 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