ratnikov-shoulda 2.0.6.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 (103) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +12 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +146 -0
  4. data/Rakefile +72 -0
  5. data/bin/convert_to_should_syntax +42 -0
  6. data/lib/shoulda/action_mailer/assertions.rb +38 -0
  7. data/lib/shoulda/action_mailer.rb +10 -0
  8. data/lib/shoulda/active_record/assertions.rb +90 -0
  9. data/lib/shoulda/active_record/macros.rb +748 -0
  10. data/lib/shoulda/active_record.rb +12 -0
  11. data/lib/shoulda/assertions.rb +47 -0
  12. data/lib/shoulda/context.rb +326 -0
  13. data/lib/shoulda/controller/formats/html.rb +199 -0
  14. data/lib/shoulda/controller/formats/xml.rb +168 -0
  15. data/lib/shoulda/controller/helpers.rb +62 -0
  16. data/lib/shoulda/controller/macros.rb +336 -0
  17. data/lib/shoulda/controller/resource_options.rb +233 -0
  18. data/lib/shoulda/controller.rb +30 -0
  19. data/lib/shoulda/helpers.rb +8 -0
  20. data/lib/shoulda/macros.rb +73 -0
  21. data/lib/shoulda/private_helpers.rb +20 -0
  22. data/lib/shoulda/proc_extensions.rb +14 -0
  23. data/lib/shoulda/rails.rb +19 -0
  24. data/lib/shoulda/tasks/list_tests.rake +24 -0
  25. data/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
  26. data/lib/shoulda/tasks.rb +3 -0
  27. data/lib/shoulda.rb +21 -0
  28. data/rails/init.rb +1 -0
  29. data/test/README +36 -0
  30. data/test/fail_macros.rb +34 -0
  31. data/test/fixtures/addresses.yml +3 -0
  32. data/test/fixtures/friendships.yml +0 -0
  33. data/test/fixtures/posts.yml +5 -0
  34. data/test/fixtures/products.yml +0 -0
  35. data/test/fixtures/taggings.yml +0 -0
  36. data/test/fixtures/tags.yml +9 -0
  37. data/test/fixtures/users.yml +6 -0
  38. data/test/functional/posts_controller_test.rb +108 -0
  39. data/test/functional/users_controller_test.rb +38 -0
  40. data/test/other/context_test.rb +161 -0
  41. data/test/other/convert_to_should_syntax_test.rb +63 -0
  42. data/test/other/helpers_test.rb +183 -0
  43. data/test/other/private_helpers_test.rb +34 -0
  44. data/test/other/should_test.rb +266 -0
  45. data/test/rails_root/app/controllers/application.rb +25 -0
  46. data/test/rails_root/app/controllers/posts_controller.rb +86 -0
  47. data/test/rails_root/app/controllers/users_controller.rb +84 -0
  48. data/test/rails_root/app/helpers/application_helper.rb +3 -0
  49. data/test/rails_root/app/helpers/posts_helper.rb +2 -0
  50. data/test/rails_root/app/helpers/users_helper.rb +2 -0
  51. data/test/rails_root/app/models/address.rb +7 -0
  52. data/test/rails_root/app/models/flea.rb +3 -0
  53. data/test/rails_root/app/models/friendship.rb +4 -0
  54. data/test/rails_root/app/models/post.rb +12 -0
  55. data/test/rails_root/app/models/product.rb +12 -0
  56. data/test/rails_root/app/models/tag.rb +8 -0
  57. data/test/rails_root/app/models/tagging.rb +4 -0
  58. data/test/rails_root/app/models/user.rb +28 -0
  59. data/test/rails_root/app/views/layouts/posts.rhtml +19 -0
  60. data/test/rails_root/app/views/layouts/users.rhtml +17 -0
  61. data/test/rails_root/app/views/layouts/wide.html.erb +1 -0
  62. data/test/rails_root/app/views/posts/edit.rhtml +27 -0
  63. data/test/rails_root/app/views/posts/index.rhtml +25 -0
  64. data/test/rails_root/app/views/posts/new.rhtml +26 -0
  65. data/test/rails_root/app/views/posts/show.rhtml +18 -0
  66. data/test/rails_root/app/views/users/edit.rhtml +22 -0
  67. data/test/rails_root/app/views/users/index.rhtml +22 -0
  68. data/test/rails_root/app/views/users/new.rhtml +21 -0
  69. data/test/rails_root/app/views/users/show.rhtml +13 -0
  70. data/test/rails_root/config/boot.rb +109 -0
  71. data/test/rails_root/config/database.yml +4 -0
  72. data/test/rails_root/config/environment.rb +14 -0
  73. data/test/rails_root/config/environments/sqlite3.rb +0 -0
  74. data/test/rails_root/config/initializers/new_rails_defaults.rb +15 -0
  75. data/test/rails_root/config/initializers/shoulda.rb +8 -0
  76. data/test/rails_root/config/routes.rb +6 -0
  77. data/test/rails_root/db/migrate/001_create_users.rb +19 -0
  78. data/test/rails_root/db/migrate/002_create_posts.rb +13 -0
  79. data/test/rails_root/db/migrate/003_create_taggings.rb +12 -0
  80. data/test/rails_root/db/migrate/004_create_tags.rb +11 -0
  81. data/test/rails_root/db/migrate/005_create_dogs.rb +12 -0
  82. data/test/rails_root/db/migrate/006_create_addresses.rb +14 -0
  83. data/test/rails_root/db/migrate/007_create_fleas.rb +11 -0
  84. data/test/rails_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  85. data/test/rails_root/db/migrate/009_create_products.rb +17 -0
  86. data/test/rails_root/db/migrate/010_create_friendships.rb +14 -0
  87. data/test/rails_root/db/schema.rb +0 -0
  88. data/test/rails_root/public/404.html +30 -0
  89. data/test/rails_root/public/422.html +30 -0
  90. data/test/rails_root/public/500.html +30 -0
  91. data/test/rails_root/script/console +3 -0
  92. data/test/rails_root/script/generate +3 -0
  93. data/test/test_helper.rb +33 -0
  94. data/test/unit/address_test.rb +10 -0
  95. data/test/unit/dog_test.rb +10 -0
  96. data/test/unit/flea_test.rb +6 -0
  97. data/test/unit/friendship_test.rb +6 -0
  98. data/test/unit/post_test.rb +19 -0
  99. data/test/unit/product_test.rb +27 -0
  100. data/test/unit/tag_test.rb +14 -0
  101. data/test/unit/tagging_test.rb +6 -0
  102. data/test/unit/user_test.rb +60 -0
  103. metadata +189 -0
@@ -0,0 +1,12 @@
1
+ We're using GitHub[http://github.com/thoughtbot/shoulda/tree/master] and Lighthouse[http://thoughtbot.lighthouseapp.com/projects/5807], and we've been getting any combination of github pull requests, Lighthouse tickets, patches, emails, etc. We need to normalize this workflow to make sure we don't miss any fixes.
2
+
3
+ * Make sure you're accessing the source from the {official repository}[http://github.com/thoughtbot/shoulda/tree/master].
4
+ * We prefer git branches over patches, but we can take either.
5
+ * If you're using git, please make a branch for each separate contribution. We can cherry pick your commits, but pulling from a branch is easier.
6
+ * If you're submitting patches, please cut each fix or feature into a separate patch.
7
+ * There should be a Lighthouse[http://thoughtbot.lighthouseapp.com/projects/5807] ticket for any submission. If you've found a bug and want to fix it, open a new ticket at the same time.
8
+ * We've got github/lighthouse integration going, so you can update tickets when you commit. {This blog post}[http://hoth.entp.com/2008/4/11/github-and-lighthouse-sitting-in-a-tree] explains the commit options pretty well.
9
+ * Please <b>don't send pull requests</b> Just update the lighthouse ticket with the url for your fix (or attach the patch) when it's ready. The github pull requests pretty much get dropped on the floor until someone with commit rights notices them in the mailbox.
10
+ * Contributions without tests won't be accepted. The file <tt>/test/README</tt> explains the testing system pretty thoroughly.
11
+
12
+
data/MIT-LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2007, Tammer Saleh, Thoughtbot, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,146 @@
1
+ = Shoulda - Making tests easy on the fingers and eyes
2
+
3
+ Shoulda makes it easy to write elegant, understandable, and maintainable tests. Shoulda consists of test macros, assertions, and helpers added on to the Test::Unit framework. It's fully compatible with your existing tests, and requires no retooling to use.
4
+
5
+ Helpers:: #context and #should give you rSpec like test blocks.
6
+ In addition, you get nested contexts and a much more readable syntax.
7
+ Macros:: Generate hundreds of lines of Controller and ActiveRecord tests with these powerful macros.
8
+ They get you started quickly, and can help you ensure that your application is conforming to best practices.
9
+ Assertions:: Many common rails testing idioms have been distilled into a set of useful assertions.
10
+
11
+ = Usage
12
+
13
+ === Context Helpers (Shoulda::Context)
14
+
15
+ Stop killing your fingers with all of those underscores... Name your tests with plain sentences!
16
+
17
+ class UserTest < Test::Unit::TestCase
18
+ context "A User instance" do
19
+ setup do
20
+ @user = User.find(:first)
21
+ end
22
+
23
+ should "return its full name" do
24
+ assert_equal 'John Doe', @user.full_name
25
+ end
26
+
27
+ context "with a profile" do
28
+ setup do
29
+ @user.profile = Profile.find(:first)
30
+ end
31
+
32
+ should "return true when sent #has_profile?" do
33
+ assert @user.has_profile?
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ Produces the following test methods:
40
+
41
+ "test: A User instance should return its full name."
42
+ "test: A User instance with a profile should return true when sent #has_profile?."
43
+
44
+ So readable!
45
+
46
+ === ActiveRecord Tests (Shoulda::ActiveRecord::Macros)
47
+
48
+ Quick macro tests for your ActiveRecord associations and validations:
49
+
50
+ class PostTest < Test::Unit::TestCase
51
+ fixtures :all
52
+
53
+ should_belong_to :user
54
+ should_have_many :tags, :through => :taggings
55
+
56
+ should_require_unique_attributes :title
57
+ should_require_attributes :body, :message => /wtf/
58
+ should_require_attributes :title
59
+ should_only_allow_numeric_values_for :user_id
60
+ end
61
+
62
+ class UserTest < Test::Unit::TestCase
63
+ should_have_many :posts
64
+
65
+ should_not_allow_values_for :email, "blah", "b lah"
66
+ should_allow_values_for :email, "a@b.com", "asdf@asdf.com"
67
+ should_ensure_length_in_range :email, 1..100
68
+ should_ensure_value_in_range :age, 1..100
69
+ should_protect_attributes :password
70
+ end
71
+
72
+ Makes TDD so much easier.
73
+
74
+ === Controller Tests (Shoulda::Controller::Macros)
75
+
76
+ Macros to test the most common controller patterns...
77
+
78
+ context "on GET to :show for first record" do
79
+ setup do
80
+ get :show, :id => 1
81
+ end
82
+
83
+ should_assign_to :user
84
+ should_respond_with :success
85
+ should_render_template :show
86
+ should_not_set_the_flash
87
+
88
+ should "do something else really cool" do
89
+ assert_equal 1, assigns(:user).id
90
+ end
91
+ end
92
+
93
+ === Helpful Assertions (Shoulda::Assertions)
94
+
95
+ More to come here, but have fun with what's there.
96
+
97
+ assert_same_elements([:a, :b, :c], [:c, :a, :b])
98
+ assert_contains(['a', '1'], /\d/)
99
+ assert_contains(['a', '1'], 'a')
100
+
101
+ === 3rd Party and Application Specific Macros
102
+
103
+ Any *.rb file under RAILS_ROOT/test/shoulda_macros/ or vendor/(plugins|gems)/gem_name/shoulda_macros/ will be automatically required when you run your tests. This allows you to distribute macros with your plugins, or to organize the macros inside your application. Remember to add your macro to Test::Unit::TestCase in the macro file:
104
+
105
+ # test/shoulda_macros/security.rb
106
+ class Test::Unit::TestCase
107
+ def self.should_be_denied(opts = {})
108
+ should_set_the_flash_to(opts[:flash] || /Please log in/i)
109
+ should_redirect_to(opts[:redirect] || 'login_url')
110
+ end
111
+ end
112
+
113
+ = Rails Installation
114
+
115
+ === As a Gem
116
+
117
+ Use this if you prefer to use versioned releases of shoulda. Specify the gem dependency in your config/environment.rb file:
118
+
119
+ Rails::Initializer.run do |config|
120
+ config.gem "thoughtbot-shoulda", :lib => "shoulda", :source => "http://gems.github.com"
121
+ end
122
+
123
+ Then:
124
+
125
+ $ rake gems:install
126
+ $ rake gems:unpack
127
+
128
+ === As a Plugin
129
+
130
+ Use this if you prefer to use the edge version of shoulda:
131
+
132
+ $ script/plugin install git://github.com/thoughtbot/shoulda.git
133
+
134
+ === As a Plugin (using git submodules)
135
+
136
+ Use this if you prefer the idea of being able to easily switch between using edge or a tagged version of shoulda:
137
+
138
+ $ git submodule add git://github.com/thoughtbot/shoulda.git vendor/plugins/shoulda
139
+
140
+ = Credits
141
+
142
+ Shoulda is maintained by {Tammer Saleh}[mailto:tsaleh@thoughtbot.com], and is funded by Thoughtbot[http://www.thoughtbot.com], inc.
143
+
144
+ = License
145
+
146
+ Shoulda is Copyright © 2006-2008 Tammer Saleh, Thoughtbot. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
data/Rakefile ADDED
@@ -0,0 +1,72 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+
6
+ $LOAD_PATH.unshift("lib")
7
+ require 'shoulda'
8
+ load 'tasks/shoulda.rake'
9
+
10
+ # Test::Unit::UI::VERBOSE
11
+ test_files_pattern = 'test/{unit,functional,other}/**/*_test.rb'
12
+ Rake::TestTask.new do |t|
13
+ t.libs << 'lib'
14
+ t.pattern = test_files_pattern
15
+ t.verbose = false
16
+ end
17
+
18
+ Rake::RDocTask.new { |rdoc|
19
+ rdoc.rdoc_dir = 'doc'
20
+ rdoc.title = "Shoulda -- Making tests easy on the fingers and eyes"
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
23
+ rdoc.rdoc_files.include('README.rdoc', 'CONTRIBUTION_GUIDELINES.rdoc', 'lib/**/*.rb')
24
+ }
25
+
26
+ desc "Run code-coverage analysis using rcov"
27
+ task :coverage do
28
+ rm_rf "coverage"
29
+ files = Dir[test_files_pattern]
30
+ system "rcov --rails --sort coverage -Ilib #{files.join(' ')}"
31
+ end
32
+
33
+ desc 'Update documentation on website'
34
+ task :sync_docs => 'rdoc' do
35
+ `rsync -ave ssh doc/ dev@dev.thoughtbot.com:/home/dev/www/dev.thoughtbot.com/shoulda`
36
+ end
37
+
38
+ desc 'Default: run tests.'
39
+ task :default => ['test']
40
+
41
+ spec = Gem::Specification.new do |s|
42
+ s.name = "shoulda"
43
+ s.version = Shoulda::VERSION
44
+ s.summary = "Making tests easy on the fingers and eyes"
45
+ s.homepage = "http://thoughtbot.com/projects/shoulda"
46
+ s.rubyforge_project = "shoulda"
47
+
48
+ s.files = FileList["[A-Z]*", "{bin,lib,rails,test}/**/*"]
49
+ s.executables = s.files.grep(/^bin/) { |f| File.basename(f) }
50
+
51
+ s.has_rdoc = true
52
+ s.extra_rdoc_files = ["README.rdoc", "CONTRIBUTION_GUIDELINES.rdoc"]
53
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--main", "README.rdoc"]
54
+
55
+ s.authors = ["Tammer Saleh"]
56
+ s.email = "tsaleh@thoughtbot.com"
57
+ end
58
+
59
+ Rake::GemPackageTask.new spec do |pkg|
60
+ pkg.need_tar = true
61
+ pkg.need_zip = true
62
+ end
63
+
64
+ desc "Clean files generated by rake tasks"
65
+ task :clobber => [:clobber_rdoc, :clobber_package]
66
+
67
+ desc "Generate a gemspec file for GitHub"
68
+ task :gemspec do
69
+ File.open("#{spec.name}.gemspec", 'w') do |f|
70
+ f.write spec.to_ruby
71
+ end
72
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+ require 'tmpdir'
4
+
5
+ TMP = Dir::tmpdir
6
+
7
+ def usage(msg = nil)
8
+ puts "Error: #{msg}" if msg
9
+ puts if msg
10
+ puts "Usage: #{File.basename(__FILE__)} normal_test_file.rb"
11
+ puts
12
+ puts "Will convert an existing test file with names like "
13
+ puts
14
+ puts " def test_should_do_stuff"
15
+ puts " ..."
16
+ puts " end"
17
+ puts
18
+ puts "to one using the new syntax: "
19
+ puts
20
+ puts " should \"be super cool\" do"
21
+ puts " ..."
22
+ puts " end"
23
+ puts
24
+ puts "A copy of the old file will be left under #{TMP} in case\nthis script just seriously screws up"
25
+ puts
26
+ exit (msg ? 2 : 0)
27
+ end
28
+
29
+ usage("Wrong number of arguments.") unless ARGV.size == 1
30
+ usage("Temp directory '#{TMP}' is not valid. Set TMPDIR environment variable to a writeable directory.") unless File.directory?(TMP) && File.writable?(TMP)
31
+
32
+ file = ARGV.shift
33
+ tmpfile = File.join(TMP, File.basename(file))
34
+ usage("File '#{file}' doesn't exist") unless File.exists?(file)
35
+
36
+ FileUtils.cp(file, tmpfile)
37
+ contents = File.read(tmpfile)
38
+ contents.gsub!(/def test_should_(\S+)/) {|line| "should \"#{$1.tr('_', ' ')}\" do"}
39
+ contents.gsub!(/def test_(\S+)/) {|line| "should \"RENAME ME: test #{$1.tr('_', ' ')}\" do"}
40
+ File.open(file, 'w') { |f| f.write(contents) }
41
+
42
+ puts "File '#{file}' has been converted to 'should' syntax. Old version has been stored in '#{tmpfile}'"
@@ -0,0 +1,38 @@
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."
24
+ end
25
+ end
26
+
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
34
+ end
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,10 @@
1
+ require 'shoulda'
2
+ require 'shoulda/action_mailer/assertions'
3
+
4
+ module Test # :nodoc: all
5
+ module Unit
6
+ class TestCase
7
+ include Shoulda::ActionMailer::Assertions
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,90 @@
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
11
+
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
18
+
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 = //)
36
+ object = get_instance_of(object_or_klass)
37
+ object.send("#{attribute}=", value)
38
+ object.valid?
39
+ assert_does_not_contain(object.errors.on(attribute), error_message_to_avoid, "when set to #{value.inspect}")
40
+ end
41
+
42
+ # Asserts that an Active Record model invalidates the passed
43
+ # <tt>value</tt> by making sure the <tt>error_message_to_expect</tt> is
44
+ # contained within the list of errors for that attribute.
45
+ #
46
+ # assert_bad_value(User.new, :email, "invalid")
47
+ # assert_bad_value(User.new, :ssn, "123", /length/)
48
+ #
49
+ # If a class is passed as the first argument, a new object will be
50
+ # instantiated before the assertion. If an instance variable exists with
51
+ # the same name as the class (underscored), that object will be used
52
+ # instead.
53
+ #
54
+ # assert_bad_value(User, :email, "invalid")
55
+ #
56
+ # @product = Product.new(:tangible => true)
57
+ # assert_bad_value(Product, :price, "0")
58
+ def assert_bad_value(object_or_klass, attribute, value,
59
+ error_message_to_expect = self.class.default_error_message(:invalid))
60
+ object = get_instance_of(object_or_klass)
61
+ object.send("#{attribute}=", value)
62
+ assert !object.valid?, "#{object.class} allowed #{value.inspect} as a value for #{attribute}"
63
+ assert object.errors.on(attribute), "There are no errors on #{attribute} after being set to #{value.inspect}"
64
+ assert_contains(object.errors.on(attribute), error_message_to_expect, "when set to #{value.inspect}")
65
+ end
66
+
67
+ def pretty_error_messages(obj)
68
+ obj.errors.map do |a, m|
69
+ msg = "#{a} #{m}"
70
+ msg << " (#{obj.send(a).inspect})" unless a.to_sym == :base
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def get_instance_of(object_or_klass)
77
+ if object_or_klass.is_a?(Class)
78
+ klass = object_or_klass
79
+ instance_variable_get("@#{instance_variable_name_for(klass)}") || klass.new
80
+ else
81
+ object_or_klass
82
+ end
83
+ end
84
+
85
+ def instance_variable_name_for(klass)
86
+ klass.to_s.split('::').last.underscore
87
+ end
88
+ end
89
+ end
90
+ end