mocha 0.5.6 → 3.1.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 (191) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.github/FUNDING.yml +1 -0
  4. data/.rubocop.yml +92 -0
  5. data/.rubocop_todo.yml +39 -0
  6. data/.yardopts +25 -0
  7. data/CONTRIBUTING.md +7 -0
  8. data/COPYING.md +3 -0
  9. data/Gemfile +17 -0
  10. data/{MIT-LICENSE → MIT-LICENSE.md} +2 -2
  11. data/README.md +361 -0
  12. data/RELEASE.md +1247 -0
  13. data/Rakefile +165 -123
  14. data/gemfiles/Gemfile.minitest.latest +8 -0
  15. data/gemfiles/Gemfile.rubocop +9 -0
  16. data/gemfiles/Gemfile.test-unit.latest +8 -0
  17. data/lib/mocha/any_instance_method.rb +12 -26
  18. data/lib/mocha/any_instance_receiver.rb +20 -0
  19. data/lib/mocha/api.rb +213 -0
  20. data/lib/mocha/argument_iterator.rb +17 -0
  21. data/lib/mocha/backtrace_filter.rb +25 -0
  22. data/lib/mocha/block_matchers.rb +33 -0
  23. data/lib/mocha/cardinality.rb +110 -0
  24. data/lib/mocha/central.rb +33 -22
  25. data/lib/mocha/change_state_side_effect.rb +17 -0
  26. data/lib/mocha/class_methods.rb +67 -0
  27. data/lib/mocha/configuration.rb +338 -0
  28. data/lib/mocha/default_name.rb +15 -0
  29. data/lib/mocha/default_receiver.rb +13 -0
  30. data/lib/mocha/deprecation.rb +6 -15
  31. data/lib/mocha/detection/minitest.rb +25 -0
  32. data/lib/mocha/detection/test_unit.rb +30 -0
  33. data/lib/mocha/error_with_filtered_backtrace.rb +15 -0
  34. data/lib/mocha/exception_raiser.rb +11 -10
  35. data/lib/mocha/expectation.rb +562 -171
  36. data/lib/mocha/expectation_error.rb +9 -14
  37. data/lib/mocha/expectation_error_factory.rb +37 -0
  38. data/lib/mocha/expectation_list.rb +30 -14
  39. data/lib/mocha/hooks.rb +55 -0
  40. data/lib/mocha/ignoring_warning.rb +20 -0
  41. data/lib/mocha/impersonating_any_instance_name.rb +13 -0
  42. data/lib/mocha/impersonating_name.rb +13 -0
  43. data/lib/mocha/in_state_ordering_constraint.rb +17 -0
  44. data/lib/mocha/inspect.rb +54 -30
  45. data/lib/mocha/instance_method.rb +17 -4
  46. data/lib/mocha/integration/assertion_counter.rb +15 -0
  47. data/lib/mocha/integration/minitest/adapter.rb +71 -0
  48. data/lib/mocha/integration/minitest.rb +29 -0
  49. data/lib/mocha/integration/monkey_patcher.rb +26 -0
  50. data/lib/mocha/integration/test_unit/adapter.rb +61 -0
  51. data/lib/mocha/integration/test_unit.rb +29 -0
  52. data/lib/mocha/integration.rb +5 -0
  53. data/lib/mocha/invocation.rb +76 -0
  54. data/lib/mocha/logger.rb +26 -0
  55. data/lib/mocha/macos_version.rb +7 -0
  56. data/lib/mocha/method_matcher.rb +8 -10
  57. data/lib/mocha/minitest.rb +7 -0
  58. data/lib/mocha/mock.rb +333 -108
  59. data/lib/mocha/mockery.rb +192 -0
  60. data/lib/mocha/name.rb +13 -0
  61. data/lib/mocha/not_initialized_error.rb +9 -0
  62. data/lib/mocha/object_methods.rb +183 -0
  63. data/lib/mocha/object_receiver.rb +20 -0
  64. data/lib/mocha/parameter_matchers/all_of.rb +38 -28
  65. data/lib/mocha/parameter_matchers/any_of.rb +44 -33
  66. data/lib/mocha/parameter_matchers/any_parameters.rb +33 -26
  67. data/lib/mocha/parameter_matchers/anything.rb +31 -22
  68. data/lib/mocha/parameter_matchers/base_methods.rb +64 -0
  69. data/lib/mocha/parameter_matchers/equals.rb +36 -25
  70. data/lib/mocha/parameter_matchers/equivalent_uri.rb +65 -0
  71. data/lib/mocha/parameter_matchers/has_entries.rb +48 -29
  72. data/lib/mocha/parameter_matchers/has_entry.rb +90 -42
  73. data/lib/mocha/parameter_matchers/has_key.rb +39 -26
  74. data/lib/mocha/parameter_matchers/has_keys.rb +59 -0
  75. data/lib/mocha/parameter_matchers/has_value.rb +39 -26
  76. data/lib/mocha/parameter_matchers/includes.rb +88 -23
  77. data/lib/mocha/parameter_matchers/instance_methods.rb +28 -0
  78. data/lib/mocha/parameter_matchers/instance_of.rb +37 -26
  79. data/lib/mocha/parameter_matchers/is_a.rb +38 -26
  80. data/lib/mocha/parameter_matchers/kind_of.rb +39 -26
  81. data/lib/mocha/parameter_matchers/not.rb +37 -26
  82. data/lib/mocha/parameter_matchers/optionally.rb +52 -17
  83. data/lib/mocha/parameter_matchers/positional_or_keyword_hash.rb +91 -0
  84. data/lib/mocha/parameter_matchers/regexp_matches.rb +37 -25
  85. data/lib/mocha/parameter_matchers/responds_with.rb +82 -0
  86. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +55 -0
  87. data/lib/mocha/parameter_matchers.rb +12 -5
  88. data/lib/mocha/parameters_matcher.rb +28 -19
  89. data/lib/mocha/raised_exception.rb +13 -0
  90. data/lib/mocha/return_values.rb +13 -18
  91. data/lib/mocha/ruby_version.rb +7 -0
  92. data/lib/mocha/sequence.rb +23 -17
  93. data/lib/mocha/single_return_value.rb +8 -18
  94. data/lib/mocha/state_machine.rb +95 -0
  95. data/lib/mocha/stubbed_method.rb +96 -0
  96. data/lib/mocha/stubbing_error.rb +10 -0
  97. data/lib/mocha/test_unit.rb +7 -0
  98. data/lib/mocha/thrower.rb +15 -0
  99. data/lib/mocha/thrown_object.rb +14 -0
  100. data/lib/mocha/version.rb +5 -0
  101. data/lib/mocha/yield_parameters.rb +12 -20
  102. data/lib/mocha.rb +19 -17
  103. data/mocha.gemspec +40 -0
  104. metadata +129 -145
  105. data/COPYING +0 -3
  106. data/README +0 -35
  107. data/RELEASE +0 -188
  108. data/examples/misc.rb +0 -44
  109. data/examples/mocha.rb +0 -26
  110. data/examples/stubba.rb +0 -65
  111. data/lib/mocha/auto_verify.rb +0 -118
  112. data/lib/mocha/class_method.rb +0 -66
  113. data/lib/mocha/infinite_range.rb +0 -25
  114. data/lib/mocha/is_a.rb +0 -9
  115. data/lib/mocha/metaclass.rb +0 -7
  116. data/lib/mocha/missing_expectation.rb +0 -17
  117. data/lib/mocha/multiple_yields.rb +0 -20
  118. data/lib/mocha/no_yields.rb +0 -11
  119. data/lib/mocha/object.rb +0 -110
  120. data/lib/mocha/parameter_matchers/base.rb +0 -15
  121. data/lib/mocha/parameter_matchers/object.rb +0 -9
  122. data/lib/mocha/pretty_parameters.rb +0 -28
  123. data/lib/mocha/setup_and_teardown.rb +0 -23
  124. data/lib/mocha/single_yield.rb +0 -18
  125. data/lib/mocha/standalone.rb +0 -32
  126. data/lib/mocha/stub.rb +0 -18
  127. data/lib/mocha/test_case_adapter.rb +0 -49
  128. data/lib/mocha_standalone.rb +0 -2
  129. data/lib/stubba.rb +0 -2
  130. data/test/acceptance/expected_invocation_count_acceptance_test.rb +0 -187
  131. data/test/acceptance/mocha_acceptance_test.rb +0 -98
  132. data/test/acceptance/mock_with_initializer_block_acceptance_test.rb +0 -44
  133. data/test/acceptance/mocked_methods_dispatch_acceptance_test.rb +0 -71
  134. data/test/acceptance/optional_parameters_acceptance_test.rb +0 -63
  135. data/test/acceptance/parameter_matcher_acceptance_test.rb +0 -117
  136. data/test/acceptance/partial_mocks_acceptance_test.rb +0 -40
  137. data/test/acceptance/sequence_acceptance_test.rb +0 -179
  138. data/test/acceptance/standalone_acceptance_test.rb +0 -131
  139. data/test/acceptance/stubba_acceptance_test.rb +0 -102
  140. data/test/active_record_test_case.rb +0 -36
  141. data/test/deprecation_disabler.rb +0 -15
  142. data/test/execution_point.rb +0 -34
  143. data/test/integration/mocha_test_result_integration_test.rb +0 -105
  144. data/test/integration/stubba_integration_test.rb +0 -89
  145. data/test/integration/stubba_test_result_integration_test.rb +0 -85
  146. data/test/method_definer.rb +0 -18
  147. data/test/test_helper.rb +0 -12
  148. data/test/test_runner.rb +0 -31
  149. data/test/unit/any_instance_method_test.rb +0 -126
  150. data/test/unit/array_inspect_test.rb +0 -16
  151. data/test/unit/auto_verify_test.rb +0 -129
  152. data/test/unit/central_test.rb +0 -124
  153. data/test/unit/class_method_test.rb +0 -200
  154. data/test/unit/date_time_inspect_test.rb +0 -21
  155. data/test/unit/expectation_error_test.rb +0 -24
  156. data/test/unit/expectation_list_test.rb +0 -75
  157. data/test/unit/expectation_raiser_test.rb +0 -28
  158. data/test/unit/expectation_test.rb +0 -483
  159. data/test/unit/hash_inspect_test.rb +0 -16
  160. data/test/unit/infinite_range_test.rb +0 -53
  161. data/test/unit/metaclass_test.rb +0 -22
  162. data/test/unit/method_matcher_test.rb +0 -23
  163. data/test/unit/missing_expectation_test.rb +0 -42
  164. data/test/unit/mock_test.rb +0 -323
  165. data/test/unit/multiple_yields_test.rb +0 -18
  166. data/test/unit/no_yield_test.rb +0 -18
  167. data/test/unit/object_inspect_test.rb +0 -37
  168. data/test/unit/object_test.rb +0 -165
  169. data/test/unit/parameter_matchers/all_of_test.rb +0 -26
  170. data/test/unit/parameter_matchers/any_of_test.rb +0 -26
  171. data/test/unit/parameter_matchers/anything_test.rb +0 -21
  172. data/test/unit/parameter_matchers/has_entries_test.rb +0 -30
  173. data/test/unit/parameter_matchers/has_entry_test.rb +0 -40
  174. data/test/unit/parameter_matchers/has_key_test.rb +0 -25
  175. data/test/unit/parameter_matchers/has_value_test.rb +0 -25
  176. data/test/unit/parameter_matchers/includes_test.rb +0 -25
  177. data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
  178. data/test/unit/parameter_matchers/is_a_test.rb +0 -25
  179. data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
  180. data/test/unit/parameter_matchers/not_test.rb +0 -26
  181. data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -25
  182. data/test/unit/parameter_matchers/stub_matcher.rb +0 -23
  183. data/test/unit/parameters_matcher_test.rb +0 -121
  184. data/test/unit/return_values_test.rb +0 -63
  185. data/test/unit/sequence_test.rb +0 -104
  186. data/test/unit/setup_and_teardown_test.rb +0 -76
  187. data/test/unit/single_return_value_test.rb +0 -33
  188. data/test/unit/single_yield_test.rb +0 -18
  189. data/test/unit/string_inspect_test.rb +0 -11
  190. data/test/unit/stub_test.rb +0 -24
  191. data/test/unit/yield_parameters_test.rb +0 -93
@@ -1,33 +1,42 @@
1
- require 'mocha/parameter_matchers/base'
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
2
4
 
3
5
  module Mocha
4
-
5
6
  module ParameterMatchers
6
-
7
- # :call-seq: anything -> parameter_matcher
8
- #
9
- # Matches any object.
10
- # object = mock()
11
- # object.expects(:method_1).with(anything)
12
- # object.method_1('foo')
13
- # # no error raised
14
- def anything
15
- Anything.new
7
+ module Methods
8
+ # Matches any object.
9
+ #
10
+ # @return [Anything] parameter matcher.
11
+ #
12
+ # @see Expectation#with
13
+ #
14
+ # @example Any object will match.
15
+ # object = mock()
16
+ # object.expects(:method_1).with(anything)
17
+ # object.method_1('foo')
18
+ # object.method_1(789)
19
+ # object.method_1(:bar)
20
+ # # no error raised
21
+ def anything
22
+ Anything.new
23
+ end
16
24
  end
17
-
18
- class Anything < Base # :nodoc:
19
-
25
+
26
+ # Parameter matcher which always matches a single parameter.
27
+ class Anything
28
+ include BaseMethods
29
+
30
+ # @private
20
31
  def matches?(available_parameters)
21
32
  available_parameters.shift
22
- return true
33
+ true
23
34
  end
24
-
35
+
36
+ # @private
25
37
  def mocha_inspect
26
- "anything"
38
+ 'anything'
27
39
  end
28
-
29
40
  end
30
-
31
41
  end
32
-
33
- end
42
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/deprecation'
4
+
5
+ module Mocha
6
+ module ParameterMatchers
7
+ # @abstract Include and implement +#matches?+ and +#mocha_inspect+ to define a custom matcher. Also add a suitably named instance method to {Methods} to build an instance of the new matcher c.f. {Methods#equals}.
8
+ module BaseMethods
9
+ # A shorthand way of combining two matchers when both must match.
10
+ #
11
+ # Returns a new {AllOf} parameter matcher combining two matchers using a logical AND.
12
+ #
13
+ # This shorthand will not work with an implicit equals match. Instead, an explicit {Equals} matcher should be used.
14
+ #
15
+ # @param [BaseMethods] other parameter matcher.
16
+ # @return [AllOf] parameter matcher.
17
+ #
18
+ # @see Expectation#with
19
+ #
20
+ # @example Alternative ways to combine matchers with a logical AND.
21
+ # object = mock()
22
+ # object.expects(:run).with(all_of(has_key(:foo), has_key(:bar)))
23
+ # object.run(foo: 'foovalue', bar: 'barvalue')
24
+ #
25
+ # # is exactly equivalent to
26
+ #
27
+ # object.expects(:run).with(has_key(:foo) & has_key(:bar))
28
+ # object.run(foo: 'foovalue', bar: 'barvalue)
29
+ def &(other)
30
+ AllOf.new(self, other)
31
+ end
32
+
33
+ # A shorthand way of combining two matchers when at least one must match.
34
+ #
35
+ # Returns a new +AnyOf+ parameter matcher combining two matchers using a logical OR.
36
+ #
37
+ # This shorthand will not work with an implicit equals match. Instead, an explicit {Equals} matcher should be used.
38
+ #
39
+ # @param [BaseMethods] other parameter matcher.
40
+ # @return [AnyOf] parameter matcher.
41
+ #
42
+ # @see Expectation#with
43
+ #
44
+ # @example Alternative ways to combine matchers with a logical OR.
45
+ # object = mock()
46
+ # object.expects(:run).with(any_of(has_key(:foo), has_key(:bar)))
47
+ # object.run(foo: 'foovalue')
48
+ #
49
+ # # is exactly equivalent to
50
+ #
51
+ # object.expects(:run).with(has_key(:foo) | has_key(:bar))
52
+ # object.run(foo: 'foovalue')
53
+ #
54
+ # @example Using an explicit {Equals} matcher in combination with {#|}.
55
+ # object.expects(:run).with(equals(1) | equals(2))
56
+ # object.run(1) # passes
57
+ # object.run(2) # passes
58
+ # object.run(3) # fails
59
+ def |(other)
60
+ AnyOf.new(self, other)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,42 +1,53 @@
1
- require 'mocha/parameter_matchers/base'
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
2
4
 
3
5
  module Mocha
4
-
5
6
  module ParameterMatchers
6
-
7
- # :call-seq: equals(value) -> parameter_matcher
8
- #
9
- # Matches +Object+ equalling +value+.
10
- # object = mock()
11
- # object.expects(:method_1).with(equals(2))
12
- # object.method_1(2)
13
- # # no error raised
14
- #
15
- # object = mock()
16
- # object.expects(:method_1).with(equals(2))
17
- # object.method_1(3)
18
- # # error raised, because method_1 was not called with Object equalling 3
19
- def equals(value)
20
- Equals.new(value)
7
+ module Methods
8
+ # Matches any +Object+ equalling +value+.
9
+ #
10
+ # @param [Object] value expected value.
11
+ # @return [Equals] parameter matcher.
12
+ #
13
+ # @see Expectation#with
14
+ # @see Object#==
15
+ #
16
+ # @example Actual parameter equals expected parameter.
17
+ # object = mock()
18
+ # object.expects(:method_1).with(equals(2))
19
+ # object.method_1(2)
20
+ # # no error raised
21
+ #
22
+ # @example Actual parameter does not equal expected parameter.
23
+ # object = mock()
24
+ # object.expects(:method_1).with(equals(2))
25
+ # object.method_1(3)
26
+ # # error raised, because method_1 was not called with an +Object+ that equals 2
27
+ def equals(value)
28
+ Equals.new(value)
29
+ end
21
30
  end
22
31
 
23
- class Equals < Base # :nodoc:
24
-
32
+ # Parameter matcher which matches when actual parameter equals expected value.
33
+ class Equals
34
+ include BaseMethods
35
+
36
+ # @private
25
37
  def initialize(value)
26
38
  @value = value
27
39
  end
28
-
40
+
41
+ # @private
29
42
  def matches?(available_parameters)
30
43
  parameter = available_parameters.shift
31
44
  parameter == @value
32
45
  end
33
-
46
+
47
+ # @private
34
48
  def mocha_inspect
35
49
  @value.mocha_inspect
36
50
  end
37
-
38
51
  end
39
-
40
52
  end
41
-
42
- end
53
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
4
+ require 'uri'
5
+
6
+ module Mocha
7
+ module ParameterMatchers
8
+ module Methods
9
+ # Matches a URI without regard to the ordering of parameters in the query string.
10
+ #
11
+ # @param [String] uri URI to match.
12
+ # @return [EquivalentUri] parameter matcher.
13
+ #
14
+ # @see Expectation#with
15
+ #
16
+ # @example Actual URI is equivalent.
17
+ # object = mock()
18
+ # object.expects(:method_1).with(equivalent_uri('http://example.com/foo?a=1&b=2'))
19
+ # object.method_1('http://example.com/foo?b=2&a=1')
20
+ # # no error raised
21
+ #
22
+ # @example Actual URI is not equivalent.
23
+ # object = mock()
24
+ # object.expects(:method_1).with(equivalent_uri('http://example.com/foo?a=1&b=2'))
25
+ # object.method_1('http://example.com/foo?a=1&b=3')
26
+ # # error raised, because the query parameters were different
27
+ def equivalent_uri(uri)
28
+ EquivalentUri.new(uri)
29
+ end
30
+ end
31
+
32
+ # Parameter matcher which matches URIs with equivalent query strings.
33
+ class EquivalentUri
34
+ include BaseMethods
35
+
36
+ # @private
37
+ def initialize(uri)
38
+ @uri = URI.parse(uri)
39
+ end
40
+
41
+ # @private
42
+ def matches?(available_parameters)
43
+ actual = explode(URI.parse(available_parameters.shift))
44
+ expected = explode(@uri)
45
+ actual == expected
46
+ end
47
+
48
+ # @private
49
+ def mocha_inspect
50
+ "equivalent_uri(#{@uri.mocha_inspect})"
51
+ end
52
+
53
+ private
54
+
55
+ # @private
56
+ def explode(uri)
57
+ query_hash = Hash.new { |hash, key| hash[key] = [] }
58
+ URI.decode_www_form(uri.query || '').each do |key, value|
59
+ query_hash[key] << value
60
+ end
61
+ URI::Generic::COMPONENT.inject({}) { |h, k| h.merge(k => uri.__send__(k)) }.merge(query: query_hash)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,42 +1,61 @@
1
- require 'mocha/parameter_matchers/base'
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
4
+ require 'mocha/parameter_matchers/all_of'
5
+ require 'mocha/parameter_matchers/has_entry'
2
6
 
3
7
  module Mocha
4
-
5
8
  module ParameterMatchers
6
-
7
- # :call-seq: has_entries(entries) -> parameter_matcher
8
- #
9
- # Matches +Hash+ containing all +entries+.
10
- # object = mock()
11
- # object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2))
12
- # object.method_1('key_1' => 1, 'key_2' => 2, 'key_3' => 3)
13
- # # no error raised
14
- #
15
- # object = mock()
16
- # object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2))
17
- # object.method_1('key_1' => 1, 'key_2' => 99)
18
- # # error raised, because method_1 was not called with Hash containing entries: 'key_1' => 1, 'key_2' => 2
19
- def has_entries(entries)
20
- HasEntries.new(entries)
9
+ module Methods
10
+ # Matches +Hash+ containing all +entries+.
11
+ #
12
+ # @param [Hash] entries expected +Hash+ entries.
13
+ # @return [HasEntries] parameter matcher.
14
+ #
15
+ # @see Expectation#with
16
+ #
17
+ # @example Actual parameter contains all expected entries.
18
+ # object = mock()
19
+ # object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2))
20
+ # object.method_1('key_1' => 1, 'key_2' => 2, 'key_3' => 3)
21
+ # # no error raised
22
+ #
23
+ # @example Actual parameter does not contain all expected entries.
24
+ # object = mock()
25
+ # object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2))
26
+ # object.method_1('key_1' => 1, 'key_2' => 99)
27
+ # # error raised, because method_1 was not called with Hash containing entries: 'key_1' => 1, 'key_2' => 2
28
+ #
29
+ def has_entries(entries) # rubocop:disable Naming/PredicatePrefix
30
+ HasEntries.new(entries)
31
+ end
21
32
  end
22
-
23
- class HasEntries < Base # :nodoc:
24
-
25
- def initialize(entries)
33
+
34
+ # Parameter matcher which matches when actual parameter contains all expected +Hash+ entries.
35
+ class HasEntries
36
+ include BaseMethods
37
+
38
+ # @private
39
+ def initialize(entries, exact: false)
26
40
  @entries = entries
41
+ @exact = exact
27
42
  end
28
-
43
+
44
+ # @private
29
45
  def matches?(available_parameters)
30
46
  parameter = available_parameters.shift
31
- @entries.all? { |key, value| parameter[key] == value }
47
+ return false unless parameter
48
+ return false unless parameter.respond_to?(:keys)
49
+ return false if @exact && @entries.length != parameter.keys.length
50
+
51
+ has_entry_matchers = @entries.map { |key, value| HasEntry.new(key, value) }
52
+ AllOf.new(*has_entry_matchers).matches?([parameter])
32
53
  end
33
-
54
+
55
+ # @private
34
56
  def mocha_inspect
35
- "has_entries(#{@entries.mocha_inspect})"
57
+ @exact ? @entries.mocha_inspect : "has_entries(#{@entries.mocha_inspect})"
36
58
  end
37
-
38
59
  end
39
-
40
60
  end
41
-
42
- end
61
+ end
@@ -1,55 +1,103 @@
1
- require 'mocha/parameter_matchers/base'
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
2
4
 
3
5
  module Mocha
4
-
5
6
  module ParameterMatchers
6
-
7
- # :call-seq: has_entry(key, value) -> parameter_matcher
8
- # has_entry(key => value) -> parameter_matcher
9
- #
10
- # Matches +Hash+ containing entry with +key+ and +value+.
11
- # object = mock()
12
- # object.expects(:method_1).with(has_entry('key_1', 1))
13
- # object.method_1('key_1' => 1, 'key_2' => 2)
14
- # # no error raised
15
- #
16
- # object = mock()
17
- # object.expects(:method_1).with(has_entry('key_1' => 1))
18
- # object.method_1('key_1' => 1, 'key_2' => 2)
19
- # # no error raised
20
- #
21
- # object = mock()
22
- # object.expects(:method_1).with(has_entry('key_1', 1))
23
- # object.method_1('key_1' => 2, 'key_2' => 1)
24
- # # error raised, because method_1 was not called with Hash containing entry: 'key_1' => 1
25
- #
26
- # object = mock()
27
- # object.expects(:method_1).with(has_entry('key_1' => 1))
28
- # object.method_1('key_1' => 2, 'key_2' => 1)
29
- # # error raised, because method_1 was not called with Hash containing entry: 'key_1' => 1
30
- def has_entry(*options)
31
- key, value = options.shift, options.shift
32
- key, value = key.to_a[0][0..1] if key.is_a?(Hash)
33
- HasEntry.new(key, value)
7
+ module Methods
8
+ # Matches +Hash+ containing entry with +key+ and +value+.
9
+ #
10
+ # @overload def has_entry(key, value)
11
+ # @param [Object] key key for entry.
12
+ # @param [Object] value value for entry.
13
+ # @overload def has_entry(single_entry_hash)
14
+ # @param [Hash] single_entry_hash +Hash+ with single entry.
15
+ # @raise [ArgumentError] if +single_entry_hash+ does not contain exactly one entry.
16
+ #
17
+ # @return [HasEntry] parameter matcher.
18
+ #
19
+ # @see Expectation#with
20
+ #
21
+ # @example Actual parameter contains expected entry supplied as key and value.
22
+ # object = mock()
23
+ # object.expects(:method_1).with(has_entry('key_1', 1))
24
+ # object.method_1('key_1' => 1, 'key_2' => 2)
25
+ # # no error raised
26
+ #
27
+ # @example Actual parameter contains expected entry supplied as +Hash+ entry.
28
+ # object = mock()
29
+ # object.expects(:method_1).with(has_entry('key_1' => 1))
30
+ # object.method_1('key_1' => 1, 'key_2' => 2)
31
+ # # no error raised
32
+ #
33
+ # @example Actual parameter does not contain expected entry supplied as key and value.
34
+ # object = mock()
35
+ # object.expects(:method_1).with(has_entry('key_1', 1))
36
+ # object.method_1('key_1' => 2, 'key_2' => 1)
37
+ # # error raised, because method_1 was not called with Hash containing entry: 'key_1' => 1
38
+ #
39
+ # @example Actual parameter does not contain expected entry supplied as +Hash+ entry.
40
+ #
41
+ # object = mock()
42
+ # object.expects(:method_1).with(has_entry('key_1' => 1))
43
+ # object.method_1('key_1' => 2, 'key_2' => 1)
44
+ # # error raised, because method_1 was not called with Hash containing entry: 'key_1' => 1
45
+ #
46
+ def has_entry(*options) # rubocop:disable Naming/PredicatePrefix
47
+ case options.length
48
+ when 0
49
+ raise ArgumentError, 'No arguments. Expecting at least one.'
50
+ when 1
51
+ key, value = HasEntry.parse_option(options[0])
52
+ when 2
53
+ key, value = options
54
+ else
55
+ raise ArgumentError, 'Too many arguments; use either a single argument (must be a Hash) or two arguments (a key and a value).'
56
+ end
57
+ HasEntry.new(key, value)
58
+ end
34
59
  end
35
-
36
- class HasEntry < Base # :nodoc:
37
-
60
+
61
+ # Parameter matcher which matches when actual parameter contains expected +Hash+ entry.
62
+ class HasEntry
63
+ include BaseMethods
64
+
65
+ # @private
38
66
  def initialize(key, value)
39
- @key, @value = key, value
67
+ @key = key
68
+ @value = value
40
69
  end
41
-
70
+
71
+ # @private
42
72
  def matches?(available_parameters)
43
73
  parameter = available_parameters.shift
44
- parameter[@key] == @value
74
+ return false unless parameter.respond_to?(:keys) && parameter.respond_to?(:[])
75
+
76
+ matching_keys = parameter.keys.select { |key| @key.to_matcher.matches?([key]) }
77
+ matching_keys.any? { |key| @value.to_matcher.matches?([parameter[key]]) }
45
78
  end
46
-
79
+
80
+ # @private
47
81
  def mocha_inspect
48
- "has_entry(#{@key.mocha_inspect}, #{@value.mocha_inspect})"
82
+ "has_entry(#{@key.mocha_inspect} => #{@value.mocha_inspect})"
83
+ end
84
+
85
+ # @private
86
+ def self.parse_option(option)
87
+ case option
88
+ when Hash
89
+ case option.length
90
+ when 0
91
+ raise ArgumentError, 'Argument has no entries.'
92
+ when 1
93
+ option.first
94
+ else
95
+ raise ArgumentError, 'Argument has multiple entries. Use Mocha::ParameterMatchers#has_entries instead.'
96
+ end
97
+ else
98
+ raise ArgumentError, 'Argument is not a Hash.'
99
+ end
49
100
  end
50
-
51
101
  end
52
-
53
102
  end
54
-
55
- end
103
+ end
@@ -1,42 +1,55 @@
1
- require 'mocha/parameter_matchers/base'
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
2
4
 
3
5
  module Mocha
4
-
5
6
  module ParameterMatchers
6
-
7
- # :call-seq: has_key(key) -> parameter_matcher
8
- #
9
- # Matches +Hash+ containing +key+.
10
- # object = mock()
11
- # object.expects(:method_1).with(has_key('key_1'))
12
- # object.method_1('key_1' => 1, 'key_2' => 2)
13
- # # no error raised
14
- #
15
- # object = mock()
16
- # object.expects(:method_1).with(has_key('key_1'))
17
- # object.method_1('key_2' => 2)
18
- # # error raised, because method_1 was not called with Hash containing key: 'key_1'
19
- def has_key(key)
20
- HasKey.new(key)
7
+ module Methods
8
+ # Matches +Hash+ containing +key+.
9
+ #
10
+ # @param [Object] key expected key.
11
+ # @return [HasKey] parameter matcher.
12
+ #
13
+ # @see Expectation#with
14
+ #
15
+ # @example Actual parameter contains entry with expected key.
16
+ # object = mock()
17
+ # object.expects(:method_1).with(has_key('key_1'))
18
+ # object.method_1('key_1' => 1, 'key_2' => 2)
19
+ # # no error raised
20
+ #
21
+ # @example Actual parameter does not contain entry with expected key.
22
+ # object = mock()
23
+ # object.expects(:method_1).with(has_key('key_1'))
24
+ # object.method_1('key_2' => 2)
25
+ # # error raised, because method_1 was not called with Hash containing key: 'key_1'
26
+ #
27
+ def has_key(key) # rubocop:disable Naming/PredicatePrefix
28
+ HasKey.new(key)
29
+ end
21
30
  end
22
31
 
23
- class HasKey < Base # :nodoc:
24
-
32
+ # Parameter matcher which matches when actual parameter contains +Hash+ entry with expected key.
33
+ class HasKey
34
+ include BaseMethods
35
+
36
+ # @private
25
37
  def initialize(key)
26
38
  @key = key
27
39
  end
28
-
40
+
41
+ # @private
29
42
  def matches?(available_parameters)
30
43
  parameter = available_parameters.shift
31
- parameter.keys.include?(@key)
44
+ return false unless parameter.respond_to?(:keys)
45
+
46
+ parameter.keys.any? { |key| @key.to_matcher.matches?([key]) }
32
47
  end
33
-
48
+
49
+ # @private
34
50
  def mocha_inspect
35
51
  "has_key(#{@key.mocha_inspect})"
36
52
  end
37
-
38
53
  end
39
-
40
54
  end
41
-
42
- end
55
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
4
+
5
+ module Mocha
6
+ module ParameterMatchers
7
+ module Methods
8
+ # Matches +Hash+ containing +keys+.
9
+ #
10
+ # @param [*Array<Object>] keys expected keys.
11
+ # @return [HasKeys] parameter matcher.
12
+ #
13
+ # @see Expectation#with
14
+ #
15
+ # @example Actual parameter contains entry with expected keys.
16
+ # object = mock()
17
+ # object.expects(:method_1).with(has_keys(:key_1, :key_2))
18
+ # object.method_1(:key_1 => 1, :key_2 => 2, :key_3 => 3)
19
+ # # no error raised
20
+ #
21
+ # @example Actual parameter does not contain all expected keys.
22
+ # object = mock()
23
+ # object.expects(:method_1).with(has_keys(:key_1, :key_2))
24
+ # object.method_1(:key_2 => 2)
25
+ # # error raised, because method_1 was not called with Hash containing key: :key_1
26
+ #
27
+ def has_keys(*keys) # rubocop:disable Naming/PredicatePrefix
28
+ HasKeys.new(*keys)
29
+ end
30
+ end
31
+
32
+ # Parameter matcher which matches when actual parameter contains +Hash+ with all expected keys.
33
+ class HasKeys
34
+ include BaseMethods
35
+
36
+ # @private
37
+ def initialize(*keys)
38
+ raise ArgumentError, 'No arguments. Expecting at least one.' if keys.empty?
39
+
40
+ @keys = keys
41
+ end
42
+
43
+ # @private
44
+ def matches?(available_parameters)
45
+ parameter = available_parameters.shift
46
+ return false unless parameter.respond_to?(:keys)
47
+
48
+ @keys.map(&:to_matcher).all? do |matcher|
49
+ parameter.keys.any? { |key| matcher.matches?([key]) }
50
+ end
51
+ end
52
+
53
+ # @private
54
+ def mocha_inspect
55
+ "has_keys(#{@keys.mocha_inspect(wrapped: false)})"
56
+ end
57
+ end
58
+ end
59
+ end