thoughtbot-shoulda 2.10.2 → 2.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (241) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +5 -5
  2. data/README.rdoc +72 -89
  3. data/Rakefile +31 -33
  4. data/lib/shoulda.rb +6 -6
  5. data/lib/shoulda/action_controller.rb +8 -0
  6. data/lib/shoulda/action_controller/macros.rb +54 -73
  7. data/lib/shoulda/action_controller/matchers.rb +7 -5
  8. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +10 -7
  9. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +18 -1
  10. data/lib/shoulda/action_controller/matchers/redirect_to_matcher.rb +62 -0
  11. data/lib/shoulda/action_controller/matchers/render_template_matcher.rb +54 -0
  12. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +33 -15
  13. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +10 -10
  14. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +17 -13
  15. data/lib/shoulda/action_controller/matchers/route_matcher.rb +3 -3
  16. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +13 -2
  17. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +1 -1
  18. data/lib/shoulda/action_mailer.rb +3 -0
  19. data/lib/shoulda/action_mailer/assertions.rb +4 -0
  20. data/lib/shoulda/action_mailer/matchers.rb +22 -0
  21. data/lib/shoulda/action_mailer/matchers/have_sent_email.rb +110 -0
  22. data/lib/shoulda/active_record/helpers.rb +8 -3
  23. data/lib/shoulda/active_record/macros.rb +88 -143
  24. data/lib/shoulda/active_record/matchers.rb +0 -1
  25. data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +1 -1
  26. data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +10 -2
  27. data/lib/shoulda/active_record/matchers/association_matcher.rb +8 -8
  28. data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +1 -1
  29. data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +2 -2
  30. data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +11 -11
  31. data/lib/shoulda/active_record/matchers/have_db_index_matcher.rb +8 -8
  32. data/lib/shoulda/active_record/matchers/validate_format_of_matcher.rb +2 -4
  33. data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +3 -3
  34. data/lib/shoulda/active_record/matchers/validation_matcher.rb +0 -1
  35. data/lib/shoulda/assertions.rb +10 -2
  36. data/lib/shoulda/autoload_macros.rb +20 -20
  37. data/lib/shoulda/context.rb +70 -39
  38. data/lib/shoulda/{rspec.rb → integrations/rspec.rb} +2 -0
  39. data/lib/shoulda/integrations/rspec2.rb +22 -0
  40. data/lib/shoulda/{test_unit.rb → integrations/test_unit.rb} +0 -0
  41. data/lib/shoulda/macros.rb +46 -18
  42. data/lib/shoulda/rails.rb +0 -5
  43. data/lib/shoulda/tasks/yaml_to_shoulda.rake +11 -11
  44. data/lib/shoulda/version.rb +4 -0
  45. data/rails/init.rb +3 -2
  46. data/test/fail_macros.rb +20 -4
  47. data/test/functional/posts_controller_test.rb +7 -7
  48. data/test/functional/users_controller_test.rb +1 -1
  49. data/test/matchers/action_mailer/have_sent_email_test.rb +70 -0
  50. data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +7 -1
  51. data/test/matchers/active_record/allow_value_matcher_test.rb +1 -1
  52. data/test/matchers/active_record/association_matcher_test.rb +16 -16
  53. data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +3 -2
  54. data/test/matchers/active_record/ensure_length_of_matcher_test.rb +1 -1
  55. data/test/matchers/active_record/have_db_column_matcher_test.rb +1 -1
  56. data/test/matchers/active_record/have_db_index_matcher_test.rb +1 -1
  57. data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +1 -1
  58. data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +1 -1
  59. data/test/matchers/active_record/validate_format_of_matcher_test.rb +1 -1
  60. data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +1 -1
  61. data/test/matchers/active_record/validate_presence_of_matcher_test.rb +1 -1
  62. data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +1 -1
  63. data/test/matchers/controller/assign_to_matcher_test.rb +11 -1
  64. data/test/matchers/controller/filter_param_matcher_test.rb +10 -2
  65. data/test/matchers/controller/redirect_to_matcher_test.rb +37 -0
  66. data/test/matchers/controller/render_template_matcher_test.rb +37 -0
  67. data/test/matchers/controller/render_with_layout_matcher_test.rb +15 -1
  68. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +1 -1
  69. data/test/matchers/controller/respond_with_matcher_test.rb +1 -11
  70. data/test/matchers/controller/route_matcher_test.rb +18 -1
  71. data/test/matchers/controller/set_session_matcher_test.rb +11 -1
  72. data/test/matchers/controller/set_the_flash_matcher.rb +1 -1
  73. data/test/other/autoload_macro_test.rb +1 -1
  74. data/test/other/context_test.rb +210 -27
  75. data/test/other/convert_to_should_syntax_test.rb +1 -1
  76. data/test/other/helpers_test.rb +13 -36
  77. data/test/other/private_helpers_test.rb +2 -2
  78. data/test/other/should_test.rb +13 -13
  79. data/test/{model_builder.rb → rails2_model_builder.rb} +32 -8
  80. data/test/{rails_root → rails2_root}/app/controllers/application_controller.rb +0 -3
  81. data/test/{rails_root → rails2_root}/app/controllers/posts_controller.rb +0 -0
  82. data/test/{rails_root → rails2_root}/app/controllers/users_controller.rb +0 -0
  83. data/test/{rails_root → rails2_root}/app/helpers/application_helper.rb +0 -0
  84. data/test/{rails_root → rails2_root}/app/helpers/posts_helper.rb +0 -0
  85. data/test/{rails_root → rails2_root}/app/helpers/users_helper.rb +0 -0
  86. data/test/{rails_root → rails2_root}/app/models/address.rb +0 -0
  87. data/test/rails2_root/app/models/flea.rb +11 -0
  88. data/test/{rails_root → rails2_root}/app/models/friendship.rb +0 -0
  89. data/test/rails2_root/app/models/notifier.rb +8 -0
  90. data/test/{rails_root → rails2_root}/app/models/pets/cat.rb +0 -0
  91. data/test/{rails_root → rails2_root}/app/models/pets/dog.rb +0 -0
  92. data/test/{rails_root → rails2_root}/app/models/post.rb +1 -1
  93. data/test/{rails_root → rails2_root}/app/models/product.rb +0 -0
  94. data/test/{rails_root → rails2_root}/app/models/profile.rb +0 -0
  95. data/test/{rails_root → rails2_root}/app/models/registration.rb +0 -0
  96. data/test/{rails_root → rails2_root}/app/models/tag.rb +0 -0
  97. data/test/{rails_root → rails2_root}/app/models/tagging.rb +0 -0
  98. data/test/{rails_root → rails2_root}/app/models/treat.rb +0 -0
  99. data/test/{rails_root → rails2_root}/app/models/user.rb +0 -0
  100. data/test/{rails_root → rails2_root}/app/views/layouts/posts.rhtml +0 -0
  101. data/test/{rails_root → rails2_root}/app/views/layouts/users.rhtml +0 -0
  102. data/test/{rails_root → rails2_root}/app/views/layouts/wide.html.erb +0 -0
  103. data/test/rails2_root/app/views/notifier/the_email.html.erb +1 -0
  104. data/test/{rails_root → rails2_root}/app/views/posts/edit.rhtml +0 -0
  105. data/test/{rails_root → rails2_root}/app/views/posts/index.rhtml +0 -0
  106. data/test/{rails_root → rails2_root}/app/views/posts/new.rhtml +0 -0
  107. data/test/{rails_root → rails2_root}/app/views/posts/show.rhtml +0 -0
  108. data/test/{rails_root → rails2_root}/app/views/users/edit.rhtml +0 -0
  109. data/test/{rails_root → rails2_root}/app/views/users/index.rhtml +0 -0
  110. data/test/{rails_root → rails2_root}/app/views/users/new.rhtml +0 -0
  111. data/test/{rails_root → rails2_root}/app/views/users/show.rhtml +0 -0
  112. data/test/{rails_root → rails2_root}/config/boot.rb +0 -0
  113. data/test/{rails_root → rails2_root}/config/database.yml +1 -1
  114. data/test/{rails_root → rails2_root}/config/environment.rb +0 -1
  115. data/test/rails2_root/config/environments/test.rb +23 -0
  116. data/test/{rails_root → rails2_root}/config/initializers/new_rails_defaults.rb +0 -0
  117. data/test/{rails_root → rails2_root}/config/initializers/shoulda.rb +0 -0
  118. data/test/{rails_root → rails2_root}/config/routes.rb +0 -0
  119. data/test/{rails_root → rails2_root}/db/migrate/001_create_users.rb +0 -0
  120. data/test/{rails_root → rails2_root}/db/migrate/002_create_posts.rb +0 -0
  121. data/test/{rails_root → rails2_root}/db/migrate/003_create_taggings.rb +0 -0
  122. data/test/{rails_root → rails2_root}/db/migrate/004_create_tags.rb +0 -0
  123. data/test/{rails_root → rails2_root}/db/migrate/005_create_dogs.rb +0 -0
  124. data/test/{rails_root → rails2_root}/db/migrate/006_create_addresses.rb +0 -0
  125. data/test/{rails_root → rails2_root}/db/migrate/007_create_fleas.rb +0 -0
  126. data/test/{rails_root → rails2_root}/db/migrate/008_create_dogs_fleas.rb +0 -0
  127. data/test/{rails_root → rails2_root}/db/migrate/009_create_products.rb +0 -0
  128. data/test/{rails_root → rails2_root}/db/migrate/010_create_friendships.rb +0 -0
  129. data/test/{rails_root → rails2_root}/db/migrate/011_create_treats.rb +0 -0
  130. data/test/{rails_root → rails2_root}/db/migrate/20090506203502_create_profiles.rb +0 -0
  131. data/test/{rails_root → rails2_root}/db/migrate/20090506203536_create_registrations.rb +0 -0
  132. data/test/{rails_root → rails2_root}/db/migrate/20090513104502_create_cats.rb +0 -0
  133. data/test/{rails_root → rails2_root}/db/schema.rb +0 -0
  134. data/test/{rails_root → rails2_root}/public/404.html +0 -0
  135. data/test/{rails_root → rails2_root}/public/422.html +0 -0
  136. data/test/{rails_root → rails2_root}/public/500.html +0 -0
  137. data/test/{rails_root → rails2_root}/script/console +0 -0
  138. data/test/{rails_root → rails2_root}/script/generate +0 -0
  139. data/test/{rails_root → rails2_root}/test/shoulda_macros/custom_macro.rb +0 -0
  140. data/test/{rails_root → rails2_root}/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +0 -0
  141. data/test/{rails_root → rails2_root}/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +0 -0
  142. data/test/rails2_test_helper.rb +6 -0
  143. data/test/rails3_model_builder.rb +118 -0
  144. data/test/rails3_root/Gemfile +28 -0
  145. data/test/rails3_root/README +244 -0
  146. data/test/rails3_root/Rakefile +10 -0
  147. data/test/rails3_root/app/controllers/application_controller.rb +22 -0
  148. data/test/rails3_root/app/controllers/posts_controller.rb +87 -0
  149. data/test/rails3_root/app/controllers/users_controller.rb +82 -0
  150. data/test/rails3_root/app/helpers/application_helper.rb +2 -0
  151. data/test/rails3_root/app/models/address.rb +7 -0
  152. data/test/rails3_root/app/models/flea.rb +11 -0
  153. data/test/rails3_root/app/models/friendship.rb +4 -0
  154. data/test/rails3_root/app/models/notifier.rb +8 -0
  155. data/test/rails3_root/app/models/pets/cat.rb +7 -0
  156. data/test/rails3_root/app/models/pets/dog.rb +10 -0
  157. data/test/rails3_root/app/models/post.rb +12 -0
  158. data/test/rails3_root/app/models/product.rb +12 -0
  159. data/test/rails3_root/app/models/profile.rb +2 -0
  160. data/test/rails3_root/app/models/registration.rb +2 -0
  161. data/test/rails3_root/app/models/tag.rb +8 -0
  162. data/test/rails3_root/app/models/tagging.rb +4 -0
  163. data/test/rails3_root/app/models/treat.rb +3 -0
  164. data/test/rails3_root/app/models/user.rb +32 -0
  165. data/test/rails3_root/app/views/layouts/application.html.erb +14 -0
  166. data/test/rails3_root/app/views/layouts/posts.rhtml +19 -0
  167. data/test/rails3_root/app/views/layouts/users.rhtml +17 -0
  168. data/test/rails3_root/app/views/layouts/wide.html.erb +1 -0
  169. data/test/rails3_root/app/views/notifier/the_email.html.erb +1 -0
  170. data/test/rails3_root/app/views/posts/edit.rhtml +27 -0
  171. data/test/rails3_root/app/views/posts/index.rhtml +25 -0
  172. data/test/rails3_root/app/views/posts/new.rhtml +24 -0
  173. data/test/rails3_root/app/views/posts/show.rhtml +18 -0
  174. data/test/rails3_root/app/views/users/edit.rhtml +22 -0
  175. data/test/rails3_root/app/views/users/index.rhtml +22 -0
  176. data/test/rails3_root/app/views/users/new.rhtml +21 -0
  177. data/test/rails3_root/app/views/users/show.rhtml +13 -0
  178. data/test/rails3_root/config.ru +4 -0
  179. data/test/rails3_root/config/application.rb +46 -0
  180. data/test/rails3_root/config/boot.rb +6 -0
  181. data/test/rails3_root/config/database.yml +22 -0
  182. data/test/rails3_root/config/environment.rb +5 -0
  183. data/test/rails3_root/config/environments/development.rb +19 -0
  184. data/test/rails3_root/config/environments/production.rb +42 -0
  185. data/test/rails3_root/config/environments/test.rb +32 -0
  186. data/test/rails3_root/config/initializers/backtrace_silencers.rb +7 -0
  187. data/test/rails3_root/config/initializers/inflections.rb +10 -0
  188. data/test/rails3_root/config/initializers/mime_types.rb +5 -0
  189. data/test/rails3_root/config/initializers/secret_token.rb +7 -0
  190. data/test/rails3_root/config/initializers/session_store.rb +8 -0
  191. data/test/rails3_root/config/locales/en.yml +5 -0
  192. data/test/rails3_root/config/routes.rb +4 -0
  193. data/test/rails3_root/db/migrate/001_create_users.rb +19 -0
  194. data/test/rails3_root/db/migrate/002_create_posts.rb +13 -0
  195. data/test/rails3_root/db/migrate/003_create_taggings.rb +12 -0
  196. data/test/rails3_root/db/migrate/004_create_tags.rb +11 -0
  197. data/test/rails3_root/db/migrate/005_create_dogs.rb +12 -0
  198. data/test/rails3_root/db/migrate/006_create_addresses.rb +14 -0
  199. data/test/rails3_root/db/migrate/007_create_fleas.rb +11 -0
  200. data/test/rails3_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  201. data/test/rails3_root/db/migrate/009_create_products.rb +17 -0
  202. data/test/rails3_root/db/migrate/010_create_friendships.rb +14 -0
  203. data/test/rails3_root/db/migrate/011_create_treats.rb +12 -0
  204. data/test/rails3_root/db/migrate/20090506203502_create_profiles.rb +12 -0
  205. data/test/rails3_root/db/migrate/20090506203536_create_registrations.rb +14 -0
  206. data/test/rails3_root/db/migrate/20090513104502_create_cats.rb +12 -0
  207. data/test/rails3_root/db/seeds.rb +7 -0
  208. data/test/rails3_root/public/404.html +26 -0
  209. data/test/rails3_root/public/422.html +26 -0
  210. data/test/rails3_root/public/500.html +26 -0
  211. data/test/{rails_root/config/environments/test.rb → rails3_root/public/favicon.ico} +0 -0
  212. data/test/rails3_root/public/images/rails.png +0 -0
  213. data/test/rails3_root/public/index.html +279 -0
  214. data/test/rails3_root/public/javascripts/application.js +2 -0
  215. data/test/rails3_root/public/javascripts/controls.js +965 -0
  216. data/test/rails3_root/public/javascripts/dragdrop.js +974 -0
  217. data/test/rails3_root/public/javascripts/effects.js +1123 -0
  218. data/test/rails3_root/public/javascripts/prototype.js +4874 -0
  219. data/test/rails3_root/public/javascripts/rails.js +118 -0
  220. data/test/rails3_root/public/robots.txt +5 -0
  221. data/test/rails3_root/script/rails +9 -0
  222. data/test/rails3_root/test/performance/browsing_test.rb +9 -0
  223. data/test/rails3_root/test/test_helper.rb +13 -0
  224. data/test/rails3_test_helper.rb +6 -0
  225. data/test/test_helper.rb +16 -8
  226. data/test/unit/address_test.rb +1 -1
  227. data/test/unit/cat_test.rb +1 -1
  228. data/test/unit/dog_test.rb +1 -1
  229. data/test/unit/flea_test.rb +9 -1
  230. data/test/unit/friendship_test.rb +1 -1
  231. data/test/unit/post_test.rb +1 -5
  232. data/test/unit/product_test.rb +1 -1
  233. data/test/unit/tag_test.rb +1 -5
  234. data/test/unit/tagging_test.rb +1 -1
  235. data/test/unit/user_test.rb +3 -37
  236. metadata +184 -118
  237. data/lib/shoulda/action_view.rb +0 -10
  238. data/lib/shoulda/action_view/macros.rb +0 -61
  239. data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +0 -128
  240. data/test/matchers/active_record/have_named_scope_matcher_test.rb +0 -65
  241. 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?
@@ -20,9 +20,9 @@ module Shoulda # :nodoc:
20
20
  # dependent option.
21
21
  #
22
22
  # Example:
23
- # it { should_have_many(:friends) }
24
- # it { should_have_many(:enemies).through(:friends) }
25
- # it { should_have_many(:enemies).dependent(:destroy) }
23
+ # it { should have_many(:friends) }
24
+ # it { should have_many(:enemies).through(:friends) }
25
+ # it { should have_many(:enemies).dependent(:destroy) }
26
26
  #
27
27
  def have_many(name)
28
28
  AssociationMatcher.new(:has_many, name)
@@ -70,10 +70,10 @@ module Shoulda # :nodoc:
70
70
 
71
71
  def matches?(subject)
72
72
  @subject = subject
73
- association_exists? &&
74
- macro_correct? &&
75
- foreign_key_exists? &&
76
- through_association_valid? &&
73
+ association_exists? &&
74
+ macro_correct? &&
75
+ foreign_key_exists? &&
76
+ through_association_valid? &&
77
77
  dependent_correct? &&
78
78
  join_table_exists?
79
79
  end
@@ -160,7 +160,7 @@ module Shoulda # :nodoc:
160
160
  end
161
161
 
162
162
  def join_table_exists?
163
- if @macro != :has_and_belongs_to_many ||
163
+ if @macro != :has_and_belongs_to_many ||
164
164
  ::ActiveRecord::Base.connection.tables.include?(join_table.to_s)
165
165
  true
166
166
  else
@@ -57,7 +57,7 @@ module Shoulda # :nodoc:
57
57
  @low_message ||= :inclusion
58
58
  @high_message ||= :inclusion
59
59
 
60
- disallows_lower_value &&
60
+ disallows_lower_value &&
61
61
  allows_minimum_value &&
62
62
  disallows_higher_value &&
63
63
  allows_maximum_value
@@ -84,7 +84,7 @@ module Shoulda # :nodoc:
84
84
  def matches?(subject)
85
85
  super(subject)
86
86
  translate_messages!
87
- disallows_lower_length &&
87
+ disallows_lower_length &&
88
88
  allows_minimum_length &&
89
89
  ((@minimum == @maximum) ||
90
90
  (disallows_higher_length &&
@@ -106,7 +106,7 @@ module Shoulda # :nodoc:
106
106
  end
107
107
 
108
108
  def disallows_lower_length
109
- @minimum == 0 ||
109
+ @minimum == 0 ||
110
110
  @minimum.nil? ||
111
111
  disallows_length_of(@minimum - 1, @short_message)
112
112
  end
@@ -24,12 +24,12 @@ module Shoulda # :nodoc:
24
24
  @macro = macro
25
25
  @column = column
26
26
  end
27
-
27
+
28
28
  def of_type(column_type)
29
29
  @column_type = column_type
30
30
  self
31
31
  end
32
-
32
+
33
33
  def with_options(opts = {})
34
34
  @precision = opts[:precision]
35
35
  @limit = opts[:limit]
@@ -41,8 +41,8 @@ module Shoulda # :nodoc:
41
41
 
42
42
  def matches?(subject)
43
43
  @subject = subject
44
- column_exists? &&
45
- correct_column_type? &&
44
+ column_exists? &&
45
+ correct_column_type? &&
46
46
  correct_precision? &&
47
47
  correct_limit? &&
48
48
  correct_default? &&
@@ -80,7 +80,7 @@ module Shoulda # :nodoc:
80
80
  false
81
81
  end
82
82
  end
83
-
83
+
84
84
  def correct_column_type?
85
85
  return true if @column_type.nil?
86
86
  if matched_column.type.to_s == @column_type.to_s
@@ -91,7 +91,7 @@ module Shoulda # :nodoc:
91
91
  false
92
92
  end
93
93
  end
94
-
94
+
95
95
  def correct_precision?
96
96
  return true if @precision.nil?
97
97
  if matched_column.precision.to_s == @precision.to_s
@@ -103,7 +103,7 @@ module Shoulda # :nodoc:
103
103
  false
104
104
  end
105
105
  end
106
-
106
+
107
107
  def correct_limit?
108
108
  return true if @limit.nil?
109
109
  if matched_column.limit.to_s == @limit.to_s
@@ -115,7 +115,7 @@ module Shoulda # :nodoc:
115
115
  false
116
116
  end
117
117
  end
118
-
118
+
119
119
  def correct_default?
120
120
  return true if @default.nil?
121
121
  if matched_column.default.to_s == @default.to_s
@@ -127,7 +127,7 @@ module Shoulda # :nodoc:
127
127
  false
128
128
  end
129
129
  end
130
-
130
+
131
131
  def correct_null?
132
132
  return true if @null.nil?
133
133
  if matched_column.null.to_s == @null.to_s
@@ -139,7 +139,7 @@ module Shoulda # :nodoc:
139
139
  false
140
140
  end
141
141
  end
142
-
142
+
143
143
  def correct_scale?
144
144
  return true if @scale.nil?
145
145
  if matched_column.scale.to_s == @scale.to_s
@@ -150,7 +150,7 @@ module Shoulda # :nodoc:
150
150
  false
151
151
  end
152
152
  end
153
-
153
+
154
154
  def matched_column
155
155
  model_class.columns.detect { |each| each.name == @column.to_s }
156
156
  end
@@ -27,7 +27,7 @@ module Shoulda # :nodoc:
27
27
  @macro = macro
28
28
  @columns = normalize_columns_to_array(columns)
29
29
  end
30
-
30
+
31
31
  def unique(unique)
32
32
  @unique = unique
33
33
  self
@@ -51,11 +51,11 @@ module Shoulda # :nodoc:
51
51
  end
52
52
 
53
53
  protected
54
-
54
+
55
55
  def index_exists?
56
56
  ! matched_index.nil?
57
57
  end
58
-
58
+
59
59
  def correct_unique?
60
60
  return true if @unique.nil?
61
61
  if matched_index.unique == @unique
@@ -66,7 +66,7 @@ module Shoulda # :nodoc:
66
66
  false
67
67
  end
68
68
  end
69
-
69
+
70
70
  def matched_index
71
71
  indexes.detect { |each| each.columns == @columns }
72
72
  end
@@ -74,11 +74,11 @@ module Shoulda # :nodoc:
74
74
  def model_class
75
75
  @subject.class
76
76
  end
77
-
77
+
78
78
  def table_name
79
79
  model_class.table_name
80
80
  end
81
-
81
+
82
82
  def indexes
83
83
  ::ActiveRecord::Base.connection.indexes(table_name)
84
84
  end
@@ -86,7 +86,7 @@ module Shoulda # :nodoc:
86
86
  def expectation
87
87
  expected = "#{model_class.name} to #{description}"
88
88
  end
89
-
89
+
90
90
  def index_type
91
91
  case @unique
92
92
  when nil
@@ -97,7 +97,7 @@ module Shoulda # :nodoc:
97
97
  'unique'
98
98
  end
99
99
  end
100
-
100
+
101
101
  def normalize_columns_to_array(columns)
102
102
  if columns.class == Array
103
103
  columns.collect { |each| each.to_s }
@@ -25,7 +25,7 @@ module Shoulda # :nodoc:
25
25
  end
26
26
 
27
27
  class ValidateFormatOfMatcher < ValidationMatcher # :nodoc:
28
-
28
+
29
29
  def initialize(attribute)
30
30
  super
31
31
  end
@@ -34,13 +34,12 @@ module Shoulda # :nodoc:
34
34
  @expected_message = message if message
35
35
  self
36
36
  end
37
-
37
+
38
38
  def with(value)
39
39
  raise "You may not call both with and not_with" if @value_to_fail
40
40
  @value_to_pass = value
41
41
  self
42
42
  end
43
-
44
43
 
45
44
  def not_with(value)
46
45
  raise "You may not call both with and not_with" if @value_to_pass
@@ -48,7 +47,6 @@ module Shoulda # :nodoc:
48
47
  self
49
48
  end
50
49
 
51
-
52
50
  def matches?(subject)
53
51
  super(subject)
54
52
  @expected_message ||= :blank
@@ -67,8 +67,8 @@ module Shoulda # :nodoc:
67
67
  def matches?(subject)
68
68
  @subject = subject.class.new
69
69
  @expected_message ||= :taken
70
- find_existing &&
71
- set_scoped_attributes &&
70
+ find_existing &&
71
+ set_scoped_attributes &&
72
72
  validate_attribute &&
73
73
  validate_after_scope_change
74
74
  end
@@ -121,7 +121,7 @@ module Shoulda # :nodoc:
121
121
  @subject.send("#{scope}=", next_value)
122
122
 
123
123
  if allows_value_of(existing_value, @expected_message)
124
- @negative_failure_message <<
124
+ @negative_failure_message <<
125
125
  " (with different value of #{scope})"
126
126
  true
127
127
  else
@@ -18,7 +18,6 @@ module Shoulda # :nodoc:
18
18
  @subject = subject
19
19
  false
20
20
  end
21
-
22
21
 
23
22
  private
24
23
 
@@ -26,7 +26,7 @@ module Shoulda # :nodoc:
26
26
  case x
27
27
  when Regexp
28
28
  assert(collection.detect { |e| e =~ x }, msg)
29
- else
29
+ else
30
30
  assert(collection.include?(x), msg)
31
31
  end
32
32
  end
@@ -39,13 +39,17 @@ module Shoulda # :nodoc:
39
39
  case x
40
40
  when Regexp
41
41
  assert(!collection.detect { |e| e =~ x }, msg)
42
- else
42
+ else
43
43
  assert(!collection.include?(x), msg)
44
44
  end
45
45
  end
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]
@@ -1,40 +1,40 @@
1
1
  module Shoulda # :nodoc:
2
- # Call autoload_macros when you want to load test macros automatically in a non-Rails
2
+ # Call autoload_macros when you want to load test macros automatically in a non-Rails
3
3
  # project (it's done automatically for Rails projects).
4
4
  # You don't need to specify ROOT/test/shoulda_macros explicitly. Your custom macros
5
5
  # are loaded automatically when you call autoload_macros.
6
6
  #
7
7
  # The first argument is the path to you application's root directory.
8
- # All following arguments are directories relative to your root, which contain
9
- # shoulda_macros subdirectories. These directories support the same kinds of globs as the
8
+ # All following arguments are directories relative to your root, which contain
9
+ # shoulda_macros subdirectories. These directories support the same kinds of globs as the
10
10
  # Dir class.
11
- #
11
+ #
12
12
  # Basic usage (from a test_helper):
13
13
  # Shoulda.autoload_macros(File.dirname(__FILE__) + '/..')
14
- # will load everything in
15
- # - your_app/test/shoulda_macros
14
+ # will load everything in
15
+ # - your_app/test/shoulda_macros
16
16
  #
17
- # To load vendored macros as well:
17
+ # To load vendored macros as well:
18
18
  # Shoulda.autoload_macros(APP_ROOT, 'vendor/*')
19
- # will load everything in
20
- # - APP_ROOT/vendor/*/shoulda_macros
21
- # - APP_ROOT/test/shoulda_macros
19
+ # will load everything in
20
+ # - APP_ROOT/vendor/*/shoulda_macros
21
+ # - APP_ROOT/test/shoulda_macros
22
22
  #
23
- # To load macros in an app with a vendor directory laid out like Rails':
23
+ # To load macros in an app with a vendor directory laid out like Rails':
24
24
  # Shoulda.autoload_macros(APP_ROOT, 'vendor/{plugins,gems}/*')
25
25
  # or
26
26
  # Shoulda.autoload_macros(APP_ROOT, 'vendor/plugins/*', 'vendor/gems/*')
27
- # will load everything in
28
- # - APP_ROOT/vendor/plugins/*/shoulda_macros
29
- # - APP_ROOT/vendor/gems/*/shoulda_macros
30
- # - APP_ROOT/test/shoulda_macros
27
+ # will load everything in
28
+ # - APP_ROOT/vendor/plugins/*/shoulda_macros
29
+ # - APP_ROOT/vendor/gems/*/shoulda_macros
30
+ # - APP_ROOT/test/shoulda_macros
31
31
  #
32
- # If you prefer to stick testing dependencies away from your production dependencies:
32
+ # If you prefer to stick testing dependencies away from your production dependencies:
33
33
  # Shoulda.autoload_macros(APP_ROOT, 'vendor/*', 'test/vendor/*')
34
- # will load everything in
35
- # - APP_ROOT/vendor/*/shoulda_macros
36
- # - APP_ROOT/test/vendor/*/shoulda_macros
37
- # - APP_ROOT/test/shoulda_macros
34
+ # will load everything in
35
+ # - APP_ROOT/vendor/*/shoulda_macros
36
+ # - APP_ROOT/test/vendor/*/shoulda_macros
37
+ # - APP_ROOT/test/shoulda_macros
38
38
  def self.autoload_macros(root, *dirs)
39
39
  dirs << File.join('test')
40
40
  complete_dirs = dirs.map{|d| File.join(root, d, 'shoulda_macros')}
@@ -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
@@ -86,7 +116,7 @@ module Shoulda
86
116
  # context "on GET" do
87
117
  # setup { get :index }
88
118
  #
89
- # should_respond_with :success
119
+ # should respond_with(:success)
90
120
  #
91
121
  # # runs before "get :index"
92
122
  # before_should "find all users" do
@@ -185,7 +215,7 @@ module Shoulda
185
215
  # subject { User.first }
186
216
  #
187
217
  # # uses the existing user
188
- # should_validate_uniqueness_of :email
218
+ # should validate_uniqueness_of(:email)
189
219
  # end
190
220
  def subject(&block)
191
221
  @subject_block = block
@@ -214,27 +244,10 @@ 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
233
- if subject_block
234
- instance_eval(&subject_block)
235
- else
236
- get_instance_of(self.class.described_type)
237
- end
250
+ @shoulda_subject ||= construct_subject
238
251
  end
239
252
 
240
253
  def subject_block # :nodoc:
@@ -243,17 +256,7 @@ module Shoulda
243
256
 
244
257
  def get_instance_of(object_or_klass) # :nodoc:
245
258
  if object_or_klass.is_a?(Class)
246
- klass = object_or_klass
247
- ivar = "@#{instance_variable_name_for(klass)}"
248
- if instance = instance_variable_get(ivar)
249
- warn "[WARNING] Using #{ivar} as the subject. Future versions " <<
250
- "of Shoulda will require an explicit subject using the " <<
251
- "subject class method. Add this after your setup to avoid " <<
252
- "this warning: subject { #{ivar} }"
253
- instance
254
- else
255
- klass.new
256
- end
259
+ object_or_klass.new
257
260
  else
258
261
  object_or_klass
259
262
  end
@@ -262,6 +265,16 @@ module Shoulda
262
265
  def instance_variable_name_for(klass) # :nodoc:
263
266
  klass.to_s.split('::').last.underscore
264
267
  end
268
+
269
+ private
270
+
271
+ def construct_subject
272
+ if subject_block
273
+ instance_eval(&subject_block)
274
+ else
275
+ get_instance_of(self.class.described_type)
276
+ end
277
+ end
265
278
  end
266
279
 
267
280
  class Context # :nodoc:
@@ -305,14 +318,27 @@ module Shoulda
305
318
  self.teardown_blocks << blk
306
319
  end
307
320
 
308
- def should(name, options = {}, &blk)
309
- 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
310
330
  self.shoulds << { :name => name, :before => options[:before], :block => blk }
311
331
  else
312
332
  self.should_eventuallys << { :name => name }
313
333
  end
314
334
  end
315
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
+
316
342
  def should_eventually(name, &blk)
317
343
  self.should_eventuallys << { :name => name, :block => blk }
318
344
  end
@@ -321,6 +347,11 @@ module Shoulda
321
347
  self.subject_block = block
322
348
  end
323
349
 
350
+ def subject_block
351
+ return @subject_block if @subject_block
352
+ parent.subject_block
353
+ end
354
+
324
355
  def full_name
325
356
  parent_name = parent.full_name if am_subcontext?
326
357
  return [parent_name, name].join(" ").strip