Skip to content

Commit

Permalink
contain_exactly should work with sets and other collections, too.
Browse files Browse the repository at this point in the history
  • Loading branch information
myronmarston committed Dec 31, 2013
1 parent d6cada7 commit ec93540
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 15 deletions.
2 changes: 2 additions & 0 deletions Changelog.md
Expand Up @@ -22,6 +22,8 @@ Enhancements:
Note that it expects the expected array to be splatted as
individual args: `expect(array).to contain_exactly(1, 2)` is
the same as `expect(array).to match_array([1, 2])`. (Myron Marston)
* Update `contain_exactly`/`match_array` so that it can match against
other non-array collections (such as a `Set`). (Myron Marston)
* Update built-in matchers so that they can accept matchers as arguments
to allow you to compose matchers in arbitrary ways. (Myron Marston)
* Add `RSpec::Matchers::Composable` mixin that can be used to make
Expand Down
16 changes: 10 additions & 6 deletions lib/rspec/matchers/built_in/contain_exactly.rb
Expand Up @@ -3,21 +3,21 @@ module Matchers
module BuiltIn
class ContainExactly < BaseMatcher
def match(expected, actual)
return false unless actual.respond_to? :to_ary
return false unless actual_is_a_collection?
@actual = actual.to_a
extra_items.empty? && missing_items.empty?
end

def failure_message
if actual.respond_to? :to_ary
message = "expected collection contained: #{safe_sort(surface_descriptions_in expected).inspect}\n"
if actual_is_a_collection?
message = "expected collection contained: #{safe_sort(surface_descriptions_in expected).inspect}\n"
message += "actual collection contained: #{safe_sort(actual).inspect}\n"
message += "the missing elements were: #{safe_sort(surface_descriptions_in missing_items).inspect}\n" unless missing_items.empty?
message += "the extra elements were: #{safe_sort(extra_items).inspect}\n" unless extra_items.empty?
message
else
message = "expected an array, actual collection was #{actual.inspect}"
"expected a collection that can be converted to an array with `#to_a`, but got #{actual.inspect}"
end

message
end

def failure_message_when_negated
Expand All @@ -30,6 +30,10 @@ def description

private

def actual_is_a_collection?
enumerable?(actual) && actual.respond_to?(:to_a)
end

def safe_sort(array)
array.sort rescue array
end
Expand Down
17 changes: 8 additions & 9 deletions spec/rspec/matchers/built_in/contain_exactly_spec.rb
Expand Up @@ -189,27 +189,26 @@ def timeout_if_not_debugging(time)
it "fails with nil and the expected error message is given" do
expect {
expect(nil).to contain_exactly(1, 2, 3)
}.to fail_with(/expected an array/)
}.to fail_with(/expected a collection/)
end

it "fails with a float and the expected error message is given" do
expect {
expect(3.7).to contain_exactly(1, 2, 3)
}.to fail_with(/expected an array/)
}.to fail_with(/expected a collection/)
end

it "fails with a string and the expected error message is given" do
expect {
expect("I like turtles").to contain_exactly(1, 2, 3)
}.to fail_with(/expected an array/)
}.to fail_with(/expected a collection/)
end

context "when using the `should =~` syntax", :uses_should do
it 'fails with a clear message when given a hash' do
expect {
{}.should =~ {}
}.to fail_with(/expected an array/)
end
it 'works with other collection types' do
expect(Set.new([3, 2, 1])).to contain_exactly(1, 2, 3)
expect {
expect(Set.new([3, 2, 1])).to contain_exactly(1, 2)
}.to fail_matching("expected collection contained: [1, 2]")
end
end

Expand Down

0 comments on commit ec93540

Please sign in to comment.