Skip to content
Browse files

Dup arrays and hashes in change matcher.

This fixes a bug in which expecting the contents of an array or hash to
change due to some action would fail (false negative) because the before
and after values were actually the same object.

- Closes #41
  • Loading branch information...
1 parent 9e3eeac commit ae1c3f8c3803c7a3fe87c2f9c3d01e561fbe3644 @dchelimsky dchelimsky committed
Showing with 60 additions and 2 deletions.
  1. +2 −0 features/Changelog.md
  2. +6 −1 lib/rspec/matchers/change.rb
  3. +52 −1 spec/rspec/matchers/change_spec.rb
View
2 features/Changelog.md
@@ -8,6 +8,8 @@
* Bug fixes
* Removed non-ascii characters that were choking rcov (Geoffrey Byers)
+ * change matcher dups arrays and hashes so their before/after states can be
+ compared correctly.
### 2.5.0 / 2011-02-05
View
7 lib/rspec/matchers/change.rb
@@ -26,7 +26,12 @@ def raise_block_syntax_error
end
def evaluate_value_proc
- @value_proc.call
+ case val = @value_proc.call
+ when Array, Hash
+ val.dup
+ else
+ val
+ end
end
def failure_message_for_should
View
53 spec/rspec/matchers/change_spec.rb
@@ -14,7 +14,7 @@ class SomethingExpected
end
it "passes when actual is modified by the block" do
- expect {@instance.some_value = 6}.to change(@instance, :some_value)
+ expect {@instance.some_value = 6.0}.to change(@instance, :some_value)
end
it "fails when actual is not modified by the block" do
@@ -44,6 +44,57 @@ class SomethingExpected
end.to fail_with("some_value should have changed, but is still true")
end
end
+
+ context "with nil value" do
+ before(:each) do
+ @instance = SomethingExpected.new
+ @instance.some_value = nil
+ end
+
+ it "passes when actual is modified by the block" do
+ expect {@instance.some_value = false}.to change(@instance, :some_value)
+ end
+
+ it "fails when actual is not modified by the block" do
+ expect do
+ expect {}.to change(@instance, :some_value)
+ end.to fail_with("some_value should have changed, but is still nil")
+ end
+ end
+
+ context "with an array" do
+ before(:each) do
+ @instance = SomethingExpected.new
+ @instance.some_value = []
+ end
+
+ it "passes when actual is modified by the block" do
+ expect {@instance.some_value << 1}.to change(@instance, :some_value)
+ end
+
+ it "fails when actual is not modified by the block" do
+ expect do
+ expect {}.to change(@instance, :some_value)
+ end.to fail_with("some_value should have changed, but is still []")
+ end
+ end
+
+ context "with a hash" do
+ before(:each) do
+ @instance = SomethingExpected.new
+ @instance.some_value = {:a => 'a'}
+ end
+
+ it "passes when actual is modified by the block" do
+ expect {@instance.some_value[:a] = 'A'}.to change(@instance, :some_value)
+ end
+
+ it "fails when actual is not modified by the block" do
+ expect do
+ expect {}.to change(@instance, :some_value)
+ end.to fail
+ end
+ end
end
describe "should_not change(actual, message)" do

0 comments on commit ae1c3f8

Please sign in to comment.
Something went wrong with that request. Please try again.