arrow 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +1590 -0
- data/LICENSE +28 -0
- data/README +75 -0
- data/Rakefile +366 -0
- data/Rakefile.local +63 -0
- data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
- data/data/arrow/applets/args.rb +50 -0
- data/data/arrow/applets/config.rb +55 -0
- data/data/arrow/applets/error.rb +63 -0
- data/data/arrow/applets/files.rb +46 -0
- data/data/arrow/applets/inspect.rb +46 -0
- data/data/arrow/applets/nosuchapplet.rb +31 -0
- data/data/arrow/applets/status.rb +92 -0
- data/data/arrow/applets/test.rb +133 -0
- data/data/arrow/applets/tutorial/counter.rb +96 -0
- data/data/arrow/applets/tutorial/dingus.rb +67 -0
- data/data/arrow/applets/tutorial/hello.rb +34 -0
- data/data/arrow/applets/tutorial/hello2.rb +73 -0
- data/data/arrow/applets/tutorial/imgtext.rb +90 -0
- data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
- data/data/arrow/applets/tutorial/index.rb +36 -0
- data/data/arrow/applets/tutorial/logo.rb +98 -0
- data/data/arrow/applets/tutorial/memcache.rb +61 -0
- data/data/arrow/applets/tutorial/missing.rb +37 -0
- data/data/arrow/applets/tutorial/protected.rb +100 -0
- data/data/arrow/applets/tutorial/redirector.rb +52 -0
- data/data/arrow/applets/tutorial/rndimages.rb +159 -0
- data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
- data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
- data/data/arrow/applets/tutorial/superhello.rb +72 -0
- data/data/arrow/applets/tutorial/timeclock.rb +78 -0
- data/data/arrow/applets/view-applet.rb +123 -0
- data/data/arrow/applets/view-template.rb +85 -0
- data/data/arrow/applets/wiki.rb +274 -0
- data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
- data/data/arrow/templates/applet-status.tmpl +153 -0
- data/data/arrow/templates/args-display.tmpl +120 -0
- data/data/arrow/templates/config/display-table.tmpl +36 -0
- data/data/arrow/templates/config/display.tmpl +36 -0
- data/data/arrow/templates/counter-deleted.tmpl +33 -0
- data/data/arrow/templates/counter.tmpl +59 -0
- data/data/arrow/templates/dingus.tmpl +55 -0
- data/data/arrow/templates/enumtable.tmpl +8 -0
- data/data/arrow/templates/error-display.tmpl +92 -0
- data/data/arrow/templates/filemap.tmpl +89 -0
- data/data/arrow/templates/hello-world-src.tmpl +34 -0
- data/data/arrow/templates/hello-world.tmpl +60 -0
- data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
- data/data/arrow/templates/imgtext/form.tmpl +70 -0
- data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
- data/data/arrow/templates/imgtext/reload.tmpl +55 -0
- data/data/arrow/templates/inspect/display.tmpl +80 -0
- data/data/arrow/templates/loginform.tmpl +64 -0
- data/data/arrow/templates/logout.tmpl +32 -0
- data/data/arrow/templates/memcache/display.tmpl +41 -0
- data/data/arrow/templates/navbar.incl +27 -0
- data/data/arrow/templates/nosuchapplet.tmpl +32 -0
- data/data/arrow/templates/printsource.tmpl +35 -0
- data/data/arrow/templates/protected.tmpl +36 -0
- data/data/arrow/templates/rndimages.tmpl +38 -0
- data/data/arrow/templates/service-response.tmpl +13 -0
- data/data/arrow/templates/sharenotes/display.tmpl +38 -0
- data/data/arrow/templates/status.tmpl +120 -0
- data/data/arrow/templates/templateviewer.tmpl +43 -0
- data/data/arrow/templates/test/harness.tmpl +57 -0
- data/data/arrow/templates/test/list.tmpl +48 -0
- data/data/arrow/templates/test/problem.tmpl +42 -0
- data/data/arrow/templates/tutorial/index.tmpl +37 -0
- data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
- data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
- data/data/arrow/templates/view-applet.tmpl +40 -0
- data/data/arrow/templates/view-template.tmpl +83 -0
- data/data/arrow/templates/wiki/formerror.tmpl +47 -0
- data/data/arrow/templates/wiki/markup_help.incl +6 -0
- data/data/arrow/templates/wiki/new.tmpl +56 -0
- data/data/arrow/templates/wiki/new_system.tmpl +122 -0
- data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
- data/data/arrow/templates/wiki/show.tmpl +34 -0
- data/docs/manual/layouts/default.page +43 -0
- data/docs/manual/lib/api-filter.rb +81 -0
- data/docs/manual/lib/editorial-filter.rb +64 -0
- data/docs/manual/lib/examples-filter.rb +244 -0
- data/docs/manual/lib/links-filter.rb +117 -0
- data/lib/apache/fakerequest.rb +448 -0
- data/lib/apache/logger.rb +33 -0
- data/lib/arrow.rb +51 -0
- data/lib/arrow/acceptparam.rb +207 -0
- data/lib/arrow/applet.rb +725 -0
- data/lib/arrow/appletmixins.rb +218 -0
- data/lib/arrow/appletregistry.rb +590 -0
- data/lib/arrow/applettestcase.rb +503 -0
- data/lib/arrow/broker.rb +255 -0
- data/lib/arrow/cache.rb +176 -0
- data/lib/arrow/config-loaders/yaml.rb +75 -0
- data/lib/arrow/config.rb +615 -0
- data/lib/arrow/constants.rb +24 -0
- data/lib/arrow/cookie.rb +359 -0
- data/lib/arrow/cookieset.rb +108 -0
- data/lib/arrow/dispatcher.rb +368 -0
- data/lib/arrow/dispatcherloader.rb +50 -0
- data/lib/arrow/exceptions.rb +61 -0
- data/lib/arrow/fallbackhandler.rb +48 -0
- data/lib/arrow/formvalidator.rb +631 -0
- data/lib/arrow/htmltokenizer.rb +343 -0
- data/lib/arrow/logger.rb +488 -0
- data/lib/arrow/logger/apacheoutputter.rb +69 -0
- data/lib/arrow/logger/arrayoutputter.rb +63 -0
- data/lib/arrow/logger/coloroutputter.rb +111 -0
- data/lib/arrow/logger/fileoutputter.rb +96 -0
- data/lib/arrow/logger/htmloutputter.rb +54 -0
- data/lib/arrow/logger/outputter.rb +123 -0
- data/lib/arrow/mixins.rb +425 -0
- data/lib/arrow/monkeypatches.rb +94 -0
- data/lib/arrow/object.rb +117 -0
- data/lib/arrow/path.rb +196 -0
- data/lib/arrow/service.rb +447 -0
- data/lib/arrow/session.rb +289 -0
- data/lib/arrow/session/dbstore.rb +100 -0
- data/lib/arrow/session/filelock.rb +160 -0
- data/lib/arrow/session/filestore.rb +132 -0
- data/lib/arrow/session/id.rb +98 -0
- data/lib/arrow/session/lock.rb +253 -0
- data/lib/arrow/session/md5id.rb +42 -0
- data/lib/arrow/session/nulllock.rb +42 -0
- data/lib/arrow/session/posixlock.rb +166 -0
- data/lib/arrow/session/sha1id.rb +54 -0
- data/lib/arrow/session/store.rb +366 -0
- data/lib/arrow/session/usertrackid.rb +52 -0
- data/lib/arrow/spechelpers.rb +73 -0
- data/lib/arrow/template.rb +713 -0
- data/lib/arrow/template/attr.rb +31 -0
- data/lib/arrow/template/call.rb +31 -0
- data/lib/arrow/template/comment.rb +33 -0
- data/lib/arrow/template/container.rb +118 -0
- data/lib/arrow/template/else.rb +41 -0
- data/lib/arrow/template/elsif.rb +44 -0
- data/lib/arrow/template/escape.rb +53 -0
- data/lib/arrow/template/export.rb +87 -0
- data/lib/arrow/template/for.rb +145 -0
- data/lib/arrow/template/if.rb +78 -0
- data/lib/arrow/template/import.rb +119 -0
- data/lib/arrow/template/include.rb +206 -0
- data/lib/arrow/template/iterator.rb +208 -0
- data/lib/arrow/template/nodes.rb +734 -0
- data/lib/arrow/template/parser.rb +571 -0
- data/lib/arrow/template/prettyprint.rb +53 -0
- data/lib/arrow/template/render.rb +191 -0
- data/lib/arrow/template/selectlist.rb +94 -0
- data/lib/arrow/template/set.rb +87 -0
- data/lib/arrow/template/timedelta.rb +81 -0
- data/lib/arrow/template/unless.rb +78 -0
- data/lib/arrow/template/urlencode.rb +51 -0
- data/lib/arrow/template/yield.rb +139 -0
- data/lib/arrow/templatefactory.rb +125 -0
- data/lib/arrow/testcase.rb +567 -0
- data/lib/arrow/transaction.rb +608 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/documentation.rb +114 -0
- data/rake/helpers.rb +502 -0
- data/rake/hg.rb +282 -0
- data/rake/manual.rb +787 -0
- data/rake/packaging.rb +129 -0
- data/rake/publishing.rb +278 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/arrow/acceptparam_spec.rb +157 -0
- data/spec/arrow/applet_spec.rb +575 -0
- data/spec/arrow/appletmixins_spec.rb +409 -0
- data/spec/arrow/appletregistry_spec.rb +294 -0
- data/spec/arrow/broker_spec.rb +153 -0
- data/spec/arrow/config_spec.rb +224 -0
- data/spec/arrow/cookieset_spec.rb +164 -0
- data/spec/arrow/dispatcher_spec.rb +137 -0
- data/spec/arrow/dispatcherloader_spec.rb +65 -0
- data/spec/arrow/formvalidator_spec.rb +781 -0
- data/spec/arrow/logger_spec.rb +346 -0
- data/spec/arrow/mixins_spec.rb +120 -0
- data/spec/arrow/service_spec.rb +645 -0
- data/spec/arrow/session_spec.rb +121 -0
- data/spec/arrow/template/iterator_spec.rb +222 -0
- data/spec/arrow/templatefactory_spec.rb +185 -0
- data/spec/arrow/transaction_spec.rb +319 -0
- data/spec/arrow_spec.rb +37 -0
- data/spec/lib/appletmatchers.rb +281 -0
- data/spec/lib/constants.rb +77 -0
- data/spec/lib/helpers.rb +41 -0
- data/spec/lib/matchers.rb +44 -0
- data/tests/cookie.tests.rb +310 -0
- data/tests/path.tests.rb +157 -0
- data/tests/session.tests.rb +111 -0
- data/tests/session_id.tests.rb +82 -0
- data/tests/session_lock.tests.rb +191 -0
- data/tests/session_store.tests.rb +53 -0
- data/tests/template.tests.rb +1360 -0
- metadata +339 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
BEGIN {
|
4
|
+
require 'pathname'
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
6
|
+
|
7
|
+
libdir = basedir + "lib"
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
10
|
+
}
|
11
|
+
|
12
|
+
require 'rubygems'
|
13
|
+
require 'spec'
|
14
|
+
require 'tempfile'
|
15
|
+
require 'tmpdir'
|
16
|
+
require 'pathname'
|
17
|
+
require 'apache/fakerequest'
|
18
|
+
require 'arrow'
|
19
|
+
require 'arrow/dispatcher'
|
20
|
+
require 'arrow/config-loaders/yaml'
|
21
|
+
|
22
|
+
require 'spec/lib/matchers'
|
23
|
+
require 'spec/lib/constants'
|
24
|
+
|
25
|
+
|
26
|
+
include Arrow::TestConstants
|
27
|
+
|
28
|
+
|
29
|
+
#####################################################################
|
30
|
+
### C O N T E X T S
|
31
|
+
#####################################################################
|
32
|
+
|
33
|
+
describe Arrow::Dispatcher do
|
34
|
+
include Arrow::TimeMatchers
|
35
|
+
|
36
|
+
before(:all) do
|
37
|
+
@tmpfile = Tempfile.new( 'test.conf', '.' )
|
38
|
+
TEST_CONFIG.dup.write( @tmpfile.path )
|
39
|
+
@tmpfile.close
|
40
|
+
end
|
41
|
+
|
42
|
+
after( :all ) do
|
43
|
+
@tmpfile.delete
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
after(:each) do
|
48
|
+
Pathname.glob( "%s/arrow-fatal*" % Dir.tmpdir ).each do |f|
|
49
|
+
f.unlink
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
### Specs
|
55
|
+
|
56
|
+
it "raises an error when its factory method is called with " +
|
57
|
+
"something other than a String or Hash" do
|
58
|
+
lambda {
|
59
|
+
Arrow::Dispatcher.create( :something )
|
60
|
+
}.should raise_error( ArgumentError, /invalid config hash/i )
|
61
|
+
end
|
62
|
+
|
63
|
+
it "writes a crashlog to TMPDIR when create fails" do
|
64
|
+
crashlog = Pathname.new( Dir.tmpdir + "/arrow-fatal.log.#{$$}" )
|
65
|
+
crashlog.unlink if crashlog.exist?
|
66
|
+
|
67
|
+
begin
|
68
|
+
Arrow::Dispatcher.create( :something )
|
69
|
+
rescue ArgumentError
|
70
|
+
end
|
71
|
+
|
72
|
+
crashlog.exist?.should == true
|
73
|
+
crashlog.ctime.should be_after( Time.now - 60 )
|
74
|
+
end
|
75
|
+
|
76
|
+
it "assumes a string configspec is a default configfile" do
|
77
|
+
dispatcher = Arrow::Dispatcher.create( @tmpfile.path )
|
78
|
+
Arrow::Dispatcher.instance.should equal( dispatcher )
|
79
|
+
end
|
80
|
+
|
81
|
+
it "reads dispatcher configs from an object's #read method if it has one" do
|
82
|
+
config_obj = mock( "configuration object", :null_object => true )
|
83
|
+
config_obj.should_receive( :respond_to? ).with( :read ).and_return( true )
|
84
|
+
config_obj.should_receive( :read ).and_return( YAML.dump({}) )
|
85
|
+
|
86
|
+
Arrow::Dispatcher.create_from_hosts_file( config_obj )
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
describe "instance" do
|
91
|
+
it "has an associated name" do
|
92
|
+
@config = Arrow::Config.new( TEST_CONFIG_HASH )
|
93
|
+
@dispatcher = Arrow::Dispatcher.new( "test", @config )
|
94
|
+
@dispatcher.name.should == "test"
|
95
|
+
end
|
96
|
+
|
97
|
+
describe " running under $SAFE = 1" do
|
98
|
+
before(:all) do
|
99
|
+
@configfile = Tempfile.new( 'test.conf', '.' )
|
100
|
+
@configfile.print( YAML.dump(TEST_CONFIG_HASH) )
|
101
|
+
@configfile.close
|
102
|
+
|
103
|
+
hosts_config = YAML.dump({
|
104
|
+
:testing => @configfile.path,
|
105
|
+
})
|
106
|
+
@host_configio = StringIO.new( hosts_config )
|
107
|
+
@host_configio.taint
|
108
|
+
end
|
109
|
+
|
110
|
+
after(:all) do
|
111
|
+
@configfile.delete
|
112
|
+
end
|
113
|
+
|
114
|
+
# Fake actually loading the config file
|
115
|
+
before(:each) do
|
116
|
+
@host_configio.rewind
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should be able to create dispatchers from a tainted hosts file" do
|
120
|
+
$SAFE = 1
|
121
|
+
rval = nil
|
122
|
+
|
123
|
+
lambda {
|
124
|
+
rval = Arrow::Dispatcher.create_from_hosts_file( @host_configio )
|
125
|
+
}.should_not raise_error()
|
126
|
+
|
127
|
+
rval.should be_an_instance_of( Hash )
|
128
|
+
rval.should have(2).keys
|
129
|
+
rval.keys.should include( :testing )
|
130
|
+
rval.keys.should include( File.expand_path(@configfile.path) )
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
# vim: set nosta noet ts=4 sw=4:
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
BEGIN {
|
4
|
+
require 'pathname'
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
6
|
+
|
7
|
+
libdir = basedir + "lib"
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
10
|
+
}
|
11
|
+
|
12
|
+
require 'spec'
|
13
|
+
require 'spec/lib/helpers'
|
14
|
+
|
15
|
+
require 'apache/fakerequest'
|
16
|
+
|
17
|
+
require 'arrow'
|
18
|
+
require 'arrow/dispatcherloader'
|
19
|
+
|
20
|
+
|
21
|
+
#####################################################################
|
22
|
+
### C O N T E X T S
|
23
|
+
#####################################################################
|
24
|
+
|
25
|
+
describe Arrow::DispatcherLoader do
|
26
|
+
include Arrow::SpecHelpers
|
27
|
+
|
28
|
+
|
29
|
+
before( :all ) do
|
30
|
+
setup_logging( :crit )
|
31
|
+
end
|
32
|
+
|
33
|
+
after( :all ) do
|
34
|
+
reset_logging()
|
35
|
+
end
|
36
|
+
|
37
|
+
it "creates Arrow::Dispatchers from a registered configfile on child_init" do
|
38
|
+
req = Apache::Request.new
|
39
|
+
Arrow::Dispatcher.should_receive( :create_from_hosts_file ).with( 'hosts.yml' )
|
40
|
+
Arrow::DispatcherLoader.new( 'hosts.yml' ).child_init( req ).should == Apache::OK
|
41
|
+
end
|
42
|
+
|
43
|
+
it "handles errors while loading dispachers by logging to a tempfile and to Apache's log" do
|
44
|
+
req = Apache::Request.new
|
45
|
+
Arrow::Dispatcher.should_receive( :create_from_hosts_file ).with( 'hosts.yml' ).
|
46
|
+
and_raise( RuntimeError.new("something bad happened") )
|
47
|
+
|
48
|
+
logpath = mock( "error logfile Pathname" )
|
49
|
+
io = mock( "error logfile IO" )
|
50
|
+
|
51
|
+
Pathname.should_receive( :new ).with( instance_of(String) ).
|
52
|
+
and_return( logpath )
|
53
|
+
logpath.should_receive( :+ ).with( 'arrow-dispatcher-failure.log' ).and_return( logpath )
|
54
|
+
logpath.should_receive( :open ).with( IO::WRONLY|IO::TRUNC|IO::CREAT ).and_yield( io )
|
55
|
+
io.should_receive( :puts ).with( /something bad happened/ )
|
56
|
+
io.should_receive( :flush )
|
57
|
+
|
58
|
+
expect {
|
59
|
+
Arrow::DispatcherLoader.new( 'hosts.yml' ).child_init( req )
|
60
|
+
}.to raise_error( RuntimeError, /something bad happened/ )
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
65
|
+
|
@@ -0,0 +1,781 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
BEGIN {
|
4
|
+
require 'pathname'
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
6
|
+
|
7
|
+
libdir = basedir + "lib"
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
10
|
+
}
|
11
|
+
|
12
|
+
begin
|
13
|
+
require 'spec'
|
14
|
+
require 'apache/fakerequest'
|
15
|
+
require 'arrow'
|
16
|
+
require 'spec/lib/helpers'
|
17
|
+
require 'arrow/formvalidator'
|
18
|
+
require 'date'
|
19
|
+
rescue LoadError
|
20
|
+
unless Object.const_defined?( :Gem )
|
21
|
+
require 'rubygems'
|
22
|
+
retry
|
23
|
+
end
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
#####################################################################
|
29
|
+
### C O N T E X T S
|
30
|
+
#####################################################################
|
31
|
+
TestProfile = {
|
32
|
+
:required => [ :required ],
|
33
|
+
:optional => %w{
|
34
|
+
optional number int_constraint bool_constraint email_constraint
|
35
|
+
host_constraint regexp_w_captures regexp_w_one_capture
|
36
|
+
alpha_constraint alphanumeric_constraint printable_constraint
|
37
|
+
proc_constraint uri_constraint
|
38
|
+
},
|
39
|
+
:constraints => {
|
40
|
+
:number => /^\d+$/,
|
41
|
+
:regexp_w_captures => /(\w+)(\S+)?/,
|
42
|
+
:regexp_w_one_capture => /(\w+)/,
|
43
|
+
:int_constraint => :integer,
|
44
|
+
:bool_constraint => :boolean,
|
45
|
+
:email_constraint => :email,
|
46
|
+
:uri_constraint => :uri,
|
47
|
+
:host_constraint => :hostname,
|
48
|
+
:alpha_constraint => :alpha,
|
49
|
+
:alphanumeric_constraint => :alphanumeric,
|
50
|
+
:printable_constraint => :printable,
|
51
|
+
:proc_constraint => Proc.new {|d| Date.parse(d) rescue nil },
|
52
|
+
},
|
53
|
+
}
|
54
|
+
|
55
|
+
|
56
|
+
describe Arrow::FormValidator do
|
57
|
+
include Arrow::SpecHelpers
|
58
|
+
|
59
|
+
before( :all ) do
|
60
|
+
setup_logging( :crit )
|
61
|
+
end
|
62
|
+
|
63
|
+
before(:each) do
|
64
|
+
@validator = Arrow::FormValidator.new( TestProfile )
|
65
|
+
end
|
66
|
+
|
67
|
+
after( :all ) do
|
68
|
+
reset_logging()
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
# Test index operator interface
|
74
|
+
it "should provide read and write access to valid args via the index operator" do
|
75
|
+
rval = nil
|
76
|
+
|
77
|
+
@validator.validate( {'required' => "1"} )
|
78
|
+
@validator[:required].should == "1"
|
79
|
+
|
80
|
+
@validator[:required] = "bar"
|
81
|
+
@validator["required"].should == "bar"
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
it "should untaint valid args if told to do so" do
|
86
|
+
rval = nil
|
87
|
+
tainted_one = "1"
|
88
|
+
tainted_one.taint
|
89
|
+
|
90
|
+
@validator.validate( {'required' => 1, 'number' => tainted_one},
|
91
|
+
:untaint_all_constraints => true )
|
92
|
+
|
93
|
+
Arrow::Logger.global.notice "Validator: %p" % [@validator]
|
94
|
+
|
95
|
+
@validator[:number].should == "1"
|
96
|
+
@validator[:number].tainted?.should be_false()
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
it "should untaint field names" do
|
101
|
+
rval = nil
|
102
|
+
tainted_one = "1"
|
103
|
+
tainted_one.taint
|
104
|
+
|
105
|
+
@validator.validate( {'required' => 1, 'number' => tainted_one},
|
106
|
+
:untaint_all_constraints => true )
|
107
|
+
|
108
|
+
Arrow::Logger.global.notice "Validator: %p" % [@validator]
|
109
|
+
|
110
|
+
@validator[:number].should == "1"
|
111
|
+
@validator[:number].tainted?.should be_false()
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
it "should return the capture from a regexp constraint if it has only one" do
|
116
|
+
rval = nil
|
117
|
+
params = { 'required' => 1, 'regexp_w_one_capture' => " ygdrassil " }
|
118
|
+
|
119
|
+
@validator.validate( params, :untaint_all_constraints => true )
|
120
|
+
|
121
|
+
Arrow::Logger.global.notice "Validator: %p" % [@validator]
|
122
|
+
|
123
|
+
@validator[:regexp_w_one_capture].should == 'ygdrassil'
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should return the captures from a regexp constraint as an array if it has more than one" do
|
127
|
+
rval = nil
|
128
|
+
params = { 'required' => 1, 'regexp_w_captures' => " the1tree(!) " }
|
129
|
+
|
130
|
+
@validator.validate( params, :untaint_all_constraints => true )
|
131
|
+
|
132
|
+
Arrow::Logger.global.notice "Validator: %p" % [@validator]
|
133
|
+
|
134
|
+
@validator[:regexp_w_captures].should == ['the1tree', '(!)']
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should return the captures from a regexp constraint as an array " +
|
138
|
+
"even if an optional capture doesn't match anything" do
|
139
|
+
rval = nil
|
140
|
+
params = { 'required' => 1, 'regexp_w_captures' => " the1tree " }
|
141
|
+
|
142
|
+
@validator.validate( params, :untaint_all_constraints => true )
|
143
|
+
|
144
|
+
Arrow::Logger.global.notice "Validator: %p" % [@validator]
|
145
|
+
|
146
|
+
@validator[:regexp_w_captures].should == ['the1tree', nil]
|
147
|
+
end
|
148
|
+
|
149
|
+
it "knows the names of fields that were required but missing from the parameters" do
|
150
|
+
@validator.validate( {} )
|
151
|
+
|
152
|
+
@validator.should have_errors()
|
153
|
+
@validator.should_not be_okay()
|
154
|
+
|
155
|
+
@validator.missing.should have(1).members
|
156
|
+
@validator.missing.should == ['required']
|
157
|
+
end
|
158
|
+
|
159
|
+
it "knows the names of fields that did not meet their constraints" do
|
160
|
+
params = {'number' => 'rhinoceros'}
|
161
|
+
@validator.validate( params )
|
162
|
+
|
163
|
+
@validator.should have_errors()
|
164
|
+
@validator.should_not be_okay()
|
165
|
+
|
166
|
+
@validator.invalid.should have(1).keys
|
167
|
+
@validator.invalid.keys.should == ['number']
|
168
|
+
end
|
169
|
+
|
170
|
+
it "can return a combined list of all problem parameters, which includes " +
|
171
|
+
" both missing and invalid fields" do
|
172
|
+
params = {'number' => 'rhinoceros'}
|
173
|
+
@validator.validate( params )
|
174
|
+
|
175
|
+
@validator.should have_errors()
|
176
|
+
@validator.should_not be_okay()
|
177
|
+
|
178
|
+
@validator.error_fields.should have(2).members
|
179
|
+
@validator.error_fields.should include('number')
|
180
|
+
@validator.error_fields.should include('required')
|
181
|
+
end
|
182
|
+
|
183
|
+
it "can return human descriptions of validation errors" do
|
184
|
+
params = {'number' => 'rhinoceros', 'unknown' => "1"}
|
185
|
+
@validator.validate( params )
|
186
|
+
|
187
|
+
@validator.error_messages.should have(2).members
|
188
|
+
@validator.error_messages.should include("Missing value for 'Required'")
|
189
|
+
@validator.error_messages.should include("Invalid value for 'Number'")
|
190
|
+
end
|
191
|
+
|
192
|
+
it "can include unknown fields in its human descriptions of validation errors" do
|
193
|
+
params = {'number' => 'rhinoceros', 'unknown' => "1"}
|
194
|
+
@validator.validate( params )
|
195
|
+
|
196
|
+
@validator.error_messages(true).should have(3).members
|
197
|
+
@validator.error_messages(true).should include("Missing value for 'Required'")
|
198
|
+
@validator.error_messages(true).should include("Invalid value for 'Number'")
|
199
|
+
@validator.error_messages(true).should include("Unknown parameter 'Unknown'")
|
200
|
+
end
|
201
|
+
|
202
|
+
it "can use provided descriptions of parameters when constructing human " +
|
203
|
+
"validation error messages" do
|
204
|
+
descs = {
|
205
|
+
:number => "Numeral",
|
206
|
+
:required => "Test Name",
|
207
|
+
}
|
208
|
+
params = {'number' => 'rhinoceros', 'unknown' => "1"}
|
209
|
+
@validator.validate( params, :descriptions => descs )
|
210
|
+
|
211
|
+
@validator.error_messages.should have(2).members
|
212
|
+
@validator.error_messages.should include("Missing value for 'Test Name'")
|
213
|
+
@validator.error_messages.should include("Invalid value for 'Numeral'")
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
it "capitalizes the names of simple fields for descriptions" do
|
218
|
+
@validator.get_description( "required" ).should == 'Required'
|
219
|
+
end
|
220
|
+
|
221
|
+
it "splits apart underbarred field names into capitalized words for descriptions" do
|
222
|
+
@validator.get_description( "rodent_size" ).should == 'Rodent Size'
|
223
|
+
end
|
224
|
+
|
225
|
+
it "uses the key for descriptions of hash fields" do
|
226
|
+
@validator.get_description( "rodent[size]" ).should == 'Size'
|
227
|
+
end
|
228
|
+
|
229
|
+
it "uses separate capitalized words for descriptions of hash fields with underbarred keys " do
|
230
|
+
@validator.get_description( "castle[baron_id]" ).should == 'Baron Id'
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should be able to coalesce simple hash fields into a hash of validated values" do
|
234
|
+
@validator.validate( {'rodent[size]' => 'unusual'}, :optional => ['rodent[size]'] )
|
235
|
+
|
236
|
+
@validator.valid.should == {'rodent' => {'size' => 'unusual'}}
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should be able to coalesce complex hash fields into a nested hash of validated values" do
|
240
|
+
profile = {
|
241
|
+
:optional => [
|
242
|
+
'recipe[ingredient][name]',
|
243
|
+
'recipe[ingredient][cost]',
|
244
|
+
'recipe[yield]'
|
245
|
+
]
|
246
|
+
}
|
247
|
+
args = {
|
248
|
+
'recipe[ingredient][name]' => 'nutmeg',
|
249
|
+
'recipe[ingredient][cost]' => '$0.18',
|
250
|
+
'recipe[yield]' => '2 loaves',
|
251
|
+
}
|
252
|
+
|
253
|
+
@validator.validate( args, profile )
|
254
|
+
@validator.valid.should == {
|
255
|
+
'recipe' => {
|
256
|
+
'ingredient' => { 'name' => 'nutmeg', 'cost' => '$0.18' },
|
257
|
+
'yield' => '2 loaves'
|
258
|
+
}
|
259
|
+
}
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should untaint both keys and values in complex hash fields if untainting is turned on" do
|
263
|
+
profile = {
|
264
|
+
:required => [
|
265
|
+
'recipe[ingredient][rarity]',
|
266
|
+
],
|
267
|
+
:optional => [
|
268
|
+
'recipe[ingredient][name]',
|
269
|
+
'recipe[ingredient][cost]',
|
270
|
+
'recipe[yield]'
|
271
|
+
],
|
272
|
+
:constraints => {
|
273
|
+
'recipe[ingredient][rarity]' => /^([\w\-]+)$/,
|
274
|
+
},
|
275
|
+
:untaint_all_constraints => true,
|
276
|
+
}
|
277
|
+
args = {
|
278
|
+
'recipe[ingredient][rarity]'.taint => 'super-rare'.taint,
|
279
|
+
'recipe[ingredient][name]'.taint => 'nutmeg'.taint,
|
280
|
+
'recipe[ingredient][cost]'.taint => '$0.18'.taint,
|
281
|
+
'recipe[yield]'.taint => '2 loaves'.taint,
|
282
|
+
}
|
283
|
+
|
284
|
+
@validator.validate( args, profile )
|
285
|
+
|
286
|
+
@validator.valid.should == {
|
287
|
+
'recipe' => {
|
288
|
+
'ingredient' => { 'name' => 'nutmeg', 'cost' => '$0.18', 'rarity' => 'super-rare' },
|
289
|
+
'yield' => '2 loaves'
|
290
|
+
}
|
291
|
+
}
|
292
|
+
|
293
|
+
@validator.valid.keys.all? {|key| key.should_not be_tainted() }
|
294
|
+
@validator.valid.values.all? {|key| key.should_not be_tainted() }
|
295
|
+
@validator.valid['recipe'].keys.all? {|key| key.should_not be_tainted() }
|
296
|
+
@validator.valid['recipe']['ingredient'].keys.all? {|key| key.should_not be_tainted() }
|
297
|
+
@validator.valid['recipe']['yield'].should_not be_tainted()
|
298
|
+
@validator.valid['recipe']['ingredient']['rarity'].should_not be_tainted()
|
299
|
+
@validator.valid['recipe']['ingredient']['name'].should_not be_tainted()
|
300
|
+
@validator.valid['recipe']['ingredient']['cost'].should_not be_tainted()
|
301
|
+
end
|
302
|
+
|
303
|
+
it "accepts the value 'true' for fields with boolean constraints" do
|
304
|
+
params = {'required' => '1', 'bool_constraint' => 'true'}
|
305
|
+
|
306
|
+
@validator.validate( params )
|
307
|
+
|
308
|
+
@validator.should be_okay()
|
309
|
+
@validator.should_not have_errors()
|
310
|
+
|
311
|
+
@validator[:bool_constraint].should be_true()
|
312
|
+
end
|
313
|
+
|
314
|
+
it "accepts the value 't' for fields with boolean constraints" do
|
315
|
+
params = {'required' => '1', 'bool_constraint' => 't'}
|
316
|
+
|
317
|
+
@validator.validate( params )
|
318
|
+
|
319
|
+
@validator.should be_okay()
|
320
|
+
@validator.should_not have_errors()
|
321
|
+
|
322
|
+
@validator[:bool_constraint].should be_true()
|
323
|
+
end
|
324
|
+
|
325
|
+
it "accepts the value 'yes' for fields with boolean constraints" do
|
326
|
+
params = {'required' => '1', 'bool_constraint' => 'yes'}
|
327
|
+
|
328
|
+
@validator.validate( params )
|
329
|
+
|
330
|
+
@validator.should be_okay()
|
331
|
+
@validator.should_not have_errors()
|
332
|
+
|
333
|
+
@validator[:bool_constraint].should be_true()
|
334
|
+
end
|
335
|
+
|
336
|
+
it "accepts the value 'y' for fields with boolean constraints" do
|
337
|
+
params = {'required' => '1', 'bool_constraint' => 'y'}
|
338
|
+
|
339
|
+
@validator.validate( params )
|
340
|
+
|
341
|
+
@validator.should be_okay()
|
342
|
+
@validator.should_not have_errors()
|
343
|
+
|
344
|
+
@validator[:bool_constraint].should be_true()
|
345
|
+
end
|
346
|
+
|
347
|
+
it "accepts the value '1' for fields with boolean constraints" do
|
348
|
+
params = {'required' => '1', 'bool_constraint' => '1'}
|
349
|
+
|
350
|
+
@validator.validate( params )
|
351
|
+
|
352
|
+
@validator.should be_okay()
|
353
|
+
@validator.should_not have_errors()
|
354
|
+
|
355
|
+
@validator[:bool_constraint].should be_true()
|
356
|
+
end
|
357
|
+
|
358
|
+
it "accepts the value 'false' for fields with boolean constraints" do
|
359
|
+
params = {'required' => '1', 'bool_constraint' => 'false'}
|
360
|
+
|
361
|
+
@validator.validate( params )
|
362
|
+
|
363
|
+
@validator.should be_okay()
|
364
|
+
@validator.should_not have_errors()
|
365
|
+
|
366
|
+
@validator[:bool_constraint].should be_false()
|
367
|
+
end
|
368
|
+
|
369
|
+
it "accepts the value 'f' for fields with boolean constraints" do
|
370
|
+
params = {'required' => '1', 'bool_constraint' => 'f'}
|
371
|
+
|
372
|
+
@validator.validate( params )
|
373
|
+
|
374
|
+
@validator.should be_okay()
|
375
|
+
@validator.should_not have_errors()
|
376
|
+
|
377
|
+
@validator[:bool_constraint].should be_false()
|
378
|
+
end
|
379
|
+
|
380
|
+
it "accepts the value 'no' for fields with boolean constraints" do
|
381
|
+
params = {'required' => '1', 'bool_constraint' => 'no'}
|
382
|
+
|
383
|
+
@validator.validate( params )
|
384
|
+
|
385
|
+
@validator.should be_okay()
|
386
|
+
@validator.should_not have_errors()
|
387
|
+
|
388
|
+
@validator[:bool_constraint].should be_false()
|
389
|
+
end
|
390
|
+
|
391
|
+
it "accepts the value 'n' for fields with boolean constraints" do
|
392
|
+
params = {'required' => '1', 'bool_constraint' => 'n'}
|
393
|
+
|
394
|
+
@validator.validate( params )
|
395
|
+
|
396
|
+
@validator.should be_okay()
|
397
|
+
@validator.should_not have_errors()
|
398
|
+
|
399
|
+
@validator[:bool_constraint].should be_false()
|
400
|
+
end
|
401
|
+
|
402
|
+
it "accepts the value '0' for fields with boolean constraints" do
|
403
|
+
params = {'required' => '1', 'bool_constraint' => '0'}
|
404
|
+
|
405
|
+
@validator.validate( params )
|
406
|
+
|
407
|
+
@validator.should be_okay()
|
408
|
+
@validator.should_not have_errors()
|
409
|
+
|
410
|
+
@validator[:bool_constraint].should be_false()
|
411
|
+
end
|
412
|
+
|
413
|
+
it "rejects non-boolean parameters for fields with boolean constraints" do
|
414
|
+
params = {'required' => '1', 'bool_constraint' => 'peanut'}
|
415
|
+
|
416
|
+
@validator.validate( params )
|
417
|
+
|
418
|
+
@validator.should_not be_okay()
|
419
|
+
@validator.should have_errors()
|
420
|
+
|
421
|
+
@validator[:bool_constraint].should be_nil()
|
422
|
+
end
|
423
|
+
|
424
|
+
it "accepts simple integers for fields with integer constraints" do
|
425
|
+
params = {'required' => '1', 'int_constraint' => '11'}
|
426
|
+
|
427
|
+
@validator.validate( params )
|
428
|
+
|
429
|
+
@validator.should be_okay()
|
430
|
+
@validator.should_not have_errors()
|
431
|
+
|
432
|
+
@validator[:int_constraint].should == 11
|
433
|
+
end
|
434
|
+
|
435
|
+
it "accepts '0' for fields with integer constraints" do
|
436
|
+
params = {'required' => '1', 'int_constraint' => '0'}
|
437
|
+
|
438
|
+
@validator.validate( params )
|
439
|
+
|
440
|
+
@validator.should be_okay()
|
441
|
+
@validator.should_not have_errors()
|
442
|
+
|
443
|
+
@validator[:int_constraint].should == 0
|
444
|
+
end
|
445
|
+
|
446
|
+
it "accepts negative integers for fields with integer constraints" do
|
447
|
+
params = {'required' => '1', 'int_constraint' => '-407'}
|
448
|
+
|
449
|
+
@validator.validate( params )
|
450
|
+
|
451
|
+
@validator.should be_okay()
|
452
|
+
@validator.should_not have_errors()
|
453
|
+
|
454
|
+
@validator[:int_constraint].should == -407
|
455
|
+
end
|
456
|
+
|
457
|
+
it "rejects non-integers for fields with integer constraints" do
|
458
|
+
params = {'required' => '1', 'int_constraint' => '11.1'}
|
459
|
+
|
460
|
+
@validator.validate( params )
|
461
|
+
|
462
|
+
@validator.should_not be_okay()
|
463
|
+
@validator.should have_errors()
|
464
|
+
|
465
|
+
@validator[:int_constraint].should be_nil()
|
466
|
+
end
|
467
|
+
|
468
|
+
it "rejects integer values with other cruft in them for fields with integer constraints" do
|
469
|
+
params = {'required' => '1', 'int_constraint' => '88licks'}
|
470
|
+
|
471
|
+
@validator.validate( params )
|
472
|
+
|
473
|
+
@validator.should_not be_okay()
|
474
|
+
@validator.should have_errors()
|
475
|
+
|
476
|
+
@validator[:int_constraint].should be_nil()
|
477
|
+
end
|
478
|
+
|
479
|
+
ValidURIs = %w{
|
480
|
+
http://127.0.0.1
|
481
|
+
http://127.0.0.1/
|
482
|
+
http://[127.0.0.1]/
|
483
|
+
http://ruby-lang.org/
|
484
|
+
http://www.rocketboom.com/vlog/rb_08_feb_01
|
485
|
+
http://del.icio.us/search/?fr=del_icio_us&p=ruby+arrow&type=all
|
486
|
+
http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:8080/index.html
|
487
|
+
http://[1080:0:0:0:8:800:200C:417A]/index.html
|
488
|
+
http://[3ffe:2a00:100:7031::1]
|
489
|
+
http://[1080::8:800:200C:417A]/foo
|
490
|
+
http://[::192.9.5.5]/ipng
|
491
|
+
http://[::FFFF:129.144.52.38]:3474/index.html
|
492
|
+
http://[2010:836B:4179::836B:4179]
|
493
|
+
|
494
|
+
https://mail.google.com/
|
495
|
+
https://127.0.0.1/
|
496
|
+
https://r4.com:8080/
|
497
|
+
|
498
|
+
ftp://ftp.ruby-lang.org/pub/ruby/1.0/ruby-0.49.tar.gz
|
499
|
+
ftp://crashoverride:god@gibson.ellingsonmineral.com/root/.workspace/.garbage.
|
500
|
+
|
501
|
+
ldap:/o=University%20of%20Michigan,c=US
|
502
|
+
ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US
|
503
|
+
ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress
|
504
|
+
ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)
|
505
|
+
ldap://ldap.itd.umich.edu/c=GB?objectClass?one
|
506
|
+
ldap://ldap.question.com/o=Question%3f,c=US?mail
|
507
|
+
ldap://ldap.netscape.com/o=Babsco,c=US??(int=%5c00%5c00%5c00%5c04)
|
508
|
+
ldap:/??sub??bindname=cn=Manager%2co=Foo
|
509
|
+
ldap:/??sub??!bindname=cn=Manager%2co=Foo
|
510
|
+
}
|
511
|
+
|
512
|
+
ValidURIs.each do |uri_string|
|
513
|
+
it "accepts #{uri_string} for fields with URI constraints" do
|
514
|
+
params = {'required' => '1', 'uri_constraint' => uri_string}
|
515
|
+
|
516
|
+
@validator.validate( params )
|
517
|
+
|
518
|
+
@validator.should be_okay()
|
519
|
+
@validator.should_not have_errors()
|
520
|
+
|
521
|
+
@validator[:uri_constraint].should be_a_kind_of( URI::Generic )
|
522
|
+
@validator[:uri_constraint].to_s.should == uri_string
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
# :FIXME: I don't know LDAP uris very well, so I'm not sure how they're likely to
|
527
|
+
# be invalidly-occurring in the wild
|
528
|
+
InvalidURIs = %W{
|
529
|
+
glark:
|
530
|
+
|
531
|
+
http:
|
532
|
+
http://
|
533
|
+
http://_com/vlog/rb_08_feb_01
|
534
|
+
http://del.icio.us/search/\x20\x14\x18
|
535
|
+
http://FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/index.html
|
536
|
+
http://1080:0:0:0:8:800:200C:417A/index.html
|
537
|
+
http://3ffe:2a00:100:7031::1
|
538
|
+
http://1080::8:800:200C:417A/foo
|
539
|
+
http://::192.9.5.5/ipng
|
540
|
+
http://::FFFF:129.144.52.38:80/index.html
|
541
|
+
http://2010:836B:4179::836B:4179
|
542
|
+
|
543
|
+
https:
|
544
|
+
https://user:pass@/
|
545
|
+
https://r4.com:nonnumericport/
|
546
|
+
|
547
|
+
ftp:
|
548
|
+
ftp:ruby-0.49.tar.gz
|
549
|
+
ftp://crashoverride:god@/root/.workspace/.garbage.
|
550
|
+
|
551
|
+
ldap:
|
552
|
+
ldap:/o=University\x20of\x20Michigan,c=US
|
553
|
+
ldap://ldap.itd.umich.edu/o=University+\x00of+Michigan
|
554
|
+
}
|
555
|
+
|
556
|
+
InvalidURIs.each do |uri_string|
|
557
|
+
it "rejects #{uri_string} for fields with URI constraints" do
|
558
|
+
params = {'required' => '1', 'uri_constraint' => uri_string}
|
559
|
+
|
560
|
+
# lambda {
|
561
|
+
@validator.validate( params )
|
562
|
+
# }.should_not raise_error()
|
563
|
+
|
564
|
+
@validator.should_not be_okay()
|
565
|
+
@validator.should have_errors()
|
566
|
+
|
567
|
+
@validator[:uri_constraint].should be_nil()
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
it "accepts simple RFC822 addresses for fields with email constraints" do
|
572
|
+
params = {'required' => '1', 'email_constraint' => 'jrandom@hacker.ie'}
|
573
|
+
|
574
|
+
@validator.validate( params )
|
575
|
+
|
576
|
+
@validator.should be_okay()
|
577
|
+
@validator.should_not have_errors()
|
578
|
+
|
579
|
+
@validator[:email_constraint].should == 'jrandom@hacker.ie'
|
580
|
+
end
|
581
|
+
|
582
|
+
it "accepts hyphenated domains in RFC822 addresses for fields with email constraints" do
|
583
|
+
params = {'required' => '1', 'email_constraint' => 'jrandom@just-another-hacquer.fr'}
|
584
|
+
|
585
|
+
@validator.validate( params )
|
586
|
+
|
587
|
+
@validator.should be_okay()
|
588
|
+
@validator.should_not have_errors()
|
589
|
+
|
590
|
+
@validator[:email_constraint].should == 'jrandom@just-another-hacquer.fr'
|
591
|
+
end
|
592
|
+
|
593
|
+
ComplexAddresses = [
|
594
|
+
'ruby+hacker@random-example.org',
|
595
|
+
'"ruby hacker"@ph8675309.org',
|
596
|
+
'jrandom@[ruby hacquer].com',
|
597
|
+
'abcdefghijklmnopqrstuvwxyz@abcdefghijklmnopqrstuvwxyz',
|
598
|
+
]
|
599
|
+
ComplexAddresses.each do |addy|
|
600
|
+
it "accepts #{addy} for fields with email constraints" do
|
601
|
+
params = {'required' => '1', 'email_constraint' => addy}
|
602
|
+
|
603
|
+
@validator.validate( params )
|
604
|
+
|
605
|
+
@validator.should be_okay()
|
606
|
+
@validator.should_not have_errors()
|
607
|
+
|
608
|
+
@validator[:email_constraint].should == addy
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
|
613
|
+
BogusAddresses = [
|
614
|
+
'jrandom@hacquer com',
|
615
|
+
'jrandom@ruby hacquer.com',
|
616
|
+
'j random@rubyhacquer.com',
|
617
|
+
'j random@ruby|hacquer.com',
|
618
|
+
'j:random@rubyhacquer.com',
|
619
|
+
]
|
620
|
+
BogusAddresses.each do |addy|
|
621
|
+
it "rejects #{addy} for fields with email constraints" do
|
622
|
+
params = {'required' => '1', 'email_constraint' => addy}
|
623
|
+
|
624
|
+
@validator.validate( params )
|
625
|
+
|
626
|
+
@validator.should_not be_okay()
|
627
|
+
@validator.should have_errors()
|
628
|
+
|
629
|
+
@validator[:email_constraint].should be_nil()
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
it "accepts simple hosts for fields with host constraints" do
|
634
|
+
params = {'required' => '1', 'host_constraint' => 'deveiate.org'}
|
635
|
+
|
636
|
+
@validator.validate( params )
|
637
|
+
|
638
|
+
@validator.should be_okay()
|
639
|
+
@validator.should_not have_errors()
|
640
|
+
|
641
|
+
@validator[:host_constraint].should == 'deveiate.org'
|
642
|
+
end
|
643
|
+
|
644
|
+
it "accepts hyphenated hosts for fields with host constraints" do
|
645
|
+
params = {'required' => '1', 'host_constraint' => 'your-characters-can-fly.kr'}
|
646
|
+
|
647
|
+
@validator.validate( params )
|
648
|
+
|
649
|
+
@validator.should be_okay()
|
650
|
+
@validator.should_not have_errors()
|
651
|
+
|
652
|
+
@validator[:host_constraint].should == 'your-characters-can-fly.kr'
|
653
|
+
end
|
654
|
+
|
655
|
+
BogusHosts = [
|
656
|
+
'.',
|
657
|
+
'glah ',
|
658
|
+
'glah[lock]',
|
659
|
+
'glah.be$',
|
660
|
+
'indus«tree».com',
|
661
|
+
]
|
662
|
+
|
663
|
+
BogusHosts.each do |hostname|
|
664
|
+
it "rejects #{hostname} for fields with host constraints" do
|
665
|
+
params = {'required' => '1', 'host_constraint' => hostname}
|
666
|
+
|
667
|
+
@validator.validate( params )
|
668
|
+
|
669
|
+
@validator.should_not be_okay()
|
670
|
+
@validator.should have_errors()
|
671
|
+
|
672
|
+
@validator[:host_constraint].should be_nil()
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
it "accepts alpha characters for fields with alpha constraints" do
|
677
|
+
params = {'required' => '1', 'alpha_constraint' => 'abelincoln'}
|
678
|
+
|
679
|
+
@validator.validate( params )
|
680
|
+
|
681
|
+
@validator.should be_okay()
|
682
|
+
@validator.should_not have_errors()
|
683
|
+
|
684
|
+
@validator[:alpha_constraint].should == 'abelincoln'
|
685
|
+
end
|
686
|
+
|
687
|
+
it "rejects non-alpha characters for fields with alpha constraints" do
|
688
|
+
params = {'required' => '1', 'alpha_constraint' => 'duck45'}
|
689
|
+
|
690
|
+
@validator.validate( params )
|
691
|
+
|
692
|
+
@validator.should_not be_okay()
|
693
|
+
@validator.should have_errors()
|
694
|
+
|
695
|
+
@validator[:alpha_constraint].should be_nil()
|
696
|
+
end
|
697
|
+
|
698
|
+
### 'alphanumeric'
|
699
|
+
it "accepts alphanumeric characters for fields with alphanumeric constraints" do
|
700
|
+
params = {'required' => '1', 'alphanumeric_constraint' => 'zombieabe11'}
|
701
|
+
|
702
|
+
@validator.validate( params )
|
703
|
+
|
704
|
+
@validator.should be_okay()
|
705
|
+
@validator.should_not have_errors()
|
706
|
+
|
707
|
+
@validator[:alphanumeric_constraint].should == 'zombieabe11'
|
708
|
+
end
|
709
|
+
|
710
|
+
it "rejects non-alphanumeric characters for fields with alphanumeric constraints" do
|
711
|
+
params = {'required' => '1', 'alphanumeric_constraint' => 'duck!ling'}
|
712
|
+
|
713
|
+
@validator.validate( params )
|
714
|
+
|
715
|
+
@validator.should_not be_okay()
|
716
|
+
@validator.should have_errors()
|
717
|
+
|
718
|
+
@validator[:alphanumeric_constraint].should be_nil()
|
719
|
+
end
|
720
|
+
|
721
|
+
### 'printable'
|
722
|
+
it "accepts printable characters for fields with 'printable' constraints" do
|
723
|
+
test_content = <<-EOF
|
724
|
+
I saw you with some kind of medical apparatus strapped to your
|
725
|
+
spine. It was all glass and metal, a great crystaline hypodermic
|
726
|
+
spider, carrying you into the aether with a humming, crackling sound.
|
727
|
+
EOF
|
728
|
+
|
729
|
+
params = {
|
730
|
+
'required' => '1',
|
731
|
+
'printable_constraint' => test_content
|
732
|
+
}
|
733
|
+
|
734
|
+
@validator.validate( params )
|
735
|
+
|
736
|
+
@validator.should be_okay()
|
737
|
+
@validator.should_not have_errors()
|
738
|
+
|
739
|
+
@validator[:printable_constraint].should == test_content
|
740
|
+
end
|
741
|
+
|
742
|
+
it "rejects non-printable characters for fields with 'printable' constraints" do
|
743
|
+
params = {'required' => '1', 'printable_constraint' => %{\0Something cold\0}}
|
744
|
+
|
745
|
+
@validator.validate( params )
|
746
|
+
|
747
|
+
@validator.should_not be_okay()
|
748
|
+
@validator.should have_errors()
|
749
|
+
|
750
|
+
@validator[:printable_constraint].should be_nil()
|
751
|
+
end
|
752
|
+
|
753
|
+
|
754
|
+
it "accepts parameters for fields with Proc constraints if the Proc " +
|
755
|
+
"returns a true value" do
|
756
|
+
test_date = '2007-07-17'
|
757
|
+
params = {'required' => '1', 'proc_constraint' => test_date}
|
758
|
+
|
759
|
+
@validator.validate( params )
|
760
|
+
|
761
|
+
@validator.should be_okay()
|
762
|
+
@validator.should_not have_errors()
|
763
|
+
|
764
|
+
@validator[:proc_constraint].should == Date.parse( test_date )
|
765
|
+
end
|
766
|
+
|
767
|
+
it "rejects parameters for fields with Proc constraints if the Proc " +
|
768
|
+
"returns a false value" do
|
769
|
+
|
770
|
+
params = {'required' => '1', 'proc_constraint' => %{::::}}
|
771
|
+
|
772
|
+
@validator.validate( params )
|
773
|
+
|
774
|
+
@validator.should_not be_okay()
|
775
|
+
@validator.should have_errors()
|
776
|
+
|
777
|
+
@validator[:proc_constraint].should be_nil()
|
778
|
+
end
|
779
|
+
|
780
|
+
end
|
781
|
+
|