Permalink
Browse files

Add `contain_exactly` as an alternate version of `match_array`.

Fixes #398.
  • Loading branch information...
myronmarston committed Dec 24, 2013
1 parent 96caa7e commit 6bde36e7b4ec67fcdd239cf498bebf07f661e561
View
@@ -18,6 +18,10 @@ Enhancements:
Simply chain them off of any existing matcher to create an expression
like `expect(alphabet).to start_with("a").and end_with("z")`.
(Eloy Espinaco)
+* Add `contain_exactly` as a less ambiguous version of `match_array`.
+ 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)
Breaking Changes for 3.0.0:
View
@@ -71,7 +71,6 @@ expect(actual).to be >= expected
expect(actual).to be <= expected
expect(actual).to be < expected
expect(actual).to be_within(delta).of(expected)
-expect(array).to match_array(expected)
```
### Regular expressions
@@ -152,21 +151,27 @@ expect(1..10).to cover(3)
expect(actual).to include(expected)
expect(actual).to start_with(expected)
expect(actual).to end_with(expected)
+
+expect(actual).to contain_exactly(individual, items)
+# ...which is the same as:
+expect(actual).to match_array(expected_array)
```
#### Examples
```ruby
-expect([1,2,3]).to include(1)
-expect([1,2,3]).to include(1, 2)
-expect([1,2,3]).to start_with(1)
-expect([1,2,3]).to start_with(1,2)
-expect([1,2,3]).to end_with(3)
-expect([1,2,3]).to end_with(2,3)
+expect([1, 2, 3]).to include(1)
+expect([1, 2, 3]).to include(1, 2)
+expect([1, 2, 3]).to start_with(1)
+expect([1, 2, 3]).to start_with(1, 2)
+expect([1, 2, 3]).to end_with(3)
+expect([1, 2, 3]).to end_with(2, 3)
expect({:a => 'b'}).to include(:a => 'b')
expect("this string").to include("is str")
expect("this string").to start_with("this")
expect("this string").to end_with("ring")
+expect([1, 2, 3]).to contain_exactly(2, 3, 1)
+expect([1, 2, 3]).to match_array([3, 2, 1])
```
## `should` syntax
@@ -77,16 +77,18 @@ e.g.
## Collection membership
expect(actual).to include(expected)
- expect(array).to match_array(expected)
+ expect(array).to match_array(expected_array)
+ # ...which is the same as:
+ expect(array).to contain_exactly(individual, elements)
### Examples
- expect([1,2,3]).to include(1)
- expect([1,2,3]).to include(1, 2)
+ expect([1, 2, 3]).to include(1)
+ expect([1, 2, 3]).to include(1, 2)
expect(:a => 'b').to include(:a => 'b')
expect("this string").to include("is str")
- expect([1,2,3]).to match_array([1,2,3])
- expect([1,2,3]).to match_array([3,2,1])
+ expect([1, 2, 3]).to contain_exactly(2, 1, 3)
+ expect([1, 2, 3]).to match_array([3, 2, 1])
## Ranges (1.9 only)
@@ -0,0 +1,46 @@
+Feature: contain_exactly matcher
+
+ The `contain_exactly` matcher provides a way to test arrays against each other
+ in a way that disregards differences in the ordering between the actual
+ and expected array. For example:
+
+ ```ruby
+ expect([1, 2, 3]).to contain_exactly(2, 3, 1) # pass
+ expect([:a, :c, :b]).to contain_exactly(:a, :c ) # fail
+ ```
+
+ This matcher is also available as `match_array`, which expects the
+ expected array to be given as a single array argument rather than
+ as individual splatted elements. The above could also be written as:
+
+ ```ruby
+ expect([1, 2, 3]).to match_array [2, 3, 1] # pass
+ expect([:a, :c, :b]).to match_array [:a, :c] # fail
+ ```
+
+ Scenario: array operator matchers
+ Given a file named "contain_exactly_matcher_spec.rb" with:
+ """ruby
+ describe do
+ example { expect([1, 2, 3]).to contain_exactly(1, 2, 3) }
+ example { expect([1, 2, 3]).to contain_exactly(1, 3, 2) }
+ example { expect([1, 2, 3]).to contain_exactly(2, 1, 3) }
+ example { expect([1, 2, 3]).to contain_exactly(2, 3, 1) }
+ example { expect([1, 2, 3]).to contain_exactly(3, 1, 2) }
+ example { expect([1, 2, 3]).to contain_exactly(3, 2, 1) }
+
+ # deliberate failures
+ example { expect([1, 2, 3]).to contain_exactly(1, 2, 1) }
+ end
+ """
+ When I run `rspec contain_exactly_matcher_spec.rb`
+ Then the output should contain "7 examples, 1 failure"
+ And the output should contain:
+ """
+ Failure/Error: example { expect([1, 2, 3]).to contain_exactly(1, 2, 1) }
+ expected collection contained: [1, 1, 2]
+ actual collection contained: [1, 2, 3]
+ the missing elements were: [1]
+ the extra elements were: [3]
+ """
+
@@ -1,37 +0,0 @@
-Feature: match_array matcher
-
- The `match_array` matcher provides a way to test arrays against each other
- in a way that disregards differences in the ordering between the actual
- and expected array. For example:
-
- ```ruby
- expect([1, 2, 3]).to match_array [2, 3, 1] # pass
- expect([:a, :c, :b]).to match_array [:a, :c] # fail
- ```
-
- Scenario: array operator matchers
- Given a file named "array_operator_matchers_spec.rb" with:
- """ruby
- describe do
- example { expect([1, 2, 3]).to match_array [1, 2, 3] }
- example { expect([1, 2, 3]).to match_array [1, 3, 2] }
- example { expect([1, 2, 3]).to match_array [2, 1, 3] }
- example { expect([1, 2, 3]).to match_array [2, 3, 1] }
- example { expect([1, 2, 3]).to match_array [3, 1, 2] }
- example { expect([1, 2, 3]).to match_array [3, 2, 1] }
-
- # deliberate failures
- example { expect([1, 2, 3]).to match_array [1, 2, 1] }
- end
- """
- When I run `rspec array_operator_matchers_spec.rb`
- Then the output should contain "7 examples, 1 failure"
- And the output should contain:
- """
- Failure/Error: example { expect([1, 2, 3]).to match_array [1, 2, 1] }
- expected collection contained: [1, 1, 2]
- actual collection contained: [1, 2, 3]
- the missing elements were: [1]
- the extra elements were: [3]
- """
-
View
@@ -343,6 +343,28 @@ def change(receiver=nil, message=nil, &block)
alias_matcher :a_lambda_changing, :change
alias_matcher :a_proc_changing, :change
+ # Passes if actual contains all of the expected regardless of order.
+ # This works for collections. Pass in multiple args and it will only
+ # pass if all args are found in collection.
+ #
+ # @note This is also available using the `=~` operator with `should`,
+ # but `=~` is not supported with `expect`.
+ #
+ # @note This matcher only supports positive expectations.
+ # `expect(...).not_to contain_exactly(other_array)` is not supported.
+ #
+ # @example
+ #
+ # expect([1, 2, 3]).to contain_exactly(1, 2, 3)
+ # expect([1, 2, 3]).to contain_exactly(1, 3, 2)
+ #
+ # @see #match_array
+ def contain_exactly(*items)
+ BuiltIn::ContainExactly.new(items)
+ end
+ alias_matcher :a_collection_containing_exactly, :contain_exactly
+ alias_matcher :an_array_containing_exactly, :contain_exactly
+
# Passes if actual covers expected. This works for
# Ranges. You can also pass in multiple args
# and it will only pass if all args are found in Range.
@@ -468,28 +490,19 @@ def match(expected)
alias_matcher :an_object_matching, :match
alias_matcher :a_string_matching, :match
- # Passes if actual contains all of the expected regardless of order.
- # This works for collections. Pass in multiple args and it will only
- # pass if all args are found in collection.
- #
- # @note This is also available using the `=~` operator with `should`,
- # but `=~` is not supported with `expect`.
- #
- # @note This matcher only supports positive expectations.
- # expect(..).not_to match_array(other_array) is not supported.
+ # An alternate form of `contain_exactly` that accepts
+ # the expected contents as a single array arg rather
+ # that splatted out as individual items.
#
# @example
#
- # expect([1,2,3]).to match_array([1,2,3])
- # expect([1,2,3]).to match_array([1,3,2])
- def match_array(array)
- BuiltIn::MatchArray.new(array)
- end
- alias_matcher :an_array_matching, :match_array do |desc|
- desc.sub("contain", "an array containing")
- end
- alias_matcher :a_collection_matching, :match_array do |desc|
- desc.sub("contain", "a collection containing")
+ # expect(results).to contain_exactly(1, 2)
+ # # is identical to:
+ # expect(results).to match_array([1, 2])
+ #
+ # @see #contain_exactly
+ def match_array(items)
+ contain_exactly(*items)
end
# With no args, matches if any error is raised.
@@ -14,6 +14,7 @@ module BuiltIn
autoload :BeWithin, 'rspec/matchers/built_in/be_within'
autoload :Change, 'rspec/matchers/built_in/change'
autoload :Compound, 'rspec/matchers/built_in/compound'
+ autoload :ContainExactly, 'rspec/matchers/built_in/contain_exactly'
autoload :Cover, 'rspec/matchers/built_in/cover'
autoload :EndWith, 'rspec/matchers/built_in/start_and_end_with'
autoload :Eq, 'rspec/matchers/built_in/eq'
@@ -23,7 +24,6 @@ module BuiltIn
autoload :Has, 'rspec/matchers/built_in/has'
autoload :Include, 'rspec/matchers/built_in/include'
autoload :Match, 'rspec/matchers/built_in/match'
- autoload :MatchArray, 'rspec/matchers/built_in/match_array'
autoload :NegativeOperatorMatcher, 'rspec/matchers/built_in/operators'
autoload :OperatorMatcher, 'rspec/matchers/built_in/operators'
autoload :PositiveOperatorMatcher, 'rspec/matchers/built_in/operators'
@@ -1,7 +1,7 @@
module RSpec
module Matchers
module BuiltIn
- class MatchArray < BaseMatcher
+ class ContainExactly < BaseMatcher
def match(expected, actual)
return false unless actual.respond_to? :to_ary
@@ -30,7 +30,7 @@ def failure_message
end
def failure_message_when_negated
- "`match_array` does not support negation"
+ "`contain_exactly` does not support negation"
end
def description
@@ -26,7 +26,7 @@ def get(klass, operator)
end
end
- register Enumerable, '=~', BuiltIn::MatchArray
+ register Enumerable, '=~', BuiltIn::ContainExactly
def initialize(actual)
@actual = actual
@@ -100,6 +100,22 @@ module RSpec
expect(a_lambda_changing).to be_aliased_to(change).with_description("a lambda changing result")
end
+ specify do
+ expect(
+ an_array_containing_exactly(1, 2)
+ ).to be_aliased_to(
+ contain_exactly(1, 2)
+ ).with_description("an array containing exactly 1 and 2")
+ end
+
+ specify do
+ expect(
+ a_collection_containing_exactly(1, 2)
+ ).to be_aliased_to(
+ contain_exactly(1, 2)
+ ).with_description("a collection containing exactly 1 and 2")
+ end
+
specify do
expect(
a_range_covering(1, 2)
@@ -222,22 +238,6 @@ module RSpec
).with_description('match regex /foo/')
end
- specify do
- expect(
- an_array_matching([1, 2])
- ).to be_aliased_to(
- match_array([1, 2])
- ).with_description("an array containing exactly 1 and 2")
- end
-
- specify do
- expect(
- a_collection_matching([1, 2])
- ).to be_aliased_to(
- match_array([1, 2])
- ).with_description("a collection containing exactly 1 and 2")
- end
-
specify do
expect(
a_block_raising(ArgumentError)
Oops, something went wrong.

0 comments on commit 6bde36e

Please sign in to comment.