strelka 0.0.1pre4 → 0.0.1.pre129

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/History.rdoc +1 -1
  2. data/IDEAS.rdoc +62 -0
  3. data/Manifest.txt +38 -7
  4. data/README.rdoc +124 -5
  5. data/Rakefile +22 -6
  6. data/bin/leash +102 -157
  7. data/contrib/hoetemplate/.autotest.erb +23 -0
  8. data/contrib/hoetemplate/History.rdoc.erb +4 -0
  9. data/contrib/hoetemplate/Manifest.txt.erb +8 -0
  10. data/contrib/hoetemplate/README.rdoc.erb +17 -0
  11. data/contrib/hoetemplate/Rakefile.erb +24 -0
  12. data/contrib/hoetemplate/data/file_name/apps/file_name_app +36 -0
  13. data/contrib/hoetemplate/data/file_name/templates/layout.tmpl.erb +13 -0
  14. data/contrib/hoetemplate/data/file_name/templates/top.tmpl.erb +8 -0
  15. data/contrib/hoetemplate/lib/file_name.rb.erb +18 -0
  16. data/contrib/hoetemplate/spec/file_name_spec.rb.erb +21 -0
  17. data/data/strelka/apps/hello-world +30 -0
  18. data/lib/strelka/app/defaultrouter.rb +49 -30
  19. data/lib/strelka/app/errors.rb +121 -0
  20. data/lib/strelka/app/exclusiverouter.rb +40 -0
  21. data/lib/strelka/app/filters.rb +18 -7
  22. data/lib/strelka/app/negotiation.rb +122 -0
  23. data/lib/strelka/app/parameters.rb +171 -14
  24. data/lib/strelka/app/paramvalidator.rb +751 -0
  25. data/lib/strelka/app/plugins.rb +66 -46
  26. data/lib/strelka/app/restresources.rb +499 -0
  27. data/lib/strelka/app/router.rb +73 -0
  28. data/lib/strelka/app/routing.rb +140 -18
  29. data/lib/strelka/app/templating.rb +12 -3
  30. data/lib/strelka/app.rb +174 -24
  31. data/lib/strelka/constants.rb +0 -20
  32. data/lib/strelka/exceptions.rb +29 -0
  33. data/lib/strelka/httprequest/acceptparams.rb +377 -0
  34. data/lib/strelka/httprequest/negotiation.rb +257 -0
  35. data/lib/strelka/httprequest.rb +155 -7
  36. data/lib/strelka/httpresponse/negotiation.rb +579 -0
  37. data/lib/strelka/httpresponse.rb +140 -0
  38. data/lib/strelka/logging.rb +4 -1
  39. data/lib/strelka/mixins.rb +53 -0
  40. data/lib/strelka.rb +22 -1
  41. data/spec/data/error.tmpl +1 -0
  42. data/spec/lib/constants.rb +0 -1
  43. data/spec/lib/helpers.rb +21 -0
  44. data/spec/strelka/app/defaultrouter_spec.rb +41 -35
  45. data/spec/strelka/app/errors_spec.rb +212 -0
  46. data/spec/strelka/app/exclusiverouter_spec.rb +220 -0
  47. data/spec/strelka/app/filters_spec.rb +196 -0
  48. data/spec/strelka/app/negotiation_spec.rb +73 -0
  49. data/spec/strelka/app/parameters_spec.rb +149 -0
  50. data/spec/strelka/app/paramvalidator_spec.rb +1059 -0
  51. data/spec/strelka/app/plugins_spec.rb +26 -19
  52. data/spec/strelka/app/restresources_spec.rb +393 -0
  53. data/spec/strelka/app/router_spec.rb +63 -0
  54. data/spec/strelka/app/routing_spec.rb +183 -9
  55. data/spec/strelka/app/templating_spec.rb +1 -2
  56. data/spec/strelka/app_spec.rb +265 -32
  57. data/spec/strelka/exceptions_spec.rb +53 -0
  58. data/spec/strelka/httprequest/acceptparams_spec.rb +282 -0
  59. data/spec/strelka/httprequest/negotiation_spec.rb +246 -0
  60. data/spec/strelka/httprequest_spec.rb +204 -14
  61. data/spec/strelka/httpresponse/negotiation_spec.rb +464 -0
  62. data/spec/strelka/httpresponse_spec.rb +114 -0
  63. data/spec/strelka/mixins_spec.rb +99 -0
  64. data.tar.gz.sig +1 -0
  65. metadata +175 -79
  66. metadata.gz.sig +2 -0
  67. data/IDEAS.textile +0 -174
  68. data/data/strelka/apps/strelka-admin +0 -65
  69. data/data/strelka/apps/strelka-setup +0 -26
  70. data/data/strelka/bootstrap-config.rb +0 -34
  71. data/data/strelka/templates/admin/console.tmpl +0 -21
  72. data/data/strelka/templates/layout.tmpl +0 -30
  73. data/lib/strelka/process.rb +0 -19
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
7
+ }
8
+
9
+ require 'rspec'
10
+
11
+ require 'spec/lib/helpers'
12
+
13
+ require 'strelka'
14
+ require 'strelka/app/exclusiverouter'
15
+
16
+
17
+ #####################################################################
18
+ ### C O N T E X T S
19
+ #####################################################################
20
+
21
+ describe Strelka::App::ExclusiveRouter do
22
+
23
+ before( :all ) do
24
+ setup_logging( :fatal )
25
+ @request_factory = Mongrel2::RequestFactory.new( route: '/user' )
26
+ end
27
+
28
+ before( :each ) do
29
+ @router = Strelka::App::ExclusiveRouter.new
30
+ end
31
+
32
+ after( :all ) do
33
+ reset_logging()
34
+ end
35
+
36
+ context "a router with routes for 'foo', 'foo/bar'" do
37
+
38
+ before( :each ) do
39
+ @router.add_route( :GET, ['foo'], route(:foo) )
40
+ @router.add_route( :GET, ['foo','bar'], route(:foo_bar) )
41
+ end
42
+
43
+ it "doesn't route /user/foo/bar/baz" do
44
+ req = @request_factory.get( '/user/foo/bar/baz' )
45
+ @router.route_request( req ).should be_nil()
46
+ end
47
+
48
+ it "routes /user/foo/bar to the foo/bar action" do
49
+ req = @request_factory.get( '/user/foo/bar' )
50
+ @router.route_request( req ).should match_route( :foo_bar )
51
+ end
52
+
53
+ it "routes /user/foo/bar?limit=10 to the foo/bar action" do
54
+ req = @request_factory.get( '/user/foo/bar?limit=10' )
55
+ @router.route_request( req ).should match_route( :foo_bar )
56
+ end
57
+
58
+ it "routes /user/foo to the foo action" do
59
+ req = @request_factory.get( '/user/foo' )
60
+ @router.route_request( req ).should match_route( :foo )
61
+ end
62
+
63
+ it "doesn't route /user" do
64
+ req = @request_factory.get( '/user' )
65
+ @router.route_request( req ).should be_nil()
66
+ end
67
+
68
+ it "doesn't route /user/other" do
69
+ req = @request_factory.get( '/user/other' )
70
+ @router.route_request( req ).should be_nil()
71
+ end
72
+
73
+ end
74
+
75
+ context "a router with routes for 'foo', 'foo/bar', and a fallback action" do
76
+
77
+ before( :each ) do
78
+ @router.add_route( :GET, [], route(:fallback) )
79
+ @router.add_route( :GET, ['foo'], route(:foo) )
80
+ @router.add_route( :GET, ['foo','bar'], route(:foo_bar) )
81
+ end
82
+
83
+ it "doesn't route /user/foo/bar/baz" do
84
+ req = @request_factory.get( '/user/foo/bar/baz' )
85
+ @router.route_request( req ).should be_nil()
86
+ end
87
+
88
+ it "routes /user/foo/bar to the foo/bar action" do
89
+ req = @request_factory.get( '/user/foo/bar' )
90
+ @router.route_request( req ).should match_route( :foo_bar )
91
+ end
92
+
93
+ it "routes /user/foo to the foo action" do
94
+ req = @request_factory.get( '/user/foo' )
95
+ @router.route_request( req ).should match_route( :foo )
96
+ end
97
+
98
+ it "routes /user to the fallback action" do
99
+ req = @request_factory.get( '/user' )
100
+ @router.route_request( req ).should match_route( :fallback )
101
+ end
102
+
103
+ it "doesn't route /user/other" do
104
+ req = @request_factory.get( '/user/other' )
105
+ @router.route_request( req ).should be_nil()
106
+ end
107
+
108
+ end
109
+
110
+ context "a router with routes for 'foo', 'foo/\w{3}', and 'foo/\w{6}'" do
111
+
112
+ before( :each ) do
113
+ @router.add_route( :GET, ['foo'], route(:foo) )
114
+ @router.add_route( :GET, ['foo',/\w{3}/], route(:foo_three) )
115
+ @router.add_route( :GET, ['foo',/\w{6}/], route(:foo_six) )
116
+ end
117
+
118
+ it "doesn't route /user/foo/barbim/baz" do
119
+ req = @request_factory.get( '/user/foo/barbim/baz' )
120
+ @router.route_request( req ).should be_nil()
121
+ end
122
+
123
+ it "routes /user/foo/barbat to the foo/\w{6} action" do
124
+ req = @request_factory.get( '/user/foo/barbat' )
125
+ @router.route_request( req ).should match_route( :foo_six )
126
+ end
127
+
128
+ it "doesn't route /user/foo/bar/baz" do
129
+ req = @request_factory.get( '/user/foo/bar/baz' )
130
+ @router.route_request( req ).should be_nil()
131
+ end
132
+
133
+ it "routes /user/foo/bar to the foo/\w{3} action" do
134
+ req = @request_factory.get( '/user/foo/bar' )
135
+ @router.route_request( req ).should match_route( :foo_three )
136
+ end
137
+
138
+ it "routes /user/foo to the foo action" do
139
+ req = @request_factory.get( '/user/foo' )
140
+ @router.route_request( req ).should match_route( :foo )
141
+ end
142
+
143
+ it "doesn't route /user" do
144
+ req = @request_factory.get( '/user' )
145
+ @router.route_request( req ).should be_nil()
146
+ end
147
+
148
+ it "doesn't route /user/other" do
149
+ req = @request_factory.get( '/user/other' )
150
+ @router.route_request( req ).should be_nil()
151
+ end
152
+
153
+ end
154
+
155
+ # get '/foo/\w{3}'
156
+ # get '/foo/\d+'
157
+
158
+ context "a router with routes for: 'foo/\w{3}', then 'foo/\d+'" do
159
+
160
+ before( :each ) do
161
+ @router.add_route( :GET, ['foo',/\w{3}/], route(:foo_three) )
162
+ @router.add_route( :GET, ['foo',/\d+/], route(:foo_digit) )
163
+ end
164
+
165
+ it "routes /user/foo/1 to the foo/\d+ action" do
166
+ req = @request_factory.get( '/user/foo/1' )
167
+ @router.route_request( req ).should match_route( :foo_digit )
168
+ end
169
+
170
+ it "routes /user/foo/12 to the foo/\d+ action" do
171
+ req = @request_factory.get( '/user/foo/12' )
172
+ @router.route_request( req ).should match_route( :foo_digit )
173
+ end
174
+
175
+ it "routes /user/foo/123 to the foo/\w{3} action" do
176
+ req = @request_factory.get( '/user/foo/123' )
177
+ @router.route_request( req ).should match_route( :foo_three )
178
+ end
179
+
180
+ it "routes /user/foo/1234 to the foo/\d+ action" do
181
+ req = @request_factory.get( '/user/foo/1234' )
182
+ @router.route_request( req ).should match_route( :foo_digit )
183
+ end
184
+
185
+ end
186
+
187
+ # get '/foo/\d+'
188
+ # get '/foo/\w{3}'
189
+
190
+ context "a router with routes for: 'foo/\d+', then 'foo/\w{3}'" do
191
+
192
+ before( :each ) do
193
+ @router.add_route( :GET, ['foo',/\d+/], route(:foo_digit) )
194
+ @router.add_route( :GET, ['foo',/\w{3}/], route(:foo_three) )
195
+ end
196
+
197
+ it "routes /user/foo/1 to the foo/\d+ action" do
198
+ req = @request_factory.get( '/user/foo/1' )
199
+ @router.route_request( req ).should match_route( :foo_digit )
200
+ end
201
+
202
+ it "routes /user/foo/12 to the foo/\d+ action" do
203
+ req = @request_factory.get( '/user/foo/12' )
204
+ @router.route_request( req ).should match_route( :foo_digit )
205
+ end
206
+
207
+ it "routes /user/foo/123 to the foo/\d+ action" do
208
+ req = @request_factory.get( '/user/foo/123' )
209
+ @router.route_request( req ).should match_route( :foo_digit )
210
+ end
211
+
212
+ it "routes /user/foo/1234 to the foo/\d+ action" do
213
+ req = @request_factory.get( '/user/foo/1234' )
214
+ @router.route_request( req ).should match_route( :foo_digit )
215
+ end
216
+
217
+ end
218
+
219
+ end
220
+
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
7
+ }
8
+
9
+ require 'rspec'
10
+
11
+ require 'spec/lib/helpers'
12
+
13
+ require 'strelka'
14
+ require 'strelka/app/plugins'
15
+ require 'strelka/app/filters'
16
+
17
+ require 'strelka/behavior/plugin'
18
+
19
+
20
+ #####################################################################
21
+ ### C O N T E X T S
22
+ #####################################################################
23
+
24
+ describe Strelka::App::Filters do
25
+
26
+ before( :all ) do
27
+ setup_logging( :fatal )
28
+ @request_factory = Mongrel2::RequestFactory.new( route: '' )
29
+ end
30
+
31
+ after( :all ) do
32
+ reset_logging()
33
+ end
34
+
35
+
36
+ it_should_behave_like( "A Strelka::App Plugin" )
37
+
38
+
39
+ describe "an including App" do
40
+
41
+ before( :each ) do
42
+ Strelka.log.debug "Creating a new Strelka::App"
43
+ @app = Class.new( Strelka::App ) do
44
+ plugin :filters
45
+ def initialize( appid='params-test', sspec=TEST_SEND_SPEC, rspec=TEST_RECV_SPEC )
46
+ super
47
+ end
48
+ end
49
+ Strelka.log.debug " new instance is: %p, filters array: 0x%016x" %
50
+ [ @app, @app.filters.object_id * 2 ]
51
+ end
52
+
53
+
54
+ it "has a Hash of filters" do
55
+ @app.filters.should be_a( Hash )
56
+ end
57
+
58
+
59
+ describe "that doesn't declare any filters" do
60
+
61
+ it "doesn't have any request filters" do
62
+ @app.request_filters.should be_empty()
63
+ end
64
+
65
+ it "doesn't have any response filters" do
66
+ @app.response_filters.should be_empty()
67
+ end
68
+
69
+ end
70
+
71
+
72
+ describe "that declares a filter without a phase" do
73
+
74
+ before( :each ) do
75
+ @app.class_eval do
76
+ filter do |reqres|
77
+ if reqres.respond_to?( :notes )
78
+ reqres.notes[:test] = 'filtered notes'
79
+ else
80
+ reqres.body = 'filtered body'
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ after( :each ) do
87
+ @app.filters[:request].clear
88
+ @app.filters[:response].clear
89
+ @app.filters[:both].clear
90
+ end
91
+
92
+
93
+ it "has a single request filter" do
94
+ @app.request_filters.should have(1).member
95
+ end
96
+
97
+ it "has a single response filter" do
98
+ @app.response_filters.should have(1).member
99
+ end
100
+
101
+ it "passes both the request and the response through it" do
102
+ req = @request_factory.get( '/account/118811' )
103
+
104
+ res = @app.new.handle( req )
105
+
106
+ req.notes[:test].should == 'filtered notes'
107
+ res.body.should == 'filtered body'
108
+ end
109
+
110
+ end
111
+
112
+ describe "that declares a request filter" do
113
+
114
+ before( :each ) do
115
+ @app.class_eval do
116
+ filter( :request ) do |reqres|
117
+ if reqres.respond_to?( :notes )
118
+ reqres.notes[:test] = 'filtered notes'
119
+ else
120
+ reqres.body = 'filtered body'
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ after( :each ) do
127
+ @app.filters[:request].clear
128
+ @app.filters[:response].clear
129
+ @app.filters[:both].clear
130
+ end
131
+
132
+
133
+ it "has a single request filter" do
134
+ @app.request_filters.should have(1).member
135
+ end
136
+
137
+ it "has no response filters" do
138
+ @app.response_filters.should be_empty()
139
+ end
140
+
141
+ it "passes just the request through it" do
142
+ req = @request_factory.get( '/account/118811' )
143
+
144
+ res = @app.new.handle( req )
145
+
146
+ req.notes[:test].should == 'filtered notes'
147
+ res.body.should_not == 'filtered body'
148
+ end
149
+
150
+ end
151
+
152
+ describe "that declares a response filter" do
153
+
154
+ before( :each ) do
155
+ @app.class_eval do
156
+ filter( :response ) do |reqres|
157
+ if reqres.respond_to?( :notes )
158
+ reqres.notes[:test] = 'filtered notes'
159
+ else
160
+ reqres.body = 'filtered body'
161
+ end
162
+ end
163
+ end
164
+ end
165
+
166
+ after( :each ) do
167
+ @app.filters[:request].clear
168
+ @app.filters[:response].clear
169
+ @app.filters[:both].clear
170
+ end
171
+
172
+
173
+ it "has no request filters" do
174
+ @app.request_filters.should be_empty()
175
+ end
176
+
177
+ it "has no response filters" do
178
+ @app.response_filters.should have(1).member
179
+ end
180
+
181
+ it "passes just the response through it" do
182
+ req = @request_factory.get( '/account/118811' )
183
+
184
+ res = @app.new.handle( req )
185
+
186
+ req.notes[:test].should == {}
187
+ res.body.should == 'filtered body'
188
+ end
189
+
190
+ end
191
+
192
+ end
193
+
194
+
195
+ end
196
+
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
7
+ }
8
+
9
+ require 'rspec'
10
+
11
+ require 'spec/lib/helpers'
12
+
13
+ require 'strelka'
14
+ require 'strelka/app/plugins'
15
+ require 'strelka/app/negotiation'
16
+ require 'strelka/behavior/plugin'
17
+
18
+
19
+ #####################################################################
20
+ ### C O N T E X T S
21
+ #####################################################################
22
+
23
+ describe Strelka::App::Negotiation do
24
+
25
+
26
+ before( :all ) do
27
+ setup_logging( :fatal )
28
+ @request_factory = Mongrel2::RequestFactory.new( route: '/service/user' )
29
+ end
30
+
31
+ after( :all ) do
32
+ reset_logging()
33
+ end
34
+
35
+
36
+ it_should_behave_like( "A Strelka::App Plugin" )
37
+
38
+
39
+ describe "an including App" do
40
+
41
+ before( :each ) do
42
+ @app = Class.new( Strelka::App ) do
43
+ plugin :negotiation
44
+ def initialize( appid='conneg-test', sspec=TEST_SEND_SPEC, rspec=TEST_RECV_SPEC )
45
+ super
46
+ end
47
+ end
48
+ end
49
+
50
+ after( :each ) do
51
+ @app = nil
52
+ end
53
+
54
+
55
+ it "gets requests that have been extended with content-negotiation" do
56
+ req = @request_factory.get( '/service/user/estark' )
57
+ @app.new.handle( req )
58
+ req.singleton_class.included_modules.
59
+ should include( Strelka::HTTPRequest::Negotiation )
60
+ end
61
+
62
+ it "gets responses that have been extended with content-negotiation" do
63
+ req = @request_factory.get( '/service/user/estark' )
64
+ res = @app.new.handle( req )
65
+ res.singleton_class.included_modules.
66
+ should include( Strelka::HTTPResponse::Negotiation )
67
+ end
68
+
69
+ end
70
+
71
+
72
+ end
73
+
@@ -24,6 +24,7 @@ describe Strelka::App::Parameters do
24
24
 
25
25
  before( :all ) do
26
26
  setup_logging( :fatal )
27
+ @request_factory = Mongrel2::RequestFactory.new( route: '/user' )
27
28
  end
28
29
 
29
30
  after( :all ) do
@@ -39,9 +40,16 @@ describe Strelka::App::Parameters do
39
40
  before( :each ) do
40
41
  @app = Class.new( Strelka::App ) do
41
42
  plugin :parameters
43
+ def initialize( appid='params-test', sspec=TEST_SEND_SPEC, rspec=TEST_RECV_SPEC )
44
+ super
45
+ end
42
46
  end
43
47
  end
44
48
 
49
+ after( :each ) do
50
+ @app = nil
51
+ end
52
+
45
53
  it "has a parameters Hash" do
46
54
  @app.parameters.should be_a( Hash )
47
55
  end
@@ -56,6 +64,91 @@ describe Strelka::App::Parameters do
56
64
  should include( :constraint => /(?<username>(?i-mx:\w+))/ )
57
65
  end
58
66
 
67
+ it "can declare a parameter with an Array validation" do
68
+ @app.class_eval do
69
+ param :username, [:printable, lambda {|str| str.length <= 16 }]
70
+ end
71
+
72
+ @app.parameters.should have( 1 ).member
73
+ @app.parameters[:username][:constraint][0].should == :printable
74
+ @app.parameters[:username][:constraint][1].should be_an_instance_of( Proc )
75
+ end
76
+
77
+ it "can declare a parameter with a Hash validation" do
78
+ @app.class_eval do
79
+ param :username, {'ambrel' => 'A. Hotchgah'}
80
+ end
81
+
82
+ @app.parameters.should have( 1 ).member
83
+ @app.parameters[ :username ].
84
+ should include( :constraint => {'ambrel' => 'A. Hotchgah'} )
85
+ end
86
+
87
+ it "can declare a parameter with a matcher validation" do
88
+ @app.class_eval do
89
+ param :host, :hostname
90
+ end
91
+
92
+ @app.parameters.should have( 1 ).member
93
+ @app.parameters[ :host ].should include( :constraint => :hostname )
94
+ end
95
+
96
+ it "can declare a parameter with a validation pattern and a description" do
97
+ @app.class_eval do
98
+ param :username, /\w+/i, "The user's login"
99
+ end
100
+
101
+ @app.parameters.should have( 1 ).member
102
+ @app.parameters[ :username ].should include( :required => false )
103
+ @app.parameters[ :username ].should include( :constraint => /(?<username>(?i-mx:\w+))/ )
104
+ @app.parameters[ :username ].should include( :description => "The user's login" )
105
+ end
106
+
107
+ it "can declare a parameter with an Array validation and a description" do
108
+ @app.class_eval do
109
+ param :username, ['johnny5', 'ariel', 'hotah'], "The user's login"
110
+ end
111
+
112
+ @app.parameters.should have( 1 ).member
113
+ @app.parameters[ :username ].
114
+ should include( :constraint => ['johnny5', 'ariel', 'hotah'] )
115
+ @app.parameters[ :username ].should include( :description => "The user's login" )
116
+ end
117
+
118
+ it "can declare a parameter with just a description" do
119
+ @app.class_eval do
120
+ param :uuid, "UUID string"
121
+ end
122
+
123
+ @app.parameters.should have( 1 ).member
124
+ @app.parameters[ :uuid ].should include( :description => "UUID string" )
125
+ @app.parameters[ :uuid ].should include( :constraint => :uuid )
126
+ end
127
+
128
+ it "can declare a parameter with a validation pattern and a flag" do
129
+ @app.class_eval do
130
+ param :username, /\w+/i, :untaint
131
+ end
132
+
133
+ @app.parameters.should have( 1 ).member
134
+ @app.parameters[ :username ].should include( :required => false )
135
+ @app.parameters[ :username ].should include( :untaint => true )
136
+ @app.parameters[ :username ].should include( :constraint => /(?<username>(?i-mx:\w+))/ )
137
+ @app.parameters[ :username ].should include( :description => nil )
138
+ end
139
+
140
+ it "can declare a parameter with a validation Array and a flag" do
141
+ @app.class_eval do
142
+ param :username, ['amhel', 'hotah', 'aurelii'], :required
143
+ end
144
+
145
+ @app.parameters.should have( 1 ).member
146
+ @app.parameters[ :username ].should include( :required => true )
147
+ @app.parameters[ :username ].
148
+ should include( :constraint => ['amhel', 'hotah', 'aurelii'] )
149
+ @app.parameters[ :username ].should include( :description => nil )
150
+ end
151
+
59
152
  it "inherits parameters from its superclass" do
60
153
  @app.class_eval do
61
154
  param :username, /\w+/i
@@ -67,6 +160,62 @@ describe Strelka::App::Parameters do
67
160
  should include( :constraint => /(?<username>(?i-mx:\w+))/ )
68
161
  end
69
162
 
163
+ describe "instance" do
164
+
165
+ before( :each ) do
166
+ @app.class_eval do
167
+ param :username, /\w+/, :required
168
+ param :id, /\d+/
169
+ end
170
+ end
171
+
172
+ it "gets requests that have had their parameters replaced with a validator" do
173
+ req = @request_factory.get( '/user/search' )
174
+ @app.new.handle( req )
175
+
176
+ req.params.should be_a( Strelka::App::ParamValidator )
177
+ req.params.should have_errors()
178
+ req.params.error_messages.should == ["Missing value for 'Username'"]
179
+ end
180
+
181
+ it "validates parameters from the request" do
182
+ req = @request_factory.get( '/user/search?username=anheptoh'.taint )
183
+ @app.new.handle( req )
184
+
185
+ req.params.should be_a( Strelka::App::ParamValidator )
186
+ req.params.should be_okay()
187
+ req.params.should_not have_errors()
188
+ req.params[:username].should == 'anheptoh'
189
+ req.params[:username].should be_tainted()
190
+ end
191
+
192
+ it "untaints all parameters if global untainting is enabled" do
193
+ @app.class_eval do
194
+ untaint_all_constraints true
195
+ end
196
+
197
+ @app.untaint_all_constraints.should be_true()
198
+ req = @request_factory.get( '/user/search?username=shereshnaheth'.taint )
199
+ @app.new.handle( req )
200
+
201
+ req.params[:username].should == 'shereshnaheth'
202
+ req.params[:username].should_not be_tainted()
203
+ end
204
+
205
+ it "untaints parameters flagged for untainting" do
206
+ @app.class_eval do
207
+ param :message, :printable, :untaint
208
+ end
209
+
210
+ req = @request_factory.get( '/user/search?message=I+love+the+circus.'.taint )
211
+ @app.new.handle( req )
212
+
213
+ req.params[:message].should_not be_tainted()
214
+ req.params[:message].should == 'I love the circus.'
215
+ end
216
+
217
+ end
218
+
70
219
  end
71
220
 
72
221