rr 1.1.1 → 3.0.0

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 (223) hide show
  1. checksums.yaml +5 -5
  2. data/Appraisals +6 -0
  3. data/CHANGES.md +102 -1
  4. data/CREDITS.md +5 -0
  5. data/Gemfile +3 -0
  6. data/README.md +91 -110
  7. data/Rakefile +43 -0
  8. data/doc/02_syntax_comparison.md +1 -0
  9. data/gemfiles/ruby_19_rspec_2.gemfile +14 -0
  10. data/gemfiles/ruby_19_rspec_2.gemfile.lock +49 -0
  11. data/gemfiles/ruby_19_rspec_2_rails_4.gemfile +15 -0
  12. data/gemfiles/ruby_19_rspec_2_rails_4.gemfile.lock +119 -0
  13. data/lib/rr/class_instance_method_defined.rb +1 -1
  14. data/lib/rr/core_ext/array.rb +2 -0
  15. data/lib/rr/core_ext/hash.rb +2 -0
  16. data/lib/rr/deprecations.rb +97 -0
  17. data/lib/rr/double.rb +28 -10
  18. data/lib/rr/double_definitions/double_definition.rb +39 -16
  19. data/lib/rr/double_definitions/double_definition_create.rb +5 -5
  20. data/lib/rr/double_definitions/double_definition_create_blank_slate.rb +10 -4
  21. data/lib/rr/double_definitions/double_injections/any_instance_of.rb +1 -1
  22. data/lib/rr/double_definitions/double_injections/instance.rb +2 -2
  23. data/lib/rr/double_definitions/strategies/strategy.rb +27 -8
  24. data/lib/rr/double_definitions/strategies/verification/mock.rb +8 -2
  25. data/lib/rr/double_matches.rb +4 -3
  26. data/lib/rr/dsl.rb +152 -0
  27. data/lib/rr/expectations/any_argument_expectation.rb +4 -4
  28. data/lib/rr/expectations/argument_equality_expectation.rb +43 -5
  29. data/lib/rr/injections/double_injection.rb +67 -19
  30. data/lib/rr/injections/method_missing_injection.rb +37 -6
  31. data/lib/rr/integrations.rb +13 -12
  32. data/lib/rr/integrations/decorator.rb +4 -1
  33. data/lib/rr/integrations/minitest_4.rb +1 -1
  34. data/lib/rr/integrations/minitest_4_active_support.rb +1 -1
  35. data/lib/rr/integrations/rspec/invocation_matcher.rb +0 -8
  36. data/lib/rr/integrations/rspec_2.rb +28 -3
  37. data/lib/rr/keyword_arguments.rb +15 -0
  38. data/lib/rr/method_dispatches/base_method_dispatch.rb +22 -5
  39. data/lib/rr/method_dispatches/method_dispatch.rb +21 -10
  40. data/lib/rr/method_dispatches/method_missing_dispatch.rb +14 -5
  41. data/lib/rr/recorded_call.rb +35 -0
  42. data/lib/rr/recorded_calls.rb +23 -9
  43. data/lib/rr/space.rb +15 -5
  44. data/lib/rr/spy_verification.rb +13 -5
  45. data/lib/rr/version.rb +1 -2
  46. data/lib/rr/wildcard_matchers.rb +10 -10
  47. data/lib/rr/without_autohook.rb +7 -14
  48. data/rr.gemspec +14 -5
  49. data/spec/custom_formatter_for_rspec.rb +18 -0
  50. data/spec/custom_formatter_for_rspec_2.rb +40 -0
  51. data/spec/defines_spec_suite_tasks.rb +57 -0
  52. data/spec/fixtures/rubygems_patch_for_187.rb +598 -0
  53. data/spec/global_helper.rb +38 -0
  54. data/spec/spec.opts +3 -0
  55. data/spec/spec_suite_configuration.rb +126 -0
  56. data/spec/spec_suite_runner.rb +47 -0
  57. data/spec/suites.yml +10 -0
  58. data/spec/suites/rspec_2/functional/any_instance_of_spec.rb +147 -0
  59. data/spec/suites/rspec_2/functional/dont_allow_spec.rb +17 -0
  60. data/spec/suites/rspec_2/functional/mock_bang_spec.rb +20 -0
  61. data/spec/suites/rspec_2/functional/mock_instance_of_spec.rb +14 -0
  62. data/spec/suites/rspec_2/functional/mock_instance_of_strong_spec.rb +15 -0
  63. data/spec/suites/rspec_2/functional/mock_proxy_instance_of_spec.rb +15 -0
  64. data/spec/suites/rspec_2/functional/mock_proxy_spec.rb +14 -0
  65. data/spec/suites/rspec_2/functional/mock_spec.rb +17 -0
  66. data/spec/suites/rspec_2/functional/mock_strong_spec.rb +14 -0
  67. data/spec/suites/rspec_2/functional/received_spec.rb +16 -0
  68. data/spec/suites/rspec_2/functional/spy_spec.rb +102 -0
  69. data/spec/suites/rspec_2/functional/stub_bang_spec.rb +20 -0
  70. data/spec/suites/rspec_2/functional/stub_instance_of_spec.rb +15 -0
  71. data/spec/suites/rspec_2/functional/stub_instance_of_strong_spec.rb +15 -0
  72. data/spec/suites/rspec_2/functional/stub_proxy_instance_of_spec.rb +16 -0
  73. data/spec/suites/rspec_2/functional/stub_proxy_spec.rb +45 -0
  74. data/spec/suites/rspec_2/functional/stub_spec.rb +71 -0
  75. data/spec/suites/rspec_2/functional/stub_strong_spec.rb +15 -0
  76. data/spec/suites/rspec_2/functional/wildcard_matchers_spec.rb +128 -0
  77. data/spec/suites/rspec_2/helper.rb +28 -0
  78. data/spec/suites/rspec_2/integration/minitest_4_spec.rb +109 -0
  79. data/spec/suites/rspec_2/integration/minitest_spec.rb +109 -0
  80. data/spec/suites/rspec_2/spec_helper.rb +3 -0
  81. data/spec/suites/rspec_2/support/matchers/wildcard_matcher_matchers.rb +32 -0
  82. data/spec/suites/rspec_2/support/mixins/double_definition_creator_helpers.rb +173 -0
  83. data/spec/suites/rspec_2/support/mixins/mock_definition_creator_helpers.rb +45 -0
  84. data/spec/suites/rspec_2/support/mixins/proxy_definition_creator_helpers.rb +33 -0
  85. data/spec/suites/rspec_2/support/mixins/stub_creator_helpers.rb +43 -0
  86. data/spec/suites/rspec_2/support/mixins/stub_definition_creator_helpers.rb +45 -0
  87. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_with_never_called_qualifier.rb +39 -0
  88. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_with_times_called_qualifier.rb +50 -0
  89. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_without_qualifiers.rb +131 -0
  90. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/dont_allow.rb +148 -0
  91. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_instance_of.rb +26 -0
  92. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_instance_of_strong.rb +28 -0
  93. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_proxy.rb +11 -0
  94. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_strong.rb +37 -0
  95. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mocking.rb +107 -0
  96. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_instance_of.rb +32 -0
  97. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_instance_of_strong.rb +39 -0
  98. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_proxy.rb +11 -0
  99. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_strong.rb +37 -0
  100. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stubbing.rb +57 -0
  101. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/array_flatten_bug.rb +35 -0
  102. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/block_form.rb +31 -0
  103. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/comparing_arity.rb +63 -0
  104. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/object_is_proxy.rb +43 -0
  105. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/sequential_invocations.rb +26 -0
  106. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/setting_implementation.rb +51 -0
  107. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/yields.rb +81 -0
  108. data/spec/suites/rspec_2/support/shared_examples/space.rb +13 -0
  109. data/spec/suites/rspec_2/support/shared_examples/times_called_expectation.rb +9 -0
  110. data/spec/suites/rspec_2/unit/core_ext/array_spec.rb +39 -0
  111. data/spec/suites/rspec_2/unit/core_ext/enumerable_spec.rb +53 -0
  112. data/spec/suites/rspec_2/unit/core_ext/hash_spec.rb +55 -0
  113. data/spec/suites/rspec_2/unit/core_ext/range_spec.rb +41 -0
  114. data/spec/suites/rspec_2/unit/core_ext/regexp_spec.rb +41 -0
  115. data/spec/suites/rspec_2/unit/deprecations_spec.rb +27 -0
  116. data/spec/suites/rspec_2/unit/double_definitions/child_double_definition_create_spec.rb +114 -0
  117. data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_blank_slate_spec.rb +93 -0
  118. data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_spec.rb +446 -0
  119. data/spec/suites/rspec_2/unit/dsl/double_creators_spec.rb +133 -0
  120. data/spec/suites/rspec_2/unit/dsl/space_spec.rb +99 -0
  121. data/spec/suites/rspec_2/unit/dsl/wildcard_matchers_spec.rb +67 -0
  122. data/spec/suites/rspec_2/unit/errors/rr_error_spec.rb +67 -0
  123. data/spec/suites/rspec_2/unit/expectations/any_argument_expectation_spec.rb +48 -0
  124. data/spec/suites/rspec_2/unit/expectations/anything_argument_equality_expectation_spec.rb +14 -0
  125. data/spec/suites/rspec_2/unit/expectations/argument_equality_expectation_spec.rb +135 -0
  126. data/spec/suites/rspec_2/unit/expectations/boolean_argument_equality_expectation_spec.rb +30 -0
  127. data/spec/suites/rspec_2/unit/expectations/hash_including_argument_equality_expectation_spec.rb +92 -0
  128. data/spec/suites/rspec_2/unit/expectations/satisfy_argument_equality_expectation_spec.rb +61 -0
  129. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/any_times_matcher_spec.rb +22 -0
  130. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_least_matcher_spec.rb +37 -0
  131. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_most_matcher_spec.rb +43 -0
  132. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/integer_matcher_spec.rb +58 -0
  133. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/proc_matcher_spec.rb +35 -0
  134. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/range_matcher_spec.rb +39 -0
  135. data/spec/suites/rspec_2/unit/hash_with_object_id_key_spec.rb +88 -0
  136. data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_spec.rb +533 -0
  137. data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_verify_spec.rb +32 -0
  138. data/spec/suites/rspec_2/unit/integrations/rspec/invocation_matcher_spec.rb +297 -0
  139. data/spec/suites/rspec_2/unit/integrations/rspec_spec.rb +70 -0
  140. data/spec/suites/rspec_2/unit/rr_spec.rb +28 -0
  141. data/spec/suites/rspec_2/unit/space_spec.rb +598 -0
  142. data/spec/suites/rspec_2/unit/spy_verification_spec.rb +133 -0
  143. data/spec/suites/rspec_2/unit/times_called_matchers/any_times_matcher_spec.rb +46 -0
  144. data/spec/suites/rspec_2/unit/times_called_matchers/at_least_matcher_spec.rb +54 -0
  145. data/spec/suites/rspec_2/unit/times_called_matchers/at_most_matcher_spec.rb +69 -0
  146. data/spec/suites/rspec_2/unit/times_called_matchers/integer_matcher_spec.rb +69 -0
  147. data/spec/suites/rspec_2/unit/times_called_matchers/proc_matcher_spec.rb +54 -0
  148. data/spec/suites/rspec_2/unit/times_called_matchers/range_matcher_spec.rb +75 -0
  149. data/spec/suites/rspec_2/unit/times_called_matchers/times_called_matcher_spec.rb +117 -0
  150. data/spec/suites/rspec_2/unit/wildcard_matchers/anything_spec.rb +33 -0
  151. data/spec/suites/rspec_2/unit/wildcard_matchers/boolean_spec.rb +45 -0
  152. data/spec/suites/rspec_2/unit/wildcard_matchers/duck_type_spec.rb +64 -0
  153. data/spec/suites/rspec_2/unit/wildcard_matchers/hash_including_spec.rb +64 -0
  154. data/spec/suites/rspec_2/unit/wildcard_matchers/is_a_spec.rb +55 -0
  155. data/spec/suites/rspec_2/unit/wildcard_matchers/numeric_spec.rb +46 -0
  156. data/spec/suites/rspec_2/unit/wildcard_matchers/satisfy_spec.rb +57 -0
  157. data/spec/support/adapter.rb +22 -0
  158. data/spec/support/adapter_tests/base.rb +45 -0
  159. data/spec/support/adapter_tests/minitest.rb +7 -0
  160. data/spec/support/adapter_tests/rspec.rb +70 -0
  161. data/spec/support/adapter_tests/test_unit.rb +47 -0
  162. data/spec/support/command_runner.rb +105 -0
  163. data/spec/support/generator.rb +56 -0
  164. data/spec/support/integration_tests/base.rb +64 -0
  165. data/spec/support/integration_tests/rails.rb +60 -0
  166. data/spec/support/integration_tests/rails_minitest.rb +13 -0
  167. data/spec/support/integration_tests/rails_rspec.rb +13 -0
  168. data/spec/support/integration_tests/rails_test_unit.rb +13 -0
  169. data/spec/support/integration_tests/rails_test_unit_like.rb +13 -0
  170. data/spec/support/integration_tests/ruby.rb +7 -0
  171. data/spec/support/integration_tests/ruby_minitest.rb +13 -0
  172. data/spec/support/integration_tests/ruby_rspec.rb +13 -0
  173. data/spec/support/integration_tests/ruby_test_unit.rb +13 -0
  174. data/spec/support/matchers/be_a_subset_of_matcher.rb +24 -0
  175. data/spec/support/project/cucumber.rb +50 -0
  176. data/spec/support/project/generator.rb +348 -0
  177. data/spec/support/project/minitest.rb +39 -0
  178. data/spec/support/project/rails.rb +199 -0
  179. data/spec/support/project/rails_minitest.rb +17 -0
  180. data/spec/support/project/rails_rspec.rb +50 -0
  181. data/spec/support/project/rails_test_unit.rb +17 -0
  182. data/spec/support/project/rails_test_unit_like.rb +17 -0
  183. data/spec/support/project/rspec.rb +69 -0
  184. data/spec/support/project/ruby.rb +34 -0
  185. data/spec/support/project/ruby_minitest.rb +11 -0
  186. data/spec/support/project/ruby_rspec.rb +29 -0
  187. data/spec/support/project/ruby_test_unit.rb +11 -0
  188. data/spec/support/project/ruby_test_unit_like.rb +21 -0
  189. data/spec/support/project/test_unit.rb +29 -0
  190. data/spec/support/project/test_unit_like.rb +7 -0
  191. data/spec/support/project/tests_runner.rb +22 -0
  192. data/spec/support/test.sqlite3 +0 -0
  193. data/spec/support/test_case/generator.rb +53 -0
  194. data/spec/support/test_case/minitest.rb +13 -0
  195. data/spec/support/test_case/rspec.rb +19 -0
  196. data/spec/support/test_case/test_unit.rb +21 -0
  197. data/spec/support/test_file/generator.rb +120 -0
  198. data/spec/support/test_file/minitest.rb +19 -0
  199. data/spec/support/test_file/rails_minitest.rb +7 -0
  200. data/spec/support/test_file/rails_rspec.rb +12 -0
  201. data/spec/support/test_file/rails_test_unit.rb +25 -0
  202. data/spec/support/test_file/rspec.rb +33 -0
  203. data/spec/support/test_file/test_unit.rb +36 -0
  204. data/spec/support/test_helper/generator.rb +27 -0
  205. data/spec/support/test_helper/minitest.rb +7 -0
  206. data/spec/support/test_helper/rails.rb +31 -0
  207. data/spec/support/test_helper/rails_minitest.rb +7 -0
  208. data/spec/support/test_helper/rails_rspec.rb +25 -0
  209. data/spec/support/test_helper/rails_test_unit.rb +23 -0
  210. data/spec/support/test_helper/rspec.rb +7 -0
  211. data/spec/support/test_helper/ruby.rb +31 -0
  212. data/spec/support/test_helper/test_unit.rb +7 -0
  213. metadata +240 -19
  214. data/VERSION +0 -1
  215. data/lib/rr/adapters.rb +0 -44
  216. data/lib/rr/adapters/rr_methods.rb +0 -142
  217. data/lib/rr/integrations/rspec_1.rb +0 -46
  218. data/lib/rr/integrations/test_unit_1.rb +0 -63
  219. data/lib/rr/integrations/test_unit_2.rb +0 -15
  220. data/lib/rr/integrations/test_unit_200.rb +0 -27
  221. data/lib/rr/integrations/test_unit_200_active_support.rb +0 -25
  222. data/lib/rr/integrations/test_unit_2_active_support.rb +0 -38
  223. data/lib/rr/proc_from_block.rb +0 -11
@@ -71,12 +71,43 @@ module RR
71
71
  id = BoundObjects.size
72
72
  BoundObjects[id] = subject_class
73
73
 
74
- subject_class.class_eval((<<-METHOD), __FILE__, __LINE__ + 1)
75
- def method_missing(method_name, *args, &block)
76
- obj = ::RR::Injections::MethodMissingInjection::BoundObjects[#{id}]
77
- MethodDispatches::MethodMissingDispatch.new(self, obj, method_name, args, block).call
78
- end
79
- METHOD
74
+ if KeywordArguments.fully_supported?
75
+ subject_class.class_eval((<<-METHOD), __FILE__, __LINE__ + 1)
76
+ def method_missing(method_name, *args, **kwargs, &block)
77
+ if respond_to_missing?(method_name, true)
78
+ super(method_name, *args, **kwargs, &block)
79
+ else
80
+ obj = ::RR::Injections::MethodMissingInjection::BoundObjects[#{id}]
81
+ MethodDispatches::MethodMissingDispatch.new(
82
+ self,
83
+ obj,
84
+ method_name,
85
+ args,
86
+ kwargs,
87
+ block
88
+ ).call
89
+ end
90
+ end
91
+ METHOD
92
+ else
93
+ subject_class.class_eval((<<-METHOD), __FILE__, __LINE__ + 1)
94
+ def method_missing(method_name, *args, &block)
95
+ if respond_to_missing?(method_name, true)
96
+ super(method_name, *args, &block)
97
+ else
98
+ obj = ::RR::Injections::MethodMissingInjection::BoundObjects[#{id}]
99
+ MethodDispatches::MethodMissingDispatch.new(
100
+ self,
101
+ obj,
102
+ method_name,
103
+ args,
104
+ {},
105
+ block
106
+ ).call
107
+ end
108
+ end
109
+ METHOD
110
+ end
80
111
  end
81
112
 
82
113
  def original_method_alias_name
@@ -30,20 +30,21 @@ module RR
30
30
  adapters.select { |adapter| adapter.applies? }
31
31
  end
32
32
 
33
- def self.find_applicable_adapter_matching(pattern)
34
- adapter = adapters.
35
- select { |adapter| adapter.name.to_s =~ pattern }.
33
+ def self.find_applicable_adapter(name)
34
+ adapters.
35
+ select { |adapter| name === adapter.name.to_s }.
36
36
  find { |adapter| adapter.applies? }
37
- if adapter
38
- mod = Module.new
39
- (class << mod; self; end).class_eval do
40
- define_method(:included) do |base|
41
- # Note: This assumes that the thing that is including this module
42
- # is the same that the adapter detected and will hook into.
43
- adapter.hook
44
- end
37
+ end
38
+
39
+ def self.module_shim_for_adapter(adapter)
40
+ mod = Module.new
41
+ (class << mod; self; end).class_eval do
42
+ define_method(:included) do |base|
43
+ # Note: This assumes that the thing that is including this module
44
+ # is the same that the adapter detected and will hook into.
45
+ adapter.load
45
46
  end
46
- mod
47
47
  end
48
+ mod
48
49
  end
49
50
  end
@@ -22,9 +22,12 @@ module RR
22
22
  end
23
23
 
24
24
  def load
25
+ return if @loaded
25
26
  hook
27
+ if RR.debug?
28
+ puts "Loaded adapter: #{name}"
29
+ end
26
30
  @loaded = true
27
- puts "Loaded adapter: #{name}" if RR.debug?
28
31
  rescue => e
29
32
  if RR.debug?
30
33
  puts "Couldn't load adapter #{name}: #{e.class} (#{e.message})"
@@ -36,7 +36,7 @@ module RR
36
36
  def hook
37
37
  assertion_error_class = self.assertion_error_class
38
38
  test_case_class.class_eval do
39
- include RR::Adapters::RRMethods
39
+ include RR::DSL
40
40
  include Mixin
41
41
 
42
42
  unless instance_methods.any? { |method_name| method_name.to_sym == :setup_with_rr }
@@ -20,7 +20,7 @@ module RR
20
20
  def hook
21
21
  parent_adapter_class = self.parent_adapter_class
22
22
  ::ActiveSupport::TestCase.class_eval do
23
- include RR::Adapters::RRMethods
23
+ include RR::DSL
24
24
  include parent_adapter_class::Mixin
25
25
 
26
26
  setup do
@@ -37,11 +37,3 @@ module RR
37
37
  end
38
38
  end
39
39
  end
40
-
41
- module RR
42
- module Adapters
43
- module Rspec
44
- InvocationMatcher = RR::Integrations::RSpec::InvocationMatcher
45
- end
46
- end
47
- end
@@ -1,6 +1,24 @@
1
1
  module RR
2
2
  module Integrations
3
- class RSpec2 < RSpec1
3
+ class RSpec2
4
+ module Mixin
5
+ def setup_mocks_for_rspec
6
+ RR.reset
7
+ end
8
+
9
+ def verify_mocks_for_rspec
10
+ RR.verify
11
+ end
12
+
13
+ def teardown_mocks_for_rspec
14
+ RR.reset
15
+ end
16
+
17
+ def have_received(method = nil)
18
+ RSpec::InvocationMatcher.new(method)
19
+ end
20
+ end
21
+
4
22
  def name
5
23
  'RSpec 2'
6
24
  end
@@ -14,9 +32,16 @@ module RR
14
32
  def hook
15
33
  ::RSpec.configure do |config|
16
34
  config.mock_with Mixin
17
- config.include RR::Adapters::RRMethods
35
+ config.include RR::DSL
18
36
  end
19
- patterns = ::RSpec.configuration.backtrace_clean_patterns
37
+
38
+ patterns =
39
+ if ::RSpec.configuration.respond_to?(:backtrace_exclusion_patterns)
40
+ ::RSpec.configuration.backtrace_exclusion_patterns
41
+ else
42
+ ::RSpec.configuration.backtrace_clean_patterns
43
+ end
44
+
20
45
  unless patterns.include?(RR::Errors::BACKTRACE_IDENTIFIER)
21
46
  patterns.push(RR::Errors::BACKTRACE_IDENTIFIER)
22
47
  end
@@ -0,0 +1,15 @@
1
+ module RR
2
+ module KeywordArguments
3
+ class << self
4
+ if (RUBY_VERSION <=> "3.0.0") >= 0
5
+ def fully_supported?
6
+ true
7
+ end
8
+ else
9
+ def fully_supported?
10
+ false
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -4,7 +4,7 @@ module RR
4
4
  extend Forwardable
5
5
  include Space::Reader
6
6
 
7
- attr_reader :args, :block, :double
7
+ attr_reader :args, :kwargs, :block, :double
8
8
 
9
9
  def call
10
10
  raise NotImplementedError
@@ -12,7 +12,7 @@ module RR
12
12
 
13
13
  protected
14
14
  def find_double_to_attempt
15
- matches = DoubleMatches.new(doubles).find_all_matches(args)
15
+ matches = DoubleMatches.new(doubles).find_all_matches(args, kwargs)
16
16
 
17
17
  unless matches.exact_terminal_doubles_to_attempt.empty?
18
18
  return matches.exact_terminal_doubles_to_attempt.first
@@ -47,8 +47,25 @@ module RR
47
47
  end
48
48
  end
49
49
 
50
- def call_original_method_missing
51
- subject.__send__(MethodMissingDispatch.original_method_missing_alias_name, method_name, *args, &block)
50
+ if KeywordArguments.fully_supported?
51
+ def call_original_method_missing
52
+ subject.__send__(
53
+ MethodMissingDispatch.original_method_missing_alias_name,
54
+ method_name,
55
+ *args,
56
+ **kwargs,
57
+ &block
58
+ )
59
+ end
60
+ else
61
+ def call_original_method_missing
62
+ subject.__send__(
63
+ MethodMissingDispatch.original_method_missing_alias_name,
64
+ method_name,
65
+ *args,
66
+ &block
67
+ )
68
+ end
52
69
  end
53
70
 
54
71
  def implementation_is_original_method?
@@ -70,7 +87,7 @@ module RR
70
87
  message =
71
88
  "On subject #{subject},\n" <<
72
89
  "unexpected method invocation:\n" <<
73
- " #{Double.formatted_name(method_name, args)}\n" <<
90
+ " #{Double.formatted_name(method_name, args, kwargs)}\n" <<
74
91
  "expected invocations:\n" <<
75
92
  Double.list_message_part(doubles)
76
93
  raise RR::Errors.build_error(:DoubleNotFoundError, message)
@@ -3,15 +3,19 @@ module RR
3
3
  class MethodDispatch < BaseMethodDispatch
4
4
  attr_reader :double_injection, :subject
5
5
 
6
- def initialize(double_injection, subject, args, block)
7
- @double_injection, @subject, @args, @block = double_injection, subject, args, block
6
+ def initialize(double_injection, subject, args, kwargs, block)
7
+ @double_injection = double_injection
8
+ @subject = subject
9
+ @args = args
10
+ @kwargs = kwargs
11
+ @block = block
8
12
  @double = find_double_to_attempt
9
13
  end
10
14
 
11
15
  def call
12
- space.record_call(subject, method_name, args, block)
16
+ space.record_call(subject, method_name, args, kwargs, block)
13
17
  if double
14
- double.method_call(args)
18
+ double.method_call(args, kwargs)
15
19
  call_yields
16
20
  return_value_1 = call_implementation
17
21
  return_value_2 = extract_subject_from_return_value(return_value_1)
@@ -27,11 +31,19 @@ module RR
27
31
 
28
32
  def call_original_method
29
33
  if subject_has_original_method?
30
- subject.__send__(original_method_alias_name, *args, &block)
34
+ if KeywordArguments.fully_supported?
35
+ subject.__send__(original_method_alias_name, *args, **kwargs, &block)
36
+ else
37
+ subject.__send__(original_method_alias_name, *args, &block)
38
+ end
31
39
  elsif subject_has_original_method_missing?
32
40
  call_original_method_missing
33
41
  else
34
- subject.__send__(:method_missing, method_name, *args, &block)
42
+ if KeywordArguments.fully_supported?
43
+ subject.__send__(:method_missing, method_name, *args, **kwargs, &block)
44
+ else
45
+ subject.__send__(:method_missing, method_name, *args, &block)
46
+ end
35
47
  end
36
48
  end
37
49
 
@@ -41,11 +53,10 @@ module RR
41
53
  call_original_method
42
54
  else
43
55
  if implementation
44
- if implementation.is_a?(Method)
45
- implementation.call(*args, &block)
56
+ if KeywordArguments.fully_supported?
57
+ implementation.call(*args, **kwargs, &block)
46
58
  else
47
- call_args = block ? args + [ProcFromBlock.new(&block)] : args
48
- implementation.call(*call_args)
59
+ implementation.call(*args, &block)
49
60
  end
50
61
  else
51
62
  nil
@@ -9,8 +9,13 @@ module RR
9
9
 
10
10
  attr_reader :subject, :subject_class, :method_name
11
11
 
12
- def initialize(subject, subject_class, method_name, args, block)
13
- @subject, @subject_class, @method_name, @args, @block = subject, subject_class, method_name, args, block
12
+ def initialize(subject, subject_class, method_name, args, kwargs, block)
13
+ @subject = subject
14
+ @subject_class = subject_class
15
+ @method_name = method_name
16
+ @args = args
17
+ @kwargs = kwargs
18
+ @block = block
14
19
  end
15
20
 
16
21
  def call
@@ -40,14 +45,18 @@ module RR
40
45
  protected
41
46
  def call_implementation
42
47
  if implementation_is_original_method?
43
- space.record_call(subject, method_name, args, block)
44
- double.method_call(args)
48
+ space.record_call(subject, method_name, args, kwargs, block)
49
+ double.method_call(args, kwargs)
45
50
  call_original_method
46
51
  else
47
52
  if double_injection = Injections::DoubleInjection.find(subject_class, method_name)
48
53
  double_injection.bind_method
49
54
  # The DoubleInjection takes care of calling double.method_call
50
- subject.__send__(method_name, *args, &block)
55
+ if KeywordArguments.fully_supported?
56
+ subject.__send__(method_name, *args, **kwargs, &block)
57
+ else
58
+ subject.__send__(method_name, *args, &block)
59
+ end
51
60
  else
52
61
  nil
53
62
  end
@@ -0,0 +1,35 @@
1
+ module RR
2
+ class RecordedCall < Struct.new(:subject,
3
+ :method_name,
4
+ :arguments,
5
+ :keyword_arguments,
6
+ :block)
7
+ def inspect
8
+ '[%s, %s, %s, %s, %s]' % [
9
+ subject_to_s,
10
+ method_name.inspect,
11
+ arguments.inspect,
12
+ keyword_arguments.inspect,
13
+ block.inspect
14
+ ]
15
+ end
16
+
17
+ def ==(other)
18
+ other.is_a?(self.class) &&
19
+ subject == other.subject &&
20
+ method_name == other.method_name &&
21
+ arguments == other.arguments &&
22
+ keyword_arguments == other.keyword_arguments
23
+ end
24
+
25
+ private
26
+
27
+ def subject_to_s
28
+ if subject.respond_to?(:__rr__original_to_s, true)
29
+ subject.__rr__original_to_s
30
+ else
31
+ subject.to_s
32
+ end
33
+ end
34
+ end
35
+ end
@@ -9,13 +9,21 @@ module RR
9
9
 
10
10
  attr_reader :recorded_calls
11
11
 
12
+ def [](index)
13
+ @recorded_calls[index]
14
+ end
15
+
12
16
  def clear
13
17
  self.ordered_index = 0
14
18
  recorded_calls.clear
15
19
  end
16
20
 
17
- def <<(recorded_call)
18
- recorded_calls << recorded_call
21
+ def add(subject, method_name, arguments, keyword_arguments, block)
22
+ recorded_calls << RecordedCall.new(subject,
23
+ method_name,
24
+ arguments,
25
+ keyword_arguments,
26
+ block)
19
27
  end
20
28
 
21
29
  def any?(&block)
@@ -43,9 +51,9 @@ module RR
43
51
  unless Injections::DoubleInjection.exists_by_subject?(spy_verification.subject, spy_verification.method_name)
44
52
  RR::Errors.build_error(RR::Errors::SpyVerificationErrors::DoubleInjectionNotFoundError,
45
53
  "A Double Injection for the subject and method call:\n" <<
46
- "#{spy_verification.subject.inspect}\n" <<
54
+ "#{spy_verification.subject_inspect}\n" <<
47
55
  "#{spy_verification.method_name}\ndoes not exist in:\n" <<
48
- "\t#{recorded_calls.map {|call| call.inspect}.join("\n\t")}"
56
+ "\t#{recorded_calls.map {|call| call.inspect }.join("\n\t")}"
49
57
  )
50
58
  end
51
59
  end
@@ -77,22 +85,28 @@ module RR
77
85
 
78
86
  def match_double_injection(spy_verification)
79
87
  lambda do |recorded_call|
80
- recorded_call[0] == spy_verification.subject &&
81
- recorded_call[1] == spy_verification.method_name
88
+ recorded_call.subject == spy_verification.subject &&
89
+ recorded_call.method_name == spy_verification.method_name
82
90
  end
83
91
  end
84
92
 
85
93
  def match_argument_expectation(spy_verification)
86
94
  lambda do |recorded_call|
87
- spy_verification.argument_expectation.exact_match?(*recorded_call[2]) ||
88
- spy_verification.argument_expectation.wildcard_match?(*recorded_call[2])
95
+ expectation = spy_verification.argument_expectation
96
+ arguments = recorded_call.arguments
97
+ keyword_arguments = recorded_call.keyword_arguments
98
+ expectation.exact_match?(arguments, keyword_arguments) ||
99
+ expectation.wildcard_match?(arguments, keyword_arguments)
89
100
  end
90
101
  end
91
102
 
92
103
  def invocation_count_error(spy_verification, matching_recorded_calls)
104
+ method_name = spy_verification.method_name
105
+ arguments = spy_verification.argument_expectation.expected_arguments
106
+ keyword_arguments = spy_verification.argument_expectation.expected_keyword_arguments
93
107
  RR::Errors.build_error(RR::Errors::SpyVerificationErrors::InvocationCountError,
94
108
  "On subject #{spy_verification.subject.inspect}\n" <<
95
- "Expected #{Double.formatted_name(spy_verification.method_name, spy_verification.argument_expectation.expected_arguments)}\n" <<
109
+ "Expected #{Double.formatted_name(method_name, arguments, keyword_arguments)}\n" <<
96
110
  "to be called #{spy_verification.times_matcher.expected_times_message},\n" <<
97
111
  "but was called #{matching_recorded_calls.size} times.\n" <<
98
112
  "All of the method calls related to Doubles are:\n" <<