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
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/configuration'
4
+ require 'mocha/deprecation'
5
+ require 'mocha/ruby_version'
6
+ require 'mocha/parameter_matchers/base_methods'
7
+ require 'mocha/parameter_matchers/has_entries'
8
+
9
+ module Mocha
10
+ module ParameterMatchers
11
+ # @private
12
+ class PositionalOrKeywordHash
13
+ include BaseMethods
14
+
15
+ def initialize(expected_value, expectation, last_expected_value)
16
+ @expected_value = expected_value
17
+ @expectation = expectation
18
+ @last_expected_value = last_expected_value
19
+ end
20
+
21
+ def matches?(actual_values)
22
+ actual_value, is_last_actual_value = extract_actual_value(actual_values)
23
+
24
+ if !matches_entries_exactly?(actual_value)
25
+ false
26
+ elsif is_last_actual_value
27
+ matches_last_actual_value?(actual_value)
28
+ else
29
+ true
30
+ end
31
+ end
32
+
33
+ def mocha_inspect
34
+ @expected_value.mocha_inspect
35
+ end
36
+
37
+ private
38
+
39
+ def matches_entries_exactly?(actual_value)
40
+ HasEntries.new(@expected_value, exact: true).matches?([actual_value])
41
+ end
42
+
43
+ def matches_last_actual_value?(actual_value)
44
+ if same_type_of_hash?(actual_value, @expected_value)
45
+ true
46
+ elsif last_expected_value_is_positional_hash? # rubocop:disable Lint/DuplicateBranch
47
+ true
48
+ elsif Mocha.configuration.strict_keyword_argument_matching?
49
+ false
50
+ else
51
+ deprecation_warning(actual_value, @expected_value) if Mocha::RUBY_V27_PLUS
52
+ true
53
+ end
54
+ end
55
+
56
+ def last_expected_value_is_positional_hash?
57
+ @last_expected_value && !ruby2_keywords_hash?(@expected_value)
58
+ end
59
+
60
+ def extract_actual_value(actual_values)
61
+ [actual_values.shift, actual_values.empty?]
62
+ end
63
+
64
+ def same_type_of_hash?(actual, expected)
65
+ ruby2_keywords_hash?(actual) == ruby2_keywords_hash?(expected)
66
+ end
67
+
68
+ def deprecation_warning(actual, expected)
69
+ details1 = "Expectation #{expectation_definition} expected #{hash_type(expected)} (#{expected.mocha_inspect}),".squeeze(' ')
70
+ details2 = "but received #{hash_type(actual)} (#{actual.mocha_inspect})."
71
+ sentence1 = 'These will stop matching when strict keyword argument matching is enabled.'
72
+ sentence2 = 'See the documentation for Mocha::Configuration#strict_keyword_argument_matching=.'
73
+ Deprecation.warning([details1, details2, sentence1, sentence2].join(' '))
74
+ end
75
+
76
+ def hash_type(hash)
77
+ ruby2_keywords_hash?(hash) ? 'keyword arguments' : 'positional hash'
78
+ end
79
+
80
+ def ruby2_keywords_hash?(hash)
81
+ hash.is_a?(Hash) && ::Hash.ruby2_keywords_hash?(hash)
82
+ end
83
+
84
+ def expectation_definition
85
+ return nil unless @expectation
86
+
87
+ "defined at #{@expectation.definition_location}"
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,43 +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: regexp_matches(regexp) -> parameter_matcher
8
- #
9
- # Matches any object that matches the regular expression, +regexp+.
10
- # object = mock()
11
- # object.expects(:method_1).with(regexp_matches(/e/))
12
- # object.method_1('hello')
13
- # # no error raised
14
- #
15
- # object = mock()
16
- # object.expects(:method_1).with(regexp_matches(/a/))
17
- # object.method_1('hello')
18
- # # error raised, because method_1 was not called with a parameter that matched the
19
- # # regular expression
20
- def regexp_matches(regexp)
21
- RegexpMatches.new(regexp)
7
+ module Methods
8
+ # Matches any object that matches +regexp+.
9
+ #
10
+ # @param [Regexp] regexp regular expression to match.
11
+ # @return [RegexpMatches] parameter matcher.
12
+ #
13
+ # @see Expectation#with
14
+ #
15
+ # @example Actual parameter is matched by specified regular expression.
16
+ # object = mock()
17
+ # object.expects(:method_1).with(regexp_matches(/e/))
18
+ # object.method_1('hello')
19
+ # # no error raised
20
+ #
21
+ # @example Actual parameter is not matched by specified regular expression.
22
+ # object = mock()
23
+ # object.expects(:method_1).with(regexp_matches(/a/))
24
+ # object.method_1('hello')
25
+ # # error raised, because method_1 was not called with a parameter that matched the
26
+ # # regular expression
27
+ def regexp_matches(regexp)
28
+ RegexpMatches.new(regexp)
29
+ end
22
30
  end
23
31
 
24
- class RegexpMatches < Base # :nodoc:
25
-
32
+ # Parameter matcher which matches if specified regular expression matches actual paramter.
33
+ class RegexpMatches
34
+ include BaseMethods
35
+
36
+ # @private
26
37
  def initialize(regexp)
27
38
  @regexp = regexp
28
39
  end
29
-
40
+
41
+ # @private
30
42
  def matches?(available_parameters)
31
43
  parameter = available_parameters.shift
44
+ return false unless parameter.respond_to?(:=~)
45
+
32
46
  parameter =~ @regexp
33
47
  end
34
-
48
+
49
+ # @private
35
50
  def mocha_inspect
36
51
  "regexp_matches(#{@regexp.mocha_inspect})"
37
52
  end
38
-
39
53
  end
40
-
41
54
  end
42
-
43
55
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
4
+ require 'mocha/parameter_matchers/all_of'
5
+ require 'yaml'
6
+
7
+ module Mocha
8
+ module ParameterMatchers
9
+ module Methods
10
+ # @overload def responds_with(message, result)
11
+ # Matches any object that responds to +message+ with +result+. To put it another way, it tests the quack, not the duck.
12
+ # @param [Symbol] message method to invoke.
13
+ # @param [Object] result expected result of sending +message+.
14
+ # @overload def responds_with(messages_vs_results)
15
+ # Matches any object that responds to all the messages with the corresponding results as specified by +messages_vs_results+.
16
+ # @param [Hash<Symbol,Object>] messages_vs_results +Hash+ of messages vs results.
17
+ # @raise [ArgumentError] if +messages_vs_results+ does not contain at least one entry.
18
+ #
19
+ # @return [RespondsWith] parameter matcher.
20
+ #
21
+ # @see Expectation#with
22
+ #
23
+ # @example Actual parameter responds with "FOO" when :upcase is invoked.
24
+ # object = mock()
25
+ # object.expects(:method_1).with(responds_with(:upcase, "FOO"))
26
+ # object.method_1("foo")
27
+ # # no error raised, because "foo".upcase == "FOO"
28
+ #
29
+ # @example Actual parameter does not respond with "FOO" when :upcase is invoked.
30
+ # object = mock()
31
+ # object.expects(:method_1).with(responds_with(:upcase, "BAR"))
32
+ # object.method_1("foo")
33
+ # # error raised, because "foo".upcase != "BAR"
34
+ #
35
+ # @example Actual parameter responds with "FOO" when :upcase is invoked and "oof" when :reverse is invoked.
36
+ # object = mock()
37
+ # object.expects(:method_1).with(responds_with(upcase: "FOO", reverse: "oof"))
38
+ # object.method_1("foo")
39
+ # # no error raised, because "foo".upcase == "FOO" and "foo".reverse == "oof"
40
+ def responds_with(*options)
41
+ case options.length
42
+ when 0
43
+ raise ArgumentError, 'No arguments. Expecting at least one.'
44
+ when 1
45
+ option = options.first
46
+ raise ArgumentError, 'Argument is not a Hash.' unless option.is_a?(Hash)
47
+ raise ArgumentError, 'Argument has no entries.' if option.empty?
48
+
49
+ matchers = option.map { |message, result| RespondsWith.new(message, result) }
50
+ AllOf.new(*matchers)
51
+ when 2
52
+ message, result = options
53
+ RespondsWith.new(message, result)
54
+ else
55
+ raise ArgumentError, 'Too many arguments; use either a single argument (must be a Hash) or two arguments (a message and a result).'
56
+ end
57
+ end
58
+ end
59
+
60
+ # Parameter matcher which matches if actual parameter returns expected result when specified method is invoked.
61
+ class RespondsWith
62
+ include BaseMethods
63
+
64
+ # @private
65
+ def initialize(message, result)
66
+ @message = message
67
+ @result = result
68
+ end
69
+
70
+ # @private
71
+ def matches?(available_parameters)
72
+ parameter = available_parameters.shift
73
+ @result.to_matcher.matches?([parameter.__send__(@message)])
74
+ end
75
+
76
+ # @private
77
+ def mocha_inspect
78
+ "responds_with(#{@message.mocha_inspect}, #{@result.mocha_inspect})"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
4
+ require 'yaml'
5
+
6
+ module Mocha
7
+ module ParameterMatchers
8
+ module Methods
9
+ # Matches any YAML that represents the specified +object+
10
+ #
11
+ # @param [Object] object object whose YAML to compare.
12
+ # @return [YamlEquivalent] parameter matcher.
13
+ #
14
+ # @see Expectation#with
15
+ #
16
+ # @example Actual parameter is YAML equivalent of specified +object+.
17
+ # object = mock()
18
+ # object.expects(:method_1).with(yaml_equivalent(1, 2, 3))
19
+ # object.method_1("--- \n- 1\n- 2\n- 3\n")
20
+ # # no error raised
21
+ #
22
+ # @example Actual parameter is not YAML equivalent of specified +object+.
23
+ # object = mock()
24
+ # object.expects(:method_1).with(yaml_equivalent(1, 2, 3))
25
+ # object.method_1("--- \n- 1\n- 2\n")
26
+ # # error raised, because method_1 was not called with YAML representing the specified Array
27
+ def yaml_equivalent(object)
28
+ YamlEquivalent.new(object)
29
+ end
30
+ end
31
+
32
+ # Parameter matcher which matches if actual parameter is YAML equivalent of specified object.
33
+ class YamlEquivalent
34
+ include BaseMethods
35
+
36
+ # @private
37
+ def initialize(object)
38
+ @object = object
39
+ end
40
+
41
+ # @private
42
+ def matches?(available_parameters)
43
+ parameter = available_parameters.shift
44
+ # rubocop:disable Security/YAMLLoad
45
+ @object == YAML.load(parameter)
46
+ # rubocop:enable Security/YAMLLoad
47
+ end
48
+
49
+ # @private
50
+ def mocha_inspect
51
+ "yaml_equivalent(#{@object.mocha_inspect})"
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,11 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mocha
2
-
3
- # Used as parameters for Expectation#with to restrict the parameter values which will match the expectation.
4
- module ParameterMatchers; end
5
-
4
+ # Matcher classes used as parameters for {Expectation#with} to restrict the parameter values which will match the expectation. Can be nested. Build matcher instances in tests using methods in {Methods}, e.g. {Methods#includes}.
5
+ module ParameterMatchers
6
+ # These methods build instances of the {ParameterMatchers} classes which are used with {Expectation#with} to restrict the parameter values. Can be nested, e.g. see {Methods#all_of} examples.
7
+ module Methods; end
8
+ end
6
9
  end
7
10
 
8
- require 'mocha/parameter_matchers/object'
11
+ require 'mocha/parameter_matchers/instance_methods'
9
12
 
10
13
  require 'mocha/parameter_matchers/all_of'
11
14
  require 'mocha/parameter_matchers/any_of'
@@ -15,6 +18,7 @@ require 'mocha/parameter_matchers/equals'
15
18
  require 'mocha/parameter_matchers/has_entry'
16
19
  require 'mocha/parameter_matchers/has_entries'
17
20
  require 'mocha/parameter_matchers/has_key'
21
+ require 'mocha/parameter_matchers/has_keys'
18
22
  require 'mocha/parameter_matchers/has_value'
19
23
  require 'mocha/parameter_matchers/includes'
20
24
  require 'mocha/parameter_matchers/instance_of'
@@ -23,3 +27,6 @@ require 'mocha/parameter_matchers/kind_of'
23
27
  require 'mocha/parameter_matchers/not'
24
28
  require 'mocha/parameter_matchers/optionally'
25
29
  require 'mocha/parameter_matchers/regexp_matches'
30
+ require 'mocha/parameter_matchers/responds_with'
31
+ require 'mocha/parameter_matchers/yaml_equivalent'
32
+ require 'mocha/parameter_matchers/equivalent_uri'
@@ -1,37 +1,46 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'mocha/inspect'
2
4
  require 'mocha/parameter_matchers'
3
5
 
4
6
  module Mocha
5
-
6
7
  class ParametersMatcher
7
-
8
- def initialize(expected_parameters = [ParameterMatchers::AnyParameters.new], &matching_block)
9
- @expected_parameters, @matching_block = expected_parameters, matching_block
8
+ def initialize(expected_parameters = [ParameterMatchers::AnyParameters.new], expectation = nil, &matching_block)
9
+ @expected_parameters = expected_parameters
10
+ @expectation = expectation
11
+ @matching_block = matching_block
10
12
  end
11
-
13
+
12
14
  def match?(actual_parameters = [])
13
15
  if @matching_block
14
- return @matching_block.call(*actual_parameters)
16
+ @matching_block.call(*actual_parameters)
15
17
  else
16
- return parameters_match?(actual_parameters)
18
+ parameters_match?(actual_parameters)
17
19
  end
18
20
  end
19
-
21
+
20
22
  def parameters_match?(actual_parameters)
21
- matchers.all? { |matcher| matcher.matches?(actual_parameters) } && (actual_parameters.length == 0)
23
+ matchers.all? { |matcher| matcher.matches?(actual_parameters) } && actual_parameters.empty?
22
24
  end
23
-
25
+
24
26
  def mocha_inspect
25
- signature = matchers.mocha_inspect
26
- signature = signature.gsub(/^\[|\]$/, '')
27
- signature = signature.gsub(/^\{|\}$/, '') if matchers.length == 1
28
- "(#{signature})"
27
+ if @matching_block
28
+ '(arguments_accepted_by_custom_matching_block)'
29
+ else
30
+ signature = matchers.mocha_inspect
31
+ signature = signature.gsub(/^\[|\]$/, '')
32
+ "(#{signature})"
33
+ end
29
34
  end
30
-
35
+
31
36
  def matchers
32
- @expected_parameters.map { |parameter| parameter.to_matcher }
37
+ @expected_parameters.map.with_index do |parameter, index|
38
+ parameter.to_matcher(
39
+ expectation: @expectation,
40
+ top_level: true,
41
+ last: index == @expected_parameters.length - 1
42
+ )
43
+ end
33
44
  end
34
-
35
45
  end
36
-
37
- end
46
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mocha
4
+ class RaisedException
5
+ def initialize(exception)
6
+ @exception = exception
7
+ end
8
+
9
+ def mocha_inspect
10
+ "raised #{@exception}"
11
+ end
12
+ end
13
+ end
@@ -1,34 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'mocha/single_return_value'
2
4
 
3
- module Mocha # :nodoc:
4
-
5
- class ReturnValues # :nodoc:
6
-
5
+ module Mocha
6
+ class ReturnValues
7
7
  def self.build(*values)
8
8
  new(*values.map { |value| SingleReturnValue.new(value) })
9
9
  end
10
-
10
+
11
11
  attr_accessor :values
12
-
12
+
13
13
  def initialize(*values)
14
14
  @values = values
15
15
  end
16
-
17
- def next
16
+
17
+ def next(invocation)
18
18
  case @values.length
19
- when 0
20
- nil
21
- when 1
22
- @values.first.evaluate
23
- else
24
- @values.shift.evaluate
19
+ when 0 then nil
20
+ when 1 then @values.first.evaluate(invocation)
21
+ else @values.shift.evaluate(invocation)
25
22
  end
26
23
  end
27
-
24
+
28
25
  def +(other)
29
26
  self.class.new(*(@values + other.values))
30
27
  end
31
-
32
28
  end
33
-
34
- end
29
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mocha
4
+ RUBY_V27_PLUS = Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.7')
5
+ RUBY_V30_PLUS = Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('3.0')
6
+ RUBY_V34_PLUS = Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('3.4')
7
+ end
@@ -1,42 +1,48 @@
1
- module Mocha # :nodoc:
2
-
1
+ # frozen_string_literal: true
2
+
3
+ module Mocha
4
+ # Used to constrain the order in which expectations can occur.
5
+ #
6
+ # @see API#sequence
7
+ # @see Expectation#in_sequence
3
8
  class Sequence
4
-
9
+ # @private
5
10
  class InSequenceOrderingConstraint
6
-
7
11
  def initialize(sequence, index)
8
- @sequence, @index = sequence, index
12
+ @sequence = sequence
13
+ @index = index
9
14
  end
10
-
15
+
11
16
  def allows_invocation_now?
12
17
  @sequence.satisfied_to_index?(@index)
13
18
  end
14
-
19
+
15
20
  def mocha_inspect
16
21
  "in sequence #{@sequence.mocha_inspect}"
17
22
  end
18
-
19
23
  end
20
-
24
+
25
+ # @private
21
26
  def initialize(name)
22
27
  @name = name
23
28
  @expectations = []
24
29
  end
25
-
30
+
31
+ # @private
26
32
  def constrain_as_next_in_sequence(expectation)
27
33
  index = @expectations.length
28
34
  @expectations << expectation
29
35
  expectation.add_ordering_constraint(InSequenceOrderingConstraint.new(self, index))
30
36
  end
31
-
37
+
38
+ # @private
32
39
  def satisfied_to_index?(index)
33
- @expectations[0...index].all? { |expectation| expectation.satisfied? }
40
+ @expectations[0...index].all?(&:satisfied?)
34
41
  end
35
-
42
+
43
+ # @private
36
44
  def mocha_inspect
37
- "#{@name.mocha_inspect}"
45
+ @name.mocha_inspect.to_s
38
46
  end
39
-
40
47
  end
41
-
42
- end
48
+ end
@@ -1,24 +1,14 @@
1
- require 'mocha/is_a'
2
- require 'mocha/deprecation'
1
+ # frozen_string_literal: true
3
2
 
4
- module Mocha # :nodoc:
5
-
6
- class SingleReturnValue # :nodoc:
7
-
3
+ module Mocha
4
+ class SingleReturnValue
8
5
  def initialize(value)
9
6
  @value = value
10
7
  end
11
-
12
- def evaluate
13
- if @value.__is_a__(Proc) then
14
- message = 'use of Expectation#returns with instance of Proc - see Expectation#returns RDoc for alternatives'
15
- Deprecation.warning(message)
16
- @value.call
17
- else
18
- @value
19
- end
8
+
9
+ def evaluate(invocation)
10
+ invocation.returned(@value)
11
+ @value
20
12
  end
21
-
22
13
  end
23
-
24
- end
14
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mocha
4
+ # A state machine that is used to constrain the order of invocations.
5
+ # An invocation can be constrained to occur when a state {#is}, or {#is_not}, active.
6
+ class StateMachine
7
+ # Provides the ability to determine whether a {StateMachine} is in a specified state at some point in the future.
8
+ class StatePredicate
9
+ # @private
10
+ def initialize(state_machine, state, description, &active_check)
11
+ @state_machine = state_machine
12
+ @state = state
13
+ @description = description
14
+ @active_check = active_check
15
+ end
16
+
17
+ # @private
18
+ def active?
19
+ @active_check.call(@state_machine.current_state, @state)
20
+ end
21
+
22
+ # @private
23
+ def mocha_inspect
24
+ "#{@state_machine.name} #{@description} #{@state.mocha_inspect}"
25
+ end
26
+ end
27
+
28
+ # Provides a mechanism to change the state of a {StateMachine} at some point in the future.
29
+ class State < StatePredicate
30
+ # @private
31
+ def activate
32
+ @state_machine.current_state = @state
33
+ end
34
+ end
35
+
36
+ # @private
37
+ attr_reader :name
38
+
39
+ # @private
40
+ attr_accessor :current_state
41
+
42
+ # @private
43
+ def initialize(name)
44
+ @name = name
45
+ @current_state = nil
46
+ end
47
+
48
+ # Put the {StateMachine} into the state specified by +initial_state_name+.
49
+ #
50
+ # @param [String] initial_state_name name of initial state
51
+ # @return [StateMachine] state machine, thereby allowing invocations of other {StateMachine} methods to be chained.
52
+ def starts_as(initial_state_name)
53
+ become(initial_state_name)
54
+ self
55
+ end
56
+
57
+ # Put the {StateMachine} into the +next_state_name+.
58
+ #
59
+ # @param [String] next_state_name name of new state
60
+ def become(next_state_name)
61
+ @current_state = next_state_name
62
+ end
63
+
64
+ # Provides mechanisms to (a) determine whether the {StateMachine} is in a given state; or (b) to change the {StateMachine} into the given state.
65
+ #
66
+ # @param [String] state_name name of expected/desired state.
67
+ # @return [StatePredicate,State] (a) state predicate which, when queried, will indicate whether the {StateMachine} is in the given state; or (b) state which, when activated, will change the {StateMachine} into the given state.
68
+ #
69
+ # @overload def is(expected_state_name)
70
+ # Provides a mechanism to determine whether the {StateMachine} is in the state specified by +expected_state_name+ at some point in the future
71
+ # @param [String] expected_state_name name of expected state.
72
+ # @return [StatePredicate] state predicate which, when queried, will indicate whether the {StateMachine} is in the state specified by +expected_state_name+
73
+ #
74
+ # @overload def is(desired_state_name)
75
+ # Provides a mechanism to change the {StateMachine} into the state specified by +desired_state_name+ at some point in the future.
76
+ # @param [String] desired_state_name name of desired new state.
77
+ # @return [State] state which, when activated, will change the {StateMachine} into the state with the specified +desired_state_name+.
78
+ def is(state_name)
79
+ State.new(self, state_name, 'is') { |current, given| current == given }
80
+ end
81
+
82
+ # Provides a mechanism to determine whether the {StateMachine} is *not* in the state specified by +unexpected_state_name+ at some point in the future.
83
+ #
84
+ # @param [String] unexpected_state_name name of unexpected state.
85
+ # @return [StatePredicate] state predicate which, when queried, will indicate whether the {StateMachine} is *not* in the state specified by +unexpected_state_name+.
86
+ def is_not(unexpected_state_name) # rubocop:disable Naming/PredicatePrefix
87
+ StatePredicate.new(self, unexpected_state_name, 'is not') { |current, given| current != given }
88
+ end
89
+
90
+ # @private
91
+ def mocha_inspect
92
+ %(#{@name} #{@current_state ? "is #{@current_state.mocha_inspect}" : 'has no current state'})
93
+ end
94
+ end
95
+ end