Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions features/built_in_matchers/predicates.feature
Original file line number Diff line number Diff line change
Expand Up @@ -88,32 +88,33 @@ Feature: Predicate matchers
"""
When I run `rspec should_have_key_spec.rb`
Then the output should contain "2 examples, 1 failure"
And the output should contain "expected #has_key?(:bar) to return true, got false"
And the output should contain "expected `{:foo=>7}.has_key?(:bar)` to return true, got false"

Scenario: should_not have_all_string_keys (based on custom #has_all_string_keys? method)
Given a file named "should_not_have_all_string_keys_spec.rb" with:
"""ruby
class Hash
def has_all_string_keys?
keys.all? { |k| String === k }
class Float
def has_decimals?
round != self
end
end

RSpec.describe Hash do
context 'with symbol keys' do
subject { { :foo => 7, :bar => 5 } }
it { is_expected.not_to have_all_string_keys }
RSpec.describe Float do
context 'with decimals' do
subject { 4.2 }

it { is_expected.to have_decimals }
end

context 'with string keys' do
subject { { 'foo' => 7, 'bar' => 5 } }
it { is_expected.not_to have_all_string_keys } # deliberate failure
context 'with no decimals' do
subject { 42.0 }
it { is_expected.to have_decimals } # deliberate failure
end
end
"""
When I run `rspec should_not_have_all_string_keys_spec.rb`
Then the output should contain "2 examples, 1 failure"
And the output should contain "expected #has_all_string_keys? to return false, got true"
And the output should contain "expected `42.0.has_decimals?` to return true, got false"

Scenario: matcher arguments are passed on to the predicate method
Given a file named "predicate_matcher_argument_spec.rb" with:
Expand Down
30 changes: 0 additions & 30 deletions lib/rspec/matchers/built_in/has.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,37 +130,7 @@ def failure_to_respond_explanation
class Has < DynamicPredicate
# :nodoc:
REGEX = Matchers::HAS_REGEX

# @api private
# @return [String]
def failure_message
validity_message || "expected ##{predicate}#{failure_message_args_description} to return true, got false"
end

# @api private
# @return [String]
def failure_message_when_negated
validity_message || "expected ##{predicate}#{failure_message_args_description} to return false, got true"
end

# @api private
# @return [String]
def description
[method_description, args_description].compact.join(' ')
end

private

def args_description
return nil if @args.empty?
@args.map { |arg| RSpec::Support::ObjectFormatter.format(arg) }.join(', ')
end

def failure_message_args_description
desc = args_description
"(#{desc})" if desc
end

def predicate
@predicate ||= :"has_#{root}?"
end
Expand Down
14 changes: 7 additions & 7 deletions spec/rspec/matchers/built_in/has_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
it "fails if #has_sym?(*args) returns false" do
expect {
expect({ :b => "B" }).to have_key(:a)
}.to fail_with("expected #has_key?(:a) to return true, got false")
}.to fail_with('expected `{:b=>"B"}.has_key?(:a)` to return true, got false')
end

obj_with_block_method = Object.new
Expand Down Expand Up @@ -65,15 +65,15 @@ def obj_with_block_method.has_some_stuff?; yield; end
def o.has_some_stuff?; false; end
expect {
expect(o).to have_some_stuff
}.to fail_with("expected #has_some_stuff? to return true, got false")
}.to fail_with("expected `#{o.inspect}.has_some_stuff?` to return true, got false")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit out of context. Where does the inspect part come from? I would expect the message to be "expected o.has_some_stuff? to return true, got false". Is that something you were referring to in "produce a better output"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its because actual e.g o is being printed by the matcher

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. I didn't parse it at first.

end

it 'includes multiple args in the failure message if multiple args were given to the matcher' do
o = Object.new
def o.has_some_stuff?(*_); false; end
expect {
expect(o).to have_some_stuff(:a, 7, "foo")
}.to fail_with('expected #has_some_stuff?(:a, 7, "foo") to return true, got false')
}.to fail_with(%Q{expected `#{o.inspect}.has_some_stuff?(:a, 7, "foo")` to return true, got false})
end

it "fails if #has_sym?(*args) returns nil" do
Expand All @@ -83,7 +83,7 @@ def has_foo?
end
expect {
expect(klass.new).to have_foo
}.to fail_with(/expected #has_foo.* to return true, got false/)
}.to fail_with(/expected `.*\.has_foo\?` to return true, got nil/)
end

it 'fails if #has_sym?(*args) is private' do
Expand Down Expand Up @@ -150,7 +150,7 @@ def has_foo?
it "fails if #has_sym?(*args) returns true" do
expect {
expect({ :a => "A" }).not_to have_key(:a)
}.to fail_with("expected #has_key?(:a) to return false, got true")
}.to fail_with('expected `{:a=>"A"}.has_key?(:a)` to return false, got true')
end

it "fails if target does not respond to #has_sym?" do
Expand All @@ -174,15 +174,15 @@ def o.has_sym?(*_args)
def o.has_some_stuff?; true; end
expect {
expect(o).not_to have_some_stuff
}.to fail_with("expected #has_some_stuff? to return false, got true")
}.to fail_with("expected `#{o.inspect}.has_some_stuff?` to return false, got true")
end

it 'includes multiple args in the failure message if multiple args were given to the matcher' do
o = Object.new
def o.has_some_stuff?(*_); true; end
expect {
expect(o).not_to have_some_stuff(:a, 7, "foo")
}.to fail_with('expected #has_some_stuff?(:a, 7, "foo") to return false, got true')
}.to fail_with(%Q{expected `#{o.inspect}.has_some_stuff?(:a, 7, "foo")` to return false, got true})
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/rspec/matchers/description_generation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def object.has_eyes_closed?; true; end
def object.has_taste_for?(*_args); true; end

expect(object).to have_taste_for("wine", "cheese")
expect(RSpec::Matchers.generated_description).to eq 'is expected to have taste for "wine", "cheese"'
expect(RSpec::Matchers.generated_description).to eq 'is expected to have taste for "wine" and "cheese"'
end

example "expect(...).to include(x)" do
Expand Down