shoulda-matchers 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.travis.yml +9 -15
- data/Appraisals +10 -8
- data/Gemfile.lock +1 -1
- data/NEWS.md +62 -32
- data/gemfiles/3.0.gemfile.lock +2 -2
- data/gemfiles/3.1.gemfile.lock +2 -2
- data/gemfiles/3.2.gemfile +1 -1
- data/gemfiles/3.2.gemfile.lock +3 -3
- data/lib/shoulda/matchers/active_model.rb +1 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +7 -2
- data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +2 -0
- data/lib/shoulda/matchers/active_model/exception_message_finder.rb +3 -2
- data/lib/shoulda/matchers/active_model/helpers.rb +5 -2
- data/lib/shoulda/matchers/active_model/odd_even_number_matcher.rb +47 -0
- data/lib/shoulda/matchers/active_model/only_integer_matcher.rb +4 -0
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +26 -3
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +68 -16
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +5 -0
- data/lib/shoulda/matchers/active_model/validation_message_finder.rb +3 -2
- data/lib/shoulda/matchers/active_record/association_matcher.rb +29 -4
- data/lib/shoulda/matchers/version.rb +1 -1
- data/shoulda-matchers.gemspec +1 -0
- data/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb +195 -0
- data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +18 -0
- data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +21 -0
- data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +23 -0
- data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +46 -0
- data/spec/shoulda/matchers/active_model/odd_even_number_matcher_spec.rb +93 -0
- data/spec/shoulda/matchers/active_model/only_integer_matcher_spec.rb +4 -4
- data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +60 -0
- data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +16 -0
- data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +45 -8
- data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +13 -0
- data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +50 -2
- data/spec/support/i18n_faker.rb +10 -0
- metadata +10 -3
@@ -8,10 +8,14 @@ module Shoulda # :nodoc:
|
|
8
8
|
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
9
9
|
# translation for <tt>:not_a_number</tt>.
|
10
10
|
# * <tt>only_integer</tt> - allows only integer values
|
11
|
+
# * <tt>odd</tt> - Specifies the value must be an odd number.
|
12
|
+
# * <tt>even</tt> - Specifies the value must be an even number.
|
11
13
|
#
|
12
14
|
# Examples:
|
13
15
|
# it { should validate_numericality_of(:price) }
|
14
16
|
# it { should validate_numericality_of(:age).only_integer }
|
17
|
+
# it { should validate_numericality_of(:frequency).odd }
|
18
|
+
# it { should validate_numericality_of(:frequency).even }
|
15
19
|
#
|
16
20
|
def validate_numericality_of(attr)
|
17
21
|
ValidateNumericalityOfMatcher.new(attr)
|
@@ -22,7 +26,6 @@ module Shoulda # :nodoc:
|
|
22
26
|
|
23
27
|
def initialize(attribute)
|
24
28
|
@attribute = attribute
|
25
|
-
@options = {}
|
26
29
|
@submatchers = []
|
27
30
|
|
28
31
|
add_disallow_value_matcher
|
@@ -34,6 +37,18 @@ module Shoulda # :nodoc:
|
|
34
37
|
self
|
35
38
|
end
|
36
39
|
|
40
|
+
def odd
|
41
|
+
odd_number_matcher = OddEvenNumberMatcher.new(@attribute, :odd => true)
|
42
|
+
add_submatcher(odd_number_matcher)
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def even
|
47
|
+
even_number_matcher = OddEvenNumberMatcher.new(@attribute, :even => true)
|
48
|
+
add_submatcher(even_number_matcher)
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
37
52
|
def with_message(message)
|
38
53
|
@submatchers.each { |matcher| matcher.with_message(message) }
|
39
54
|
self
|
@@ -49,7 +64,11 @@ module Shoulda # :nodoc:
|
|
49
64
|
end
|
50
65
|
|
51
66
|
def failure_message_for_should
|
52
|
-
|
67
|
+
submatcher_failure_messages_for_should.last
|
68
|
+
end
|
69
|
+
|
70
|
+
def failure_message_for_should_not
|
71
|
+
submatcher_failure_messages_for_should_not.last
|
53
72
|
end
|
54
73
|
|
55
74
|
private
|
@@ -70,10 +89,14 @@ module Shoulda # :nodoc:
|
|
70
89
|
failing_submatchers.empty?
|
71
90
|
end
|
72
91
|
|
73
|
-
def
|
92
|
+
def submatcher_failure_messages_for_should
|
74
93
|
failing_submatchers.map(&:failure_message_for_should)
|
75
94
|
end
|
76
95
|
|
96
|
+
def submatcher_failure_messages_for_should_not
|
97
|
+
failing_submatchers.map(&:failure_message_for_should_not)
|
98
|
+
end
|
99
|
+
|
77
100
|
def failing_submatchers
|
78
101
|
@failing_submatchers ||= @submatchers.select { |matcher| !matcher.matches?(@subject) }
|
79
102
|
end
|
@@ -55,12 +55,26 @@ module Shoulda # :nodoc:
|
|
55
55
|
self
|
56
56
|
end
|
57
57
|
|
58
|
+
def allow_nil
|
59
|
+
@options[:allow_nil] = true
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def description
|
64
|
+
result = "require "
|
65
|
+
result << "case sensitive " unless @options[:case_insensitive]
|
66
|
+
result << "unique value for #{@attribute}"
|
67
|
+
result << " scoped to #{@options[:scopes].join(', ')}" if @options[:scopes].present?
|
68
|
+
result
|
69
|
+
end
|
70
|
+
|
58
71
|
def matches?(subject)
|
59
72
|
@subject = subject.class.new
|
60
73
|
@expected_message ||= :taken
|
61
74
|
set_scoped_attributes &&
|
62
|
-
|
63
|
-
validate_after_scope_change?
|
75
|
+
validate_everything_except_duplicate_nils? &&
|
76
|
+
validate_after_scope_change? &&
|
77
|
+
allows_nil?
|
64
78
|
end
|
65
79
|
|
66
80
|
def description
|
@@ -73,17 +87,42 @@ module Shoulda # :nodoc:
|
|
73
87
|
|
74
88
|
private
|
75
89
|
|
76
|
-
def
|
77
|
-
@
|
90
|
+
def allows_nil?
|
91
|
+
if @options[:allow_nil]
|
92
|
+
ensure_nil_record_in_database
|
93
|
+
allows_value_of(nil, @expected_message)
|
94
|
+
else
|
95
|
+
true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def existing_record
|
100
|
+
@existing_record ||= first_instance
|
78
101
|
end
|
79
102
|
|
80
103
|
def first_instance
|
81
|
-
@subject.class.first ||
|
104
|
+
@subject.class.first || create_record_in_database
|
82
105
|
end
|
83
106
|
|
84
|
-
def
|
107
|
+
def ensure_nil_record_in_database
|
108
|
+
unless existing_record_is_nil?
|
109
|
+
create_record_in_database(nil_value: true)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def existing_record_is_nil?
|
114
|
+
@existing_record.present? && existing_value.nil?
|
115
|
+
end
|
116
|
+
|
117
|
+
def create_record_in_database(options = {})
|
118
|
+
if options[:nil_value]
|
119
|
+
value = nil
|
120
|
+
else
|
121
|
+
value = "arbitrary_string"
|
122
|
+
end
|
123
|
+
|
85
124
|
@subject.class.new.tap do |instance|
|
86
|
-
instance.send("#{@attribute}=",
|
125
|
+
instance.send("#{@attribute}=", value)
|
87
126
|
instance.save(:validate => false)
|
88
127
|
end
|
89
128
|
end
|
@@ -93,7 +132,7 @@ module Shoulda # :nodoc:
|
|
93
132
|
@options[:scopes].all? do |scope|
|
94
133
|
setter = :"#{scope}="
|
95
134
|
if @subject.respond_to?(setter)
|
96
|
-
@subject.send(setter,
|
135
|
+
@subject.send(setter, existing_record.send(scope))
|
97
136
|
true
|
98
137
|
else
|
99
138
|
@failure_message_for_should = "#{class_name} doesn't seem to have a #{scope} attribute."
|
@@ -105,10 +144,18 @@ module Shoulda # :nodoc:
|
|
105
144
|
end
|
106
145
|
end
|
107
146
|
|
108
|
-
def
|
147
|
+
def validate_everything_except_duplicate_nils?
|
148
|
+
if @options[:allow_nil] && existing_value.nil?
|
149
|
+
create_record_without_nil
|
150
|
+
end
|
151
|
+
|
109
152
|
disallows_value_of(existing_value, @expected_message)
|
110
153
|
end
|
111
154
|
|
155
|
+
def create_record_without_nil
|
156
|
+
@existing_record = create_record_in_database
|
157
|
+
end
|
158
|
+
|
112
159
|
# TODO: There is a chance that we could change the scoped field
|
113
160
|
# to a value that's already taken. An alternative implementation
|
114
161
|
# could actually find all values for scope and create a unique
|
@@ -117,16 +164,19 @@ module Shoulda # :nodoc:
|
|
117
164
|
true
|
118
165
|
else
|
119
166
|
@options[:scopes].all? do |scope|
|
120
|
-
previous_value =
|
167
|
+
previous_value = existing_record.send(scope)
|
121
168
|
|
122
169
|
# Assume the scope is a foreign key if the field is nil
|
123
170
|
previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s])
|
124
171
|
|
125
|
-
next_value =
|
126
|
-
previous_value.next
|
127
|
-
|
128
|
-
previous_value.
|
129
|
-
|
172
|
+
next_value =
|
173
|
+
if previous_value.respond_to?(:next)
|
174
|
+
previous_value.next
|
175
|
+
elsif previous_value.respond_to?(:to_datetime)
|
176
|
+
previous_value.to_datetime.next
|
177
|
+
else
|
178
|
+
previous_value.to_s.next
|
179
|
+
end
|
130
180
|
|
131
181
|
@subject.send("#{scope}=", next_value)
|
132
182
|
|
@@ -147,6 +197,8 @@ module Shoulda # :nodoc:
|
|
147
197
|
def correct_type_for_column(column)
|
148
198
|
if column.type == :string
|
149
199
|
'0'
|
200
|
+
elsif column.type == :datetime
|
201
|
+
DateTime.now
|
150
202
|
else
|
151
203
|
0
|
152
204
|
end
|
@@ -157,7 +209,7 @@ module Shoulda # :nodoc:
|
|
157
209
|
end
|
158
210
|
|
159
211
|
def existing_value
|
160
|
-
value =
|
212
|
+
value = existing_record.send(@attribute)
|
161
213
|
if @options[:case_insensitive] && value.respond_to?(:swapcase!)
|
162
214
|
value.swapcase!
|
163
215
|
end
|
@@ -6,9 +6,10 @@ module Shoulda
|
|
6
6
|
class ValidationMessageFinder
|
7
7
|
include Helpers
|
8
8
|
|
9
|
-
def initialize(instance, attribute)
|
9
|
+
def initialize(instance, attribute, context=nil)
|
10
10
|
@instance = instance
|
11
11
|
@attribute = attribute
|
12
|
+
@context = context
|
12
13
|
end
|
13
14
|
|
14
15
|
def allow_description(allowed_values)
|
@@ -58,7 +59,7 @@ module Shoulda
|
|
58
59
|
end
|
59
60
|
|
60
61
|
def validate_instance
|
61
|
-
@instance.valid?
|
62
|
+
@instance.valid?(@context)
|
62
63
|
@instance
|
63
64
|
end
|
64
65
|
end
|
@@ -7,6 +7,8 @@ module Shoulda # :nodoc:
|
|
7
7
|
# * <tt>:class_name</tt> - tests that the association resolves to class_name.
|
8
8
|
# * <tt>:validate</tt> - tests that the association makes use of the validate
|
9
9
|
# option.
|
10
|
+
# * <tt>:touch</tt> - tests that the association makes use of the touch
|
11
|
+
# option.
|
10
12
|
#
|
11
13
|
# Example:
|
12
14
|
# it { should belong_to(:parent) }
|
@@ -107,7 +109,12 @@ module Shoulda # :nodoc:
|
|
107
109
|
end
|
108
110
|
|
109
111
|
def validate(validate = true)
|
110
|
-
@validate = validate
|
112
|
+
@options[:validate] = validate
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
def touch(touch = true)
|
117
|
+
@options[:touch] = touch
|
111
118
|
self
|
112
119
|
end
|
113
120
|
|
@@ -122,7 +129,8 @@ module Shoulda # :nodoc:
|
|
122
129
|
order_correct? &&
|
123
130
|
conditions_correct? &&
|
124
131
|
join_table_exists? &&
|
125
|
-
validate_correct?
|
132
|
+
validate_correct? &&
|
133
|
+
touch_correct?
|
126
134
|
end
|
127
135
|
|
128
136
|
def failure_message_for_should
|
@@ -258,14 +266,31 @@ module Shoulda # :nodoc:
|
|
258
266
|
end
|
259
267
|
|
260
268
|
def validate_correct?
|
261
|
-
if
|
269
|
+
if option_correct?(:validate)
|
270
|
+
true
|
271
|
+
else
|
272
|
+
@missing = "#{@name} should have :validate => #{@options[:validate]}"
|
273
|
+
false
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def touch_correct?
|
278
|
+
if option_correct?(:touch)
|
262
279
|
true
|
263
280
|
else
|
264
|
-
@missing = "#{@name} should have :
|
281
|
+
@missing = "#{@name} should have :touch => #{@options[:touch]}"
|
265
282
|
false
|
266
283
|
end
|
267
284
|
end
|
268
285
|
|
286
|
+
def option_correct?(key)
|
287
|
+
!@options.key?(key) || reflection_set_properly_for?(key)
|
288
|
+
end
|
289
|
+
|
290
|
+
def reflection_set_properly_for?(key)
|
291
|
+
@options[key] == !!reflection.options[key]
|
292
|
+
end
|
293
|
+
|
269
294
|
def class_has_foreign_key?(klass)
|
270
295
|
if @options.key?(:foreign_key)
|
271
296
|
reflection.options[:foreign_key] == @options[:foreign_key]
|
data/shoulda-matchers.gemspec
CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
+
s.required_ruby_version = '>= 1.9.2'
|
21
22
|
s.add_dependency('activesupport', '>= 3.0.0')
|
22
23
|
|
23
24
|
s.add_development_dependency('appraisal', '~> 0.4')
|
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
|
4
|
+
context "a unique attribute" do
|
5
|
+
before do
|
6
|
+
@model = define_model(:example, :attr => :string,
|
7
|
+
:other => :integer) do
|
8
|
+
attr_accessible :attr, :other
|
9
|
+
validates_uniqueness_of :attr
|
10
|
+
end.new
|
11
|
+
end
|
12
|
+
|
13
|
+
context "with an existing value" do
|
14
|
+
before do
|
15
|
+
@existing = Example.create!(:attr => 'value', :other => 1)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should require a unique value for that attribute" do
|
19
|
+
@model.should validate_uniqueness_of(:attr)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should pass when the subject is an existing record" do
|
23
|
+
@existing.should validate_uniqueness_of(:attr)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should fail when a scope is specified" do
|
27
|
+
@model.should_not validate_uniqueness_of(:attr).scoped_to(:other)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "without an existing value" do
|
32
|
+
before do
|
33
|
+
Example.first.should be_nil
|
34
|
+
@matcher = validate_uniqueness_of(:attr)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "does not not require a created instance" do
|
38
|
+
@model.should @matcher
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "a unique attribute with a custom error and an existing value" do
|
44
|
+
before do
|
45
|
+
@model = define_model(:example, :attr => :string) do
|
46
|
+
attr_accessible :attr
|
47
|
+
validates_uniqueness_of :attr, :message => 'Bad value'
|
48
|
+
end.new
|
49
|
+
Example.create!(:attr => 'value')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should fail when checking the default message" do
|
53
|
+
@model.should_not validate_uniqueness_of(:attr)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should fail when checking a message that doesn't match" do
|
57
|
+
@model.should_not validate_uniqueness_of(:attr).with_message(/abc/i)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should pass when checking a message that matches" do
|
61
|
+
@model.should validate_uniqueness_of(:attr).with_message(/bad/i)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "a scoped unique attribute with an existing value" do
|
66
|
+
before do
|
67
|
+
@model = define_model(:example, :attr => :string,
|
68
|
+
:scope1 => :integer,
|
69
|
+
:scope2 => :integer,
|
70
|
+
:other => :integer) do
|
71
|
+
attr_accessible :attr, :scope1, :scope2, :other
|
72
|
+
validates_uniqueness_of :attr, :scope => [:scope1, :scope2]
|
73
|
+
end.new
|
74
|
+
@existing = Example.create!(:attr => 'value', :scope1 => 1, :scope2 => 2, :other => 3)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should pass when the correct scope is specified" do
|
78
|
+
@model.should validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should pass when the subject is an existing record" do
|
82
|
+
@existing.should validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should fail when too narrow of a scope is specified" do
|
86
|
+
@model.should_not validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2, :other)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should fail when too broad of a scope is specified" do
|
90
|
+
@model.should_not validate_uniqueness_of(:attr).scoped_to(:scope1)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should fail when a different scope is specified" do
|
94
|
+
@model.should_not validate_uniqueness_of(:attr).scoped_to(:other)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should fail when no scope is specified" do
|
98
|
+
@model.should_not validate_uniqueness_of(:attr)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should fail when a non-existent attribute is specified as a scope" do
|
102
|
+
@model.should_not validate_uniqueness_of(:attr).scoped_to(:fake)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "a non-unique attribute with an existing value" do
|
107
|
+
before do
|
108
|
+
@model = define_model(:example, :attr => :string) do
|
109
|
+
attr_accessible :attr
|
110
|
+
end.new
|
111
|
+
Example.create!(:attr => 'value')
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should not require a unique value for that attribute" do
|
115
|
+
@model.should_not validate_uniqueness_of(:attr)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "a case sensitive unique attribute with an existing value" do
|
120
|
+
before do
|
121
|
+
@model = define_model(:example, :attr => :string) do
|
122
|
+
attr_accessible :attr
|
123
|
+
validates_uniqueness_of :attr, :case_sensitive => true
|
124
|
+
end.new
|
125
|
+
Example.create!(:attr => 'value')
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should not require a unique, case-insensitive value for that attribute" do
|
129
|
+
@model.should_not validate_uniqueness_of(:attr).case_insensitive
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should require a unique, case-sensitive value for that attribute" do
|
133
|
+
@model.should validate_uniqueness_of(:attr)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "a case sensitive unique integer attribute with an existing value" do
|
138
|
+
before do
|
139
|
+
@model = define_model(:example, :attr => :integer) do
|
140
|
+
attr_accessible :attr
|
141
|
+
validates_uniqueness_of :attr, :case_sensitive => true
|
142
|
+
end.new
|
143
|
+
Example.create!(:attr => 'value')
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should require a unique, case-insensitive value for that attribute" do
|
147
|
+
@model.should validate_uniqueness_of(:attr).case_insensitive
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should require a unique, case-sensitive value for that attribute" do
|
151
|
+
@model.should validate_uniqueness_of(:attr)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context "when the validation allows nil" do
|
156
|
+
before do
|
157
|
+
@model = define_model(:example, :attr => :integer) do
|
158
|
+
attr_accessible :attr
|
159
|
+
validates_uniqueness_of :attr, :allow_nil => true
|
160
|
+
end.new
|
161
|
+
end
|
162
|
+
|
163
|
+
context "when there is an existing entry with a nil" do
|
164
|
+
it "should allow_nil" do
|
165
|
+
Example.create!(:attr => nil)
|
166
|
+
@model.should validate_uniqueness_of(:attr).allow_nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should create a nil and verify that it is allowed" do
|
171
|
+
@model.should validate_uniqueness_of(:attr).allow_nil
|
172
|
+
Example.all.any?{ |instance| instance.attr.nil? }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context "when the validation does not allow a nil" do
|
177
|
+
before do
|
178
|
+
@model = define_model(:example, :attr => :integer) do
|
179
|
+
attr_accessible :attr
|
180
|
+
validates_uniqueness_of :attr
|
181
|
+
end.new
|
182
|
+
end
|
183
|
+
|
184
|
+
context "when there is an existing entry with a nil" do
|
185
|
+
it "should not allow_nil" do
|
186
|
+
Example.create!(:attr => nil)
|
187
|
+
@model.should_not validate_uniqueness_of(:attr).allow_nil
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should not allow_nil" do
|
192
|
+
@model.should_not validate_uniqueness_of(:attr).allow_nil
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|