sequel 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/record_spec.rb CHANGED
@@ -6,9 +6,7 @@ describe "Model#save" do
6
6
  MODEL_DB.reset
7
7
 
8
8
  @c = Class.new(Sequel::Model(:items)) do
9
- def columns
10
- [:id, :x, :y]
11
- end
9
+ columns :id, :x, :y
12
10
  end
13
11
  end
14
12
 
@@ -52,9 +50,7 @@ describe "Model#save_changes" do
52
50
  MODEL_DB.reset
53
51
 
54
52
  @c = Class.new(Sequel::Model(:items)) do
55
- def columns
56
- [:id, :x, :y]
57
- end
53
+ columns :id, :x, :y
58
54
  end
59
55
  end
60
56
 
@@ -109,47 +105,67 @@ describe "Model#save_changes" do
109
105
  end
110
106
  end
111
107
 
112
- describe "Model#set" do
113
-
108
+ describe "Model#update_values" do
114
109
  before(:each) do
115
110
  MODEL_DB.reset
116
111
 
117
112
  @c = Class.new(Sequel::Model(:items)) do
118
- def columns
119
- [:id, :x, :y]
120
- end
113
+ columns :id, :x, :y
121
114
  end
122
115
  end
123
116
 
124
117
  it "should generate an update statement" do
125
118
  o = @c.new(:id => 1)
126
- o.set(:x => 1)
119
+ o.update_values(:x => 1)
127
120
  MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
128
121
  end
129
122
 
130
123
  it "should update attribute values" do
131
124
  o = @c.new(:id => 1)
132
125
  o.x.should be_nil
133
- o.set(:x => 1)
126
+ o.update_values(:x => 1)
134
127
  o.x.should == 1
135
128
  end
136
129
 
137
130
  it "should support string keys" do
138
131
  o = @c.new(:id => 1)
139
132
  o.x.should be_nil
140
- o.set('x' => 1)
133
+ o.update_values('x' => 1)
141
134
  o.x.should == 1
142
135
  MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
143
136
  end
137
+ end
138
+
139
+ describe "Model#set_values" do
140
+ before(:each) do
141
+ MODEL_DB.reset
142
+
143
+ @c = Class.new(Sequel::Model(:items)) do
144
+ columns :id, :x, :y
145
+ end
146
+ end
144
147
 
145
- it "should be aliased by #update" do
148
+ it "should not touch the database" do
146
149
  o = @c.new(:id => 1)
147
- o.update(:x => 1)
148
- MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
150
+ o.set_values(:x => 1)
151
+ MODEL_DB.sqls.should == []
152
+ end
153
+
154
+ it "should update attribute values" do
155
+ o = @c.new(:id => 1)
156
+ o.x.should be_nil
157
+ o.set_values(:x => 1)
158
+ o.x.should == 1
159
+ end
160
+
161
+ it "should support string keys" do
162
+ o = @c.new(:id => 1)
163
+ o.x.should be_nil
164
+ o.set_values('x' => 1)
165
+ o.x.should == 1
149
166
  end
150
167
  end
151
168
 
152
-
153
169
  describe "Model#new?" do
154
170
 
155
171
  before(:each) do
@@ -170,6 +186,7 @@ describe "Model#new?" do
170
186
  n.should_not be_new
171
187
  end
172
188
 
189
+ ### DEPRECATED
173
190
  it "should alias new_record? to new?" do
174
191
  n = @c.new(:x => 1)
175
192
  n.should respond_to(:new_record?)
@@ -217,7 +234,7 @@ end
217
234
 
218
235
  describe Sequel::Model, "with this" do
219
236
 
220
- before { @example = Class.new Sequel::Model(:examples) }
237
+ before { @example = Class.new Sequel::Model(:examples); @example.columns :id, :a, :x, :y }
221
238
 
222
239
  it "should return a dataset identifying the record" do
223
240
  instance = @example.new :id => 3
@@ -250,6 +267,7 @@ end
250
267
  describe "Model#pk" do
251
268
  before(:each) do
252
269
  @m = Class.new(Sequel::Model)
270
+ @m.columns :id, :x, :y
253
271
  end
254
272
 
255
273
  it "should be default return the value of the :id column" do
@@ -283,6 +301,7 @@ end
283
301
  describe "Model#pk_hash" do
284
302
  before(:each) do
285
303
  @m = Class.new(Sequel::Model)
304
+ @m.columns :id, :x, :y
286
305
  end
287
306
 
288
307
  it "should be default return the value of the :id column" do
@@ -313,14 +332,59 @@ describe "Model#pk_hash" do
313
332
  end
314
333
  end
315
334
 
335
+ describe Sequel::Model, "set_with_params" do
336
+
337
+ before(:each) do
338
+ MODEL_DB.reset
339
+
340
+ @c = Class.new(Sequel::Model(:items)) do
341
+ columns :x, :y, :id
342
+ end
343
+ @c.instance_variable_set(:@columns, true)
344
+ @o1 = @c.new
345
+ @o2 = @c.load(:id => 5)
346
+ end
347
+
348
+ it "should filter the given params using the model columns" do
349
+ @o1.set_with_params(:x => 1, :z => 2)
350
+ @o1.values.should == {:x => 1}
351
+ MODEL_DB.sqls.should == []
352
+
353
+ @o2.set_with_params(:y => 1, :abc => 2)
354
+ @o2.values.should == {:y => 1, :id=> 5}
355
+ MODEL_DB.sqls.should == []
356
+ end
357
+
358
+ it "should work with both strings and symbols" do
359
+ @o1.set_with_params('x'=> 1, 'z'=> 2)
360
+ @o1.values.should == {:x => 1}
361
+ MODEL_DB.sqls.should == []
362
+
363
+ @o2.set_with_params('y'=> 1, 'abc'=> 2)
364
+ @o2.values.should == {:y => 1, :id=> 5}
365
+ MODEL_DB.sqls.should == []
366
+ end
367
+
368
+ it "should support virtual attributes" do
369
+ @c.class_def(:blah=) {|v| self.x = v}
370
+ @o1.set_with_params(:blah => 333)
371
+ @o1.values.should == {:x => 333}
372
+ MODEL_DB.sqls.should == []
373
+ @o1.set_with_params('blah'=> 334)
374
+ @o1.values.should == {:x => 334}
375
+ MODEL_DB.sqls.should == []
376
+ end
377
+ end
378
+
316
379
  describe Sequel::Model, "update_with_params" do
317
380
 
318
381
  before(:each) do
319
382
  MODEL_DB.reset
320
383
 
321
384
  @c = Class.new(Sequel::Model(:items)) do
322
- def self.columns; [:x, :y]; end
385
+ columns :x, :y, :id
323
386
  end
387
+ @c.instance_variable_set(:@columns, true)
324
388
  @o1 = @c.new
325
389
  @o2 = @c.load(:id => 5)
326
390
  end
@@ -334,7 +398,8 @@ describe Sequel::Model, "update_with_params" do
334
398
  MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
335
399
  end
336
400
 
337
- it "should be aliased by create_with" do
401
+ ### DEPRECATE
402
+ it "should be aliased by update_with" do
338
403
  @o1.update_with(:x => 1, :z => 2)
339
404
  MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
340
405
 
@@ -345,19 +410,21 @@ describe Sequel::Model, "update_with_params" do
345
410
 
346
411
  it "should support virtual attributes" do
347
412
  @c.class_def(:blah=) {|v| self.x = v}
348
- @o1.update_with(:blah => 333)
413
+ @o1.update_with_params(:blah => 333)
349
414
  MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (333)"
350
415
  end
351
416
  end
352
417
 
418
+ ### DEPRECATE
353
419
  describe Sequel::Model, "create_with_params" do
354
420
 
355
421
  before(:each) do
356
422
  MODEL_DB.reset
357
423
 
358
424
  @c = Class.new(Sequel::Model(:items)) do
359
- def self.columns; [:x, :y]; end
425
+ columns :x, :y
360
426
  end
427
+ @c.instance_variable_set(:@columns, true)
361
428
  end
362
429
 
363
430
  it "should filter the given params using the model columns" do
@@ -390,12 +457,19 @@ describe Sequel::Model, "#destroy" do
390
457
  before(:each) do
391
458
  MODEL_DB.reset
392
459
  @model = Class.new(Sequel::Model(:items))
460
+ @model.columns :id
393
461
  @model.dataset.meta_def(:delete) {MODEL_DB.execute delete_sql}
394
462
 
395
463
  @instance = @model.new(:id => 1234)
396
464
  #@model.stub!(:delete).and_return(:true)
397
465
  end
398
466
 
467
+ it "should return self" do
468
+ @model.db.should_receive(:transaction)
469
+ @model.after_destroy{3}
470
+ @instance.destroy.should == @instance
471
+ end
472
+
399
473
  it "should run within a transaction" do
400
474
  @model.db.should_receive(:transaction)
401
475
  @instance.destroy
@@ -434,6 +508,7 @@ end
434
508
  describe Sequel::Model, "#each" do
435
509
  setup do
436
510
  @model = Class.new(Sequel::Model(:items))
511
+ @model.columns :a, :b, :id
437
512
  @m = @model.new(:a => 1, :b => 2, :id => 4444)
438
513
  end
439
514
 
@@ -447,6 +522,7 @@ end
447
522
  describe Sequel::Model, "#keys" do
448
523
  setup do
449
524
  @model = Class.new(Sequel::Model(:items))
525
+ @model.columns :a, :b, :id
450
526
  @m = @model.new(:a => 1, :b => 2, :id => 4444)
451
527
  end
452
528
 
@@ -459,32 +535,100 @@ describe Sequel::Model, "#keys" do
459
535
  end
460
536
  end
461
537
 
462
- describe Sequel::Model, "#===" do
538
+ describe Sequel::Model, "#==" do
463
539
  specify "should compare instances by values" do
464
- a = Sequel::Model.new(:id => 1, :x => 3)
465
- b = Sequel::Model.new(:id => 1, :x => 4)
466
- c = Sequel::Model.new(:id => 1, :x => 3)
540
+ z = Class.new(Sequel::Model)
541
+ z.columns :id, :x
542
+ a = z.new(:id => 1, :x => 3)
543
+ b = z.new(:id => 1, :x => 4)
544
+ c = z.new(:id => 1, :x => 3)
467
545
 
468
546
  a.should_not == b
469
547
  a.should == c
470
548
  b.should_not == c
471
549
  end
550
+
551
+ specify "should be aliased to #eql?" do
552
+ z = Class.new(Sequel::Model)
553
+ z.columns :id, :x
554
+ a = z.new(:id => 1, :x => 3)
555
+ b = z.new(:id => 1, :x => 4)
556
+ c = z.new(:id => 1, :x => 3)
557
+
558
+ a.eql?(b).should == false
559
+ a.eql?(c).should == true
560
+ b.eql?(c).should == false
561
+ end
472
562
  end
473
563
 
474
564
  describe Sequel::Model, "#===" do
475
- specify "should compare instances by pk only" do
476
- a = Sequel::Model.new(:id => 1, :x => 3)
477
- b = Sequel::Model.new(:id => 1, :x => 4)
478
- c = Sequel::Model.new(:id => 2, :x => 3)
565
+ specify "should compare instances by class and pk if pk is not nil" do
566
+ z = Class.new(Sequel::Model)
567
+ z.columns :id, :x
568
+ y = Class.new(Sequel::Model)
569
+ y.columns :id, :x
570
+ a = z.new(:id => 1, :x => 3)
571
+ b = z.new(:id => 1, :x => 4)
572
+ c = z.new(:id => 2, :x => 3)
573
+ d = y.new(:id => 1, :x => 3)
479
574
 
480
575
  a.should === b
481
576
  a.should_not === c
577
+ a.should_not === d
578
+ end
579
+
580
+ specify "should always be false if the primary key is nil" do
581
+ z = Class.new(Sequel::Model)
582
+ z.columns :id, :x
583
+ y = Class.new(Sequel::Model)
584
+ y.columns :id, :x
585
+ a = z.new(:x => 3)
586
+ b = z.new(:x => 4)
587
+ c = z.new(:x => 3)
588
+ d = y.new(:x => 3)
589
+
590
+ a.should_not === b
591
+ a.should_not === c
592
+ a.should_not === d
593
+ end
594
+ end
595
+
596
+ describe Sequel::Model, "#hash" do
597
+ specify "should be the same only for objects with the same class and pk if the pk is not nil" do
598
+ z = Class.new(Sequel::Model)
599
+ z.columns :id, :x
600
+ y = Class.new(Sequel::Model)
601
+ y.columns :id, :x
602
+ a = z.new(:id => 1, :x => 3)
603
+ b = z.new(:id => 1, :x => 4)
604
+ c = z.new(:id => 2, :x => 3)
605
+ d = y.new(:id => 1, :x => 3)
606
+
607
+ a.hash.should == b.hash
608
+ a.hash.should_not == c.hash
609
+ a.hash.should_not == d.hash
610
+ end
611
+
612
+ specify "should be the same only for objects with the same class and values if the pk is nil" do
613
+ z = Class.new(Sequel::Model)
614
+ z.columns :id, :x
615
+ y = Class.new(Sequel::Model)
616
+ y.columns :id, :x
617
+ a = z.new(:x => 3)
618
+ b = z.new(:x => 4)
619
+ c = z.new(:x => 3)
620
+ d = y.new(:x => 3)
621
+
622
+ a.hash.should_not == b.hash
623
+ a.hash.should == c.hash
624
+ a.hash.should_not == d.hash
482
625
  end
483
626
  end
484
627
 
485
628
  describe Sequel::Model, "#initialize" do
486
629
  setup do
487
630
  @c = Class.new(Sequel::Model) do
631
+ columns :id, :x
488
632
  end
489
633
  end
490
634
 
@@ -528,7 +672,7 @@ describe Sequel::Model, ".create" do
528
672
  before(:each) do
529
673
  MODEL_DB.reset
530
674
  @c = Class.new(Sequel::Model(:items)) do
531
- def columns; [:x]; end
675
+ columns :x
532
676
  end
533
677
  end
534
678
 
@@ -566,7 +710,7 @@ describe Sequel::Model, "#refresh" do
566
710
  setup do
567
711
  MODEL_DB.reset
568
712
  @c = Class.new(Sequel::Model(:items)) do
569
- def columns; [:x]; end
713
+ columns :x
570
714
  end
571
715
  end
572
716
 
@@ -590,4 +734,18 @@ describe Sequel::Model, "#refresh" do
590
734
  @m.reload
591
735
  @m[:x].should == 'kaboom'
592
736
  end
737
+
738
+ specify "should remove cached associations" do
739
+ @c.many_to_one :node, :class=>@c
740
+ @c.one_to_many :attributes, :class=>@c
741
+ @c.many_to_many :tags, :class=>@c
742
+ @m = @c.new(:id => 555)
743
+ @m.instance_variable_set(:@node, 15)
744
+ @m.instance_variable_set(:@attributes, [15])
745
+ @m.instance_variable_set(:@tags, [15])
746
+ @m.reload
747
+ @m.instance_variable_get(:@node).should == nil
748
+ @m.instance_variable_get(:@attributes).should == nil
749
+ @m.instance_variable_get(:@tags).should == nil
750
+ end
593
751
  end
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,12 @@
1
1
  require 'rubygems'
2
2
  unless Object.const_defined?('Sequel')
3
+ $:.unshift(File.join(File.dirname(__FILE__), "../../sequel_core/lib/"))
3
4
  require 'sequel_core'
4
5
  end
5
- require File.join(File.dirname(__FILE__), "../lib/sequel_model")
6
+ unless Sequel.const_defined?('Model')
7
+ $:.unshift(File.join(File.dirname(__FILE__), "../lib/"))
8
+ require 'sequel_model'
9
+ end
6
10
 
7
11
  class MockDataset < Sequel::Dataset
8
12
  def insert(*args)
@@ -40,4 +44,15 @@ class MockDatabase < Sequel::Database
40
44
  def dataset; MockDataset.new(self); end
41
45
  end
42
46
 
43
- Sequel::Model.db = MODEL_DB = MockDatabase.new
47
+ class << Sequel::Model
48
+ alias orig_columns columns
49
+ def columns(*cols)
50
+ return if cols.empty?
51
+ define_method(:columns){cols}
52
+ @dataset.instance_variable_set(:@columns, cols) if @dataset
53
+ define_method(:str_columns){cols.map{|x|x.to_s.freeze}}
54
+ def_column_accessor(*cols)
55
+ end
56
+ end
57
+
58
+ Sequel::Model.db = MODEL_DB = MockDatabase.new
@@ -1,33 +1,386 @@
1
1
  require File.join(File.dirname(__FILE__), "spec_helper")
2
2
 
3
+ describe "Validation::Errors" do
4
+ setup do
5
+ @errors = Validation::Errors.new
6
+ class Validation::Errors
7
+ attr_accessor :errors
8
+ end
9
+ end
10
+
11
+ specify "should be clearable using #clear" do
12
+ @errors.errors = {1 => 2, 3 => 4}
13
+ @errors.clear
14
+ @errors.errors.should == {}
15
+ end
16
+
17
+ specify "should be empty if no errors are added" do
18
+ @errors.should be_empty
19
+ @errors[:blah] << "blah"
20
+ @errors.should_not be_empty
21
+ end
22
+
23
+ specify "should return errors for a specific attribute using #on or #[]" do
24
+ @errors[:blah].should == []
25
+ @errors.on(:blah).should == []
26
+
27
+ @errors[:blah] << 'blah'
28
+ @errors[:blah].should == ['blah']
29
+ @errors.on(:blah).should == ['blah']
30
+
31
+ @errors[:bleu].should == []
32
+ @errors.on(:bleu).should == []
33
+ end
34
+
35
+ specify "should accept errors using #[] << or #add" do
36
+ @errors[:blah] << 'blah'
37
+ @errors[:blah].should == ['blah']
38
+
39
+ @errors.add :blah, 'zzzz'
40
+ @errors[:blah].should == ['blah', 'zzzz']
41
+ end
42
+
43
+ specify "should return full messages using #full_messages" do
44
+ @errors.full_messages.should == []
45
+
46
+ @errors[:blow] << 'blieuh'
47
+ @errors[:blow] << 'blich'
48
+ @errors[:blay] << 'bliu'
49
+ msgs = @errors.full_messages
50
+ msgs.size.should == 3
51
+ msgs.should include('blow blieuh', 'blow blich', 'blay bliu')
52
+ end
53
+ end
54
+
55
+ describe Validation do
56
+ setup do
57
+ @c = Class.new do
58
+ include Validation
59
+
60
+ def self.validates_coolness_of(attr)
61
+ validates_each(attr) {|o, a, v| o.errors[a] << 'is not cool' if v != :cool}
62
+ end
63
+ end
64
+
65
+ @d = Class.new do
66
+ attr_accessor :errors
67
+ def initialize; @errors = Validation::Errors.new; end
68
+ end
69
+ end
70
+
71
+ specify "should respond to validates, validations, has_validations?" do
72
+ @c.should respond_to(:validations)
73
+ @c.should respond_to(:has_validations?)
74
+ end
75
+
76
+ specify "should acccept validation definitions using validates_each" do
77
+ @c.validates_each(:xx, :yy) {|o, a, v| o.errors[a] << 'too low' if v < 50}
78
+
79
+ @c.validations[:xx].size.should == 1
80
+ @c.validations[:yy].size.should == 1
81
+
82
+ o = @d.new
83
+ @c.validations[:xx].first.call(o, :aa, 40)
84
+ @c.validations[:yy].first.call(o, :bb, 60)
85
+
86
+ o.errors.full_messages.should == ['aa too low']
87
+ end
88
+
89
+ specify "should return true/false for has_validations?" do
90
+ @c.has_validations?.should == false
91
+ @c.validates_each(:xx) {1}
92
+ @c.has_validations?.should == true
93
+ end
94
+
95
+ specify "should provide a validates method that takes block with validation definitions" do
96
+ @c.validates do
97
+ coolness_of :blah
98
+ end
99
+ @c.validations[:blah].should_not be_empty
100
+
101
+ o = @d.new
102
+ @c.validations[:blah].first.call(o, :ttt, 40)
103
+ o.errors.full_messages.should == ['ttt is not cool']
104
+ o.errors.clear
105
+ @c.validations[:blah].first.call(o, :ttt, :cool)
106
+ o.errors.should be_empty
107
+ end
108
+ end
109
+
110
+ describe "A Validation instance" do
111
+ setup do
112
+ @c = Class.new do
113
+ attr_accessor :score
114
+
115
+ include Validation
116
+
117
+ validates_each :score do |o, a, v|
118
+ o.errors[a] << 'too low' if v < 87
119
+ end
120
+ end
121
+
122
+ @o = @c.new
123
+ end
124
+
125
+ specify "should supply a #valid? method that returns true if validations pass" do
126
+ @o.score = 50
127
+ @o.should_not be_valid
128
+ @o.score = 100
129
+ @o.should be_valid
130
+ end
131
+
132
+ specify "should provide an errors object" do
133
+ @o.score = 100
134
+ @o.should be_valid
135
+ @o.errors.should be_empty
136
+
137
+ @o.score = 86
138
+ @o.should_not be_valid
139
+ @o.errors[:score].should == ['too low']
140
+ @o.errors[:blah].should be_empty
141
+ end
142
+ end
143
+
144
+ describe Validation::Generator do
145
+ setup do
146
+ $testit = nil
147
+
148
+ @c = Class.new do
149
+ include Validation
150
+
151
+ def self.validates_blah
152
+ $testit = 1324
153
+ end
154
+ end
155
+ end
156
+
157
+ specify "should instance_eval the block, sending everything to its receiver" do
158
+ Validation::Generator.new(@c) do
159
+ blah
160
+ end
161
+ $testit.should == 1324
162
+ end
163
+ end
164
+
165
+ describe "Validations" do
166
+ setup do
167
+ @c = Class.new do
168
+ attr_accessor :value
169
+ include Validation
170
+ end
171
+ @m = @c.new
172
+ end
173
+
174
+ specify "should validate acceptance_of" do
175
+ @c.validates_acceptance_of :value
176
+ @m.should be_valid
177
+ @m.value = '1'
178
+ @m.should be_valid
179
+ end
180
+
181
+ specify "should validate acceptance_of with accept" do
182
+ @c.validates_acceptance_of :value, :accept => 'true'
183
+ @m.value = '1'
184
+ @m.should_not be_valid
185
+ @m.value = 'true'
186
+ @m.should be_valid
187
+ end
188
+
189
+ specify "should validate acceptance_of with allow_nil => false" do
190
+ @c.validates_acceptance_of :value, :allow_nil => false
191
+ @m.should_not be_valid
192
+ end
193
+
194
+ specify "should validate confirmation_of" do
195
+ @c.send(:attr_accessor, :value_confirmation)
196
+ @c.validates_confirmation_of :value
197
+
198
+ @m.value = 'blah'
199
+ @m.should_not be_valid
200
+
201
+ @m.value_confirmation = 'blah'
202
+ @m.should be_valid
203
+ end
204
+
205
+ specify "should validate format_of" do
206
+ @c.validates_format_of :value, :with => /.+_.+/
207
+ @m.value = 'abc_'
208
+ @m.should_not be_valid
209
+ @m.value = 'abc_def'
210
+ @m.should be_valid
211
+ end
212
+
213
+ specify "should raise for validate_format_of without regexp" do
214
+ proc {@c.validates_format_of :value}.should raise_error(ArgumentError)
215
+ proc {@c.validates_format_of :value, :with => :blah}.should raise_error(ArgumentError)
216
+ end
217
+
218
+ specify "should validate length_of with maximum" do
219
+ @c.validates_length_of :value, :maximum => 5
220
+ @m.should_not be_valid
221
+ @m.value = '12345'
222
+ @m.should be_valid
223
+ @m.value = '123456'
224
+ @m.should_not be_valid
225
+ end
226
+
227
+ specify "should validate length_of with minimum" do
228
+ @c.validates_length_of :value, :minimum => 5
229
+ @m.should_not be_valid
230
+ @m.value = '12345'
231
+ @m.should be_valid
232
+ @m.value = '1234'
233
+ @m.should_not be_valid
234
+ end
235
+
236
+ specify "should validate length_of with within" do
237
+ @c.validates_length_of :value, :within => 2..5
238
+ @m.should_not be_valid
239
+ @m.value = '12345'
240
+ @m.should be_valid
241
+ @m.value = '1'
242
+ @m.should_not be_valid
243
+ @m.value = '123456'
244
+ @m.should_not be_valid
245
+ end
246
+
247
+ specify "should validate length_of with is" do
248
+ @c.validates_length_of :value, :is => 3
249
+ @m.should_not be_valid
250
+ @m.value = '123'
251
+ @m.should be_valid
252
+ @m.value = '12'
253
+ @m.should_not be_valid
254
+ @m.value = '1234'
255
+ @m.should_not be_valid
256
+ end
257
+
258
+ specify "should validate length_of with allow_nil" do
259
+ @c.validates_length_of :value, :is => 3, :allow_nil => true
260
+ @m.should be_valid
261
+ end
262
+
263
+ specify "should validate numericality_of" do
264
+ @c.validates_numericality_of :value
265
+ @m.value = 'blah'
266
+ @m.should_not be_valid
267
+ @m.value = '123'
268
+ @m.should be_valid
269
+ @m.value = '123.1231'
270
+ @m.should be_valid
271
+ end
272
+
273
+ specify "should validate numericality_of with only_integer" do
274
+ @c.validates_numericality_of :value, :only_integer => true
275
+ @m.value = 'blah'
276
+ @m.should_not be_valid
277
+ @m.value = '123'
278
+ @m.should be_valid
279
+ @m.value = '123.1231'
280
+ @m.should_not be_valid
281
+ end
282
+
283
+ specify "should validate presence_of" do
284
+ @c.validates_presence_of :value
285
+ @m.should_not be_valid
286
+ @m.value = ''
287
+ @m.should_not be_valid
288
+ @m.value = 1234
289
+ @m.should be_valid
290
+ end
291
+ end
292
+
293
+ context "Superclass validations" do
294
+ setup do
295
+ @c1 = Class.new do
296
+ include Validation
297
+ attr_accessor :value
298
+ validates_length_of :value, :minimum => 5
299
+ end
300
+
301
+ @c2 = Class.new(@c1) do
302
+ validates_format_of :value, :with => /^[a-z]+$/
303
+ end
304
+ end
305
+
306
+ specify "should be checked when validating" do
307
+ o = @c2.new
308
+ o.value = 'ab'
309
+ o.valid?.should == false
310
+ o.errors.full_messages.should == [
311
+ 'value is too short'
312
+ ]
313
+
314
+ o.value = '12'
315
+ o.valid?.should == false
316
+ o.errors.full_messages.should == [
317
+ 'value is too short',
318
+ 'value is invalid'
319
+ ]
320
+
321
+ o.value = 'abcde'
322
+ o.valid?.should be_true
323
+ end
324
+
325
+ specify "should be skipped if skip_superclass_validations is called" do
326
+ @c2.skip_superclass_validations
327
+
328
+ o = @c2.new
329
+ o.value = 'ab'
330
+ o.valid?.should be_true
331
+
332
+ o.value = '12'
333
+ o.valid?.should == false
334
+ o.errors.full_messages.should == [
335
+ 'value is invalid'
336
+ ]
337
+
338
+ o.value = 'abcde'
339
+ o.valid?.should be_true
340
+ end
341
+ end
342
+
343
+ context ".validates with block" do
344
+ specify "should support calling .each" do
345
+ @c = Class.new do
346
+ attr_accessor :vvv
347
+
348
+ include Validation
349
+ validates do
350
+ each :vvv do |o, a, v|
351
+ o.errors[a] << "is less than zero" if v.to_i < 0
352
+ end
353
+ end
354
+ end
355
+
356
+ o = @c.new
357
+ o.vvv = 1
358
+ o.should be_valid
359
+ o.vvv = -1
360
+ o.should_not be_valid
361
+ end
362
+ end
363
+
3
364
  describe Sequel::Model, "Validations" do
4
365
 
5
366
  before(:all) do
6
367
  class Person < Sequel::Model
7
- def columns
8
- [:id,:name,:first_name,:last_name,:middle_name,:initials,:age, :terms]
9
- end
368
+ columns :id,:name,:first_name,:last_name,:middle_name,:initials,:age, :terms
10
369
  end
11
370
 
12
371
  class Smurf < Person
13
372
  end
14
373
 
15
374
  class Cow < Sequel::Model
16
- def columns
17
- [:id, :name, :got_milk]
18
- end
375
+ columns :id, :name, :got_milk
19
376
  end
20
377
 
21
378
  class User < Sequel::Model
22
- def columns
23
- [:id, :username, :password]
24
- end
379
+ columns :id, :username, :password
25
380
  end
26
381
 
27
382
  class Address < Sequel::Model
28
- def columns
29
- [:id, :zip_code]
30
- end
383
+ columns :id, :zip_code
31
384
  end
32
385
  end
33
386
 
@@ -137,6 +490,52 @@ describe Sequel::Model, "Validations" do
137
490
  @cow.name = "Betsy"
138
491
  @cow.should be_valid
139
492
  end
493
+
494
+ it "should validate the uniqueness of a column" do
495
+ class User < Sequel::Model
496
+ validations.clear
497
+ validates do
498
+ uniqueness_of :username
499
+ end
500
+ end
501
+ User.dataset.extend(Module.new {
502
+ def fetch_rows(sql)
503
+ @db << sql
504
+
505
+ case sql
506
+ when /COUNT.*username = '0records'/
507
+ when /COUNT.*username = '2records'/
508
+ yield({:v => 2})
509
+ when /COUNT.*username = '1record'/
510
+ yield({:v => 1})
511
+ when /username = '1record'/
512
+ yield({:id => 3, :username => "1record", :password => "test"})
513
+ end
514
+ end
515
+ })
516
+
517
+ @user = User.new(:username => "2records", :password => "anothertest")
518
+ @user.should_not be_valid
519
+ @user.errors.full_messages.should == ['username is already taken']
520
+
521
+ @user = User.new(:username => "1record", :password => "anothertest")
522
+ @user.should_not be_valid
523
+ @user.errors.full_messages.should == ['username is already taken']
524
+
525
+ @user = User.new(:id=>4, :username => "1record", :password => "anothertest")
526
+ @user.instance_variable_set(:@new, false)
527
+ @user.should_not be_valid
528
+ @user.errors.full_messages.should == ['username is already taken']
529
+
530
+ @user = User.new(:id=>3, :username => "1record", :password => "anothertest")
531
+ @user.instance_variable_set(:@new, false)
532
+ @user.should be_valid
533
+ @user.errors.full_messages.should == []
534
+
535
+ @user = User.new(:username => "0records", :password => "anothertest")
536
+ @user.should be_valid
537
+ @user.errors.full_messages.should == []
538
+ end
140
539
 
141
540
  it "should have a validates block that contains multiple validations" do
142
541
  class Person < Sequel::Model
@@ -185,7 +584,7 @@ describe Sequel::Model, "Validations" do
185
584
 
186
585
  it "should validate correctly instances initialized with string keys" do
187
586
  class Can < Sequel::Model
188
- def columns; [:id, :name]; end
587
+ columns :id, :name
189
588
 
190
589
  validates_length_of :name, :minimum => 4
191
590
  end
@@ -219,7 +618,7 @@ end
219
618
  describe "Model#save" do
220
619
  setup do
221
620
  @c = Class.new(Sequel::Model(:people)) do
222
- def columns; [:id]; end
621
+ columns :id
223
622
 
224
623
  validates_each :id do |o, a, v|
225
624
  o.errors[a] << 'blah' unless v == 5
@@ -243,4 +642,4 @@ describe "Model#save" do
243
642
  specify "should return false if validations fail" do
244
643
  @m.save.should == false
245
644
  end
246
- end
645
+ end