Created
June 6, 2012 19:01
-
-
Save bakineggs/2883923 to your computer and use it in GitHub Desktop.
matchers for testing that one hash/array is contained in another
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# contain_array checks to see if one array contains all of the elements from another array in the same relative order | |
# | |
# Any elements that are hashes are matched using contain_hash | |
# Any elements that are arrays are matched using contain_array | |
# | |
# Examples: | |
# | |
# describe 'something' do | |
# subject do | |
# [:a, {:b => [:c, :d, :e]}] | |
# end | |
# | |
# it { should contain_array [:a] } # pass | |
# it { should contain_array [:b] } # fail | |
# it { should contain_array [{:b => [:c]}] } # pass | |
# it { should contain_array [{:b => [:f]}] } # fail | |
# it { should contain_array [{:b => [:c, :e]}] } # pass | |
# it { should contain_array [{:b => [:e, :c]}] } # fail | |
# it { should contain_array } # pass | |
# end | |
require 'contains_hash' | |
class ContainsArray | |
def initialize expected_contents | |
@expected_contents = expected_contents | |
end | |
def matches? actual_array | |
@actual_array = actual_array | |
return false unless @expected_contents.is_a?(Array) && actual_array.is_a?(Array) | |
return false if @expected_contents.length > actual_array.length | |
index = 0 | |
@expected_contents.each do |value| | |
index += 1 while index < actual_array.length && !element_matches?(value, actual_array[index]) | |
return false if index == actual_array.length | |
end | |
true | |
end | |
def failure_message_for_should | |
"Expected to contain array, but did not.\n#{common_failure_message}" | |
end | |
def failure_message_for_should_not | |
"Expected not to contain array, but did.\n#{common_failure_message}" | |
end | |
def description | |
"contain array #{@expected_contents.inspect}" | |
end | |
private | |
def element_matches? expected, actual | |
if expected.is_a? Hash | |
ContainsHash.new(expected).matches? actual | |
elsif expected.is_a? Array | |
ContainsArray.new(expected).matches? actual | |
else | |
expected == actual | |
end | |
end | |
def common_failure_message | |
"Actual Array: #{@actual_array.inspect}\nExpected Contents: #{@expected_contents.inspect}" | |
end | |
end | |
def contain_array expected_contents = [] | |
ContainsArray.new expected_contents | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'contains_array' | |
describe ContainsArray do | |
let(:matcher) { ContainsArray.new expected_contents } | |
describe '#matches?' do | |
let(:actual_array) { [:a, {:b => [:c, :d, :e], :f => :g}] } | |
subject { matcher.matches? actual_array } | |
context 'when the expected contents are empty' do | |
let(:expected_contents) { [] } | |
it { should be_true } | |
end | |
context 'when all elements are in the array' do | |
let(:expected_contents) { [:a] } | |
it { should be_true } | |
end | |
context 'when no elements are in the array' do | |
let(:expected_contents) { [:b] } | |
it { should be_false } | |
end | |
context 'when not all elements are in the array' do | |
let(:expected_contents) { [:a, :b] } | |
it { should be_false } | |
end | |
context 'when a hash element partially matches' do | |
let(:expected_contents) { [{:f => :g}] } | |
it { should be_true } | |
end | |
context 'when elements match in order' do | |
let(:expected_contents) { [:a, {:f => :g}] } | |
it { should be_true } | |
end | |
context 'when elements match out of order' do | |
let(:expected_contents) { [{:f => :g}, :a] } | |
it { should be_false } | |
end | |
context 'when a hash element contains an array that partially matches in order' do | |
let(:expected_contents) { [{:b => [:d, :e]}] } | |
it { should be_true } | |
end | |
context 'when a hash element contains an array that partially matches out of order' do | |
let(:expected_contents) { [{:b => [:e, :d]}] } | |
it { should be_false } | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# contain_hash checks to see if one hash contains all of the keys and values from another hash | |
# | |
# Any values that are hashes are matched using contain_hash | |
# Any values that are arrays are matched using contain_array | |
# | |
# Examples: | |
# | |
# describe 'something' do | |
# subject do | |
# {:a => :b, :c => [:d, :e, :f]} | |
# end | |
# | |
# it { should contain_hash(:a => :b) } # pass | |
# it { should contain_hash(:a => :c) } # fails | |
# it { should contain_hash(:a => :b, :c => [:e]) } # pass | |
# it { should contain_hash(:a => :b, :c => [:g]) } # fail | |
# it { should contain_hash(:a => :b, :c => [:d, :f]) } # pass | |
# it { should contain_hash(:a => :b, :c => [:f, :d]) } # fail | |
# it { should contain_hash } # pass | |
# end | |
require 'contains_array' | |
class ContainsHash | |
def initialize expected_contents | |
@expected_contents = expected_contents | |
end | |
def matches? actual_hash | |
@actual_hash = actual_hash | |
return false unless @expected_contents.is_a?(Hash) && actual_hash.is_a?(Hash) | |
return false unless (@expected_contents.keys - actual_hash.keys).empty? | |
@expected_contents.each do |key, value| | |
actual_value = actual_hash[key] | |
if value.is_a? Hash | |
return false unless ContainsHash.new(value).matches? actual_value | |
elsif value.is_a? Array | |
return false unless ContainsArray.new(value).matches? actual_value | |
else | |
return false unless value == actual_value | |
end | |
end | |
true | |
end | |
def failure_message_for_should | |
"Expected to contain hash, but did not.\n#{common_failure_message}" | |
end | |
def failure_message_for_should_not | |
"Expected not to contain hash, but did.\n#{common_failure_message}" | |
end | |
def description | |
"contain hash #{@expected_contents.inspect}" | |
end | |
private | |
def common_failure_message | |
"Actual Hash: #{@actual_hash.inspect}\nExpected Contents: #{@expected_contents.inspect}" | |
end | |
end | |
def contain_hash expected_contents = {} | |
ContainsHash.new expected_contents | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'contains_hash' | |
describe ContainsHash do | |
let(:matcher) { ContainsHash.new expected_contents } | |
describe '#matches?' do | |
let(:actual_hash) { {:a => :b, :c => [:d, :e, :f, {:g => :h, :i => :j}]} } | |
subject { matcher.matches? actual_hash } | |
context 'when the expected contents are empty' do | |
let(:expected_contents) { {} } | |
it { should be_true } | |
end | |
context 'when all keys and values are in the hash' do | |
let(:expected_contents) { {:a => :b} } | |
it { should be_true } | |
end | |
context 'when a key has a different value in the hash' do | |
let(:expected_contents) { {:a => :c} } | |
it { should be_false } | |
end | |
context 'when a key with an array value has a match in order' do | |
let(:expected_contents) { {:a => :b, :c => [:d, :f]} } | |
it { should be_true } | |
end | |
context 'when a key with an array value has a match out of order' do | |
let(:expected_contents) { {:a => :b, :c => [:f, :d]} } | |
it { should be_false } | |
end | |
context 'when a key with an array value contains a hash that partially matches' do | |
let(:expected_contents) { {:a => :b, :c => [{:g => :h}]} } | |
it { should be_true } | |
end | |
context 'when a key with an array value contains a hash that does not match' do | |
let(:expected_contents) { {:a => :b, :c => [{:g => :k}]} } | |
it { should be_false } | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment