strelka 0.0.1.pre.203 → 0.0.1.pre.214
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.
- data.tar.gz.sig +6 -2
- data/ChangeLog +103 -26
- data/MILESTONES.rdoc +16 -0
- data/Manifest.txt +1 -0
- data/Rakefile +1 -0
- data/lib/strelka/app.rb +39 -22
- data/lib/strelka/app/errors.rb +22 -1
- data/lib/strelka/app/parameters.rb +3 -4
- data/lib/strelka/app/templating.rb +49 -28
- data/lib/strelka/logging.rb +1 -1
- data/lib/strelka/mixins.rb +9 -0
- data/lib/strelka/paramvalidator.rb +2 -1
- data/lib/strelka/plugins.rb +10 -8
- data/spec/strelka/app/errors_spec.rb +23 -0
- data/spec/strelka/app/templating_spec.rb +19 -0
- data/spec/strelka/app_spec.rb +21 -0
- data/spec/strelka/httpresponse/negotiation_spec.rb +1 -0
- data/spec/strelka/paramvalidator_spec.rb +780 -707
- data/spec/strelka/plugins_spec.rb +27 -1
- metadata +117 -35
- metadata.gz.sig +0 -0
data/lib/strelka/logging.rb
CHANGED
@@ -186,7 +186,7 @@ module Strelka::Logging
|
|
186
186
|
:info => colorize( :normal ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
|
187
187
|
:warn => colorize( :bold, :yellow ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
|
188
188
|
:error => colorize( :red ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
|
189
|
-
:fatal => colorize( :bold, :red
|
189
|
+
:fatal => colorize( :bold, :red ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
|
190
190
|
}
|
191
191
|
|
192
192
|
|
data/lib/strelka/mixins.rb
CHANGED
@@ -305,9 +305,11 @@ module Strelka
|
|
305
305
|
# include Strelka::MethodUtilities
|
306
306
|
#
|
307
307
|
# singleton_attr_accessor :types
|
308
|
+
# singleton_method_alias :kinds, :types
|
308
309
|
# end
|
309
310
|
#
|
310
311
|
# MyClass.types = [ :pheno, :proto, :stereo ]
|
312
|
+
# MyClass.kinds # => [:pheno, :proto, :stereo]
|
311
313
|
#
|
312
314
|
module MethodUtilities
|
313
315
|
|
@@ -338,6 +340,12 @@ module Strelka
|
|
338
340
|
end
|
339
341
|
end
|
340
342
|
|
343
|
+
### Creates an alias for the +original+ method named +newname+.
|
344
|
+
def singleton_method_alias( newname, original )
|
345
|
+
singleton_class.__send__( :alias_method, newname, original )
|
346
|
+
end
|
347
|
+
|
348
|
+
|
341
349
|
end # module MethodUtilities
|
342
350
|
|
343
351
|
|
@@ -354,6 +362,7 @@ module Strelka
|
|
354
362
|
status_info = nil
|
355
363
|
|
356
364
|
if http_status.is_a?( Hash ) && http_status.key?(:status)
|
365
|
+
self.log.debug "Re-finishing with a status_info struct: %p." % [ http_status ]
|
357
366
|
status_info = http_status
|
358
367
|
else
|
359
368
|
message ||= HTTP::STATUS_NAME[ http_status ]
|
@@ -371,7 +371,8 @@ class Strelka::ParamValidator < ::FormValidator
|
|
371
371
|
args.unshift( block ) if block
|
372
372
|
|
373
373
|
# Custom validator -- either a callback or a regex
|
374
|
-
if args.first.is_a?( Regexp ) ||
|
374
|
+
if args.first.is_a?( Regexp ) ||
|
375
|
+
args.first.respond_to?( :call )
|
375
376
|
self.profile[:constraints][ name ] = args.shift
|
376
377
|
|
377
378
|
# Builtin match validator, either explicit or implied by the name
|
data/lib/strelka/plugins.rb
CHANGED
@@ -209,6 +209,7 @@ module Strelka
|
|
209
209
|
|
210
210
|
extend( cm_mod )
|
211
211
|
cm_mod.instance_variables.each do |ivar|
|
212
|
+
next if instance_variable_defined?( ivar )
|
212
213
|
Strelka.log.debug " copying class instance variable %s" % [ ivar ]
|
213
214
|
ival = cm_mod.instance_variable_get( ivar )
|
214
215
|
|
@@ -258,17 +259,18 @@ module Strelka
|
|
258
259
|
end
|
259
260
|
|
260
261
|
|
262
|
+
### Return the list of plugin modules that are in effect for the current
|
263
|
+
### app.
|
264
|
+
def application_stack
|
265
|
+
Strelka.log.debug "Ancestors are: %p" % [ self.class.ancestors ]
|
266
|
+
return self.ancestors.select {|mod| mod.respond_to?(:plugin_name) }
|
267
|
+
end
|
268
|
+
|
261
269
|
|
262
270
|
### Output the application stack into the logfile.
|
263
271
|
def dump_application_stack
|
264
|
-
stack = self.
|
265
|
-
|
266
|
-
drop_while {|mod| mod != Strelka::PluginLoader }.
|
267
|
-
select {|mod| mod.respond_to?(:plugin_name) }.
|
268
|
-
collect {|mod| mod.plugin_name }.
|
269
|
-
reverse
|
270
|
-
|
271
|
-
self.log.info "Application stack: request -> %s" % [ stack.join(" -> ") ]
|
272
|
+
stack = self.application_stack.map( &:plugin_name )
|
273
|
+
Strelka.log.info "Application stack: request -> %s" % [ stack.join(" -> ") ]
|
272
274
|
end
|
273
275
|
|
274
276
|
end # module PluginLoader
|
@@ -177,6 +177,29 @@ describe Strelka::App::Errors do
|
|
177
177
|
res.notes[:status_info][:message].should == "Your sandwich is missing something."
|
178
178
|
end
|
179
179
|
|
180
|
+
it "provides its own exception handler for the request phase" do
|
181
|
+
@app.class_eval do
|
182
|
+
on_status do |res, info|
|
183
|
+
res.body = info[:exception].class.name
|
184
|
+
return res
|
185
|
+
end
|
186
|
+
|
187
|
+
get do |req|
|
188
|
+
raise "An uncaught exception"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
req = @request_factory.get( '/foom' )
|
193
|
+
res = @app.new.handle( req )
|
194
|
+
|
195
|
+
res.notes[:status_info].should include( :status, :message, :headers, :exception )
|
196
|
+
res.notes[:status_info][:status].should == HTTP::SERVER_ERROR
|
197
|
+
res.notes[:status_info][:message].should == "An uncaught exception"
|
198
|
+
res.notes[:status_info][:exception].should be_a( RuntimeError )
|
199
|
+
res.body.should == "RuntimeError"
|
200
|
+
end
|
201
|
+
|
202
|
+
|
180
203
|
context "template-style handlers" do
|
181
204
|
|
182
205
|
before( :all ) do
|
@@ -172,6 +172,25 @@ describe Strelka::App::Templating do
|
|
172
172
|
res.status.should == 200
|
173
173
|
end
|
174
174
|
|
175
|
+
it "doesn't wrap the layout around non-template responses" do
|
176
|
+
@app.class_eval do
|
177
|
+
layout 'layout.tmpl'
|
178
|
+
|
179
|
+
def handle_request( req )
|
180
|
+
# Super through the plugins and then load the template into the response
|
181
|
+
super do
|
182
|
+
res = req.response
|
183
|
+
res.body = self.template( :main ).render
|
184
|
+
res
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
res = @app.new.handle( @req )
|
190
|
+
|
191
|
+
res.body.should == "A template for testing the Templating plugin.\n"
|
192
|
+
end
|
193
|
+
|
175
194
|
end
|
176
195
|
|
177
196
|
end
|
data/spec/strelka/app_spec.rb
CHANGED
@@ -350,6 +350,27 @@ describe Strelka::App do
|
|
350
350
|
res.body.should =~ /internal server error/i
|
351
351
|
end
|
352
352
|
|
353
|
+
it "isn't in 'developer mode' by default" do
|
354
|
+
@app.should_not be_in_devmode()
|
355
|
+
end
|
356
|
+
|
357
|
+
it "can be configured to be in 'developer mode' using the Configurability API" do
|
358
|
+
@app.configure( devmode: true )
|
359
|
+
@app.should be_in_devmode()
|
360
|
+
end
|
361
|
+
|
362
|
+
it "configures itself to be in 'developer mode' if debugging is enabled" do
|
363
|
+
debugsetting = $DEBUG
|
364
|
+
|
365
|
+
begin
|
366
|
+
$DEBUG = true
|
367
|
+
@app.configure
|
368
|
+
@app.should be_in_devmode()
|
369
|
+
ensure
|
370
|
+
$DEBUG = debugsetting
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
353
374
|
|
354
375
|
describe "process name" do
|
355
376
|
|
@@ -49,932 +49,1005 @@ describe Strelka::ParamValidator do
|
|
49
49
|
@validator.should have_args()
|
50
50
|
end
|
51
51
|
|
52
|
-
it "allows constraints to be added" do
|
53
|
-
@validator.add( :a_field, :string )
|
54
|
-
@validator.param_names.should include( 'a_field' )
|
55
|
-
end
|
56
52
|
|
57
|
-
|
58
|
-
|
59
|
-
|
53
|
+
describe "profile" do
|
54
|
+
|
55
|
+
it "allows constraints to be added" do
|
60
56
|
@validator.add( :a_field, :string )
|
61
|
-
|
62
|
-
|
63
|
-
end
|
57
|
+
@validator.param_names.should include( 'a_field' )
|
58
|
+
end
|
64
59
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
60
|
+
it "doesn't allow a constraint to be added twice" do
|
61
|
+
@validator.add( :a_field, :string )
|
62
|
+
expect {
|
63
|
+
@validator.add( :a_field, :string )
|
64
|
+
}.to raise_error( /parameter "a_field" is already defined/i )
|
65
|
+
@validator.param_names.should include( 'a_field' )
|
66
|
+
end
|
70
67
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
68
|
+
it "allows an existing constraint to be overridden" do
|
69
|
+
@validator.add( :a_field, :string )
|
70
|
+
@validator.override( :a_field, :integer )
|
71
|
+
@validator.param_names.should include( 'a_field' )
|
72
|
+
@validator.validate( 'a_field' => 'a string!' )
|
73
|
+
@validator.should have_errors()
|
74
|
+
@validator.should_not be_okay()
|
75
|
+
@validator.error_messages.should include( "Invalid value for 'A Field'" )
|
76
|
+
end
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
@validator.should_not be_okay()
|
84
|
-
@validator.error_messages.should include( "Invalid value for 'A Field'" )
|
85
|
-
end
|
78
|
+
it "doesn't allow a non-existant constraint to be overridden" do
|
79
|
+
expect {
|
80
|
+
@validator.override( :a_field, :string )
|
81
|
+
}.to raise_error( /no parameter "a_field" defined/i )
|
82
|
+
@validator.param_names.should_not include( 'a_field' )
|
83
|
+
end
|
86
84
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
end
|
85
|
+
it "raises an exception on an unknown constraint type" do
|
86
|
+
expect {
|
87
|
+
@validator.add( :foo, $stderr )
|
88
|
+
}.to raise_error( /no builtin "foo" validator/ )
|
89
|
+
end
|
93
90
|
|
94
|
-
|
95
|
-
|
96
|
-
@validator.
|
97
|
-
|
98
|
-
|
91
|
+
it "retains its profile through a copy" do
|
92
|
+
@validator.add( :foo, :string, :required )
|
93
|
+
dup = @validator.dup
|
94
|
+
@validator.validate( {} )
|
95
|
+
@validator.should_not be_okay()
|
96
|
+
@validator.should have_errors()
|
97
|
+
@validator.error_messages.should == ["Missing value for 'Foo'"]
|
98
|
+
end
|
99
99
|
|
100
|
-
|
101
|
-
@validator.add( :foo, :string, :required )
|
102
|
-
dup = @validator.dup
|
103
|
-
@validator.validate( {} )
|
104
|
-
@validator.should_not be_okay()
|
105
|
-
@validator.should have_errors()
|
106
|
-
@validator.error_messages.should == ["Missing value for 'Foo'"]
|
107
|
-
end
|
100
|
+
end # describe "profile"
|
108
101
|
|
109
|
-
|
110
|
-
@validator.add( :foo, /^\d+$/ )
|
102
|
+
describe "validation" do
|
111
103
|
|
112
|
-
|
113
|
-
|
104
|
+
it "provides read and write access to valid args via the index operator" do
|
105
|
+
@validator.add( :foo, /^\d+$/ )
|
114
106
|
|
115
|
-
|
116
|
-
|
117
|
-
end
|
107
|
+
@validator.validate( {'foo' => "1"} )
|
108
|
+
@validator[:foo].should == "1"
|
118
109
|
|
110
|
+
@validator[:foo] = "bar"
|
111
|
+
@validator["foo"].should == "bar"
|
112
|
+
end
|
119
113
|
|
120
|
-
|
121
|
-
|
122
|
-
|
114
|
+
it "untaints valid args if told to do so" do
|
115
|
+
tainted_one = "1"
|
116
|
+
tainted_one.taint
|
123
117
|
|
124
|
-
|
125
|
-
|
118
|
+
@validator.add( :number, /^\d+$/, :untaint )
|
119
|
+
@validator.validate( 'number' => tainted_one )
|
126
120
|
|
127
|
-
|
128
|
-
|
129
|
-
|
121
|
+
@validator[:number].should == "1"
|
122
|
+
@validator[:number].tainted?.should be_false()
|
123
|
+
end
|
130
124
|
|
125
|
+
it "knows the names of fields that were required but missing from the parameters" do
|
126
|
+
@validator.add( :id, :integer, :required )
|
127
|
+
@validator.validate( {} )
|
131
128
|
|
132
|
-
|
133
|
-
|
134
|
-
@validator.validate( 'treename' => " ygdrassil " )
|
135
|
-
@validator[:treename].should == 'ygdrassil'
|
136
|
-
end
|
129
|
+
@validator.should have_errors()
|
130
|
+
@validator.should_not be_okay()
|
137
131
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
@validator[:stuff].should == ['the1tree', '(!)']
|
142
|
-
end
|
132
|
+
@validator.missing.should have(1).members
|
133
|
+
@validator.missing.should == ['id']
|
134
|
+
end
|
143
135
|
|
144
|
-
|
145
|
-
|
146
|
-
|
136
|
+
it "knows the names of fields that did not meet their constraints" do
|
137
|
+
@validator.add( :number, :integer, :required )
|
138
|
+
@validator.validate( 'number' => 'rhinoceros' )
|
147
139
|
|
148
|
-
|
149
|
-
|
150
|
-
@validator[:order_number][:sku].should_not be_tainted()
|
151
|
-
end
|
140
|
+
@validator.should have_errors()
|
141
|
+
@validator.should_not be_okay()
|
152
142
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
@validator.validate( 'amount' => '2.28' )
|
143
|
+
@validator.invalid.should have(1).keys
|
144
|
+
@validator.invalid.keys.should == ['number']
|
145
|
+
end
|
157
146
|
|
158
|
-
|
159
|
-
|
147
|
+
it "can return a combined list of missing and invalid fields" do
|
148
|
+
@validator.add( :number, :integer )
|
149
|
+
@validator.add( :id, /^(\w{20})$/, :required )
|
160
150
|
|
161
|
-
|
162
|
-
@validator.add( :id, :integer, :required )
|
163
|
-
@validator.validate( {} )
|
151
|
+
@validator.validate( 'number' => 'rhinoceros' )
|
164
152
|
|
165
|
-
|
166
|
-
|
153
|
+
@validator.should have_errors()
|
154
|
+
@validator.should_not be_okay()
|
167
155
|
|
168
|
-
|
169
|
-
|
170
|
-
|
156
|
+
@validator.error_fields.should have(2).members
|
157
|
+
@validator.error_fields.should include('number')
|
158
|
+
@validator.error_fields.should include('id')
|
159
|
+
end
|
171
160
|
|
172
|
-
|
173
|
-
|
174
|
-
|
161
|
+
it "allows valid parameters to be fetched en masse" do
|
162
|
+
@validator.add( :foom, /^\d+$/ )
|
163
|
+
@validator.add( :bewm, /^\d+$/ )
|
164
|
+
@validator.validate( 'foom' => "1", "bewm" => "2" )
|
165
|
+
@validator.values_at( :foom, :bewm ).should == [ '1', '2' ]
|
166
|
+
end
|
175
167
|
|
176
|
-
|
177
|
-
|
168
|
+
it "re-validates if profile is modified" do
|
169
|
+
@validator.add( :a_field, :string )
|
170
|
+
@validator.validate( 'a_field' => 'a string!' )
|
171
|
+
@validator.should_not have_errors()
|
172
|
+
@validator.should be_okay()
|
178
173
|
|
179
|
-
|
180
|
-
|
181
|
-
|
174
|
+
@validator.override( :a_field, :integer )
|
175
|
+
@validator.should have_errors()
|
176
|
+
@validator.should_not be_okay()
|
177
|
+
@validator.error_messages.should include( "Invalid value for 'A Field'" )
|
178
|
+
end
|
182
179
|
|
183
|
-
|
184
|
-
" both missing and invalid fields" do
|
185
|
-
@validator.add( :number, :integer )
|
186
|
-
@validator.add( :id, /^(\w{20})$/, :required )
|
180
|
+
end # describe "validation"
|
187
181
|
|
188
|
-
|
182
|
+
describe "validation error descriptions" do
|
189
183
|
|
190
|
-
|
191
|
-
|
184
|
+
it "can return human descriptions of validation errors" do
|
185
|
+
@validator.add( :number, :integer )
|
186
|
+
@validator.add( :id, /^(\w{20})$/, :required )
|
187
|
+
@validator.validate( 'number' => 'rhinoceros', 'unknown' => "1" )
|
192
188
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
189
|
+
@validator.error_messages.should have(2).members
|
190
|
+
@validator.error_messages.should include("Missing value for 'Id'")
|
191
|
+
@validator.error_messages.should include("Invalid value for 'Number'")
|
192
|
+
end
|
197
193
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
194
|
+
it "can include unknown fields in its human descriptions of validation errors" do
|
195
|
+
@validator.add( :number, :integer )
|
196
|
+
@validator.add( :id, /^(\w{20})$/, :required )
|
197
|
+
@validator.validate( 'number' => 'rhinoceros', 'unknown' => "1" )
|
202
198
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
199
|
+
@validator.error_messages(true).should have(3).members
|
200
|
+
@validator.error_messages(true).should include("Missing value for 'Id'")
|
201
|
+
@validator.error_messages(true).should include("Invalid value for 'Number'")
|
202
|
+
@validator.error_messages(true).should include("Unknown parameter 'Unknown'")
|
203
|
+
end
|
207
204
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
205
|
+
it "can use descriptions of parameters when constructing human validation error messages" do
|
206
|
+
@validator.add( :number, :integer, "Numeral" )
|
207
|
+
@validator.add( :id, /^(\w{20})$/, "Test Name", :required )
|
208
|
+
@validator.validate( 'number' => 'rhinoceros', 'unknown' => "1" )
|
212
209
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
end
|
210
|
+
@validator.error_messages.should have(2).members
|
211
|
+
@validator.error_messages.should include("Missing value for 'Test Name'")
|
212
|
+
@validator.error_messages.should include("Invalid value for 'Numeral'")
|
213
|
+
end
|
218
214
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
@validator.add( :id, /^(\w{20})$/, "Test Name", :required )
|
223
|
-
@validator.validate( 'number' => 'rhinoceros', 'unknown' => "1" )
|
215
|
+
it "can get and set the profile's descriptions directly" do
|
216
|
+
@validator.add( :number, :integer )
|
217
|
+
@validator.add( :id, /^(\w{20})$/, :required )
|
224
218
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
219
|
+
@validator.descriptions = {
|
220
|
+
number: 'Numeral',
|
221
|
+
id: 'Test Name'
|
222
|
+
}
|
223
|
+
@validator.validate( 'number' => 'rhinoceros', 'unknown' => "1" )
|
229
224
|
|
230
|
-
|
231
|
-
|
232
|
-
|
225
|
+
@validator.descriptions.should have( 2 ).members
|
226
|
+
@validator.error_messages.should have( 2 ).members
|
227
|
+
@validator.error_messages.should include("Missing value for 'Test Name'")
|
228
|
+
@validator.error_messages.should include("Invalid value for 'Numeral'")
|
229
|
+
end
|
233
230
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
}
|
238
|
-
@validator.validate( 'number' => 'rhinoceros', 'unknown' => "1" )
|
231
|
+
it "capitalizes the names of simple fields for descriptions" do
|
232
|
+
@validator.get_description( "required" ).should == 'Required'
|
233
|
+
end
|
239
234
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
@validator.error_messages.should include("Invalid value for 'Numeral'")
|
244
|
-
end
|
235
|
+
it "splits apart underbarred field names into capitalized words for descriptions" do
|
236
|
+
@validator.get_description( "rodent_size" ).should == 'Rodent Size'
|
237
|
+
end
|
245
238
|
|
246
|
-
|
247
|
-
|
248
|
-
|
239
|
+
it "uses the key for descriptions of hash fields" do
|
240
|
+
@validator.get_description( "rodent[size]" ).should == 'Size'
|
241
|
+
end
|
249
242
|
|
250
|
-
|
251
|
-
|
252
|
-
|
243
|
+
it "uses separate capitalized words for descriptions of hash fields with underbarred keys " do
|
244
|
+
@validator.get_description( "castle[baron_id]" ).should == 'Baron Id'
|
245
|
+
end
|
253
246
|
|
254
|
-
|
255
|
-
@validator.get_description( "rodent[size]" ).should == 'Size'
|
256
|
-
end
|
247
|
+
end # describe "validation error descriptions"
|
257
248
|
|
258
|
-
|
259
|
-
@validator.get_description( "castle[baron_id]" ).should == 'Baron Id'
|
260
|
-
end
|
249
|
+
describe "hash parameters" do
|
261
250
|
|
262
|
-
|
263
|
-
|
264
|
-
|
251
|
+
it "coalesces simple hash fields into a hash of validated values" do
|
252
|
+
@validator.add( 'rodent[size]', :string )
|
253
|
+
@validator.validate( 'rodent[size]' => 'unusual' )
|
265
254
|
|
266
|
-
|
267
|
-
|
255
|
+
@validator.valid.should == {'rodent' => {'size' => 'unusual'}}
|
256
|
+
end
|
257
|
+
|
258
|
+
it "coalesces complex hash fields into a nested hash of validated values" do
|
259
|
+
@validator.add( 'recipe[ingredient][name]', :string )
|
260
|
+
@validator.add( 'recipe[ingredient][cost]', :string )
|
261
|
+
@validator.add( 'recipe[yield]', :string )
|
268
262
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
args = {
|
275
|
-
'recipe[ingredient][name]' => 'nutmeg',
|
276
|
-
'recipe[ingredient][cost]' => '$0.18',
|
277
|
-
'recipe[yield]' => '2 loaves',
|
278
|
-
}
|
279
|
-
@validator.validate( args )
|
280
|
-
|
281
|
-
@validator.valid.should == {
|
282
|
-
'recipe' => {
|
283
|
-
'ingredient' => { 'name' => 'nutmeg', 'cost' => '$0.18' },
|
284
|
-
'yield' => '2 loaves'
|
263
|
+
args = {
|
264
|
+
'recipe[ingredient][name]' => 'nutmeg',
|
265
|
+
'recipe[ingredient][cost]' => '$0.18',
|
266
|
+
'recipe[yield]' => '2 loaves',
|
285
267
|
}
|
286
|
-
|
287
|
-
end
|
268
|
+
@validator.validate( args )
|
288
269
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
@validator.untaint_all_constraints
|
295
|
-
|
296
|
-
args = {
|
297
|
-
'recipe[ingredient][rarity]'.taint => 'super-rare'.taint,
|
298
|
-
'recipe[ingredient][name]'.taint => 'nutmeg'.taint,
|
299
|
-
'recipe[ingredient][cost]'.taint => '$0.18'.taint,
|
300
|
-
'recipe[yield]'.taint => '2 loaves'.taint,
|
301
|
-
}
|
302
|
-
@validator.validate( args )
|
303
|
-
|
304
|
-
@validator.valid.should == {
|
305
|
-
'recipe' => {
|
306
|
-
'ingredient' => { 'name' => 'nutmeg', 'cost' => '$0.18', 'rarity' => 'super-rare' },
|
307
|
-
'yield' => '2 loaves'
|
270
|
+
@validator.valid.should == {
|
271
|
+
'recipe' => {
|
272
|
+
'ingredient' => { 'name' => 'nutmeg', 'cost' => '$0.18' },
|
273
|
+
'yield' => '2 loaves'
|
274
|
+
}
|
308
275
|
}
|
309
|
-
|
310
|
-
|
311
|
-
@validator.valid.keys.all? {|key| key.should_not be_tainted() }
|
312
|
-
@validator.valid.values.all? {|key| key.should_not be_tainted() }
|
313
|
-
@validator.valid['recipe'].keys.all? {|key| key.should_not be_tainted() }
|
314
|
-
@validator.valid['recipe']['ingredient'].keys.all? {|key| key.should_not be_tainted() }
|
315
|
-
@validator.valid['recipe']['yield'].should_not be_tainted()
|
316
|
-
@validator.valid['recipe']['ingredient']['rarity'].should_not be_tainted()
|
317
|
-
@validator.valid['recipe']['ingredient']['name'].should_not be_tainted()
|
318
|
-
@validator.valid['recipe']['ingredient']['cost'].should_not be_tainted()
|
319
|
-
end
|
276
|
+
end
|
320
277
|
|
321
|
-
|
322
|
-
|
323
|
-
|
278
|
+
it "untaints both keys and values in complex hash fields if untainting is turned on" do
|
279
|
+
@validator.add( 'recipe[ingredient][rarity]', /^([\w\-]+)$/, :required )
|
280
|
+
@validator.add( 'recipe[ingredient][name]', :string )
|
281
|
+
@validator.add( 'recipe[ingredient][cost]', :string )
|
282
|
+
@validator.add( 'recipe[yield]', :string )
|
283
|
+
@validator.untaint_all_constraints
|
284
|
+
|
285
|
+
args = {
|
286
|
+
'recipe[ingredient][rarity]'.taint => 'super-rare'.taint,
|
287
|
+
'recipe[ingredient][name]'.taint => 'nutmeg'.taint,
|
288
|
+
'recipe[ingredient][cost]'.taint => '$0.18'.taint,
|
289
|
+
'recipe[yield]'.taint => '2 loaves'.taint,
|
290
|
+
}
|
291
|
+
@validator.validate( args )
|
324
292
|
|
325
|
-
|
326
|
-
|
293
|
+
@validator.valid.should == {
|
294
|
+
'recipe' => {
|
295
|
+
'ingredient' => { 'name' => 'nutmeg', 'cost' => '$0.18', 'rarity' => 'super-rare' },
|
296
|
+
'yield' => '2 loaves'
|
297
|
+
}
|
298
|
+
}
|
327
299
|
|
328
|
-
|
329
|
-
|
300
|
+
@validator.valid.keys.all? {|key| key.should_not be_tainted() }
|
301
|
+
@validator.valid.values.all? {|key| key.should_not be_tainted() }
|
302
|
+
@validator.valid['recipe'].keys.all? {|key| key.should_not be_tainted() }
|
303
|
+
@validator.valid['recipe']['ingredient'].keys.all? {|key| key.should_not be_tainted() }
|
304
|
+
@validator.valid['recipe']['yield'].should_not be_tainted()
|
305
|
+
@validator.valid['recipe']['ingredient']['rarity'].should_not be_tainted()
|
306
|
+
@validator.valid['recipe']['ingredient']['name'].should_not be_tainted()
|
307
|
+
@validator.valid['recipe']['ingredient']['cost'].should_not be_tainted()
|
308
|
+
end
|
330
309
|
|
331
|
-
|
332
|
-
@validator.add( :enabled, :boolean )
|
333
|
-
@validator.validate( 'enabled' => 't' )
|
310
|
+
end # describe "hash parameters"
|
334
311
|
|
335
|
-
|
336
|
-
@validator.should_not have_errors()
|
312
|
+
describe "constraints" do
|
337
313
|
|
338
|
-
|
339
|
-
|
314
|
+
it "treats ArgumentErrors in builtin constraints as validation failures" do
|
315
|
+
@validator.add( :integer )
|
316
|
+
@validator.validate( 'integer' => 'jalopy' )
|
317
|
+
@validator.should_not be_okay()
|
318
|
+
@validator.should have_errors()
|
319
|
+
@validator[:integer].should be_nil()
|
320
|
+
end
|
340
321
|
|
341
|
-
|
342
|
-
@validator.add( :enabled, :boolean )
|
343
|
-
@validator.validate( 'enabled' => 'yes' )
|
322
|
+
describe "Regexp constraints" do
|
344
323
|
|
345
|
-
|
346
|
-
|
324
|
+
it "returns the capture from a regexp constraint if it has only one" do
|
325
|
+
@validator.add( :treename, /(\w+)/ )
|
326
|
+
@validator.validate( 'treename' => " ygdrassil " )
|
327
|
+
@validator[:treename].should == 'ygdrassil'
|
328
|
+
end
|
347
329
|
|
348
|
-
|
349
|
-
|
330
|
+
it "returns the captures from a regexp constraint as an array if it has more than one" do
|
331
|
+
@validator.add( :stuff, /(\w+)(\S+)?/ )
|
332
|
+
@validator.validate( 'stuff' => " the1tree(!) " )
|
333
|
+
@validator[:stuff].should == ['the1tree', '(!)']
|
334
|
+
end
|
350
335
|
|
351
|
-
|
352
|
-
|
353
|
-
|
336
|
+
it "returns the captures from a regexp constraint with named captures as a Hash" do
|
337
|
+
@validator.add( :order_number, /(?<category>[[:upper:]]{3})-(?<sku>\d{12})/, :untaint )
|
338
|
+
@validator.validate( 'order_number' => " JVV-886451300133 ".taint )
|
354
339
|
|
355
|
-
|
356
|
-
|
340
|
+
@validator[:order_number].should == {:category => 'JVV', :sku => '886451300133'}
|
341
|
+
@validator[:order_number][:category].should_not be_tainted()
|
342
|
+
@validator[:order_number][:sku].should_not be_tainted()
|
343
|
+
end
|
357
344
|
|
358
|
-
|
359
|
-
|
345
|
+
it "returns the captures from a regexp constraint as an array " +
|
346
|
+
"even if an optional capture doesn't match anything" do
|
347
|
+
@validator.add( :amount, /^([\-+])?(\d+(?:\.\d+)?)/ )
|
348
|
+
@validator.validate( 'amount' => '2.28' )
|
360
349
|
|
361
|
-
|
362
|
-
|
363
|
-
@validator.validate( 'enabled' => '1' )
|
350
|
+
@validator[:amount].should == [ nil, '2.28' ]
|
351
|
+
end
|
364
352
|
|
365
|
-
|
366
|
-
@validator.should_not have_errors()
|
353
|
+
end
|
367
354
|
|
368
|
-
|
369
|
-
end
|
355
|
+
describe ":boolean constraints" do
|
370
356
|
|
371
|
-
|
372
|
-
|
373
|
-
|
357
|
+
before( :each ) do
|
358
|
+
@validator.add( :enabled, :boolean )
|
359
|
+
end
|
374
360
|
|
375
|
-
|
376
|
-
|
361
|
+
it "accepts the value 'true' for fields with boolean constraints" do
|
362
|
+
@validator.validate( 'enabled' => 'true' )
|
377
363
|
|
378
|
-
|
379
|
-
|
364
|
+
@validator.should be_okay()
|
365
|
+
@validator.should_not have_errors()
|
380
366
|
|
381
|
-
|
382
|
-
|
383
|
-
@validator.validate( 'enabled' => 'f' )
|
367
|
+
@validator[:enabled].should be_true()
|
368
|
+
end
|
384
369
|
|
385
|
-
|
386
|
-
|
370
|
+
it "accepts the value 't' for fields with boolean constraints" do
|
371
|
+
@validator.validate( 'enabled' => 't' )
|
387
372
|
|
388
|
-
|
389
|
-
|
373
|
+
@validator.should be_okay()
|
374
|
+
@validator.should_not have_errors()
|
390
375
|
|
391
|
-
|
392
|
-
|
393
|
-
@validator.validate( 'enabled' => 'no' )
|
376
|
+
@validator[:enabled].should be_true()
|
377
|
+
end
|
394
378
|
|
395
|
-
|
396
|
-
|
379
|
+
it "accepts the value 'yes' for fields with boolean constraints" do
|
380
|
+
@validator.validate( 'enabled' => 'yes' )
|
397
381
|
|
398
|
-
|
399
|
-
|
382
|
+
@validator.should be_okay()
|
383
|
+
@validator.should_not have_errors()
|
400
384
|
|
401
|
-
|
402
|
-
|
403
|
-
@validator.validate( 'enabled' => 'n' )
|
385
|
+
@validator[:enabled].should be_true()
|
386
|
+
end
|
404
387
|
|
405
|
-
|
406
|
-
|
388
|
+
it "accepts the value 'y' for fields with boolean constraints" do
|
389
|
+
@validator.validate( 'enabled' => 'y' )
|
407
390
|
|
408
|
-
|
409
|
-
|
391
|
+
@validator.should be_okay()
|
392
|
+
@validator.should_not have_errors()
|
410
393
|
|
411
|
-
|
412
|
-
|
413
|
-
@validator.validate( 'enabled' => '0' )
|
394
|
+
@validator[:enabled].should be_true()
|
395
|
+
end
|
414
396
|
|
415
|
-
|
416
|
-
|
397
|
+
it "accepts the value '1' for fields with boolean constraints" do
|
398
|
+
@validator.validate( 'enabled' => '1' )
|
417
399
|
|
418
|
-
|
419
|
-
|
400
|
+
@validator.should be_okay()
|
401
|
+
@validator.should_not have_errors()
|
420
402
|
|
421
|
-
|
422
|
-
|
423
|
-
@validator.validate( 'enabled' => 'peanut' )
|
403
|
+
@validator[:enabled].should be_true()
|
404
|
+
end
|
424
405
|
|
425
|
-
|
426
|
-
|
406
|
+
it "accepts the value 'false' for fields with boolean constraints" do
|
407
|
+
@validator.validate( 'enabled' => 'false' )
|
427
408
|
|
428
|
-
|
429
|
-
|
409
|
+
@validator.should be_okay()
|
410
|
+
@validator.should_not have_errors()
|
430
411
|
|
431
|
-
|
432
|
-
|
433
|
-
@validator.validate( 'count' => '11' )
|
412
|
+
@validator[:enabled].should be_false()
|
413
|
+
end
|
434
414
|
|
435
|
-
|
436
|
-
|
415
|
+
it "accepts the value 'f' for fields with boolean constraints" do
|
416
|
+
@validator.validate( 'enabled' => 'f' )
|
437
417
|
|
438
|
-
|
439
|
-
|
418
|
+
@validator.should be_okay()
|
419
|
+
@validator.should_not have_errors()
|
440
420
|
|
441
|
-
|
442
|
-
|
443
|
-
@validator.validate( 'count' => '0' )
|
421
|
+
@validator[:enabled].should be_false()
|
422
|
+
end
|
444
423
|
|
445
|
-
|
446
|
-
|
424
|
+
it "accepts the value 'no' for fields with boolean constraints" do
|
425
|
+
@validator.validate( 'enabled' => 'no' )
|
447
426
|
|
448
|
-
|
449
|
-
|
427
|
+
@validator.should be_okay()
|
428
|
+
@validator.should_not have_errors()
|
450
429
|
|
451
|
-
|
452
|
-
|
453
|
-
@validator.validate( 'count' => '-407' )
|
430
|
+
@validator[:enabled].should be_false()
|
431
|
+
end
|
454
432
|
|
455
|
-
|
456
|
-
|
433
|
+
it "accepts the value 'n' for fields with boolean constraints" do
|
434
|
+
@validator.validate( 'enabled' => 'n' )
|
457
435
|
|
458
|
-
|
459
|
-
|
436
|
+
@validator.should be_okay()
|
437
|
+
@validator.should_not have_errors()
|
460
438
|
|
461
|
-
|
462
|
-
|
463
|
-
@validator.validate( 'count' => '11.1' )
|
439
|
+
@validator[:enabled].should be_false()
|
440
|
+
end
|
464
441
|
|
465
|
-
|
466
|
-
|
442
|
+
it "accepts the value '0' for fields with boolean constraints" do
|
443
|
+
@validator.validate( 'enabled' => '0' )
|
467
444
|
|
468
|
-
|
469
|
-
|
445
|
+
@validator.should be_okay()
|
446
|
+
@validator.should_not have_errors()
|
470
447
|
|
471
|
-
|
472
|
-
|
473
|
-
@validator.validate( 'count' => '88licks' )
|
448
|
+
@validator[:enabled].should be_false()
|
449
|
+
end
|
474
450
|
|
475
|
-
|
476
|
-
|
451
|
+
it "rejects non-boolean parameters for fields with boolean constraints" do
|
452
|
+
@validator.validate( 'enabled' => 'peanut' )
|
477
453
|
|
478
|
-
|
479
|
-
|
454
|
+
@validator.should_not be_okay()
|
455
|
+
@validator.should have_errors()
|
480
456
|
|
481
|
-
|
482
|
-
|
483
|
-
@validator.validate( 'amount' => '3.14' )
|
457
|
+
@validator[:enabled].should be_nil()
|
458
|
+
end
|
484
459
|
|
485
|
-
|
486
|
-
@validator.should_not have_errors()
|
460
|
+
end
|
487
461
|
|
488
|
-
|
489
|
-
end
|
462
|
+
describe ":integer constraints" do
|
490
463
|
|
491
|
-
|
492
|
-
|
493
|
-
|
464
|
+
it "accepts simple integers for fields with integer constraints" do
|
465
|
+
@validator.add( :count, :integer )
|
466
|
+
@validator.validate( 'count' => '11' )
|
494
467
|
|
495
|
-
|
496
|
-
|
468
|
+
@validator.should be_okay()
|
469
|
+
@validator.should_not have_errors()
|
497
470
|
|
498
|
-
|
499
|
-
|
471
|
+
@validator[:count].should == 11
|
472
|
+
end
|
500
473
|
|
501
|
-
|
502
|
-
|
503
|
-
|
474
|
+
it "accepts '0' for fields with integer constraints" do
|
475
|
+
@validator.add( :count, :integer )
|
476
|
+
@validator.validate( 'count' => '0' )
|
504
477
|
|
505
|
-
|
506
|
-
|
478
|
+
@validator.should be_okay()
|
479
|
+
@validator.should_not have_errors()
|
507
480
|
|
508
|
-
|
509
|
-
|
481
|
+
@validator[:count].should == 0
|
482
|
+
end
|
510
483
|
|
511
|
-
|
512
|
-
|
513
|
-
|
484
|
+
it "accepts negative integers for fields with integer constraints" do
|
485
|
+
@validator.add( :count, :integer )
|
486
|
+
@validator.validate( 'count' => '-407' )
|
514
487
|
|
515
|
-
|
516
|
-
|
488
|
+
@validator.should be_okay()
|
489
|
+
@validator.should_not have_errors()
|
517
490
|
|
518
|
-
|
519
|
-
|
491
|
+
@validator[:count].should == -407
|
492
|
+
end
|
520
493
|
|
521
|
-
|
522
|
-
|
523
|
-
|
494
|
+
it "rejects non-integers for fields with integer constraints" do
|
495
|
+
@validator.add( :count, :integer )
|
496
|
+
@validator.validate( 'count' => '11.1' )
|
524
497
|
|
525
|
-
|
526
|
-
|
498
|
+
@validator.should_not be_okay()
|
499
|
+
@validator.should have_errors()
|
527
500
|
|
528
|
-
|
529
|
-
|
501
|
+
@validator[:count].should be_nil()
|
502
|
+
end
|
530
503
|
|
531
|
-
|
532
|
-
|
533
|
-
|
504
|
+
it "rejects integer values with other cruft in them for fields with integer constraints" do
|
505
|
+
@validator.add( :count, :integer )
|
506
|
+
@validator.validate( 'count' => '88licks' )
|
534
507
|
|
535
|
-
|
536
|
-
|
508
|
+
@validator.should_not be_okay()
|
509
|
+
@validator.should have_errors()
|
537
510
|
|
538
|
-
|
539
|
-
|
511
|
+
@validator[:count].should be_nil()
|
512
|
+
end
|
540
513
|
|
541
|
-
|
542
|
-
@validator.add( :amount, :float )
|
543
|
-
@validator.validate( 'amount' => '1756e-5' )
|
514
|
+
end
|
544
515
|
|
545
|
-
|
546
|
-
@validator.should_not have_errors()
|
516
|
+
describe ":float constraints" do
|
547
517
|
|
548
|
-
|
549
|
-
|
518
|
+
before( :each ) do
|
519
|
+
@validator.add( :amount, :float )
|
520
|
+
end
|
550
521
|
|
551
|
-
|
552
|
-
|
553
|
-
@validator.validate( 'amount' => '-28e8' )
|
522
|
+
it "accepts simple floats for fields with float constraints" do
|
523
|
+
@validator.validate( 'amount' => '3.14' )
|
554
524
|
|
555
|
-
|
556
|
-
|
525
|
+
@validator.should be_okay()
|
526
|
+
@validator.should_not have_errors()
|
557
527
|
|
558
|
-
|
559
|
-
|
528
|
+
@validator[:amount].should == 3.14
|
529
|
+
end
|
560
530
|
|
561
|
-
|
562
|
-
|
563
|
-
@validator.add( :amount, :float )
|
564
|
-
@validator.validate( 'amount' => '.5552e-10' )
|
531
|
+
it "accepts negative floats for fields with float constraints" do
|
532
|
+
@validator.validate( 'amount' => '-3.14' )
|
565
533
|
|
566
|
-
|
567
|
-
|
534
|
+
@validator.should be_okay()
|
535
|
+
@validator.should_not have_errors()
|
568
536
|
|
569
|
-
|
570
|
-
|
537
|
+
@validator[:amount].should == -3.14
|
538
|
+
end
|
571
539
|
|
572
|
-
|
573
|
-
|
574
|
-
@validator.add( :amount, :float )
|
575
|
-
@validator.validate( 'amount' => '-.288088e18' )
|
540
|
+
it "accepts positive floats for fields with float constraints" do
|
541
|
+
@validator.validate( 'amount' => '+3.14' )
|
576
542
|
|
577
|
-
|
578
|
-
|
543
|
+
@validator.should be_okay()
|
544
|
+
@validator.should_not have_errors()
|
579
545
|
|
580
|
-
|
581
|
-
|
546
|
+
@validator[:amount].should == 3.14
|
547
|
+
end
|
582
548
|
|
583
|
-
|
584
|
-
|
585
|
-
@validator.validate( 'amount' => '288' )
|
549
|
+
it "accepts floats that begin with '.' for fields with float constraints" do
|
550
|
+
@validator.validate( 'amount' => '.1418' )
|
586
551
|
|
587
|
-
|
588
|
-
|
552
|
+
@validator.should be_okay()
|
553
|
+
@validator.should_not have_errors()
|
589
554
|
|
590
|
-
|
591
|
-
|
555
|
+
@validator[:amount].should == 0.1418
|
556
|
+
end
|
592
557
|
|
593
|
-
|
594
|
-
|
595
|
-
@validator.validate( 'amount' => '-1606' )
|
558
|
+
it "accepts negative floats that begin with '.' for fields with float constraints" do
|
559
|
+
@validator.validate( 'amount' => '-.171' )
|
596
560
|
|
597
|
-
|
598
|
-
|
561
|
+
@validator.should be_okay()
|
562
|
+
@validator.should_not have_errors()
|
599
563
|
|
600
|
-
|
601
|
-
|
564
|
+
@validator[:amount].should == -0.171
|
565
|
+
end
|
602
566
|
|
603
|
-
|
604
|
-
|
605
|
-
@validator.validate( 'amount' => '2600' )
|
567
|
+
it "accepts positive floats that begin with '.' for fields with float constraints" do
|
568
|
+
@validator.validate( 'amount' => '+.86668001' )
|
606
569
|
|
607
|
-
|
608
|
-
|
570
|
+
@validator.should be_okay()
|
571
|
+
@validator.should_not have_errors()
|
609
572
|
|
610
|
-
|
611
|
-
|
573
|
+
@validator[:amount].should == 0.86668001
|
574
|
+
end
|
612
575
|
|
576
|
+
it "accepts floats in exponential notation for fields with float constraints" do
|
577
|
+
@validator.validate( 'amount' => '1756e-5' )
|
613
578
|
|
614
|
-
|
615
|
-
|
616
|
-
@validator.validate( 'expires' => '2008-11-18' )
|
579
|
+
@validator.should be_okay()
|
580
|
+
@validator.should_not have_errors()
|
617
581
|
|
618
|
-
|
619
|
-
|
582
|
+
@validator[:amount].should == 1756e-5
|
583
|
+
end
|
620
584
|
|
621
|
-
|
622
|
-
|
585
|
+
it "accepts negative floats in exponential notation for fields with float constraints" do
|
586
|
+
@validator.validate( 'amount' => '-28e8' )
|
623
587
|
|
588
|
+
@validator.should be_okay()
|
589
|
+
@validator.should_not have_errors()
|
624
590
|
|
625
|
-
|
626
|
-
|
627
|
-
http://127.0.0.1/
|
628
|
-
http://[127.0.0.1]/
|
629
|
-
http://ruby-lang.org/
|
630
|
-
http://www.rocketboom.com/vlog/rb_08_feb_01
|
631
|
-
http://del.icio.us/search/?fr=del_icio_us&p=ruby+arrow&type=all
|
632
|
-
http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:8080/index.html
|
633
|
-
http://[1080:0:0:0:8:800:200C:417A]/index.html
|
634
|
-
http://[3ffe:2a00:100:7031::1]
|
635
|
-
http://[1080::8:800:200C:417A]/foo
|
636
|
-
http://[::192.9.5.5]/ipng
|
637
|
-
http://[::FFFF:129.144.52.38]:3474/index.html
|
638
|
-
http://[2010:836B:4179::836B:4179]
|
639
|
-
|
640
|
-
https://mail.google.com/
|
641
|
-
https://127.0.0.1/
|
642
|
-
https://r4.com:8080/
|
643
|
-
|
644
|
-
ftp://ftp.ruby-lang.org/pub/ruby/1.0/ruby-0.49.tar.gz
|
645
|
-
ftp://crashoverride:god@gibson.ellingsonmineral.com/root/.workspace/.garbage.
|
646
|
-
|
647
|
-
ldap:/o=University%20of%20Michigan,c=US
|
648
|
-
ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US
|
649
|
-
ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress
|
650
|
-
ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)
|
651
|
-
ldap://ldap.itd.umich.edu/c=GB?objectClass?one
|
652
|
-
ldap://ldap.question.com/o=Question%3f,c=US?mail
|
653
|
-
ldap://ldap.netscape.com/o=Babsco,c=US??(int=%5c00%5c00%5c00%5c04)
|
654
|
-
ldap:/??sub??bindname=cn=Manager%2co=Foo
|
655
|
-
ldap:/??sub??!bindname=cn=Manager%2co=Foo
|
656
|
-
}
|
657
|
-
|
658
|
-
VALID_URIS.each do |uri_string|
|
659
|
-
it "accepts #{uri_string} for fields with URI constraints" do
|
660
|
-
@validator.add( :homepage, :uri )
|
661
|
-
@validator.validate( 'homepage' => uri_string )
|
591
|
+
@validator[:amount].should == -28e8
|
592
|
+
end
|
662
593
|
|
663
|
-
|
664
|
-
|
594
|
+
it "accepts floats that start with '.' in exponential notation for fields with float " +
|
595
|
+
"constraints" do
|
596
|
+
@validator.validate( 'amount' => '.5552e-10' )
|
597
|
+
|
598
|
+
@validator.should be_okay()
|
599
|
+
@validator.should_not have_errors()
|
600
|
+
|
601
|
+
@validator[:amount].should == 0.5552e-10
|
602
|
+
end
|
603
|
+
|
604
|
+
it "accepts negative floats that start with '.' in exponential notation for fields with " +
|
605
|
+
"float constraints" do
|
606
|
+
@validator.validate( 'amount' => '-.288088e18' )
|
607
|
+
|
608
|
+
@validator.should be_okay()
|
609
|
+
@validator.should_not have_errors()
|
610
|
+
|
611
|
+
@validator[:amount].should == -0.288088e18
|
612
|
+
end
|
613
|
+
|
614
|
+
it "accepts integers for fields with float constraints" do
|
615
|
+
@validator.validate( 'amount' => '288' )
|
616
|
+
|
617
|
+
@validator.should be_okay()
|
618
|
+
@validator.should_not have_errors()
|
619
|
+
|
620
|
+
@validator[:amount].should == 288.0
|
621
|
+
end
|
622
|
+
|
623
|
+
it "accepts negative integers for fields with float constraints" do
|
624
|
+
@validator.validate( 'amount' => '-1606' )
|
625
|
+
|
626
|
+
@validator.should be_okay()
|
627
|
+
@validator.should_not have_errors()
|
628
|
+
|
629
|
+
@validator[:amount].should == -1606.0
|
630
|
+
end
|
631
|
+
|
632
|
+
it "accepts positive integers for fields with float constraints" do
|
633
|
+
@validator.validate( 'amount' => '2600' )
|
634
|
+
|
635
|
+
@validator.should be_okay()
|
636
|
+
@validator.should_not have_errors()
|
637
|
+
|
638
|
+
@validator[:amount].should == 2600.0
|
639
|
+
end
|
665
640
|
|
666
|
-
@validator[:homepage].should be_a_kind_of( URI::Generic )
|
667
|
-
@validator[:homepage].to_s.should == uri_string
|
668
641
|
end
|
669
|
-
end
|
670
642
|
|
671
|
-
|
672
|
-
# be invalidly-occurring in the wild
|
673
|
-
INVALID_URIS = %W{
|
674
|
-
glark:
|
675
|
-
|
676
|
-
http:
|
677
|
-
http://
|
678
|
-
http://_com/vlog/rb_08_feb_01
|
679
|
-
http://del.icio.us/search/\x20\x14\x18
|
680
|
-
http://FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/index.html
|
681
|
-
http://1080:0:0:0:8:800:200C:417A/index.html
|
682
|
-
http://3ffe:2a00:100:7031::1
|
683
|
-
http://1080::8:800:200C:417A/foo
|
684
|
-
http://::192.9.5.5/ipng
|
685
|
-
http://::FFFF:129.144.52.38:80/index.html
|
686
|
-
http://2010:836B:4179::836B:4179
|
687
|
-
|
688
|
-
https:
|
689
|
-
https://user:pass@/
|
690
|
-
https://r4.com:nonnumericport/
|
691
|
-
|
692
|
-
ftp:
|
693
|
-
ftp:ruby-0.49.tar.gz
|
694
|
-
ftp://crashoverride:god@/root/.workspace/.garbage.
|
695
|
-
|
696
|
-
ldap:
|
697
|
-
ldap:/o=University\x20of\x20Michigan,c=US
|
698
|
-
ldap://ldap.itd.umich.edu/o=University+\x00of+Michigan
|
699
|
-
}
|
700
|
-
|
701
|
-
INVALID_URIS.each do |uri_string|
|
702
|
-
it "rejects #{uri_string} for fields with URI constraints" do
|
703
|
-
@validator.add( :homepage, :uri )
|
704
|
-
@validator.validate( 'homepage' => uri_string )
|
643
|
+
describe ":date constaints" do
|
705
644
|
|
706
|
-
|
707
|
-
|
645
|
+
before( :each ) do
|
646
|
+
@validator.add( :expires, :date )
|
647
|
+
end
|
648
|
+
|
649
|
+
it "accepts dates for fields with date constraints" do
|
650
|
+
@validator.validate( 'expires' => '2008-11-18' )
|
651
|
+
|
652
|
+
@validator.should be_okay()
|
653
|
+
@validator.should_not have_errors()
|
654
|
+
|
655
|
+
@validator[:expires].should == Date.parse( '2008-11-18' )
|
656
|
+
end
|
657
|
+
|
658
|
+
it "rejects non-dates for fields with date constraints" do
|
659
|
+
@validator.validate( 'expires' => 'Mexico' )
|
660
|
+
|
661
|
+
@validator.should_not be_okay()
|
662
|
+
@validator.should have_errors()
|
663
|
+
|
664
|
+
@validator[:expires].should be_nil()
|
665
|
+
end
|
708
666
|
|
709
|
-
@validator[:homepage].should be_nil()
|
710
667
|
end
|
711
|
-
end
|
712
668
|
|
713
|
-
|
714
|
-
|
715
|
-
|
669
|
+
describe ":uri constraints" do
|
670
|
+
VALID_URIS = %w{
|
671
|
+
http://127.0.0.1
|
672
|
+
http://127.0.0.1/
|
673
|
+
http://[127.0.0.1]/
|
674
|
+
http://ruby-lang.org/
|
675
|
+
http://www.rocketboom.com/vlog/rb_08_feb_01
|
676
|
+
http://del.icio.us/search/?fr=del_icio_us&p=ruby+arrow&type=all
|
677
|
+
http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:8080/index.html
|
678
|
+
http://[1080:0:0:0:8:800:200C:417A]/index.html
|
679
|
+
http://[3ffe:2a00:100:7031::1]
|
680
|
+
http://[1080::8:800:200C:417A]/foo
|
681
|
+
http://[::192.9.5.5]/ipng
|
682
|
+
http://[::FFFF:129.144.52.38]:3474/index.html
|
683
|
+
http://[2010:836B:4179::836B:4179]
|
684
|
+
|
685
|
+
https://mail.google.com/
|
686
|
+
https://127.0.0.1/
|
687
|
+
https://r4.com:8080/
|
688
|
+
|
689
|
+
ftp://ftp.ruby-lang.org/pub/ruby/1.0/ruby-0.49.tar.gz
|
690
|
+
ftp://crashoverride:god@gibson.ellingsonmineral.com/root/.workspace/.garbage.
|
691
|
+
|
692
|
+
ldap:/o=University%20of%20Michigan,c=US
|
693
|
+
ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US
|
694
|
+
ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress
|
695
|
+
ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)
|
696
|
+
ldap://ldap.itd.umich.edu/c=GB?objectClass?one
|
697
|
+
ldap://ldap.question.com/o=Question%3f,c=US?mail
|
698
|
+
ldap://ldap.netscape.com/o=Babsco,c=US??(int=%5c00%5c00%5c00%5c04)
|
699
|
+
ldap:/??sub??bindname=cn=Manager%2co=Foo
|
700
|
+
ldap:/??sub??!bindname=cn=Manager%2co=Foo
|
701
|
+
}
|
716
702
|
|
717
|
-
|
718
|
-
|
703
|
+
INVALID_URIS = %W{
|
704
|
+
glark:
|
705
|
+
|
706
|
+
http:
|
707
|
+
http://
|
708
|
+
http://_com/vlog/rb_08_feb_01
|
709
|
+
http://del.icio.us/search/\x20\x14\x18
|
710
|
+
http://FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/index.html
|
711
|
+
http://1080:0:0:0:8:800:200C:417A/index.html
|
712
|
+
http://3ffe:2a00:100:7031::1
|
713
|
+
http://1080::8:800:200C:417A/foo
|
714
|
+
http://::192.9.5.5/ipng
|
715
|
+
http://::FFFF:129.144.52.38:80/index.html
|
716
|
+
http://2010:836B:4179::836B:4179
|
717
|
+
|
718
|
+
https:
|
719
|
+
https://user:pass@/
|
720
|
+
https://r4.com:nonnumericport/
|
721
|
+
|
722
|
+
ftp:
|
723
|
+
ftp:ruby-0.49.tar.gz
|
724
|
+
ftp://crashoverride:god@/root/.workspace/.garbage.
|
725
|
+
|
726
|
+
ldap:
|
727
|
+
ldap:/o=University\x20of\x20Michigan,c=US
|
728
|
+
ldap://ldap.itd.umich.edu/o=University+\x00of+Michigan
|
729
|
+
}
|
719
730
|
|
720
|
-
|
721
|
-
|
731
|
+
before( :each ) do
|
732
|
+
@validator.add( :homepage, :uri )
|
733
|
+
end
|
722
734
|
|
723
|
-
|
724
|
-
|
725
|
-
|
735
|
+
VALID_URIS.each do |uri_string|
|
736
|
+
it "accepts #{uri_string} for fields with URI constraints" do
|
737
|
+
@validator.validate( 'homepage' => uri_string )
|
726
738
|
|
727
|
-
|
728
|
-
|
739
|
+
@validator.should be_okay()
|
740
|
+
@validator.should_not have_errors()
|
729
741
|
|
730
|
-
|
731
|
-
|
742
|
+
@validator[:homepage].should be_a_kind_of( URI::Generic )
|
743
|
+
@validator[:homepage].to_s.should == uri_string
|
744
|
+
end
|
745
|
+
end
|
732
746
|
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
'jrandom@[ruby hacquer].com',
|
737
|
-
'abcdefghijklmnopqrstuvwxyz@abcdefghijklmnopqrstuvwxyz',
|
738
|
-
]
|
739
|
-
COMPLEX_ADDRESSES.each do |addy|
|
740
|
-
it "accepts #{addy} for fields with email constraints" do
|
741
|
-
@validator.add( :mail, :email )
|
742
|
-
@validator.validate( 'mail' => addy )
|
747
|
+
INVALID_URIS.each do |uri_string|
|
748
|
+
it "rejects #{uri_string} for fields with URI constraints" do
|
749
|
+
@validator.validate( 'homepage' => uri_string )
|
743
750
|
|
744
|
-
|
745
|
-
|
751
|
+
@validator.should_not be_okay()
|
752
|
+
@validator.should have_errors()
|
753
|
+
|
754
|
+
@validator[:homepage].should be_nil()
|
755
|
+
end
|
756
|
+
end
|
746
757
|
|
747
|
-
@validator[:mail].should == addy
|
748
758
|
end
|
749
|
-
end
|
750
759
|
|
760
|
+
describe ":email constraints" do
|
751
761
|
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
762
|
+
COMPLEX_ADDRESSES = [
|
763
|
+
'ruby+hacker@random-example.org',
|
764
|
+
'"ruby hacker"@ph8675309.org',
|
765
|
+
'jrandom@[ruby hacquer].com',
|
766
|
+
'abcdefghijklmnopqrstuvwxyz@abcdefghijklmnopqrstuvwxyz',
|
767
|
+
]
|
768
|
+
BOGUS_ADDRESSES = [
|
769
|
+
'jrandom@hacquer com',
|
770
|
+
'jrandom@ruby hacquer.com',
|
771
|
+
'j random@rubyhacquer.com',
|
772
|
+
'j random@ruby|hacquer.com',
|
773
|
+
'j:random@rubyhacquer.com',
|
774
|
+
]
|
763
775
|
|
764
|
-
|
765
|
-
|
776
|
+
it "accepts simple RFC822 addresses for fields with email constraints" do
|
777
|
+
@validator.add( :email )
|
778
|
+
@validator.validate( 'email' => 'jrandom@hacker.ie' )
|
779
|
+
|
780
|
+
@validator.should be_okay()
|
781
|
+
@validator.should_not have_errors()
|
782
|
+
|
783
|
+
@validator[:email].should == 'jrandom@hacker.ie'
|
784
|
+
end
|
785
|
+
|
786
|
+
it "accepts hyphenated domains in RFC822 addresses for fields with email constraints" do
|
787
|
+
@validator.add( :email )
|
788
|
+
@validator.validate( 'email' => 'jrandom@just-another-hacquer.fr' )
|
789
|
+
|
790
|
+
@validator.should be_okay()
|
791
|
+
@validator.should_not have_errors()
|
792
|
+
|
793
|
+
@validator[:email].should == 'jrandom@just-another-hacquer.fr'
|
794
|
+
end
|
795
|
+
|
796
|
+
COMPLEX_ADDRESSES.each do |addy|
|
797
|
+
it "accepts #{addy} for fields with email constraints" do
|
798
|
+
@validator.add( :mail, :email )
|
799
|
+
@validator.validate( 'mail' => addy )
|
800
|
+
|
801
|
+
@validator.should be_okay()
|
802
|
+
@validator.should_not have_errors()
|
803
|
+
|
804
|
+
@validator[:mail].should == addy
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
808
|
+
BOGUS_ADDRESSES.each do |addy|
|
809
|
+
it "rejects #{addy} for fields with email constraints" do
|
810
|
+
@validator.add( :mail, :email )
|
811
|
+
@validator.validate( 'mail' => addy )
|
812
|
+
|
813
|
+
@validator.should_not be_okay()
|
814
|
+
@validator.should have_errors()
|
815
|
+
|
816
|
+
@validator[:mail].should be_nil()
|
817
|
+
end
|
818
|
+
end
|
766
819
|
|
767
|
-
@validator[:mail].should be_nil()
|
768
820
|
end
|
769
|
-
end
|
770
821
|
|
771
|
-
|
772
|
-
@validator.add( :host, :hostname )
|
773
|
-
@validator.validate( 'host' => 'deveiate.org' )
|
822
|
+
describe ":hostname constraints" do
|
774
823
|
|
775
|
-
|
776
|
-
|
824
|
+
BOGUS_HOSTS = [
|
825
|
+
'.',
|
826
|
+
'glah ',
|
827
|
+
'glah[lock]',
|
828
|
+
'glah.be$',
|
829
|
+
'indus«tree».com',
|
830
|
+
]
|
777
831
|
|
778
|
-
|
779
|
-
|
832
|
+
it "accepts simple hostnames for fields with hostname constraints" do
|
833
|
+
@validator.add( :host, :hostname )
|
834
|
+
@validator.validate( 'host' => 'deveiate.org' )
|
780
835
|
|
781
|
-
|
782
|
-
|
783
|
-
@validator.validate( 'hostname' => 'your-characters-can-fly.kr' )
|
836
|
+
@validator.should be_okay()
|
837
|
+
@validator.should_not have_errors()
|
784
838
|
|
785
|
-
|
786
|
-
|
839
|
+
@validator[:host].should == 'deveiate.org'
|
840
|
+
end
|
787
841
|
|
788
|
-
|
789
|
-
|
842
|
+
it "accepts hyphenated hostnames for fields with hostname constraints" do
|
843
|
+
@validator.add( :hostname )
|
844
|
+
@validator.validate( 'hostname' => 'your-characters-can-fly.kr' )
|
790
845
|
|
791
|
-
|
792
|
-
|
793
|
-
'glah ',
|
794
|
-
'glah[lock]',
|
795
|
-
'glah.be$',
|
796
|
-
'indus«tree».com',
|
797
|
-
]
|
846
|
+
@validator.should be_okay()
|
847
|
+
@validator.should_not have_errors()
|
798
848
|
|
799
|
-
|
800
|
-
|
801
|
-
@validator.add( :hostname )
|
802
|
-
@validator.validate( 'hostname' => hostname )
|
849
|
+
@validator[:hostname].should == 'your-characters-can-fly.kr'
|
850
|
+
end
|
803
851
|
|
804
|
-
|
805
|
-
|
852
|
+
BOGUS_HOSTS.each do |hostname|
|
853
|
+
it "rejects #{hostname} for fields with :hostname constraints" do
|
854
|
+
@validator.add( :hostname )
|
855
|
+
@validator.validate( 'hostname' => hostname )
|
856
|
+
|
857
|
+
@validator.should_not be_okay()
|
858
|
+
@validator.should have_errors()
|
859
|
+
|
860
|
+
@validator[:hostname].should be_nil()
|
861
|
+
end
|
862
|
+
end
|
806
863
|
|
807
|
-
@validator[:hostname].should be_nil()
|
808
864
|
end
|
809
|
-
end
|
810
865
|
|
811
|
-
|
812
|
-
@validator.add( :alpha )
|
813
|
-
@validator.validate( 'alpha' => 'abelincoln' )
|
866
|
+
describe ":alpha constraints" do
|
814
867
|
|
815
|
-
|
816
|
-
|
868
|
+
it "accepts alpha characters for fields with alpha constraints" do
|
869
|
+
@validator.add( :alpha )
|
870
|
+
@validator.validate( 'alpha' => 'abelincoln' )
|
817
871
|
|
818
|
-
|
819
|
-
|
872
|
+
@validator.should be_okay()
|
873
|
+
@validator.should_not have_errors()
|
820
874
|
|
821
|
-
|
822
|
-
|
823
|
-
@validator.validate( 'alpha' => 'duck45' )
|
875
|
+
@validator[:alpha].should == 'abelincoln'
|
876
|
+
end
|
824
877
|
|
825
|
-
|
826
|
-
|
878
|
+
it "rejects non-alpha characters for fields with alpha constraints" do
|
879
|
+
@validator.add( :alpha )
|
880
|
+
@validator.validate( 'alpha' => 'duck45' )
|
827
881
|
|
828
|
-
|
829
|
-
|
882
|
+
@validator.should_not be_okay()
|
883
|
+
@validator.should have_errors()
|
830
884
|
|
831
|
-
|
832
|
-
|
833
|
-
@validator.add( :username, :alphanumeric )
|
834
|
-
@validator.validate( 'username' => 'zombieabe11' )
|
885
|
+
@validator[:alpha].should be_nil()
|
886
|
+
end
|
835
887
|
|
836
|
-
|
837
|
-
@validator.should_not have_errors()
|
888
|
+
end
|
838
889
|
|
839
|
-
|
840
|
-
end
|
890
|
+
describe ":alphanumeric constraints" do
|
841
891
|
|
842
|
-
|
843
|
-
|
844
|
-
|
892
|
+
it "accepts alphanumeric characters for fields with alphanumeric constraints" do
|
893
|
+
@validator.add( :username, :alphanumeric )
|
894
|
+
@validator.validate( 'username' => 'zombieabe11' )
|
845
895
|
|
846
|
-
|
847
|
-
|
896
|
+
@validator.should be_okay()
|
897
|
+
@validator.should_not have_errors()
|
848
898
|
|
849
|
-
|
850
|
-
|
899
|
+
@validator[:username].should == 'zombieabe11'
|
900
|
+
end
|
851
901
|
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
I saw you with some kind of medical apparatus strapped to your
|
856
|
-
spine. It was all glass and metal, a great crystaline hypodermic
|
857
|
-
spider, carrying you into the aether with a humming, crackling sound.
|
858
|
-
EOF
|
902
|
+
it "rejects non-alphanumeric characters for fields with alphanumeric constraints" do
|
903
|
+
@validator.add( :username, :alphanumeric )
|
904
|
+
@validator.validate( 'username' => 'duck!ling' )
|
859
905
|
|
860
|
-
|
861
|
-
|
906
|
+
@validator.should_not be_okay()
|
907
|
+
@validator.should have_errors()
|
862
908
|
|
863
|
-
|
864
|
-
|
865
|
-
end
|
909
|
+
@validator[:username].should be_nil()
|
910
|
+
end
|
866
911
|
|
867
|
-
|
868
|
-
@validator.add( :prologue, :printable )
|
869
|
-
@validator.validate( 'prologue' => %{\0Something cold\0} )
|
912
|
+
end
|
870
913
|
|
871
|
-
|
872
|
-
@validator.should have_errors()
|
914
|
+
describe ":printable constraints" do
|
873
915
|
|
874
|
-
|
875
|
-
|
916
|
+
it "accepts printable characters for fields with 'printable' constraints" do
|
917
|
+
test_content = <<-EOF
|
918
|
+
I saw you with some kind of medical apparatus strapped to your
|
919
|
+
spine. It was all glass and metal, a great crystaline hypodermic
|
920
|
+
spider, carrying you into the aether with a humming, crackling sound.
|
921
|
+
EOF
|
876
922
|
|
923
|
+
@validator.add( :prologue, :printable )
|
924
|
+
@validator.validate( 'prologue' => test_content )
|
877
925
|
|
878
|
-
|
879
|
-
|
880
|
-
|
926
|
+
@validator.should be_okay()
|
927
|
+
@validator[:prologue].should == test_content
|
928
|
+
end
|
881
929
|
|
882
|
-
|
883
|
-
|
930
|
+
it "rejects non-printable characters for fields with 'printable' constraints" do
|
931
|
+
@validator.add( :prologue, :printable )
|
932
|
+
@validator.validate( 'prologue' => %{\0Something cold\0} )
|
884
933
|
|
885
|
-
|
886
|
-
|
934
|
+
@validator.should_not be_okay()
|
935
|
+
@validator.should have_errors()
|
887
936
|
|
888
|
-
|
889
|
-
|
937
|
+
@validator[:prologue].should be_nil()
|
938
|
+
end
|
890
939
|
|
891
|
-
@validator.add( :creation_date ) do |input|
|
892
|
-
Date.parse( input )
|
893
940
|
end
|
894
|
-
@validator.validate( 'creation_date' => test_date )
|
895
941
|
|
896
|
-
|
897
|
-
@validator.should_not have_errors()
|
942
|
+
describe ":word constraints" do
|
898
943
|
|
899
|
-
|
900
|
-
|
944
|
+
it "accepts any word characters for fields with 'word' constraints" do
|
945
|
+
@validator.add( :vocab_word, :word )
|
946
|
+
@validator.validate( 'vocab_word' => "Собака" )
|
947
|
+
|
948
|
+
@validator.should_not have_errors()
|
949
|
+
@validator.should be_okay()
|
950
|
+
|
951
|
+
@validator[:vocab_word].should == "Собака"
|
952
|
+
end
|
953
|
+
|
954
|
+
it "rejects non-word characters for fields with 'word' constraints" do
|
955
|
+
@validator.add( :vocab_word, :word )
|
956
|
+
@validator.validate( 'vocab_word' => "Собака!" )
|
957
|
+
|
958
|
+
@validator.should have_errors()
|
959
|
+
@validator.should_not be_okay()
|
960
|
+
|
961
|
+
@validator[:vocab_word].should be_nil()
|
962
|
+
end
|
901
963
|
|
902
|
-
it "rejects parameters for fields with Proc constraints if the Proc returns a false value" do
|
903
|
-
@validator.add( :creation_date ) do |input|
|
904
|
-
Date.parse( input )
|
905
964
|
end
|
906
|
-
@validator.validate( 'creation_date' => '::::' )
|
907
965
|
|
908
|
-
|
909
|
-
@validator.should have_errors()
|
966
|
+
describe "Proc constraints" do
|
910
967
|
|
911
|
-
|
912
|
-
|
968
|
+
it "accepts parameters for fields with Proc constraints if the Proc returns a true value" do
|
969
|
+
test_date = '2007-07-17'
|
913
970
|
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
971
|
+
@validator.add( :creation_date ) do |input|
|
972
|
+
Date.parse( input )
|
973
|
+
end
|
974
|
+
@validator.validate( 'creation_date' => test_date )
|
918
975
|
|
919
|
-
|
976
|
+
@validator.should be_okay()
|
977
|
+
@validator.should_not have_errors()
|
920
978
|
|
921
|
-
|
922
|
-
|
923
|
-
newval.should be_okay()
|
924
|
-
newval.should_not have_errors()
|
979
|
+
@validator[:creation_date].should == Date.parse( test_date )
|
980
|
+
end
|
925
981
|
|
926
|
-
|
927
|
-
|
928
|
-
|
982
|
+
it "rejects parameters for fields with Proc constraints if the Proc returns a false value" do
|
983
|
+
@validator.add( :creation_date ) do |input|
|
984
|
+
Date.parse( input )
|
985
|
+
end
|
986
|
+
@validator.validate( 'creation_date' => '::::' )
|
929
987
|
|
930
|
-
|
931
|
-
|
932
|
-
@validator.validate( {} )
|
933
|
-
@validator.merge!( 'foo' => '1' )
|
988
|
+
@validator.should_not be_okay()
|
989
|
+
@validator.should have_errors()
|
934
990
|
|
935
|
-
|
936
|
-
|
991
|
+
@validator[:creation_date].should be_nil()
|
992
|
+
end
|
937
993
|
|
938
|
-
|
939
|
-
end
|
994
|
+
end
|
940
995
|
|
941
|
-
|
942
|
-
@validator.add( :foom, /^\d+$/ )
|
943
|
-
@validator.validate( {} )
|
944
|
-
@validator.merge!( 'foom' => '5' )
|
996
|
+
describe "merging new parameters" do
|
945
997
|
|
946
|
-
|
947
|
-
|
998
|
+
it "can be merged with another set of parameters" do
|
999
|
+
@validator.add( :foo, :integer, :required )
|
1000
|
+
@validator.validate( {} )
|
1001
|
+
newval = @validator.merge( 'foo' => '1' )
|
948
1002
|
|
949
|
-
|
950
|
-
|
1003
|
+
newval.should_not equal( @validator )
|
1004
|
+
|
1005
|
+
@validator.should_not be_okay()
|
1006
|
+
@validator.should have_errors()
|
1007
|
+
newval.should be_okay()
|
1008
|
+
newval.should_not have_errors()
|
1009
|
+
|
1010
|
+
@validator[:foo].should == nil
|
1011
|
+
newval[:foo].should == 1
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
it "can have required parameters merged into it after the initial validation" do
|
1015
|
+
@validator.add( :foo, :integer, :required )
|
1016
|
+
@validator.validate( {} )
|
1017
|
+
@validator.merge!( 'foo' => '1' )
|
1018
|
+
|
1019
|
+
@validator.should be_okay()
|
1020
|
+
@validator.should_not have_errors()
|
1021
|
+
|
1022
|
+
@validator[:foo].should == 1
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
it "can have optional parameters merged into it after the initial validation" do
|
1026
|
+
@validator.add( :foom, /^\d+$/ )
|
1027
|
+
@validator.validate( {} )
|
1028
|
+
@validator.merge!( 'foom' => '5' )
|
1029
|
+
|
1030
|
+
@validator.should be_okay()
|
1031
|
+
@validator.should_not have_errors()
|
1032
|
+
|
1033
|
+
@validator[:foom].should == '5'
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
it "rejects invalid parameters when they're merged after initial validation" do
|
1037
|
+
@validator.add( :foom, /^\d+$/ )
|
1038
|
+
@validator.add( :bewm, /^\d+$/ )
|
1039
|
+
@validator.validate( 'foom' => "1" )
|
1040
|
+
|
1041
|
+
@validator.merge!( 'bewm' => 'buckwheat noodles' )
|
1042
|
+
|
1043
|
+
@validator.should_not be_okay()
|
1044
|
+
@validator.should have_errors()
|
1045
|
+
@validator[:bewm].should == nil
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
end
|
951
1049
|
|
952
|
-
|
953
|
-
@validator.add( :foom, /^\d+$/ )
|
954
|
-
@validator.add( :bewm, /^\d+$/ )
|
955
|
-
@validator.validate( 'foom' => "1" )
|
956
|
-
|
957
|
-
@validator.merge!( 'bewm' => 'buckwheat noodles' )
|
958
|
-
|
959
|
-
@validator.should_not be_okay()
|
960
|
-
@validator.should have_errors()
|
961
|
-
@validator[:bewm].should == nil
|
962
|
-
end
|
963
|
-
|
964
|
-
it "allows valid parameters to be fetched en masse" do
|
965
|
-
@validator.add( :foom, /^\d+$/ )
|
966
|
-
@validator.add( :bewm, /^\d+$/ )
|
967
|
-
@validator.validate( 'foom' => "1", "bewm" => "2" )
|
968
|
-
@validator.values_at( :foom, :bewm ).should == [ '1', '2' ]
|
969
|
-
end
|
970
|
-
|
971
|
-
it "treats ArgumentErrors in builtin constraints as validation failures" do
|
972
|
-
@validator.add( :integer )
|
973
|
-
@validator.validate( 'integer' => 'jalopy' )
|
974
|
-
@validator.should_not be_okay()
|
975
|
-
@validator.should have_errors()
|
976
|
-
@validator[:integer].should be_nil()
|
977
|
-
end
|
1050
|
+
end # describe "constraints"
|
978
1051
|
|
979
1052
|
end
|
980
1053
|
|