rspec-expectations 2.13.0 → 2.99.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
- data/Changelog.md +204 -23
- data/README.md +43 -87
- data/features/README.md +10 -10
- data/features/built_in_matchers/README.md +41 -41
- data/features/built_in_matchers/be.feature +40 -40
- data/features/built_in_matchers/be_within.feature +3 -3
- data/features/built_in_matchers/expect_change.feature +6 -6
- data/features/built_in_matchers/expect_error.feature +2 -2
- data/features/built_in_matchers/start_with.feature +1 -1
- data/features/built_in_matchers/throw_symbol.feature +11 -11
- data/features/built_in_matchers/yield.feature +18 -3
- data/features/custom_matchers/define_diffable_matcher.feature +1 -1
- data/features/custom_matchers/define_matcher_outside_rspec.feature +6 -6
- data/features/custom_matchers/define_matcher_with_fluent_interface.feature +1 -1
- data/features/customized_message.feature +1 -1
- data/features/diffing.feature +1 -1
- data/features/step_definitions/additional_cli_steps.rb +10 -0
- data/features/support/env.rb +10 -1
- data/features/support/rubinius.rb +6 -0
- data/features/syntax_configuration.feature +3 -0
- data/features/test_frameworks/test_unit.feature +55 -17
- data/lib/rspec/expectations/caller_filter.rb +60 -0
- data/lib/rspec/{matchers → expectations}/configuration.rb +5 -3
- data/lib/rspec/expectations/deprecation.rb +20 -31
- data/lib/rspec/expectations/differ.rb +48 -9
- data/lib/rspec/expectations/expectation_target.rb +81 -15
- data/lib/rspec/expectations/extensions/object.rb +2 -12
- data/lib/rspec/expectations/fail_with.rb +11 -1
- data/lib/rspec/expectations/handler.rb +16 -7
- data/lib/rspec/expectations/syntax.rb +5 -7
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/expectations.rb +28 -2
- data/lib/rspec/matchers/be_close.rb +4 -1
- data/lib/rspec/matchers/built_in/base_matcher.rb +17 -10
- data/lib/rspec/matchers/built_in/be.rb +69 -32
- data/lib/rspec/matchers/built_in/be_within.rb +9 -3
- data/lib/rspec/matchers/built_in/change.rb +49 -3
- data/lib/rspec/matchers/built_in/has.rb +40 -7
- data/lib/rspec/matchers/built_in/have.rb +170 -5
- data/lib/rspec/matchers/built_in/include.rb +3 -11
- data/lib/rspec/matchers/built_in/match.rb +5 -0
- data/lib/rspec/matchers/built_in/match_array.rb +1 -1
- data/lib/rspec/matchers/built_in/raise_error.rb +34 -8
- data/lib/rspec/matchers/built_in/respond_to.rb +7 -1
- data/lib/rspec/matchers/built_in/satisfy.rb +7 -1
- data/lib/rspec/matchers/built_in/throw_symbol.rb +10 -2
- data/lib/rspec/matchers/built_in/yield.rb +102 -5
- data/lib/rspec/matchers/built_in.rb +2 -2
- data/lib/rspec/matchers/differentiate_block_method_types.rb +55 -0
- data/lib/rspec/matchers/dsl.rb +2 -1
- data/lib/rspec/matchers/match_aliases.rb +22 -0
- data/lib/rspec/matchers/matcher.rb +131 -10
- data/lib/rspec/matchers/operator_matcher.rb +70 -66
- data/lib/rspec/matchers/pretty.rb +11 -1
- data/lib/rspec/matchers/test_unit_integration.rb +28 -0
- data/lib/rspec/matchers.rb +175 -146
- data/lib/rspec-expectations.rb +5 -0
- data/spec/rspec/{matchers → expectations}/configuration_spec.rb +78 -91
- data/spec/rspec/expectations/differ_spec.rb +65 -6
- data/spec/rspec/expectations/expectation_target_spec.rb +72 -3
- data/spec/rspec/expectations/extensions/kernel_spec.rb +9 -5
- data/spec/rspec/expectations/fail_with_spec.rb +19 -0
- data/spec/rspec/expectations/handler_spec.rb +43 -22
- data/spec/rspec/expectations/syntax_spec.rb +51 -9
- data/spec/rspec/expectations_spec.rb +71 -0
- data/spec/rspec/matchers/base_matcher_spec.rb +33 -18
- data/spec/rspec/matchers/be_close_spec.rb +9 -6
- data/spec/rspec/matchers/be_spec.rb +146 -45
- data/spec/rspec/matchers/be_within_spec.rb +8 -0
- data/spec/rspec/matchers/change_spec.rb +107 -7
- data/spec/rspec/matchers/description_generation_spec.rb +38 -20
- data/spec/rspec/matchers/differentiate_block_method_types_spec.rb +39 -0
- data/spec/rspec/matchers/eq_spec.rb +1 -1
- data/spec/rspec/matchers/equal_spec.rb +26 -0
- data/spec/rspec/matchers/exist_spec.rb +9 -9
- data/spec/rspec/matchers/has_spec.rb +25 -1
- data/spec/rspec/matchers/have_spec.rb +411 -3
- data/spec/rspec/matchers/include_matcher_integration_spec.rb +2 -2
- data/spec/rspec/matchers/include_spec.rb +4 -4
- data/spec/rspec/matchers/match_array_spec.rb +1 -1
- data/spec/rspec/matchers/match_spec.rb +14 -1
- data/spec/rspec/matchers/matcher_spec.rb +213 -24
- data/spec/rspec/matchers/operator_matcher_spec.rb +56 -8
- data/spec/rspec/matchers/pretty_spec.rb +23 -0
- data/spec/rspec/matchers/raise_error_spec.rb +242 -102
- data/spec/rspec/matchers/respond_to_spec.rb +4 -4
- data/spec/rspec/matchers/satisfy_spec.rb +1 -1
- data/spec/rspec/matchers/start_with_end_with_spec.rb +2 -2
- data/spec/rspec/matchers/throw_symbol_spec.rb +14 -14
- data/spec/rspec/matchers/yield_spec.rb +81 -4
- data/spec/spec_helper.rb +5 -3
- data/spec/support/helper_methods.rb +42 -0
- data/spec/support/shared_examples.rb +42 -0
- metadata +40 -44
- data/spec/rspec/matchers/matchers_spec.rb +0 -37
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Feature: Test::Unit integration
|
|
2
2
|
|
|
3
|
-
RSpec-expectations is a stand-alone gem that can be used without
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
syntax but prefer the test organization of another framework.
|
|
3
|
+
RSpec-expectations is a stand-alone gem that can be used without the rest of
|
|
4
|
+
RSpec. If you like the way Test::Unit (or MiniTest) organizes tests, but
|
|
5
|
+
prefer RSpec's approach to expressing expectations, you can have both.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
The one downside is that failures are reported as errors with MiniTest.
|
|
8
|
+
|
|
9
|
+
Scenario: use rspec/expectations with Test::Unit
|
|
9
10
|
Given a file named "rspec_expectations_test.rb" with:
|
|
10
11
|
"""ruby
|
|
11
12
|
require 'test/unit'
|
|
@@ -17,30 +18,67 @@ Feature: Test::Unit integration
|
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def be_an_int
|
|
20
|
-
|
|
21
|
+
# This is actually an internal rspec-expectations API, but is used
|
|
22
|
+
# here to demonstrate that deprecation warnings from within
|
|
23
|
+
# rspec-expectations work correcty without depending on rspec-core
|
|
24
|
+
RSpec.deprecate(:be_an_int, :replacement => :be_an_integer)
|
|
21
25
|
be_an_integer
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
def test_passing_expectation
|
|
25
|
-
|
|
26
|
-
x.should == 4
|
|
29
|
+
expect(1 + 3).to eq 4
|
|
27
30
|
end
|
|
28
31
|
|
|
29
32
|
def test_failing_expectation
|
|
30
|
-
|
|
31
|
-
array.should be_empty
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def test_expect_matcher
|
|
35
|
-
expect { @a = 5 }.to change { @a }.from(nil).to(5)
|
|
33
|
+
expect([1,2]).to be_empty
|
|
36
34
|
end
|
|
37
35
|
|
|
38
|
-
def
|
|
39
|
-
1.
|
|
36
|
+
def test_custom_matcher_with_deprecation_warning
|
|
37
|
+
expect(1).to be_an_int
|
|
40
38
|
end
|
|
41
39
|
end
|
|
42
40
|
"""
|
|
43
41
|
When I run `ruby rspec_expectations_test.rb`
|
|
44
|
-
Then the output should contain "
|
|
42
|
+
Then the output should contain "3 tests, 0 assertions, 0 failures, 1 errors" or "3 tests, 0 assertions, 1 failures, 0 errors"
|
|
45
43
|
And the output should contain "expected empty? to return true, got false"
|
|
46
44
|
And the output should contain "be_an_int is deprecated"
|
|
45
|
+
And the output should contain a deprecation warning about rspec-expecations' built-in integration
|
|
46
|
+
|
|
47
|
+
Scenario: use rspec/expectations with Test::Unit
|
|
48
|
+
Given a file named "rspec_expectations_with_manual_integration_test.rb" with:
|
|
49
|
+
"""
|
|
50
|
+
require 'test/unit'
|
|
51
|
+
require "rspec/expectations"
|
|
52
|
+
|
|
53
|
+
class RSpecExpectationsTest < Test::Unit::TestCase
|
|
54
|
+
include ::RSpec::Matchers
|
|
55
|
+
|
|
56
|
+
RSpec::Matchers.define :be_an_integer do
|
|
57
|
+
match { |actual| Integer === actual }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def be_an_int
|
|
61
|
+
# This is actually an internal rspec-expectations API, but is used
|
|
62
|
+
# here to demonstrate that deprecation warnings from within
|
|
63
|
+
# rspec-expectations work correcty without depending on rspec-core
|
|
64
|
+
RSpec.deprecate(:be_an_int, :replacement => :be_an_integer)
|
|
65
|
+
be_an_integer
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_passing_expectation
|
|
69
|
+
expect(1 + 3).to eq 4
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_failing_expectation
|
|
73
|
+
expect([1,2]).to be_empty
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_custom_matcher_with_deprecation_warning
|
|
77
|
+
expect(1).to be_an_int
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
"""
|
|
81
|
+
When I run `ruby rspec_expectations_with_manual_integration_test.rb`
|
|
82
|
+
Then the output should contain "3 tests, 0 assertions, 0 failures, 1 errors" or "3 tests, 0 assertions, 1 failures, 0 errors"
|
|
83
|
+
And the output should not contain a deprecation warning about rspec-expecations' built-in integration
|
|
84
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
# Consistent implementation for "cleaning" the caller method to strip out
|
|
3
|
+
# non-rspec lines. This enables errors to be reported at the call site in
|
|
4
|
+
# the code using the library, which is far more useful than the particular
|
|
5
|
+
# internal method that raised an error.
|
|
6
|
+
|
|
7
|
+
unless defined?(CallerFilter)
|
|
8
|
+
|
|
9
|
+
class CallerFilter
|
|
10
|
+
|
|
11
|
+
RSPEC_LIBS = %w[
|
|
12
|
+
core
|
|
13
|
+
mocks
|
|
14
|
+
expectations
|
|
15
|
+
matchers
|
|
16
|
+
rails
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
ADDITIONAL_TOP_LEVEL_FILES = %w[ autorun ]
|
|
20
|
+
|
|
21
|
+
LIB_REGEX = %r{/lib/rspec/(#{(RSPEC_LIBS + ADDITIONAL_TOP_LEVEL_FILES).join('|')})(\.rb|/)}
|
|
22
|
+
|
|
23
|
+
if RUBY_VERSION >= '2.0.0'
|
|
24
|
+
def self.first_non_rspec_line
|
|
25
|
+
# `caller` is an expensive method that scales linearly with the size of
|
|
26
|
+
# the stack. The performance hit for fetching it in chunks is small,
|
|
27
|
+
# and since the target line is probably near the top of the stack, the
|
|
28
|
+
# overall improvement of a chunked search like this is significant.
|
|
29
|
+
#
|
|
30
|
+
# See benchmarks/caller.rb for measurements.
|
|
31
|
+
|
|
32
|
+
# Initial value here is mostly arbitrary, but is chosen to give good
|
|
33
|
+
# performance on the common case of creating a double.
|
|
34
|
+
increment = 5
|
|
35
|
+
i = 1
|
|
36
|
+
line = nil
|
|
37
|
+
|
|
38
|
+
while !line
|
|
39
|
+
stack = caller(i, increment)
|
|
40
|
+
return nil unless stack
|
|
41
|
+
|
|
42
|
+
line = stack.find { |l| l !~ LIB_REGEX }
|
|
43
|
+
|
|
44
|
+
i += increment
|
|
45
|
+
increment *= 2 # The choice of two here is arbitrary.
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
line
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
# Earlier rubies do not support the two argument form of `caller`. This
|
|
52
|
+
# fallback is logically the same, but slower.
|
|
53
|
+
def self.first_non_rspec_line
|
|
54
|
+
caller.find { |line| line !~ LIB_REGEX }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'rspec/expectations/syntax'
|
|
2
2
|
|
|
3
3
|
module RSpec
|
|
4
|
-
module
|
|
4
|
+
module Expectations
|
|
5
5
|
# Provides configuration options for rspec-expectations.
|
|
6
6
|
class Configuration
|
|
7
7
|
# Configures the supported syntax.
|
|
@@ -94,11 +94,13 @@ module RSpec
|
|
|
94
94
|
end
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
|
+
end
|
|
97
98
|
|
|
99
|
+
module Matchers
|
|
98
100
|
# The configuration object
|
|
99
|
-
# @return [RSpec::
|
|
101
|
+
# @return [RSpec::Expectations::Configuration] the configuration object
|
|
100
102
|
def self.configuration
|
|
101
|
-
@configuration ||= Configuration.new
|
|
103
|
+
@configuration ||= Expectations::Configuration.new
|
|
102
104
|
end
|
|
103
105
|
|
|
104
106
|
# set default syntax
|
|
@@ -1,38 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
unless respond_to?(:deprecate)
|
|
3
|
-
class << self
|
|
4
|
-
# Used internally by RSpec to display standard deprecation warnings.
|
|
5
|
-
# This is also defined in rspec-core, but we can't assume it's loaded
|
|
6
|
-
# since rspec-expectations should be usable w/o rspec-core.
|
|
7
|
-
def deprecate(method, alternate_method=nil, version=nil)
|
|
8
|
-
version_string = version ? "rspec-#{version}" : "a future version of RSpec"
|
|
9
|
-
|
|
10
|
-
message = <<-NOTICE
|
|
11
|
-
|
|
12
|
-
*****************************************************************
|
|
13
|
-
DEPRECATION WARNING: you are using deprecated behaviour that will
|
|
14
|
-
be removed from #{version_string}.
|
|
15
|
-
|
|
16
|
-
#{caller(0)[2]}
|
|
1
|
+
require 'rspec/expectations/caller_filter' unless defined?(::RSpec::CallerFilter)
|
|
17
2
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
message << "
|
|
27
|
-
|
|
3
|
+
module RSpec
|
|
4
|
+
module Expectations
|
|
5
|
+
module Deprecation
|
|
6
|
+
# @private
|
|
7
|
+
#
|
|
8
|
+
# Used internally to print deprecation warnings
|
|
9
|
+
def deprecate(deprecated, options={})
|
|
10
|
+
message = "DEPRECATION: #{deprecated} is deprecated."
|
|
11
|
+
message << " Use #{options[:replacement]} instead." if options[:replacement]
|
|
12
|
+
message << " Called from #{CallerFilter.first_non_rspec_line}."
|
|
13
|
+
warn message
|
|
28
14
|
end
|
|
29
15
|
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
def warn_deprecation(
|
|
34
|
-
|
|
16
|
+
# @private
|
|
17
|
+
#
|
|
18
|
+
# Used internally to print deprecation warnings
|
|
19
|
+
def warn_deprecation(warning)
|
|
20
|
+
message = "\nDEPRECATION: #{warning}\n"
|
|
21
|
+
warn message
|
|
35
22
|
end
|
|
36
23
|
end
|
|
37
24
|
end
|
|
25
|
+
|
|
26
|
+
extend(Expectations::Deprecation) unless respond_to?(:deprecate)
|
|
38
27
|
end
|
|
@@ -5,12 +5,14 @@ require 'pp'
|
|
|
5
5
|
module RSpec
|
|
6
6
|
module Expectations
|
|
7
7
|
class Differ
|
|
8
|
+
|
|
8
9
|
# This is snagged from diff/lcs/ldiff.rb (which is a commandline tool)
|
|
9
|
-
def diff_as_string(
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
def diff_as_string(input_data_new, input_data_old)
|
|
11
|
+
encoding = pick_encoding input_data_new, input_data_old
|
|
12
|
+
output = matching_encoding("", encoding)
|
|
13
|
+
data_old = input_data_old.split(matching_encoding("\n", encoding)).map! { |e| e.chomp }
|
|
14
|
+
data_new = input_data_new.split(matching_encoding("\n", encoding)).map! { |e| e.chomp }
|
|
12
15
|
diffs = Diff::LCS.diff(data_old, data_new)
|
|
13
|
-
output = ""
|
|
14
16
|
return output if diffs.empty?
|
|
15
17
|
oldhunk = hunk = nil
|
|
16
18
|
file_length_difference = 0
|
|
@@ -33,16 +35,24 @@ module RSpec
|
|
|
33
35
|
hunk.unshift(oldhunk)
|
|
34
36
|
end
|
|
35
37
|
else
|
|
36
|
-
output << oldhunk.diff(format)
|
|
38
|
+
output << matching_encoding(oldhunk.diff(format).to_s, encoding)
|
|
37
39
|
end
|
|
38
40
|
ensure
|
|
39
41
|
oldhunk = hunk
|
|
40
|
-
output << "\n"
|
|
42
|
+
output << matching_encoding("\n", encoding)
|
|
41
43
|
end
|
|
42
44
|
end
|
|
43
45
|
#Handle the last remaining hunk
|
|
44
|
-
output << oldhunk.diff(format)
|
|
46
|
+
output << matching_encoding(oldhunk.diff(format).to_s, encoding)
|
|
47
|
+
output << matching_encoding("\n", encoding)
|
|
45
48
|
color_diff output
|
|
49
|
+
rescue Encoding::CompatibilityError
|
|
50
|
+
if input_data_new.encoding != input_data_old.encoding
|
|
51
|
+
"Could not produce a diff because the encoding of the actual string (#{input_data_old.encoding}) "+
|
|
52
|
+
"differs from the encoding of the expected string (#{input_data_new.encoding})"
|
|
53
|
+
else
|
|
54
|
+
"Could not produce a diff because of the encoding of the string (#{input_data_old.encoding})"
|
|
55
|
+
end
|
|
46
56
|
end
|
|
47
57
|
|
|
48
58
|
def diff_as_object(actual, expected)
|
|
@@ -99,8 +109,16 @@ module RSpec
|
|
|
99
109
|
def object_to_string(object)
|
|
100
110
|
case object
|
|
101
111
|
when Hash
|
|
102
|
-
object.keys.sort_by { |k| k.to_s }.map do |
|
|
103
|
-
|
|
112
|
+
object.keys.sort_by { |k| k.to_s }.map do |key|
|
|
113
|
+
pp_key = PP.singleline_pp(key, "")
|
|
114
|
+
pp_value = PP.singleline_pp(object[key], "")
|
|
115
|
+
|
|
116
|
+
# on 1.9.3 PP seems to minimise to US-ASCII, ensure we're matching source encoding
|
|
117
|
+
#
|
|
118
|
+
# note, PP is used to ensure the ordering of the internal values of key/value e.g.
|
|
119
|
+
# <# a: b: c:> not <# c: a: b:>
|
|
120
|
+
encoding = pick_encoding pp_key, pp_value
|
|
121
|
+
matching_encoding("#{pp_key} => #{pp_value}", encoding)
|
|
104
122
|
end.join(",\n")
|
|
105
123
|
when String
|
|
106
124
|
object =~ /\n/ ? object : object.inspect
|
|
@@ -108,6 +126,27 @@ module RSpec
|
|
|
108
126
|
PP.pp(object,"")
|
|
109
127
|
end
|
|
110
128
|
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
if String.method_defined?(:encoding)
|
|
133
|
+
def pick_encoding(source_a, source_b)
|
|
134
|
+
Encoding.compatible?(source_a, source_b) || Encoding.default_external
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def matching_encoding(string, encoding)
|
|
138
|
+
string.encode encoding
|
|
139
|
+
rescue Encoding::UndefinedConversionError
|
|
140
|
+
string.encode(encoding, :undef => :replace)
|
|
141
|
+
end
|
|
142
|
+
else
|
|
143
|
+
def pick_encoding(source_a, source_b)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def matching_encoding(string, encoding)
|
|
147
|
+
string
|
|
148
|
+
end
|
|
149
|
+
end
|
|
111
150
|
end
|
|
112
151
|
|
|
113
152
|
end
|
|
@@ -1,23 +1,48 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Expectations
|
|
3
3
|
# Wraps the target of an expectation.
|
|
4
|
+
#
|
|
4
5
|
# @example
|
|
5
|
-
# expect(something)
|
|
6
|
+
# expect(something) # => ExpectationTarget wrapping something
|
|
7
|
+
# expect { do_something } # => ExpectationTarget wrapping the block
|
|
6
8
|
#
|
|
7
9
|
# # used with `to`
|
|
8
10
|
# expect(actual).to eq(3)
|
|
9
11
|
#
|
|
10
|
-
# # with `
|
|
11
|
-
# expect(actual).
|
|
12
|
+
# # with `not_to`
|
|
13
|
+
# expect(actual).not_to eq(3)
|
|
14
|
+
#
|
|
15
|
+
# @note `ExpectationTarget` is not intended to be instantiated
|
|
16
|
+
# directly by users. Use `expect` instead.
|
|
12
17
|
class ExpectationTarget
|
|
13
18
|
class << self
|
|
14
19
|
attr_accessor :deprecated_should_enabled
|
|
15
20
|
alias deprecated_should_enabled? deprecated_should_enabled
|
|
16
21
|
end
|
|
17
22
|
|
|
23
|
+
# @private
|
|
24
|
+
# Used as a sentinel value to be able to tell when the user
|
|
25
|
+
# did not pass an argument. We can't use `nil` for that because
|
|
26
|
+
# `nil` is a valid value to pass.
|
|
27
|
+
UndefinedValue = Module.new
|
|
28
|
+
|
|
18
29
|
# @api private
|
|
19
|
-
def initialize(
|
|
20
|
-
@target =
|
|
30
|
+
def initialize(value)
|
|
31
|
+
@target = value
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @private
|
|
35
|
+
def self.for(value, block)
|
|
36
|
+
if UndefinedValue.equal?(value)
|
|
37
|
+
unless block
|
|
38
|
+
raise ArgumentError, "You must pass either an argument or a block to `expect`."
|
|
39
|
+
end
|
|
40
|
+
BlockExpectationTarget.new(block)
|
|
41
|
+
elsif block
|
|
42
|
+
raise ArgumentError, "You cannot pass both an argument and a block to `expect`."
|
|
43
|
+
else
|
|
44
|
+
new(value)
|
|
45
|
+
end
|
|
21
46
|
end
|
|
22
47
|
|
|
23
48
|
# Runs the given expectation, passing if `matcher` returns true.
|
|
@@ -30,35 +55,34 @@ module RSpec
|
|
|
30
55
|
# @return [Boolean] true if the expectation succeeds (else raises)
|
|
31
56
|
# @see RSpec::Matchers
|
|
32
57
|
def to(matcher=nil, message=nil, &block)
|
|
33
|
-
prevent_operator_matchers(:to
|
|
58
|
+
prevent_operator_matchers(:to) unless matcher
|
|
34
59
|
RSpec::Expectations::PositiveExpectationHandler.handle_matcher(@target, matcher, message, &block)
|
|
35
60
|
end
|
|
36
61
|
|
|
37
62
|
# Runs the given expectation, passing if `matcher` returns false.
|
|
38
63
|
# @example
|
|
39
|
-
# expect(value).to_not eq(5)
|
|
40
64
|
# expect(value).not_to eq(5)
|
|
41
65
|
# @param [Matcher]
|
|
42
66
|
# matcher
|
|
43
67
|
# @param [String] message optional message to display when the expectation fails
|
|
44
68
|
# @return [Boolean] false if the negative expectation succeeds (else raises)
|
|
45
69
|
# @see RSpec::Matchers
|
|
46
|
-
def
|
|
47
|
-
prevent_operator_matchers(:
|
|
70
|
+
def not_to(matcher=nil, message=nil, &block)
|
|
71
|
+
prevent_operator_matchers(:not_to) unless matcher
|
|
48
72
|
RSpec::Expectations::NegativeExpectationHandler.handle_matcher(@target, matcher, message, &block)
|
|
49
73
|
end
|
|
50
|
-
alias not_to
|
|
74
|
+
alias to_not not_to
|
|
51
75
|
|
|
52
76
|
def self.enable_deprecated_should
|
|
53
77
|
return if deprecated_should_enabled?
|
|
54
78
|
|
|
55
79
|
def should(*args)
|
|
56
|
-
RSpec.deprecate "`expect { }.should`", "`expect { }.to`"
|
|
80
|
+
RSpec.deprecate "`expect { }.should`", :replacement => "`expect { }.to`"
|
|
57
81
|
@target.should(*args)
|
|
58
82
|
end
|
|
59
83
|
|
|
60
84
|
def should_not(*args)
|
|
61
|
-
RSpec.deprecate "`expect { }.should_not`", "`expect { }.
|
|
85
|
+
RSpec.deprecate "`expect { }.should_not`", :replacement => "`expect { }.not_to`"
|
|
62
86
|
@target.should_not(*args)
|
|
63
87
|
end
|
|
64
88
|
|
|
@@ -76,13 +100,55 @@ module RSpec
|
|
|
76
100
|
|
|
77
101
|
private
|
|
78
102
|
|
|
79
|
-
def prevent_operator_matchers(verb
|
|
80
|
-
return if matcher
|
|
81
|
-
|
|
103
|
+
def prevent_operator_matchers(verb)
|
|
82
104
|
raise ArgumentError, "The expect syntax does not support operator matchers, " +
|
|
83
105
|
"so you must pass a matcher to `##{verb}`."
|
|
84
106
|
end
|
|
85
107
|
end
|
|
108
|
+
|
|
109
|
+
# @private
|
|
110
|
+
# Validates the provided matcher to ensure it supports block
|
|
111
|
+
# expectations, in order to avoid user confusion when they
|
|
112
|
+
# use a block thinking the expectation will be on the return
|
|
113
|
+
# value of the block rather than the block itself.
|
|
114
|
+
class BlockExpectationTarget < ExpectationTarget
|
|
115
|
+
def to(matcher, message=nil, &block)
|
|
116
|
+
enforce_block_expectation(matcher)
|
|
117
|
+
super
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def not_to(matcher, message=nil, &block)
|
|
121
|
+
enforce_block_expectation(matcher)
|
|
122
|
+
super
|
|
123
|
+
end
|
|
124
|
+
alias to_not not_to
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
def enforce_block_expectation(matcher)
|
|
129
|
+
return if supports_block_expectations?(matcher)
|
|
130
|
+
|
|
131
|
+
RSpec.deprecate("Using a matcher in a block expectation expression " +
|
|
132
|
+
"(e.g. `expect { }.to matcher`) that does not implement " +
|
|
133
|
+
"`supports_block_expectations?`",
|
|
134
|
+
:replacement => "a value expectation expression " +
|
|
135
|
+
"(e.g. `expect(value).to matcher`) or implement " +
|
|
136
|
+
"`supports_block_expectations?` on the provided matcher " +
|
|
137
|
+
"(#{description_of matcher})")
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def supports_block_expectations?(matcher)
|
|
141
|
+
matcher.supports_block_expectations?
|
|
142
|
+
rescue NoMethodError
|
|
143
|
+
false
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def description_of(matcher)
|
|
147
|
+
matcher.description
|
|
148
|
+
rescue NoMethodError
|
|
149
|
+
matcher.inspect
|
|
150
|
+
end
|
|
151
|
+
end
|
|
86
152
|
end
|
|
87
153
|
end
|
|
88
154
|
|
|
@@ -6,17 +6,7 @@ module RSpec
|
|
|
6
6
|
def const_missing(name)
|
|
7
7
|
case name
|
|
8
8
|
when :Rspec, :Spec
|
|
9
|
-
RSpec.
|
|
10
|
-
*****************************************************************
|
|
11
|
-
DEPRECATION WARNING: you are using a deprecated constant that will
|
|
12
|
-
be removed from a future version of RSpec.
|
|
13
|
-
|
|
14
|
-
#{caller(0)[2]}
|
|
15
|
-
|
|
16
|
-
* #{name} is deprecated.
|
|
17
|
-
* RSpec is the new top-level module in RSpec-2
|
|
18
|
-
***************************************************************
|
|
19
|
-
WARNING
|
|
9
|
+
RSpec.deprecate(name.to_s, :replacement => "RSpec")
|
|
20
10
|
RSpec
|
|
21
11
|
else
|
|
22
12
|
begin
|
|
@@ -31,7 +21,7 @@ WARNING
|
|
|
31
21
|
|
|
32
22
|
# @deprecated (no replacement)
|
|
33
23
|
def differ=(ignore)
|
|
34
|
-
RSpec.deprecate("RSpec::Expectations.differ=(differ)"
|
|
24
|
+
RSpec.deprecate("RSpec::Expectations.differ=(differ)")
|
|
35
25
|
end
|
|
36
26
|
end
|
|
37
27
|
end
|
|
@@ -52,7 +52,17 @@ module RSpec
|
|
|
52
52
|
|
|
53
53
|
def coerce_to_string(string_or_array)
|
|
54
54
|
return string_or_array unless Array === string_or_array
|
|
55
|
-
string_or_array.join(
|
|
55
|
+
diffably_stringify(string_or_array).join("\n")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def diffably_stringify(array)
|
|
59
|
+
array.map do |entry|
|
|
60
|
+
if Array === entry
|
|
61
|
+
entry.inspect
|
|
62
|
+
else
|
|
63
|
+
entry.to_s.gsub("\n", "\\n")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
56
66
|
end
|
|
57
67
|
|
|
58
68
|
if String.method_defined?(:encoding)
|
|
@@ -2,13 +2,14 @@ module RSpec
|
|
|
2
2
|
module Expectations
|
|
3
3
|
|
|
4
4
|
class ExpectationHandler
|
|
5
|
-
def self.message_must_be_string(msg)
|
|
6
|
-
"WARNING: ignoring the provided expectation message argument " +
|
|
7
|
-
"(#{msg.inspect}) since it is not a string."
|
|
8
|
-
end
|
|
9
|
-
|
|
10
5
|
def self.check_message(msg)
|
|
11
|
-
|
|
6
|
+
unless msg.nil? || msg.respond_to?(:to_str) || msg.respond_to?(:call)
|
|
7
|
+
::Kernel.warn [
|
|
8
|
+
"WARNING: ignoring the provided expectation message argument (",
|
|
9
|
+
msg.inspect,
|
|
10
|
+
") since it is not a string or a proc."
|
|
11
|
+
].join
|
|
12
|
+
end
|
|
12
13
|
end
|
|
13
14
|
end
|
|
14
15
|
|
|
@@ -23,12 +24,18 @@ module RSpec
|
|
|
23
24
|
match = matcher.matches?(actual, &block)
|
|
24
25
|
return match if match
|
|
25
26
|
|
|
27
|
+
message = message.call if message.respond_to?(:call)
|
|
28
|
+
|
|
26
29
|
message ||= matcher.respond_to?(:failure_message_for_should) ?
|
|
27
30
|
matcher.failure_message_for_should :
|
|
28
31
|
matcher.failure_message
|
|
29
32
|
|
|
30
33
|
if matcher.respond_to?(:diffable?) && matcher.diffable?
|
|
31
|
-
|
|
34
|
+
if RSpec::Matchers::DSL::Matcher === matcher
|
|
35
|
+
::RSpec::Expectations.fail_with message, matcher.expected_as_array, matcher.actual
|
|
36
|
+
else
|
|
37
|
+
::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual
|
|
38
|
+
end
|
|
32
39
|
else
|
|
33
40
|
::RSpec::Expectations.fail_with message
|
|
34
41
|
end
|
|
@@ -47,6 +54,8 @@ module RSpec
|
|
|
47
54
|
matcher.matches?(actual, &block)
|
|
48
55
|
return match unless match
|
|
49
56
|
|
|
57
|
+
message = message.call if message.respond_to?(:call)
|
|
58
|
+
|
|
50
59
|
message ||= matcher.respond_to?(:failure_message_for_should_not) ?
|
|
51
60
|
matcher.failure_message_for_should_not :
|
|
52
61
|
matcher.negative_failure_message
|
|
@@ -32,10 +32,10 @@ module RSpec
|
|
|
32
32
|
# `ExpectationTarget`.
|
|
33
33
|
# @example
|
|
34
34
|
# expect(actual).to eq(expected)
|
|
35
|
-
# expect(actual).
|
|
35
|
+
# expect(actual).not_to eq(expected)
|
|
36
36
|
# @return [ExpectationTarget]
|
|
37
37
|
# @see ExpectationTarget#to
|
|
38
|
-
# @see ExpectationTarget#
|
|
38
|
+
# @see ExpectationTarget#not_to
|
|
39
39
|
|
|
40
40
|
# @api private
|
|
41
41
|
# Determines where we add `should` and `should_not`.
|
|
@@ -79,11 +79,9 @@ module RSpec
|
|
|
79
79
|
def enable_expect(syntax_host = ::RSpec::Matchers)
|
|
80
80
|
return if expect_enabled?(syntax_host)
|
|
81
81
|
|
|
82
|
-
syntax_host.
|
|
83
|
-
def expect(
|
|
84
|
-
|
|
85
|
-
raise ArgumentError.new("You must pass an argument or a block to #expect but not both.") unless target.size == 1
|
|
86
|
-
::RSpec::Expectations::ExpectationTarget.new(target.first)
|
|
82
|
+
syntax_host.module_exec do
|
|
83
|
+
def expect(value=::RSpec::Expectations::ExpectationTarget::UndefinedValue, &block)
|
|
84
|
+
::RSpec::Expectations::ExpectationTarget.for(value, block)
|
|
87
85
|
end
|
|
88
86
|
end
|
|
89
87
|
|
data/lib/rspec/expectations.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'rspec/expectations/extensions'
|
|
2
2
|
require 'rspec/matchers'
|
|
3
3
|
require 'rspec/expectations/expectation_target'
|
|
4
|
-
require 'rspec/
|
|
4
|
+
require 'rspec/expectations/configuration'
|
|
5
5
|
require 'rspec/expectations/fail_with'
|
|
6
6
|
require 'rspec/expectations/errors'
|
|
7
7
|
require 'rspec/expectations/deprecation'
|
|
@@ -37,11 +37,37 @@ module RSpec
|
|
|
37
37
|
# `eq.failure_message_for_should_not`.
|
|
38
38
|
#
|
|
39
39
|
# rspec-expectations ships with a standard set of useful matchers, and writing
|
|
40
|
-
# your own matchers is quite simple.
|
|
40
|
+
# your own matchers is quite simple.
|
|
41
41
|
#
|
|
42
42
|
# See [RSpec::Matchers](../RSpec/Matchers) for more information about the
|
|
43
43
|
# built-in matchers that ship with rspec-expectations, and how to write your
|
|
44
44
|
# own custom matchers.
|
|
45
45
|
module Expectations
|
|
46
|
+
|
|
47
|
+
# @api private
|
|
48
|
+
KERNEL_METHOD_METHOD = ::Kernel.instance_method(:method)
|
|
49
|
+
|
|
50
|
+
# @api private
|
|
51
|
+
#
|
|
52
|
+
# Used internally to get a method handle for a particular object
|
|
53
|
+
# and method name.
|
|
54
|
+
#
|
|
55
|
+
# Includes handling for a few special cases:
|
|
56
|
+
#
|
|
57
|
+
# - Objects that redefine #method (e.g. an HTTPRequest struct)
|
|
58
|
+
# - BasicObject subclasses that mixin a Kernel dup (e.g. SimpleDelegator)
|
|
59
|
+
if RUBY_VERSION.to_i >= 2
|
|
60
|
+
def self.method_handle_for(object, method_name)
|
|
61
|
+
KERNEL_METHOD_METHOD.bind(object).call(method_name)
|
|
62
|
+
end
|
|
63
|
+
else
|
|
64
|
+
def self.method_handle_for(object, method_name)
|
|
65
|
+
if ::Kernel === object
|
|
66
|
+
KERNEL_METHOD_METHOD.bind(object).call(method_name)
|
|
67
|
+
else
|
|
68
|
+
object.method(method_name)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
46
72
|
end
|
|
47
73
|
end
|