shoulda 2.10.3 → 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 (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