diff --git a/lib/shoulda/general.rb b/lib/shoulda/general.rb index ef44ac6d..66e9f3f6 100644 --- a/lib/shoulda/general.rb +++ b/lib/shoulda/general.rb @@ -182,9 +182,20 @@ module ThoughtBot # :nodoc: # value by making sure the error_message_to_avoid is not # contained within the list of errors for that attribute. # - # assert_good_value(User.new, :email, "user@example.com") #=> passes - # assert_good_value(User.new, :ssn, "123456789", /length/) #=> passes - def assert_good_value(object, attribute, value, error_message_to_avoid = //) + # assert_good_value(User.new, :email, "user@example.com") + # assert_good_value(User.new, :ssn, "123456789", /length/) + # + # If a class is passed as the first argument, a new object will be + # instantiated before the assertion. If an instance variable exists with + # the same name as the class (underscored), that object will be used + # instead. + # + # assert_good_value(User, :email, "user@example.com") + # + # @product = Product.new(:tangible => false) + # assert_good_value(Product, :price, "0") + def assert_good_value(object_or_klass, attribute, value, error_message_to_avoid = //) + object = get_instance_of(object_or_klass) object.send("#{attribute}=", value) object.valid? assert_does_not_contain(object.errors.on(attribute), error_message_to_avoid, "when set to #{value.inspect}") @@ -194,9 +205,20 @@ module ThoughtBot # :nodoc: # value by making sure the error_message_to_expect is # contained within the list of errors for that attribute. # - # assert_bad_value(User.new, :email, "invalid") #=> passes - # assert_bad_value(User.new, :ssn, "123", /length/) #=> passes - def assert_bad_value(object, attribute, value, error_message_to_expect = /invalid/) + # assert_bad_value(User.new, :email, "invalid") + # assert_bad_value(User.new, :ssn, "123", /length/) + # + # If a class is passed as the first argument, a new object will be + # instantiated before the assertion. If an instance variable exists with + # the same name as the class (underscored), that object will be used + # instead. + # + # assert_bad_value(User, :email, "invalid") + # + # @product = Product.new(:tangible => true) + # assert_bad_value(Product, :price, "0") + def assert_bad_value(object_or_klass, attribute, value, error_message_to_expect = /invalid/) + object = get_instance_of(object_or_klass) object.send("#{attribute}=", value) assert !object.valid?, "#{object.class} allowed #{value.inspect} as a value for #{attribute}" assert object.errors.on(attribute), "There are no errors on #{attribute} after being set to #{value.inspect}" @@ -206,6 +228,17 @@ module ThoughtBot # :nodoc: def pretty_error_messages(obj) obj.errors.map { |a, m| "#{a} #{m} (#{obj.send(a).inspect})" } end + + private + + def get_instance_of(object_or_klass) + if object_or_klass.is_a?(Class) + klass = object_or_klass + instance_variable_get("@#{klass.to_s.underscore}") || klass.new + else + object_or_klass + end + end end end end diff --git a/test/fixtures/products.yml b/test/fixtures/products.yml new file mode 100644 index 00000000..e69de29b diff --git a/test/other/helpers_test.rb b/test/other/helpers_test.rb index 0478233f..e3dd098e 100644 --- a/test/other/helpers_test.rb +++ b/test/other/helpers_test.rb @@ -129,6 +129,20 @@ class HelpersTest < Test::Unit::TestCase # :nodoc: assert_good_value User.new, :ssn, "x", /length/ end end + + should "accept a class as the first argument" do + assert_good_value User, :email, "good@example.com" + end + + context "with an instance variable" do + setup do + @product = Product.new(:tangible => true) + end + + should "use that instance variable" do + assert_good_value Product, :price, "9999", /included/ + end + end end context "assert_bad_value" do @@ -151,5 +165,19 @@ class HelpersTest < Test::Unit::TestCase # :nodoc: assert_bad_value User.new, :ssn, "xxxxxxxxx", /length/ end end + + should "accept a class as the first argument" do + assert_bad_value User, :email, "bad" + end + + context "with an instance variable" do + setup do + @product = Product.new(:tangible => true) + end + + should "use that instance variable" do + assert_bad_value Product, :price, "0", /included/ + end + end end end diff --git a/test/rails_root/app/models/product.rb b/test/rails_root/app/models/product.rb new file mode 100644 index 00000000..1108a44d --- /dev/null +++ b/test/rails_root/app/models/product.rb @@ -0,0 +1,9 @@ +class Product < ActiveRecord::Base + validates_presence_of :title, :price + validates_inclusion_of :price, :in => 0..99, :unless => :tangible + + validates_inclusion_of :price, :in => 1..9999, :if => :tangible + validates_inclusion_of :weight, :in => 1..100, :if => :tangible + validates_format_of :size, :with => /.+x.+x.+/, :if => :tangible + validates_length_of :size, :in => 5..20, :if => :tangible +end diff --git a/test/rails_root/db/migrate/009_create_products.rb b/test/rails_root/db/migrate/009_create_products.rb new file mode 100644 index 00000000..173f948f --- /dev/null +++ b/test/rails_root/db/migrate/009_create_products.rb @@ -0,0 +1,17 @@ +class CreateProducts < ActiveRecord::Migration + def self.up + create_table :products do |t| + t.string :title + t.integer :price + t.integer :weight + t.string :size + t.boolean :tangible + + t.timestamps + end + end + + def self.down + drop_table :products + end +end