aldebaran 1.0.1

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 (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,101 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ begin
4
+ require 'haml'
5
+
6
+ class HAMLTest < Test::Unit::TestCase
7
+ def haml_app(&block)
8
+ mock_app {
9
+ set :views, File.dirname(__FILE__) + '/views'
10
+ get '/', &block
11
+ }
12
+ get '/'
13
+ end
14
+
15
+ it 'renders inline HAML strings' do
16
+ haml_app { haml '%h1 Hiya' }
17
+ assert ok?
18
+ assert_equal "<h1>Hiya</h1>\n", body
19
+ end
20
+
21
+ it 'renders .haml files in views path' do
22
+ haml_app { haml :hello }
23
+ assert ok?
24
+ assert_equal "<h1>Hello From Haml</h1>\n", body
25
+ end
26
+
27
+ it "renders with inline layouts" do
28
+ mock_app {
29
+ layout { %q(%h1= 'THIS. IS. ' + yield.upcase) }
30
+ get('/') { haml '%em Sparta' }
31
+ }
32
+ get '/'
33
+ assert ok?
34
+ assert_equal "<h1>THIS. IS. <EM>SPARTA</EM></h1>\n", body
35
+ end
36
+
37
+ it "renders with file layouts" do
38
+ haml_app {
39
+ haml 'Hello World', :layout => :layout2
40
+ }
41
+ assert ok?
42
+ assert_equal "<h1>HAML Layout!</h1>\n<p>Hello World</p>\n", body
43
+ end
44
+
45
+ it "raises error if template not found" do
46
+ mock_app {
47
+ get('/') { haml :no_such_template }
48
+ }
49
+ assert_raise(Errno::ENOENT) { get('/') }
50
+ end
51
+
52
+ it "passes HAML options to the Haml engine" do
53
+ mock_app {
54
+ get '/' do
55
+ haml "!!!\n%h1 Hello World", :format => :html5
56
+ end
57
+ }
58
+ get '/'
59
+ assert ok?
60
+ assert_equal "<!DOCTYPE html>\n<h1>Hello World</h1>\n", body
61
+ end
62
+
63
+ it "passes default HAML options to the Haml engine" do
64
+ mock_app {
65
+ set :haml, {:format => :html5}
66
+ get '/' do
67
+ haml "!!!\n%h1 Hello World"
68
+ end
69
+ }
70
+ get '/'
71
+ assert ok?
72
+ assert_equal "<!DOCTYPE html>\n<h1>Hello World</h1>\n", body
73
+ end
74
+
75
+ it "merges the default HAML options with the overrides and passes them to the Haml engine" do
76
+ mock_app {
77
+ set :haml, {:format => :html5, :attr_wrapper => '"'} # default HAML attr are <tag attr='single-quoted'>
78
+ get '/' do
79
+ haml "!!!\n%h1{:class => :header} Hello World"
80
+ end
81
+ get '/html4' do
82
+ haml "!!!\n%h1{:class => 'header'} Hello World", :format => :html4
83
+ end
84
+ }
85
+ get '/'
86
+ assert ok?
87
+ assert_equal "<!DOCTYPE html>\n<h1 class=\"header\">Hello World</h1>\n", body
88
+ get '/html4'
89
+ assert ok?
90
+ assert_match(/^<!DOCTYPE html PUBLIC (.*) HTML 4.01/, body)
91
+ end
92
+
93
+ it "is possible to pass locals" do
94
+ haml_app { haml "= foo", :locals => { :foo => 'bar' }}
95
+ assert_equal "bar\n", body
96
+ end
97
+ end
98
+
99
+ rescue LoadError
100
+ warn "#{$!.to_s}: skipping haml tests"
101
+ end
@@ -0,0 +1,115 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+ Encoding.default_external = "UTF-8" if defined? Encoding
3
+
4
+ RUBY_ENGINE = 'ruby' unless defined? RUBY_ENGINE
5
+
6
+ begin
7
+ require 'rack'
8
+ rescue LoadError
9
+ require 'rubygems'
10
+ require 'rack'
11
+ end
12
+
13
+ testdir = File.dirname(__FILE__)
14
+ $LOAD_PATH.unshift testdir unless $LOAD_PATH.include?(testdir)
15
+
16
+ libdir = File.dirname(File.dirname(__FILE__)) + '/lib'
17
+ $LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
18
+
19
+ require 'contest'
20
+ require 'rack/test'
21
+ require 'aldebaran/base'
22
+
23
+ class aldebaran::Base
24
+ # Allow assertions in request context
25
+ include Test::Unit::Assertions
26
+ end
27
+
28
+ class Rack::Builder
29
+ def include?(middleware)
30
+ @ins.any? { |m| p m ; middleware === m }
31
+ end
32
+ end
33
+
34
+ aldebaran::Base.set :environment, :test
35
+
36
+ class Test::Unit::TestCase
37
+ include Rack::Test::Methods
38
+
39
+ class << self
40
+ alias_method :it, :test
41
+ alias_method :section, :context
42
+ end
43
+
44
+ def self.example(desc = nil, &block)
45
+ @example_count = 0 unless instance_variable_defined? :@example_count
46
+ @example_count += 1
47
+ it(desc || "Example #{@example_count}", &block)
48
+ end
49
+
50
+ alias_method :response, :last_response
51
+
52
+ setup do
53
+ aldebaran::Base.set :environment, :test
54
+ end
55
+
56
+ # Sets up a aldebaran::Base subclass defined with the block
57
+ # given. Used in setup or individual spec methods to establish
58
+ # the application.
59
+ def mock_app(base=aldebaran::Base, &block)
60
+ @app = aldebaran.new(base, &block)
61
+ end
62
+
63
+ def app
64
+ Rack::Lint.new(@app)
65
+ end
66
+
67
+ def body
68
+ response.body.to_s
69
+ end
70
+
71
+ def assert_body(value)
72
+ assert_equal value.lstrip.gsub(/\s*\n\s*/, ""), body.lstrip.gsub(/\s*\n\s*/, "")
73
+ end
74
+
75
+ def assert_like(a,b)
76
+ pattern = /id=['"][^"']*["']|\s+/
77
+ assert_equal a.strip.gsub(pattern, ""), b.strip.gsub(pattern, "")
78
+ end
79
+
80
+ def assert_include(str, substr)
81
+ assert str.include?(substr), "expected #{str.inspect} to include #{substr.inspect}"
82
+ end
83
+
84
+ def options(uri, params = {}, env = {}, &block)
85
+ request(uri, env.merge(:method => "OPTIONS", :params => params), &block)
86
+ end
87
+
88
+ def patch(uri, params = {}, env = {}, &block)
89
+ request(uri, env.merge(:method => "PATCH", :params => params), &block)
90
+ end
91
+
92
+ # Delegate other missing methods to response.
93
+ def method_missing(name, *args, &block)
94
+ if response && response.respond_to?(name)
95
+ response.send(name, *args, &block)
96
+ else
97
+ super
98
+ end
99
+ rescue Rack::Test::Error
100
+ super
101
+ end
102
+
103
+ # Also check response since we delegate there.
104
+ def respond_to?(symbol, include_private=false)
105
+ super || (response && response.respond_to?(symbol, include_private))
106
+ end
107
+
108
+ # Do not output warnings for the duration of the block.
109
+ def silence_warnings
110
+ $VERBOSE, v = nil, $VERBOSE
111
+ yield
112
+ ensure
113
+ $VERBOSE = v
114
+ end
115
+ end
@@ -0,0 +1,1192 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+ require 'date'
3
+
4
+ class HelpersTest < Test::Unit::TestCase
5
+ def test_default
6
+ assert true
7
+ end
8
+
9
+ def status_app(code, &block)
10
+ code += 2 if [204, 205, 304].include? code
11
+ block ||= proc { }
12
+ mock_app do
13
+ get '/' do
14
+ status code
15
+ instance_eval(&block).inspect
16
+ end
17
+ end
18
+ get '/'
19
+ end
20
+
21
+ describe 'status' do
22
+ it 'sets the response status code' do
23
+ status_app 207
24
+ assert_equal 207, response.status
25
+ end
26
+ end
27
+
28
+ describe 'not_found?' do
29
+ it 'is true for status == 404' do
30
+ status_app(404) { not_found? }
31
+ assert_body 'true'
32
+ end
33
+
34
+ it 'is false for status > 404' do
35
+ status_app(405) { not_found? }
36
+ assert_body 'false'
37
+ end
38
+
39
+ it 'is false for status < 404' do
40
+ status_app(403) { not_found? }
41
+ assert_body 'false'
42
+ end
43
+ end
44
+
45
+ describe 'informational?' do
46
+ it 'is true for 1xx status' do
47
+ status_app(100 + rand(100)) { informational? }
48
+ assert_body 'true'
49
+ end
50
+
51
+ it 'is false for status > 199' do
52
+ status_app(200 + rand(400)) { informational? }
53
+ assert_body 'false'
54
+ end
55
+ end
56
+
57
+ describe 'success?' do
58
+ it 'is true for 2xx status' do
59
+ status_app(200 + rand(100)) { success? }
60
+ assert_body 'true'
61
+ end
62
+
63
+ it 'is false for status < 200' do
64
+ status_app(100 + rand(100)) { success? }
65
+ assert_body 'false'
66
+ end
67
+
68
+ it 'is false for status > 299' do
69
+ status_app(300 + rand(300)) { success? }
70
+ assert_body 'false'
71
+ end
72
+ end
73
+
74
+ describe 'redirect?' do
75
+ it 'is true for 3xx status' do
76
+ status_app(300 + rand(100)) { redirect? }
77
+ assert_body 'true'
78
+ end
79
+
80
+ it 'is false for status < 300' do
81
+ status_app(200 + rand(100)) { redirect? }
82
+ assert_body 'false'
83
+ end
84
+
85
+ it 'is false for status > 399' do
86
+ status_app(400 + rand(200)) { redirect? }
87
+ assert_body 'false'
88
+ end
89
+ end
90
+
91
+ describe 'client_error?' do
92
+ it 'is true for 4xx status' do
93
+ status_app(400 + rand(100)) { client_error? }
94
+ assert_body 'true'
95
+ end
96
+
97
+ it 'is false for status < 400' do
98
+ status_app(200 + rand(200)) { client_error? }
99
+ assert_body 'false'
100
+ end
101
+
102
+ it 'is false for status > 499' do
103
+ status_app(500 + rand(100)) { client_error? }
104
+ assert_body 'false'
105
+ end
106
+ end
107
+
108
+ describe 'server_error?' do
109
+ it 'is true for 5xx status' do
110
+ status_app(500 + rand(100)) { server_error? }
111
+ assert_body 'true'
112
+ end
113
+
114
+ it 'is false for status < 500' do
115
+ status_app(200 + rand(300)) { server_error? }
116
+ assert_body 'false'
117
+ end
118
+ end
119
+
120
+ describe 'body' do
121
+ it 'takes a block for defered body generation' do
122
+ mock_app {
123
+ get '/' do
124
+ body { 'Hello World' }
125
+ end
126
+ }
127
+
128
+ get '/'
129
+ assert_equal 'Hello World', body
130
+ end
131
+
132
+ it 'takes a String, Array, or other object responding to #each' do
133
+ mock_app {
134
+ get '/' do
135
+ body 'Hello World'
136
+ end
137
+ }
138
+
139
+ get '/'
140
+ assert_equal 'Hello World', body
141
+ end
142
+ end
143
+
144
+ describe 'redirect' do
145
+ it 'uses a 302 when only a path is given' do
146
+ mock_app {
147
+ get '/' do
148
+ redirect '/foo'
149
+ fail 'redirect should halt'
150
+ end
151
+ }
152
+
153
+ get '/'
154
+ assert_equal 302, status
155
+ assert_equal '', body
156
+ assert_equal 'http://example.org/foo', response['Location']
157
+ end
158
+
159
+ it 'uses the code given when specified' do
160
+ mock_app {
161
+ get '/' do
162
+ redirect '/foo', 301
163
+ fail 'redirect should halt'
164
+ end
165
+ }
166
+
167
+ get '/'
168
+ assert_equal 301, status
169
+ assert_equal '', body
170
+ assert_equal 'http://example.org/foo', response['Location']
171
+ end
172
+
173
+ it 'redirects back to request.referer when passed back' do
174
+ mock_app {
175
+ get '/try_redirect' do
176
+ redirect back
177
+ end
178
+ }
179
+
180
+ request = Rack::MockRequest.new(@app)
181
+ response = request.get('/try_redirect', 'HTTP_REFERER' => '/foo')
182
+ assert_equal 302, response.status
183
+ assert_equal 'http://example.org/foo', response['Location']
184
+ end
185
+
186
+ it 'redirects using a non-standard HTTP port' do
187
+ mock_app {
188
+ get '/' do
189
+ redirect '/foo'
190
+ end
191
+ }
192
+
193
+ request = Rack::MockRequest.new(@app)
194
+ response = request.get('/', 'SERVER_PORT' => '81')
195
+ assert_equal 'http://example.org:81/foo', response['Location']
196
+ end
197
+
198
+ it 'redirects using a non-standard HTTPS port' do
199
+ mock_app {
200
+ get '/' do
201
+ redirect '/foo'
202
+ end
203
+ }
204
+
205
+ request = Rack::MockRequest.new(@app)
206
+ response = request.get('/', 'SERVER_PORT' => '444')
207
+ assert_equal 'http://example.org:444/foo', response['Location']
208
+ end
209
+
210
+ it 'uses 303 for post requests if request is HTTP 1.1' do
211
+ mock_app { post('/') { redirect '/'} }
212
+ post '/', {}, 'HTTP_VERSION' => 'HTTP/1.1'
213
+ assert_equal 303, status
214
+ assert_equal '', body
215
+ assert_equal 'http://example.org/', response['Location']
216
+ end
217
+
218
+ it 'uses 302 for post requests if request is HTTP 1.0' do
219
+ mock_app { post('/') { redirect '/'} }
220
+ post '/', {}, 'HTTP_VERSION' => 'HTTP/1.0'
221
+ assert_equal 302, status
222
+ assert_equal '', body
223
+ assert_equal 'http://example.org/', response['Location']
224
+ end
225
+
226
+ it 'works behind a reverse proxy' do
227
+ mock_app do
228
+ get '/' do
229
+ redirect '/foo'
230
+ end
231
+ end
232
+
233
+ request = Rack::MockRequest.new(@app)
234
+ response = request.get('/', 'HTTP_X_FORWARDED_HOST' => 'example.com', 'SERVER_PORT' => '8080')
235
+ assert_equal 'http://example.com/foo', response['Location']
236
+ end
237
+
238
+ it 'accepts absolute URIs' do
239
+ mock_app do
240
+ get '/' do
241
+ redirect 'http://google.com'
242
+ fail 'redirect should halt'
243
+ end
244
+ end
245
+
246
+ get '/'
247
+ assert_equal 302, status
248
+ assert_equal '', body
249
+ assert_equal 'http://google.com', response['Location']
250
+ end
251
+
252
+ it 'accepts absolute URIs with a different schema' do
253
+ mock_app do
254
+ get '/' do
255
+ redirect 'mailto:jsmith@example.com'
256
+ fail 'redirect should halt'
257
+ end
258
+ end
259
+
260
+ get '/'
261
+ assert_equal 302, status
262
+ assert_equal '', body
263
+ assert_equal 'mailto:jsmith@example.com', response['Location']
264
+ end
265
+ end
266
+
267
+ describe 'error' do
268
+ it 'sets a status code and halts' do
269
+ mock_app {
270
+ get '/' do
271
+ error 501
272
+ fail 'error should halt'
273
+ end
274
+ }
275
+
276
+ get '/'
277
+ assert_equal 501, status
278
+ assert_equal '', body
279
+ end
280
+
281
+ it 'takes an optional body' do
282
+ mock_app {
283
+ get '/' do
284
+ error 501, 'FAIL'
285
+ fail 'error should halt'
286
+ end
287
+ }
288
+
289
+ get '/'
290
+ assert_equal 501, status
291
+ assert_equal 'FAIL', body
292
+ end
293
+
294
+ it 'uses a 500 status code when first argument is a body' do
295
+ mock_app {
296
+ get '/' do
297
+ error 'FAIL'
298
+ fail 'error should halt'
299
+ end
300
+ }
301
+
302
+ get '/'
303
+ assert_equal 500, status
304
+ assert_equal 'FAIL', body
305
+ end
306
+ end
307
+
308
+ describe 'not_found' do
309
+ it 'halts with a 404 status' do
310
+ mock_app {
311
+ get '/' do
312
+ not_found
313
+ fail 'not_found should halt'
314
+ end
315
+ }
316
+
317
+ get '/'
318
+ assert_equal 404, status
319
+ assert_equal '', body
320
+ end
321
+
322
+ it 'does not set a X-Cascade header' do
323
+ mock_app {
324
+ get '/' do
325
+ not_found
326
+ fail 'not_found should halt'
327
+ end
328
+ }
329
+
330
+ get '/'
331
+ assert_equal 404, status
332
+ assert_equal nil, response.headers['X-Cascade']
333
+ end
334
+ end
335
+
336
+ describe 'headers' do
337
+ it 'sets headers on the response object when given a Hash' do
338
+ mock_app {
339
+ get '/' do
340
+ headers 'X-Foo' => 'bar', 'X-Baz' => 'bling'
341
+ 'kthx'
342
+ end
343
+ }
344
+
345
+ get '/'
346
+ assert ok?
347
+ assert_equal 'bar', response['X-Foo']
348
+ assert_equal 'bling', response['X-Baz']
349
+ assert_equal 'kthx', body
350
+ end
351
+
352
+ it 'returns the response headers hash when no hash provided' do
353
+ mock_app {
354
+ get '/' do
355
+ headers['X-Foo'] = 'bar'
356
+ 'kthx'
357
+ end
358
+ }
359
+
360
+ get '/'
361
+ assert ok?
362
+ assert_equal 'bar', response['X-Foo']
363
+ end
364
+ end
365
+
366
+ describe 'session' do
367
+ it 'uses the existing rack.session' do
368
+ mock_app {
369
+ get '/' do
370
+ session[:foo]
371
+ end
372
+ }
373
+
374
+ get '/', {}, { 'rack.session' => { :foo => 'bar' } }
375
+ assert_equal 'bar', body
376
+ end
377
+
378
+ it 'creates a new session when none provided' do
379
+ mock_app {
380
+ enable :sessions
381
+
382
+ get '/' do
383
+ assert session.empty?
384
+ session[:foo] = 'bar'
385
+ redirect '/hi'
386
+ end
387
+
388
+ get '/hi' do
389
+ "hi #{session[:foo]}"
390
+ end
391
+ }
392
+
393
+ get '/'
394
+ follow_redirect!
395
+ assert_equal 'hi bar', body
396
+ end
397
+
398
+ it 'inserts session middleware' do
399
+ mock_app do
400
+ enable :sessions
401
+ get '/' do
402
+ assert env['rack.session']
403
+ assert env['rack.session.options']
404
+ 'ok'
405
+ end
406
+ end
407
+
408
+ get '/'
409
+ assert_body 'ok'
410
+ end
411
+
412
+ it 'sets a default session secret' do
413
+ mock_app do
414
+ enable :sessions
415
+ get '/' do
416
+ secret = env['rack.session.options'][:secret]
417
+ assert secret
418
+ assert_equal secret, settings.session_secret
419
+ 'ok'
420
+ end
421
+ end
422
+
423
+ get '/'
424
+ assert_body 'ok'
425
+ end
426
+
427
+ it 'allows disabling session secret' do
428
+ mock_app do
429
+ enable :sessions
430
+ disable :session_secret
431
+ get '/' do
432
+ assert !env['rack.session.options'].include?(:session_secret)
433
+ 'ok'
434
+ end
435
+ end
436
+
437
+ get '/'
438
+ assert_body 'ok'
439
+ end
440
+
441
+ it 'accepts an options hash' do
442
+ mock_app do
443
+ set :sessions, :foo => :bar
444
+ get '/' do
445
+ assert_equal env['rack.session.options'][:foo], :bar
446
+ 'ok'
447
+ end
448
+ end
449
+
450
+ get '/'
451
+ assert_body 'ok'
452
+ end
453
+ end
454
+
455
+ describe 'mime_type' do
456
+ include aldebaran::Helpers
457
+
458
+ it "looks up mime types in Rack's MIME registry" do
459
+ Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
460
+ assert_equal 'application/foo', mime_type('foo')
461
+ assert_equal 'application/foo', mime_type('.foo')
462
+ assert_equal 'application/foo', mime_type(:foo)
463
+ end
464
+
465
+ it 'returns nil when given nil' do
466
+ assert mime_type(nil).nil?
467
+ end
468
+
469
+ it 'returns nil when media type not registered' do
470
+ assert mime_type(:bizzle).nil?
471
+ end
472
+
473
+ it 'returns the argument when given a media type string' do
474
+ assert_equal 'text/plain', mime_type('text/plain')
475
+ end
476
+ end
477
+
478
+ test 'Base.mime_type registers mime type' do
479
+ mock_app {
480
+ mime_type :foo, 'application/foo'
481
+
482
+ get '/' do
483
+ "foo is #{mime_type(:foo)}"
484
+ end
485
+ }
486
+
487
+ get '/'
488
+ assert_equal 'foo is application/foo', body
489
+ end
490
+
491
+ describe 'content_type' do
492
+ it 'sets the Content-Type header' do
493
+ mock_app {
494
+ get '/' do
495
+ content_type 'text/plain'
496
+ 'Hello World'
497
+ end
498
+ }
499
+
500
+ get '/'
501
+ assert_equal 'text/plain;charset=utf-8', response['Content-Type']
502
+ assert_equal 'Hello World', body
503
+ end
504
+
505
+ it 'takes media type parameters (like charset=)' do
506
+ mock_app {
507
+ get '/' do
508
+ content_type 'text/html', :charset => 'latin1'
509
+ "<h1>Hello, World</h1>"
510
+ end
511
+ }
512
+
513
+ get '/'
514
+ assert ok?
515
+ assert_equal 'text/html;charset=latin1', response['Content-Type']
516
+ assert_equal "<h1>Hello, World</h1>", body
517
+ end
518
+
519
+ it "looks up symbols in Rack's mime types dictionary" do
520
+ Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
521
+ mock_app {
522
+ get '/foo.xml' do
523
+ content_type :foo
524
+ "I AM FOO"
525
+ end
526
+ }
527
+
528
+ get '/foo.xml'
529
+ assert ok?
530
+ assert_equal 'application/foo', response['Content-Type']
531
+ assert_equal 'I AM FOO', body
532
+ end
533
+
534
+ it 'fails when no mime type is registered for the argument provided' do
535
+ mock_app {
536
+ get '/foo.xml' do
537
+ content_type :bizzle
538
+ "I AM FOO"
539
+ end
540
+ }
541
+
542
+ assert_raise(RuntimeError) { get '/foo.xml' }
543
+ end
544
+
545
+ it 'only sets default charset for specific mime types' do
546
+ tests_ran = false
547
+ mock_app do
548
+ mime_type :foo, 'text/foo'
549
+ mime_type :bar, 'application/bar'
550
+ mime_type :baz, 'application/baz'
551
+ add_charset << mime_type(:baz)
552
+ get '/' do
553
+ assert_equal content_type(:txt), 'text/plain;charset=utf-8'
554
+ assert_equal content_type(:css), 'text/css;charset=utf-8'
555
+ assert_equal content_type(:html), 'text/html;charset=utf-8'
556
+ assert_equal content_type(:foo), 'text/foo;charset=utf-8'
557
+ assert_equal content_type(:xml), 'application/xml;charset=utf-8'
558
+ assert_equal content_type(:xhtml), 'application/xhtml+xml;charset=utf-8'
559
+ assert_equal content_type(:js), 'application/javascript;charset=utf-8'
560
+ assert_equal content_type(:json), 'application/json;charset=utf-8'
561
+ assert_equal content_type(:bar), 'application/bar'
562
+ assert_equal content_type(:png), 'image/png'
563
+ assert_equal content_type(:baz), 'application/baz;charset=utf-8'
564
+ tests_ran = true
565
+ "done"
566
+ end
567
+ end
568
+ get '/'
569
+ assert tests_ran
570
+ end
571
+
572
+ it 'handles already present params' do
573
+ mock_app do
574
+ get '/' do
575
+ content_type 'foo/bar;level=1', :charset => 'utf-8'
576
+ 'ok'
577
+ end
578
+ end
579
+ get '/'
580
+ assert_equal 'foo/bar;level=1, charset=utf-8', response['Content-Type']
581
+ end
582
+
583
+ it 'does not add charset if present' do
584
+ mock_app do
585
+ get '/' do
586
+ content_type 'text/plain;charset=utf-16'
587
+ 'ok'
588
+ end
589
+ end
590
+ get '/'
591
+ assert_equal 'text/plain;charset=utf-16', response['Content-Type']
592
+ end
593
+ end
594
+
595
+ describe 'attachment' do
596
+ def attachment_app(filename=nil)
597
+ mock_app {
598
+ get '/attachment' do
599
+ attachment filename
600
+ response.write("<aldebaran></aldebaran>")
601
+ end
602
+ }
603
+ end
604
+
605
+ it 'sets the Content-Type response header' do
606
+ attachment_app('test.xml')
607
+ get '/attachment'
608
+ assert_equal 'application/xml;charset=utf-8', response['Content-Type']
609
+ assert_equal '<aldebaran></aldebaran>', body
610
+ end
611
+
612
+ it 'sets the Content-Type response header without extname' do
613
+ attachment_app('test')
614
+ get '/attachment'
615
+ assert_equal 'text/html;charset=utf-8', response['Content-Type']
616
+ assert_equal '<aldebaran></aldebaran>', body
617
+ end
618
+
619
+ it 'sets the Content-Type response header without extname' do
620
+ mock_app do
621
+ get '/attachment' do
622
+ content_type :atom
623
+ attachment 'test.xml'
624
+ response.write("<aldebaran></aldebaran>")
625
+ end
626
+ end
627
+ get '/attachment'
628
+ assert_equal 'application/atom+xml', response['Content-Type']
629
+ assert_equal '<aldebaran></aldebaran>', body
630
+ end
631
+
632
+ end
633
+
634
+ describe 'send_file' do
635
+ setup do
636
+ @file = File.dirname(__FILE__) + '/file.txt'
637
+ File.open(@file, 'wb') { |io| io.write('Hello World') }
638
+ end
639
+
640
+ def teardown
641
+ File.unlink @file
642
+ @file = nil
643
+ end
644
+
645
+ def send_file_app(opts={})
646
+ path = @file
647
+ mock_app {
648
+ get '/file.txt' do
649
+ send_file path, opts
650
+ end
651
+ }
652
+ end
653
+
654
+ it "sends the contents of the file" do
655
+ send_file_app
656
+ get '/file.txt'
657
+ assert ok?
658
+ assert_equal 'Hello World', body
659
+ end
660
+
661
+ it 'sets the Content-Type response header if a mime-type can be located' do
662
+ send_file_app
663
+ get '/file.txt'
664
+ assert_equal 'text/plain;charset=utf-8', response['Content-Type']
665
+ end
666
+
667
+ it 'sets the Content-Type response header if type option is set to a file extesion' do
668
+ send_file_app :type => 'html'
669
+ get '/file.txt'
670
+ assert_equal 'text/html;charset=utf-8', response['Content-Type']
671
+ end
672
+
673
+ it 'sets the Content-Type response header if type option is set to a mime type' do
674
+ send_file_app :type => 'application/octet-stream'
675
+ get '/file.txt'
676
+ assert_equal 'application/octet-stream', response['Content-Type']
677
+ end
678
+
679
+ it 'sets the Content-Length response header' do
680
+ send_file_app
681
+ get '/file.txt'
682
+ assert_equal 'Hello World'.length.to_s, response['Content-Length']
683
+ end
684
+
685
+ it 'sets the Last-Modified response header' do
686
+ send_file_app
687
+ get '/file.txt'
688
+ assert_equal File.mtime(@file).httpdate, response['Last-Modified']
689
+ end
690
+
691
+ it 'allows passing in a differen Last-Modified response header with :last_modified' do
692
+ time = Time.now
693
+ send_file_app :last_modified => time
694
+ get '/file.txt'
695
+ assert_equal time.httpdate, response['Last-Modified']
696
+ end
697
+
698
+ it "returns a 404 when not found" do
699
+ mock_app {
700
+ get '/' do
701
+ send_file 'this-file-does-not-exist.txt'
702
+ end
703
+ }
704
+ get '/'
705
+ assert not_found?
706
+ end
707
+
708
+ it "does not set the Content-Disposition header by default" do
709
+ send_file_app
710
+ get '/file.txt'
711
+ assert_nil response['Content-Disposition']
712
+ end
713
+
714
+ it "sets the Content-Disposition header when :disposition set to 'attachment'" do
715
+ send_file_app :disposition => 'attachment'
716
+ get '/file.txt'
717
+ assert_equal 'attachment; filename="file.txt"', response['Content-Disposition']
718
+ end
719
+
720
+ it "sets the Content-Disposition header when :disposition set to 'inline'" do
721
+ send_file_app :disposition => 'inline'
722
+ get '/file.txt'
723
+ assert_equal 'inline', response['Content-Disposition']
724
+ end
725
+
726
+ it "sets the Content-Disposition header when :filename provided" do
727
+ send_file_app :filename => 'foo.txt'
728
+ get '/file.txt'
729
+ assert_equal 'attachment; filename="foo.txt"', response['Content-Disposition']
730
+ end
731
+
732
+ it "is able to send files with unkown mime type" do
733
+ @file = File.dirname(__FILE__) + '/file.foobar'
734
+ File.open(@file, 'wb') { |io| io.write('Hello World') }
735
+ send_file_app
736
+ get '/file.txt'
737
+ assert_equal 'application/octet-stream', response['Content-Type']
738
+ end
739
+
740
+ it "does not override Content-Type if already set and no explicit type is given" do
741
+ path = @file
742
+ mock_app do
743
+ get '/' do
744
+ content_type :png
745
+ send_file path
746
+ end
747
+ end
748
+ get '/'
749
+ assert_equal 'image/png', response['Content-Type']
750
+ end
751
+
752
+ it "does override Content-Type even if already set, if explicit type is given" do
753
+ path = @file
754
+ mock_app do
755
+ get '/' do
756
+ content_type :png
757
+ send_file path, :type => :gif
758
+ end
759
+ end
760
+ get '/'
761
+ assert_equal 'image/gif', response['Content-Type']
762
+ end
763
+ end
764
+
765
+ describe 'cache_control' do
766
+ setup do
767
+ mock_app do
768
+ get '/foo' do
769
+ cache_control :public, :no_cache, :max_age => 60.0
770
+ 'Hello World'
771
+ end
772
+
773
+ get '/bar' do
774
+ cache_control :public, :no_cache
775
+ 'Hello World'
776
+ end
777
+ end
778
+ end
779
+
780
+ it 'sets the Cache-Control header' do
781
+ get '/foo'
782
+ assert_equal ['public', 'no-cache', 'max-age=60'], response['Cache-Control'].split(', ')
783
+ end
784
+
785
+ it 'last argument does not have to be a hash' do
786
+ get '/bar'
787
+ assert_equal ['public', 'no-cache'], response['Cache-Control'].split(', ')
788
+ end
789
+ end
790
+
791
+ describe 'expires' do
792
+ setup do
793
+ mock_app do
794
+ get '/foo' do
795
+ expires 60, :public, :no_cache
796
+ 'Hello World'
797
+ end
798
+
799
+ get '/bar' do
800
+ expires Time.now
801
+ end
802
+
803
+ get '/baz' do
804
+ expires Time.at(0)
805
+ end
806
+
807
+ get '/blah' do
808
+ obj = Object.new
809
+ def obj.method_missing(*a, &b) 60.send(*a, &b) end
810
+ def obj.is_a?(thing) 60.is_a?(thing) end
811
+ expires obj, :public, :no_cache
812
+ 'Hello World'
813
+ end
814
+
815
+ get '/boom' do
816
+ expires '9999'
817
+ end
818
+ end
819
+ end
820
+
821
+ it 'sets the Cache-Control header' do
822
+ get '/foo'
823
+ assert_equal ['public', 'no-cache', 'max-age=60'], response['Cache-Control'].split(', ')
824
+ end
825
+
826
+ it 'sets the Expires header' do
827
+ get '/foo'
828
+ assert_not_nil response['Expires']
829
+ end
830
+
831
+ it 'allows passing time objects' do
832
+ get '/bar'
833
+ assert_not_nil response['Expires']
834
+ end
835
+
836
+ it 'allows passing time objects' do
837
+ get '/baz'
838
+ assert_equal 'Thu, 01 Jan 1970 00:00:00 GMT', response['Expires']
839
+ end
840
+
841
+ it 'accepts values pretending to be a Numeric (like ActiveSupport::Duration)' do
842
+ get '/blah'
843
+ assert_equal ['public', 'no-cache', 'max-age=60'], response['Cache-Control'].split(', ')
844
+ end
845
+
846
+ it 'fails when Time.parse raises an ArgumentError' do
847
+ assert_raise(ArgumentError) { get '/boom' }
848
+ end
849
+ end
850
+
851
+ describe 'last_modified' do
852
+ it 'ignores nil' do
853
+ mock_app do
854
+ get '/' do last_modified nil; 200; end
855
+ end
856
+
857
+ get '/'
858
+ assert ! response['Last-Modified']
859
+ end
860
+
861
+ [Time.now, DateTime.now, Date.today, Time.now.to_i,
862
+ Struct.new(:to_time).new(Time.now) ].each do |last_modified_time|
863
+ describe "with #{last_modified_time.class.name}" do
864
+ setup do
865
+ mock_app do
866
+ get '/' do
867
+ last_modified last_modified_time
868
+ 'Boo!'
869
+ end
870
+ end
871
+ wrapper = Object.new.extend aldebaran::Helpers
872
+ @last_modified_time = wrapper.time_for last_modified_time
873
+ end
874
+
875
+ # fixes strange missing test error when running complete test suite.
876
+ it("does not complain about missing tests") { }
877
+
878
+ context "when there's no If-Modified-Since header" do
879
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
880
+ get '/'
881
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
882
+ end
883
+
884
+ it 'conditional GET misses and returns a body' do
885
+ get '/'
886
+ assert_equal 200, status
887
+ assert_equal 'Boo!', body
888
+ end
889
+ end
890
+
891
+ context "when there's an invalid If-Modified-Since header" do
892
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
893
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'a really weird date' }
894
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
895
+ end
896
+
897
+ it 'conditional GET misses and returns a body' do
898
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'a really weird date' }
899
+ assert_equal 200, status
900
+ assert_equal 'Boo!', body
901
+ end
902
+ end
903
+
904
+ context "when the resource has been modified since the If-Modified-Since header date" do
905
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
906
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time - 1).httpdate }
907
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
908
+ end
909
+
910
+ it 'conditional GET misses and returns a body' do
911
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time - 1).httpdate }
912
+ assert_equal 200, status
913
+ assert_equal 'Boo!', body
914
+ end
915
+
916
+ it 'does not rely on string comparison' do
917
+ mock_app do
918
+ get '/compare' do
919
+ last_modified "Mon, 18 Oct 2010 20:57:11 GMT"
920
+ "foo"
921
+ end
922
+ end
923
+
924
+ get '/compare', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2010 23:43:52 GMT' }
925
+ assert_equal 200, status
926
+ assert_equal 'foo', body
927
+ get '/compare', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT' }
928
+ assert_equal 304, status
929
+ assert_equal '', body
930
+ end
931
+ end
932
+
933
+ context "when the resource has been modified on the exact If-Modified-Since header date" do
934
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
935
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @last_modified_time.httpdate }
936
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
937
+ end
938
+
939
+ it 'conditional GET matches and halts' do
940
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @last_modified_time.httpdate }
941
+ assert_equal 304, status
942
+ assert_equal '', body
943
+ end
944
+ end
945
+
946
+ context "when the resource hasn't been modified since the If-Modified-Since header date" do
947
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
948
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time + 1).httpdate }
949
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
950
+ end
951
+
952
+ it 'conditional GET matches and halts' do
953
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time + 1).httpdate }
954
+ assert_equal 304, status
955
+ assert_equal '', body
956
+ end
957
+ end
958
+ end
959
+ end
960
+ end
961
+
962
+ describe 'etag' do
963
+ setup do
964
+ mock_app {
965
+ get '/' do
966
+ body { 'Hello World' }
967
+ etag 'FOO'
968
+ 'Boo!'
969
+ end
970
+
971
+ post '/' do
972
+ etag 'FOO'
973
+ 'Matches!'
974
+ end
975
+ }
976
+ end
977
+
978
+ it 'sets the ETag header' do
979
+ get '/'
980
+ assert_equal '"FOO"', response['ETag']
981
+ end
982
+
983
+ it 'returns a body when conditional get misses' do
984
+ get '/'
985
+ assert_equal 200, status
986
+ assert_equal 'Boo!', body
987
+ end
988
+
989
+ it 'returns a body when posting with no If-None-Match header' do
990
+ post '/'
991
+ assert_equal 200, status
992
+ assert_equal 'Matches!', body
993
+ end
994
+
995
+ it 'returns a body when conditional post matches' do
996
+ post '/', {}, { 'HTTP_IF_NONE_MATCH' => '"FOO"' }
997
+ assert_equal 200, status
998
+ assert_equal 'Matches!', body
999
+ end
1000
+
1001
+ it 'halts with 412 when conditional post misses' do
1002
+ post '/', {}, { 'HTTP_IF_NONE_MATCH' => '"BAR"' }
1003
+ assert_equal 412, status
1004
+ assert_equal '', body
1005
+ end
1006
+
1007
+ it 'halts when a conditional GET matches' do
1008
+ get '/', {}, { 'HTTP_IF_NONE_MATCH' => '"FOO"' }
1009
+ assert_equal 304, status
1010
+ assert_equal '', body
1011
+ end
1012
+
1013
+ it 'should handle multiple ETag values in If-None-Match header' do
1014
+ get '/', {}, { 'HTTP_IF_NONE_MATCH' => '"BAR", *' }
1015
+ assert_equal 304, status
1016
+ assert_equal '', body
1017
+ end
1018
+
1019
+ it 'uses a weak etag with the :weak option' do
1020
+ mock_app {
1021
+ get '/' do
1022
+ etag 'FOO', :weak
1023
+ "that's weak, dude."
1024
+ end
1025
+ }
1026
+ get '/'
1027
+ assert_equal 'W/"FOO"', response['ETag']
1028
+ end
1029
+
1030
+ it 'raises an ArgumentError for an invalid strength' do
1031
+ mock_app do
1032
+ get '/' do
1033
+ etag 'FOO', :w00t
1034
+ "that's weak, dude."
1035
+ end
1036
+ end
1037
+ assert_raise(ArgumentError) { get '/' }
1038
+ end
1039
+ end
1040
+
1041
+ describe 'back' do
1042
+ it "makes redirecting back pretty" do
1043
+ mock_app {
1044
+ get '/foo' do
1045
+ redirect back
1046
+ end
1047
+ }
1048
+
1049
+ get '/foo', {}, 'HTTP_REFERER' => 'http://github.com'
1050
+ assert redirect?
1051
+ assert_equal "http://github.com", response.location
1052
+ end
1053
+ end
1054
+
1055
+ describe 'uri' do
1056
+ it 'generates absolute urls' do
1057
+ mock_app { get('/') { uri }}
1058
+ get '/'
1059
+ assert_equal 'http://example.org/', body
1060
+ end
1061
+
1062
+ it 'includes path_info' do
1063
+ mock_app { get('/:name') { uri }}
1064
+ get '/foo'
1065
+ assert_equal 'http://example.org/foo', body
1066
+ end
1067
+
1068
+ it 'allows passing an alternative to path_info' do
1069
+ mock_app { get('/:name') { uri '/bar' }}
1070
+ get '/foo'
1071
+ assert_equal 'http://example.org/bar', body
1072
+ end
1073
+
1074
+ it 'includes script_name' do
1075
+ mock_app { get('/:name') { uri '/bar' }}
1076
+ get '/foo', {}, { "SCRIPT_NAME" => '/foo' }
1077
+ assert_equal 'http://example.org/foo/bar', body
1078
+ end
1079
+
1080
+ it 'handles absolute URIs' do
1081
+ mock_app { get('/') { uri 'http://google.com' }}
1082
+ get '/'
1083
+ assert_equal 'http://google.com', body
1084
+ end
1085
+
1086
+ it 'handles different protocols' do
1087
+ mock_app { get('/') { uri 'mailto:jsmith@example.com' }}
1088
+ get '/'
1089
+ assert_equal 'mailto:jsmith@example.com', body
1090
+ end
1091
+
1092
+ it 'is aliased to #url' do
1093
+ mock_app { get('/') { url }}
1094
+ get '/'
1095
+ assert_equal 'http://example.org/', body
1096
+ end
1097
+
1098
+ it 'is aliased to #to' do
1099
+ mock_app { get('/') { to }}
1100
+ get '/'
1101
+ assert_equal 'http://example.org/', body
1102
+ end
1103
+ end
1104
+
1105
+ describe 'logger' do
1106
+ it 'logging works when logging is enabled' do
1107
+ mock_app do
1108
+ enable :logging
1109
+ get '/' do
1110
+ logger.info "Program started"
1111
+ logger.warn "Nothing to do!"
1112
+ end
1113
+ end
1114
+ io = StringIO.new
1115
+ get '/', {}, 'rack.errors' => io
1116
+ assert io.string.include?("INFO -- : Program started")
1117
+ assert io.string.include?("WARN -- : Nothing to do")
1118
+ end
1119
+
1120
+ it 'logging works when logging is disable, but no output is produced' do
1121
+ mock_app do
1122
+ disable :logging
1123
+ get '/' do
1124
+ logger.info "Program started"
1125
+ logger.warn "Nothing to do!"
1126
+ end
1127
+ end
1128
+ io = StringIO.new
1129
+ get '/', {}, 'rack.errors' => io
1130
+ assert !io.string.include?("INFO -- : Program started")
1131
+ assert !io.string.include?("WARN -- : Nothing to do")
1132
+ end
1133
+ end
1134
+
1135
+ module ::HelperOne; def one; '1'; end; end
1136
+ module ::HelperTwo; def two; '2'; end; end
1137
+
1138
+ describe 'Adding new helpers' do
1139
+ it 'takes a list of modules to mix into the app' do
1140
+ mock_app {
1141
+ helpers ::HelperOne, ::HelperTwo
1142
+
1143
+ get '/one' do
1144
+ one
1145
+ end
1146
+
1147
+ get '/two' do
1148
+ two
1149
+ end
1150
+ }
1151
+
1152
+ get '/one'
1153
+ assert_equal '1', body
1154
+
1155
+ get '/two'
1156
+ assert_equal '2', body
1157
+ end
1158
+
1159
+ it 'takes a block to mix into the app' do
1160
+ mock_app {
1161
+ helpers do
1162
+ def foo
1163
+ 'foo'
1164
+ end
1165
+ end
1166
+
1167
+ get '/' do
1168
+ foo
1169
+ end
1170
+ }
1171
+
1172
+ get '/'
1173
+ assert_equal 'foo', body
1174
+ end
1175
+
1176
+ it 'evaluates the block in class context so that methods can be aliased' do
1177
+ mock_app {
1178
+ helpers do
1179
+ alias_method :h, :escape_html
1180
+ end
1181
+
1182
+ get '/' do
1183
+ h('42 < 43')
1184
+ end
1185
+ }
1186
+
1187
+ get '/'
1188
+ assert ok?
1189
+ assert_equal '42 &lt; 43', body
1190
+ end
1191
+ end
1192
+ end