sinatra-acd 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/AUTHORS +61 -0
  4. data/CHANGES +1293 -0
  5. data/Gemfile +76 -0
  6. data/LICENSE +23 -0
  7. data/README.de.md +2864 -0
  8. data/README.es.md +2786 -0
  9. data/README.fr.md +2924 -0
  10. data/README.hu.md +694 -0
  11. data/README.ja.md +2726 -0
  12. data/README.ko.md +2832 -0
  13. data/README.md +2980 -0
  14. data/README.pt-br.md +965 -0
  15. data/README.pt-pt.md +791 -0
  16. data/README.ru.md +2799 -0
  17. data/README.zh.md +2158 -0
  18. data/Rakefile +199 -0
  19. data/examples/chat.rb +61 -0
  20. data/examples/simple.rb +3 -0
  21. data/examples/stream.ru +26 -0
  22. data/lib/sinatra.rb +4 -0
  23. data/lib/sinatra/base.rb +2044 -0
  24. data/lib/sinatra/images/404.png +0 -0
  25. data/lib/sinatra/images/500.png +0 -0
  26. data/lib/sinatra/main.rb +34 -0
  27. data/lib/sinatra/show_exceptions.rb +345 -0
  28. data/lib/sinatra/version.rb +3 -0
  29. data/sinatra.gemspec +19 -0
  30. data/test/asciidoctor_test.rb +72 -0
  31. data/test/base_test.rb +171 -0
  32. data/test/builder_test.rb +91 -0
  33. data/test/coffee_test.rb +90 -0
  34. data/test/compile_test.rb +183 -0
  35. data/test/contest.rb +100 -0
  36. data/test/creole_test.rb +65 -0
  37. data/test/delegator_test.rb +160 -0
  38. data/test/encoding_test.rb +20 -0
  39. data/test/erb_test.rb +116 -0
  40. data/test/extensions_test.rb +98 -0
  41. data/test/filter_test.rb +487 -0
  42. data/test/haml_test.rb +109 -0
  43. data/test/helper.rb +131 -0
  44. data/test/helpers_test.rb +1917 -0
  45. data/test/integration/app.rb +79 -0
  46. data/test/integration_helper.rb +236 -0
  47. data/test/integration_test.rb +104 -0
  48. data/test/less_test.rb +69 -0
  49. data/test/liquid_test.rb +77 -0
  50. data/test/mapped_error_test.rb +285 -0
  51. data/test/markaby_test.rb +80 -0
  52. data/test/markdown_test.rb +82 -0
  53. data/test/mediawiki_test.rb +68 -0
  54. data/test/middleware_test.rb +68 -0
  55. data/test/nokogiri_test.rb +67 -0
  56. data/test/public/favicon.ico +0 -0
  57. data/test/rabl_test.rb +89 -0
  58. data/test/rack_test.rb +45 -0
  59. data/test/radius_test.rb +59 -0
  60. data/test/rdoc_test.rb +66 -0
  61. data/test/readme_test.rb +130 -0
  62. data/test/request_test.rb +97 -0
  63. data/test/response_test.rb +63 -0
  64. data/test/result_test.rb +76 -0
  65. data/test/route_added_hook_test.rb +59 -0
  66. data/test/routing_test.rb +1412 -0
  67. data/test/sass_test.rb +115 -0
  68. data/test/scss_test.rb +88 -0
  69. data/test/server_test.rb +48 -0
  70. data/test/settings_test.rb +582 -0
  71. data/test/sinatra_test.rb +12 -0
  72. data/test/slim_test.rb +102 -0
  73. data/test/static_test.rb +236 -0
  74. data/test/streaming_test.rb +149 -0
  75. data/test/stylus_test.rb +90 -0
  76. data/test/templates_test.rb +382 -0
  77. data/test/textile_test.rb +65 -0
  78. data/test/views/a/in_a.str +1 -0
  79. data/test/views/ascii.erb +2 -0
  80. data/test/views/b/in_b.str +1 -0
  81. data/test/views/calc.html.erb +1 -0
  82. data/test/views/error.builder +3 -0
  83. data/test/views/error.erb +3 -0
  84. data/test/views/error.haml +3 -0
  85. data/test/views/error.sass +2 -0
  86. data/test/views/explicitly_nested.str +1 -0
  87. data/test/views/foo/hello.test +1 -0
  88. data/test/views/hello.asciidoc +1 -0
  89. data/test/views/hello.builder +1 -0
  90. data/test/views/hello.coffee +1 -0
  91. data/test/views/hello.creole +1 -0
  92. data/test/views/hello.erb +1 -0
  93. data/test/views/hello.haml +1 -0
  94. data/test/views/hello.less +5 -0
  95. data/test/views/hello.liquid +1 -0
  96. data/test/views/hello.mab +1 -0
  97. data/test/views/hello.md +1 -0
  98. data/test/views/hello.mediawiki +1 -0
  99. data/test/views/hello.nokogiri +1 -0
  100. data/test/views/hello.rabl +2 -0
  101. data/test/views/hello.radius +1 -0
  102. data/test/views/hello.rdoc +1 -0
  103. data/test/views/hello.sass +2 -0
  104. data/test/views/hello.scss +3 -0
  105. data/test/views/hello.slim +1 -0
  106. data/test/views/hello.str +1 -0
  107. data/test/views/hello.styl +2 -0
  108. data/test/views/hello.test +1 -0
  109. data/test/views/hello.textile +1 -0
  110. data/test/views/hello.wlang +1 -0
  111. data/test/views/hello.yajl +1 -0
  112. data/test/views/layout2.builder +3 -0
  113. data/test/views/layout2.erb +2 -0
  114. data/test/views/layout2.haml +2 -0
  115. data/test/views/layout2.liquid +2 -0
  116. data/test/views/layout2.mab +2 -0
  117. data/test/views/layout2.nokogiri +3 -0
  118. data/test/views/layout2.rabl +3 -0
  119. data/test/views/layout2.radius +2 -0
  120. data/test/views/layout2.slim +3 -0
  121. data/test/views/layout2.str +2 -0
  122. data/test/views/layout2.test +1 -0
  123. data/test/views/layout2.wlang +2 -0
  124. data/test/views/nested.str +1 -0
  125. data/test/views/utf8.erb +2 -0
  126. data/test/wlang_test.rb +87 -0
  127. data/test/yajl_test.rb +86 -0
  128. metadata +280 -0
@@ -0,0 +1,98 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class ExtensionsTest < Test::Unit::TestCase
4
+ module FooExtensions
5
+ def foo
6
+ end
7
+
8
+ private
9
+ def im_hiding_in_ur_foos
10
+ end
11
+ end
12
+
13
+ module BarExtensions
14
+ def bar
15
+ end
16
+ end
17
+
18
+ module BazExtensions
19
+ def baz
20
+ end
21
+ end
22
+
23
+ module QuuxExtensions
24
+ def quux
25
+ end
26
+ end
27
+
28
+ module PainExtensions
29
+ def foo=(name); end
30
+ def bar?(name); end
31
+ def fizz!(name); end
32
+ end
33
+
34
+ it 'will add the methods to the DSL for the class in which you register them and its subclasses' do
35
+ Sinatra::Base.register FooExtensions
36
+ assert Sinatra::Base.respond_to?(:foo)
37
+
38
+ Sinatra::Application.register BarExtensions
39
+ assert Sinatra::Application.respond_to?(:bar)
40
+ assert Sinatra::Application.respond_to?(:foo)
41
+ assert !Sinatra::Base.respond_to?(:bar)
42
+ end
43
+
44
+ it 'allows extending by passing a block' do
45
+ Sinatra::Base.register { def im_in_ur_anonymous_module; end }
46
+ assert Sinatra::Base.respond_to?(:im_in_ur_anonymous_module)
47
+ end
48
+
49
+ it 'will make sure any public methods added via Application#register are delegated to Sinatra::Delegator' do
50
+ Sinatra::Application.register FooExtensions
51
+ assert Sinatra::Delegator.private_instance_methods.
52
+ map { |m| m.to_sym }.include?(:foo)
53
+ assert !Sinatra::Delegator.private_instance_methods.
54
+ map { |m| m.to_sym }.include?(:im_hiding_in_ur_foos)
55
+ end
56
+
57
+ it 'will handle special method names' do
58
+ Sinatra::Application.register PainExtensions
59
+ assert Sinatra::Delegator.private_instance_methods.
60
+ map { |m| m.to_sym }.include?(:foo=)
61
+ assert Sinatra::Delegator.private_instance_methods.
62
+ map { |m| m.to_sym }.include?(:bar?)
63
+ assert Sinatra::Delegator.private_instance_methods.
64
+ map { |m| m.to_sym }.include?(:fizz!)
65
+ end
66
+
67
+ it 'will not delegate methods on Base#register' do
68
+ Sinatra::Base.register QuuxExtensions
69
+ assert !Sinatra::Delegator.private_instance_methods.include?("quux")
70
+ end
71
+
72
+ it 'will extend the Sinatra::Application application by default' do
73
+ Sinatra.register BazExtensions
74
+ assert !Sinatra::Base.respond_to?(:baz)
75
+ assert Sinatra::Application.respond_to?(:baz)
76
+ end
77
+
78
+ module BizzleExtension
79
+ def bizzle
80
+ bizzle_option
81
+ end
82
+
83
+ def self.registered(base)
84
+ fail "base should be BizzleApp" unless base == BizzleApp
85
+ fail "base should have already extended BizzleExtension" unless base.respond_to?(:bizzle)
86
+ base.set :bizzle_option, 'bizzle!'
87
+ end
88
+ end
89
+
90
+ class BizzleApp < Sinatra::Base
91
+ end
92
+
93
+ it 'sends .registered to the extension module after extending the class' do
94
+ BizzleApp.register BizzleExtension
95
+ assert_equal 'bizzle!', BizzleApp.bizzle_option
96
+ assert_equal 'bizzle!', BizzleApp.bizzle
97
+ end
98
+ end
@@ -0,0 +1,487 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class BeforeFilterTest < Test::Unit::TestCase
4
+ it "executes filters in the order defined" do
5
+ count = 0
6
+ mock_app do
7
+ get('/') { 'Hello World' }
8
+ before do
9
+ assert_equal 0, count
10
+ count = 1
11
+ end
12
+ before do
13
+ assert_equal 1, count
14
+ count = 2
15
+ end
16
+ end
17
+
18
+ get '/'
19
+ assert ok?
20
+ assert_equal 2, count
21
+ assert_equal 'Hello World', body
22
+ end
23
+
24
+ it "can modify the request" do
25
+ mock_app do
26
+ get('/foo') { 'foo' }
27
+ get('/bar') { 'bar' }
28
+ before { request.path_info = '/bar' }
29
+ end
30
+
31
+ get '/foo'
32
+ assert ok?
33
+ assert_equal 'bar', body
34
+ end
35
+
36
+ it "can modify instance variables available to routes" do
37
+ mock_app do
38
+ before { @foo = 'bar' }
39
+ get('/foo') { @foo }
40
+ end
41
+
42
+ get '/foo'
43
+ assert ok?
44
+ assert_equal 'bar', body
45
+ end
46
+
47
+ it "allows redirects" do
48
+ mock_app do
49
+ before { redirect '/bar' }
50
+ get('/foo') do
51
+ fail 'before block should have halted processing'
52
+ 'ORLY?!'
53
+ end
54
+ end
55
+
56
+ get '/foo'
57
+ assert redirect?
58
+ assert_equal 'http://example.org/bar', response['Location']
59
+ assert_equal '', body
60
+ end
61
+
62
+ it "does not modify the response with its return value" do
63
+ mock_app do
64
+ before { 'Hello World!' }
65
+ get('/foo') do
66
+ assert_equal [], response.body
67
+ 'cool'
68
+ end
69
+ end
70
+
71
+ get '/foo'
72
+ assert ok?
73
+ assert_equal 'cool', body
74
+ end
75
+
76
+ it "does modify the response with halt" do
77
+ mock_app do
78
+ before { halt 302, 'Hi' }
79
+ get '/foo' do
80
+ "should not happen"
81
+ end
82
+ end
83
+
84
+ get '/foo'
85
+ assert_equal 302, response.status
86
+ assert_equal 'Hi', body
87
+ end
88
+
89
+ it "gives you access to params" do
90
+ mock_app do
91
+ before { @foo = params['foo'] }
92
+ get('/foo') { @foo }
93
+ end
94
+
95
+ get '/foo?foo=cool'
96
+ assert ok?
97
+ assert_equal 'cool', body
98
+ end
99
+
100
+ it "properly unescapes parameters" do
101
+ mock_app do
102
+ before { @foo = params['foo'] }
103
+ get('/foo') { @foo }
104
+ end
105
+
106
+ get '/foo?foo=bar%3Abaz%2Fbend'
107
+ assert ok?
108
+ assert_equal 'bar:baz/bend', body
109
+ end
110
+
111
+ it "runs filters defined in superclasses" do
112
+ base = Class.new(Sinatra::Base)
113
+ base.before { @foo = 'hello from superclass' }
114
+
115
+ mock_app(base) { get('/foo') { @foo } }
116
+
117
+ get '/foo'
118
+ assert_equal 'hello from superclass', body
119
+ end
120
+
121
+ it 'does not run before filter when serving static files' do
122
+ ran_filter = false
123
+ mock_app do
124
+ before { ran_filter = true }
125
+ set :static, true
126
+ set :public_folder, File.dirname(__FILE__)
127
+ end
128
+ get "/#{File.basename(__FILE__)}"
129
+ assert ok?
130
+ assert_equal File.read(__FILE__), body
131
+ assert !ran_filter
132
+ end
133
+
134
+ it 'takes an optional route pattern' do
135
+ ran_filter = false
136
+ mock_app do
137
+ before("/b*") { ran_filter = true }
138
+ get('/foo') { }
139
+ get('/bar') { }
140
+ end
141
+ get '/foo'
142
+ assert !ran_filter
143
+ get '/bar'
144
+ assert ran_filter
145
+ end
146
+
147
+ it 'generates block arguments from route pattern' do
148
+ subpath = nil
149
+ mock_app do
150
+ before("/foo/:sub") { |s| subpath = s }
151
+ get('/foo/*') { }
152
+ end
153
+ get '/foo/bar'
154
+ assert_equal subpath, 'bar'
155
+ end
156
+
157
+ it 'can catch exceptions in before filters and handle them properly' do
158
+ doodle = ''
159
+ mock_app do
160
+ before do
161
+ doodle += 'This begins'
162
+ raise StandardError, "before"
163
+ end
164
+ get "/" do
165
+ doodle = 'and runs'
166
+ end
167
+ error 500 do
168
+ "Error handled #{env['sinatra.error'].message}"
169
+ end
170
+ end
171
+
172
+ doodle = ''
173
+ get '/'
174
+ assert_equal 'Error handled before', body
175
+ assert_equal 'This begins', doodle
176
+ end
177
+ end
178
+
179
+ class AfterFilterTest < Test::Unit::TestCase
180
+ it "executes before and after filters in correct order" do
181
+ invoked = 0
182
+ mock_app do
183
+ before { invoked = 2 }
184
+ get('/') { invoked += 2; 'hello' }
185
+ after { invoked *= 2 }
186
+ end
187
+
188
+ get '/'
189
+ assert ok?
190
+
191
+ assert_equal 8, invoked
192
+ end
193
+
194
+ it "executes filters in the order defined" do
195
+ count = 0
196
+ mock_app do
197
+ get('/') { 'Hello World' }
198
+ after do
199
+ assert_equal 0, count
200
+ count = 1
201
+ end
202
+ after do
203
+ assert_equal 1, count
204
+ count = 2
205
+ end
206
+ end
207
+
208
+ get '/'
209
+ assert ok?
210
+ assert_equal 2, count
211
+ assert_equal 'Hello World', body
212
+ end
213
+
214
+ it "allows redirects" do
215
+ mock_app do
216
+ get('/foo') { 'ORLY' }
217
+ after { redirect '/bar' }
218
+ end
219
+
220
+ get '/foo'
221
+ assert redirect?
222
+ assert_equal 'http://example.org/bar', response['Location']
223
+ assert_equal '', body
224
+ end
225
+
226
+ it "does not modify the response with its return value" do
227
+ mock_app do
228
+ get('/foo') { 'cool' }
229
+ after { 'Hello World!' }
230
+ end
231
+
232
+ get '/foo'
233
+ assert ok?
234
+ assert_equal 'cool', body
235
+ end
236
+
237
+ it "does modify the response with halt" do
238
+ mock_app do
239
+ get '/foo' do
240
+ "should not be returned"
241
+ end
242
+ after { halt 302, 'Hi' }
243
+ end
244
+
245
+ get '/foo'
246
+ assert_equal 302, response.status
247
+ assert_equal 'Hi', body
248
+ end
249
+
250
+ it "runs filters defined in superclasses" do
251
+ count = 2
252
+ base = Class.new(Sinatra::Base)
253
+ base.after { count *= 2 }
254
+ mock_app(base) do
255
+ get('/foo') do
256
+ count += 2
257
+ "ok"
258
+ end
259
+ end
260
+
261
+ get '/foo'
262
+ assert_equal 8, count
263
+ end
264
+
265
+ it 'does not run after filter when serving static files' do
266
+ ran_filter = false
267
+ mock_app do
268
+ after { ran_filter = true }
269
+ set :static, true
270
+ set :public_folder, File.dirname(__FILE__)
271
+ end
272
+ get "/#{File.basename(__FILE__)}"
273
+ assert ok?
274
+ assert_equal File.read(__FILE__), body
275
+ assert !ran_filter
276
+ end
277
+
278
+ it 'takes an optional route pattern' do
279
+ ran_filter = false
280
+ mock_app do
281
+ after("/b*") { ran_filter = true }
282
+ get('/foo') { }
283
+ get('/bar') { }
284
+ end
285
+ get '/foo'
286
+ assert !ran_filter
287
+ get '/bar'
288
+ assert ran_filter
289
+ end
290
+
291
+ it 'changes to path_info from a pattern matching before filter are respected when routing' do
292
+ mock_app do
293
+ before('/foo') { request.path_info = '/bar' }
294
+ get('/bar') { 'blah' }
295
+ end
296
+ get '/foo'
297
+ assert ok?
298
+ assert_equal 'blah', body
299
+ end
300
+
301
+ it 'generates block arguments from route pattern' do
302
+ subpath = nil
303
+ mock_app do
304
+ after("/foo/:sub") { |s| subpath = s }
305
+ get('/foo/*') { }
306
+ end
307
+ get '/foo/bar'
308
+ assert_equal subpath, 'bar'
309
+ end
310
+
311
+ it 'is possible to access url params from the route param' do
312
+ ran = false
313
+ mock_app do
314
+ get('/foo/*') { }
315
+ before('/foo/:sub') do
316
+ assert_equal params[:sub], 'bar'
317
+ ran = true
318
+ end
319
+ end
320
+ get '/foo/bar'
321
+ assert ran
322
+ end
323
+
324
+ it 'is possible to apply host_name conditions to before filters with no path' do
325
+ ran = false
326
+ mock_app do
327
+ before(:host_name => 'example.com') { ran = true }
328
+ get('/') { 'welcome' }
329
+ end
330
+ get('/', {}, { 'HTTP_HOST' => 'example.org' })
331
+ assert !ran
332
+ get('/', {}, { 'HTTP_HOST' => 'example.com' })
333
+ assert ran
334
+ end
335
+
336
+ it 'is possible to apply host_name conditions to before filters with a path' do
337
+ ran = false
338
+ mock_app do
339
+ before('/foo', :host_name => 'example.com') { ran = true }
340
+ get('/') { 'welcome' }
341
+ end
342
+ get('/', {}, { 'HTTP_HOST' => 'example.com' })
343
+ assert !ran
344
+ get('/foo', {}, { 'HTTP_HOST' => 'example.org' })
345
+ assert !ran
346
+ get('/foo', {}, { 'HTTP_HOST' => 'example.com' })
347
+ assert ran
348
+ end
349
+
350
+ it 'is possible to apply host_name conditions to after filters with no path' do
351
+ ran = false
352
+ mock_app do
353
+ after(:host_name => 'example.com') { ran = true }
354
+ get('/') { 'welcome' }
355
+ end
356
+ get('/', {}, { 'HTTP_HOST' => 'example.org' })
357
+ assert !ran
358
+ get('/', {}, { 'HTTP_HOST' => 'example.com' })
359
+ assert ran
360
+ end
361
+
362
+ it 'is possible to apply host_name conditions to after filters with a path' do
363
+ ran = false
364
+ mock_app do
365
+ after('/foo', :host_name => 'example.com') { ran = true }
366
+ get('/') { 'welcome' }
367
+ end
368
+ get('/', {}, { 'HTTP_HOST' => 'example.com' })
369
+ assert !ran
370
+ get('/foo', {}, { 'HTTP_HOST' => 'example.org' })
371
+ assert !ran
372
+ get('/foo', {}, { 'HTTP_HOST' => 'example.com' })
373
+ assert ran
374
+ end
375
+
376
+ it 'is possible to apply user_agent conditions to before filters with no path' do
377
+ ran = false
378
+ mock_app do
379
+ before(:user_agent => /foo/) { ran = true }
380
+ get('/') { 'welcome' }
381
+ end
382
+ get('/', {}, { 'HTTP_USER_AGENT' => 'bar' })
383
+ assert !ran
384
+ get('/', {}, { 'HTTP_USER_AGENT' => 'foo' })
385
+ assert ran
386
+ end
387
+
388
+ it 'is possible to apply user_agent conditions to before filters with a path' do
389
+ ran = false
390
+ mock_app do
391
+ before('/foo', :user_agent => /foo/) { ran = true }
392
+ get('/') { 'welcome' }
393
+ end
394
+ get('/', {}, { 'HTTP_USER_AGENT' => 'foo' })
395
+ assert !ran
396
+ get('/foo', {}, { 'HTTP_USER_AGENT' => 'bar' })
397
+ assert !ran
398
+ get('/foo', {}, { 'HTTP_USER_AGENT' => 'foo' })
399
+ assert ran
400
+ end
401
+
402
+ it 'can add params' do
403
+ mock_app do
404
+ before { params['foo'] = 'bar' }
405
+ get('/') { params['foo'] }
406
+ end
407
+
408
+ get '/'
409
+ assert_body 'bar'
410
+ end
411
+
412
+ it 'can remove params' do
413
+ mock_app do
414
+ before { params.delete('foo') }
415
+ get('/') { params['foo'].to_s }
416
+ end
417
+
418
+ get '/?foo=bar'
419
+ assert_body ''
420
+ end
421
+
422
+ it 'is possible to apply user_agent conditions to after filters with no path' do
423
+ ran = false
424
+ mock_app do
425
+ after(:user_agent => /foo/) { ran = true }
426
+ get('/') { 'welcome' }
427
+ end
428
+ get('/', {}, { 'HTTP_USER_AGENT' => 'bar' })
429
+ assert !ran
430
+ get('/', {}, { 'HTTP_USER_AGENT' => 'foo' })
431
+ assert ran
432
+ end
433
+
434
+ it 'is possible to apply user_agent conditions to after filters with a path' do
435
+ ran = false
436
+ mock_app do
437
+ after('/foo', :user_agent => /foo/) { ran = true }
438
+ get('/') { 'welcome' }
439
+ end
440
+ get('/', {}, { 'HTTP_USER_AGENT' => 'foo' })
441
+ assert !ran
442
+ get('/foo', {}, { 'HTTP_USER_AGENT' => 'bar' })
443
+ assert !ran
444
+ get('/foo', {}, { 'HTTP_USER_AGENT' => 'foo' })
445
+ assert ran
446
+ end
447
+
448
+ it 'only triggers provides condition if conforms with current Content-Type' do
449
+ mock_app do
450
+ before(:provides => :txt) { @type = 'txt' }
451
+ before(:provides => :html) { @type = 'html' }
452
+ get('/') { @type }
453
+ end
454
+
455
+ get('/', {}, { 'HTTP_ACCEPT' => '*/*' })
456
+ assert_body 'txt'
457
+ end
458
+
459
+ it 'can catch exceptions in after filters and handle them properly' do
460
+ doodle = ''
461
+ mock_app do
462
+ after do
463
+ doodle += ' and after'
464
+ raise StandardError, "after"
465
+ end
466
+ get "/foo" do
467
+ doodle = 'Been now'
468
+ raise StandardError, "now"
469
+ end
470
+ get "/" do
471
+ doodle = 'Been now'
472
+ end
473
+ error 500 do
474
+ "Error handled #{env['sinatra.error'].message}"
475
+ end
476
+ end
477
+
478
+ get '/foo'
479
+ assert_equal 'Error handled now', body
480
+ assert_equal 'Been now and after', doodle
481
+
482
+ doodle = ''
483
+ get '/'
484
+ assert_equal 'Error handled after', body
485
+ assert_equal 'Been now and after', doodle
486
+ end
487
+ end