Skip to content

Commit

Permalink
Updated should_change and should_not_change to accept a string descri…
Browse files Browse the repository at this point in the history
…ption and a block [#154]
  • Loading branch information
matflores authored and jferris committed Jun 9, 2009
1 parent 40568e7 commit 4e4317f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 34 deletions.
48 changes: 25 additions & 23 deletions lib/shoulda/macros.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3,65 +3,67 @@
module Shoulda # :nodoc: module Shoulda # :nodoc:
module Macros module Macros
# Macro that creates a test asserting a change between the return value # Macro that creates a test asserting a change between the return value
# of an expression that is run before and after the current setup block # of a block that is run before and after the current setup block
# is run. This is similar to Active Support's <tt>assert_difference</tt> # is run. This is similar to Active Support's <tt>assert_difference</tt>
# assertion, but supports more than just numeric values. See also # assertion, but supports more than just numeric values. See also
# should_not_change. # should_not_change.
# #
# The passed description will be used when generating the test name and failure messages.
#
# Example: # Example:
# #
# context "Creating a post" do # context "Creating a post" do
# setup { Post.create } # setup { Post.create }
# should_change "Post.count", :by => 1 # should_change("the number of posts", :by => 1) { Post.count }
# end # end
# #
# As shown in this example, the <tt>:by</tt> option expects a numeric # As shown in this example, the <tt>:by</tt> option expects a numeric
# difference between the before and after values of the expression. You # difference between the before and after values of the expression. You
# may also specify <tt>:from</tt> and <tt>:to</tt> options: # may also specify <tt>:from</tt> and <tt>:to</tt> options:
# #
# should_change "Post.count", :from => 0, :to => 1 # should_change("the number of posts", :from => 0, :to => 1) { Post.count }
# should_change "@post.title", :from => "old", :to => "new" # should_change("the post title", :from => "old", :to => "new") { @post.title }
# #
# Combinations of <tt>:by</tt>, <tt>:from</tt>, and <tt>:to</tt> are allowed: # Combinations of <tt>:by</tt>, <tt>:from</tt>, and <tt>:to</tt> are allowed:
# #
# should_change "@post.title" # => assert the value changed in some way # should_change("the post title") { @post.title } # => assert the value changed in some way
# should_change "@post.title", :from => "old" # => assert the value changed to anything other than "old" # should_change("the post title", :from => "old") { @post.title } # => assert the value changed to anything other than "old"
# should_change "@post.title", :to => "new" # => assert the value changed from anything other than "new" # should_change("the post title", :to => "new") { @post.title } # => assert the value changed from anything other than "new"
def should_change(expression, options = {}) def should_change(description, options = {}, &block)
by, from, to = get_options!([options], :by, :from, :to) by, from, to = get_options!([options], :by, :from, :to)
stmt = "change #{expression.inspect}" stmt = "change #{description}"
stmt << " from #{from.inspect}" if from stmt << " from #{from.inspect}" if from
stmt << " to #{to.inspect}" if to stmt << " to #{to.inspect}" if to
stmt << " by #{by.inspect}" if by stmt << " by #{by.inspect}" if by


expression_eval = lambda { eval(expression) } before = lambda { @_before_should_change = block.bind(self).call }
before = lambda { @_before_should_change = expression_eval.bind(self).call }
should stmt, :before => before do should stmt, :before => before do
old_value = @_before_should_change old_value = @_before_should_change
new_value = expression_eval.bind(self).call new_value = block.bind(self).call
assert_operator from, :===, old_value, "#{expression.inspect} did not originally match #{from.inspect}" if from assert_operator from, :===, old_value, "#{description} did not originally match #{from.inspect}" if from
assert_not_equal old_value, new_value, "#{expression.inspect} did not change" unless by == 0 assert_not_equal old_value, new_value, "#{description} did not change" unless by == 0
assert_operator to, :===, new_value, "#{expression.inspect} was not changed to match #{to.inspect}" if to assert_operator to, :===, new_value, "#{description} was not changed to match #{to.inspect}" if to
assert_equal old_value + by, new_value if by assert_equal old_value + by, new_value if by
end end
end end


# Macro that creates a test asserting no change between the return value # Macro that creates a test asserting no change between the return value
# of an expression that is run before and after the current setup block # of a block that is run before and after the current setup block
# is run. This is the logical opposite of should_change. # is run. This is the logical opposite of should_change.
# #
# The passed description will be used when generating the test name and failure message.
#
# Example: # Example:
# #
# context "Updating a post" do # context "Updating a post" do
# setup { @post.update_attributes(:title => "new") } # setup { @post.update_attributes(:title => "new") }
# should_not_change "Post.count" # should_not_change("the number of posts") { Post.count }
# end # end
def should_not_change(expression) def should_not_change(description, &block)
expression_eval = lambda { eval(expression) } before = lambda { @_before_should_not_change = block.bind(self).call }
before = lambda { @_before_should_not_change = expression_eval.bind(self).call } should "not change #{description}", :before => before do
should "not change #{expression.inspect}", :before => before do new_value = block.bind(self).call
new_value = expression_eval.bind(self).call assert_equal @_before_should_not_change, new_value, "#{description} changed"
assert_equal @_before_should_not_change, new_value, "#{expression.inspect} changed"
end end
end end


Expand Down
22 changes: 11 additions & 11 deletions test/other/helpers_test.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -88,24 +88,24 @@ class HelpersTest < ActiveSupport::TestCase # :nodoc:
@a.push(4) @a.push(4)
end end


should_change "@a.length", :by => 1 should_change("the number of elements", :by => 1) { @a.length }
should_change "@a.length", :from => 3 should_change("the number of elements", :from => 3) { @a.length }
should_change "@a.length", :to => 4 should_change("the number of elements", :to => 4) { @a.length }
should_change "@a[0]", :by => 0 should_change("the first element", :by => 0) { @a[0] }
should_not_change "@a[0]" should_not_change("the first element") { @a[0] }
end end


context "after replacing it with an array of strings" do context "after replacing it with an array of strings" do
setup do setup do
@a = %w(a b c d e f) @a = %w(a b c d e f)
end end


should_change "@a.length", :by => 3 should_change("the number of elements", :by => 3) { @a.length }
should_change "@a.length", :from => 3, :to => 6, :by => 3 should_change("the number of elements", :from => 3, :to => 6, :by => 3) { @a.length }
should_change "@a[0]" should_change("the first element") { @a[0] }
should_change "@a[1]", :from => 2, :to => "b" should_change("the second element", :from => 2, :to => "b") { @a[1] }
should_change "@a[2]", :from => /\d/, :to => /\w/ should_change("the third element", :from => /\d/, :to => /\w/) { @a[2] }
should_change "@a[3]", :to => String should_change("the last element", :to => String) { @a[3] }
end end
end end


Expand Down

0 comments on commit 4e4317f

Please sign in to comment.