faster_shoulda 2.11.3

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 (259) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +10 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +154 -0
  4. data/Rakefile +74 -0
  5. data/bin/convert_to_should_syntax +42 -0
  6. data/lib/shoulda/action_controller/macros.rb +221 -0
  7. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +114 -0
  8. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +74 -0
  9. data/lib/shoulda/action_controller/matchers/redirect_to_matcher.rb +62 -0
  10. data/lib/shoulda/action_controller/matchers/render_template_matcher.rb +54 -0
  11. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +99 -0
  12. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +74 -0
  13. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +85 -0
  14. data/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
  15. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +98 -0
  16. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +100 -0
  17. data/lib/shoulda/action_controller/matchers.rb +39 -0
  18. data/lib/shoulda/action_controller.rb +34 -0
  19. data/lib/shoulda/action_mailer/assertions.rb +42 -0
  20. data/lib/shoulda/action_mailer/matchers/have_sent_email.rb +110 -0
  21. data/lib/shoulda/action_mailer/matchers.rb +22 -0
  22. data/lib/shoulda/action_mailer.rb +13 -0
  23. data/lib/shoulda/active_record/assertions.rb +69 -0
  24. data/lib/shoulda/active_record/helpers.rb +32 -0
  25. data/lib/shoulda/active_record/macros.rb +457 -0
  26. data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
  27. data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +110 -0
  28. data/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
  29. data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
  30. data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
  31. data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
  32. data/lib/shoulda/active_record/matchers/have_db_index_matcher.rb +112 -0
  33. data/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
  34. data/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
  35. data/lib/shoulda/active_record/matchers/validate_format_of_matcher.rb +65 -0
  36. data/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
  37. data/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
  38. data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
  39. data/lib/shoulda/active_record/matchers/validation_matcher.rb +56 -0
  40. data/lib/shoulda/active_record/matchers.rb +42 -0
  41. data/lib/shoulda/active_record.rb +16 -0
  42. data/lib/shoulda/assertions.rb +79 -0
  43. data/lib/shoulda/autoload_macros.rb +46 -0
  44. data/lib/shoulda/context.rb +537 -0
  45. data/lib/shoulda/helpers.rb +8 -0
  46. data/lib/shoulda/integrations/rspec.rb +13 -0
  47. data/lib/shoulda/integrations/rspec2.rb +22 -0
  48. data/lib/shoulda/integrations/test_unit.rb +22 -0
  49. data/lib/shoulda/macros.rb +161 -0
  50. data/lib/shoulda/private_helpers.rb +13 -0
  51. data/lib/shoulda/proc_extensions.rb +14 -0
  52. data/lib/shoulda/rails.rb +8 -0
  53. data/lib/shoulda/tasks/list_tests.rake +29 -0
  54. data/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
  55. data/lib/shoulda/tasks.rb +3 -0
  56. data/lib/shoulda/version.rb +4 -0
  57. data/lib/shoulda.rb +9 -0
  58. data/rails/init.rb +8 -0
  59. data/test/README +36 -0
  60. data/test/fail_macros.rb +55 -0
  61. data/test/fixtures/addresses.yml +3 -0
  62. data/test/fixtures/friendships.yml +0 -0
  63. data/test/fixtures/posts.yml +5 -0
  64. data/test/fixtures/products.yml +0 -0
  65. data/test/fixtures/taggings.yml +0 -0
  66. data/test/fixtures/tags.yml +9 -0
  67. data/test/fixtures/users.yml +6 -0
  68. data/test/functional/posts_controller_test.rb +121 -0
  69. data/test/functional/users_controller_test.rb +19 -0
  70. data/test/hello_should.rb +37 -0
  71. data/test/matchers/action_mailer/have_sent_email_test.rb +76 -0
  72. data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +74 -0
  73. data/test/matchers/active_record/allow_value_matcher_test.rb +64 -0
  74. data/test/matchers/active_record/association_matcher_test.rb +263 -0
  75. data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +81 -0
  76. data/test/matchers/active_record/ensure_length_of_matcher_test.rb +158 -0
  77. data/test/matchers/active_record/have_db_column_matcher_test.rb +169 -0
  78. data/test/matchers/active_record/have_db_index_matcher_test.rb +91 -0
  79. data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +29 -0
  80. data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +44 -0
  81. data/test/matchers/active_record/validate_format_of_matcher_test.rb +39 -0
  82. data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +52 -0
  83. data/test/matchers/active_record/validate_presence_of_matcher_test.rb +86 -0
  84. data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +147 -0
  85. data/test/matchers/controller/assign_to_matcher_test.rb +55 -0
  86. data/test/matchers/controller/filter_param_matcher_test.rb +40 -0
  87. data/test/matchers/controller/redirect_to_matcher_test.rb +37 -0
  88. data/test/matchers/controller/render_template_matcher_test.rb +37 -0
  89. data/test/matchers/controller/render_with_layout_matcher_test.rb +47 -0
  90. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +32 -0
  91. data/test/matchers/controller/respond_with_matcher_test.rb +96 -0
  92. data/test/matchers/controller/route_matcher_test.rb +75 -0
  93. data/test/matchers/controller/set_session_matcher_test.rb +48 -0
  94. data/test/matchers/controller/set_the_flash_matcher.rb +95 -0
  95. data/test/other/autoload_macro_test.rb +18 -0
  96. data/test/other/context_test.rb +372 -0
  97. data/test/other/convert_to_should_syntax_test.rb +63 -0
  98. data/test/other/helpers_test.rb +317 -0
  99. data/test/other/private_helpers_test.rb +32 -0
  100. data/test/other/should_test.rb +271 -0
  101. data/test/rails2_model_builder.rb +130 -0
  102. data/test/rails2_root/app/controllers/application_controller.rb +22 -0
  103. data/test/rails2_root/app/controllers/posts_controller.rb +87 -0
  104. data/test/rails2_root/app/controllers/users_controller.rb +84 -0
  105. data/test/rails2_root/app/helpers/application_helper.rb +3 -0
  106. data/test/rails2_root/app/helpers/posts_helper.rb +2 -0
  107. data/test/rails2_root/app/helpers/users_helper.rb +2 -0
  108. data/test/rails2_root/app/models/address.rb +7 -0
  109. data/test/rails2_root/app/models/flea.rb +11 -0
  110. data/test/rails2_root/app/models/friendship.rb +4 -0
  111. data/test/rails2_root/app/models/notifier.rb +8 -0
  112. data/test/rails2_root/app/models/pets/cat.rb +7 -0
  113. data/test/rails2_root/app/models/pets/dog.rb +10 -0
  114. data/test/rails2_root/app/models/post.rb +12 -0
  115. data/test/rails2_root/app/models/product.rb +12 -0
  116. data/test/rails2_root/app/models/profile.rb +2 -0
  117. data/test/rails2_root/app/models/registration.rb +2 -0
  118. data/test/rails2_root/app/models/tag.rb +8 -0
  119. data/test/rails2_root/app/models/tagging.rb +4 -0
  120. data/test/rails2_root/app/models/treat.rb +3 -0
  121. data/test/rails2_root/app/models/user.rb +32 -0
  122. data/test/rails2_root/app/views/layouts/posts.rhtml +19 -0
  123. data/test/rails2_root/app/views/layouts/users.rhtml +17 -0
  124. data/test/rails2_root/app/views/layouts/wide.html.erb +1 -0
  125. data/test/rails2_root/app/views/notifier/the_email.html.erb +1 -0
  126. data/test/rails2_root/app/views/posts/edit.rhtml +27 -0
  127. data/test/rails2_root/app/views/posts/index.rhtml +25 -0
  128. data/test/rails2_root/app/views/posts/new.rhtml +26 -0
  129. data/test/rails2_root/app/views/posts/show.rhtml +18 -0
  130. data/test/rails2_root/app/views/users/edit.rhtml +22 -0
  131. data/test/rails2_root/app/views/users/index.rhtml +22 -0
  132. data/test/rails2_root/app/views/users/new.rhtml +21 -0
  133. data/test/rails2_root/app/views/users/show.rhtml +13 -0
  134. data/test/rails2_root/config/boot.rb +110 -0
  135. data/test/rails2_root/config/database.yml +4 -0
  136. data/test/rails2_root/config/environment.rb +17 -0
  137. data/test/rails2_root/config/environments/test.rb +23 -0
  138. data/test/rails2_root/config/initializers/new_rails_defaults.rb +15 -0
  139. data/test/rails2_root/config/initializers/shoulda.rb +8 -0
  140. data/test/rails2_root/config/routes.rb +6 -0
  141. data/test/rails2_root/db/migrate/001_create_users.rb +19 -0
  142. data/test/rails2_root/db/migrate/002_create_posts.rb +13 -0
  143. data/test/rails2_root/db/migrate/003_create_taggings.rb +12 -0
  144. data/test/rails2_root/db/migrate/004_create_tags.rb +11 -0
  145. data/test/rails2_root/db/migrate/005_create_dogs.rb +12 -0
  146. data/test/rails2_root/db/migrate/006_create_addresses.rb +14 -0
  147. data/test/rails2_root/db/migrate/007_create_fleas.rb +11 -0
  148. data/test/rails2_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  149. data/test/rails2_root/db/migrate/009_create_products.rb +17 -0
  150. data/test/rails2_root/db/migrate/010_create_friendships.rb +14 -0
  151. data/test/rails2_root/db/migrate/011_create_treats.rb +12 -0
  152. data/test/rails2_root/db/migrate/20090506203502_create_profiles.rb +12 -0
  153. data/test/rails2_root/db/migrate/20090506203536_create_registrations.rb +14 -0
  154. data/test/rails2_root/db/migrate/20090513104502_create_cats.rb +12 -0
  155. data/test/rails2_root/db/schema.rb +0 -0
  156. data/test/rails2_root/public/404.html +30 -0
  157. data/test/rails2_root/public/422.html +30 -0
  158. data/test/rails2_root/public/500.html +30 -0
  159. data/test/rails2_root/script/console +3 -0
  160. data/test/rails2_root/script/generate +3 -0
  161. data/test/rails2_root/test/shoulda_macros/custom_macro.rb +6 -0
  162. data/test/rails2_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
  163. data/test/rails2_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
  164. data/test/rails2_test_helper.rb +6 -0
  165. data/test/rails3_model_builder.rb +118 -0
  166. data/test/rails3_root/Gemfile +28 -0
  167. data/test/rails3_root/README +244 -0
  168. data/test/rails3_root/Rakefile +10 -0
  169. data/test/rails3_root/app/controllers/application_controller.rb +22 -0
  170. data/test/rails3_root/app/controllers/posts_controller.rb +87 -0
  171. data/test/rails3_root/app/controllers/users_controller.rb +82 -0
  172. data/test/rails3_root/app/helpers/application_helper.rb +2 -0
  173. data/test/rails3_root/app/models/address.rb +7 -0
  174. data/test/rails3_root/app/models/flea.rb +11 -0
  175. data/test/rails3_root/app/models/friendship.rb +4 -0
  176. data/test/rails3_root/app/models/notifier.rb +8 -0
  177. data/test/rails3_root/app/models/pets/cat.rb +7 -0
  178. data/test/rails3_root/app/models/pets/dog.rb +10 -0
  179. data/test/rails3_root/app/models/post.rb +12 -0
  180. data/test/rails3_root/app/models/product.rb +12 -0
  181. data/test/rails3_root/app/models/profile.rb +2 -0
  182. data/test/rails3_root/app/models/registration.rb +2 -0
  183. data/test/rails3_root/app/models/tag.rb +8 -0
  184. data/test/rails3_root/app/models/tagging.rb +4 -0
  185. data/test/rails3_root/app/models/treat.rb +3 -0
  186. data/test/rails3_root/app/models/user.rb +32 -0
  187. data/test/rails3_root/app/views/layouts/application.html.erb +14 -0
  188. data/test/rails3_root/app/views/layouts/posts.rhtml +19 -0
  189. data/test/rails3_root/app/views/layouts/users.rhtml +17 -0
  190. data/test/rails3_root/app/views/layouts/wide.html.erb +1 -0
  191. data/test/rails3_root/app/views/notifier/the_email.html.erb +1 -0
  192. data/test/rails3_root/app/views/posts/edit.rhtml +27 -0
  193. data/test/rails3_root/app/views/posts/index.rhtml +25 -0
  194. data/test/rails3_root/app/views/posts/new.rhtml +24 -0
  195. data/test/rails3_root/app/views/posts/show.rhtml +18 -0
  196. data/test/rails3_root/app/views/users/edit.rhtml +22 -0
  197. data/test/rails3_root/app/views/users/index.rhtml +22 -0
  198. data/test/rails3_root/app/views/users/new.rhtml +21 -0
  199. data/test/rails3_root/app/views/users/show.rhtml +13 -0
  200. data/test/rails3_root/config/application.rb +46 -0
  201. data/test/rails3_root/config/boot.rb +6 -0
  202. data/test/rails3_root/config/database.yml +22 -0
  203. data/test/rails3_root/config/environment.rb +5 -0
  204. data/test/rails3_root/config/environments/development.rb +19 -0
  205. data/test/rails3_root/config/environments/production.rb +42 -0
  206. data/test/rails3_root/config/environments/test.rb +32 -0
  207. data/test/rails3_root/config/initializers/backtrace_silencers.rb +7 -0
  208. data/test/rails3_root/config/initializers/inflections.rb +10 -0
  209. data/test/rails3_root/config/initializers/mime_types.rb +5 -0
  210. data/test/rails3_root/config/initializers/secret_token.rb +7 -0
  211. data/test/rails3_root/config/initializers/session_store.rb +8 -0
  212. data/test/rails3_root/config/locales/en.yml +5 -0
  213. data/test/rails3_root/config/routes.rb +4 -0
  214. data/test/rails3_root/config.ru +4 -0
  215. data/test/rails3_root/db/migrate/001_create_users.rb +19 -0
  216. data/test/rails3_root/db/migrate/002_create_posts.rb +13 -0
  217. data/test/rails3_root/db/migrate/003_create_taggings.rb +12 -0
  218. data/test/rails3_root/db/migrate/004_create_tags.rb +11 -0
  219. data/test/rails3_root/db/migrate/005_create_dogs.rb +12 -0
  220. data/test/rails3_root/db/migrate/006_create_addresses.rb +14 -0
  221. data/test/rails3_root/db/migrate/007_create_fleas.rb +11 -0
  222. data/test/rails3_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  223. data/test/rails3_root/db/migrate/009_create_products.rb +17 -0
  224. data/test/rails3_root/db/migrate/010_create_friendships.rb +14 -0
  225. data/test/rails3_root/db/migrate/011_create_treats.rb +12 -0
  226. data/test/rails3_root/db/migrate/20090506203502_create_profiles.rb +12 -0
  227. data/test/rails3_root/db/migrate/20090506203536_create_registrations.rb +14 -0
  228. data/test/rails3_root/db/migrate/20090513104502_create_cats.rb +12 -0
  229. data/test/rails3_root/db/seeds.rb +7 -0
  230. data/test/rails3_root/public/404.html +26 -0
  231. data/test/rails3_root/public/422.html +26 -0
  232. data/test/rails3_root/public/500.html +26 -0
  233. data/test/rails3_root/public/favicon.ico +0 -0
  234. data/test/rails3_root/public/images/rails.png +0 -0
  235. data/test/rails3_root/public/index.html +279 -0
  236. data/test/rails3_root/public/javascripts/application.js +2 -0
  237. data/test/rails3_root/public/javascripts/controls.js +965 -0
  238. data/test/rails3_root/public/javascripts/dragdrop.js +974 -0
  239. data/test/rails3_root/public/javascripts/effects.js +1123 -0
  240. data/test/rails3_root/public/javascripts/prototype.js +4874 -0
  241. data/test/rails3_root/public/javascripts/rails.js +118 -0
  242. data/test/rails3_root/public/robots.txt +5 -0
  243. data/test/rails3_root/script/rails +9 -0
  244. data/test/rails3_root/test/performance/browsing_test.rb +9 -0
  245. data/test/rails3_root/test/test_helper.rb +13 -0
  246. data/test/rails3_test_helper.rb +6 -0
  247. data/test/rspec_test.rb +207 -0
  248. data/test/test_helper.rb +36 -0
  249. data/test/unit/address_test.rb +10 -0
  250. data/test/unit/cat_test.rb +7 -0
  251. data/test/unit/dog_test.rb +9 -0
  252. data/test/unit/flea_test.rb +14 -0
  253. data/test/unit/friendship_test.rb +6 -0
  254. data/test/unit/post_test.rb +15 -0
  255. data/test/unit/product_test.rb +23 -0
  256. data/test/unit/tag_test.rb +11 -0
  257. data/test/unit/tagging_test.rb +6 -0
  258. data/test/unit/user_test.rb +46 -0
  259. metadata +325 -0
@@ -0,0 +1,79 @@
1
+ module Shoulda # :nodoc:
2
+ module Assertions
3
+ # Asserts that two arrays contain the same elements, the same number of times. Essentially ==, but unordered.
4
+ #
5
+ # assert_same_elements([:a, :b, :c], [:c, :a, :b]) => passes
6
+ def assert_same_elements(a1, a2, msg = nil)
7
+ [:select, :inject, :size].each do |m|
8
+ [a1, a2].each {|a| assert_respond_to(a, m, "Are you sure that #{a.inspect} is an array? It doesn't respond to #{m}.") }
9
+ end
10
+
11
+ assert a1h = a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h }
12
+ assert a2h = a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h }
13
+
14
+ assert_equal(a1h, a2h, msg)
15
+ end
16
+
17
+ # Asserts that the given collection contains item x. If x is a regular expression, ensure that
18
+ # at least one element from the collection matches x. +extra_msg+ is appended to the error message if the assertion fails.
19
+ #
20
+ # assert_contains(['a', '1'], /\d/) => passes
21
+ # assert_contains(['a', '1'], 'a') => passes
22
+ # assert_contains(['a', '1'], /not there/) => fails
23
+ def assert_contains(collection, x, extra_msg = "")
24
+ collection = [collection] unless collection.is_a?(Array)
25
+ msg = "#{x.inspect} not found in #{collection.to_a.inspect} #{extra_msg}"
26
+ case x
27
+ when Regexp
28
+ assert(collection.detect { |e| e =~ x }, msg)
29
+ else
30
+ assert(collection.include?(x), msg)
31
+ end
32
+ end
33
+
34
+ # Asserts that the given collection does not contain item x. If x is a regular expression, ensure that
35
+ # none of the elements from the collection match x.
36
+ def assert_does_not_contain(collection, x, extra_msg = "")
37
+ collection = [collection] unless collection.is_a?(Array)
38
+ msg = "#{x.inspect} found in #{collection.to_a.inspect} " + extra_msg
39
+ case x
40
+ when Regexp
41
+ assert(!collection.detect { |e| e =~ x }, msg)
42
+ else
43
+ assert(!collection.include?(x), msg)
44
+ end
45
+ end
46
+
47
+ # Asserts that the given matcher returns true when +target+ is passed to #matches?
48
+ def assert_accepts(matcher, target, options = {})
49
+ if matcher.respond_to?(:in_context)
50
+ matcher.in_context(self)
51
+ end
52
+
53
+ if matcher.matches?(target)
54
+ assert_block { true }
55
+ if options[:message]
56
+ assert_match options[:message], matcher.negative_failure_message
57
+ end
58
+ else
59
+ assert_block(matcher.failure_message) { false }
60
+ end
61
+ end
62
+
63
+ # Asserts that the given matcher returns false when +target+ is passed to #matches?
64
+ def assert_rejects(matcher, target, options = {})
65
+ if matcher.respond_to?(:in_context)
66
+ matcher.in_context(self)
67
+ end
68
+
69
+ unless matcher.matches?(target)
70
+ assert_block { true }
71
+ if options[:message]
72
+ assert_match options[:message], matcher.failure_message
73
+ end
74
+ else
75
+ assert_block(matcher.negative_failure_message) { false }
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,46 @@
1
+ module Shoulda # :nodoc:
2
+ # Call autoload_macros when you want to load test macros automatically in a non-Rails
3
+ # project (it's done automatically for Rails projects).
4
+ # You don't need to specify ROOT/test/shoulda_macros explicitly. Your custom macros
5
+ # are loaded automatically when you call autoload_macros.
6
+ #
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
10
+ # Dir class.
11
+ #
12
+ # Basic usage (from a test_helper):
13
+ # Shoulda.autoload_macros(File.dirname(__FILE__) + '/..')
14
+ # will load everything in
15
+ # - your_app/test/shoulda_macros
16
+ #
17
+ # To load vendored macros as well:
18
+ # Shoulda.autoload_macros(APP_ROOT, 'vendor/*')
19
+ # will load everything in
20
+ # - APP_ROOT/vendor/*/shoulda_macros
21
+ # - APP_ROOT/test/shoulda_macros
22
+ #
23
+ # To load macros in an app with a vendor directory laid out like Rails':
24
+ # Shoulda.autoload_macros(APP_ROOT, 'vendor/{plugins,gems}/*')
25
+ # or
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
31
+ #
32
+ # If you prefer to stick testing dependencies away from your production dependencies:
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
38
+ def self.autoload_macros(root, *dirs)
39
+ dirs << File.join('test')
40
+ complete_dirs = dirs.map{|d| File.join(root, d, 'shoulda_macros')}
41
+ all_files = complete_dirs.inject([]){ |files, dir| files + Dir[File.join(dir, '*.rb')] }
42
+ all_files.each do |file|
43
+ require file
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,537 @@
1
+ module Shoulda
2
+ class << self
3
+ attr_accessor :contexts
4
+ def contexts # :nodoc:
5
+ @contexts ||= []
6
+ end
7
+
8
+ def current_context # :nodoc:
9
+ self.contexts.last
10
+ end
11
+
12
+ def add_context(context) # :nodoc:
13
+ self.contexts.push(context)
14
+ end
15
+
16
+ def remove_context # :nodoc:
17
+ self.contexts.pop
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+ # == Should statements
23
+ #
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).
28
+ #
29
+ # === Example:
30
+ #
31
+ # class UserTest < Test::Unit::TestCase
32
+ #
33
+ # def setup
34
+ # @user = User.new("John", "Doe")
35
+ # end
36
+ #
37
+ # should "return its full name"
38
+ # assert_equal 'John Doe', @user.full_name
39
+ # end
40
+ #
41
+ # end
42
+ #
43
+ # ...will produce the following test:
44
+ # * <tt>"test: User should return its full name. "</tt>
45
+ #
46
+ # Note: The part before <tt>should</tt> in the test name is gleamed from the name of the Test::Unit class.
47
+ #
48
+ # Should statements can also take a Proc as a <tt>:before </tt>option. This proc runs after any
49
+ # parent context's setups but before the current context's setup.
50
+ #
51
+ # === Example:
52
+ #
53
+ # context "Some context" do
54
+ # setup { puts("I run after the :before proc") }
55
+ #
56
+ # should "run a :before proc", :before => lambda { puts("I run before the setup") } do
57
+ # assert true
58
+ # end
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
82
+
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)
91
+ if Shoulda.current_context
92
+ Shoulda.current_context.should_not(matcher)
93
+ else
94
+ context_name = self.name.gsub(/Test/, "")
95
+ context = Shoulda::Context.new(context_name, self) do
96
+ should_not(matcher)
97
+ end
98
+ context.build
99
+ end
100
+ end
101
+
102
+ # == Before statements
103
+ #
104
+ # Before statements are should statements that run before the current
105
+ # context's setup. These are especially useful when setting expectations.
106
+ #
107
+ # === Example:
108
+ #
109
+ # class UserControllerTest < Test::Unit::TestCase
110
+ # context "the index action" do
111
+ # setup do
112
+ # @users = [Factory(:user)]
113
+ # User.stubs(:find).returns(@users)
114
+ # end
115
+ #
116
+ # context "on GET" do
117
+ # setup { get :index }
118
+ #
119
+ # should respond_with(:success)
120
+ #
121
+ # # runs before "get :index"
122
+ # before_should "find all users" do
123
+ # User.expects(:find).with(:all).returns(@users)
124
+ # end
125
+ # end
126
+ # end
127
+ # end
128
+ def before_should(name, &blk)
129
+ should(name, :before => blk) { assert true }
130
+ end
131
+
132
+ # Just like should, but never runs, and instead prints an 'X' in the Test::Unit output.
133
+ def should_eventually(name, options = {}, &blk)
134
+ context_name = self.name.gsub(/Test/, "")
135
+ context = Shoulda::Context.new(context_name, self) do
136
+ should_eventually(name, &blk)
137
+ end
138
+ context.build
139
+ end
140
+
141
+ # == Contexts
142
+ #
143
+ # A context block groups should statements under a common set of setup/teardown methods.
144
+ # Context blocks can be arbitrarily nested, and can do wonders for improving the maintainability
145
+ # and readability of your test code.
146
+ #
147
+ # A context block can contain setup, should, should_eventually, and teardown blocks.
148
+ #
149
+ # class UserTest < Test::Unit::TestCase
150
+ # context "A User instance" do
151
+ # setup do
152
+ # @user = User.find(:first)
153
+ # end
154
+ #
155
+ # should "return its full name"
156
+ # assert_equal 'John Doe', @user.full_name
157
+ # end
158
+ # end
159
+ # end
160
+ #
161
+ # This code will produce the method <tt>"test: A User instance should return its full name. "</tt>.
162
+ #
163
+ # Contexts may be nested. Nested contexts run their setup blocks from out to in before each
164
+ # should statement. They then run their teardown blocks from in to out after each should statement.
165
+ #
166
+ # class UserTest < Test::Unit::TestCase
167
+ # context "A User instance" do
168
+ # setup do
169
+ # @user = User.find(:first)
170
+ # end
171
+ #
172
+ # should "return its full name"
173
+ # assert_equal 'John Doe', @user.full_name
174
+ # end
175
+ #
176
+ # context "with a profile" do
177
+ # setup do
178
+ # @user.profile = Profile.find(:first)
179
+ # end
180
+ #
181
+ # should "return true when sent :has_profile?"
182
+ # assert @user.has_profile?
183
+ # end
184
+ # end
185
+ # end
186
+ # end
187
+ #
188
+ # This code will produce the following methods
189
+ # * <tt>"test: A User instance should return its full name. "</tt>
190
+ # * <tt>"test: A User instance with a profile should return true when sent :has_profile?. "</tt>
191
+ #
192
+ # <b>Just like should statements, a context block can exist next to normal <tt>def test_the_old_way; end</tt>
193
+ # tests</b>. This means you do not have to fully commit to the context/should syntax in a test file.
194
+
195
+ def context(name, &blk)
196
+ if Shoulda.current_context
197
+ Shoulda.current_context.context(name, &blk)
198
+ else
199
+ context = Shoulda::Context.new(name, self, &blk)
200
+ context.build
201
+ end
202
+ end
203
+
204
+ def fast_context(name, &blk)
205
+ if Shoulda.current_context
206
+ Shoulda.current_context.context(name,&blk)
207
+ else
208
+ context = Shoulda::FastContext.new(name,self,&blk)
209
+ context.build
210
+ end
211
+ end
212
+
213
+ # Returns the class being tested, as determined by the test class name.
214
+ #
215
+ # class UserTest; described_type; end
216
+ # # => User
217
+ def described_type
218
+ self.name.gsub(/Test$/, '').constantize
219
+ end
220
+
221
+ # Sets the return value of the subject instance method:
222
+ #
223
+ # class UserTest < Test::Unit::TestCase
224
+ # subject { User.first }
225
+ #
226
+ # # uses the existing user
227
+ # should validate_uniqueness_of(:email)
228
+ # end
229
+ def subject(&block)
230
+ @subject_block = block
231
+ end
232
+
233
+ def subject_block # :nodoc:
234
+ @subject_block
235
+ end
236
+ end
237
+
238
+ module InstanceMethods
239
+ # Returns an instance of the class under test.
240
+ #
241
+ # class UserTest
242
+ # should "be a user" do
243
+ # assert_kind_of User, subject # passes
244
+ # end
245
+ # end
246
+ #
247
+ # The subject can be explicitly set using the subject class method:
248
+ #
249
+ # class UserTest
250
+ # subject { User.first }
251
+ # should "be an existing user" do
252
+ # assert !subject.new_record? # uses the first user
253
+ # end
254
+ # end
255
+ #
256
+ # The subject is used by all macros that require an instance of the class
257
+ # being tested.
258
+ def subject
259
+ @shoulda_subject ||= construct_subject
260
+ end
261
+
262
+ def subject_block # :nodoc:
263
+ (@shoulda_context && @shoulda_context.subject_block) || self.class.subject_block
264
+ end
265
+
266
+ def get_instance_of(object_or_klass) # :nodoc:
267
+ if object_or_klass.is_a?(Class)
268
+ object_or_klass.new
269
+ else
270
+ object_or_klass
271
+ end
272
+ end
273
+
274
+ def instance_variable_name_for(klass) # :nodoc:
275
+ klass.to_s.split('::').last.underscore
276
+ end
277
+
278
+ private
279
+
280
+ def construct_subject
281
+ if subject_block
282
+ instance_eval(&subject_block)
283
+ else
284
+ get_instance_of(self.class.described_type)
285
+ end
286
+ end
287
+ end
288
+
289
+ class Setup
290
+ def initialize(can_run_count,&blk)
291
+ @ran_already = false
292
+ @can_run_count = (can_run_count == :once ? 1 : 10)
293
+ @blk = blk
294
+ @ivars = {}
295
+ end
296
+
297
+ def run(binding)
298
+ if can_ran?
299
+ before_ivars = binding.instance_variables
300
+ @blk.bind(binding).call
301
+ after_ivars = binding.instance_variables
302
+ capture_ivars(before_ivars,after_ivars,binding) if @can_run_count == 1
303
+ @ran_already = true
304
+ else
305
+ copy_ivars(binding)
306
+ end
307
+ end
308
+
309
+
310
+ private
311
+ def can_ran?
312
+ return false if(@ran_already && @can_run_count == 1)
313
+ return true
314
+ end
315
+ def copy_ivars(binding)
316
+ @ivars.each do |name,value|
317
+ binding.instance_variable_set(name,value)
318
+ end
319
+ end
320
+
321
+ def capture_ivars(before_ivars,after_ivars,binding)
322
+ added_ivars = after_ivars - before_ivars
323
+ added_ivars.each { |var_name|
324
+ @ivars[var_name] = binding.instance_variable_get(var_name)
325
+ }
326
+ end
327
+ end
328
+
329
+
330
+ class Context # :nodoc:
331
+
332
+ attr_accessor :name # my name
333
+ attr_accessor :parent # may be another context, or the original test::unit class.
334
+ attr_accessor :subcontexts # array of contexts nested under myself
335
+ attr_accessor :setup_blocks # blocks given via setup methods
336
+ attr_accessor :teardown_blocks # blocks given via teardown methods
337
+ attr_accessor :shoulds # array of hashes representing the should statements
338
+ attr_accessor :should_eventuallys # array of hashes representing the should eventually statements
339
+ attr_accessor :subject_block
340
+
341
+ def initialize(name, parent, &blk)
342
+ Shoulda.add_context(self)
343
+ self.name = name
344
+ self.parent = parent
345
+ self.setup_blocks = []
346
+ self.teardown_blocks = []
347
+ self.shoulds = []
348
+ self.should_eventuallys = []
349
+ self.subcontexts = []
350
+
351
+ merge_block(&blk)
352
+ Shoulda.remove_context
353
+ end
354
+
355
+ def merge_block(&blk)
356
+ blk.bind(self).call
357
+ end
358
+
359
+ def context(name, &blk)
360
+ self.subcontexts << Context.new(name, self, &blk)
361
+ end
362
+
363
+ def fast_context(name,&blk)
364
+ self.subcontexts << FastContext.new(name,self,&blk)
365
+ end
366
+
367
+ def setup(count = :each,&blk)
368
+ self.setup_blocks << Setup.new(count,&blk)
369
+ end
370
+
371
+ def teardown(&blk)
372
+ self.teardown_blocks << blk
373
+ end
374
+
375
+ def should(name_or_matcher, options = {}, &blk)
376
+ if name_or_matcher.respond_to?(:description) && name_or_matcher.respond_to?(:matches?)
377
+ name = name_or_matcher.description
378
+ blk = lambda { assert_accepts name_or_matcher, subject }
379
+ else
380
+ name = name_or_matcher
381
+ end
382
+
383
+ if blk
384
+ self.shoulds << { :name => name, :before => options[:before], :block => blk }
385
+ else
386
+ self.should_eventuallys << { :name => name }
387
+ end
388
+ end
389
+
390
+ def should_not(matcher)
391
+ name = matcher.description
392
+ blk = lambda { assert_rejects matcher, subject }
393
+ self.shoulds << { :name => "not #{name}", :block => blk }
394
+ end
395
+
396
+ def should_eventually(name, &blk)
397
+ self.should_eventuallys << { :name => name, :block => blk }
398
+ end
399
+
400
+ def subject(&block)
401
+ self.subject_block = block
402
+ end
403
+
404
+ def subject_block
405
+ return @subject_block if @subject_block
406
+ parent.subject_block
407
+ end
408
+
409
+ def full_name
410
+ parent_name = parent.full_name if am_subcontext?
411
+ return [parent_name, name].join(" ").strip
412
+ end
413
+
414
+ def am_subcontext?
415
+ parent.is_a?(self.class) || self.class < parent.class # my parent is the same class as myself.
416
+ end
417
+
418
+ def test_unit_class
419
+ am_subcontext? ? parent.test_unit_class : parent
420
+ end
421
+
422
+ def test_methods
423
+ @test_methods ||= Hash.new { |h,k|
424
+ h[k] = Hash[k.instance_methods.map { |n| [n, true] }]
425
+ }
426
+ end
427
+
428
+ def create_test_from_should_hash(should)
429
+ test_name = ["test:", full_name, "should", "#{should[:name]}. "].flatten.join(' ').to_sym
430
+
431
+ if test_methods[test_unit_class][test_name.to_s] then
432
+ warn " * WARNING: '#{test_name}' is already defined"
433
+ end
434
+
435
+ test_methods[test_unit_class][test_name.to_s] = true
436
+
437
+ context = self
438
+ test_unit_class.send(:define_method, test_name) do
439
+ @shoulda_context = context
440
+ begin
441
+ context.run_parent_setup_blocks(self)
442
+ should[:before].bind(self).call if should[:before]
443
+ context.run_current_setup_blocks(self)
444
+ should[:block].bind(self).call
445
+ ensure
446
+ context.run_all_teardown_blocks(self)
447
+ end
448
+ end
449
+ end
450
+
451
+ def run_all_setup_blocks(binding)
452
+ run_parent_setup_blocks(binding)
453
+ run_current_setup_blocks(binding)
454
+ end
455
+
456
+ def run_parent_setup_blocks(binding)
457
+ self.parent.run_all_setup_blocks(binding) if am_subcontext?
458
+ end
459
+
460
+ def run_current_setup_blocks(binding)
461
+ setup_blocks.each do |setup_block|
462
+ setup_block.run(binding)
463
+ #setup_block.bind(binding).call
464
+ end
465
+ end
466
+
467
+ def run_all_teardown_blocks(binding)
468
+ teardown_blocks.reverse.each do |teardown_block|
469
+ teardown_block.bind(binding).call
470
+ end
471
+ self.parent.run_all_teardown_blocks(binding) if am_subcontext?
472
+ end
473
+
474
+ def print_should_eventuallys
475
+ should_eventuallys.each do |should|
476
+ test_name = [full_name, "should", "#{should[:name]}. "].flatten.join(' ')
477
+ puts " * DEFERRED: " + test_name
478
+ end
479
+ end
480
+
481
+ def build
482
+ shoulds.each do |should|
483
+ create_test_from_should_hash(should)
484
+ end
485
+
486
+ subcontexts.each { |context| context.build }
487
+
488
+ print_should_eventuallys
489
+ end
490
+
491
+ def method_missing(method, *args, &blk)
492
+ test_unit_class.send(method, *args, &blk)
493
+ end
494
+
495
+ end
496
+
497
+ class FastContext < Context
498
+ def build
499
+ run_current_should_blocks
500
+ subcontexts.each { |context| context.build }
501
+
502
+ print_should_eventuallys
503
+ end #end of method build
504
+
505
+ def run_current_should_blocks
506
+ test_name = ["test:", full_name].flatten.join(' ').to_sym
507
+
508
+ if test_unit_class.instance_methods.include?(test_name.to_s)
509
+ warn " * WARNING: '#{test_name}' is already defined"
510
+ end
511
+
512
+ context = self
513
+ all_shoulds = shoulds
514
+ test_unit_class.send(:define_method, test_name) do
515
+ @shoulda_context = context
516
+ @current_should = nil
517
+ begin
518
+ context.run_parent_setup_blocks(self)
519
+ all_shoulds.each {|should|
520
+ @current_should = should
521
+ should[:before].bind(self).call if should[:before]
522
+ }
523
+ context.run_current_setup_blocks(self)
524
+ all_shoulds.each do |should|
525
+ should[:block].bind(self).call
526
+ end
527
+ rescue Test::Unit::AssertionFailedError => e
528
+ error = Test::Unit::AssertionFailedError.new(["FAILED:", context.full_name, "should", "#{@current_should[:name]}:", e.message].flatten.join(' '))
529
+ error.set_backtrace e.backtrace
530
+ raise error
531
+ ensure
532
+ context.run_all_teardown_blocks(self)
533
+ end
534
+ end
535
+ end # end of method run_current_should_blocks
536
+ end #end of class FastContext
537
+ end
@@ -0,0 +1,8 @@
1
+ module Shoulda # :nodoc:
2
+ module Helpers
3
+ # Prints a message to stdout, tagged with the name of the calling method.
4
+ def report!(msg = "")
5
+ puts("#{caller.first}: #{msg}")
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ require 'shoulda/active_record/matchers'
2
+ require 'shoulda/action_controller/matchers'
3
+ require 'shoulda/action_mailer/matchers'
4
+ require 'active_support/test_case'
5
+
6
+ # :enddoc:
7
+ module ActiveSupport
8
+ class TestCase
9
+ include Shoulda::ActiveRecord::Matchers
10
+ include Shoulda::ActionController::Matchers
11
+ include Shoulda::ActionMailer::Matchers
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ require 'shoulda/active_record/matchers'
2
+ require 'shoulda/action_controller/matchers'
3
+ require 'shoulda/action_mailer/matchers'
4
+
5
+ # :enddoc:
6
+
7
+ module RSpec
8
+ module Matchers
9
+ include Shoulda::ActiveRecord::Matchers
10
+ end
11
+
12
+ module Rails
13
+ module ControllerExampleGroup
14
+ include Shoulda::ActionController::Matchers
15
+ end
16
+
17
+ module MailerExampleGroup
18
+ include Shoulda::ActionMailer::Matchers
19
+ end
20
+ end
21
+ end
22
+