tpitale-shoulda 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +10 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +171 -0
  4. data/Rakefile +71 -0
  5. data/bin/convert_to_should_syntax +42 -0
  6. data/lib/shoulda.rb +11 -0
  7. data/lib/shoulda/action_controller.rb +26 -0
  8. data/lib/shoulda/action_controller/macros.rb +240 -0
  9. data/lib/shoulda/action_controller/matchers.rb +37 -0
  10. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +109 -0
  11. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +57 -0
  12. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +81 -0
  13. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +74 -0
  14. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +81 -0
  15. data/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
  16. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +87 -0
  17. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +85 -0
  18. data/lib/shoulda/action_mailer.rb +10 -0
  19. data/lib/shoulda/action_mailer/assertions.rb +38 -0
  20. data/lib/shoulda/action_view.rb +10 -0
  21. data/lib/shoulda/action_view/macros.rb +61 -0
  22. data/lib/shoulda/active_record.rb +16 -0
  23. data/lib/shoulda/active_record/assertions.rb +69 -0
  24. data/lib/shoulda/active_record/helpers.rb +27 -0
  25. data/lib/shoulda/active_record/macros.rb +512 -0
  26. data/lib/shoulda/active_record/matchers.rb +43 -0
  27. data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
  28. data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
  29. data/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
  30. data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
  31. data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
  32. data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
  33. data/lib/shoulda/active_record/matchers/have_db_index_matcher.rb +112 -0
  34. data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +128 -0
  35. data/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
  36. data/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
  37. data/lib/shoulda/active_record/matchers/validate_format_of_matcher.rb +67 -0
  38. data/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
  39. data/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
  40. data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
  41. data/lib/shoulda/active_record/matchers/validation_matcher.rb +57 -0
  42. data/lib/shoulda/assertions.rb +71 -0
  43. data/lib/shoulda/autoload_macros.rb +46 -0
  44. data/lib/shoulda/context.rb +413 -0
  45. data/lib/shoulda/helpers.rb +8 -0
  46. data/lib/shoulda/macros.rb +133 -0
  47. data/lib/shoulda/minitest.rb +24 -0
  48. data/lib/shoulda/private_helpers.rb +13 -0
  49. data/lib/shoulda/proc_extensions.rb +14 -0
  50. data/lib/shoulda/rails.rb +13 -0
  51. data/lib/shoulda/rspec.rb +11 -0
  52. data/lib/shoulda/tasks.rb +3 -0
  53. data/lib/shoulda/tasks/list_tests.rake +29 -0
  54. data/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
  55. data/lib/shoulda/test_unit.rb +22 -0
  56. data/rails/init.rb +7 -0
  57. data/test/README +36 -0
  58. data/test/fail_macros.rb +39 -0
  59. data/test/fixtures/addresses.yml +3 -0
  60. data/test/fixtures/friendships.yml +0 -0
  61. data/test/fixtures/posts.yml +5 -0
  62. data/test/fixtures/products.yml +0 -0
  63. data/test/fixtures/taggings.yml +0 -0
  64. data/test/fixtures/tags.yml +9 -0
  65. data/test/fixtures/users.yml +6 -0
  66. data/test/functional/posts_controller_test.rb +121 -0
  67. data/test/functional/users_controller_test.rb +19 -0
  68. data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +68 -0
  69. data/test/matchers/active_record/allow_value_matcher_test.rb +64 -0
  70. data/test/matchers/active_record/association_matcher_test.rb +263 -0
  71. data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +80 -0
  72. data/test/matchers/active_record/ensure_length_of_matcher_test.rb +158 -0
  73. data/test/matchers/active_record/have_db_column_matcher_test.rb +169 -0
  74. data/test/matchers/active_record/have_db_index_matcher_test.rb +91 -0
  75. data/test/matchers/active_record/have_named_scope_matcher_test.rb +65 -0
  76. data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +29 -0
  77. data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +44 -0
  78. data/test/matchers/active_record/validate_format_of_matcher_test.rb +39 -0
  79. data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +52 -0
  80. data/test/matchers/active_record/validate_presence_of_matcher_test.rb +86 -0
  81. data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +147 -0
  82. data/test/matchers/controller/assign_to_matcher_test.rb +35 -0
  83. data/test/matchers/controller/filter_param_matcher_test.rb +32 -0
  84. data/test/matchers/controller/render_with_layout_matcher_test.rb +33 -0
  85. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +32 -0
  86. data/test/matchers/controller/respond_with_matcher_test.rb +106 -0
  87. data/test/matchers/controller/route_matcher_test.rb +58 -0
  88. data/test/matchers/controller/set_session_matcher_test.rb +38 -0
  89. data/test/matchers/controller/set_the_flash_matcher.rb +41 -0
  90. data/test/model_builder.rb +106 -0
  91. data/test/other/autoload_macro_test.rb +18 -0
  92. data/test/other/context_test.rb +203 -0
  93. data/test/other/convert_to_should_syntax_test.rb +63 -0
  94. data/test/other/helpers_test.rb +340 -0
  95. data/test/other/private_helpers_test.rb +32 -0
  96. data/test/other/should_test.rb +271 -0
  97. data/test/rails_root/app/controllers/application_controller.rb +25 -0
  98. data/test/rails_root/app/controllers/posts_controller.rb +87 -0
  99. data/test/rails_root/app/controllers/users_controller.rb +84 -0
  100. data/test/rails_root/app/helpers/application_helper.rb +3 -0
  101. data/test/rails_root/app/helpers/posts_helper.rb +2 -0
  102. data/test/rails_root/app/helpers/users_helper.rb +2 -0
  103. data/test/rails_root/app/models/address.rb +7 -0
  104. data/test/rails_root/app/models/flea.rb +3 -0
  105. data/test/rails_root/app/models/friendship.rb +4 -0
  106. data/test/rails_root/app/models/pets/cat.rb +7 -0
  107. data/test/rails_root/app/models/pets/dog.rb +10 -0
  108. data/test/rails_root/app/models/post.rb +12 -0
  109. data/test/rails_root/app/models/product.rb +12 -0
  110. data/test/rails_root/app/models/profile.rb +2 -0
  111. data/test/rails_root/app/models/registration.rb +2 -0
  112. data/test/rails_root/app/models/tag.rb +8 -0
  113. data/test/rails_root/app/models/tagging.rb +4 -0
  114. data/test/rails_root/app/models/treat.rb +3 -0
  115. data/test/rails_root/app/models/user.rb +32 -0
  116. data/test/rails_root/app/views/layouts/posts.rhtml +19 -0
  117. data/test/rails_root/app/views/layouts/users.rhtml +17 -0
  118. data/test/rails_root/app/views/layouts/wide.html.erb +1 -0
  119. data/test/rails_root/app/views/posts/edit.rhtml +27 -0
  120. data/test/rails_root/app/views/posts/index.rhtml +25 -0
  121. data/test/rails_root/app/views/posts/new.rhtml +26 -0
  122. data/test/rails_root/app/views/posts/show.rhtml +18 -0
  123. data/test/rails_root/app/views/users/edit.rhtml +22 -0
  124. data/test/rails_root/app/views/users/index.rhtml +22 -0
  125. data/test/rails_root/app/views/users/new.rhtml +21 -0
  126. data/test/rails_root/app/views/users/show.rhtml +13 -0
  127. data/test/rails_root/config/boot.rb +110 -0
  128. data/test/rails_root/config/database.yml +4 -0
  129. data/test/rails_root/config/environment.rb +18 -0
  130. data/test/rails_root/config/environments/test.rb +0 -0
  131. data/test/rails_root/config/initializers/new_rails_defaults.rb +15 -0
  132. data/test/rails_root/config/initializers/shoulda.rb +8 -0
  133. data/test/rails_root/config/routes.rb +6 -0
  134. data/test/rails_root/db/migrate/001_create_users.rb +19 -0
  135. data/test/rails_root/db/migrate/002_create_posts.rb +13 -0
  136. data/test/rails_root/db/migrate/003_create_taggings.rb +12 -0
  137. data/test/rails_root/db/migrate/004_create_tags.rb +11 -0
  138. data/test/rails_root/db/migrate/005_create_dogs.rb +12 -0
  139. data/test/rails_root/db/migrate/006_create_addresses.rb +14 -0
  140. data/test/rails_root/db/migrate/007_create_fleas.rb +11 -0
  141. data/test/rails_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  142. data/test/rails_root/db/migrate/009_create_products.rb +17 -0
  143. data/test/rails_root/db/migrate/010_create_friendships.rb +14 -0
  144. data/test/rails_root/db/migrate/011_create_treats.rb +12 -0
  145. data/test/rails_root/db/migrate/20090506203502_create_profiles.rb +12 -0
  146. data/test/rails_root/db/migrate/20090506203536_create_registrations.rb +14 -0
  147. data/test/rails_root/db/migrate/20090513104502_create_cats.rb +12 -0
  148. data/test/rails_root/db/schema.rb +0 -0
  149. data/test/rails_root/log/test.log +1 -0
  150. data/test/rails_root/public/404.html +30 -0
  151. data/test/rails_root/public/422.html +30 -0
  152. data/test/rails_root/public/500.html +30 -0
  153. data/test/rails_root/script/console +3 -0
  154. data/test/rails_root/script/generate +3 -0
  155. data/test/rails_root/test/shoulda_macros/custom_macro.rb +6 -0
  156. data/test/rails_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
  157. data/test/rails_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
  158. data/test/rspec_test.rb +207 -0
  159. data/test/test_helper.rb +28 -0
  160. data/test/unit/address_test.rb +10 -0
  161. data/test/unit/cat_test.rb +7 -0
  162. data/test/unit/dog_test.rb +9 -0
  163. data/test/unit/flea_test.rb +6 -0
  164. data/test/unit/friendship_test.rb +6 -0
  165. data/test/unit/post_test.rb +19 -0
  166. data/test/unit/product_test.rb +23 -0
  167. data/test/unit/tag_test.rb +15 -0
  168. data/test/unit/tagging_test.rb +6 -0
  169. data/test/unit/user_test.rb +80 -0
  170. metadata +226 -0
@@ -0,0 +1,121 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'posts_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class PostsController; def rescue_action(e) raise e end; end
6
+
7
+ class PostsControllerTest < ActionController::TestCase
8
+ fixtures :all
9
+
10
+ def setup
11
+ @controller = PostsController.new
12
+ @request = ActionController::TestRequest.new
13
+ @response = ActionController::TestResponse.new
14
+ @post = Post.find(:first)
15
+ end
16
+
17
+ # autodetects the :controller
18
+ should_route :get, '/posts', :action => :index
19
+ # explicitly specify :controller
20
+ should_route :post, '/posts', :controller => :posts, :action => :create
21
+ # non-string parameter
22
+ should_route :get, '/posts/1', :action => :show, :id => 1
23
+ # string-parameter
24
+ should_route :put, '/posts/1', :action => :update, :id => "1"
25
+ should_route :delete, '/posts/1', :action => :destroy, :id => 1
26
+ should_route :get, '/posts/new', :action => :new
27
+
28
+ # Test the nested routes
29
+ should_route :get, '/users/5/posts', :action => :index, :user_id => 5
30
+ should_route :post, '/users/5/posts', :action => :create, :user_id => 5
31
+ should_route :get, '/users/5/posts/1', :action => :show, :id => 1, :user_id => 5
32
+ should_route :delete, '/users/5/posts/1', :action => :destroy, :id => 1, :user_id => 5
33
+ should_route :get, '/users/5/posts/new', :action => :new, :user_id => 5
34
+ should_route :put, '/users/5/posts/1', :action => :update, :id => 1, :user_id => 5
35
+
36
+ context "Logged in" do
37
+ setup do
38
+ @request.session[:logged_in] = true
39
+ end
40
+
41
+ context "viewing posts for a user" do
42
+ setup do
43
+ get :index, :user_id => users(:first)
44
+ end
45
+ should_respond_with :success
46
+ should_assign_to :user, :class => User
47
+ should_render_template :index
48
+ should_assign_to(:user) { users(:first) }
49
+ should_fail do
50
+ should_assign_to :user, :class => Post
51
+ end
52
+ should_fail do
53
+ should_assign_to(:user) { posts(:first) }
54
+ end
55
+ should_assign_to :posts
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
+ end
60
+
61
+ context "viewing posts for a user with rss format" do
62
+ setup do
63
+ get :index, :user_id => users(:first), :format => 'rss'
64
+ @user = users(:first)
65
+ end
66
+ should_respond_with :success
67
+ should_respond_with_content_type 'application/rss+xml'
68
+ should_respond_with_content_type :rss
69
+ should_respond_with_content_type /rss/
70
+ should_set_session(:mischief) { nil }
71
+ should_set_session(:special) { '$2 off your next purchase' }
72
+ should_set_session(:special_user_id) { @user.id }
73
+ should_set_session(:false_var) { false }
74
+ should_fail do
75
+ should_set_session(:special_user_id) { 'value' }
76
+ end
77
+ should_assign_to :user, :posts
78
+ should_not_assign_to :foo, :bar
79
+ end
80
+
81
+ context "viewing a post on GET to #show" do
82
+ setup { get :show, :user_id => users(:first), :id => posts(:first) }
83
+ should_render_with_layout 'wide'
84
+ context "with a symbol" do # to avoid redefining a test
85
+ should_render_with_layout :wide
86
+ end
87
+ should_assign_to :false_flag
88
+ should_set_the_flash_to nil
89
+ should_fail do
90
+ should_set_the_flash_to /.*/
91
+ end
92
+ end
93
+
94
+ context "on GET to #new" do
95
+ setup { get :new, :user_id => users(:first) }
96
+ should_render_without_layout
97
+ should_not_set_the_flash
98
+ should_render_a_form
99
+ end
100
+
101
+ context "on POST to #create" do
102
+ setup do
103
+ post :create, :user_id => users(:first),
104
+ :post => { :title => "first post",
105
+ :body => 'blah blah blah' }
106
+ end
107
+
108
+ should_redirect_to('the created post') { user_post_url(users(:first),
109
+ assigns(:post)) }
110
+ should_fail do
111
+ should_redirect_to('elsewhere') { user_posts_url(users(:first)) }
112
+ end
113
+
114
+ should_set_the_flash_to /success/
115
+ should_fail do
116
+ should_not_set_the_flash
117
+ end
118
+ end
119
+ end
120
+
121
+ end
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'users_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class UsersController; def rescue_action(e) raise e end; end
6
+
7
+ class UsersControllerTest < ActionController::TestCase
8
+ fixtures :all
9
+
10
+ def setup
11
+ @controller = UsersController.new
12
+ @request = ActionController::TestRequest.new
13
+ @response = ActionController::TestResponse.new
14
+ @user = User.find(:first)
15
+ end
16
+
17
+ should_filter_params :ssn
18
+
19
+ end
@@ -0,0 +1,68 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
2
+
3
+ class AllowMassAssignmentOfMatcherTest < ActiveSupport::TestCase # :nodoc:
4
+
5
+ context "an attribute that is blacklisted from mass-assignment" do
6
+ setup do
7
+ define_model :example, :attr => :string do
8
+ attr_protected :attr
9
+ end
10
+ @model = Example.new
11
+ end
12
+
13
+ should "reject being mass-assignable" do
14
+ assert_rejects allow_mass_assignment_of(:attr), @model
15
+ end
16
+ end
17
+
18
+ context "an attribute that is not whitelisted for mass-assignment" do
19
+ setup do
20
+ define_model :example, :attr => :string, :other => :string do
21
+ attr_accessible :other
22
+ end
23
+ @model = Example.new
24
+ end
25
+
26
+ should "reject being mass-assignable" do
27
+ assert_rejects allow_mass_assignment_of(:attr), @model
28
+ end
29
+ end
30
+
31
+ context "an attribute that is whitelisted for mass-assignment" do
32
+ setup do
33
+ define_model :example, :attr => :string do
34
+ attr_accessible :attr
35
+ end
36
+ @model = Example.new
37
+ end
38
+
39
+ should "accept being mass-assignable" do
40
+ assert_accepts allow_mass_assignment_of(:attr), @model
41
+ end
42
+ end
43
+
44
+ context "an attribute not included in the mass-assignment blacklist" do
45
+ setup do
46
+ define_model :example, :attr => :string, :other => :string do
47
+ attr_protected :other
48
+ end
49
+ @model = Example.new
50
+ end
51
+
52
+ should "accept being mass-assignable" do
53
+ assert_accepts allow_mass_assignment_of(:attr), @model
54
+ end
55
+ end
56
+
57
+ context "an attribute on a class with no protected attributes" do
58
+ setup do
59
+ define_model :example, :attr => :string
60
+ @model = Example.new
61
+ end
62
+
63
+ should "accept being mass-assignable" do
64
+ assert_accepts allow_mass_assignment_of(:attr), @model
65
+ end
66
+ end
67
+
68
+ end
@@ -0,0 +1,64 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
2
+
3
+ class AllowValueMatcherTest < ActiveSupport::TestCase # :nodoc:
4
+
5
+ context "an attribute with a format validation" do
6
+ setup do
7
+ define_model :example, :attr => :string do
8
+ validates_format_of :attr, :with => /abc/
9
+ end
10
+ @model = Example.new
11
+ end
12
+
13
+ should "allow a good value" do
14
+ assert_accepts allow_value("abcde").for(:attr), @model
15
+ end
16
+
17
+ should "not allow a bad value" do
18
+ assert_rejects allow_value("xyz").for(:attr), @model
19
+ end
20
+ end
21
+
22
+ context "an attribute with a format validation and a custom message" do
23
+ setup do
24
+ define_model :example, :attr => :string do
25
+ validates_format_of :attr, :with => /abc/, :message => 'bad value'
26
+ end
27
+ @model = Example.new
28
+ end
29
+
30
+ should "allow a good value" do
31
+ assert_accepts allow_value('abcde').for(:attr).with_message(/bad/),
32
+ @model
33
+ end
34
+
35
+ should "not allow a bad value" do
36
+ assert_rejects allow_value('xyz').for(:attr).with_message(/bad/),
37
+ @model
38
+ end
39
+ end
40
+
41
+ context "an attribute with several validations" do
42
+ setup do
43
+ define_model :example, :attr => :string do
44
+ validates_presence_of :attr
45
+ validates_length_of :attr, :within => 1..5
46
+ validates_numericality_of :attr, :greater_than_or_equal_to => 1,
47
+ :less_than_or_equal_to => 50000
48
+ end
49
+ @model = Example.new
50
+ end
51
+
52
+ should "allow a good value" do
53
+ assert_accepts allow_value("12345").for(:attr), @model
54
+ end
55
+
56
+ bad_values = [nil, "", "abc", "0", "50001", "123456"]
57
+ bad_values.each do |value|
58
+ should "not allow a bad value (#{value.inspect})" do
59
+ assert_rejects allow_value(value).for(:attr), @model
60
+ end
61
+ end
62
+ end
63
+
64
+ end
@@ -0,0 +1,263 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
2
+
3
+ class AssociationMatcherTest < ActiveSupport::TestCase # :nodoc:
4
+
5
+ context "belong_to" do
6
+ setup do
7
+ @matcher = belong_to(:parent)
8
+ end
9
+
10
+ should "accept a good association with the default foreign key" do
11
+ define_model :parent
12
+ define_model :child, :parent_id => :integer do
13
+ belongs_to :parent
14
+ end
15
+ assert_accepts @matcher, Child.new
16
+ end
17
+
18
+ should "reject a nonexistent association" do
19
+ define_model :child
20
+ assert_rejects @matcher, Child.new
21
+ end
22
+
23
+ should "reject an association of the wrong type" do
24
+ define_model :parent, :child_id => :integer
25
+ child_class = define_model :child do
26
+ has_one :parent
27
+ end
28
+ assert_rejects @matcher, Child.new
29
+ end
30
+
31
+ should "reject an association that has a nonexistent foreign key" do
32
+ define_model :parent
33
+ define_model :child do
34
+ belongs_to :parent
35
+ end
36
+ assert_rejects @matcher, Child.new
37
+ end
38
+
39
+ should "accept an association with an existing custom foreign key" do
40
+ define_model :parent
41
+ define_model :child, :guardian_id => :integer do
42
+ belongs_to :parent, :foreign_key => 'guardian_id'
43
+ end
44
+ assert_accepts @matcher, Child.new
45
+ end
46
+
47
+ should "accept a polymorphic association" do
48
+ define_model :child, :parent_type => :string,
49
+ :parent_id => :integer do
50
+ belongs_to :parent, :polymorphic => true
51
+ end
52
+ assert_accepts @matcher, Child.new
53
+ end
54
+
55
+ should "accept an association with a valid :dependent option" do
56
+ define_model :parent
57
+ define_model :child, :parent_id => :integer do
58
+ belongs_to :parent, :dependent => :destroy
59
+ end
60
+ assert_accepts @matcher.dependent(:destroy), Child.new
61
+ end
62
+
63
+ should "reject an association with a bad :dependent option" do
64
+ define_model :parent
65
+ define_model :child, :parent_id => :integer do
66
+ belongs_to :parent
67
+ end
68
+ assert_rejects @matcher.dependent(:destroy), Child.new
69
+ end
70
+ end
71
+
72
+ context "have_many" do
73
+ setup do
74
+ @matcher = have_many(:children)
75
+ end
76
+
77
+ should "accept a valid association without any options" do
78
+ define_model :child, :parent_id => :integer
79
+ define_model :parent do
80
+ has_many :children
81
+ end
82
+ assert_accepts @matcher, Parent.new
83
+ end
84
+
85
+ should "accept a valid association with a :through option" do
86
+ define_model :child
87
+ define_model :conception, :child_id => :integer,
88
+ :parent_id => :integer do
89
+ belongs_to :child
90
+ end
91
+ define_model :parent do
92
+ has_many :conceptions
93
+ has_many :children, :through => :conceptions
94
+ end
95
+ assert_accepts @matcher, Parent.new
96
+ end
97
+
98
+ should "accept a valid association with an :as option" do
99
+ define_model :child, :guardian_type => :string,
100
+ :guardian_id => :integer
101
+ define_model :parent do
102
+ has_many :children, :as => :guardian
103
+ end
104
+ assert_accepts @matcher, Parent.new
105
+ end
106
+
107
+ should "reject an association that has a nonexistent foreign key" do
108
+ define_model :child
109
+ define_model :parent do
110
+ has_many :children
111
+ end
112
+ assert_rejects @matcher, Parent.new
113
+ end
114
+
115
+ should "reject an association with a bad :as option" do
116
+ define_model :child, :caretaker_type => :string,
117
+ :caretaker_id => :integer
118
+ define_model :parent do
119
+ has_many :children, :as => :guardian
120
+ end
121
+ assert_rejects @matcher, Parent.new
122
+ end
123
+
124
+ should "reject an association that has a bad :through option" do
125
+ define_model :child, :parent_id => :integer
126
+ define_model :parent do
127
+ has_many :children
128
+ end
129
+ assert_rejects @matcher.through(:conceptions),
130
+ Parent.new,
131
+ :message => /does not have any relationship to conceptions/
132
+ end
133
+
134
+ should "reject an association that has the wrong :through option" do
135
+ define_model :child
136
+ define_model :conception, :child_id => :integer,
137
+ :parent_id => :integer do
138
+ belongs_to :child
139
+ end
140
+ define_model :parent do
141
+ has_many :conceptions
142
+ has_many :relationships
143
+ has_many :children, :through => :conceptions
144
+ end
145
+ assert_rejects @matcher.through(:relationships),
146
+ Parent.new,
147
+ :message => /through relationships, but got it through conceptions/
148
+ end
149
+
150
+ should "accept an association with a valid :dependent option" do
151
+ define_model :child, :parent_id => :integer
152
+ define_model :parent do
153
+ has_many :children, :dependent => :destroy
154
+ end
155
+ assert_accepts @matcher.dependent(:destroy), Parent.new
156
+ end
157
+
158
+ should "reject an association with a bad :dependent option" do
159
+ define_model :child, :parent_id => :integer
160
+ define_model :parent do
161
+ has_many :children
162
+ end
163
+ assert_rejects @matcher.dependent(:destroy), Parent.new
164
+ end
165
+ end
166
+
167
+ context "have_one" do
168
+ setup do
169
+ @matcher = have_one(:profile)
170
+ end
171
+
172
+ should "accept a valid association without any options" do
173
+ define_model :profile, :person_id => :integer
174
+ define_model :person do
175
+ has_one :profile
176
+ end
177
+ assert_accepts @matcher, Person.new
178
+ end
179
+
180
+ should "accept a valid association with an :as option" do
181
+ define_model :profile, :profilable_id => :integer,
182
+ :profilable_type => :string
183
+ define_model :person do
184
+ has_one :profile, :as => :profilable
185
+ end
186
+ assert_accepts @matcher, Person.new
187
+ end
188
+
189
+ should "reject an association that has a nonexistent foreign key" do
190
+ define_model :profile
191
+ define_model :person do
192
+ has_one :profile
193
+ end
194
+ assert_rejects @matcher, Person.new
195
+ end
196
+
197
+ should "reject an association with a bad :as option" do
198
+ define_model :profile, :profilable_id => :integer,
199
+ :profilable_type => :string
200
+ define_model :person do
201
+ has_one :profile, :as => :describable
202
+ end
203
+ assert_rejects @matcher, Person.new
204
+ end
205
+
206
+ should "accept an association with a valid :dependent option" do
207
+ define_model :profile, :person_id => :integer
208
+ define_model :person do
209
+ has_one :profile, :dependent => :destroy
210
+ end
211
+ assert_accepts @matcher.dependent(:destroy), Person.new
212
+ end
213
+
214
+ should "reject an association with a bad :dependent option" do
215
+ define_model :profile, :person_id => :integer
216
+ define_model :person do
217
+ has_one :profile
218
+ end
219
+ assert_rejects @matcher.dependent(:destroy), Person.new
220
+ end
221
+ end
222
+
223
+ context "have_and_belong_to_many" do
224
+ setup do
225
+ @matcher = have_and_belong_to_many(:relatives)
226
+ end
227
+
228
+ should "accept a valid association" do
229
+ define_model :relatives
230
+ define_model :person do
231
+ has_and_belongs_to_many :relatives
232
+ end
233
+ define_model :people_relative, :person_id => :integer,
234
+ :relative_id => :integer
235
+ assert_accepts @matcher, Person.new
236
+ end
237
+
238
+ should "reject a nonexistent association" do
239
+ define_model :relatives
240
+ define_model :person
241
+ define_model :people_relative, :person_id => :integer,
242
+ :relative_id => :integer
243
+ assert_rejects @matcher, Person.new
244
+ end
245
+
246
+ should "reject an association with a nonexistent join table" do
247
+ define_model :relatives
248
+ define_model :person do
249
+ has_and_belongs_to_many :relatives
250
+ end
251
+ assert_rejects @matcher, Person.new
252
+ end
253
+
254
+ should "reject an association of the wrong type" do
255
+ define_model :relatives, :person_id => :integer
256
+ define_model :person do
257
+ has_many :relatives
258
+ end
259
+ assert_rejects @matcher, Person.new
260
+ end
261
+ end
262
+
263
+ end