shoulda-matchers 1.4.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/.travis.yml +11 -3
  2. data/Appraisals +3 -3
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +69 -70
  5. data/MIT-LICENSE +1 -1
  6. data/NEWS.md +22 -4
  7. data/README.md +3 -1
  8. data/Rakefile +9 -5
  9. data/features/step_definitions/rails_steps.rb +7 -7
  10. data/features/support/env.rb +1 -1
  11. data/gemfiles/3.0.gemfile +1 -1
  12. data/gemfiles/3.0.gemfile.lock +25 -22
  13. data/gemfiles/3.1.gemfile +1 -1
  14. data/gemfiles/3.1.gemfile.lock +27 -24
  15. data/gemfiles/3.2.gemfile +1 -1
  16. data/gemfiles/3.2.gemfile.lock +56 -52
  17. data/lib/shoulda/matchers/action_controller.rb +3 -2
  18. data/lib/shoulda/matchers/action_controller/assign_to_matcher.rb +10 -8
  19. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +2 -4
  20. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +3 -4
  21. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +3 -4
  22. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +6 -6
  23. data/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb +5 -2
  24. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +2 -2
  25. data/lib/shoulda/matchers/action_controller/route_matcher.rb +12 -12
  26. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -4
  27. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +10 -11
  28. data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +121 -0
  29. data/lib/shoulda/matchers/action_mailer/have_sent_email_matcher.rb +7 -4
  30. data/lib/shoulda/matchers/active_model.rb +1 -1
  31. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +8 -8
  32. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +5 -4
  33. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +3 -3
  34. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +2 -2
  35. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +0 -1
  36. data/lib/shoulda/matchers/active_model/helpers.rb +16 -7
  37. data/lib/shoulda/matchers/active_model/only_integer_matcher.rb +3 -3
  38. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +8 -6
  39. data/lib/shoulda/matchers/active_model/validate_format_of_matcher.rb +19 -10
  40. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +4 -4
  41. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +19 -21
  42. data/lib/shoulda/matchers/active_model/validation_matcher.rb +7 -7
  43. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +1 -1
  44. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +5 -5
  45. data/lib/shoulda/matchers/active_record/association_matcher.rb +3 -3
  46. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +11 -7
  47. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +2 -2
  48. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +5 -5
  49. data/lib/shoulda/matchers/active_record/query_the_database_matcher.rb +5 -2
  50. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +3 -3
  51. data/lib/shoulda/matchers/assertion_error.rb +4 -1
  52. data/lib/shoulda/matchers/independent/delegate_matcher.rb +17 -7
  53. data/lib/shoulda/matchers/integrations/rspec.rb +19 -33
  54. data/lib/shoulda/matchers/version.rb +1 -1
  55. data/shoulda-matchers.gemspec +6 -4
  56. data/spec/shoulda/matchers/action_controller/assign_to_matcher_spec.rb +66 -0
  57. data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +22 -0
  58. data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +42 -0
  59. data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +78 -0
  60. data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +58 -0
  61. data/spec/shoulda/matchers/action_controller/respond_with_content_type_matcher_spec.rb +31 -0
  62. data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +31 -0
  63. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +65 -0
  64. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +51 -0
  65. data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +153 -0
  66. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +142 -0
  67. data/spec/shoulda/matchers/action_mailer/have_sent_email_spec.rb +324 -0
  68. data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +111 -0
  69. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +124 -0
  70. data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +43 -0
  71. data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +74 -0
  72. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +171 -0
  73. data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +113 -0
  74. data/spec/shoulda/{active_model → matchers/active_model}/exception_message_finder_spec.rb +2 -2
  75. data/spec/shoulda/matchers/active_model/helpers_spec.rb +158 -0
  76. data/spec/shoulda/matchers/active_model/only_integer_matcher_spec.rb +52 -0
  77. data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +41 -0
  78. data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +41 -0
  79. data/spec/shoulda/matchers/active_model/validate_format_of_matcher_spec.rb +75 -0
  80. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +73 -0
  81. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +127 -0
  82. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +175 -0
  83. data/spec/shoulda/{active_model → matchers/active_model}/validation_message_finder_spec.rb +0 -1
  84. data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +106 -0
  85. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +534 -0
  86. data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +111 -0
  87. data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +78 -0
  88. data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +41 -0
  89. data/spec/shoulda/{active_record → matchers/active_record}/query_the_database_matcher_spec.rb +10 -10
  90. data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +86 -0
  91. data/spec/shoulda/{independent → matchers/independent}/delegate_matcher_spec.rb +55 -34
  92. data/spec/spec_helper.rb +1 -2
  93. data/spec/support/active_model_versions.rb +4 -0
  94. data/spec/support/activemodel_helpers.rb +19 -0
  95. data/spec/support/controller_builder.rb +38 -12
  96. data/spec/support/model_builder.rb +8 -2
  97. metadata +106 -98
  98. data/spec/fixtures/addresses.yml +0 -3
  99. data/spec/fixtures/friendships.yml +0 -0
  100. data/spec/fixtures/posts.yml +0 -5
  101. data/spec/fixtures/products.yml +0 -0
  102. data/spec/fixtures/taggings.yml +0 -0
  103. data/spec/fixtures/tags.yml +0 -9
  104. data/spec/fixtures/users.yml +0 -6
  105. data/spec/shoulda/action_controller/assign_to_matcher_spec.rb +0 -63
  106. data/spec/shoulda/action_controller/filter_param_matcher_spec.rb +0 -20
  107. data/spec/shoulda/action_controller/redirect_to_matcher_spec.rb +0 -40
  108. data/spec/shoulda/action_controller/render_template_matcher_spec.rb +0 -69
  109. data/spec/shoulda/action_controller/render_with_layout_matcher_spec.rb +0 -55
  110. data/spec/shoulda/action_controller/respond_with_content_type_matcher_spec.rb +0 -28
  111. data/spec/shoulda/action_controller/respond_with_matcher_spec.rb +0 -83
  112. data/spec/shoulda/action_controller/route_matcher_spec.rb +0 -65
  113. data/spec/shoulda/action_controller/set_session_matcher_spec.rb +0 -46
  114. data/spec/shoulda/action_controller/set_the_flash_matcher_spec.rb +0 -130
  115. data/spec/shoulda/action_mailer/have_sent_email_spec.rb +0 -333
  116. data/spec/shoulda/active_model/allow_mass_assignment_of_matcher_spec.rb +0 -115
  117. data/spec/shoulda/active_model/allow_value_matcher_spec.rb +0 -131
  118. data/spec/shoulda/active_model/disallow_value_matcher_spec.rb +0 -65
  119. data/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb +0 -79
  120. data/spec/shoulda/active_model/ensure_inclusion_of_matcher_spec.rb +0 -181
  121. data/spec/shoulda/active_model/ensure_length_of_matcher_spec.rb +0 -138
  122. data/spec/shoulda/active_model/helpers_spec.rb +0 -129
  123. data/spec/shoulda/active_model/only_integer_matcher_spec.rb +0 -69
  124. data/spec/shoulda/active_model/validate_acceptance_of_matcher_spec.rb +0 -43
  125. data/spec/shoulda/active_model/validate_confirmation_of_matcher_spec.rb +0 -48
  126. data/spec/shoulda/active_model/validate_format_of_matcher_spec.rb +0 -79
  127. data/spec/shoulda/active_model/validate_numericality_of_matcher_spec.rb +0 -112
  128. data/spec/shoulda/active_model/validate_presence_of_matcher_spec.rb +0 -135
  129. data/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb +0 -154
  130. data/spec/shoulda/active_record/accept_nested_attributes_for_matcher_spec.rb +0 -84
  131. data/spec/shoulda/active_record/association_matcher_spec.rb +0 -642
  132. data/spec/shoulda/active_record/have_db_column_matcher_spec.rb +0 -185
  133. data/spec/shoulda/active_record/have_db_index_matcher_spec.rb +0 -105
  134. data/spec/shoulda/active_record/have_readonly_attributes_matcher_spec.rb +0 -46
  135. data/spec/shoulda/active_record/serialize_matcher_spec.rb +0 -81
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::AllowMassAssignmentOfMatcher do
4
+ context '#description' do
5
+ context 'without a role' do
6
+ it 'includes the attribute name' do
7
+ described_class.new(:attr).description.should ==
8
+ 'allow mass assignment of attr'
9
+ end
10
+ end
11
+
12
+ if active_model_3_1?
13
+ context 'with a role' do
14
+ it 'includes the attribute name and the role' do
15
+ described_class.new(:attr).as(:admin).description.should ==
16
+ 'allow mass assignment of attr as admin'
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ context 'an attribute that is blacklisted from mass-assignment' do
23
+ it 'rejects being mass-assignable' do
24
+ model = define_model(:example, :blacklisted => :string) do
25
+ attr_protected :blacklisted
26
+ end.new
27
+
28
+ model.should_not allow_mass_assignment_of(:blacklisted)
29
+ end
30
+ end
31
+
32
+ context 'an attribute that is not whitelisted for mass-assignment' do
33
+ it 'rejects being mass-assignable' do
34
+ model = define_model(:example, :not_whitelisted => :string,
35
+ :whitelisted => :string) do
36
+ attr_accessible :whitelisted
37
+ end.new
38
+
39
+ model.should_not allow_mass_assignment_of(:not_whitelisted)
40
+ end
41
+ end
42
+
43
+ context 'an attribute that is whitelisted for mass-assignment' do
44
+ it 'accepts being mass-assignable' do
45
+ define_model(:example, :whitelisted => :string) do
46
+ attr_accessible :whitelisted
47
+ end.new.should allow_mass_assignment_of(:whitelisted)
48
+ end
49
+ end
50
+
51
+ context 'an attribute not included in the mass-assignment blacklist' do
52
+ it 'accepts being mass-assignable' do
53
+ model = define_model(:example, :not_blacklisted => :string,
54
+ :blacklisted => :string) do
55
+ attr_protected :blacklisted
56
+ end.new
57
+
58
+ model.should allow_mass_assignment_of(:not_blacklisted)
59
+ end
60
+ end
61
+
62
+ unless active_model_3_2?
63
+ context 'an attribute on a class with no protected attributes' do
64
+ it 'accepts being mass-assignable' do
65
+ no_protected_attributes.should allow_mass_assignment_of(:attr)
66
+ end
67
+
68
+ it 'assigns a negative failure message' do
69
+ matcher = allow_mass_assignment_of(:attr)
70
+
71
+ matcher.matches?(no_protected_attributes).should be_true
72
+
73
+ matcher.failure_message_for_should_not.should_not be_nil
74
+ end
75
+ end
76
+
77
+ def no_protected_attributes
78
+ define_model(:example, :attr => :string).new
79
+ end
80
+ end
81
+
82
+ context 'an attribute on a class with all protected attributes' do
83
+ it 'rejects being mass-assignable' do
84
+ all_protected_attributes.should_not allow_mass_assignment_of(:attr)
85
+ end
86
+
87
+ def all_protected_attributes
88
+ define_model(:example, :attr => :string) do
89
+ attr_accessible nil
90
+ end.new
91
+ end
92
+ end
93
+
94
+ if active_model_3_1?
95
+ context 'an attribute included in the mass-assignment whitelist for admin role only' do
96
+ it 'rejects being mass-assignable' do
97
+ mass_assignable_as_admin.should_not allow_mass_assignment_of(:attr)
98
+ end
99
+
100
+ it 'accepts being mass-assignable for admin' do
101
+ mass_assignable_as_admin.should allow_mass_assignment_of(:attr).as(:admin)
102
+ end
103
+
104
+ def mass_assignable_as_admin
105
+ define_model(:example, :attr => :string) do
106
+ attr_accessible :attr, :as => :admin
107
+ end.new
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher do
4
+ context "#description" do
5
+ it 'describes itself with multiple values' do
6
+ matcher = allow_value('foo', 'bar').for(:baz)
7
+
8
+ matcher.description.should == 'allow baz to be set to any of ["foo", "bar"]'
9
+ end
10
+
11
+ it 'describes itself with a single value' do
12
+ matcher = allow_value('foo').for(:baz)
13
+
14
+ matcher.description.should == 'allow baz to be set to "foo"'
15
+ end
16
+
17
+ if active_model_3_2?
18
+ it 'describes itself with a strict validation' do
19
+ strict_matcher = allow_value('xyz').for(:attr).strict
20
+
21
+ strict_matcher.description.should ==
22
+ %q(doesn't raise when attr is set to "xyz")
23
+ end
24
+ end
25
+ end
26
+
27
+ context 'an attribute with a validation' do
28
+ it 'allows a good value' do
29
+ validating_format(:with => /abc/).should allow_value('abcde').for(:attr)
30
+ end
31
+
32
+ it 'rejects a bad value' do
33
+ validating_format(:with => /abc/).should_not allow_value('xyz').for(:attr)
34
+ end
35
+
36
+ it 'allows several good values' do
37
+ validating_format(:with => /abc/).
38
+ should allow_value('abcde', 'deabc').for(:attr)
39
+ end
40
+
41
+ it 'rejects several bad values' do
42
+ validating_format(:with => /abc/).
43
+ should_not allow_value('xyz', 'zyx', nil, []).for(:attr)
44
+ end
45
+ end
46
+
47
+ context 'an attribute with a validation and a custom message' do
48
+ it 'allows a good value' do
49
+ validating_format(:with => /abc/, :message => 'bad value').
50
+ should allow_value('abcde').for(:attr).with_message(/bad/)
51
+ end
52
+
53
+ it 'rejects a bad value' do
54
+ validating_format(:with => /abc/, :message => 'bad value').
55
+ should_not allow_value('xyz').for(:attr).with_message(/bad/)
56
+ end
57
+ end
58
+
59
+ context 'an attribute with several validations' do
60
+ let(:model) do
61
+ define_model :example, :attr => :string do
62
+ validates_presence_of :attr
63
+ validates_length_of :attr, :within => 1..5
64
+ validates_numericality_of :attr, :greater_than_or_equal_to => 1,
65
+ :less_than_or_equal_to => 50000
66
+ end.new
67
+ end
68
+ bad_values = [nil, '', 'abc', '0', '50001', '123456', []]
69
+
70
+ it 'allows a good value' do
71
+ model.should allow_value('12345').for(:attr)
72
+ end
73
+
74
+ bad_values.each do |bad_value|
75
+ it "rejects a bad value (#{bad_value.inspect})" do
76
+ model.should_not allow_value(bad_value).for(:attr)
77
+ end
78
+ end
79
+
80
+ it "rejects several bad values (#{bad_values.map(&:inspect).join(', ')})" do
81
+ model.should_not allow_value(*bad_values).for(:attr)
82
+ end
83
+ end
84
+
85
+ context 'with a single value' do
86
+ it 'allows you to call description before calling matches?' do
87
+ model = define_model(:example, :attr => :string).new
88
+ matcher = described_class.new('foo').for(:attr)
89
+ matcher.description
90
+
91
+ expect { matcher.matches?(model) }.not_to raise_error(NoMethodError)
92
+ end
93
+ end
94
+
95
+ context 'with no values' do
96
+ it 'raises an error' do
97
+ expect { allow_value.for(:baz) }.
98
+ to raise_error(ArgumentError, /at least one argument/)
99
+ end
100
+ end
101
+
102
+ if active_model_3_2?
103
+ context 'an attribute with a strict format validation' do
104
+ it 'strictly rejects a bad value' do
105
+ validating_format(:with => /abc/, :strict => true).
106
+ should_not allow_value('xyz').for(:attr).strict
107
+ end
108
+
109
+ it 'strictly allows a bad value with a different message' do
110
+ validating_format(:with => /abc/, :strict => true).
111
+ should allow_value('xyz').for(:attr).with_message(/abc/).strict
112
+ end
113
+
114
+ it 'provides a useful negative failure message' do
115
+ matcher = allow_value('xyz').for(:attr).strict.with_message(/abc/)
116
+
117
+ matcher.matches?(validating_format(:with => /abc/, :strict => true))
118
+
119
+ matcher.failure_message_for_should_not.should == 'Expected exception to include /abc/ ' +
120
+ 'when attr is set to "xyz", got Attr is invalid'
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher do
4
+ it 'does not allow any types' do
5
+ matcher('abcde').allowed_types.should == ''
6
+ end
7
+
8
+ context 'an attribute with a format validation' do
9
+ it 'does not match if the value is allowed' do
10
+ validating_format(:with => /abc/).should_not matcher('abcde').for(:attr)
11
+ end
12
+
13
+ it 'matches if the value is not allowed' do
14
+ validating_format(:with => /abc/).should matcher('xyz').for(:attr)
15
+ end
16
+ end
17
+
18
+ context 'an attribute with a format validation and a custom message' do
19
+ it 'does not match if the value and message are both correct' do
20
+ validating_format(:with => /abc/, :message => 'good message').
21
+ should_not matcher('abcde').for(:attr).with_message('good message')
22
+ end
23
+
24
+ it "delegates its failure message to its allow matcher's negative failure message" do
25
+ allow_matcher = stub_everything(:failure_message_for_should_not => 'allow matcher failure')
26
+ Shoulda::Matchers::ActiveModel::AllowValueMatcher.stubs(:new).returns(allow_matcher)
27
+
28
+ matcher = matcher('abcde').for(:attr).with_message('good message')
29
+ matcher.matches?(validating_format(:with => /abc/, :message => 'good message'))
30
+
31
+ matcher.failure_message_for_should.should == 'allow matcher failure'
32
+ end
33
+
34
+ it 'matches if the message is correct but the value is not' do
35
+ validating_format(:with => /abc/, :message => 'good message').
36
+ should matcher('xyz').for(:attr).with_message('good message')
37
+ end
38
+ end
39
+
40
+ def matcher(value)
41
+ described_class.new(value)
42
+ end
43
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::EnsureExclusionOfMatcher do
4
+ context 'an attribute which must be excluded from a range' do
5
+ it 'accepts ensuring the correct range' do
6
+ validating_exclusion(:in => 2..5).
7
+ should ensure_exclusion_of(:attr).in_range(2..5)
8
+ end
9
+
10
+ it 'rejects ensuring excluded value' do
11
+ validating_exclusion(:in => 2..5).
12
+ should_not ensure_exclusion_of(:attr).in_range(2..6)
13
+ end
14
+
15
+ it 'does not override the default message with a blank' do
16
+ validating_exclusion(:in => 2..5).
17
+ should ensure_exclusion_of(:attr).in_range(2..5).with_message(nil)
18
+ end
19
+ end
20
+
21
+ context 'an attribute with a custom validation message' do
22
+ it 'accepts ensuring the correct range' do
23
+ validating_exclusion(:in => 2..4, :message => 'not good').
24
+ should ensure_exclusion_of(:attr).in_range(2..4).with_message(/not good/)
25
+ end
26
+ end
27
+
28
+ context 'an attribute with custom range validations' do
29
+ it 'accepts ensuring the correct range and messages' do
30
+ model = custom_validation do
31
+ if attr >= 2 && attr <= 5
32
+ errors.add(:attr, 'should be out of this range')
33
+ end
34
+ end
35
+
36
+ model.should ensure_exclusion_of(:attr).in_range(2..5).
37
+ with_message(/should be out of this range/)
38
+ end
39
+ end
40
+
41
+ context 'an attribute which must be excluded from an array' do
42
+ it 'accepts with correct array' do
43
+ validating_exclusion(:in => %w(one two)).
44
+ should ensure_exclusion_of(:attr).in_array(%w(one two))
45
+ end
46
+
47
+ it 'rejects when only part of array matches' do
48
+ validating_exclusion(:in => %w(one two)).
49
+ should_not ensure_exclusion_of(:attr).in_array(%w(one wrong_value))
50
+ end
51
+
52
+ it 'rejects when array does not match at all' do
53
+ validating_exclusion(:in => %w(one two)).
54
+ should_not ensure_exclusion_of(:attr).in_array(%w(cat dog))
55
+ end
56
+
57
+ it 'has correct description' do
58
+ ensure_exclusion_of(:attr).in_array([true, 'dog']).description.
59
+ should == 'ensure exclusion of attr in [true, "dog"]'
60
+ end
61
+
62
+ def validating_exclusion(options)
63
+ define_model(:example, :attr => :string) do
64
+ validates_exclusion_of :attr, options
65
+ end.new
66
+ end
67
+ end
68
+
69
+ def validating_exclusion(options)
70
+ define_model(:example, :attr => :integer) do
71
+ validates_exclusion_of :attr, options
72
+ end.new
73
+ end
74
+ end
@@ -0,0 +1,171 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::EnsureInclusionOfMatcher do
4
+ context 'with no validations' do
5
+ it 'rejects an array which does not have a validator defined' do
6
+ define_model(:example, :attr => :string).new.
7
+ should_not ensure_inclusion_of(:attr).in_array(%w(Yes No))
8
+ end
9
+ end
10
+
11
+ context 'with true/false values' do
12
+ it 'can verify outside values to ensure the negative case' do
13
+ define_model(:example, :attr => :string).new.
14
+ should_not ensure_inclusion_of(:attr).in_array([true, false])
15
+ end
16
+ end
17
+
18
+ context 'where we cannot determine a value outside the array' do
19
+ it 'raises a custom exception' do
20
+ model = define_model(:example, :attr => :string).new
21
+
22
+ arbitrary_string = described_class::ARBITRARY_OUTSIDE_STRING
23
+ expect { model.should ensure_inclusion_of(:attr).in_array([arbitrary_string]) }.to raise_error Shoulda::Matchers::ActiveModel::CouldNotDetermineValueOutsideOfArray
24
+ end
25
+ end
26
+
27
+ context 'an attribute which must be included in a range' do
28
+ it 'accepts ensuring the correct range' do
29
+ validating_inclusion(:in => 2..5).
30
+ should ensure_inclusion_of(:attr).in_range(2..5)
31
+ end
32
+
33
+ it 'rejects ensuring a lower minimum value' do
34
+ validating_inclusion(:in => 2..5).
35
+ should_not ensure_inclusion_of(:attr).in_range(1..5)
36
+ end
37
+
38
+ it 'rejects ensuring a higher minimum value' do
39
+ validating_inclusion(:in => 2..5).
40
+ should_not ensure_inclusion_of(:attr).in_range(3..5)
41
+ end
42
+
43
+ it 'rejects ensuring a lower maximum value' do
44
+ validating_inclusion(:in => 2..5).
45
+ should_not ensure_inclusion_of(:attr).in_range(2..4)
46
+ end
47
+
48
+ it 'rejects ensuring a higher maximum value' do
49
+ validating_inclusion(:in => 2..5).
50
+ should_not ensure_inclusion_of(:attr).in_range(2..6)
51
+ end
52
+
53
+ it 'does not override the default message with a blank' do
54
+ validating_inclusion(:in => 2..5).
55
+ should ensure_inclusion_of(:attr).in_range(2..5).with_message(nil)
56
+ end
57
+ end
58
+
59
+ context 'an attribute with a custom ranged value validation' do
60
+ it 'accepts ensuring the correct range' do
61
+ validating_inclusion(:in => 2..4, :message => 'not good').
62
+ should ensure_inclusion_of(:attr).in_range(2..4).with_message(/not good/)
63
+ end
64
+ end
65
+
66
+ context 'an attribute with custom range validations' do
67
+ it 'accepts ensuring the correct range and messages' do
68
+ model = custom_validation do
69
+ if attr < 2
70
+ errors.add(:attr, 'too low')
71
+ elsif attr > 5
72
+ errors.add(:attr, 'too high')
73
+ end
74
+ end
75
+
76
+ model.should ensure_inclusion_of(:attr).in_range(2..5).
77
+ with_low_message(/low/).with_high_message(/high/)
78
+ end
79
+ end
80
+
81
+ context 'an attribute which must be included in an array' do
82
+ it 'accepts with correct array' do
83
+ validating_inclusion(:in => %w(one two)).
84
+ should ensure_inclusion_of(:attr).in_array(%w(one two))
85
+ end
86
+
87
+ it 'rejects when only part of array matches' do
88
+ validating_inclusion(:in => %w(one two)).
89
+ should_not ensure_inclusion_of(:attr).in_array(%w(one wrong_value))
90
+ end
91
+
92
+ it 'rejects when array does not match at all' do
93
+ validating_inclusion(:in => %w(one two)).
94
+ should_not ensure_inclusion_of(:attr).in_array(%w(cat dog))
95
+ end
96
+
97
+ it 'has correct description' do
98
+ ensure_inclusion_of(:attr).in_array([true, "dog"]).description.
99
+ should == 'ensure inclusion of attr in [true, "dog"]'
100
+ end
101
+
102
+ it 'rejects allow_blank' do
103
+ validating_inclusion(:in => %w(one two)).
104
+ should_not ensure_inclusion_of(:attr).in_array(%w(one two)).allow_blank(true)
105
+ end
106
+
107
+ it 'accepts allow_blank(false)' do
108
+ validating_inclusion(:in => %w(one two)).
109
+ should ensure_inclusion_of(:attr).in_array(%w(one two)).allow_blank(false)
110
+ end
111
+
112
+ it 'rejects allow_nil' do
113
+ validating_inclusion(:in => %w(one two)).
114
+ should_not ensure_inclusion_of(:attr).in_array(%w(one two)).allow_nil(true)
115
+ end
116
+
117
+ it 'accepts allow_nil(false)' do
118
+ validating_inclusion(:in => %w(one two)).
119
+ should ensure_inclusion_of(:attr).in_array(%w(one two)).allow_nil(false)
120
+ end
121
+ end
122
+
123
+ context 'with allowed blank and allowed nil' do
124
+ it 'accepts allow_blank' do
125
+ validating_inclusion(:in => %w(one two), :allow_blank => true).
126
+ should ensure_inclusion_of(:attr).in_array(%w(one two)).allow_blank
127
+ end
128
+
129
+ it 'rejects allow_blank(false)' do
130
+ validating_inclusion(:in => %w(one two), :allow_blank => true).
131
+ should_not ensure_inclusion_of(:attr).in_array(%w(one two)).allow_blank(false)
132
+ end
133
+
134
+ it 'accepts allow_nil' do
135
+ validating_inclusion(:in => %w(one two), :allow_nil => true).
136
+ should ensure_inclusion_of(:attr).in_array(%w(one two)).allow_nil
137
+ end
138
+
139
+ it 'rejects allow_nil' do
140
+ validating_inclusion(:in => %w(one two), :allow_nil => true).
141
+ should_not ensure_inclusion_of(:attr).in_array(%w(one two)).allow_nil(false)
142
+ end
143
+ end
144
+
145
+ context 'an attribute allowing some blank values but not others' do
146
+ it 'rejects allow_blank' do
147
+ validating_inclusion(:in => ['one', 'two', '']).
148
+ should_not ensure_inclusion_of(:attr).in_array(['one', 'two', '']).allow_blank(true)
149
+ end
150
+ end
151
+
152
+ if active_model_3_2?
153
+ context 'a strict attribute which must be included in a range' do
154
+ it 'accepts ensuring the correct range' do
155
+ validating_inclusion(:in => 2..5, :strict => true).
156
+ should ensure_inclusion_of(:attr).in_range(2..5).strict
157
+ end
158
+
159
+ it 'rejects ensuring another range' do
160
+ validating_inclusion(:in => 2..5, :strict => true).
161
+ should_not ensure_inclusion_of(:attr).in_range(2..6).strict
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ def validating_inclusion(options)
168
+ define_model(:example, :attr => :string) do
169
+ validates_inclusion_of :attr, options
170
+ end.new
171
+ end