aldebaran 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/.gitignore +13 -0
  2. data/.travis.yml +16 -0
  3. data/.yardopts +4 -0
  4. data/AUTHORS +4 -0
  5. data/Gemfile +77 -0
  6. data/KNOWN_ISSUES +5 -0
  7. data/LICENSE +22 -0
  8. data/README.rdoc +1900 -0
  9. data/Rakefile +175 -0
  10. data/aldebaran.gemspec +19 -0
  11. data/lib/aldebaran.rb +7 -0
  12. data/lib/aldebaran/base.rb +1600 -0
  13. data/lib/aldebaran/images/404.png +0 -0
  14. data/lib/aldebaran/images/500.png +0 -0
  15. data/lib/aldebaran/main.rb +28 -0
  16. data/lib/aldebaran/showexceptions.rb +340 -0
  17. data/lib/aldebaran/version.rb +3 -0
  18. data/test/aldebaran_test.rb +17 -0
  19. data/test/base_test.rb +160 -0
  20. data/test/builder_test.rb +95 -0
  21. data/test/coffee_test.rb +92 -0
  22. data/test/contest.rb +98 -0
  23. data/test/creole_test.rb +65 -0
  24. data/test/delegator_test.rb +162 -0
  25. data/test/encoding_test.rb +20 -0
  26. data/test/erb_test.rb +104 -0
  27. data/test/extensions_test.rb +100 -0
  28. data/test/filter_test.rb +397 -0
  29. data/test/haml_test.rb +101 -0
  30. data/test/helper.rb +115 -0
  31. data/test/helpers_test.rb +1192 -0
  32. data/test/less_test.rb +67 -0
  33. data/test/liquid_test.rb +59 -0
  34. data/test/mapped_error_test.rb +259 -0
  35. data/test/markaby_test.rb +80 -0
  36. data/test/markdown_test.rb +81 -0
  37. data/test/middleware_test.rb +68 -0
  38. data/test/nokogiri_test.rb +69 -0
  39. data/test/public/favicon.ico +0 -0
  40. data/test/radius_test.rb +59 -0
  41. data/test/rdoc_test.rb +65 -0
  42. data/test/readme_test.rb +136 -0
  43. data/test/request_test.rb +45 -0
  44. data/test/response_test.rb +61 -0
  45. data/test/result_test.rb +98 -0
  46. data/test/route_added_hook_test.rb +59 -0
  47. data/test/routing_test.rb +1096 -0
  48. data/test/sass_test.rb +115 -0
  49. data/test/scss_test.rb +88 -0
  50. data/test/server_test.rb +48 -0
  51. data/test/settings_test.rb +493 -0
  52. data/test/slim_test.rb +98 -0
  53. data/test/static_test.rb +178 -0
  54. data/test/streaming_test.rb +100 -0
  55. data/test/templates_test.rb +298 -0
  56. data/test/textile_test.rb +65 -0
  57. data/test/views/a/in_a.str +1 -0
  58. data/test/views/ascii.erb +2 -0
  59. data/test/views/b/in_b.str +1 -0
  60. data/test/views/calc.html.erb +1 -0
  61. data/test/views/error.builder +3 -0
  62. data/test/views/error.erb +3 -0
  63. data/test/views/error.haml +3 -0
  64. data/test/views/error.sass +2 -0
  65. data/test/views/explicitly_nested.str +1 -0
  66. data/test/views/foo/hello.test +1 -0
  67. data/test/views/hello.builder +1 -0
  68. data/test/views/hello.coffee +1 -0
  69. data/test/views/hello.creole +1 -0
  70. data/test/views/hello.erb +1 -0
  71. data/test/views/hello.haml +1 -0
  72. data/test/views/hello.less +5 -0
  73. data/test/views/hello.liquid +1 -0
  74. data/test/views/hello.mab +1 -0
  75. data/test/views/hello.md +1 -0
  76. data/test/views/hello.nokogiri +1 -0
  77. data/test/views/hello.radius +1 -0
  78. data/test/views/hello.rdoc +1 -0
  79. data/test/views/hello.sass +2 -0
  80. data/test/views/hello.scss +3 -0
  81. data/test/views/hello.slim +1 -0
  82. data/test/views/hello.str +1 -0
  83. data/test/views/hello.test +1 -0
  84. data/test/views/hello.textile +1 -0
  85. data/test/views/layout2.builder +3 -0
  86. data/test/views/layout2.erb +2 -0
  87. data/test/views/layout2.haml +2 -0
  88. data/test/views/layout2.liquid +2 -0
  89. data/test/views/layout2.mab +2 -0
  90. data/test/views/layout2.nokogiri +3 -0
  91. data/test/views/layout2.radius +2 -0
  92. data/test/views/layout2.slim +3 -0
  93. data/test/views/layout2.str +2 -0
  94. data/test/views/layout2.test +1 -0
  95. data/test/views/nested.str +1 -0
  96. data/test/views/utf8.erb +2 -0
  97. metadata +231 -0
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path('../helper', __FILE__)
3
+ require 'erb'
4
+
5
+ class BaseTest < Test::Unit::TestCase
6
+ setup do
7
+ @base = aldebaran.new(aldebaran::Base)
8
+ @base.set :views, File.dirname(__FILE__) + "/views"
9
+ end
10
+
11
+ it 'allows unicode strings in ascii templates per default (1.9)' do
12
+ next unless defined? Encoding
13
+ @base.new!.erb(File.read(@base.views + "/ascii.erb").encode("ASCII"), {}, :value => "åkej")
14
+ end
15
+
16
+ it 'allows ascii strings in unicode templates per default (1.9)' do
17
+ next unless defined? Encoding
18
+ @base.new!.erb(:utf8, {}, :value => "Some Lyrics".encode("ASCII"))
19
+ end
20
+ end
@@ -0,0 +1,104 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class ERBTest < Test::Unit::TestCase
4
+ def engine
5
+ Tilt::ERBTemplate
6
+ end
7
+
8
+ def setup
9
+ Tilt.prefer engine, :erb
10
+ super
11
+ end
12
+
13
+ def erb_app(&block)
14
+ mock_app {
15
+ set :views, File.dirname(__FILE__) + '/views'
16
+ get '/', &block
17
+ }
18
+ get '/'
19
+ end
20
+
21
+ it 'uses the correct engine' do
22
+ assert_equal engine, Tilt[:erb]
23
+ end
24
+
25
+ it 'renders inline ERB strings' do
26
+ erb_app { erb '<%= 1 + 1 %>' }
27
+ assert ok?
28
+ assert_equal '2', body
29
+ end
30
+
31
+ it 'renders .erb files in views path' do
32
+ erb_app { erb :hello }
33
+ assert ok?
34
+ assert_equal "Hello World\n", body
35
+ end
36
+
37
+ it 'takes a :locals option' do
38
+ erb_app {
39
+ locals = {:foo => 'Bar'}
40
+ erb '<%= foo %>', :locals => locals
41
+ }
42
+ assert ok?
43
+ assert_equal 'Bar', body
44
+ end
45
+
46
+ it "renders with inline layouts" do
47
+ mock_app {
48
+ layout { 'THIS. IS. <%= yield.upcase %>!' }
49
+ get('/') { erb 'Sparta' }
50
+ }
51
+ get '/'
52
+ assert ok?
53
+ assert_equal 'THIS. IS. SPARTA!', body
54
+ end
55
+
56
+ it "renders with file layouts" do
57
+ erb_app {
58
+ erb 'Hello World', :layout => :layout2
59
+ }
60
+ assert ok?
61
+ assert_body "ERB Layout!\nHello World"
62
+ end
63
+
64
+ it "renders erb with blocks" do
65
+ mock_app {
66
+ def container
67
+ @_out_buf << "THIS."
68
+ yield
69
+ @_out_buf << "SPARTA!"
70
+ end
71
+ def is; "IS." end
72
+ get '/' do
73
+ erb '<% container do %> <%= is %> <% end %>'
74
+ end
75
+ }
76
+ get '/'
77
+ assert ok?
78
+ assert_equal 'THIS. IS. SPARTA!', body
79
+ end
80
+
81
+ it "can be used in a nested fashion for partials and whatnot" do
82
+ mock_app {
83
+ template(:inner) { "<inner><%= 'hi' %></inner>" }
84
+ template(:outer) { "<outer><%= erb :inner %></outer>" }
85
+ get '/' do
86
+ erb :outer
87
+ end
88
+ }
89
+
90
+ get '/'
91
+ assert ok?
92
+ assert_equal '<outer><inner>hi</inner></outer>', body
93
+ end
94
+ end
95
+
96
+
97
+ begin
98
+ require 'erubis'
99
+ class ErubisTest < ERBTest
100
+ def engine; Tilt::ErubisTemplate end
101
+ end
102
+ rescue LoadError
103
+ warn "#{$!.to_s}: skipping erubis tests"
104
+ end
@@ -0,0 +1,100 @@
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
+ aldebaran::Base.register FooExtensions
36
+ assert aldebaran::Base.respond_to?(:foo)
37
+
38
+ aldebaran::Application.register BarExtensions
39
+ assert aldebaran::Application.respond_to?(:bar)
40
+ assert aldebaran::Application.respond_to?(:foo)
41
+ assert !aldebaran::Base.respond_to?(:bar)
42
+ end
43
+
44
+ it 'allows extending by passing a block' do
45
+ aldebaran::Base.register {
46
+ def im_in_ur_anonymous_module; end
47
+ }
48
+ assert aldebaran::Base.respond_to?(:im_in_ur_anonymous_module)
49
+ end
50
+
51
+ it 'will make sure any public methods added via Application#register are delegated to aldebaran::Delegator' do
52
+ aldebaran::Application.register FooExtensions
53
+ assert aldebaran::Delegator.private_instance_methods.
54
+ map { |m| m.to_sym }.include?(:foo)
55
+ assert !aldebaran::Delegator.private_instance_methods.
56
+ map { |m| m.to_sym }.include?(:im_hiding_in_ur_foos)
57
+ end
58
+
59
+ it 'will handle special method names' do
60
+ aldebaran::Application.register PainExtensions
61
+ assert aldebaran::Delegator.private_instance_methods.
62
+ map { |m| m.to_sym }.include?(:foo=)
63
+ assert aldebaran::Delegator.private_instance_methods.
64
+ map { |m| m.to_sym }.include?(:bar?)
65
+ assert aldebaran::Delegator.private_instance_methods.
66
+ map { |m| m.to_sym }.include?(:fizz!)
67
+ end
68
+
69
+ it 'will not delegate methods on Base#register' do
70
+ aldebaran::Base.register QuuxExtensions
71
+ assert !aldebaran::Delegator.private_instance_methods.include?("quux")
72
+ end
73
+
74
+ it 'will extend the aldebaran::Application application by default' do
75
+ aldebaran.register BazExtensions
76
+ assert !aldebaran::Base.respond_to?(:baz)
77
+ assert aldebaran::Application.respond_to?(:baz)
78
+ end
79
+
80
+ module BizzleExtension
81
+ def bizzle
82
+ bizzle_option
83
+ end
84
+
85
+ def self.registered(base)
86
+ fail "base should be BizzleApp" unless base == BizzleApp
87
+ fail "base should have already extended BizzleExtension" unless base.respond_to?(:bizzle)
88
+ base.set :bizzle_option, 'bizzle!'
89
+ end
90
+ end
91
+
92
+ class BizzleApp < aldebaran::Base
93
+ end
94
+
95
+ it 'sends .registered to the extension module after extending the class' do
96
+ BizzleApp.register BizzleExtension
97
+ assert_equal 'bizzle!', BizzleApp.bizzle_option
98
+ assert_equal 'bizzle!', BizzleApp.bizzle
99
+ end
100
+ end
@@ -0,0 +1,397 @@
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 {
9
+ assert_equal 0, count
10
+ count = 1
11
+ }
12
+ before {
13
+ assert_equal 1, count
14
+ count = 2
15
+ }
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 {
26
+ get('/foo') { 'foo' }
27
+ get('/bar') { 'bar' }
28
+ before { request.path_info = '/bar' }
29
+ }
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 {
38
+ before { @foo = 'bar' }
39
+ get('/foo') { @foo }
40
+ }
41
+
42
+ get '/foo'
43
+ assert ok?
44
+ assert_equal 'bar', body
45
+ end
46
+
47
+ it "allows redirects" do
48
+ mock_app {
49
+ before { redirect '/bar' }
50
+ get('/foo') do
51
+ fail 'before block should have halted processing'
52
+ 'ORLY?!'
53
+ end
54
+ }
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 {
64
+ before { 'Hello World!' }
65
+ get '/foo' do
66
+ assert_equal [], response.body
67
+ 'cool'
68
+ end
69
+ }
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 {
78
+ before { halt 302, 'Hi' }
79
+ get '/foo' do
80
+ "should not happen"
81
+ end
82
+ }
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 {
91
+ before { @foo = params['foo'] }
92
+ get('/foo') { @foo }
93
+ }
94
+
95
+ get '/foo?foo=cool'
96
+ assert ok?
97
+ assert_equal 'cool', body
98
+ end
99
+
100
+ it "runs filters defined in superclasses" do
101
+ base = Class.new(aldebaran::Base)
102
+ base.before { @foo = 'hello from superclass' }
103
+
104
+ mock_app(base) {
105
+ get('/foo') { @foo }
106
+ }
107
+
108
+ get '/foo'
109
+ assert_equal 'hello from superclass', body
110
+ end
111
+
112
+ it 'does not run before filter when serving static files' do
113
+ ran_filter = false
114
+ mock_app {
115
+ before { ran_filter = true }
116
+ set :static, true
117
+ set :public_folder, File.dirname(__FILE__)
118
+ }
119
+ get "/#{File.basename(__FILE__)}"
120
+ assert ok?
121
+ assert_equal File.read(__FILE__), body
122
+ assert !ran_filter
123
+ end
124
+
125
+ it 'takes an optional route pattern' do
126
+ ran_filter = false
127
+ mock_app do
128
+ before("/b*") { ran_filter = true }
129
+ get('/foo') { }
130
+ get('/bar') { }
131
+ end
132
+ get '/foo'
133
+ assert !ran_filter
134
+ get '/bar'
135
+ assert ran_filter
136
+ end
137
+
138
+ it 'generates block arguments from route pattern' do
139
+ subpath = nil
140
+ mock_app do
141
+ before("/foo/:sub") { |s| subpath = s }
142
+ get('/foo/*') { }
143
+ end
144
+ get '/foo/bar'
145
+ assert_equal subpath, 'bar'
146
+ end
147
+ end
148
+
149
+ class AfterFilterTest < Test::Unit::TestCase
150
+ it "executes filters in the order defined" do
151
+ invoked = 0
152
+ mock_app do
153
+ before { invoked = 2 }
154
+ get('/') { invoked += 2 }
155
+ after { invoked *= 2 }
156
+ end
157
+
158
+ get '/'
159
+ assert ok?
160
+
161
+ assert_equal 8, invoked
162
+ end
163
+
164
+ it "executes filters in the order defined" do
165
+ count = 0
166
+ mock_app do
167
+ get('/') { 'Hello World' }
168
+ after {
169
+ assert_equal 0, count
170
+ count = 1
171
+ }
172
+ after {
173
+ assert_equal 1, count
174
+ count = 2
175
+ }
176
+ end
177
+
178
+ get '/'
179
+ assert ok?
180
+ assert_equal 2, count
181
+ assert_equal 'Hello World', body
182
+ end
183
+
184
+ it "allows redirects" do
185
+ mock_app {
186
+ get('/foo') { 'ORLY' }
187
+ after { redirect '/bar' }
188
+ }
189
+
190
+ get '/foo'
191
+ assert redirect?
192
+ assert_equal 'http://example.org/bar', response['Location']
193
+ assert_equal '', body
194
+ end
195
+
196
+ it "does not modify the response with its return value" do
197
+ mock_app {
198
+ get('/foo') { 'cool' }
199
+ after { 'Hello World!' }
200
+ }
201
+
202
+ get '/foo'
203
+ assert ok?
204
+ assert_equal 'cool', body
205
+ end
206
+
207
+ it "does modify the response with halt" do
208
+ mock_app {
209
+ get '/foo' do
210
+ "should not be returned"
211
+ end
212
+ after { halt 302, 'Hi' }
213
+ }
214
+
215
+ get '/foo'
216
+ assert_equal 302, response.status
217
+ assert_equal 'Hi', body
218
+ end
219
+
220
+ it "runs filters defined in superclasses" do
221
+ count = 2
222
+ base = Class.new(aldebaran::Base)
223
+ base.after { count *= 2 }
224
+ mock_app(base) do
225
+ get('/foo') do
226
+ count += 2
227
+ "ok"
228
+ end
229
+ end
230
+
231
+ get '/foo'
232
+ assert_equal 8, count
233
+ end
234
+
235
+ it 'does not run after filter when serving static files' do
236
+ ran_filter = false
237
+ mock_app {
238
+ after { ran_filter = true }
239
+ set :static, true
240
+ set :public_folder, File.dirname(__FILE__)
241
+ }
242
+ get "/#{File.basename(__FILE__)}"
243
+ assert ok?
244
+ assert_equal File.read(__FILE__), body
245
+ assert !ran_filter
246
+ end
247
+
248
+ it 'takes an optional route pattern' do
249
+ ran_filter = false
250
+ mock_app do
251
+ after("/b*") { ran_filter = true }
252
+ get('/foo') { }
253
+ get('/bar') { }
254
+ end
255
+ get '/foo'
256
+ assert !ran_filter
257
+ get '/bar'
258
+ assert ran_filter
259
+ end
260
+
261
+ it 'changes to path_info from a pattern matching before filter are respoected when routing' do
262
+ mock_app do
263
+ before('/foo') { request.path_info = '/bar' }
264
+ get('/bar') { 'blah' }
265
+ end
266
+ get '/foo'
267
+ assert ok?
268
+ assert_equal 'blah', body
269
+ end
270
+
271
+ it 'generates block arguments from route pattern' do
272
+ subpath = nil
273
+ mock_app do
274
+ after("/foo/:sub") { |s| subpath = s }
275
+ get('/foo/*') { }
276
+ end
277
+ get '/foo/bar'
278
+ assert_equal subpath, 'bar'
279
+ end
280
+
281
+ it 'is possible to access url params from the route param' do
282
+ ran = false
283
+ mock_app do
284
+ get('/foo/*') { }
285
+ before('/foo/:sub') do
286
+ assert_equal params[:sub], 'bar'
287
+ ran = true
288
+ end
289
+ end
290
+ get '/foo/bar'
291
+ assert ran
292
+ end
293
+
294
+ it 'is possible to apply host_name conditions to before filters with no path' do
295
+ ran = false
296
+ mock_app do
297
+ before(:host_name => 'example.com') { ran = true }
298
+ get('/') { 'welcome' }
299
+ end
300
+ get '/', {}, { 'HTTP_HOST' => 'example.org' }
301
+ assert !ran
302
+ get '/', {}, { 'HTTP_HOST' => 'example.com' }
303
+ assert ran
304
+ end
305
+
306
+ it 'is possible to apply host_name conditions to before filters with a path' do
307
+ ran = false
308
+ mock_app do
309
+ before('/foo', :host_name => 'example.com') { ran = true }
310
+ get('/') { 'welcome' }
311
+ end
312
+ get '/', {}, { 'HTTP_HOST' => 'example.com' }
313
+ assert !ran
314
+ get '/foo', {}, { 'HTTP_HOST' => 'example.org' }
315
+ assert !ran
316
+ get '/foo', {}, { 'HTTP_HOST' => 'example.com' }
317
+ assert ran
318
+ end
319
+
320
+ it 'is possible to apply host_name conditions to after filters with no path' do
321
+ ran = false
322
+ mock_app do
323
+ after(:host_name => 'example.com') { ran = true }
324
+ get('/') { 'welcome' }
325
+ end
326
+ get '/', {}, { 'HTTP_HOST' => 'example.org' }
327
+ assert !ran
328
+ get '/', {}, { 'HTTP_HOST' => 'example.com' }
329
+ assert ran
330
+ end
331
+
332
+ it 'is possible to apply host_name conditions to after filters with a path' do
333
+ ran = false
334
+ mock_app do
335
+ after('/foo', :host_name => 'example.com') { ran = true }
336
+ get('/') { 'welcome' }
337
+ end
338
+ get '/', {}, { 'HTTP_HOST' => 'example.com' }
339
+ assert !ran
340
+ get '/foo', {}, { 'HTTP_HOST' => 'example.org' }
341
+ assert !ran
342
+ get '/foo', {}, { 'HTTP_HOST' => 'example.com' }
343
+ assert ran
344
+ end
345
+
346
+ it 'is possible to apply user_agent conditions to before filters with no path' do
347
+ ran = false
348
+ mock_app do
349
+ before(:user_agent => /foo/) { ran = true }
350
+ get('/') { 'welcome' }
351
+ end
352
+ get '/', {}, { 'HTTP_USER_AGENT' => 'bar' }
353
+ assert !ran
354
+ get '/', {}, { 'HTTP_USER_AGENT' => 'foo' }
355
+ assert ran
356
+ end
357
+
358
+ it 'is possible to apply user_agent conditions to before filters with a path' do
359
+ ran = false
360
+ mock_app do
361
+ before('/foo', :user_agent => /foo/) { ran = true }
362
+ get('/') { 'welcome' }
363
+ end
364
+ get '/', {}, { 'HTTP_USER_AGENT' => 'foo' }
365
+ assert !ran
366
+ get '/foo', {}, { 'HTTP_USER_AGENT' => 'bar' }
367
+ assert !ran
368
+ get '/foo', {}, { 'HTTP_USER_AGENT' => 'foo' }
369
+ assert ran
370
+ end
371
+
372
+ it 'is possible to apply user_agent conditions to after filters with no path' do
373
+ ran = false
374
+ mock_app do
375
+ after(:user_agent => /foo/) { ran = true }
376
+ get('/') { 'welcome' }
377
+ end
378
+ get '/', {}, { 'HTTP_USER_AGENT' => 'bar' }
379
+ assert !ran
380
+ get '/', {}, { 'HTTP_USER_AGENT' => 'foo' }
381
+ assert ran
382
+ end
383
+
384
+ it 'is possible to apply user_agent conditions to before filters with a path' do
385
+ ran = false
386
+ mock_app do
387
+ after('/foo', :user_agent => /foo/) { ran = true }
388
+ get('/') { 'welcome' }
389
+ end
390
+ get '/', {}, { 'HTTP_USER_AGENT' => 'foo' }
391
+ assert !ran
392
+ get '/foo', {}, { 'HTTP_USER_AGENT' => 'bar' }
393
+ assert !ran
394
+ get '/foo', {}, { 'HTTP_USER_AGENT' => 'foo' }
395
+ assert ran
396
+ end
397
+ end