francois-shoulda 2.0.5.4 → 2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. data/README.rdoc +60 -10
  2. data/Rakefile +7 -7
  3. data/lib/shoulda.rb +7 -15
  4. data/lib/shoulda/action_controller.rb +28 -0
  5. data/lib/shoulda/action_controller/helpers.rb +47 -0
  6. data/lib/shoulda/action_controller/macros.rb +277 -0
  7. data/lib/shoulda/action_controller/matchers.rb +37 -0
  8. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +109 -0
  9. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +57 -0
  10. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +81 -0
  11. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +70 -0
  12. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +81 -0
  13. data/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
  14. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +87 -0
  15. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +85 -0
  16. data/lib/shoulda/action_mailer.rb +1 -1
  17. data/lib/shoulda/action_mailer/assertions.rb +32 -33
  18. data/lib/shoulda/action_view.rb +10 -0
  19. data/lib/shoulda/action_view/macros.rb +56 -0
  20. data/lib/shoulda/active_record.rb +6 -2
  21. data/lib/shoulda/active_record/assertions.rb +62 -89
  22. data/lib/shoulda/active_record/helpers.rb +40 -0
  23. data/lib/shoulda/active_record/macros.rb +520 -684
  24. data/lib/shoulda/active_record/matchers.rb +42 -0
  25. data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
  26. data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
  27. data/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
  28. data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
  29. data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
  30. data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
  31. data/lib/shoulda/active_record/matchers/have_index_matcher.rb +105 -0
  32. data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +125 -0
  33. data/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
  34. data/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
  35. data/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
  36. data/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
  37. data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
  38. data/lib/shoulda/active_record/matchers/validation_matcher.rb +56 -0
  39. data/lib/shoulda/assertions.rb +50 -40
  40. data/lib/shoulda/autoload_macros.rb +46 -0
  41. data/lib/shoulda/context.rb +124 -126
  42. data/lib/shoulda/helpers.rb +5 -7
  43. data/lib/shoulda/macros.rb +63 -64
  44. data/lib/shoulda/private_helpers.rb +16 -18
  45. data/lib/shoulda/rails.rb +5 -11
  46. data/lib/shoulda/rspec.rb +11 -0
  47. data/lib/shoulda/tasks/list_tests.rake +6 -1
  48. data/lib/shoulda/test_unit.rb +19 -0
  49. data/rails/init.rb +7 -1
  50. data/test/README +2 -2
  51. data/test/fail_macros.rb +15 -15
  52. data/test/fixtures/tags.yml +1 -1
  53. data/test/functional/posts_controller_test.rb +46 -26
  54. data/test/functional/users_controller_test.rb +0 -19
  55. data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +68 -0
  56. data/test/matchers/active_record/allow_value_matcher_test.rb +41 -0
  57. data/test/matchers/active_record/association_matcher_test.rb +258 -0
  58. data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +80 -0
  59. data/test/matchers/active_record/ensure_length_of_matcher_test.rb +158 -0
  60. data/test/matchers/active_record/have_db_column_matcher_test.rb +169 -0
  61. data/test/matchers/active_record/have_index_matcher_test.rb +74 -0
  62. data/test/matchers/active_record/have_named_scope_matcher_test.rb +65 -0
  63. data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +29 -0
  64. data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +44 -0
  65. data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +52 -0
  66. data/test/matchers/active_record/validate_presence_of_matcher_test.rb +86 -0
  67. data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +147 -0
  68. data/test/matchers/controller/assign_to_matcher_test.rb +35 -0
  69. data/test/matchers/controller/filter_param_matcher_test.rb +32 -0
  70. data/test/matchers/controller/render_with_layout_matcher_test.rb +33 -0
  71. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +27 -0
  72. data/test/matchers/controller/respond_with_matcher_test.rb +106 -0
  73. data/test/matchers/controller/route_matcher_test.rb +58 -0
  74. data/test/matchers/controller/set_session_matcher_test.rb +31 -0
  75. data/test/matchers/controller/set_the_flash_matcher.rb +41 -0
  76. data/test/model_builder.rb +106 -0
  77. data/test/other/autoload_macro_test.rb +18 -0
  78. data/test/other/helpers_test.rb +58 -0
  79. data/test/other/private_helpers_test.rb +1 -1
  80. data/test/other/should_test.rb +16 -16
  81. data/test/rails_root/app/controllers/posts_controller.rb +6 -5
  82. data/test/rails_root/app/models/pets/dog.rb +10 -0
  83. data/test/rails_root/app/models/treat.rb +3 -0
  84. data/test/rails_root/app/models/user.rb +4 -3
  85. data/test/rails_root/app/views/layouts/posts.rhtml +2 -0
  86. data/test/rails_root/config/database.yml +1 -1
  87. data/test/rails_root/config/environment.rb +1 -1
  88. data/test/rails_root/config/environments/{sqlite3.rb → test.rb} +0 -0
  89. data/test/rails_root/db/migrate/001_create_users.rb +3 -2
  90. data/test/rails_root/db/migrate/011_create_treats.rb +12 -0
  91. data/test/rails_root/test/shoulda_macros/custom_macro.rb +6 -0
  92. data/test/rails_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
  93. data/test/rails_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
  94. data/test/rspec_test.rb +207 -0
  95. data/test/test_helper.rb +3 -1
  96. data/test/unit/address_test.rb +1 -23
  97. data/test/unit/dog_test.rb +5 -2
  98. data/test/unit/post_test.rb +7 -3
  99. data/test/unit/product_test.rb +2 -2
  100. data/test/unit/tag_test.rb +2 -1
  101. data/test/unit/user_test.rb +25 -9
  102. metadata +84 -23
  103. data/lib/shoulda/controller.rb +0 -30
  104. data/lib/shoulda/controller/formats/html.rb +0 -201
  105. data/lib/shoulda/controller/formats/xml.rb +0 -170
  106. data/lib/shoulda/controller/helpers.rb +0 -64
  107. data/lib/shoulda/controller/macros.rb +0 -316
  108. data/lib/shoulda/controller/resource_options.rb +0 -236
  109. data/test/rails_root/app/models/dog.rb +0 -5
@@ -0,0 +1,87 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionController # :nodoc:
3
+ module Matchers
4
+
5
+ # Ensures that a session key was set to the expected value.
6
+ #
7
+ # Example:
8
+ #
9
+ # it { should set_session(:message) }
10
+ # it { should set_session(:user_id).to(@user.id) }
11
+ # it { should_not set_session(:user_id) }
12
+ def set_session(key)
13
+ SetSessionMatcher.new(key)
14
+ end
15
+
16
+ class SetSessionMatcher # :nodoc:
17
+
18
+ def initialize(key)
19
+ @key = key.to_s
20
+ end
21
+
22
+ def to(value)
23
+ @value = value
24
+ self
25
+ end
26
+
27
+ def matches?(controller)
28
+ @controller = controller
29
+ (assigned_value? && assigned_correct_value?) || cleared_value?
30
+ end
31
+
32
+ def failure_message
33
+ "Expected #{expectation}, but #{result}"
34
+ end
35
+
36
+ def negative_failure_message
37
+ "Didn't expect #{expectation}, but #{result}"
38
+ end
39
+
40
+ def description
41
+ description = "set session variable #{@key.inspect}"
42
+ description << " to #{@value.inspect}" if defined?(@value)
43
+ description
44
+ end
45
+
46
+ private
47
+
48
+ def assigned_value?
49
+ !assigned_value.blank?
50
+ end
51
+
52
+ def cleared_value?
53
+ defined?(@value) && @value.nil? && assigned_value.nil?
54
+ end
55
+
56
+ def assigned_correct_value?
57
+ return true if @value.nil?
58
+ assigned_value == @value
59
+ end
60
+
61
+ def assigned_value
62
+ session[@key]
63
+ end
64
+
65
+ def session
66
+ @controller.response.session.data
67
+ end
68
+
69
+ def expectation
70
+ expectation = "session variable #{@key} to be set"
71
+ expectation << " to #{@value.inspect}" if @value
72
+ expectation
73
+ end
74
+
75
+ def result
76
+ if session.empty?
77
+ "no session variables were set"
78
+ else
79
+ "the session was #{session.inspect}"
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,85 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionController # :nodoc:
3
+ module Matchers
4
+
5
+ # Ensures that the flash contains the given value. Can be a String, a
6
+ # Regexp, or nil (indicating that the flash should not be set).
7
+ #
8
+ # Example:
9
+ #
10
+ # it { should set_the_flash }
11
+ # it { should set_the_flash.to("Thank you for placing this order.") }
12
+ # it { should set_the_flash.to(/created/i) }
13
+ # it { should_not set_the_flash }
14
+ def set_the_flash
15
+ SetTheFlashMatcher.new
16
+ end
17
+
18
+ class SetTheFlashMatcher # :nodoc:
19
+
20
+ def to(value)
21
+ @value = value
22
+ self
23
+ end
24
+
25
+ def matches?(controller)
26
+ @controller = controller
27
+ sets_the_flash? && string_value_matches? && regexp_value_matches?
28
+ end
29
+
30
+ attr_reader :failure_message, :negative_failure_message
31
+
32
+ def description
33
+ description = "set the flash"
34
+ description << " to #{@value.inspect}" unless @value.nil?
35
+ description
36
+ end
37
+
38
+ def failure_message
39
+ "Expected #{expectation}"
40
+ end
41
+
42
+ def negative_failure_message
43
+ "Did not expect #{expectation}"
44
+ end
45
+
46
+ private
47
+
48
+ def sets_the_flash?
49
+ !flash.blank?
50
+ end
51
+
52
+ def string_value_matches?
53
+ return true unless String === @value
54
+ flash.values.any? {|value| value == @value }
55
+ end
56
+
57
+ def regexp_value_matches?
58
+ return true unless Regexp === @value
59
+ flash.values.any? {|value| value =~ @value }
60
+ end
61
+
62
+ def flash
63
+ @controller.response.session['flash']
64
+ end
65
+
66
+ def expectation
67
+ expectation = "the flash to be set"
68
+ expectation << " to #{@value.inspect}" unless @value.nil?
69
+ expectation << ", but #{flash_description}"
70
+ expectation
71
+ end
72
+
73
+ def flash_description
74
+ if flash.blank?
75
+ "no flash was set"
76
+ else
77
+ "was #{flash.inspect}"
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -4,7 +4,7 @@ require 'shoulda/action_mailer/assertions'
4
4
  module Test # :nodoc: all
5
5
  module Unit
6
6
  class TestCase
7
- include ThoughtBot::Shoulda::ActionMailer::Assertions
7
+ include Shoulda::ActionMailer::Assertions
8
8
  end
9
9
  end
10
10
  end
@@ -1,39 +1,38 @@
1
- module ThoughtBot # :nodoc:
2
- module Shoulda # :nodoc:
3
- module ActionMailer # :nodoc:
4
- module Assertions
5
- # Asserts that an email was delivered. Can take a block that can further
6
- # narrow down the types of emails you're expecting.
7
- #
8
- # assert_sent_email
9
- #
10
- # Passes if ActionMailer::Base.deliveries has an email
11
- #
12
- # assert_sent_email do |email|
13
- # email.subject =~ /hi there/ && email.to.include?('none@none.com')
14
- # end
15
- #
16
- # Passes if there is an email with subject containing 'hi there' and
17
- # 'none@none.com' as one of the recipients.
18
- #
19
- def assert_sent_email
20
- emails = ::ActionMailer::Base.deliveries
21
- assert !emails.empty?, "No emails were sent"
22
- if block_given?
23
- matching_emails = emails.select {|email| yield email }
24
- assert !matching_emails.empty?, "None of the emails matched."
25
- end
1
+ module Shoulda # :nodoc:
2
+ module ActionMailer # :nodoc:
3
+ module Assertions
4
+ # Asserts that an email was delivered. Can take a block that can further
5
+ # narrow down the types of emails you're expecting.
6
+ #
7
+ # assert_sent_email
8
+ #
9
+ # Passes if ActionMailer::Base.deliveries has an email
10
+ #
11
+ # assert_sent_email do |email|
12
+ # email.subject =~ /hi there/ && email.to.include?('none@none.com')
13
+ # end
14
+ #
15
+ # Passes if there is an email with subject containing 'hi there' and
16
+ # 'none@none.com' as one of the recipients.
17
+ #
18
+ def assert_sent_email
19
+ emails = ::ActionMailer::Base.deliveries
20
+ assert !emails.empty?, "No emails were sent"
21
+ if block_given?
22
+ matching_emails = emails.select {|email| yield email }
23
+ assert !matching_emails.empty?, "None of the emails matched."
26
24
  end
25
+ end
27
26
 
28
- # Asserts that no ActionMailer mails were delivered
29
- #
30
- # assert_did_not_send_email
31
- def assert_did_not_send_email
32
- msg = "Sent #{::ActionMailer::Base.deliveries.size} emails.\n"
33
- ::ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" }
34
- assert ::ActionMailer::Base.deliveries.empty?, msg
35
- end
27
+ # Asserts that no ActionMailer mails were delivered
28
+ #
29
+ # assert_did_not_send_email
30
+ def assert_did_not_send_email
31
+ msg = "Sent #{::ActionMailer::Base.deliveries.size} emails.\n"
32
+ ::ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" }
33
+ assert ::ActionMailer::Base.deliveries.empty?, msg
36
34
  end
37
35
  end
38
36
  end
39
37
  end
38
+
@@ -0,0 +1,10 @@
1
+ require 'shoulda'
2
+ require 'shoulda/action_view/macros'
3
+
4
+ module Test # :nodoc: all
5
+ module Unit
6
+ class TestCase
7
+ extend Shoulda::ActionView::Macros
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,56 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionView # :nodoc:
3
+ # = Macro test helpers for your view
4
+ #
5
+ # By using the macro helpers you can quickly and easily create concise and
6
+ # easy to read test suites.
7
+ #
8
+ # This code segment:
9
+ # context "on GET to :new" do
10
+ # setup do
11
+ # get :new
12
+ # end
13
+ #
14
+ # should_render_a_form
15
+ # should_render_page_with_metadata :title => /index/
16
+ #
17
+ # should "do something else really cool" do
18
+ # assert_select '#really_cool'
19
+ # end
20
+ # end
21
+ #
22
+ # Would produce 3 tests for the +show+ action
23
+ module Macros
24
+
25
+ # Macro that creates a test asserting that the rendered view contains a <form> element.
26
+ def should_render_a_form
27
+ should "display a form" do
28
+ assert_select "form", true, "The template doesn't contain a <form> element"
29
+ end
30
+ end
31
+
32
+ # Macro that creates a test asserting that the rendered view contains the selected metatags.
33
+ # Values can be string or Regexps.
34
+ # Example:
35
+ #
36
+ # should_render_page_with_metadata :description => "Description of this page", :keywords => /post/
37
+ #
38
+ # You can also use this method to test the rendered views title.
39
+ #
40
+ # Example:
41
+ # should_render_page_with_metadata :title => /index/
42
+ def should_render_page_with_metadata(options)
43
+ options.each do |key, value|
44
+ should "have metatag #{key}" do
45
+ if key.to_sym == :title
46
+ assert_select "title", value
47
+ else
48
+ assert_select "meta[name=?][content#{"*" if value.is_a?(Regexp)}=?]", key, value
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
@@ -1,12 +1,16 @@
1
1
  require 'shoulda'
2
+ require 'shoulda/active_record/helpers'
3
+ require 'shoulda/active_record/matchers'
2
4
  require 'shoulda/active_record/assertions'
3
5
  require 'shoulda/active_record/macros'
4
6
 
5
7
  module Test # :nodoc: all
6
8
  module Unit
7
9
  class TestCase
8
- include ThoughtBot::Shoulda::ActiveRecord::Assertions
9
- extend ThoughtBot::Shoulda::ActiveRecord::Macros
10
+ include Shoulda::ActiveRecord::Helpers
11
+ include Shoulda::ActiveRecord::Matchers
12
+ include Shoulda::ActiveRecord::Assertions
13
+ extend Shoulda::ActiveRecord::Macros
10
14
  end
11
15
  end
12
16
  end
@@ -1,95 +1,68 @@
1
- module ThoughtBot # :nodoc:
2
- module Shoulda # :nodoc:
3
- module ActiveRecord # :nodoc:
4
- module Assertions
5
- # Asserts that the given object can be saved
6
- #
7
- # assert_save User.new(params)
8
- def assert_save(obj)
9
- assert obj.save, "Errors: #{pretty_error_messages obj}"
10
- obj.reload
11
- end
12
-
13
- # Asserts that the given object is valid
14
- #
15
- # assert_valid User.new(params)
16
- def assert_valid(obj)
17
- assert obj.valid?, "Errors: #{pretty_error_messages obj}"
18
- end
19
-
20
- # Asserts that the given object is invalid, in the ActiveRecord sense.
21
- # Calls #valid? on the object, and fails the assertion if the value is true.
22
- #
23
- # assert_invalid User.new(params)
24
- def assert_invalid(obj)
25
- assert !obj.valid?, "<#{obj.inspect}> should have been invalid"
26
- end
27
-
28
- # Asserts that an Active Record model validates with the passed
29
- # <tt>value</tt> by making sure the <tt>error_message_to_avoid</tt> is not
30
- # contained within the list of errors for that attribute.
31
- #
32
- # assert_good_value(User.new, :email, "user@example.com")
33
- # assert_good_value(User.new, :ssn, "123456789", /length/)
34
- #
35
- # If a class is passed as the first argument, a new object will be
36
- # instantiated before the assertion. If an instance variable exists with
37
- # the same name as the class (underscored), that object will be used
38
- # instead.
39
- #
40
- # assert_good_value(User, :email, "user@example.com")
41
- #
42
- # @product = Product.new(:tangible => false)
43
- # assert_good_value(Product, :price, "0")
44
- def assert_good_value(object_or_klass, attribute, value, error_message_to_avoid = //)
45
- object = get_instance_of(object_or_klass)
46
- object.send("#{attribute}=", value)
47
- object.valid?
48
- assert_does_not_contain(object.errors.on(attribute), error_message_to_avoid, "when set to #{value.inspect}")
49
- end
50
-
51
- # Asserts that an Active Record model invalidates the passed
52
- # <tt>value</tt> by making sure the <tt>error_message_to_expect</tt> is
53
- # contained within the list of errors for that attribute.
54
- #
55
- # assert_bad_value(User.new, :email, "invalid")
56
- # assert_bad_value(User.new, :ssn, "123", /length/)
57
- #
58
- # If a class is passed as the first argument, a new object will be
59
- # instantiated before the assertion. If an instance variable exists with
60
- # the same name as the class (underscored), that object will be used
61
- # instead.
62
- #
63
- # assert_bad_value(User, :email, "invalid")
64
- #
65
- # @product = Product.new(:tangible => true)
66
- # assert_bad_value(Product, :price, "0")
67
- def assert_bad_value(object_or_klass, attribute, value,
68
- error_message_to_expect = self.class.default_error_message(:invalid))
69
- object = get_instance_of(object_or_klass)
70
- object.send("#{attribute}=", value)
71
- assert !object.valid?, "#{object.class} allowed #{value.inspect} as a value for #{attribute}"
72
- assert object.errors.on(attribute), "There are no errors on #{attribute} after being set to #{value.inspect}"
73
- assert_contains(object.errors.on(attribute), error_message_to_expect, "when set to #{value.inspect}")
74
- end
1
+ module Shoulda # :nodoc:
2
+ module ActiveRecord # :nodoc:
3
+ module Assertions
4
+ # Asserts that the given object can be saved
5
+ #
6
+ # assert_save User.new(params)
7
+ def assert_save(obj)
8
+ assert obj.save, "Errors: #{pretty_error_messages obj}"
9
+ obj.reload
10
+ end
75
11
 
76
- def pretty_error_messages(obj)
77
- obj.errors.map do |a, m|
78
- msg = "#{a} #{m}"
79
- msg << " (#{obj.send(a).inspect})" unless a.to_sym == :base
80
- end
81
- end
12
+ # Asserts that the given object is valid
13
+ #
14
+ # assert_valid User.new(params)
15
+ def assert_valid(obj)
16
+ assert obj.valid?, "Errors: #{pretty_error_messages obj}"
17
+ end
82
18
 
83
- private
19
+ # Asserts that an Active Record model validates with the passed
20
+ # <tt>value</tt> by making sure the <tt>error_message_to_avoid</tt> is not
21
+ # contained within the list of errors for that attribute.
22
+ #
23
+ # assert_good_value(User.new, :email, "user@example.com")
24
+ # assert_good_value(User.new, :ssn, "123456789", /length/)
25
+ #
26
+ # If a class is passed as the first argument, a new object will be
27
+ # instantiated before the assertion. If an instance variable exists with
28
+ # the same name as the class (underscored), that object will be used
29
+ # instead.
30
+ #
31
+ # assert_good_value(User, :email, "user@example.com")
32
+ #
33
+ # @product = Product.new(:tangible => false)
34
+ # assert_good_value(Product, :price, "0")
35
+ def assert_good_value(object_or_klass, attribute, value, error_message_to_avoid = nil)
36
+ object = get_instance_of(object_or_klass)
37
+ matcher = allow_value(value).
38
+ for(attribute).
39
+ with_message(error_message_to_avoid)
40
+ assert_accepts(matcher, object)
41
+ end
84
42
 
85
- def get_instance_of(object_or_klass)
86
- if object_or_klass.is_a?(Class)
87
- klass = object_or_klass
88
- instance_variable_get("@#{klass.to_s.underscore}") || klass.new
89
- else
90
- object_or_klass
91
- end
92
- end
43
+ # Asserts that an Active Record model invalidates the passed
44
+ # <tt>value</tt> by making sure the <tt>error_message_to_expect</tt> is
45
+ # contained within the list of errors for that attribute.
46
+ #
47
+ # assert_bad_value(User.new, :email, "invalid")
48
+ # assert_bad_value(User.new, :ssn, "123", /length/)
49
+ #
50
+ # If a class is passed as the first argument, a new object will be
51
+ # instantiated before the assertion. If an instance variable exists with
52
+ # the same name as the class (underscored), that object will be used
53
+ # instead.
54
+ #
55
+ # assert_bad_value(User, :email, "invalid")
56
+ #
57
+ # @product = Product.new(:tangible => true)
58
+ # assert_bad_value(Product, :price, "0")
59
+ def assert_bad_value(object_or_klass, attribute, value,
60
+ error_message_to_expect = nil)
61
+ object = get_instance_of(object_or_klass)
62
+ matcher = allow_value(value).
63
+ for(attribute).
64
+ with_message(error_message_to_expect)
65
+ assert_rejects(matcher, object)
93
66
  end
94
67
  end
95
68
  end