not_naughty 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require 'sequel_not_naughty'
3
+
4
+ DB = Sequel::Model.db = Sequel.sqlite
5
+
6
+ Sequel::Model.instance_eval do
7
+ %w[validate valid?].
8
+ each {|m| undef_method m.to_sym}
9
+ end
10
+
11
+ (class << Sequel::Model; self; end).module_eval do
12
+ %w[validate validates validates_acceptance_of validates_confirmation_of
13
+ validates_each validates_format_of validates_length_of
14
+ validates_numericality_of validates_presence_of validations
15
+ has_validations?].
16
+ each {|m| undef_method m.to_sym}
17
+ end
@@ -0,0 +1,97 @@
1
+ require "#{ File.dirname(__FILE__) }/sequel_spec_helper.rb"
2
+
3
+ describe Sequel::Plugins::NotNaughty do
4
+
5
+ before(:each) do
6
+ @obj = Class.new(Sequel::Model) { is :not_naughty }
7
+ end
8
+
9
+ it "should delegate validation methods in receiver" do
10
+ @instance = @obj.new
11
+
12
+ @obj.validator.should be_an_instance_of(Sequel::Plugins::NotNaughty)
13
+ @obj.validator.should_receive(:states).and_return({})
14
+ @obj.validator.should_receive(:has_validations?)
15
+ @obj.validator.should_receive(:invoke).with(@instance)
16
+
17
+ @instance.errors.should be_an_instance_of(subject::Errors)
18
+ @instance.should respond_to(:validate)
19
+ @instance.should respond_to(:valid?)
20
+ @instance.should respond_to(:save_without_validations)
21
+
22
+ @obj.validations
23
+ @obj.has_validations?
24
+ @obj.validate @instance
25
+ end
26
+ it "should return validations" do
27
+ @obj.validations.should be_an_instance_of(Hash)
28
+ end
29
+ it "should not have validations" do
30
+ @obj.has_validations?.should == false
31
+ end
32
+ it "should add_validation instance of validation" do
33
+ validation = Class.new(subject::Validation)
34
+
35
+ @obj.validator.add_validation validation, :attribute
36
+
37
+ validations = @obj.validator.states[:create][:attribute]
38
+ validations.length.should == 1
39
+ validations.first.should be_an_instance_of(validation)
40
+
41
+ validations = @obj.validator.states[:update][:attribute]
42
+ validations.length.should == 1
43
+ validations.first.should be_an_instance_of(validation)
44
+
45
+ @obj.validator.add_validation validation, :attribute, :on => :create
46
+
47
+ validations = @obj.validator.states[:create][:attribute]
48
+ validations.length.should == 2
49
+ validations[0].should be_an_instance_of(validation)
50
+ validations[1].should be_an_instance_of(validation)
51
+
52
+ validations = @obj.validator.states[:update][:attribute]
53
+ validations.length.should == 1
54
+ validations.first.should be_an_instance_of(validation)
55
+ end
56
+ it "should have validations" do
57
+ validation = Class.new(subject::Validation)
58
+ @obj.validator.add_validation validation, :attribute
59
+
60
+ @obj.has_validations?.should == true
61
+ end
62
+ it "should add_validation blocks as Validation" do
63
+ @obj.validator.add_validation(:attribute) { |o, a, v| }
64
+
65
+ @obj.validator.states[:create][:attribute].first.
66
+ should be_kind_of(subject::Validation)
67
+ @obj.validator.states[:update][:attribute].first.
68
+ should be_kind_of(subject::Validation)
69
+ end
70
+ it "should run validations on object when it's invoked" do
71
+ probe = mock 'Probe', :new? => true
72
+ probe.should_receive(:attribute).and_return(1)
73
+ probe.should_receive(:test).with(:attribute, 1)
74
+
75
+ @obj.validator.add_validation(:attribute) { |o, a, v| o.test a, v }
76
+ @obj.validate probe
77
+ end
78
+ it "should validate if saved" do
79
+ instance = @obj.new
80
+ instance.stub!(:save_without_validations).and_return(false)
81
+ @obj.validator.should_receive(:invoke).with(instance)
82
+ instance.save.should be_false
83
+ end
84
+ it "should run hooks if validated" do
85
+ instance = @obj.new
86
+ instance.should_receive(:before_validate)
87
+ instance.should_receive(:after_validate)
88
+ instance.validate
89
+ end
90
+ it "should not run hooks if validated" do
91
+ i = Class.new(Sequel::Model) { is :not_naughty, :without => :hooks }.new
92
+ i.should_not_receive(:before_validate)
93
+ i.should_not_receive(:after_validate)
94
+ i.validate
95
+ end
96
+
97
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,5 @@
1
+ --colour
2
+ --backtrace
3
+ --format
4
+ specdoc
5
+ --diff
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/../lib/not_naughty.rb'
2
+
3
+ def subject() ::NotNaughty end
4
+ def h(something)
5
+ puts '<pre>%s</pre>' %
6
+ something.inspect.gsub(/[<>]/) {|m| (m == '<')? '&lt;': '&gt;'}
7
+ end
@@ -0,0 +1,118 @@
1
+ require "#{ File.dirname(__FILE__) }/spec_helper.rb"
2
+
3
+ describe subject::Validation do
4
+
5
+ it "should register validations if inherited" do
6
+ subject::Builder.
7
+ should_receive(:update).any_number_of_times.
8
+ with Class.new(subject::Validation)
9
+ pending 'This one kinda sucks...'
10
+ end
11
+ it "should build validations with block" do
12
+ block = proc {|o, a, v|}
13
+ validation = subject::Validation.new({}, &block)
14
+
15
+ validation.instance_variable_get(:@block).should == block
16
+ end
17
+ it "should alias call to call_without_conditions" do
18
+ validation = subject::Validation.new({}) {|o, a, v|}
19
+
20
+ validation.method(:call).
21
+ should == validation.method(:call_without_conditions)
22
+ end
23
+ it "should not build conditions" do
24
+ validation = subject::Validation.
25
+ new({:if => nil, :unless => nil}) {|o, a, v|}
26
+
27
+ validation.instance_variable_get(:@conditions).should be_empty
28
+ end
29
+ it "should build conditions" do
30
+ validation = subject::Validation.new({:if => :nil?}) {|o, a, v|}
31
+ validation.instance_variable_get(:@conditions).should_not be_empty
32
+
33
+ validation.instance_variable_get(:@conditions).
34
+ first.instance_variable_get(:@condition).
35
+ should == :nil?
36
+ end
37
+ it "should alias call to call_with_conditions" do
38
+ validation = subject::Validation.new({:if => :nil?}) {|o, a, v|}
39
+
40
+ validation.method(:call).
41
+ should == validation.method(:call_with_conditions)
42
+ end
43
+ it "should call" do
44
+ probe = mock 'Probe'
45
+ probe.should_receive(:test).exactly(3).times
46
+
47
+ validation = subject::Validation.
48
+ new({}) { |o, a, v| [o, a, v].each { |p| p.test } }
49
+
50
+ validation.call probe, probe, probe
51
+ end
52
+ it "should call unless a condition passes" do
53
+ probe = mock 'Probe'
54
+ probe.stub!(:nil?).and_return(true)
55
+
56
+ validation = subject::Validation.
57
+ new({:unless => :nil?}) { |o, a, v| [o, a, v].each { |p| p.test } }
58
+
59
+ validation.call probe, probe, probe
60
+
61
+ probe.should_receive(:test).exactly(3).times
62
+ probe.stub!(:nil?).and_return(false)
63
+
64
+ validation.call probe, probe, probe
65
+ end
66
+ it "should not call" do
67
+ probe = mock 'Probe'
68
+ probe.should_not_receive(:test)
69
+
70
+ validation = subject::Validation.
71
+ new({:if => :nil?}) { |o, a, v| [o, a, v].each { |p| p.test } }
72
+
73
+ validation.call probe, probe, probe
74
+
75
+ end
76
+ it "should have validated attributes accessable" do
77
+ validation = subject::Validation.new(:probe)
78
+ validation.attributes.should include(:probe)
79
+ end
80
+ it "should clone observer peers to descendant" do
81
+ peers = subject::Validation.instance_variable_get :@observer_peers
82
+ peers.should_receive(:clone).and_return(true)
83
+ descendant = Class.new(subject::Validation)
84
+ descendant.instance_variable_get(:@observer_peers).should be_true
85
+ end
86
+
87
+ end
88
+
89
+ describe subject::Validation::Condition do
90
+
91
+ it "should evaluate positive callable" do
92
+ condition = subject::Validation::Condition.new proc {|o| o.nil?}
93
+ condition.evaluate(nil).should be_true
94
+ end
95
+ it "should evaluate negative callable" do
96
+ condition = subject::Validation::Condition.new proc {|o| o.nil?}, false
97
+ condition.evaluate(nil).should be_false
98
+ end
99
+ it "should evaluate positive Symbol" do
100
+ condition = subject::Validation::Condition.new :nil?
101
+ condition.evaluate(nil).should be_true
102
+ end
103
+ it "should evaluate negative Symbol" do
104
+ condition = subject::Validation::Condition.new :nil?, false
105
+ condition.evaluate(nil).should be_false
106
+ end
107
+ it "should evaluate positive UnboundMethod" do
108
+ um = NilClass.instance_method :nil?
109
+ condition = subject::Validation::Condition.new um
110
+ condition.evaluate(nil).should be_true
111
+ end
112
+ it "should evaluate negative UnboundMethod" do
113
+ um = NilClass.instance_method :nil?
114
+ condition = subject::Validation::Condition.new um, false
115
+ condition.evaluate(nil).should be_false
116
+ end
117
+
118
+ end
@@ -0,0 +1,267 @@
1
+ require "#{ File.dirname(__FILE__) }/spec_helper.rb"
2
+
3
+ ::NotNaughty::Validation.load(
4
+ :acceptance, :confirmation, :format,
5
+ :length, :numericality, :presence
6
+ )
7
+
8
+ describe subject::LengthValidation do
9
+
10
+ before(:each) { @receiver, @errors = mock('Receiver'), mock('Errors') }
11
+
12
+ it "should return the 'precise' block" do
13
+ validation = subject::LengthValidation.new :is => 8, :within => 10..12
14
+
15
+ probe = mock 'Probe', :length => 8, :nil? => false
16
+ validation.call @receiver, :probe, probe
17
+
18
+ @receiver.should_receive(:errors).and_return(@errors)
19
+ @errors.should_receive(:add).with(:probe, an_instance_of(String))
20
+
21
+ probe = mock 'Probe', :length => 11, :nil? => false
22
+ validation.call @receiver, :probe, probe
23
+ end
24
+ it "should return the 'range' block" do
25
+ validation = subject::LengthValidation.
26
+ new :within => 10..12, :maximum => 9
27
+
28
+ probe = mock 'Probe', :length => 10, :nil? => false
29
+ validation.call @receiver, :probe, probe
30
+
31
+ @receiver.should_receive(:errors).and_return(@errors)
32
+ @errors.should_receive(:add).with(:probe, an_instance_of(String))
33
+
34
+ probe = mock 'Probe', :length => 9, :nil? => false
35
+ validation.call @receiver, :probe, probe
36
+ end
37
+ it "should return the 'maximum' block" do
38
+ validation = subject::LengthValidation.
39
+ new :maximum => 9
40
+
41
+ probe = mock 'Probe', :length => 9, :nil? => false
42
+ validation.call @receiver, :probe, probe
43
+
44
+ @receiver.should_receive(:errors).and_return(@errors)
45
+ @errors.should_receive(:add).with(:probe, an_instance_of(String))
46
+
47
+ probe = mock 'Probe', :length => 10, :nil? => false
48
+ validation.call @receiver, :probe, probe
49
+ end
50
+ it "should return the 'minimum' block" do
51
+ validation = subject::LengthValidation.
52
+ new :minimum => 9
53
+
54
+ probe = mock 'Probe', :length => 9, :nil? => false
55
+ validation.call @receiver, :probe, probe
56
+
57
+ @receiver.should_receive(:errors).and_return(@errors)
58
+ @errors.should_receive(:add).with(:probe, an_instance_of(String))
59
+
60
+ probe = mock 'Probe', :length => 8, :nil? => false
61
+ validation.call @receiver, :probe, probe
62
+ end
63
+ it "should raise an ArgumentError" do
64
+ lambda { subject::LengthValidation.new }.
65
+ should raise_error(ArgumentError)
66
+ end
67
+
68
+ end
69
+
70
+ LengthExample = Struct.new(:name).extend(subject)
71
+ describe LengthExample do
72
+
73
+ before(:each) { @example = LengthExample.clone }
74
+
75
+ it "should always allow nil " do
76
+ @example.validates_length_of :name, :is => 1, :allow_nil => false
77
+ @example.new(nil).should be_valid
78
+ @example.new('').should_not be_valid
79
+ @example.new('a').should be_valid
80
+ @example.new('ab').should_not be_valid
81
+ end
82
+ it "should allow blank" do
83
+ @example.validates_length_of :name, :is => 1, :allow_blank => true
84
+ @example.new(nil).should be_valid
85
+ @example.new('').should be_valid
86
+ @example.new('a').should be_valid
87
+ @example.new('ab').should_not be_valid
88
+ end
89
+
90
+ end
91
+
92
+ FormatExample = Struct.new(:email).extend(subject)
93
+ describe FormatExample do
94
+
95
+ before(:each) { @example = FormatExample.clone }
96
+
97
+ it "claims to match 99% of all e-mail addresses out there..." do
98
+ # Regexp was taken from: http://www.regular-expressions.info/email.html
99
+ @example.validates_format_of :email,
100
+ :with => /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i
101
+ @example.new('"Foo Bar" <foo@bar.com>').should be_valid
102
+ @example.new('foo@bar.com').should be_valid
103
+ @example.new('foobarcom').should_not be_valid
104
+ @example.new(nil).should_not be_valid
105
+ @example.new('').should_not be_valid
106
+ end
107
+ it "should allow nil e-mail addresses" do
108
+ @example.validates_format_of :email, :allow_nil => true,
109
+ :with => /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i
110
+ @example.new('"Foo Bar" <foo@bar.com>').should be_valid
111
+ @example.new('foo@bar.com').should be_valid
112
+ @example.new('foobarcom').should_not be_valid
113
+ @example.new(nil).should be_valid
114
+ @example.new('').should_not be_valid
115
+ end
116
+ it "should allow blank e-mail addresses" do
117
+ @example.validates_format_of :email, :allow_blank => true,
118
+ :with => /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i
119
+ @example.new('"Foo Bar" <foo@bar.com>').should be_valid
120
+ @example.new('foo@bar.com').should be_valid
121
+ @example.new('foobarcom').should_not be_valid
122
+ @example.new(nil).should be_valid
123
+ @example.new('').should be_valid
124
+ end
125
+ it "should raise an ArgumentError if format does not respond to :match" do
126
+ lambda { @example.validates_format_of :email }.
127
+ should raise_error(ArgumentError)
128
+ lambda { @example.validates_format_of :email, :with => 1 }.
129
+ should raise_error(ArgumentError)
130
+ lambda { @example.validates_format_of :email, :with => '' }.
131
+ should_not raise_error(ArgumentError)
132
+ lambda { @example.validates_format_of :email, :with => // }.
133
+ should_not raise_error(ArgumentError)
134
+ end
135
+
136
+ end
137
+
138
+ PresenceExample = Struct.new(:name).extend(subject)
139
+ describe PresenceExample do
140
+
141
+ before(:each) { @example = PresenceExample.clone }
142
+
143
+ it "should be present" do
144
+ @example.validates_presence_of :name
145
+ @example.new(0).should be_valid
146
+ @example.new([0]).should be_valid
147
+ @example.new('0').should be_valid
148
+ end
149
+ it "should not be present" do
150
+ @example.validates_presence_of :name
151
+ @example.new(nil).should_not be_valid
152
+ @example.new([]).should_not be_valid
153
+ @example.new('').should_not be_valid
154
+ end
155
+
156
+ end
157
+
158
+ AcceptanceExample = Struct.new(:conditions).extend(subject)
159
+ describe AcceptanceExample do
160
+
161
+ before(:each) { @example = AcceptanceExample.clone }
162
+
163
+ it "should accept '1' and allows nil by default" do
164
+ @example.validates_acceptance_of :conditions
165
+ @example.new(nil).should be_valid
166
+ @example.new('').should_not be_valid
167
+ @example.new(true).should_not be_valid
168
+ @example.new(false).should_not be_valid
169
+ @example.new('0').should_not be_valid
170
+ @example.new('1').should be_valid
171
+ end
172
+ it "should accept true and allows nil by default" do
173
+ @example.validates_acceptance_of :conditions, :accept => true
174
+ @example.new(nil).should be_valid
175
+ @example.new('').should_not be_valid
176
+ @example.new(true).should be_valid
177
+ @example.new(false).should_not be_valid
178
+ @example.new('0').should_not be_valid
179
+ @example.new('1').should_not be_valid
180
+ end
181
+ it "should accept '1' and disallows nil" do
182
+ @example.validates_acceptance_of :conditions, :accept => true,
183
+ :allow_nil => false
184
+
185
+ @example.new(nil).should_not be_valid
186
+ @example.new('').should_not be_valid
187
+ @example.new(true).should be_valid
188
+ @example.new(false).should_not be_valid
189
+ @example.new('0').should_not be_valid
190
+ @example.new('1').should_not be_valid
191
+ end
192
+ it "should accept '1' and allow blank" do
193
+ @example.validates_acceptance_of :conditions, :accept => true,
194
+ :allow_blank => true
195
+
196
+ @example.new(nil).should be_valid
197
+ @example.new('').should be_valid
198
+ @example.new(true).should be_valid
199
+ @example.new(false).should be_valid
200
+ @example.new('0').should_not be_valid
201
+ @example.new('1').should_not be_valid
202
+ end
203
+
204
+ end
205
+
206
+ ConfirmationExample = Struct.new(:name, :name_confirmation).extend(subject)
207
+ describe ConfirmationExample do
208
+
209
+ before(:each) { @example = ConfirmationExample.clone }
210
+
211
+ it "should be confirmed without allowing neither :nil nor :blank" do
212
+ @example.validates_confirmation_of :name
213
+
214
+ @example.new(nil, 'foo').should_not be_valid
215
+ @example.new('', 'foo').should_not be_valid
216
+
217
+ @example.new('foo', 'foo').should be_valid
218
+ @example.new('foo', 'bar').should_not be_valid
219
+ end
220
+ it "should be confirmed with allowing :nil" do
221
+ @example.validates_confirmation_of :name, :allow_nil => true
222
+
223
+ @example.new(nil, 'foo').should be_valid
224
+ @example.new('', 'foo').should_not be_valid
225
+
226
+ @example.new('foo', 'foo').should be_valid
227
+ @example.new('foo', 'bar').should_not be_valid
228
+ end
229
+ it "should be confirmed with allowing :blank" do
230
+ @example.validates_confirmation_of :name, :allow_blank => true
231
+
232
+ @example.new(nil, 'foo').should be_valid
233
+ @example.new('', 'foo').should be_valid
234
+
235
+ @example.new('foo', 'foo').should be_valid
236
+ @example.new('foo', 'bar').should_not be_valid
237
+ end
238
+
239
+ end
240
+
241
+ NumericalityExample = Struct.new(:weight).extend(subject)
242
+ describe NumericalityExample do
243
+
244
+ before(:each) { @example = NumericalityExample.clone }
245
+
246
+ it "should be matched with number pattern" do
247
+ @example.validates_numericality_of :weight
248
+
249
+ @example.new('-123.56').should be_valid
250
+
251
+ @example.new('+123').should be_valid
252
+ @example.new('-123').should be_valid
253
+ @example.new('123').should be_valid
254
+ @example.new('abc').should_not be_valid
255
+ end
256
+ it "should be matched with integer pattern" do
257
+ @example.validates_numericality_of :weight, :only_integer => true
258
+
259
+ @example.new('-123.45').should_not be_valid
260
+
261
+ @example.new('+123').should be_valid
262
+ @example.new('-123').should be_valid
263
+ @example.new('123').should be_valid
264
+ @example.new('abc').should_not be_valid
265
+ end
266
+
267
+ end
@@ -0,0 +1,123 @@
1
+ require "#{ File.dirname(__FILE__) }/spec_helper.rb"
2
+
3
+ describe subject::Validator, 'with default state' do
4
+
5
+ before(:each) { @validator = subject::Validator.new }
6
+
7
+ it "should have atleast the default state" do
8
+ @validator.instance_variable_get(:@states).keys.should include(:default)
9
+ end
10
+ it "should shoult return default state" do
11
+ @validator.get_state(nil).name.should == :default
12
+ end
13
+
14
+ end
15
+
16
+ describe NotNaughty::Validator, 'with custom states' do
17
+
18
+ before(:each) do
19
+ @states = [:create, :update]
20
+ @validator = subject::Validator.new(*@states)
21
+ end
22
+
23
+ it "should assign states dynamically" do
24
+ @validator.states.keys.should include(*@states)
25
+ end
26
+ it "should have an initial state" do
27
+ @validator.instance_variable_get(:@initial_state).name.
28
+ should == @states[0]
29
+ end
30
+ it "should add validations to all states" do
31
+ @validator.add_validation :firstname, :lastname
32
+
33
+ @validator.states.each do |name, state|
34
+ state.validations.should include(:firstname, :lastname)
35
+ end
36
+ end
37
+ it "should add validations to :create state" do
38
+ @validator.add_validation :firstname, :lastname, :on => :create
39
+
40
+ @validator.states[:create].validations.keys.
41
+ should include(:firstname, :lastname)
42
+ @validator.states[:update].validations.keys.
43
+ should_not include(:firstname, :lastname)
44
+ end
45
+ it "should add validations to :create and :update states" do
46
+ @validator.add_validation :firstname, :lastname, :on => [:create, :update]
47
+
48
+ @validator.states.each do |name, state|
49
+ state.validations.should include(:firstname, :lastname)
50
+ end
51
+ end
52
+ it "should return initial state" do
53
+ @validator.get_state(nil).name.should == :create
54
+ end
55
+ it "should not have validations" do
56
+ @validator.should_not have_validations
57
+ end
58
+ it "should have validations" do
59
+ @validator.add_validation :firstname, :lastname
60
+ @validator.should have_validations
61
+ end
62
+ it "should have validations on initial state" do
63
+ @validator.add_validation :firstname, :lastname, :on => :create
64
+ @validator.should have_validations('')
65
+ end
66
+ it "should not have validations on initial state" do
67
+ @validator.add_validation :firstname, :lastname, :on => :update
68
+ @validator.should_not have_validations('')
69
+ end
70
+ it "should send! attributes to probe if invoked" do
71
+ block = proc {|o, a, v|}
72
+
73
+ probe = mock 'Probe'
74
+ probe.should_receive(:send!).with(:firstname)
75
+ probe.should_receive(:send!).with(:lastname)
76
+
77
+ @validator.add_validation :firstname, :lastname, &block
78
+ @validator.invoke probe
79
+ end
80
+ it "should call validations with object, attribute and value if invoked" do
81
+ block = proc {|o, a, v|}
82
+
83
+ probe = mock 'Probe'
84
+ value = mock 'Value'
85
+ probe.stub!(:send!).and_return(value)
86
+
87
+ @validator.add_validation :firstname, :lastname, &block
88
+ @validator.get_state.validations
89
+ @validator.invoke probe
90
+ end
91
+ it "should clone states as well" do
92
+ validator_clone = @validator.clone
93
+ validator_clone.states.length == @validator.states.length
94
+ validator_clone.states.should_not != @validator.states
95
+ end
96
+
97
+ end
98
+
99
+ describe NotNaughty::Validator::State do
100
+
101
+ before(:each) { @state = NotNaughty::Validator::State.new }
102
+
103
+ it "should initialize with name and validations" do
104
+ @state.name.should == :default
105
+ @state.validations.should be_an_instance_of(Hash)
106
+
107
+ @state = NotNaughty::Validator::State.new :foo
108
+ @state.name.should == :foo
109
+ end
110
+ it "should add validation" do
111
+ @state.add_validation(:firstname, :lastname, :on => :default) {|o, a, v|}
112
+ @state.validations.keys.should include(:firstname, :lastname)
113
+ end
114
+ it "should return validation for an attribute" do
115
+ @state.validations[:foo] = :bar
116
+ @state[:foo].should == :bar
117
+ end
118
+ it "should have validations" do
119
+ @state.validations[:foo] = [:bar]
120
+ @state.should have_validations
121
+ end
122
+
123
+ end