rspec-expectations 2.13.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- checksums.yaml.gz.sig +0 -0
- data/Changelog.md +413 -23
- data/License.txt +1 -0
- data/README.md +109 -80
- data/lib/rspec/{matchers → expectations}/configuration.rb +44 -14
- data/lib/rspec/expectations/expectation_target.rb +71 -38
- data/lib/rspec/expectations/fail_with.rb +12 -44
- data/lib/rspec/expectations/handler.rb +135 -35
- data/lib/rspec/expectations/minitest_integration.rb +16 -0
- data/lib/rspec/expectations/syntax.rb +60 -94
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/expectations.rb +46 -24
- data/lib/rspec/matchers/aliased_matcher.rb +41 -0
- data/lib/rspec/matchers/built_in/all.rb +78 -0
- data/lib/rspec/matchers/built_in/base_matcher.rb +63 -15
- data/lib/rspec/matchers/built_in/be.rb +170 -79
- data/lib/rspec/matchers/built_in/be_between.rb +77 -0
- data/lib/rspec/matchers/built_in/be_instance_of.rb +11 -3
- data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -0
- data/lib/rspec/matchers/built_in/be_within.rb +40 -16
- data/lib/rspec/matchers/built_in/change.rb +275 -74
- data/lib/rspec/matchers/built_in/compound.rb +122 -0
- data/lib/rspec/matchers/built_in/contain_exactly.rb +256 -0
- data/lib/rspec/matchers/built_in/cover.rb +3 -0
- data/lib/rspec/matchers/built_in/eq.rb +60 -6
- data/lib/rspec/matchers/built_in/eql.rb +17 -5
- data/lib/rspec/matchers/built_in/equal.rb +55 -21
- data/lib/rspec/matchers/built_in/exist.rb +74 -10
- data/lib/rspec/matchers/built_in/has.rb +71 -15
- data/lib/rspec/matchers/built_in/include.rb +58 -29
- data/lib/rspec/matchers/built_in/match.rb +19 -1
- data/lib/rspec/matchers/built_in/operators.rb +119 -0
- data/lib/rspec/matchers/built_in/output.rb +150 -0
- data/lib/rspec/matchers/built_in/raise_error.rb +91 -33
- data/lib/rspec/matchers/built_in/respond_to.rb +42 -20
- data/lib/rspec/matchers/built_in/satisfy.rb +19 -3
- data/lib/rspec/matchers/built_in/start_and_end_with.rb +54 -18
- data/lib/rspec/matchers/built_in/throw_symbol.rb +38 -8
- data/lib/rspec/matchers/built_in/yield.rb +237 -55
- data/lib/rspec/matchers/built_in.rb +45 -33
- data/lib/rspec/matchers/composable.rb +179 -0
- data/lib/rspec/matchers/dsl.rb +362 -5
- data/lib/rspec/matchers/generated_descriptions.rb +13 -6
- data/lib/rspec/matchers/matcher_delegator.rb +37 -0
- data/lib/rspec/matchers/pretty.rb +33 -20
- data/lib/rspec/matchers.rb +450 -227
- data.tar.gz.sig +1 -0
- metadata +100 -215
- metadata.gz.sig +0 -0
- data/features/README.md +0 -49
- data/features/Upgrade.md +0 -53
- data/features/built_in_matchers/README.md +0 -90
- data/features/built_in_matchers/be.feature +0 -175
- data/features/built_in_matchers/be_within.feature +0 -48
- data/features/built_in_matchers/cover.feature +0 -47
- data/features/built_in_matchers/end_with.feature +0 -48
- data/features/built_in_matchers/equality.feature +0 -139
- data/features/built_in_matchers/exist.feature +0 -45
- data/features/built_in_matchers/expect_change.feature +0 -59
- data/features/built_in_matchers/expect_error.feature +0 -144
- data/features/built_in_matchers/have.feature +0 -109
- data/features/built_in_matchers/include.feature +0 -174
- data/features/built_in_matchers/match.feature +0 -52
- data/features/built_in_matchers/operators.feature +0 -227
- data/features/built_in_matchers/predicates.feature +0 -137
- data/features/built_in_matchers/respond_to.feature +0 -84
- data/features/built_in_matchers/satisfy.feature +0 -33
- data/features/built_in_matchers/start_with.feature +0 -48
- data/features/built_in_matchers/throw_symbol.feature +0 -91
- data/features/built_in_matchers/types.feature +0 -116
- data/features/built_in_matchers/yield.feature +0 -146
- data/features/custom_matchers/access_running_example.feature +0 -53
- data/features/custom_matchers/define_diffable_matcher.feature +0 -27
- data/features/custom_matchers/define_matcher.feature +0 -368
- data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
- data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
- data/features/customized_message.feature +0 -22
- data/features/diffing.feature +0 -85
- data/features/implicit_docstrings.feature +0 -52
- data/features/step_definitions/additional_cli_steps.rb +0 -22
- data/features/support/env.rb +0 -5
- data/features/syntax_configuration.feature +0 -68
- data/features/test_frameworks/test_unit.feature +0 -46
- data/lib/rspec/expectations/deprecation.rb +0 -38
- data/lib/rspec/expectations/differ.rb +0 -115
- data/lib/rspec/expectations/errors.rb +0 -9
- data/lib/rspec/expectations/extensions/array.rb +0 -9
- data/lib/rspec/expectations/extensions/object.rb +0 -39
- data/lib/rspec/expectations/extensions.rb +0 -2
- data/lib/rspec/matchers/be_close.rb +0 -9
- data/lib/rspec/matchers/built_in/have.rb +0 -108
- data/lib/rspec/matchers/built_in/match_array.rb +0 -51
- data/lib/rspec/matchers/compatibility.rb +0 -14
- data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
- data/lib/rspec/matchers/matcher.rb +0 -300
- data/lib/rspec/matchers/method_missing.rb +0 -12
- data/lib/rspec/matchers/operator_matcher.rb +0 -109
- data/lib/rspec-expectations.rb +0 -1
- data/spec/rspec/expectations/differ_spec.rb +0 -170
- data/spec/rspec/expectations/expectation_target_spec.rb +0 -75
- data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
- data/spec/rspec/expectations/fail_with_spec.rb +0 -95
- data/spec/rspec/expectations/handler_spec.rb +0 -206
- data/spec/rspec/expectations/syntax_spec.rb +0 -97
- data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
- data/spec/rspec/matchers/be_close_spec.rb +0 -22
- data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
- data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
- data/spec/rspec/matchers/be_spec.rb +0 -516
- data/spec/rspec/matchers/be_within_spec.rb +0 -129
- data/spec/rspec/matchers/change_spec.rb +0 -542
- data/spec/rspec/matchers/configuration_spec.rb +0 -238
- data/spec/rspec/matchers/cover_spec.rb +0 -69
- data/spec/rspec/matchers/description_generation_spec.rb +0 -176
- data/spec/rspec/matchers/dsl_spec.rb +0 -57
- data/spec/rspec/matchers/eq_spec.rb +0 -60
- data/spec/rspec/matchers/eql_spec.rb +0 -41
- data/spec/rspec/matchers/equal_spec.rb +0 -78
- data/spec/rspec/matchers/exist_spec.rb +0 -124
- data/spec/rspec/matchers/has_spec.rb +0 -122
- data/spec/rspec/matchers/have_spec.rb +0 -445
- data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
- data/spec/rspec/matchers/include_spec.rb +0 -531
- data/spec/rspec/matchers/match_array_spec.rb +0 -194
- data/spec/rspec/matchers/match_spec.rb +0 -61
- data/spec/rspec/matchers/matcher_spec.rb +0 -471
- data/spec/rspec/matchers/matchers_spec.rb +0 -37
- data/spec/rspec/matchers/method_missing_spec.rb +0 -28
- data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
- data/spec/rspec/matchers/raise_error_spec.rb +0 -395
- data/spec/rspec/matchers/respond_to_spec.rb +0 -292
- data/spec/rspec/matchers/satisfy_spec.rb +0 -44
- data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
- data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
- data/spec/rspec/matchers/yield_spec.rb +0 -437
- data/spec/spec_helper.rb +0 -54
- data/spec/support/classes.rb +0 -56
- data/spec/support/in_sub_process.rb +0 -38
- data/spec/support/matchers.rb +0 -22
- data/spec/support/ruby_version.rb +0 -10
- data/spec/support/shared_examples.rb +0 -13
|
@@ -1,36 +1,84 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Matchers
|
|
3
3
|
module BuiltIn
|
|
4
|
+
# @api private
|
|
5
|
+
# Provides the implementation for `has_<predicate>`.
|
|
6
|
+
# Not intended to be instantiated directly.
|
|
4
7
|
class Has
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
include Composable
|
|
9
|
+
|
|
10
|
+
def initialize(method_name, *args, &block)
|
|
11
|
+
@method_name, @args, @block = method_name, args, block
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @private
|
|
15
|
+
def matches?(actual, &block)
|
|
16
|
+
@actual = actual
|
|
17
|
+
@block ||= block
|
|
18
|
+
predicate_accessible? && predicate_matches?
|
|
7
19
|
end
|
|
8
20
|
|
|
9
|
-
|
|
10
|
-
|
|
21
|
+
# @private
|
|
22
|
+
def does_not_match?(actual, &block)
|
|
23
|
+
@actual = actual
|
|
24
|
+
@block ||= block
|
|
25
|
+
predicate_accessible? && !predicate_matches?
|
|
11
26
|
end
|
|
12
|
-
alias == matches?
|
|
13
27
|
|
|
14
|
-
|
|
15
|
-
|
|
28
|
+
# @api private
|
|
29
|
+
# @return [String]
|
|
30
|
+
def failure_message
|
|
31
|
+
validity_message || "expected ##{predicate}#{failure_message_args_description} to return true, got false"
|
|
16
32
|
end
|
|
17
33
|
|
|
18
|
-
|
|
19
|
-
|
|
34
|
+
# @api private
|
|
35
|
+
# @return [String]
|
|
36
|
+
def failure_message_when_negated
|
|
37
|
+
validity_message || "expected ##{predicate}#{failure_message_args_description} to return false, got true"
|
|
20
38
|
end
|
|
21
39
|
|
|
40
|
+
# @api private
|
|
41
|
+
# @return [String]
|
|
22
42
|
def description
|
|
23
|
-
[method_description
|
|
43
|
+
[method_description, args_description].compact.join(' ')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @private
|
|
47
|
+
def supports_block_expectations?
|
|
48
|
+
false
|
|
24
49
|
end
|
|
25
50
|
|
|
26
|
-
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def predicate_accessible?
|
|
54
|
+
!private_predicate? && predicate_exists?
|
|
55
|
+
end
|
|
27
56
|
|
|
28
|
-
|
|
29
|
-
|
|
57
|
+
# support 1.8.7, evaluate once at load time for performance
|
|
58
|
+
if String === methods.first
|
|
59
|
+
def private_predicate?
|
|
60
|
+
@actual.private_methods.include? predicate.to_s
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
def private_predicate?
|
|
64
|
+
@actual.private_methods.include? predicate
|
|
65
|
+
end
|
|
30
66
|
end
|
|
31
67
|
|
|
32
|
-
def
|
|
33
|
-
|
|
68
|
+
def predicate_exists?
|
|
69
|
+
@actual.respond_to? predicate
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def predicate_matches?
|
|
73
|
+
@actual.__send__(predicate, *@args, &@block)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def predicate
|
|
77
|
+
@predicate ||= :"has_#{@method_name.to_s.match(Matchers::HAS_REGEX).captures.first}?"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def method_description
|
|
81
|
+
@method_name.to_s.gsub('_', ' ')
|
|
34
82
|
end
|
|
35
83
|
|
|
36
84
|
def args_description
|
|
@@ -42,6 +90,14 @@ module RSpec
|
|
|
42
90
|
desc = args_description
|
|
43
91
|
"(#{desc})" if desc
|
|
44
92
|
end
|
|
93
|
+
|
|
94
|
+
def validity_message
|
|
95
|
+
if private_predicate?
|
|
96
|
+
"expected #{@actual} to respond to `#{predicate}` but `#{predicate}` is a private method"
|
|
97
|
+
elsif !predicate_exists?
|
|
98
|
+
"expected #{@actual} to respond to `#{predicate}`"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
45
101
|
end
|
|
46
102
|
end
|
|
47
103
|
end
|
|
@@ -1,67 +1,96 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Matchers
|
|
3
3
|
module BuiltIn
|
|
4
|
+
# @api private
|
|
5
|
+
# Provides the implementation for `include`.
|
|
6
|
+
# Not intended to be instantiated directly.
|
|
4
7
|
class Include < BaseMatcher
|
|
5
8
|
def initialize(*expected)
|
|
6
9
|
@expected = expected
|
|
7
10
|
end
|
|
8
11
|
|
|
12
|
+
# @api private
|
|
13
|
+
# @return [Boolean]
|
|
9
14
|
def matches?(actual)
|
|
10
15
|
@actual = actual
|
|
11
|
-
perform_match(:all?, :all
|
|
16
|
+
perform_match(:all?, :all?)
|
|
12
17
|
end
|
|
13
18
|
|
|
19
|
+
# @api private
|
|
20
|
+
# @return [Boolean]
|
|
14
21
|
def does_not_match?(actual)
|
|
15
22
|
@actual = actual
|
|
16
|
-
perform_match(:none?, :any
|
|
23
|
+
perform_match(:none?, :any?)
|
|
17
24
|
end
|
|
18
25
|
|
|
26
|
+
# @api private
|
|
27
|
+
# @return [String]
|
|
19
28
|
def description
|
|
20
|
-
|
|
29
|
+
described_items = surface_descriptions_in(expected)
|
|
30
|
+
improve_hash_formatting "include#{to_sentence(described_items)}"
|
|
21
31
|
end
|
|
22
32
|
|
|
33
|
+
# @api private
|
|
34
|
+
# @return [String]
|
|
35
|
+
def failure_message
|
|
36
|
+
improve_hash_formatting(super)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @api private
|
|
40
|
+
# @return [String]
|
|
41
|
+
def failure_message_when_negated
|
|
42
|
+
improve_hash_formatting(super)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @api private
|
|
46
|
+
# @return [Boolean]
|
|
23
47
|
def diffable?
|
|
24
|
-
|
|
25
|
-
# output, which includes their instance variables and such.
|
|
26
|
-
@expected.none? { |e| is_a_matcher?(e) }
|
|
48
|
+
true
|
|
27
49
|
end
|
|
28
50
|
|
|
29
|
-
|
|
51
|
+
private
|
|
30
52
|
|
|
31
|
-
def perform_match(predicate,
|
|
32
|
-
|
|
33
|
-
if
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
elsif comparing_hash_keys?(
|
|
38
|
-
|
|
39
|
-
elsif comparing_with_matcher?(actual, expected)
|
|
40
|
-
actual.any? { |value| expected.matches?(value) }
|
|
53
|
+
def perform_match(predicate, hash_subset_predicate)
|
|
54
|
+
expected.__send__(predicate) do |expected_item|
|
|
55
|
+
if comparing_hash_to_a_subset?(expected_item)
|
|
56
|
+
expected_item.__send__(hash_subset_predicate) do |(key, value)|
|
|
57
|
+
actual_hash_includes?(key, value)
|
|
58
|
+
end
|
|
59
|
+
elsif comparing_hash_keys?(expected_item)
|
|
60
|
+
actual_hash_has_key?(expected_item)
|
|
41
61
|
else
|
|
42
|
-
|
|
62
|
+
actual_collection_includes?(expected_item)
|
|
43
63
|
end
|
|
44
64
|
end
|
|
45
65
|
end
|
|
46
66
|
|
|
47
|
-
def
|
|
48
|
-
actual.is_a?(Hash) &&
|
|
67
|
+
def comparing_hash_to_a_subset?(expected_item)
|
|
68
|
+
actual.is_a?(Hash) && expected_item.is_a?(Hash)
|
|
49
69
|
end
|
|
50
70
|
|
|
51
|
-
def
|
|
52
|
-
actual.
|
|
71
|
+
def actual_hash_includes?(expected_key, expected_value)
|
|
72
|
+
actual_value = actual.fetch(expected_key) { return false }
|
|
73
|
+
values_match?(expected_value, actual_value)
|
|
53
74
|
end
|
|
54
75
|
|
|
55
|
-
def
|
|
56
|
-
actual.is_a?(
|
|
76
|
+
def comparing_hash_keys?(expected_item)
|
|
77
|
+
actual.is_a?(Hash) && !expected_item.is_a?(Hash)
|
|
57
78
|
end
|
|
58
79
|
|
|
59
|
-
def
|
|
60
|
-
|
|
80
|
+
def actual_hash_has_key?(expected_key)
|
|
81
|
+
# We check `has_key?` first for perf:
|
|
82
|
+
# has_key? is O(1), but `any?` is O(N).
|
|
83
|
+
actual.has_key?(expected_key) ||
|
|
84
|
+
actual.keys.any? { |key| values_match?(expected_key, key) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def actual_collection_includes?(expected_item)
|
|
88
|
+
return true if actual.include?(expected_item)
|
|
89
|
+
|
|
90
|
+
# String lacks an `any?` method...
|
|
91
|
+
return false unless actual.respond_to?(:any?)
|
|
61
92
|
|
|
62
|
-
|
|
63
|
-
object.respond_to?(msg)
|
|
64
|
-
end && object.respond_to?(:matches?)
|
|
93
|
+
actual.any? { |value| values_match?(expected_item, value) }
|
|
65
94
|
end
|
|
66
95
|
end
|
|
67
96
|
end
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Matchers
|
|
3
3
|
module BuiltIn
|
|
4
|
+
# @api private
|
|
5
|
+
# Provides the implementation for `match`.
|
|
6
|
+
# Not intended to be instantiated directly.
|
|
4
7
|
class Match < BaseMatcher
|
|
5
8
|
|
|
9
|
+
# @api private
|
|
10
|
+
# @return [String]
|
|
11
|
+
def description
|
|
12
|
+
"match #{surface_descriptions_in(expected).inspect}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @api private
|
|
16
|
+
# @return [Boolean]
|
|
17
|
+
def diffable?
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
6
23
|
def match(expected, actual)
|
|
7
|
-
|
|
24
|
+
return true if values_match?(expected, actual)
|
|
25
|
+
actual.match(expected) if actual.respond_to?(:match)
|
|
8
26
|
end
|
|
9
27
|
end
|
|
10
28
|
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require 'rspec/support'
|
|
2
|
+
|
|
3
|
+
module RSpec
|
|
4
|
+
module Matchers
|
|
5
|
+
module BuiltIn
|
|
6
|
+
# @api private
|
|
7
|
+
# Provides the implementation for operator matchers.
|
|
8
|
+
# Not intended to be instantiated directly.
|
|
9
|
+
# Only available for use with `should`.
|
|
10
|
+
class OperatorMatcher
|
|
11
|
+
class << self
|
|
12
|
+
# @private
|
|
13
|
+
def registry
|
|
14
|
+
@registry ||= {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @private
|
|
18
|
+
def register(klass, operator, matcher)
|
|
19
|
+
registry[klass] ||= {}
|
|
20
|
+
registry[klass][operator] = matcher
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @private
|
|
24
|
+
def unregister(klass, operator)
|
|
25
|
+
registry[klass] && registry[klass].delete(operator)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @private
|
|
29
|
+
def get(klass, operator)
|
|
30
|
+
klass.ancestors.each { |ancestor|
|
|
31
|
+
matcher = registry[ancestor] && registry[ancestor][operator]
|
|
32
|
+
return matcher if matcher
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
register Enumerable, '=~', BuiltIn::ContainExactly
|
|
40
|
+
|
|
41
|
+
def initialize(actual)
|
|
42
|
+
@actual = actual
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @private
|
|
46
|
+
def self.use_custom_matcher_or_delegate(operator)
|
|
47
|
+
define_method(operator) do |expected|
|
|
48
|
+
if uses_generic_implementation_of?(operator) && matcher = OperatorMatcher.get(@actual.class, operator)
|
|
49
|
+
@actual.__send__(::RSpec::Matchers.last_expectation_handler.should_method, matcher.new(expected))
|
|
50
|
+
else
|
|
51
|
+
eval_match(@actual, operator, expected)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
negative_operator = operator.sub(/^=/, '!')
|
|
56
|
+
if negative_operator != operator && respond_to?(negative_operator)
|
|
57
|
+
define_method(negative_operator) do |expected|
|
|
58
|
+
opposite_should = ::RSpec::Matchers.last_expectation_handler.opposite_should_method
|
|
59
|
+
raise "RSpec does not support `#{::RSpec::Matchers.last_expectation_handler.should_method} #{negative_operator} expected`. " +
|
|
60
|
+
"Use `#{opposite_should} #{operator} expected` instead."
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
['==', '===', '=~', '>', '>=', '<', '<='].each do |operator|
|
|
66
|
+
use_custom_matcher_or_delegate operator
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @private
|
|
70
|
+
def fail_with_message(message)
|
|
71
|
+
RSpec::Expectations.fail_with(message, @expected, @actual)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @api private
|
|
75
|
+
# @return [String]
|
|
76
|
+
def description
|
|
77
|
+
"#{@operator} #{@expected.inspect}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def uses_generic_implementation_of?(op)
|
|
83
|
+
Support.method_handle_for(@actual, op).owner == ::Kernel
|
|
84
|
+
rescue NameError
|
|
85
|
+
false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def eval_match(actual, operator, expected)
|
|
89
|
+
::RSpec::Matchers.last_matcher = self
|
|
90
|
+
@operator, @expected = operator, expected
|
|
91
|
+
__delegate_operator(actual, operator, expected)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @private
|
|
96
|
+
# Handles operator matcher for `should`.
|
|
97
|
+
class PositiveOperatorMatcher < OperatorMatcher
|
|
98
|
+
def __delegate_operator(actual, operator, expected)
|
|
99
|
+
if actual.__send__(operator, expected)
|
|
100
|
+
true
|
|
101
|
+
elsif ['==','===', '=~'].include?(operator)
|
|
102
|
+
fail_with_message("expected: #{expected.inspect}\n got: #{actual.inspect} (using #{operator})")
|
|
103
|
+
else
|
|
104
|
+
fail_with_message("expected: #{operator} #{expected.inspect}\n got: #{operator.gsub(/./, ' ')} #{actual.inspect}")
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @private
|
|
110
|
+
# Handles operator matcher for `should_not`.
|
|
111
|
+
class NegativeOperatorMatcher < OperatorMatcher
|
|
112
|
+
def __delegate_operator(actual, operator, expected)
|
|
113
|
+
return false unless actual.__send__(operator, expected)
|
|
114
|
+
return fail_with_message("expected not: #{operator} #{expected.inspect}\n got: #{operator.gsub(/./, ' ')} #{actual.inspect}")
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
require 'stringio'
|
|
2
|
+
|
|
3
|
+
module RSpec
|
|
4
|
+
module Matchers
|
|
5
|
+
module BuiltIn
|
|
6
|
+
# @api private
|
|
7
|
+
# Provides the implementation for `output`.
|
|
8
|
+
# Not intended to be instantiated directly.
|
|
9
|
+
class Output < BaseMatcher
|
|
10
|
+
def initialize(expected)
|
|
11
|
+
@expected = expected
|
|
12
|
+
@stream_capturer = NullCapture
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def matches?(block)
|
|
16
|
+
@block = block
|
|
17
|
+
return false unless Proc === block
|
|
18
|
+
@actual = @stream_capturer.capture(block)
|
|
19
|
+
@expected ? values_match?(@expected, @actual) : captured?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def does_not_match?(block)
|
|
23
|
+
!matches?(block) && Proc === block
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @api public
|
|
27
|
+
# Tells the matcher to match against stdout.
|
|
28
|
+
def to_stdout
|
|
29
|
+
@stream_capturer = CaptureStdout
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @api public
|
|
34
|
+
# Tells the matcher to match against stderr.
|
|
35
|
+
def to_stderr
|
|
36
|
+
@stream_capturer = CaptureStderr
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @api private
|
|
41
|
+
# @return [String]
|
|
42
|
+
def failure_message
|
|
43
|
+
"expected block to #{description}, but #{positive_failure_reason}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @api private
|
|
47
|
+
# @return [String]
|
|
48
|
+
def failure_message_when_negated
|
|
49
|
+
"expected block to not #{description}, but #{negative_failure_reason}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @api private
|
|
53
|
+
# @return [String]
|
|
54
|
+
def description
|
|
55
|
+
if @expected
|
|
56
|
+
"output #{description_of @expected} to #{@stream_capturer.name}"
|
|
57
|
+
else
|
|
58
|
+
"output to #{@stream_capturer.name}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @api private
|
|
63
|
+
# @return [Boolean]
|
|
64
|
+
def diffable?
|
|
65
|
+
true
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @api private
|
|
69
|
+
# Indicates this matcher matches against a block.
|
|
70
|
+
# @return [True]
|
|
71
|
+
def supports_block_expectations?
|
|
72
|
+
true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def captured?
|
|
78
|
+
@actual.length > 0
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def positive_failure_reason
|
|
82
|
+
return "was not a block" unless Proc === @block
|
|
83
|
+
return "output #{actual_output_description}" if @expected
|
|
84
|
+
"did not"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def negative_failure_reason
|
|
88
|
+
return "was not a block" unless Proc === @block
|
|
89
|
+
"output #{actual_output_description}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def actual_output_description
|
|
93
|
+
return "nothing" unless captured?
|
|
94
|
+
@actual.inspect
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @private
|
|
99
|
+
module NullCapture
|
|
100
|
+
def self.name
|
|
101
|
+
"some stream"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def self.capture(block)
|
|
105
|
+
raise "You must chain `to_stdout` or `to_stderr` off of the `output(...)` matcher."
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @private
|
|
110
|
+
module CaptureStdout
|
|
111
|
+
def self.name
|
|
112
|
+
'stdout'
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def self.capture(block)
|
|
116
|
+
captured_stream = StringIO.new
|
|
117
|
+
|
|
118
|
+
original_stream = $stdout
|
|
119
|
+
$stdout = captured_stream
|
|
120
|
+
|
|
121
|
+
block.call
|
|
122
|
+
|
|
123
|
+
captured_stream.string
|
|
124
|
+
ensure
|
|
125
|
+
$stdout = original_stream
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @private
|
|
130
|
+
module CaptureStderr
|
|
131
|
+
def self.name
|
|
132
|
+
'stderr'
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def self.capture(block)
|
|
136
|
+
captured_stream = StringIO.new
|
|
137
|
+
|
|
138
|
+
original_stream = $stderr
|
|
139
|
+
$stderr = captured_stream
|
|
140
|
+
|
|
141
|
+
block.call
|
|
142
|
+
|
|
143
|
+
captured_stream.string
|
|
144
|
+
ensure
|
|
145
|
+
$stderr = original_stream
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|