shoulda-matchers 1.4.2 → 1.5.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 (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