tpitale-shoulda 2.11.0

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 (170) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +10 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +171 -0
  4. data/Rakefile +71 -0
  5. data/bin/convert_to_should_syntax +42 -0
  6. data/lib/shoulda.rb +11 -0
  7. data/lib/shoulda/action_controller.rb +26 -0
  8. data/lib/shoulda/action_controller/macros.rb +240 -0
  9. data/lib/shoulda/action_controller/matchers.rb +37 -0
  10. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +109 -0
  11. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +57 -0
  12. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +81 -0
  13. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +74 -0
  14. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +81 -0
  15. data/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
  16. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +87 -0
  17. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +85 -0
  18. data/lib/shoulda/action_mailer.rb +10 -0
  19. data/lib/shoulda/action_mailer/assertions.rb +38 -0
  20. data/lib/shoulda/action_view.rb +10 -0
  21. data/lib/shoulda/action_view/macros.rb +61 -0
  22. data/lib/shoulda/active_record.rb +16 -0
  23. data/lib/shoulda/active_record/assertions.rb +69 -0
  24. data/lib/shoulda/active_record/helpers.rb +27 -0
  25. data/lib/shoulda/active_record/macros.rb +512 -0
  26. data/lib/shoulda/active_record/matchers.rb +43 -0
  27. data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
  28. data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
  29. data/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
  30. data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
  31. data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
  32. data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
  33. data/lib/shoulda/active_record/matchers/have_db_index_matcher.rb +112 -0
  34. data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +128 -0
  35. data/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
  36. data/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
  37. data/lib/shoulda/active_record/matchers/validate_format_of_matcher.rb +67 -0
  38. data/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
  39. data/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
  40. data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
  41. data/lib/shoulda/active_record/matchers/validation_matcher.rb +57 -0
  42. data/lib/shoulda/assertions.rb +71 -0
  43. data/lib/shoulda/autoload_macros.rb +46 -0
  44. data/lib/shoulda/context.rb +413 -0
  45. data/lib/shoulda/helpers.rb +8 -0
  46. data/lib/shoulda/macros.rb +133 -0
  47. data/lib/shoulda/minitest.rb +24 -0
  48. data/lib/shoulda/private_helpers.rb +13 -0
  49. data/lib/shoulda/proc_extensions.rb +14 -0
  50. data/lib/shoulda/rails.rb +13 -0
  51. data/lib/shoulda/rspec.rb +11 -0
  52. data/lib/shoulda/tasks.rb +3 -0
  53. data/lib/shoulda/tasks/list_tests.rake +29 -0
  54. data/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
  55. data/lib/shoulda/test_unit.rb +22 -0
  56. data/rails/init.rb +7 -0
  57. data/test/README +36 -0
  58. data/test/fail_macros.rb +39 -0
  59. data/test/fixtures/addresses.yml +3 -0
  60. data/test/fixtures/friendships.yml +0 -0
  61. data/test/fixtures/posts.yml +5 -0
  62. data/test/fixtures/products.yml +0 -0
  63. data/test/fixtures/taggings.yml +0 -0
  64. data/test/fixtures/tags.yml +9 -0
  65. data/test/fixtures/users.yml +6 -0
  66. data/test/functional/posts_controller_test.rb +121 -0
  67. data/test/functional/users_controller_test.rb +19 -0
  68. data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +68 -0
  69. data/test/matchers/active_record/allow_value_matcher_test.rb +64 -0
  70. data/test/matchers/active_record/association_matcher_test.rb +263 -0
  71. data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +80 -0
  72. data/test/matchers/active_record/ensure_length_of_matcher_test.rb +158 -0
  73. data/test/matchers/active_record/have_db_column_matcher_test.rb +169 -0
  74. data/test/matchers/active_record/have_db_index_matcher_test.rb +91 -0
  75. data/test/matchers/active_record/have_named_scope_matcher_test.rb +65 -0
  76. data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +29 -0
  77. data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +44 -0
  78. data/test/matchers/active_record/validate_format_of_matcher_test.rb +39 -0
  79. data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +52 -0
  80. data/test/matchers/active_record/validate_presence_of_matcher_test.rb +86 -0
  81. data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +147 -0
  82. data/test/matchers/controller/assign_to_matcher_test.rb +35 -0
  83. data/test/matchers/controller/filter_param_matcher_test.rb +32 -0
  84. data/test/matchers/controller/render_with_layout_matcher_test.rb +33 -0
  85. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +32 -0
  86. data/test/matchers/controller/respond_with_matcher_test.rb +106 -0
  87. data/test/matchers/controller/route_matcher_test.rb +58 -0
  88. data/test/matchers/controller/set_session_matcher_test.rb +38 -0
  89. data/test/matchers/controller/set_the_flash_matcher.rb +41 -0
  90. data/test/model_builder.rb +106 -0
  91. data/test/other/autoload_macro_test.rb +18 -0
  92. data/test/other/context_test.rb +203 -0
  93. data/test/other/convert_to_should_syntax_test.rb +63 -0
  94. data/test/other/helpers_test.rb +340 -0
  95. data/test/other/private_helpers_test.rb +32 -0
  96. data/test/other/should_test.rb +271 -0
  97. data/test/rails_root/app/controllers/application_controller.rb +25 -0
  98. data/test/rails_root/app/controllers/posts_controller.rb +87 -0
  99. data/test/rails_root/app/controllers/users_controller.rb +84 -0
  100. data/test/rails_root/app/helpers/application_helper.rb +3 -0
  101. data/test/rails_root/app/helpers/posts_helper.rb +2 -0
  102. data/test/rails_root/app/helpers/users_helper.rb +2 -0
  103. data/test/rails_root/app/models/address.rb +7 -0
  104. data/test/rails_root/app/models/flea.rb +3 -0
  105. data/test/rails_root/app/models/friendship.rb +4 -0
  106. data/test/rails_root/app/models/pets/cat.rb +7 -0
  107. data/test/rails_root/app/models/pets/dog.rb +10 -0
  108. data/test/rails_root/app/models/post.rb +12 -0
  109. data/test/rails_root/app/models/product.rb +12 -0
  110. data/test/rails_root/app/models/profile.rb +2 -0
  111. data/test/rails_root/app/models/registration.rb +2 -0
  112. data/test/rails_root/app/models/tag.rb +8 -0
  113. data/test/rails_root/app/models/tagging.rb +4 -0
  114. data/test/rails_root/app/models/treat.rb +3 -0
  115. data/test/rails_root/app/models/user.rb +32 -0
  116. data/test/rails_root/app/views/layouts/posts.rhtml +19 -0
  117. data/test/rails_root/app/views/layouts/users.rhtml +17 -0
  118. data/test/rails_root/app/views/layouts/wide.html.erb +1 -0
  119. data/test/rails_root/app/views/posts/edit.rhtml +27 -0
  120. data/test/rails_root/app/views/posts/index.rhtml +25 -0
  121. data/test/rails_root/app/views/posts/new.rhtml +26 -0
  122. data/test/rails_root/app/views/posts/show.rhtml +18 -0
  123. data/test/rails_root/app/views/users/edit.rhtml +22 -0
  124. data/test/rails_root/app/views/users/index.rhtml +22 -0
  125. data/test/rails_root/app/views/users/new.rhtml +21 -0
  126. data/test/rails_root/app/views/users/show.rhtml +13 -0
  127. data/test/rails_root/config/boot.rb +110 -0
  128. data/test/rails_root/config/database.yml +4 -0
  129. data/test/rails_root/config/environment.rb +18 -0
  130. data/test/rails_root/config/environments/test.rb +0 -0
  131. data/test/rails_root/config/initializers/new_rails_defaults.rb +15 -0
  132. data/test/rails_root/config/initializers/shoulda.rb +8 -0
  133. data/test/rails_root/config/routes.rb +6 -0
  134. data/test/rails_root/db/migrate/001_create_users.rb +19 -0
  135. data/test/rails_root/db/migrate/002_create_posts.rb +13 -0
  136. data/test/rails_root/db/migrate/003_create_taggings.rb +12 -0
  137. data/test/rails_root/db/migrate/004_create_tags.rb +11 -0
  138. data/test/rails_root/db/migrate/005_create_dogs.rb +12 -0
  139. data/test/rails_root/db/migrate/006_create_addresses.rb +14 -0
  140. data/test/rails_root/db/migrate/007_create_fleas.rb +11 -0
  141. data/test/rails_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  142. data/test/rails_root/db/migrate/009_create_products.rb +17 -0
  143. data/test/rails_root/db/migrate/010_create_friendships.rb +14 -0
  144. data/test/rails_root/db/migrate/011_create_treats.rb +12 -0
  145. data/test/rails_root/db/migrate/20090506203502_create_profiles.rb +12 -0
  146. data/test/rails_root/db/migrate/20090506203536_create_registrations.rb +14 -0
  147. data/test/rails_root/db/migrate/20090513104502_create_cats.rb +12 -0
  148. data/test/rails_root/db/schema.rb +0 -0
  149. data/test/rails_root/log/test.log +1 -0
  150. data/test/rails_root/public/404.html +30 -0
  151. data/test/rails_root/public/422.html +30 -0
  152. data/test/rails_root/public/500.html +30 -0
  153. data/test/rails_root/script/console +3 -0
  154. data/test/rails_root/script/generate +3 -0
  155. data/test/rails_root/test/shoulda_macros/custom_macro.rb +6 -0
  156. data/test/rails_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
  157. data/test/rails_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
  158. data/test/rspec_test.rb +207 -0
  159. data/test/test_helper.rb +28 -0
  160. data/test/unit/address_test.rb +10 -0
  161. data/test/unit/cat_test.rb +7 -0
  162. data/test/unit/dog_test.rb +9 -0
  163. data/test/unit/flea_test.rb +6 -0
  164. data/test/unit/friendship_test.rb +6 -0
  165. data/test/unit/post_test.rb +19 -0
  166. data/test/unit/product_test.rb +23 -0
  167. data/test/unit/tag_test.rb +15 -0
  168. data/test/unit/tagging_test.rb +6 -0
  169. data/test/unit/user_test.rb +80 -0
  170. metadata +226 -0
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ class AutoloadMacroTest < ActiveSupport::TestCase # :nodoc:
4
+ context "The macro auto-loader" do
5
+ should "load macros from the plugins" do
6
+ assert self.class.respond_to?('plugin_macro')
7
+ end
8
+
9
+ should "load macros from the gems" do
10
+ assert self.class.respond_to?('gem_macro')
11
+ end
12
+
13
+ should "load custom macros from ROOT/test/shoulda_macros" do
14
+ assert self.class.respond_to?('custom_macro')
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,203 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ class ContextTest < ActiveSupport::TestCase # :nodoc:
4
+
5
+ def self.context_macro(&blk)
6
+ context "with a subcontext made by a macro" do
7
+ setup { @context_macro = :foo }
8
+
9
+ merge_block &blk
10
+ end
11
+ end
12
+
13
+ # def self.context_macro(&blk)
14
+ # context "with a subcontext made by a macro" do
15
+ # setup { @context_macro = :foo }
16
+ # yield # <- this doesn't work.
17
+ # end
18
+ # end
19
+
20
+ context "context with setup block" do
21
+ setup do
22
+ @blah = "blah"
23
+ end
24
+
25
+ should "run the setup block" do
26
+ assert_equal "blah", @blah
27
+ end
28
+
29
+ should "have name set right" do
30
+ assert_match(/^test: context with setup block/, self.to_s)
31
+ end
32
+
33
+ context "and a subcontext" do
34
+ setup do
35
+ @blah = "#{@blah} twice"
36
+ end
37
+
38
+ should "be named correctly" do
39
+ assert_match(/^test: context with setup block and a subcontext should be named correctly/, self.to_s)
40
+ end
41
+
42
+ should "run the setup blocks in order" do
43
+ assert_equal @blah, "blah twice"
44
+ end
45
+ end
46
+
47
+ context_macro do
48
+ should "have name set right" do
49
+ assert_match(/^test: context with setup block with a subcontext made by a macro should have name set right/, self.to_s)
50
+ end
51
+
52
+ should "run the setup block of that context macro" do
53
+ assert_equal :foo, @context_macro
54
+ end
55
+
56
+ should "run the setup block of the main context" do
57
+ assert_equal "blah", @blah
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ context "another context with setup block" do
64
+ setup do
65
+ @blah = "foo"
66
+ end
67
+
68
+ should "have @blah == 'foo'" do
69
+ assert_equal "foo", @blah
70
+ end
71
+
72
+ should "have name set right" do
73
+ assert_match(/^test: another context with setup block/, self.to_s)
74
+ end
75
+ end
76
+
77
+ context "context with method definition" do
78
+ setup do
79
+ def hello; "hi"; end
80
+ end
81
+
82
+ should "be able to read that method" do
83
+ assert_equal "hi", hello
84
+ end
85
+
86
+ should "have name set right" do
87
+ assert_match(/^test: context with method definition/, self.to_s)
88
+ end
89
+ end
90
+
91
+ context "another context" do
92
+ should "not define @blah" do
93
+ assert_nil @blah
94
+ end
95
+ end
96
+
97
+ context "context with multiple setups and/or teardowns" do
98
+
99
+ cleanup_count = 0
100
+
101
+ 2.times do |i|
102
+ setup { cleanup_count += 1 }
103
+ teardown { cleanup_count -= 1 }
104
+ end
105
+
106
+ 2.times do |i|
107
+ should "call all setups and all teardowns (check ##{i + 1})" do
108
+ assert_equal 2, cleanup_count
109
+ end
110
+ end
111
+
112
+ context "subcontexts" do
113
+
114
+ 2.times do |i|
115
+ setup { cleanup_count += 1 }
116
+ teardown { cleanup_count -= 1 }
117
+ end
118
+
119
+ 2.times do |i|
120
+ should "also call all setups and all teardowns in parent and subcontext (check ##{i + 1})" do
121
+ assert_equal 4, cleanup_count
122
+ end
123
+ end
124
+
125
+ end
126
+
127
+ end
128
+
129
+ should_eventually "pass, since it's unimplemented" do
130
+ flunk "what?"
131
+ end
132
+
133
+ should_eventually "not require a block when using should_eventually"
134
+ should "pass without a block, as that causes it to piggyback to should_eventually"
135
+
136
+ context "context for testing should piggybacking" do
137
+ should "call should_eventually as we are not passing a block"
138
+ end
139
+
140
+ context "context" do
141
+ context "with nested subcontexts" do
142
+ should_eventually "only print this statement once for a should_eventually"
143
+ end
144
+ end
145
+
146
+ class ::SomeModel; end
147
+
148
+ context "given a test named after a class" do
149
+ setup do
150
+ self.class.stubs(:name).returns("SomeModelTest")
151
+ end
152
+
153
+ should "determine the described type" do
154
+ assert_equal SomeModel, self.class.described_type
155
+ end
156
+
157
+ should "return a new instance of the described type as the subject if none exists" do
158
+ assert_kind_of SomeModel, subject
159
+ end
160
+
161
+ should "return an existing instance of the described type as the subject" do
162
+ @some_model = SomeModel.new
163
+ assert_equal @some_model, subject
164
+ end
165
+
166
+ context "with an explicit subject block" do
167
+ setup { @expected = SomeModel.new }
168
+ subject { @expected }
169
+ should "return the result of the block as the subject" do
170
+ assert_equal @expected, subject
171
+ end
172
+
173
+ context "nested context block without a subject block" do
174
+ should "return the result of the parent context's subject block" do
175
+ assert_equal @expected, subject
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ class Subject; end
183
+
184
+ class SubjectTest < ActiveSupport::TestCase
185
+
186
+ def setup
187
+ @expected = Subject.new
188
+ end
189
+
190
+ subject { @expected }
191
+
192
+ should "return a specified subject" do
193
+ assert_equal @expected, subject
194
+ end
195
+ end
196
+
197
+ class SubjectLazinessTest < ActiveSupport::TestCase
198
+ subject { Subject.new }
199
+
200
+ should "only build the subject once" do
201
+ assert_equal subject, subject
202
+ end
203
+ end
@@ -0,0 +1,63 @@
1
+ require 'test/unit'
2
+
3
+ class ConvertToShouldSyntaxTest < ActiveSupport::TestCase # :nodoc:
4
+
5
+ BEFORE_FIXTURE = <<-EOS
6
+ class DummyTest < ActiveSupport::TestCase
7
+
8
+ should "Not change this_word_with_underscores" do
9
+ end
10
+
11
+ def test_should_be_working
12
+ assert true
13
+ end
14
+
15
+ def test_some_cool_stuff
16
+ assert true
17
+ end
18
+
19
+ def non_test_method
20
+ end
21
+
22
+ end
23
+ EOS
24
+
25
+ AFTER_FIXTURE = <<-EOS
26
+ class DummyTest < ActiveSupport::TestCase
27
+
28
+ should "Not change this_word_with_underscores" do
29
+ end
30
+
31
+ should "be working" do
32
+ assert true
33
+ end
34
+
35
+ should "RENAME ME: test some cool stuff" do
36
+ assert true
37
+ end
38
+
39
+ def non_test_method
40
+ end
41
+
42
+ end
43
+ EOS
44
+
45
+ FIXTURE_PATH = "./convert_to_should_syntax_fixture.dat"
46
+
47
+ RUBY = ENV['RUBY'] || 'ruby'
48
+
49
+ def test_convert_to_should_syntax
50
+ File.open(FIXTURE_PATH, "w") {|f| f.write(BEFORE_FIXTURE)}
51
+ cmd = "#{RUBY} #{File.join(File.dirname(__FILE__), '../../bin/convert_to_should_syntax')} #{FIXTURE_PATH}"
52
+ output = `#{cmd}`
53
+ File.unlink($1) if output.match(/has been stored in '([^']+)/)
54
+ assert_match(/has been converted/, output)
55
+ result = IO.read(FIXTURE_PATH)
56
+ assert_equal result, AFTER_FIXTURE
57
+ end
58
+
59
+ def teardown
60
+ File.unlink(FIXTURE_PATH)
61
+ end
62
+
63
+ end
@@ -0,0 +1,340 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+ require 'action_mailer'
3
+ require 'mocha'
4
+
5
+ class HelpersTest < ActiveSupport::TestCase # :nodoc:
6
+
7
+ context "given delivered emails" do
8
+ setup do
9
+ email1 = stub(:subject => "one", :to => ["none1@email.com"])
10
+ email2 = stub(:subject => "two", :to => ["none2@email.com"])
11
+ ActionMailer::Base.stubs(:deliveries).returns([email1, email2])
12
+ end
13
+
14
+ should "have sent an email" do
15
+ assert_sent_email
16
+
17
+ assert_raises(Test::Unit::AssertionFailedError) do
18
+ assert_did_not_send_email
19
+ end
20
+ end
21
+
22
+ should "find email one" do
23
+ assert_sent_email do |e|
24
+ e.subject =~ /one/
25
+ end
26
+ end
27
+
28
+ should "not find an email that doesn't exist" do
29
+ assert_raises(Test::Unit::AssertionFailedError) do
30
+ assert_sent_email do |e|
31
+ e.subject =~ /whatever/
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ context "when there are no emails" do
38
+ setup do
39
+ ActionMailer::Base.stubs(:deliveries).returns([])
40
+ end
41
+
42
+ should "not have sent an email" do
43
+ assert_did_not_send_email
44
+
45
+ assert_raises(Test::Unit::AssertionFailedError) do
46
+ assert_sent_email
47
+ end
48
+ end
49
+ end
50
+
51
+ context "an array of values" do
52
+ setup do
53
+ @a = ['abc', 'def', 3]
54
+ end
55
+
56
+ [/b/, 'abc', 3].each do |x|
57
+ should "contain #{x.inspect}" do
58
+ assert_raises(Test::Unit::AssertionFailedError) do
59
+ assert_does_not_contain @a, x
60
+ end
61
+ assert_contains @a, x
62
+ end
63
+ end
64
+
65
+ should "not contain 'wtf'" do
66
+ assert_raises(Test::Unit::AssertionFailedError) {assert_contains @a, 'wtf'}
67
+ assert_does_not_contain @a, 'wtf'
68
+ end
69
+
70
+ should "be the same as another array, ordered differently" do
71
+ assert_same_elements(@a, [3, "def", "abc"])
72
+ assert_raises(Test::Unit::AssertionFailedError) do
73
+ assert_same_elements(@a, [3, 3, "def", "abc"])
74
+ end
75
+ assert_raises(Test::Unit::AssertionFailedError) do
76
+ assert_same_elements([@a, "abc"].flatten, [3, 3, "def", "abc"])
77
+ end
78
+ end
79
+ end
80
+
81
+ context "an array of values" do
82
+ setup do
83
+ @a = [1, 2, "(3)"]
84
+ end
85
+
86
+ context "after adding another value" do
87
+ setup do
88
+ @a.push(4)
89
+ end
90
+
91
+ should_change("the number of elements", :by => 1) { @a.length }
92
+ should_change("the number of elements", :from => 3) { @a.length }
93
+ should_change("the number of elements", :to => 4) { @a.length }
94
+ should_change("the first element", :by => 0) { @a[0] }
95
+ should_not_change("the first element") { @a[0] }
96
+
97
+ # tests for deprecated behavior
98
+ should_change "@a.length", :by => 1
99
+ should_change "@a.length", :from => 3
100
+ should_change "@a.length", :to => 4
101
+ should_change "@a[0]", :by => 0
102
+ should_not_change "@a[0]"
103
+ end
104
+
105
+ context "after replacing it with an array of strings" do
106
+ setup do
107
+ @a = %w(a b c d e f)
108
+ end
109
+
110
+ should_change("the number of elements", :by => 3) { @a.length }
111
+ should_change("the number of elements", :from => 3, :to => 6, :by => 3) { @a.length }
112
+ should_change("the first element") { @a[0] }
113
+ should_change("the second element", :from => 2, :to => "b") { @a[1] }
114
+ should_change("the third element", :from => /\d/, :to => /\w/) { @a[2] }
115
+ should_change("the last element", :to => String) { @a[3] }
116
+
117
+ # tests for deprecated behavior
118
+ should_change "@a.length", :by => 3
119
+ should_change "@a.length", :from => 3, :to => 6, :by => 3
120
+ should_change "@a[0]"
121
+ should_change "@a[1]", :from => 2, :to => "b"
122
+ should_change "@a[2]", :from => /\d/, :to => /\w/
123
+ should_change "@a[3]", :to => String
124
+ end
125
+ end
126
+
127
+ context "assert_good_value" do
128
+ should "validate a good email address" do
129
+ assert_good_value User.new, :email, "good@example.com"
130
+ end
131
+
132
+ should "validate a good SSN with a custom message" do
133
+ assert_good_value User.new, :ssn, "xxxxxxxxx", /length/
134
+ end
135
+
136
+ should "fail to validate a bad email address" do
137
+ assert_raises Test::Unit::AssertionFailedError do
138
+ assert_good_value User.new, :email, "bad"
139
+ end
140
+ end
141
+
142
+ should "fail to validate a bad SSN that is too short" do
143
+ assert_raises Test::Unit::AssertionFailedError do
144
+ assert_good_value User.new, :ssn, "x", /length/
145
+ end
146
+ end
147
+
148
+ should "accept a class as the first argument" do
149
+ assert_good_value User, :email, "good@example.com"
150
+ end
151
+
152
+ context "with an instance variable" do
153
+ setup do
154
+ @product = Product.new(:tangible => true)
155
+ end
156
+
157
+ should "use that instance variable" do
158
+ assert_good_value Product, :price, "9999", /included/
159
+ end
160
+ end
161
+ end
162
+
163
+ context "assert_bad_value" do
164
+ should "invalidate a bad email address" do
165
+ assert_bad_value User.new, :email, "bad"
166
+ end
167
+
168
+ should "invalidate a bad SSN with a custom message" do
169
+ assert_bad_value User.new, :ssn, "x", /length/
170
+ end
171
+
172
+ should "fail to invalidate a good email address" do
173
+ assert_raises Test::Unit::AssertionFailedError do
174
+ assert_bad_value User.new, :email, "good@example.com"
175
+ end
176
+ end
177
+
178
+ should "fail to invalidate a good SSN" do
179
+ assert_raises Test::Unit::AssertionFailedError do
180
+ assert_bad_value User.new, :ssn, "xxxxxxxxx", /length/
181
+ end
182
+ end
183
+
184
+ should "accept a class as the first argument" do
185
+ assert_bad_value User, :email, "bad"
186
+ end
187
+
188
+ context "with an instance variable" do
189
+ setup do
190
+ @product = Product.new(:tangible => true)
191
+ end
192
+
193
+ should "use that instance variable" do
194
+ assert_bad_value Product, :price, "0", /included/
195
+ end
196
+ end
197
+ end
198
+
199
+ context "a matching matcher" do
200
+ setup do
201
+ @matcher = stub('matcher', :matches? => true,
202
+ :failure_message => 'bad failure message',
203
+ :negative_failure_message => 'big time failure')
204
+ end
205
+
206
+ should "pass when given to assert_accepts with no message expectation" do
207
+ assert_accepts @matcher, 'target'
208
+ end
209
+
210
+ should "pass when given to assert_accepts with a matching message" do
211
+ assert_accepts @matcher, 'target', :message => /big time/
212
+ end
213
+
214
+ should "fail when given to assert_accepts with non-matching message" do
215
+ assert_raise Test::Unit::AssertionFailedError do
216
+ assert_accepts @matcher, 'target', :message => /small time/
217
+ end
218
+ end
219
+
220
+ context "when given to assert_rejects" do
221
+ setup do
222
+ begin
223
+ assert_rejects @matcher, 'target'
224
+ rescue Test::Unit::AssertionFailedError => @error
225
+ end
226
+ end
227
+
228
+ should "fail" do
229
+ assert_not_nil @error
230
+ end
231
+
232
+ should "use the error message from the matcher" do
233
+ assert_equal 'big time failure', @error.message
234
+ end
235
+ end
236
+ end
237
+
238
+ context "a non-matching matcher" do
239
+ setup do
240
+ @matcher = stub('matcher', :matches? => false,
241
+ :failure_message => 'big time failure',
242
+ :negative_failure_message => 'bad failure message')
243
+ end
244
+
245
+ should "pass when given to assert_rejects with no message expectation" do
246
+ assert_rejects @matcher, 'target'
247
+ end
248
+
249
+ should "pass when given to assert_rejects with a matching message" do
250
+ assert_rejects @matcher, 'target', :message => /big time/
251
+ end
252
+
253
+ should "fail when given to assert_rejects with a non-matching message" do
254
+ assert_raise Test::Unit::AssertionFailedError do
255
+ assert_rejects @matcher, 'target', :message => /small time/
256
+ end
257
+ end
258
+
259
+ context "when given to assert_accepts" do
260
+ setup do
261
+ begin
262
+ assert_accepts @matcher, 'target'
263
+ rescue Test::Unit::AssertionFailedError => @error
264
+ end
265
+ end
266
+
267
+ should "fail" do
268
+ assert_not_nil @error
269
+ end
270
+
271
+ should "use the error message from the matcher" do
272
+ assert_equal 'big time failure', @error.message
273
+ end
274
+ end
275
+ end
276
+
277
+ context "given one treat exists and one post exists" do
278
+ setup do
279
+ Treat.create!
280
+ Post.create!(:title => 'title', :body => 'body', :user_id => 1)
281
+ end
282
+
283
+ teardown do
284
+ Treat.delete_all
285
+ Post.delete_all
286
+ end
287
+
288
+ context "creating a treat" do
289
+ setup do
290
+ Treat.create!
291
+ end
292
+
293
+ should_create :treat
294
+ should_fail do
295
+ should_create :post
296
+ end
297
+ end
298
+
299
+ context "creating a treat and a post" do
300
+ setup do
301
+ Treat.create!
302
+ Post.create!(:title => 'title 2', :body => 'body', :user_id => 1)
303
+ end
304
+
305
+ should_create :treat
306
+ should_create :post
307
+ end
308
+
309
+ context "destroying a treat" do
310
+ setup do
311
+ Treat.first.destroy
312
+ end
313
+
314
+ should_destroy :treat
315
+ should_fail do
316
+ should_destroy :post
317
+ end
318
+ end
319
+
320
+ context "destroying a treat and a post" do
321
+ setup do
322
+ Treat.first.destroy
323
+ Post.first.destroy
324
+ end
325
+
326
+ should_destroy :treat
327
+ should_destroy :post
328
+ end
329
+
330
+ context "doing nothing" do
331
+ should_fail do
332
+ should_create :treat
333
+ end
334
+
335
+ should_fail do
336
+ should_destroy :treat
337
+ end
338
+ end
339
+ end
340
+ end