rspec-expectations 3.0.4 → 3.12.3
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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +1 -1
- data/Changelog.md +530 -5
- data/{License.txt → LICENSE.md} +5 -4
- data/README.md +73 -31
- data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
- data/lib/rspec/expectations/configuration.rb +96 -1
- data/lib/rspec/expectations/expectation_target.rb +82 -38
- data/lib/rspec/expectations/fail_with.rb +11 -6
- data/lib/rspec/expectations/failure_aggregator.rb +229 -0
- data/lib/rspec/expectations/handler.rb +36 -15
- data/lib/rspec/expectations/minitest_integration.rb +43 -2
- data/lib/rspec/expectations/syntax.rb +5 -5
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/expectations.rb +15 -1
- data/lib/rspec/matchers/aliased_matcher.rb +79 -4
- data/lib/rspec/matchers/built_in/all.rb +11 -0
- data/lib/rspec/matchers/built_in/base_matcher.rb +111 -28
- data/lib/rspec/matchers/built_in/be.rb +28 -114
- data/lib/rspec/matchers/built_in/be_between.rb +1 -1
- data/lib/rspec/matchers/built_in/be_instance_of.rb +5 -1
- data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -1
- data/lib/rspec/matchers/built_in/be_within.rb +5 -12
- data/lib/rspec/matchers/built_in/change.rb +171 -63
- data/lib/rspec/matchers/built_in/compound.rb +201 -30
- data/lib/rspec/matchers/built_in/contain_exactly.rb +73 -12
- data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
- data/lib/rspec/matchers/built_in/eq.rb +3 -38
- data/lib/rspec/matchers/built_in/eql.rb +2 -2
- data/lib/rspec/matchers/built_in/equal.rb +3 -3
- data/lib/rspec/matchers/built_in/exist.rb +7 -3
- data/lib/rspec/matchers/built_in/has.rb +93 -30
- data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
- data/lib/rspec/matchers/built_in/include.rb +133 -25
- data/lib/rspec/matchers/built_in/match.rb +79 -2
- data/lib/rspec/matchers/built_in/operators.rb +14 -5
- data/lib/rspec/matchers/built_in/output.rb +59 -2
- data/lib/rspec/matchers/built_in/raise_error.rb +130 -27
- data/lib/rspec/matchers/built_in/respond_to.rb +117 -15
- data/lib/rspec/matchers/built_in/satisfy.rb +28 -14
- data/lib/rspec/matchers/built_in/{start_and_end_with.rb → start_or_end_with.rb} +20 -8
- data/lib/rspec/matchers/built_in/throw_symbol.rb +15 -5
- data/lib/rspec/matchers/built_in/yield.rb +129 -156
- data/lib/rspec/matchers/built_in.rb +5 -3
- data/lib/rspec/matchers/composable.rb +24 -36
- data/lib/rspec/matchers/dsl.rb +203 -37
- data/lib/rspec/matchers/english_phrasing.rb +58 -0
- data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +82 -0
- data/lib/rspec/matchers/fail_matchers.rb +42 -0
- data/lib/rspec/matchers/generated_descriptions.rb +1 -2
- data/lib/rspec/matchers/matcher_delegator.rb +3 -4
- data/lib/rspec/matchers/matcher_protocol.rb +105 -0
- data/lib/rspec/matchers.rb +267 -144
- data.tar.gz.sig +0 -0
- metadata +71 -49
- metadata.gz.sig +0 -0
- data/lib/rspec/matchers/pretty.rb +0 -77
data/README.md
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
# RSpec Expectations [](https://github.com/rspec/rspec-expectations/actions) [](https://codeclimate.com/github/rspec/rspec-expectations)
|
2
2
|
|
3
3
|
RSpec::Expectations lets you express expected outcomes on an object in an
|
4
4
|
example.
|
5
5
|
|
6
|
-
|
6
|
+
```ruby
|
7
|
+
expect(account.balance).to eq(Money.new(37.42, :USD))
|
8
|
+
```
|
7
9
|
|
8
10
|
## Install
|
9
11
|
|
@@ -13,11 +15,34 @@ rspec-core and rspec-mocks):
|
|
13
15
|
|
14
16
|
gem install rspec
|
15
17
|
|
18
|
+
Want to run against the `main` branch? You'll need to include the dependent
|
19
|
+
RSpec repos as well. Add the following to your `Gemfile`:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
%w[rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
|
23
|
+
gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'main'
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
16
27
|
If you want to use rspec-expectations with another tool, like Test::Unit,
|
17
28
|
Minitest, or Cucumber, you can install it directly:
|
18
29
|
|
19
30
|
gem install rspec-expectations
|
20
31
|
|
32
|
+
## Contributing
|
33
|
+
|
34
|
+
Once you've set up the environment, you'll need to cd into the working
|
35
|
+
directory of whichever repo you want to work in. From there you can run the
|
36
|
+
specs and cucumber features, and make patches.
|
37
|
+
|
38
|
+
NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
|
39
|
+
can treat each RSpec repo as an independent project.
|
40
|
+
|
41
|
+
- [Build details](BUILD_DETAIL.md)
|
42
|
+
- [Code of Conduct](CODE_OF_CONDUCT.md)
|
43
|
+
- [Detailed contributing guide](CONTRIBUTING.md)
|
44
|
+
- [Development setup guide](DEVELOPMENT.md)
|
45
|
+
|
21
46
|
## Basic usage
|
22
47
|
|
23
48
|
Here's an example using rspec-core:
|
@@ -52,6 +77,7 @@ the example passes. If not, it fails with a message like:
|
|
52
77
|
```ruby
|
53
78
|
expect(actual).to eq(expected) # passes if actual == expected
|
54
79
|
expect(actual).to eql(expected) # passes if actual.eql?(expected)
|
80
|
+
expect(actual).not_to eql(not_expected) # passes if not(actual.eql?(expected))
|
55
81
|
```
|
56
82
|
|
57
83
|
Note: The new `expect` syntax no longer supports the `==` matcher.
|
@@ -85,7 +111,7 @@ Note: The new `expect` syntax no longer supports the `=~` matcher.
|
|
85
111
|
|
86
112
|
```ruby
|
87
113
|
expect(actual).to be_an_instance_of(expected) # passes if actual.class == expected
|
88
|
-
expect(actual).to be_a(expected) # passes if actual.
|
114
|
+
expect(actual).to be_a(expected) # passes if actual.kind_of?(expected)
|
89
115
|
expect(actual).to be_an(expected) # an alias for be_a
|
90
116
|
expect(actual).to be_a_kind_of(expected) # another alias
|
91
117
|
```
|
@@ -93,11 +119,12 @@ expect(actual).to be_a_kind_of(expected) # another alias
|
|
93
119
|
### Truthiness
|
94
120
|
|
95
121
|
```ruby
|
96
|
-
expect(actual).to be_truthy
|
97
|
-
expect(actual).to be true
|
98
|
-
expect(actual).to be_falsy
|
99
|
-
expect(actual).to be false
|
100
|
-
expect(actual).to be_nil
|
122
|
+
expect(actual).to be_truthy # passes if actual is truthy (not nil or false)
|
123
|
+
expect(actual).to be true # passes if actual == true
|
124
|
+
expect(actual).to be_falsy # passes if actual is falsy (nil or false)
|
125
|
+
expect(actual).to be false # passes if actual == false
|
126
|
+
expect(actual).to be_nil # passes if actual is nil
|
127
|
+
expect(actual).to_not be_nil # passes if actual is not nil
|
101
128
|
```
|
102
129
|
|
103
130
|
### Expecting errors
|
@@ -125,7 +152,7 @@ expect { |b| 5.tap(&b) }.to yield_control # passes regardless of yielded args
|
|
125
152
|
expect { |b| yield_if_true(true, &b) }.to yield_with_no_args # passes only if no args are yielded
|
126
153
|
|
127
154
|
expect { |b| 5.tap(&b) }.to yield_with_args(5)
|
128
|
-
expect { |b| 5.tap(&b) }.to yield_with_args(
|
155
|
+
expect { |b| 5.tap(&b) }.to yield_with_args(Integer)
|
129
156
|
expect { |b| "a string".tap(&b) }.to yield_with_args(/str/)
|
130
157
|
|
131
158
|
expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3)
|
@@ -148,30 +175,45 @@ expect(1..10).to cover(3)
|
|
148
175
|
### Collection membership
|
149
176
|
|
150
177
|
```ruby
|
151
|
-
|
178
|
+
# exact order, entire collection
|
179
|
+
expect(actual).to eq(expected)
|
180
|
+
|
181
|
+
# exact order, partial collection (based on an exact position)
|
152
182
|
expect(actual).to start_with(expected)
|
153
183
|
expect(actual).to end_with(expected)
|
154
184
|
|
155
|
-
|
156
|
-
|
157
|
-
|
185
|
+
# any order, entire collection
|
186
|
+
expect(actual).to match_array(expected)
|
187
|
+
|
188
|
+
# You can also express this by passing the expected elements
|
189
|
+
# as individual arguments
|
190
|
+
expect(actual).to contain_exactly(expected_element1, expected_element2)
|
191
|
+
|
192
|
+
# any order, partial collection
|
193
|
+
expect(actual).to include(expected)
|
158
194
|
```
|
159
195
|
|
160
196
|
#### Examples
|
161
197
|
|
162
198
|
```ruby
|
163
|
-
expect([1, 2, 3]).to
|
164
|
-
expect([1, 2, 3]).to include(1,
|
165
|
-
expect([1, 2, 3]).to
|
166
|
-
expect([1, 2, 3]).to start_with(1,
|
167
|
-
expect([1, 2, 3]).to
|
168
|
-
expect([1, 2, 3]).to end_with(
|
169
|
-
expect(
|
170
|
-
expect(
|
171
|
-
expect("this string").to
|
172
|
-
expect("this string").to
|
173
|
-
expect(
|
174
|
-
expect([1, 2, 3]).to
|
199
|
+
expect([1, 2, 3]).to eq([1, 2, 3]) # Order dependent equality check
|
200
|
+
expect([1, 2, 3]).to include(1) # Exact ordering, partial collection matches
|
201
|
+
expect([1, 2, 3]).to include(2, 3) #
|
202
|
+
expect([1, 2, 3]).to start_with(1) # As above, but from the start of the collection
|
203
|
+
expect([1, 2, 3]).to start_with(1, 2) #
|
204
|
+
expect([1, 2, 3]).to end_with(3) # As above but from the end of the collection
|
205
|
+
expect([1, 2, 3]).to end_with(2, 3) #
|
206
|
+
expect({:a => 'b'}).to include(:a => 'b') # Matching within hashes
|
207
|
+
expect("this string").to include("is str") # Matching within strings
|
208
|
+
expect("this string").to start_with("this") #
|
209
|
+
expect("this string").to end_with("ring") #
|
210
|
+
expect([1, 2, 3]).to contain_exactly(2, 3, 1) # Order independent matches
|
211
|
+
expect([1, 2, 3]).to match_array([3, 2, 1]) #
|
212
|
+
|
213
|
+
# Order dependent compound matchers
|
214
|
+
expect(
|
215
|
+
[{:a => 'hash'},{:a => 'another'}]
|
216
|
+
).to match([a_hash_including(:a => 'hash'), a_hash_including(:a => 'another')])
|
175
217
|
```
|
176
218
|
|
177
219
|
## `should` syntax
|
@@ -185,7 +227,7 @@ actual.should be > 3
|
|
185
227
|
[1, 2, 3].should_not include 4
|
186
228
|
```
|
187
229
|
|
188
|
-
See [detailed information on the `should` syntax and its usage.](https://github.com/rspec/rspec-expectations/blob/
|
230
|
+
See [detailed information on the `should` syntax and its usage.](https://github.com/rspec/rspec-expectations/blob/main/Should.md)
|
189
231
|
|
190
232
|
## Compound Matcher Expressions
|
191
233
|
|
@@ -238,7 +280,7 @@ expect(hash).to match(
|
|
238
280
|
:a => {
|
239
281
|
:b => a_collection_containing_exactly(
|
240
282
|
a_string_starting_with("f"),
|
241
|
-
an_instance_of(
|
283
|
+
an_instance_of(Integer)
|
242
284
|
),
|
243
285
|
:c => { :d => (a_value < 3) }
|
244
286
|
}
|
@@ -272,7 +314,7 @@ end
|
|
272
314
|
|
273
315
|
## Also see
|
274
316
|
|
275
|
-
* [
|
276
|
-
* [
|
277
|
-
* [
|
278
|
-
* [
|
317
|
+
* [https://github.com/rspec/rspec](https://github.com/rspec/rspec)
|
318
|
+
* [https://github.com/rspec/rspec-core](https://github.com/rspec/rspec-core)
|
319
|
+
* [https://github.com/rspec/rspec-mocks](https://github.com/rspec/rspec-mocks)
|
320
|
+
* [https://github.com/rspec/rspec-rails](https://github.com/rspec/rspec-rails)
|
@@ -0,0 +1,253 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Expectations
|
3
|
+
# @private
|
4
|
+
class BlockSnippetExtractor # rubocop:disable Metrics/ClassLength
|
5
|
+
# rubocop should properly handle `Struct.new {}` as an inner class definition.
|
6
|
+
|
7
|
+
attr_reader :proc, :method_name
|
8
|
+
|
9
|
+
def self.try_extracting_single_line_body_of(proc, method_name)
|
10
|
+
lines = new(proc, method_name).body_content_lines
|
11
|
+
return nil unless lines.count == 1
|
12
|
+
lines.first
|
13
|
+
rescue Error
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(proc, method_name)
|
18
|
+
@proc = proc
|
19
|
+
@method_name = method_name.to_s.freeze
|
20
|
+
end
|
21
|
+
|
22
|
+
# Ideally we should properly handle indentations of multiline snippet,
|
23
|
+
# but it's not implemented yet since because we use result of this method only when it's a
|
24
|
+
# single line and implementing the logic introduces additional complexity.
|
25
|
+
def body_content_lines
|
26
|
+
raw_body_lines.map(&:strip).reject(&:empty?)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def raw_body_lines
|
32
|
+
raw_body_snippet.split("\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
def raw_body_snippet
|
36
|
+
block_token_extractor.body_tokens.map(&:string).join
|
37
|
+
end
|
38
|
+
|
39
|
+
def block_token_extractor
|
40
|
+
@block_token_extractor ||= BlockTokenExtractor.new(method_name, source, beginning_line_number)
|
41
|
+
end
|
42
|
+
|
43
|
+
if RSpec.respond_to?(:world)
|
44
|
+
def source
|
45
|
+
raise TargetNotFoundError unless File.exist?(file_path)
|
46
|
+
RSpec.world.source_from_file(file_path)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
RSpec::Support.require_rspec_support 'source'
|
50
|
+
def source
|
51
|
+
raise TargetNotFoundError unless File.exist?(file_path)
|
52
|
+
@source ||= RSpec::Support::Source.from_file(file_path)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def file_path
|
57
|
+
source_location.first
|
58
|
+
end
|
59
|
+
|
60
|
+
def beginning_line_number
|
61
|
+
source_location.last
|
62
|
+
end
|
63
|
+
|
64
|
+
def source_location
|
65
|
+
proc.source_location || raise(TargetNotFoundError)
|
66
|
+
end
|
67
|
+
|
68
|
+
Error = Class.new(StandardError)
|
69
|
+
TargetNotFoundError = Class.new(Error)
|
70
|
+
AmbiguousTargetError = Class.new(Error)
|
71
|
+
|
72
|
+
# @private
|
73
|
+
# Performs extraction of block body snippet using tokens,
|
74
|
+
# which cannot be done with node information.
|
75
|
+
BlockTokenExtractor = Struct.new(:method_name, :source, :beginning_line_number) do
|
76
|
+
attr_reader :state, :body_tokens
|
77
|
+
|
78
|
+
def initialize(*)
|
79
|
+
super
|
80
|
+
parse!
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def parse!
|
86
|
+
@state = :initial
|
87
|
+
|
88
|
+
catch(:finish) do
|
89
|
+
source.tokens.each do |token|
|
90
|
+
invoke_state_handler(token)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def finish!
|
96
|
+
throw :finish
|
97
|
+
end
|
98
|
+
|
99
|
+
def invoke_state_handler(token)
|
100
|
+
__send__("#{state}_state", token)
|
101
|
+
end
|
102
|
+
|
103
|
+
def initial_state(token)
|
104
|
+
@state = :after_method_call if token.location == block_locator.method_call_location
|
105
|
+
end
|
106
|
+
|
107
|
+
def after_method_call_state(token)
|
108
|
+
@state = :after_opener if handle_opener_token(token)
|
109
|
+
end
|
110
|
+
|
111
|
+
def after_opener_state(token)
|
112
|
+
if handle_closer_token(token)
|
113
|
+
finish_or_find_next_block_if_incorrect!
|
114
|
+
elsif pipe_token?(token)
|
115
|
+
finalize_pending_tokens!
|
116
|
+
@state = :after_beginning_of_args
|
117
|
+
else
|
118
|
+
pending_tokens << token
|
119
|
+
handle_opener_token(token)
|
120
|
+
@state = :after_beginning_of_body unless token.type == :on_sp
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def after_beginning_of_args_state(token)
|
125
|
+
@state = :after_beginning_of_body if pipe_token?(token)
|
126
|
+
end
|
127
|
+
|
128
|
+
def after_beginning_of_body_state(token)
|
129
|
+
if handle_closer_token(token)
|
130
|
+
finish_or_find_next_block_if_incorrect!
|
131
|
+
else
|
132
|
+
pending_tokens << token
|
133
|
+
handle_opener_token(token)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def pending_tokens
|
138
|
+
@pending_tokens ||= []
|
139
|
+
end
|
140
|
+
|
141
|
+
def finalize_pending_tokens!
|
142
|
+
pending_tokens.freeze.tap do
|
143
|
+
@pending_tokens = nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def finish_or_find_next_block_if_incorrect!
|
148
|
+
body_tokens = finalize_pending_tokens!
|
149
|
+
|
150
|
+
if correct_block?(body_tokens)
|
151
|
+
@body_tokens = body_tokens
|
152
|
+
finish!
|
153
|
+
else
|
154
|
+
@state = :after_method_call
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def handle_opener_token(token)
|
159
|
+
opener_token?(token).tap do |boolean|
|
160
|
+
opener_token_stack.push(token) if boolean
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def opener_token?(token)
|
165
|
+
token.type == :on_lbrace || (token.type == :on_kw && token.string == 'do')
|
166
|
+
end
|
167
|
+
|
168
|
+
def handle_closer_token(token)
|
169
|
+
if opener_token_stack.last.closed_by?(token)
|
170
|
+
opener_token_stack.pop
|
171
|
+
opener_token_stack.empty?
|
172
|
+
else
|
173
|
+
false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def opener_token_stack
|
178
|
+
@opener_token_stack ||= []
|
179
|
+
end
|
180
|
+
|
181
|
+
def pipe_token?(token)
|
182
|
+
token.type == :on_op && token.string == '|'
|
183
|
+
end
|
184
|
+
|
185
|
+
def correct_block?(body_tokens)
|
186
|
+
return true if block_locator.body_content_locations.empty?
|
187
|
+
content_location = block_locator.body_content_locations.first
|
188
|
+
content_location.between?(body_tokens.first.location, body_tokens.last.location)
|
189
|
+
end
|
190
|
+
|
191
|
+
def block_locator
|
192
|
+
@block_locator ||= BlockLocator.new(method_name, source, beginning_line_number)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# @private
|
197
|
+
# Locates target block with node information (semantics), which tokens don't have.
|
198
|
+
BlockLocator = Struct.new(:method_name, :source, :beginning_line_number) do
|
199
|
+
def method_call_location
|
200
|
+
@method_call_location ||= method_ident_node.location
|
201
|
+
end
|
202
|
+
|
203
|
+
def body_content_locations
|
204
|
+
@body_content_locations ||= block_body_node.map(&:location).compact
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
def method_ident_node
|
210
|
+
method_call_node = block_wrapper_node.children.first
|
211
|
+
method_call_node.find do |node|
|
212
|
+
method_ident_node?(node)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def block_body_node
|
217
|
+
block_node = block_wrapper_node.children[1]
|
218
|
+
block_node.children.last
|
219
|
+
end
|
220
|
+
|
221
|
+
def block_wrapper_node
|
222
|
+
case candidate_block_wrapper_nodes.size
|
223
|
+
when 1
|
224
|
+
candidate_block_wrapper_nodes.first
|
225
|
+
when 0
|
226
|
+
raise TargetNotFoundError
|
227
|
+
else
|
228
|
+
raise AmbiguousTargetError
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def candidate_block_wrapper_nodes
|
233
|
+
@candidate_block_wrapper_nodes ||= candidate_method_ident_nodes.map do |method_ident_node|
|
234
|
+
block_wrapper_node = method_ident_node.each_ancestor.find { |node| node.type == :method_add_block }
|
235
|
+
next nil unless block_wrapper_node
|
236
|
+
method_call_node = block_wrapper_node.children.first
|
237
|
+
method_call_node.include?(method_ident_node) ? block_wrapper_node : nil
|
238
|
+
end.compact
|
239
|
+
end
|
240
|
+
|
241
|
+
def candidate_method_ident_nodes
|
242
|
+
source.nodes_by_line_number[beginning_line_number].select do |node|
|
243
|
+
method_ident_node?(node)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def method_ident_node?(node)
|
248
|
+
node.type == :@ident && node.args.first == method_name
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
@@ -18,6 +18,19 @@ module RSpec
|
|
18
18
|
#
|
19
19
|
# RSpec::Expectations.configuration
|
20
20
|
class Configuration
|
21
|
+
# @private
|
22
|
+
FALSE_POSITIVE_BEHAVIOURS =
|
23
|
+
{
|
24
|
+
:warn => lambda { |message| RSpec.warning message },
|
25
|
+
:raise => lambda { |message| raise ArgumentError, message },
|
26
|
+
:nothing => lambda { |_| true },
|
27
|
+
}
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@on_potential_false_positives = :warn
|
31
|
+
@strict_predicate_matchers = false
|
32
|
+
end
|
33
|
+
|
21
34
|
# Configures the supported syntax.
|
22
35
|
# @param [Array<Symbol>, Symbol] values the syntaxes to enable
|
23
36
|
# @example
|
@@ -44,6 +57,20 @@ module RSpec
|
|
44
57
|
end
|
45
58
|
end
|
46
59
|
|
60
|
+
# Configures the maximum character length that RSpec will print while
|
61
|
+
# formatting an object. You can set length to nil to prevent RSpec from
|
62
|
+
# doing truncation.
|
63
|
+
# @param [Fixnum] length the number of characters to limit the formatted output to.
|
64
|
+
# @example
|
65
|
+
# RSpec.configure do |rspec|
|
66
|
+
# rspec.expect_with :rspec do |c|
|
67
|
+
# c.max_formatted_output_length = 200
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
def max_formatted_output_length=(length)
|
71
|
+
RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = length
|
72
|
+
end
|
73
|
+
|
47
74
|
# The list of configured syntaxes.
|
48
75
|
# @return [Array<Symbol>] the list of configured syntaxes.
|
49
76
|
# @example
|
@@ -71,7 +98,7 @@ module RSpec
|
|
71
98
|
# Delegates to rspec-core's color option if rspec-core
|
72
99
|
# is loaded; otherwise you can set it here.
|
73
100
|
def color?
|
74
|
-
@color
|
101
|
+
defined?(@color) && @color
|
75
102
|
end
|
76
103
|
end
|
77
104
|
|
@@ -107,6 +134,18 @@ module RSpec
|
|
107
134
|
end
|
108
135
|
end
|
109
136
|
|
137
|
+
# Sets if custom matcher descriptions and failure messages
|
138
|
+
# should include clauses from methods defined using `chain`.
|
139
|
+
# @param value [Boolean]
|
140
|
+
attr_writer :include_chain_clauses_in_custom_matcher_descriptions
|
141
|
+
|
142
|
+
# Indicates whether or not custom matcher descriptions and failure messages
|
143
|
+
# should include clauses from methods defined using `chain`. It is
|
144
|
+
# false by default for backwards compatibility.
|
145
|
+
def include_chain_clauses_in_custom_matcher_descriptions?
|
146
|
+
@include_chain_clauses_in_custom_matcher_descriptions ||= false
|
147
|
+
end
|
148
|
+
|
110
149
|
# @private
|
111
150
|
def reset_syntaxes_to_default
|
112
151
|
self.syntax = [:should, :expect]
|
@@ -121,6 +160,62 @@ module RSpec
|
|
121
160
|
backtrace
|
122
161
|
end
|
123
162
|
end
|
163
|
+
|
164
|
+
# Configures whether RSpec will warn about matcher use which will
|
165
|
+
# potentially cause false positives in tests.
|
166
|
+
#
|
167
|
+
# @param [Boolean] boolean
|
168
|
+
def warn_about_potential_false_positives=(boolean)
|
169
|
+
if boolean
|
170
|
+
self.on_potential_false_positives = :warn
|
171
|
+
elsif warn_about_potential_false_positives?
|
172
|
+
self.on_potential_false_positives = :nothing
|
173
|
+
else
|
174
|
+
# no-op, handler is something else
|
175
|
+
end
|
176
|
+
end
|
177
|
+
#
|
178
|
+
# Configures what RSpec will do about matcher use which will
|
179
|
+
# potentially cause false positives in tests.
|
180
|
+
#
|
181
|
+
# @param [Symbol] behavior can be set to :warn, :raise or :nothing
|
182
|
+
def on_potential_false_positives=(behavior)
|
183
|
+
unless FALSE_POSITIVE_BEHAVIOURS.key?(behavior)
|
184
|
+
raise ArgumentError, "Supported values are: #{FALSE_POSITIVE_BEHAVIOURS.keys}"
|
185
|
+
end
|
186
|
+
@on_potential_false_positives = behavior
|
187
|
+
end
|
188
|
+
|
189
|
+
# Configures RSpec to check predicate matchers to `be(true)` / `be(false)` (strict),
|
190
|
+
# or `be_truthy` / `be_falsey` (not strict).
|
191
|
+
# Historically, the default was `false`, but `true` is recommended.
|
192
|
+
def strict_predicate_matchers=(flag)
|
193
|
+
raise ArgumentError, "Pass `true` or `false`" unless flag == true || flag == false
|
194
|
+
@strict_predicate_matchers = flag
|
195
|
+
end
|
196
|
+
|
197
|
+
attr_reader :strict_predicate_matchers
|
198
|
+
|
199
|
+
def strict_predicate_matchers?
|
200
|
+
@strict_predicate_matchers
|
201
|
+
end
|
202
|
+
|
203
|
+
# Indicates what RSpec will do about matcher use which will
|
204
|
+
# potentially cause false positives in tests, generally you want to
|
205
|
+
# avoid such scenarios so this defaults to `true`.
|
206
|
+
attr_reader :on_potential_false_positives
|
207
|
+
|
208
|
+
# Indicates whether RSpec will warn about matcher use which will
|
209
|
+
# potentially cause false positives in tests, generally you want to
|
210
|
+
# avoid such scenarios so this defaults to `true`.
|
211
|
+
def warn_about_potential_false_positives?
|
212
|
+
on_potential_false_positives == :warn
|
213
|
+
end
|
214
|
+
|
215
|
+
# @private
|
216
|
+
def false_positives_handler
|
217
|
+
FALSE_POSITIVE_BEHAVIOURS.fetch(@on_potential_false_positives)
|
218
|
+
end
|
124
219
|
end
|
125
220
|
|
126
221
|
# The configuration object.
|