dm-validations 0.9.2

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 (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