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.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/.github/FUNDING.yml +1 -0
- data/.rubocop.yml +92 -0
- data/.rubocop_todo.yml +39 -0
- data/.yardopts +25 -0
- data/CONTRIBUTING.md +7 -0
- data/COPYING.md +3 -0
- data/Gemfile +17 -0
- data/{MIT-LICENSE → MIT-LICENSE.md} +2 -2
- data/README.md +361 -0
- data/RELEASE.md +1247 -0
- data/Rakefile +165 -123
- data/gemfiles/Gemfile.minitest.latest +8 -0
- data/gemfiles/Gemfile.rubocop +9 -0
- data/gemfiles/Gemfile.test-unit.latest +8 -0
- data/lib/mocha/any_instance_method.rb +12 -26
- data/lib/mocha/any_instance_receiver.rb +20 -0
- data/lib/mocha/api.rb +213 -0
- data/lib/mocha/argument_iterator.rb +17 -0
- data/lib/mocha/backtrace_filter.rb +25 -0
- data/lib/mocha/block_matchers.rb +33 -0
- data/lib/mocha/cardinality.rb +110 -0
- data/lib/mocha/central.rb +33 -22
- data/lib/mocha/change_state_side_effect.rb +17 -0
- data/lib/mocha/class_methods.rb +67 -0
- data/lib/mocha/configuration.rb +338 -0
- data/lib/mocha/default_name.rb +15 -0
- data/lib/mocha/default_receiver.rb +13 -0
- data/lib/mocha/deprecation.rb +6 -15
- data/lib/mocha/detection/minitest.rb +25 -0
- data/lib/mocha/detection/test_unit.rb +30 -0
- data/lib/mocha/error_with_filtered_backtrace.rb +15 -0
- data/lib/mocha/exception_raiser.rb +11 -10
- data/lib/mocha/expectation.rb +562 -171
- data/lib/mocha/expectation_error.rb +9 -14
- data/lib/mocha/expectation_error_factory.rb +37 -0
- data/lib/mocha/expectation_list.rb +30 -14
- data/lib/mocha/hooks.rb +55 -0
- data/lib/mocha/ignoring_warning.rb +20 -0
- data/lib/mocha/impersonating_any_instance_name.rb +13 -0
- data/lib/mocha/impersonating_name.rb +13 -0
- data/lib/mocha/in_state_ordering_constraint.rb +17 -0
- data/lib/mocha/inspect.rb +54 -30
- data/lib/mocha/instance_method.rb +17 -4
- data/lib/mocha/integration/assertion_counter.rb +15 -0
- data/lib/mocha/integration/minitest/adapter.rb +71 -0
- data/lib/mocha/integration/minitest.rb +29 -0
- data/lib/mocha/integration/monkey_patcher.rb +26 -0
- data/lib/mocha/integration/test_unit/adapter.rb +61 -0
- data/lib/mocha/integration/test_unit.rb +29 -0
- data/lib/mocha/integration.rb +5 -0
- data/lib/mocha/invocation.rb +76 -0
- data/lib/mocha/logger.rb +26 -0
- data/lib/mocha/macos_version.rb +7 -0
- data/lib/mocha/method_matcher.rb +8 -10
- data/lib/mocha/minitest.rb +7 -0
- data/lib/mocha/mock.rb +333 -108
- data/lib/mocha/mockery.rb +192 -0
- data/lib/mocha/name.rb +13 -0
- data/lib/mocha/not_initialized_error.rb +9 -0
- data/lib/mocha/object_methods.rb +183 -0
- data/lib/mocha/object_receiver.rb +20 -0
- data/lib/mocha/parameter_matchers/all_of.rb +38 -28
- data/lib/mocha/parameter_matchers/any_of.rb +44 -33
- data/lib/mocha/parameter_matchers/any_parameters.rb +33 -26
- data/lib/mocha/parameter_matchers/anything.rb +31 -22
- data/lib/mocha/parameter_matchers/base_methods.rb +64 -0
- data/lib/mocha/parameter_matchers/equals.rb +36 -25
- data/lib/mocha/parameter_matchers/equivalent_uri.rb +65 -0
- data/lib/mocha/parameter_matchers/has_entries.rb +48 -29
- data/lib/mocha/parameter_matchers/has_entry.rb +90 -42
- data/lib/mocha/parameter_matchers/has_key.rb +39 -26
- data/lib/mocha/parameter_matchers/has_keys.rb +59 -0
- data/lib/mocha/parameter_matchers/has_value.rb +39 -26
- data/lib/mocha/parameter_matchers/includes.rb +88 -23
- data/lib/mocha/parameter_matchers/instance_methods.rb +28 -0
- data/lib/mocha/parameter_matchers/instance_of.rb +37 -26
- data/lib/mocha/parameter_matchers/is_a.rb +38 -26
- data/lib/mocha/parameter_matchers/kind_of.rb +39 -26
- data/lib/mocha/parameter_matchers/not.rb +37 -26
- data/lib/mocha/parameter_matchers/optionally.rb +52 -17
- data/lib/mocha/parameter_matchers/positional_or_keyword_hash.rb +91 -0
- data/lib/mocha/parameter_matchers/regexp_matches.rb +37 -25
- data/lib/mocha/parameter_matchers/responds_with.rb +82 -0
- data/lib/mocha/parameter_matchers/yaml_equivalent.rb +55 -0
- data/lib/mocha/parameter_matchers.rb +12 -5
- data/lib/mocha/parameters_matcher.rb +28 -19
- data/lib/mocha/raised_exception.rb +13 -0
- data/lib/mocha/return_values.rb +13 -18
- data/lib/mocha/ruby_version.rb +7 -0
- data/lib/mocha/sequence.rb +23 -17
- data/lib/mocha/single_return_value.rb +8 -18
- data/lib/mocha/state_machine.rb +95 -0
- data/lib/mocha/stubbed_method.rb +96 -0
- data/lib/mocha/stubbing_error.rb +10 -0
- data/lib/mocha/test_unit.rb +7 -0
- data/lib/mocha/thrower.rb +15 -0
- data/lib/mocha/thrown_object.rb +14 -0
- data/lib/mocha/version.rb +5 -0
- data/lib/mocha/yield_parameters.rb +12 -20
- data/lib/mocha.rb +19 -17
- data/mocha.gemspec +40 -0
- metadata +129 -145
- data/COPYING +0 -3
- data/README +0 -35
- data/RELEASE +0 -188
- data/examples/misc.rb +0 -44
- data/examples/mocha.rb +0 -26
- data/examples/stubba.rb +0 -65
- data/lib/mocha/auto_verify.rb +0 -118
- data/lib/mocha/class_method.rb +0 -66
- data/lib/mocha/infinite_range.rb +0 -25
- data/lib/mocha/is_a.rb +0 -9
- data/lib/mocha/metaclass.rb +0 -7
- data/lib/mocha/missing_expectation.rb +0 -17
- data/lib/mocha/multiple_yields.rb +0 -20
- data/lib/mocha/no_yields.rb +0 -11
- data/lib/mocha/object.rb +0 -110
- data/lib/mocha/parameter_matchers/base.rb +0 -15
- data/lib/mocha/parameter_matchers/object.rb +0 -9
- data/lib/mocha/pretty_parameters.rb +0 -28
- data/lib/mocha/setup_and_teardown.rb +0 -23
- data/lib/mocha/single_yield.rb +0 -18
- data/lib/mocha/standalone.rb +0 -32
- data/lib/mocha/stub.rb +0 -18
- data/lib/mocha/test_case_adapter.rb +0 -49
- data/lib/mocha_standalone.rb +0 -2
- data/lib/stubba.rb +0 -2
- data/test/acceptance/expected_invocation_count_acceptance_test.rb +0 -187
- data/test/acceptance/mocha_acceptance_test.rb +0 -98
- data/test/acceptance/mock_with_initializer_block_acceptance_test.rb +0 -44
- data/test/acceptance/mocked_methods_dispatch_acceptance_test.rb +0 -71
- data/test/acceptance/optional_parameters_acceptance_test.rb +0 -63
- data/test/acceptance/parameter_matcher_acceptance_test.rb +0 -117
- data/test/acceptance/partial_mocks_acceptance_test.rb +0 -40
- data/test/acceptance/sequence_acceptance_test.rb +0 -179
- data/test/acceptance/standalone_acceptance_test.rb +0 -131
- data/test/acceptance/stubba_acceptance_test.rb +0 -102
- data/test/active_record_test_case.rb +0 -36
- data/test/deprecation_disabler.rb +0 -15
- data/test/execution_point.rb +0 -34
- data/test/integration/mocha_test_result_integration_test.rb +0 -105
- data/test/integration/stubba_integration_test.rb +0 -89
- data/test/integration/stubba_test_result_integration_test.rb +0 -85
- data/test/method_definer.rb +0 -18
- data/test/test_helper.rb +0 -12
- data/test/test_runner.rb +0 -31
- data/test/unit/any_instance_method_test.rb +0 -126
- data/test/unit/array_inspect_test.rb +0 -16
- data/test/unit/auto_verify_test.rb +0 -129
- data/test/unit/central_test.rb +0 -124
- data/test/unit/class_method_test.rb +0 -200
- data/test/unit/date_time_inspect_test.rb +0 -21
- data/test/unit/expectation_error_test.rb +0 -24
- data/test/unit/expectation_list_test.rb +0 -75
- data/test/unit/expectation_raiser_test.rb +0 -28
- data/test/unit/expectation_test.rb +0 -483
- data/test/unit/hash_inspect_test.rb +0 -16
- data/test/unit/infinite_range_test.rb +0 -53
- data/test/unit/metaclass_test.rb +0 -22
- data/test/unit/method_matcher_test.rb +0 -23
- data/test/unit/missing_expectation_test.rb +0 -42
- data/test/unit/mock_test.rb +0 -323
- data/test/unit/multiple_yields_test.rb +0 -18
- data/test/unit/no_yield_test.rb +0 -18
- data/test/unit/object_inspect_test.rb +0 -37
- data/test/unit/object_test.rb +0 -165
- data/test/unit/parameter_matchers/all_of_test.rb +0 -26
- data/test/unit/parameter_matchers/any_of_test.rb +0 -26
- data/test/unit/parameter_matchers/anything_test.rb +0 -21
- data/test/unit/parameter_matchers/has_entries_test.rb +0 -30
- data/test/unit/parameter_matchers/has_entry_test.rb +0 -40
- data/test/unit/parameter_matchers/has_key_test.rb +0 -25
- data/test/unit/parameter_matchers/has_value_test.rb +0 -25
- data/test/unit/parameter_matchers/includes_test.rb +0 -25
- data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
- data/test/unit/parameter_matchers/is_a_test.rb +0 -25
- data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
- data/test/unit/parameter_matchers/not_test.rb +0 -26
- data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -25
- data/test/unit/parameter_matchers/stub_matcher.rb +0 -23
- data/test/unit/parameters_matcher_test.rb +0 -121
- data/test/unit/return_values_test.rb +0 -63
- data/test/unit/sequence_test.rb +0 -104
- data/test/unit/setup_and_teardown_test.rb +0 -76
- data/test/unit/single_return_value_test.rb +0 -33
- data/test/unit/single_yield_test.rb +0 -18
- data/test/unit/string_inspect_test.rb +0 -11
- data/test/unit/stub_test.rb +0 -24
- 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
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4
|
-
|
|
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/
|
|
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
|
-
|
|
9
|
-
@
|
|
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
|
-
|
|
16
|
+
@matching_block.call(*actual_parameters)
|
|
15
17
|
else
|
|
16
|
-
|
|
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) } &&
|
|
23
|
+
matchers.all? { |matcher| matcher.matches?(actual_parameters) } && actual_parameters.empty?
|
|
22
24
|
end
|
|
23
|
-
|
|
25
|
+
|
|
24
26
|
def mocha_inspect
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
|
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
|
data/lib/mocha/return_values.rb
CHANGED
|
@@ -1,34 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'mocha/single_return_value'
|
|
2
4
|
|
|
3
|
-
module Mocha
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
data/lib/mocha/sequence.rb
CHANGED
|
@@ -1,42 +1,48 @@
|
|
|
1
|
-
|
|
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
|
|
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?
|
|
40
|
+
@expectations[0...index].all?(&:satisfied?)
|
|
34
41
|
end
|
|
35
|
-
|
|
42
|
+
|
|
43
|
+
# @private
|
|
36
44
|
def mocha_inspect
|
|
37
|
-
|
|
45
|
+
@name.mocha_inspect.to_s
|
|
38
46
|
end
|
|
39
|
-
|
|
40
47
|
end
|
|
41
|
-
|
|
42
|
-
end
|
|
48
|
+
end
|
|
@@ -1,24 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
require 'mocha/deprecation'
|
|
1
|
+
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
module Mocha
|
|
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
|
-
|
|
14
|
-
|
|
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
|