shoulda 2.10.3 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (233) hide show
  1. data/Rakefile +8 -27
  2. data/lib/shoulda.rb +1 -3
  3. data/lib/shoulda/action_controller.rb +8 -0
  4. data/lib/shoulda/action_controller/macros.rb +54 -73
  5. data/lib/shoulda/action_controller/matchers.rb +2 -0
  6. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +9 -6
  7. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +18 -1
  8. data/lib/shoulda/action_controller/matchers/redirect_to_matcher.rb +62 -0
  9. data/lib/shoulda/action_controller/matchers/render_template_matcher.rb +54 -0
  10. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +33 -15
  11. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +1 -1
  12. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +5 -1
  13. data/lib/shoulda/action_controller/matchers/route_matcher.rb +1 -1
  14. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +13 -2
  15. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +1 -1
  16. data/lib/shoulda/action_mailer.rb +3 -0
  17. data/lib/shoulda/action_mailer/assertions.rb +4 -0
  18. data/lib/shoulda/action_mailer/matchers.rb +22 -0
  19. data/lib/shoulda/action_mailer/matchers/have_sent_email.rb +119 -0
  20. data/lib/shoulda/active_record/helpers.rb +6 -1
  21. data/lib/shoulda/active_record/macros.rb +86 -141
  22. data/lib/shoulda/active_record/matchers.rb +0 -1
  23. data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +1 -1
  24. data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +10 -2
  25. data/lib/shoulda/assertions.rb +8 -0
  26. data/lib/shoulda/context.rb +52 -32
  27. data/lib/shoulda/macros.rb +16 -18
  28. data/lib/shoulda/rails.rb +0 -5
  29. data/lib/shoulda/rspec.rb +2 -0
  30. data/lib/shoulda/version.rb +4 -0
  31. data/rails/init.rb +1 -0
  32. data/test/fail_macros.rb +20 -4
  33. data/test/functional/posts_controller_test.rb +7 -7
  34. data/test/functional/users_controller_test.rb +1 -1
  35. data/test/matchers/action_mailer/have_sent_email_test.rb +53 -0
  36. data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +7 -1
  37. data/test/matchers/active_record/allow_value_matcher_test.rb +1 -1
  38. data/test/matchers/active_record/association_matcher_test.rb +16 -16
  39. data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +3 -2
  40. data/test/matchers/active_record/ensure_length_of_matcher_test.rb +1 -1
  41. data/test/matchers/active_record/have_db_column_matcher_test.rb +1 -1
  42. data/test/matchers/active_record/have_db_index_matcher_test.rb +1 -1
  43. data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +1 -1
  44. data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +1 -1
  45. data/test/matchers/active_record/validate_format_of_matcher_test.rb +1 -1
  46. data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +1 -1
  47. data/test/matchers/active_record/validate_presence_of_matcher_test.rb +1 -1
  48. data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +1 -1
  49. data/test/matchers/controller/assign_to_matcher_test.rb +11 -1
  50. data/test/matchers/controller/filter_param_matcher_test.rb +10 -2
  51. data/test/matchers/controller/redirect_to_matcher_test.rb +37 -0
  52. data/test/matchers/controller/render_template_matcher_test.rb +37 -0
  53. data/test/matchers/controller/render_with_layout_matcher_test.rb +15 -1
  54. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +1 -1
  55. data/test/matchers/controller/respond_with_matcher_test.rb +1 -11
  56. data/test/matchers/controller/route_matcher_test.rb +1 -1
  57. data/test/matchers/controller/set_session_matcher_test.rb +11 -1
  58. data/test/matchers/controller/set_the_flash_matcher.rb +1 -1
  59. data/test/other/autoload_macro_test.rb +1 -1
  60. data/test/other/context_test.rb +177 -8
  61. data/test/other/helpers_test.rb +13 -36
  62. data/test/other/private_helpers_test.rb +1 -1
  63. data/test/other/should_test.rb +1 -1
  64. data/test/{model_builder.rb → rails2_model_builder.rb} +28 -4
  65. data/test/{rails_root → rails2_root}/app/controllers/application_controller.rb +0 -3
  66. data/test/{rails_root → rails2_root}/app/controllers/posts_controller.rb +0 -0
  67. data/test/{rails_root → rails2_root}/app/controllers/users_controller.rb +0 -0
  68. data/test/{rails_root → rails2_root}/app/helpers/application_helper.rb +0 -0
  69. data/test/{rails_root → rails2_root}/app/helpers/posts_helper.rb +0 -0
  70. data/test/{rails_root → rails2_root}/app/helpers/users_helper.rb +0 -0
  71. data/test/{rails_root → rails2_root}/app/models/address.rb +0 -0
  72. data/test/rails2_root/app/models/flea.rb +11 -0
  73. data/test/{rails_root → rails2_root}/app/models/friendship.rb +0 -0
  74. data/test/rails2_root/app/models/notifier.rb +8 -0
  75. data/test/{rails_root → rails2_root}/app/models/pets/cat.rb +0 -0
  76. data/test/{rails_root → rails2_root}/app/models/pets/dog.rb +0 -0
  77. data/test/{rails_root → rails2_root}/app/models/post.rb +0 -0
  78. data/test/{rails_root → rails2_root}/app/models/product.rb +0 -0
  79. data/test/{rails_root → rails2_root}/app/models/profile.rb +0 -0
  80. data/test/{rails_root → rails2_root}/app/models/registration.rb +0 -0
  81. data/test/{rails_root → rails2_root}/app/models/tag.rb +0 -0
  82. data/test/{rails_root → rails2_root}/app/models/tagging.rb +0 -0
  83. data/test/{rails_root → rails2_root}/app/models/treat.rb +0 -0
  84. data/test/{rails_root → rails2_root}/app/models/user.rb +0 -0
  85. data/test/{rails_root → rails2_root}/app/views/layouts/posts.rhtml +0 -0
  86. data/test/{rails_root → rails2_root}/app/views/layouts/users.rhtml +0 -0
  87. data/test/{rails_root → rails2_root}/app/views/layouts/wide.html.erb +0 -0
  88. data/test/rails2_root/app/views/notifier/the_email.html.erb +1 -0
  89. data/test/{rails_root → rails2_root}/app/views/posts/edit.rhtml +0 -0
  90. data/test/{rails_root → rails2_root}/app/views/posts/index.rhtml +0 -0
  91. data/test/{rails_root → rails2_root}/app/views/posts/new.rhtml +0 -0
  92. data/test/{rails_root → rails2_root}/app/views/posts/show.rhtml +0 -0
  93. data/test/{rails_root → rails2_root}/app/views/users/edit.rhtml +0 -0
  94. data/test/{rails_root → rails2_root}/app/views/users/index.rhtml +0 -0
  95. data/test/{rails_root → rails2_root}/app/views/users/new.rhtml +0 -0
  96. data/test/{rails_root → rails2_root}/app/views/users/show.rhtml +0 -0
  97. data/test/{rails_root → rails2_root}/config/boot.rb +0 -0
  98. data/test/{rails_root → rails2_root}/config/database.yml +1 -1
  99. data/test/{rails_root → rails2_root}/config/environment.rb +0 -1
  100. data/test/rails2_root/config/environments/test.rb +23 -0
  101. data/test/{rails_root → rails2_root}/config/initializers/new_rails_defaults.rb +0 -0
  102. data/test/{rails_root → rails2_root}/config/initializers/shoulda.rb +0 -0
  103. data/test/{rails_root → rails2_root}/config/routes.rb +0 -0
  104. data/test/{rails_root → rails2_root}/db/migrate/001_create_users.rb +0 -0
  105. data/test/{rails_root → rails2_root}/db/migrate/002_create_posts.rb +0 -0
  106. data/test/{rails_root → rails2_root}/db/migrate/003_create_taggings.rb +0 -0
  107. data/test/{rails_root → rails2_root}/db/migrate/004_create_tags.rb +0 -0
  108. data/test/{rails_root → rails2_root}/db/migrate/005_create_dogs.rb +0 -0
  109. data/test/{rails_root → rails2_root}/db/migrate/006_create_addresses.rb +0 -0
  110. data/test/{rails_root → rails2_root}/db/migrate/007_create_fleas.rb +0 -0
  111. data/test/{rails_root → rails2_root}/db/migrate/008_create_dogs_fleas.rb +0 -0
  112. data/test/{rails_root → rails2_root}/db/migrate/009_create_products.rb +0 -0
  113. data/test/{rails_root → rails2_root}/db/migrate/010_create_friendships.rb +0 -0
  114. data/test/{rails_root → rails2_root}/db/migrate/011_create_treats.rb +0 -0
  115. data/test/{rails_root → rails2_root}/db/migrate/20090506203502_create_profiles.rb +0 -0
  116. data/test/{rails_root → rails2_root}/db/migrate/20090506203536_create_registrations.rb +0 -0
  117. data/test/{rails_root → rails2_root}/db/migrate/20090513104502_create_cats.rb +0 -0
  118. data/test/{rails_root → rails2_root}/db/schema.rb +0 -0
  119. data/test/rails2_root/log/test.log +121771 -0
  120. data/test/{rails_root → rails2_root}/public/404.html +0 -0
  121. data/test/{rails_root → rails2_root}/public/422.html +0 -0
  122. data/test/{rails_root → rails2_root}/public/500.html +0 -0
  123. data/test/{rails_root → rails2_root}/script/console +0 -0
  124. data/test/{rails_root → rails2_root}/script/generate +0 -0
  125. data/test/{rails_root → rails2_root}/test/shoulda_macros/custom_macro.rb +0 -0
  126. data/test/{rails_root → rails2_root}/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +0 -0
  127. data/test/{rails_root → rails2_root}/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +0 -0
  128. data/test/rails2_test_helper.rb +6 -0
  129. data/test/rails3_model_builder.rb +118 -0
  130. data/test/rails3_root/Gemfile +28 -0
  131. data/test/rails3_root/README +244 -0
  132. data/test/rails3_root/Rakefile +10 -0
  133. data/test/rails3_root/app/controllers/application_controller.rb +22 -0
  134. data/test/rails3_root/app/controllers/posts_controller.rb +87 -0
  135. data/test/rails3_root/app/controllers/users_controller.rb +82 -0
  136. data/test/rails3_root/app/helpers/application_helper.rb +2 -0
  137. data/test/rails3_root/app/models/address.rb +7 -0
  138. data/test/rails3_root/app/models/flea.rb +11 -0
  139. data/test/rails3_root/app/models/friendship.rb +4 -0
  140. data/test/rails3_root/app/models/notifier.rb +8 -0
  141. data/test/rails3_root/app/models/pets/cat.rb +7 -0
  142. data/test/rails3_root/app/models/pets/dog.rb +10 -0
  143. data/test/rails3_root/app/models/post.rb +12 -0
  144. data/test/rails3_root/app/models/product.rb +12 -0
  145. data/test/rails3_root/app/models/profile.rb +2 -0
  146. data/test/rails3_root/app/models/registration.rb +2 -0
  147. data/test/rails3_root/app/models/tag.rb +8 -0
  148. data/test/rails3_root/app/models/tagging.rb +4 -0
  149. data/test/rails3_root/app/models/treat.rb +3 -0
  150. data/test/rails3_root/app/models/user.rb +32 -0
  151. data/test/rails3_root/app/views/layouts/application.html.erb +14 -0
  152. data/test/rails3_root/app/views/layouts/posts.rhtml +19 -0
  153. data/test/rails3_root/app/views/layouts/users.rhtml +17 -0
  154. data/test/rails3_root/app/views/layouts/wide.html.erb +1 -0
  155. data/test/rails3_root/app/views/notifier/the_email.html.erb +1 -0
  156. data/test/rails3_root/app/views/posts/edit.rhtml +27 -0
  157. data/test/rails3_root/app/views/posts/index.rhtml +25 -0
  158. data/test/rails3_root/app/views/posts/new.rhtml +24 -0
  159. data/test/rails3_root/app/views/posts/show.rhtml +18 -0
  160. data/test/rails3_root/app/views/users/edit.rhtml +22 -0
  161. data/test/rails3_root/app/views/users/index.rhtml +22 -0
  162. data/test/rails3_root/app/views/users/new.rhtml +21 -0
  163. data/test/rails3_root/app/views/users/show.rhtml +13 -0
  164. data/test/rails3_root/config.ru +4 -0
  165. data/test/rails3_root/config/application.rb +46 -0
  166. data/test/rails3_root/config/boot.rb +6 -0
  167. data/test/rails3_root/config/database.yml +22 -0
  168. data/test/rails3_root/config/environment.rb +5 -0
  169. data/test/rails3_root/config/environments/development.rb +19 -0
  170. data/test/rails3_root/config/environments/production.rb +42 -0
  171. data/test/rails3_root/config/environments/test.rb +32 -0
  172. data/test/rails3_root/config/initializers/backtrace_silencers.rb +7 -0
  173. data/test/rails3_root/config/initializers/inflections.rb +10 -0
  174. data/test/rails3_root/config/initializers/mime_types.rb +5 -0
  175. data/test/rails3_root/config/initializers/secret_token.rb +7 -0
  176. data/test/rails3_root/config/initializers/session_store.rb +8 -0
  177. data/test/rails3_root/config/locales/en.yml +5 -0
  178. data/test/rails3_root/config/routes.rb +4 -0
  179. data/test/rails3_root/db/migrate/001_create_users.rb +19 -0
  180. data/test/rails3_root/db/migrate/002_create_posts.rb +13 -0
  181. data/test/rails3_root/db/migrate/003_create_taggings.rb +12 -0
  182. data/test/rails3_root/db/migrate/004_create_tags.rb +11 -0
  183. data/test/rails3_root/db/migrate/005_create_dogs.rb +12 -0
  184. data/test/rails3_root/db/migrate/006_create_addresses.rb +14 -0
  185. data/test/rails3_root/db/migrate/007_create_fleas.rb +11 -0
  186. data/test/rails3_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  187. data/test/rails3_root/db/migrate/009_create_products.rb +17 -0
  188. data/test/rails3_root/db/migrate/010_create_friendships.rb +14 -0
  189. data/test/rails3_root/db/migrate/011_create_treats.rb +12 -0
  190. data/test/rails3_root/db/migrate/20090506203502_create_profiles.rb +12 -0
  191. data/test/rails3_root/db/migrate/20090506203536_create_registrations.rb +14 -0
  192. data/test/rails3_root/db/migrate/20090513104502_create_cats.rb +12 -0
  193. data/test/rails3_root/db/seeds.rb +7 -0
  194. data/test/rails3_root/db/test.sqlite3 +0 -0
  195. data/test/rails3_root/doc/README_FOR_APP +2 -0
  196. data/test/{rails_root/config/environments/test.rb → rails3_root/log/development.log} +0 -0
  197. data/test/rails3_root/log/production.log +0 -0
  198. data/test/rails3_root/log/server.log +0 -0
  199. data/test/rails3_root/log/test.log +63274 -0
  200. data/test/rails3_root/public/404.html +26 -0
  201. data/test/rails3_root/public/422.html +26 -0
  202. data/test/rails3_root/public/500.html +26 -0
  203. data/test/rails3_root/public/favicon.ico +0 -0
  204. data/test/rails3_root/public/images/rails.png +0 -0
  205. data/test/rails3_root/public/index.html +279 -0
  206. data/test/rails3_root/public/javascripts/application.js +2 -0
  207. data/test/rails3_root/public/javascripts/controls.js +965 -0
  208. data/test/rails3_root/public/javascripts/dragdrop.js +974 -0
  209. data/test/rails3_root/public/javascripts/effects.js +1123 -0
  210. data/test/rails3_root/public/javascripts/prototype.js +4874 -0
  211. data/test/rails3_root/public/javascripts/rails.js +118 -0
  212. data/test/rails3_root/public/robots.txt +5 -0
  213. data/test/rails3_root/script/rails +9 -0
  214. data/test/rails3_root/test/performance/browsing_test.rb +9 -0
  215. data/test/rails3_root/test/test_helper.rb +13 -0
  216. data/test/rails3_test_helper.rb +6 -0
  217. data/test/test_helper.rb +16 -8
  218. data/test/unit/address_test.rb +1 -1
  219. data/test/unit/cat_test.rb +1 -1
  220. data/test/unit/dog_test.rb +1 -1
  221. data/test/unit/flea_test.rb +9 -1
  222. data/test/unit/friendship_test.rb +1 -1
  223. data/test/unit/post_test.rb +1 -5
  224. data/test/unit/product_test.rb +1 -1
  225. data/test/unit/tag_test.rb +1 -5
  226. data/test/unit/tagging_test.rb +1 -1
  227. data/test/unit/user_test.rb +3 -37
  228. metadata +180 -73
  229. data/lib/shoulda/action_view.rb +0 -10
  230. data/lib/shoulda/action_view/macros.rb +0 -61
  231. data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +0 -128
  232. data/test/matchers/active_record/have_named_scope_matcher_test.rb +0 -65
  233. data/test/rails_root/app/models/flea.rb +0 -3
@@ -13,7 +13,6 @@ require 'shoulda/active_record/matchers/have_db_column_matcher'
13
13
  require 'shoulda/active_record/matchers/have_db_index_matcher'
14
14
  require 'shoulda/active_record/matchers/have_readonly_attribute_matcher'
15
15
  require 'shoulda/active_record/matchers/allow_mass_assignment_of_matcher'
16
- require 'shoulda/active_record/matchers/have_named_scope_matcher'
17
16
 
18
17
 
19
18
  module Shoulda # :nodoc:
@@ -24,7 +24,7 @@ module Shoulda # :nodoc:
24
24
  @failure_message = "#{@attribute} was made accessible"
25
25
  else
26
26
  if protected_attributes.empty?
27
- @failure_message = "no attributes were protected"
27
+ @negative_failure_message = "no attributes were protected"
28
28
  else
29
29
  @failure_message = "#{class_name} is protecting " <<
30
30
  "#{protected_attributes.to_a.to_sentence}, " <<
@@ -59,9 +59,17 @@ module Shoulda # :nodoc:
59
59
 
60
60
  def errors_match?
61
61
  @instance.valid?
62
- @errors = @instance.errors.on(@attribute)
62
+ @errors = errors_for_attribute(@instance, @attribute)
63
63
  @errors = [@errors] unless @errors.is_a?(Array)
64
- @expected_message ? (errors_match_regexp? || errors_match_string?) : (@errors != [nil])
64
+ @expected_message ? (errors_match_regexp? || errors_match_string?) : (@errors.compact.any?)
65
+ end
66
+
67
+ def errors_for_attribute(instance, attribute)
68
+ if instance.errors.respond_to?(:[])
69
+ instance.errors[attribute]
70
+ else
71
+ instance.errors.on(attribute)
72
+ end
65
73
  end
66
74
 
67
75
  def errors_match_regexp?
@@ -46,6 +46,10 @@ module Shoulda # :nodoc:
46
46
 
47
47
  # Asserts that the given matcher returns true when +target+ is passed to #matches?
48
48
  def assert_accepts(matcher, target, options = {})
49
+ if matcher.respond_to?(:in_context)
50
+ matcher.in_context(self)
51
+ end
52
+
49
53
  if matcher.matches?(target)
50
54
  assert_block { true }
51
55
  if options[:message]
@@ -58,6 +62,10 @@ module Shoulda # :nodoc:
58
62
 
59
63
  # Asserts that the given matcher returns false when +target+ is passed to #matches?
60
64
  def assert_rejects(matcher, target, options = {})
65
+ if matcher.respond_to?(:in_context)
66
+ matcher.in_context(self)
67
+ end
68
+
61
69
  unless matcher.matches?(target)
62
70
  assert_block { true }
63
71
  if options[:message]
@@ -21,9 +21,10 @@ module Shoulda
21
21
  module ClassMethods
22
22
  # == Should statements
23
23
  #
24
- # Should statements are just syntactic sugar over normal Test::Unit test methods. A should block
25
- # contains all the normal code and assertions you're used to seeing, with the added benefit that
26
- # they can be wrapped inside context blocks (see below).
24
+ # Should statements are just syntactic sugar over normal Test::Unit test
25
+ # methods. A should block contains all the normal code and assertions
26
+ # you're used to seeing, with the added benefit that they can be wrapped
27
+ # inside context blocks (see below).
27
28
  #
28
29
  # === Example:
29
30
  #
@@ -56,14 +57,43 @@ module Shoulda
56
57
  # assert true
57
58
  # end
58
59
  # end
60
+ #
61
+ # Should statements can also wrap matchers, making virtually any matcher
62
+ # usable in a macro style. The matcher's description is used to generate a
63
+ # test name and failure message, and the test will pass if the matcher
64
+ # matches the subject.
65
+ #
66
+ # === Example:
67
+ #
68
+ # should validate_presence_of(:first_name).with_message(/gotta be there/)
69
+ #
70
+
71
+ def should(name_or_matcher, options = {}, &blk)
72
+ if Shoulda.current_context
73
+ Shoulda.current_context.should(name_or_matcher, options, &blk)
74
+ else
75
+ context_name = self.name.gsub(/Test/, "")
76
+ context = Shoulda::Context.new(context_name, self) do
77
+ should(name_or_matcher, options, &blk)
78
+ end
79
+ context.build
80
+ end
81
+ end
59
82
 
60
- def should(name, options = {}, &blk)
83
+ # Allows negative tests using matchers. The matcher's description is used
84
+ # to generate a test name and negative failure message, and the test will
85
+ # pass unless the matcher matches the subject.
86
+ #
87
+ # === Example:
88
+ #
89
+ # should_not set_the_flash
90
+ def should_not(matcher)
61
91
  if Shoulda.current_context
62
- block_given? ? Shoulda.current_context.should(name, options, &blk) : Shoulda.current_context.should_eventually(name)
92
+ Shoulda.current_context.should_not(matcher)
63
93
  else
64
94
  context_name = self.name.gsub(/Test/, "")
65
95
  context = Shoulda::Context.new(context_name, self) do
66
- block_given? ? should(name, options, &blk) : should_eventually(name)
96
+ should_not(matcher)
67
97
  end
68
98
  context.build
69
99
  end
@@ -214,19 +244,6 @@ module Shoulda
214
244
  # end
215
245
  # end
216
246
  #
217
- # If an instance variable exists named after the described class, that
218
- # instance variable will be used as the subject. This behavior is
219
- # deprecated, and will be removed in a future version of Shoulda. The
220
- # recommended approach for using a different subject is to use the subject
221
- # class method.
222
- #
223
- # class UserTest
224
- # should "be the existing user" do
225
- # @user = User.new
226
- # assert_equal @user, subject # passes
227
- # end
228
- # end
229
- #
230
247
  # The subject is used by all macros that require an instance of the class
231
248
  # being tested.
232
249
  def subject
@@ -239,17 +256,7 @@ module Shoulda
239
256
 
240
257
  def get_instance_of(object_or_klass) # :nodoc:
241
258
  if object_or_klass.is_a?(Class)
242
- klass = object_or_klass
243
- ivar = "@#{instance_variable_name_for(klass)}"
244
- if instance = instance_variable_get(ivar)
245
- warn "[WARNING] Using #{ivar} as the subject. Future versions " <<
246
- "of Shoulda will require an explicit subject using the " <<
247
- "subject class method. Add this after your setup to avoid " <<
248
- "this warning: subject { #{ivar} }"
249
- instance
250
- else
251
- klass.new
252
- end
259
+ object_or_klass.new
253
260
  else
254
261
  object_or_klass
255
262
  end
@@ -311,14 +318,27 @@ module Shoulda
311
318
  self.teardown_blocks << blk
312
319
  end
313
320
 
314
- def should(name, options = {}, &blk)
315
- if block_given?
321
+ def should(name_or_matcher, options = {}, &blk)
322
+ if name_or_matcher.respond_to?(:description) && name_or_matcher.respond_to?(:matches?)
323
+ name = name_or_matcher.description
324
+ blk = lambda { assert_accepts name_or_matcher, subject }
325
+ else
326
+ name = name_or_matcher
327
+ end
328
+
329
+ if blk
316
330
  self.shoulds << { :name => name, :before => options[:before], :block => blk }
317
331
  else
318
332
  self.should_eventuallys << { :name => name }
319
333
  end
320
334
  end
321
335
 
336
+ def should_not(matcher)
337
+ name = matcher.description
338
+ blk = lambda { assert_rejects matcher, subject }
339
+ self.shoulds << { :name => "not #{name}", :block => blk }
340
+ end
341
+
322
342
  def should_eventually(name, &blk)
323
343
  self.should_eventuallys << { :name => name, :block => blk }
324
344
  end
@@ -2,6 +2,8 @@ require 'shoulda/private_helpers'
2
2
 
3
3
  module Shoulda # :nodoc:
4
4
  module Macros
5
+ # Deprecated.
6
+ #
5
7
  # Macro that creates a test asserting a change between the return value
6
8
  # of a block that is run before and after the current setup block
7
9
  # is run. This is similar to Active Support's <tt>assert_difference</tt>
@@ -35,23 +37,17 @@ module Shoulda # :nodoc:
35
37
  # # Assert the value changed to "new:"
36
38
  # should_change("the post title", :to => "new") { @post.title }
37
39
  def should_change(description, options = {}, &block)
40
+ ::ActiveSupport::Deprecation.warn
38
41
  by, from, to = get_options!([options], :by, :from, :to)
39
42
  stmt = "change #{description}"
40
43
  stmt << " from #{from.inspect}" if from
41
44
  stmt << " to #{to.inspect}" if to
42
45
  stmt << " by #{by.inspect}" if by
43
46
 
44
- if block_given?
45
- code = block
46
- else
47
- warn "[DEPRECATION] should_change(expression, options) is deprecated. " <<
48
- "Use should_change(description, options) { code } instead."
49
- code = lambda { eval(description) }
50
- end
51
- before = lambda { @_before_should_change = code.bind(self).call }
47
+ before = lambda { @_before_should_change = block.bind(self).call }
52
48
  should stmt, :before => before do
53
49
  old_value = @_before_should_change
54
- new_value = code.bind(self).call
50
+ new_value = block.bind(self).call
55
51
  assert_operator from, :===, old_value, "#{description} did not originally match #{from.inspect}" if from
56
52
  assert_not_equal old_value, new_value, "#{description} did not change" unless by == 0
57
53
  assert_operator to, :===, new_value, "#{description} was not changed to match #{to.inspect}" if to
@@ -59,6 +55,8 @@ module Shoulda # :nodoc:
59
55
  end
60
56
  end
61
57
 
58
+ # Deprecated.
59
+ #
62
60
  # Macro that creates a test asserting no change between the return value
63
61
  # of a block that is run before and after the current setup block
64
62
  # is run. This is the logical opposite of should_change.
@@ -72,20 +70,16 @@ module Shoulda # :nodoc:
72
70
  # should_not_change("the number of posts") { Post.count }
73
71
  # end
74
72
  def should_not_change(description, &block)
75
- if block_given?
76
- code = block
77
- else
78
- warn "[DEPRECATION] should_not_change(expression) is deprecated. " <<
79
- "Use should_not_change(description) { code } instead."
80
- code = lambda { eval(description) }
81
- end
82
- before = lambda { @_before_should_not_change = code.bind(self).call }
73
+ ::ActiveSupport::Deprecation.warn
74
+ before = lambda { @_before_should_not_change = block.bind(self).call }
83
75
  should "not change #{description}", :before => before do
84
- new_value = code.bind(self).call
76
+ new_value = block.bind(self).call
85
77
  assert_equal @_before_should_not_change, new_value, "#{description} changed"
86
78
  end
87
79
  end
88
80
 
81
+ # Deprecated.
82
+ #
89
83
  # Macro that creates a test asserting that a record of the given class was
90
84
  # created.
91
85
  #
@@ -96,9 +90,12 @@ module Shoulda # :nodoc:
96
90
  # should_create :post
97
91
  # end
98
92
  def should_create(class_name)
93
+ ::ActiveSupport::Deprecation.warn
99
94
  should_change_record_count_of(class_name, 1, 'create')
100
95
  end
101
96
 
97
+ # Deprecated.
98
+ #
102
99
  # Macro that creates a test asserting that a record of the given class was
103
100
  # destroyed.
104
101
  #
@@ -109,6 +106,7 @@ module Shoulda # :nodoc:
109
106
  # should_destroy :post
110
107
  # end
111
108
  def should_destroy(class_name)
109
+ ::ActiveSupport::Deprecation.warn
112
110
  should_change_record_count_of(class_name, -1, 'destroy')
113
111
  end
114
112
 
@@ -4,10 +4,5 @@ require 'shoulda'
4
4
 
5
5
  require 'shoulda/active_record' if defined? ActiveRecord::Base
6
6
  require 'shoulda/action_controller' if defined? ActionController::Base
7
- require 'shoulda/action_view' if defined? ActionView::Base
8
7
  require 'shoulda/action_mailer' if defined? ActionMailer::Base
9
8
 
10
- if defined?(RAILS_ROOT)
11
- # load in the 3rd party macros from vendorized plugins and gems
12
- Shoulda.autoload_macros RAILS_ROOT, File.join("vendor", "{plugins,gems}", "*")
13
- end
@@ -1,5 +1,6 @@
1
1
  require 'shoulda/active_record/matchers'
2
2
  require 'shoulda/action_controller/matchers'
3
+ require 'shoulda/action_mailer/matchers'
3
4
  require 'active_support/test_case'
4
5
 
5
6
  # :enddoc:
@@ -7,5 +8,6 @@ module ActiveSupport
7
8
  class TestCase
8
9
  include Shoulda::ActiveRecord::Matchers
9
10
  include Shoulda::ActionController::Matchers
11
+ include Shoulda::ActionMailer::Matchers
10
12
  end
11
13
  end
@@ -0,0 +1,4 @@
1
+ module Shoulda
2
+ VERSION = "2.11.0"
3
+ end
4
+
@@ -3,5 +3,6 @@ if RAILS_ENV == 'test'
3
3
  require 'shoulda/rspec'
4
4
  else
5
5
  require 'shoulda/rails'
6
+ Shoulda.autoload_macros RAILS_ROOT, File.join("vendor", "{plugins,gems}", "*")
6
7
  end
7
8
  end
@@ -27,13 +27,29 @@ module Shoulda
27
27
 
28
28
  class Context
29
29
  # alias_method_chain hack to allow the should_fail macro to work
30
- def should_with_failure_scenario(name, options = {}, &block)
30
+ def should_with_failure_scenario(*args, &block)
31
+ should_without_failure_scenario(*args, &block)
32
+ wrap_last_should_with_failure_expectation
33
+ end
34
+ alias_method_chain :should, :failure_scenario
35
+
36
+ # alias_method_chain hack to allow the should_fail macro to work
37
+ def should_not_with_failure_scenario(*args, &block)
38
+ should_not_without_failure_scenario(*args, &block)
39
+ wrap_last_should_with_failure_expectation
40
+ end
41
+ alias_method_chain :should_not, :failure_scenario
42
+
43
+ def wrap_last_should_with_failure_expectation
31
44
  if Shoulda.expected_exceptions
32
45
  expected_exceptions = Shoulda.expected_exceptions
33
- failure_block = lambda { assert_raise(*expected_exceptions, &block.bind(self)) }
46
+ should = self.shoulds.last
47
+ assertion_block = should[:block]
48
+ failure_block = lambda do
49
+ assert_raise(*expected_exceptions, &assertion_block.bind(self))
50
+ end
51
+ should[:block] = failure_block
34
52
  end
35
- should_without_failure_scenario(name, options, &(failure_block || block))
36
53
  end
37
- alias_method_chain :should, :failure_scenario
38
54
  end
39
55
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../test_helper'
1
+ require 'test_helper'
2
2
  require 'posts_controller'
3
3
 
4
4
  # Re-raise errors caught by the controller.
@@ -54,8 +54,6 @@ class PostsControllerTest < ActionController::TestCase
54
54
  end
55
55
  should_assign_to :posts
56
56
  should_not_assign_to :foo, :bar
57
- should_render_page_with_metadata :description => /Posts/, :title => /index/
58
- should_render_page_with_metadata :keywords => "posts"
59
57
  end
60
58
 
61
59
  context "viewing posts for a user with rss format" do
@@ -65,8 +63,12 @@ class PostsControllerTest < ActionController::TestCase
65
63
  end
66
64
  should_respond_with :success
67
65
  should_respond_with_content_type 'application/rss+xml'
68
- should_respond_with_content_type :rss
69
- should_respond_with_content_type /rss/
66
+ context "with a symbol" do
67
+ should_respond_with_content_type :rss
68
+ end
69
+ context "with a regexp" do
70
+ should_respond_with_content_type /rss/
71
+ end
70
72
  should_set_session(:mischief) { nil }
71
73
  should_set_session(:special) { '$2 off your next purchase' }
72
74
  should_set_session(:special_user_id) { @user.id }
@@ -85,7 +87,6 @@ class PostsControllerTest < ActionController::TestCase
85
87
  should_render_with_layout :wide
86
88
  end
87
89
  should_assign_to :false_flag
88
- should_set_the_flash_to nil
89
90
  should_fail do
90
91
  should_set_the_flash_to /.*/
91
92
  end
@@ -95,7 +96,6 @@ class PostsControllerTest < ActionController::TestCase
95
96
  setup { get :new, :user_id => users(:first) }
96
97
  should_render_without_layout
97
98
  should_not_set_the_flash
98
- should_render_a_form
99
99
  end
100
100
 
101
101
  context "on POST to #create" do
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../test_helper'
1
+ require 'test_helper'
2
2
  require 'users_controller'
3
3
 
4
4
  # Re-raise errors caught by the controller.
@@ -0,0 +1,53 @@
1
+ require 'test_helper'
2
+
3
+ class HaveSentEmailTest < ActiveSupport::TestCase # :nodoc:
4
+ context "an email" do
5
+ setup do
6
+ define_mailer :mailer, [:the_email] do
7
+ def the_email
8
+ if defined?(AbstractController::Rendering)
9
+ mail :from => "do-not-reply@example.com",
10
+ :to => "myself@me.com",
11
+ :subject => "This is spam",
12
+ :body => "Every email is spam."
13
+ else
14
+ from "do-not-reply@example.com"
15
+ recipients "myself@me.com"
16
+ subject "This is spam"
17
+ body "Every email is spam."
18
+ end
19
+ end
20
+ end
21
+ if defined?(AbstractController::Rendering)
22
+ ::ActionMailer::Base.deliveries << Mailer.the_email
23
+ else
24
+ ::ActionMailer::Base.deliveries << Mailer.create_the_email
25
+ end
26
+ end
27
+
28
+ should "accept based on the subject" do
29
+ assert_accepts have_sent_email.with_subject(/is spam$/), nil
30
+ assert_rejects have_sent_email.with_subject(/totally safe/), nil
31
+ end
32
+
33
+ should "accept based on the sender" do
34
+ assert_accepts have_sent_email.from('do-not-reply@example.com'), nil
35
+ assert_rejects have_sent_email.from('you@example.com'), nil
36
+ end
37
+
38
+ should "accept based on the body" do
39
+ assert_accepts have_sent_email.with_body(/is spam\./), nil
40
+ assert_rejects have_sent_email.with_body(/totally safe/), nil
41
+ end
42
+
43
+ should "accept baed on the recipienct" do
44
+ assert_accepts have_sent_email.to('myself@me.com'), nil
45
+ assert_rejects have_sent_email.to('you@example.com'), nil
46
+ end
47
+
48
+ should "chain" do
49
+ assert_accepts have_sent_email.with_subject(/spam/).from('do-not-reply@example.com').with_body(/spam/).to('myself@me.com'), nil
50
+ assert_rejects have_sent_email.with_subject(/ham/).from('you@example.com').with_body(/ham/).to('them@example.com'), nil
51
+ end
52
+ end
53
+ end