dm-validations 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/LICENSE +20 -0
  2. data/README +72 -0
  3. data/Rakefile +74 -0
  4. data/TODO +16 -0
  5. data/lib/dm-validations.rb +208 -0
  6. data/lib/dm-validations/absent_field_validator.rb +60 -0
  7. data/lib/dm-validations/acceptance_validator.rb +76 -0
  8. data/lib/dm-validations/auto_validate.rb +98 -0
  9. data/lib/dm-validations/confirmation_validator.rb +76 -0
  10. data/lib/dm-validations/contextual_validators.rb +56 -0
  11. data/lib/dm-validations/custom_validator.rb +72 -0
  12. data/lib/dm-validations/format_validator.rb +94 -0
  13. data/lib/dm-validations/formats/email.rb +40 -0
  14. data/lib/dm-validations/generic_validator.rb +92 -0
  15. data/lib/dm-validations/length_validator.rb +113 -0
  16. data/lib/dm-validations/method_validator.rb +58 -0
  17. data/lib/dm-validations/numeric_validator.rb +66 -0
  18. data/lib/dm-validations/primitive_validator.rb +60 -0
  19. data/lib/dm-validations/required_field_validator.rb +88 -0
  20. data/lib/dm-validations/support/object.rb +5 -0
  21. data/lib/dm-validations/uniqueness_validator.rb +61 -0
  22. data/lib/dm-validations/validation_errors.rb +63 -0
  23. data/lib/dm-validations/within_validator.rb +41 -0
  24. data/spec/integration/absent_field_validator_spec.rb +34 -0
  25. data/spec/integration/acceptance_validator_spec.rb +87 -0
  26. data/spec/integration/auto_validate_spec.rb +262 -0
  27. data/spec/integration/confirmation_validator_spec.rb +66 -0
  28. data/spec/integration/contextual_validators_spec.rb +28 -0
  29. data/spec/integration/custom_validator_spec.rb +9 -0
  30. data/spec/integration/format_validator_spec.rb +118 -0
  31. data/spec/integration/generic_validator_spec.rb +9 -0
  32. data/spec/integration/length_validator_spec.rb +113 -0
  33. data/spec/integration/method_validator_spec.rb +31 -0
  34. data/spec/integration/numeric_validator_spec.rb +192 -0
  35. data/spec/integration/primitive_validator_spec.rb +25 -0
  36. data/spec/integration/required_field_validator_spec.rb +93 -0
  37. data/spec/integration/uniqueness_validator_spec.rb +81 -0
  38. data/spec/integration/validation_errors_spec.rb +18 -0
  39. data/spec/integration/validation_spec.rb +339 -0
  40. data/spec/integration/within_validator_spec.rb +35 -0
  41. data/spec/spec.opts +2 -0
  42. data/spec/spec_helper.rb +26 -0
  43. metadata +104 -0
@@ -0,0 +1,66 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Validate::ConfirmationValidator do
5
+ before(:all) do
6
+ class Canoe
7
+ include DataMapper::Resource
8
+
9
+ property :id, Integer, :serial => true
10
+ property :name, String
11
+ property :name_confirmation, String
12
+
13
+ validates_is_confirmed :name
14
+ end
15
+ end
16
+
17
+ it "should validate the confirmation of a value on an instance of a resource" do
18
+ canoe = Canoe.new
19
+ canoe.name = 'White Water'
20
+ canoe.name_confirmation = 'Not confirmed'
21
+ canoe.valid?.should_not == true
22
+ canoe.errors.full_messages.first.should == 'Name does not match the confirmation'
23
+
24
+ canoe.name_confirmation = 'White Water'
25
+ canoe.valid?.should == true
26
+ end
27
+
28
+ it "should default the name of the confirmation field to <field>_confirmation
29
+ if one is not specified" do
30
+ canoe = Canoe.new
31
+ canoe.name = 'White Water'
32
+ canoe.name_confirmation = 'White Water'
33
+ canoe.valid?.should == true
34
+ end
35
+
36
+ it "should default to allowing nil values on the fields if not specified to" do
37
+ Canoe.new.valid?.should == true
38
+ end
39
+
40
+ it "should not pass validation with a nil value when specified to" do
41
+ class Canoe
42
+ validators.clear!
43
+ validates_is_confirmed :name, :allow_nil => false
44
+ end
45
+ Canoe.new.valid?.should_not == true
46
+ end
47
+
48
+ it "should allow the name of the confirmation field to be set" do
49
+ class Canoe
50
+ validators.clear!
51
+ validates_is_confirmed :name, :confirm => :name_check
52
+ def name_check=(value)
53
+ @name_check = value
54
+ end
55
+
56
+ def name_check
57
+ @name_confirmation ||= nil
58
+ end
59
+ end
60
+ canoe = Canoe.new
61
+ canoe.name = 'Float'
62
+ canoe.name_check = 'Float'
63
+ canoe.valid?.should == true
64
+
65
+ end
66
+ end
@@ -0,0 +1,28 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Validate::ContextualValidators do
5
+
6
+ before :all do
7
+ class Kayak
8
+ include DataMapper::Resource
9
+ property :id, Integer, :key => true
10
+ property :salesman, String, :auto_validation => false
11
+ validates_absent :salesman, :when => :sold
12
+ end
13
+ end
14
+
15
+ it "should pass validation for a specific context" do
16
+ k = Kayak.new
17
+ k.valid?(:sold).should == true
18
+ k.salesman = 'John Doe'
19
+ k.valid?(:sold).should_not == true
20
+ end
21
+
22
+ it "should raise an exception if you provide an invalid context to save" do
23
+
24
+ lambda { Kayak.new.save(:invalid_context) }.should raise_error
25
+ lambda { Kayak.new.save(nil) }.should raise_error
26
+ lambda { Kayak.new.save(false) }.should raise_error
27
+ end
28
+ end
@@ -0,0 +1,9 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Validate::CustomValidator do
5
+ it "should have specs" do
6
+ pending
7
+ # FIXME do something, add specs
8
+ end
9
+ end
@@ -0,0 +1,118 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Validate::FormatValidator do
5
+ before(:all) do
6
+ class BillOfLading
7
+ include DataMapper::Resource
8
+ property :id, Integer, :key => true
9
+ property :doc_no, String, :auto_validation => false
10
+ property :email, String, :auto_validation => false
11
+
12
+ # this is a trivial example
13
+ validates_format :doc_no, :with => lambda { |code|
14
+ (code =~ /A\d{4}/) || (code =~ /[B-Z]\d{6}X12/)
15
+ }
16
+
17
+ validates_format :email, :as => :email_address
18
+ end
19
+ end
20
+
21
+ it 'should validate the format of a value on an instance of a resource' do
22
+ bol = BillOfLading.new
23
+ bol.doc_no = 'BAD CODE :)'
24
+ bol.should_not be_valid
25
+ bol.errors.on(:doc_no).should include('Doc no has an invalid format')
26
+
27
+ bol.doc_no = 'A1234'
28
+ bol.valid?
29
+ bol.errors.on(:doc_no).should be_nil
30
+
31
+ bol.doc_no = 'B123456X12'
32
+ bol.valid?
33
+ bol.errors.on(:doc_no).should be_nil
34
+ end
35
+
36
+ it 'should have a pre-defined e-mail format' do
37
+ bad = [ '-- guy --@example.com', # spaces are invalid unless quoted
38
+ '[guy]@example.com', # square brackets are invalid unless quoted
39
+ '.guy@example.com', # local part cannot start with .
40
+ 'guy@example 10:10',
41
+ 'guy@ example dot com',
42
+ 'guy'
43
+ ]
44
+
45
+ good = [
46
+ '+1~1+@example.com',
47
+ '{_guy_}@example.com',
48
+ '"[[ guy ]]"@example.com',
49
+ 'guy."guy"@example.com',
50
+ 'guy@localhost',
51
+ 'guy@example.com',
52
+ 'guy@example.co.uk',
53
+ 'guy@example.co.za',
54
+ 'guy@[187.223.45.119]',
55
+ 'guy@123.com'
56
+ ]
57
+
58
+ bol = BillOfLading.new
59
+ bol.should_not be_valid
60
+ bol.errors.on(:email).should include('Email has an invalid format')
61
+
62
+ bad.map do |e|
63
+ bol.email = e
64
+ bol.valid?
65
+ bol.errors.on(:email).should include('Email has an invalid format')
66
+ end
67
+
68
+ good.map do |e|
69
+ bol.email = e
70
+ bol.valid?
71
+ bol.errors.on(:email).should be_nil
72
+ end
73
+
74
+ end
75
+
76
+ it 'should have pre-defined formats'
77
+ end
78
+
79
+ =begin
80
+ addresses = [
81
+ '-- dave --@example.com', # (spaces are invalid unless enclosed in quotation marks)
82
+ '[dave]@example.com', # (square brackets are invalid, unless contained within quotation marks)
83
+ '.dave@example.com', # (the local part of a domain name cannot start with a period)
84
+ 'Max@Job 3:14',
85
+ 'Job@Book of Job',
86
+ 'J. P. \'s-Gravezande, a.k.a. The Hacker!@example.com',
87
+ ]
88
+ addresses.each do |address|
89
+ if address =~ RFC2822::EmailAddress
90
+ puts "#{address} deveria ter sido rejeitado, ERRO"
91
+ else
92
+ puts "#{address} rejeitado, OK"
93
+ end
94
+ end
95
+
96
+
97
+ addresses = [
98
+ '+1~1+@example.com',
99
+ '{_dave_}@example.com',
100
+ '"[[ dave ]]"@example.com',
101
+ 'dave."dave"@example.com',
102
+ 'test@localhost',
103
+ 'test@example.com',
104
+ 'test@example.co.uk',
105
+ 'test@example.com.br',
106
+ '"J. P. \'s-Gravezande, a.k.a. The Hacker!"@example.com',
107
+ 'me@[187.223.45.119]',
108
+ 'someone@123.com',
109
+ 'simon&garfunkel@songs.com'
110
+ ]
111
+ addresses.each do |address|
112
+ if address =~ RFC2822::EmailAddress
113
+ puts "#{address} aceito, OK"
114
+ else
115
+ puts "#{address} deveria ser aceito, ERRO"
116
+ end
117
+ end
118
+ =end
@@ -0,0 +1,9 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Validate::GenericValidator do
5
+ it "should have specs" do
6
+ pending
7
+ # FIXME do something, add specs
8
+ end
9
+ end
@@ -0,0 +1,113 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Validate::LengthValidator do
5
+ before(:all) do
6
+ class MotorLaunch
7
+ include DataMapper::Resource
8
+ property :id, Integer, :serial => true
9
+ property :name, String, :auto_validation => false
10
+ end
11
+
12
+ class BoatDock
13
+ include DataMapper::Resource
14
+ property :id, Integer, :serial => true
15
+ property :name, String, :auto_validation => false, :default => "I'm a long string"
16
+ validates_length :name, :min => 3
17
+ end
18
+ end
19
+
20
+ it "should be able to consider things valid even if we have a custom error message" do
21
+ class Jabberwock
22
+ include DataMapper::Resource
23
+ property :id, Integer, :key => true
24
+ property :snickersnack, String
25
+ validates_length :snickersnack, :within => 3..40, :message => "worble warble"
26
+ end
27
+ wock = Jabberwock.new
28
+ wock.snickersnack = "hello"
29
+ wock.id = 1
30
+ wock.valid?.should == true
31
+ end
32
+
33
+ it "should be able to set a minimum length of a string field" do
34
+ class MotorLaunch
35
+ validates_length :name, :min => 3
36
+ end
37
+
38
+ launch = MotorLaunch.new
39
+ launch.name = 'Ab'
40
+ launch.valid?.should == false
41
+ launch.errors.full_messages.first.should == 'Name must be more than 3 characters long'
42
+ end
43
+
44
+ it "should be able to alias :minimum for :min " do
45
+ class MotorLaunch
46
+ validators.clear!
47
+ validates_length :name, :minimum => 3
48
+ end
49
+
50
+ launch = MotorLaunch.new
51
+ launch.name = 'Ab'
52
+ launch.valid?.should == false
53
+ launch.errors.full_messages.first.should == 'Name must be more than 3 characters long'
54
+ end
55
+
56
+ it "should be able to set a maximum length of a string field" do
57
+ class MotorLaunch
58
+ validators.clear!
59
+ validates_length :name, :max => 5
60
+ end
61
+
62
+ launch = MotorLaunch.new
63
+ launch.name = 'Lip­smackin­thirst­quenchin­acetastin­motivatin­good­buzzin­cool­talkin­high­walkin­fast­livin­ever­givin­cool­fizzin'
64
+ launch.valid?.should == false
65
+ launch.errors.full_messages.first.should == 'Name must be less than 5 characters long'
66
+ end
67
+
68
+ it "should be able to alias :maximum for :max" do
69
+ class MotorLaunch
70
+ validators.clear!
71
+ validates_length :name, :maximum => 5
72
+ end
73
+ launch = MotorLaunch.new
74
+ launch.name = 'Lip­smackin­thirst­quenchin­acetastin­motivatin­good­buzzin­cool­talkin­high­walkin­fast­livin­ever­givin­cool­fizzin'
75
+ launch.valid?.should == false
76
+ launch.errors.full_messages.first.should == 'Name must be less than 5 characters long'
77
+ end
78
+
79
+ it "should be able to specify a length range of a string field" do
80
+ class MotorLaunch
81
+ validators.clear!
82
+ validates_length :name, :in => (3..5)
83
+ end
84
+
85
+ launch = MotorLaunch.new
86
+ launch.name = 'Lip­smackin­thirst­quenchin­acetastin­motivatin­good­buzzin­cool­talkin­high­walkin­fast­livin­ever­givin­cool­fizzin'
87
+ launch.valid?.should == false
88
+ launch.errors.full_messages.first.should == 'Name must be between 3 and 5 characters long'
89
+
90
+ launch.name = 'A'
91
+ launch.valid?.should == false
92
+ launch.errors.full_messages.first.should == 'Name must be between 3 and 5 characters long'
93
+
94
+ launch.name = 'Ride'
95
+ launch.valid?.should == true
96
+ end
97
+
98
+ it "should be able to alias :within for :in" do
99
+ class MotorLaunch
100
+ validators.clear!
101
+ validates_length :name, :within => (3..5)
102
+ end
103
+
104
+ launch = MotorLaunch.new
105
+ launch.name = 'Ride'
106
+ launch.valid?.should == true
107
+ end
108
+
109
+ it "should pass if a default fulfills the requirements" do
110
+ doc = BoatDock.new
111
+ doc.should be_valid
112
+ end
113
+ end
@@ -0,0 +1,31 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Validate::MethodValidator do
5
+ before(:all) do
6
+ class Ship
7
+ include DataMapper::Resource
8
+ property :id, Integer, :key => true
9
+ property :name, String
10
+
11
+ validates_with_method :fail_validation, :when => [:testing_failure]
12
+ validates_with_method :pass_validation, :when => [:testing_success]
13
+
14
+ def fail_validation
15
+ return false, 'Validation failed'
16
+ end
17
+
18
+ def pass_validation
19
+ return true
20
+ end
21
+ end
22
+ end
23
+
24
+ it "should validate via a method on the resource" do
25
+ Ship.new.valid_for_testing_failure?.should == false
26
+ Ship.new.valid_for_testing_success?.should == true
27
+ ship = Ship.new
28
+ ship.valid_for_testing_failure?.should == false
29
+ ship.errors.full_messages.include?('Validation failed').should == true
30
+ end
31
+ end
@@ -0,0 +1,192 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ class Bill # :nodoc:
5
+ include DataMapper::Resource
6
+ property :id, Integer, :serial => true
7
+ property :amount_1, String, :auto_validation => false
8
+ property :amount_2, Float, :auto_validation => false
9
+ validates_is_number :amount_1, :amount_2
10
+ end
11
+
12
+ class Hillary # :nodoc:
13
+ include DataMapper::Resource
14
+ property :id, Integer, :serial => true
15
+ property :amount_1, Float, :auto_validation => false, :default => 0.01
16
+ validates_is_number :amount_1
17
+ end
18
+
19
+ describe DataMapper::Validate::NumericValidator do
20
+ it "should validate a floating point value on the instance of a resource" do
21
+ b = Bill.new
22
+ b.should_not be_valid
23
+ b.amount_1 = 'ABC'
24
+ b.amount_2 = 27.343
25
+ b.should_not be_valid
26
+ b.amount_1 = '34.33'
27
+ b.should be_valid
28
+ end
29
+
30
+ it "should validate an integer value on the instance of a resource" do
31
+ class Bill
32
+ property :quantity_1, String, :auto_validation => false
33
+ property :quantity_2, Integer, :auto_validation => false
34
+
35
+ validators.clear!
36
+ validates_is_number :quantity_1, :quantity_2, :integer_only => true
37
+ end
38
+ b = Bill.new
39
+ b.valid?.should_not == true
40
+ b.quantity_1 = '12.334'
41
+ b.quantity_2 = 27.343
42
+ b.valid?.should_not == true
43
+ b.quantity_1 = '34.33'
44
+ b.quantity_2 = 22
45
+ b.valid?.should_not == true
46
+ b.quantity_1 = '34'
47
+ b.valid?.should == true
48
+
49
+ end
50
+
51
+ it "should validate if a default fufills the requirements" do
52
+ h = Hillary.new
53
+ h.should be_valid
54
+ end
55
+
56
+ describe 'auto validation' do
57
+ before :all do
58
+ class Fish
59
+ include DataMapper::Resource
60
+ property :id, Integer, :serial => true
61
+ property :scales, Integer
62
+ end
63
+ end
64
+
65
+ describe 'Float' do
66
+ describe 'with default precision and scale' do
67
+ before :all do
68
+ class RobotFish < Fish
69
+ property :average_weight, Float
70
+ end
71
+ end
72
+
73
+ before do
74
+ @robot_fish = RobotFish.new
75
+ end
76
+
77
+ it 'should allow up to 10 digits before the decimal' do
78
+ @robot_fish.average_weight = 0
79
+ @robot_fish.should be_valid
80
+
81
+ @robot_fish.average_weight = 9_999_999_999
82
+ @robot_fish.should be_valid
83
+
84
+ @robot_fish.average_weight = 10_000_000_000
85
+ @robot_fish.should_not be_valid
86
+ end
87
+
88
+ it 'should allow 0 digits after the decimal' do
89
+ @robot_fish.average_weight = 0
90
+ @robot_fish.should be_valid
91
+ end
92
+
93
+ it 'should allow 1 digit after the decimal if it is a zero' do
94
+ @robot_fish.average_weight = 0.0
95
+ @robot_fish.should be_valid
96
+
97
+ @robot_fish.average_weight = 9_999_999_999.0
98
+ @robot_fish.should be_valid
99
+
100
+ @robot_fish.average_weight = 0.1
101
+ @robot_fish.should_not be_valid
102
+ end
103
+ end
104
+
105
+ describe 'with a precision of 4 and a scale of 2' do
106
+ before :all do
107
+ class GoldFish < Fish
108
+ property :average_weight, Float, :precision => 4, :scale => 2
109
+ end
110
+ end
111
+
112
+ before do
113
+ @gold_fish = GoldFish.new
114
+ end
115
+
116
+ it 'should allow up to 2 digits before the decimal' do
117
+ @gold_fish.average_weight = 0
118
+ @gold_fish.should be_valid
119
+
120
+ @gold_fish.average_weight = 99
121
+ @gold_fish.should be_valid
122
+
123
+ @gold_fish.average_weight = -99
124
+ @gold_fish.should be_valid
125
+
126
+ @gold_fish.average_weight = 100
127
+ @gold_fish.should_not be_valid
128
+
129
+ @gold_fish.average_weight = -100
130
+ @gold_fish.should_not be_valid
131
+ end
132
+
133
+ it 'should allow 2 digits after the decimal' do
134
+ @gold_fish.average_weight = 99.99
135
+ @gold_fish.should be_valid
136
+
137
+ @gold_fish.average_weight = -99.99
138
+ @gold_fish.should be_valid
139
+
140
+ @gold_fish.average_weight = 99.999
141
+ @gold_fish.should_not be_valid
142
+
143
+ @gold_fish.average_weight = -99.999
144
+ @gold_fish.should_not be_valid
145
+ end
146
+ end
147
+
148
+ describe 'with a precision of 2 and a scale of 2' do
149
+ before :all do
150
+ class SilverFish < Fish
151
+ property :average_weight, Float, :precision => 2, :scale => 2
152
+ end
153
+ end
154
+
155
+ before do
156
+ @silver_fish = SilverFish.new
157
+ end
158
+
159
+ it 'should allow a 0 before the decimal' do
160
+ @silver_fish.average_weight = 0
161
+ @silver_fish.should be_valid
162
+
163
+ @silver_fish.average_weight = 0.1
164
+ @silver_fish.should be_valid
165
+
166
+ @silver_fish.average_weight = -0.1
167
+ @silver_fish.should be_valid
168
+
169
+ @silver_fish.average_weight = 1
170
+ @silver_fish.should_not be_valid
171
+
172
+ @silver_fish.average_weight = -1
173
+ @silver_fish.should_not be_valid
174
+ end
175
+
176
+ it 'should allow 2 digits after the decimal' do
177
+ @silver_fish.average_weight = 0.99
178
+ @silver_fish.should be_valid
179
+
180
+ @silver_fish.average_weight = -0.99
181
+ @silver_fish.should be_valid
182
+
183
+ @silver_fish.average_weight = 0.999
184
+ @silver_fish.should_not be_valid
185
+
186
+ @silver_fish.average_weight = -0.999
187
+ @silver_fish.should_not be_valid
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end