sinatra 1.0 → 1.1.a

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sinatra might be problematic. Click here for more details.

Files changed (57) hide show
  1. data/CHANGES +108 -1
  2. data/LICENSE +1 -1
  3. data/README.de.rdoc +1024 -0
  4. data/README.es.rdoc +1047 -0
  5. data/README.fr.rdoc +1038 -0
  6. data/README.hu.rdoc +607 -0
  7. data/README.jp.rdoc +473 -15
  8. data/README.rdoc +429 -41
  9. data/Rakefile +17 -6
  10. data/lib/sinatra/base.rb +357 -158
  11. data/lib/sinatra/showexceptions.rb +9 -1
  12. data/sinatra.gemspec +52 -9
  13. data/test/builder_test.rb +25 -1
  14. data/test/coffee_test.rb +88 -0
  15. data/test/encoding_test.rb +18 -0
  16. data/test/filter_test.rb +61 -2
  17. data/test/hello.mab +1 -0
  18. data/test/helper.rb +1 -0
  19. data/test/helpers_test.rb +141 -37
  20. data/test/less_test.rb +26 -2
  21. data/test/liquid_test.rb +58 -0
  22. data/test/markaby_test.rb +58 -0
  23. data/test/markdown_test.rb +35 -0
  24. data/test/nokogiri_test.rb +69 -0
  25. data/test/radius_test.rb +59 -0
  26. data/test/rdoc_test.rb +34 -0
  27. data/test/request_test.rb +12 -0
  28. data/test/routing_test.rb +35 -1
  29. data/test/sass_test.rb +46 -16
  30. data/test/scss_test.rb +88 -0
  31. data/test/settings_test.rb +32 -0
  32. data/test/sinatra_test.rb +4 -0
  33. data/test/static_test.rb +64 -0
  34. data/test/templates_test.rb +55 -1
  35. data/test/textile_test.rb +34 -0
  36. data/test/views/ascii.haml +2 -0
  37. data/test/views/explicitly_nested.str +1 -0
  38. data/test/views/hello.coffee +1 -0
  39. data/test/views/hello.liquid +1 -0
  40. data/test/views/hello.mab +1 -0
  41. data/test/views/hello.md +1 -0
  42. data/test/views/hello.nokogiri +1 -0
  43. data/test/views/hello.radius +1 -0
  44. data/test/views/hello.rdoc +1 -0
  45. data/test/views/hello.sass +1 -1
  46. data/test/views/hello.scss +3 -0
  47. data/test/views/hello.str +1 -0
  48. data/test/views/hello.textile +1 -0
  49. data/test/views/layout2.liquid +2 -0
  50. data/test/views/layout2.mab +2 -0
  51. data/test/views/layout2.nokogiri +3 -0
  52. data/test/views/layout2.radius +2 -0
  53. data/test/views/layout2.str +2 -0
  54. data/test/views/nested.str +1 -0
  55. data/test/views/utf8.haml +2 -0
  56. metadata +240 -33
  57. data/lib/sinatra/tilt.rb +0 -746
@@ -1,12 +1,20 @@
1
1
  require 'rack/showexceptions'
2
2
 
3
3
  module Sinatra
4
+ # Sinatra::ShowExceptions catches all exceptions raised from the app it
5
+ # wraps. It shows a useful backtrace with the sourcefile and clickable
6
+ # context, the whole Rack environment and the request data.
7
+ #
8
+ # Be careful when you use this on public-facing sites as it could reveal
9
+ # information helpful to attackers.
4
10
  class ShowExceptions < Rack::ShowExceptions
5
11
  def initialize(app)
6
12
  @app = app
7
13
  @template = ERB.new(TEMPLATE)
8
14
  end
9
15
 
16
+ private
17
+
10
18
  def frame_class(frame)
11
19
  if frame.filename =~ /lib\/sinatra.*\.rb/
12
20
  "framework"
@@ -18,7 +26,7 @@ module Sinatra
18
26
  end
19
27
  end
20
28
 
21
- TEMPLATE = <<HTML
29
+ TEMPLATE = <<-HTML # :nodoc:
22
30
  <!DOCTYPE html>
23
31
  <html>
24
32
  <head>
@@ -3,13 +3,13 @@ Gem::Specification.new do |s|
3
3
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
4
 
5
5
  s.name = 'sinatra'
6
- s.version = '1.0'
7
- s.date = '2010-03-23'
6
+ s.version = '1.1.a'
7
+ s.date = '2010-10-19'
8
8
 
9
9
  s.description = "Classy web-development dressed in a DSL"
10
10
  s.summary = "Classy web-development dressed in a DSL"
11
11
 
12
- s.authors = ["Blake Mizerany", "Ryan Tomayko", "Simon Rozet"]
12
+ s.authors = ["Blake Mizerany", "Ryan Tomayko", "Simon Rozet", "Konstantin Haase"]
13
13
  s.email = "sinatrarb@googlegroups.com"
14
14
 
15
15
  # = MANIFEST =
@@ -17,6 +17,10 @@ Gem::Specification.new do |s|
17
17
  AUTHORS
18
18
  CHANGES
19
19
  LICENSE
20
+ README.de.rdoc
21
+ README.es.rdoc
22
+ README.fr.rdoc
23
+ README.hu.rdoc
20
24
  README.jp.rdoc
21
25
  README.rdoc
22
26
  Rakefile
@@ -26,64 +30,103 @@ Gem::Specification.new do |s|
26
30
  lib/sinatra/images/500.png
27
31
  lib/sinatra/main.rb
28
32
  lib/sinatra/showexceptions.rb
29
- lib/sinatra/tilt.rb
30
33
  sinatra.gemspec
31
34
  test/base_test.rb
32
35
  test/builder_test.rb
36
+ test/coffee_test.rb
33
37
  test/contest.rb
38
+ test/encoding_test.rb
34
39
  test/erb_test.rb
35
40
  test/erubis_test.rb
36
41
  test/extensions_test.rb
37
42
  test/filter_test.rb
38
43
  test/haml_test.rb
44
+ test/hello.mab
39
45
  test/helper.rb
40
46
  test/helpers_test.rb
41
47
  test/less_test.rb
48
+ test/liquid_test.rb
42
49
  test/mapped_error_test.rb
50
+ test/markaby_test.rb
51
+ test/markdown_test.rb
43
52
  test/middleware_test.rb
53
+ test/nokogiri_test.rb
44
54
  test/public/favicon.ico
55
+ test/radius_test.rb
56
+ test/rdoc_test.rb
45
57
  test/request_test.rb
46
58
  test/response_test.rb
47
59
  test/result_test.rb
48
60
  test/route_added_hook_test.rb
49
61
  test/routing_test.rb
50
62
  test/sass_test.rb
63
+ test/scss_test.rb
51
64
  test/server_test.rb
52
65
  test/settings_test.rb
53
66
  test/sinatra_test.rb
54
67
  test/static_test.rb
55
68
  test/templates_test.rb
69
+ test/textile_test.rb
70
+ test/views/ascii.haml
56
71
  test/views/error.builder
57
72
  test/views/error.erb
58
73
  test/views/error.erubis
59
74
  test/views/error.haml
60
75
  test/views/error.sass
76
+ test/views/explicitly_nested.str
61
77
  test/views/foo/hello.test
62
78
  test/views/hello.builder
79
+ test/views/hello.coffee
63
80
  test/views/hello.erb
64
81
  test/views/hello.erubis
65
82
  test/views/hello.haml
66
83
  test/views/hello.less
84
+ test/views/hello.liquid
85
+ test/views/hello.mab
86
+ test/views/hello.md
87
+ test/views/hello.nokogiri
88
+ test/views/hello.radius
89
+ test/views/hello.rdoc
67
90
  test/views/hello.sass
91
+ test/views/hello.scss
92
+ test/views/hello.str
68
93
  test/views/hello.test
94
+ test/views/hello.textile
69
95
  test/views/layout2.builder
70
96
  test/views/layout2.erb
71
97
  test/views/layout2.erubis
72
98
  test/views/layout2.haml
99
+ test/views/layout2.liquid
100
+ test/views/layout2.mab
101
+ test/views/layout2.nokogiri
102
+ test/views/layout2.radius
103
+ test/views/layout2.str
73
104
  test/views/layout2.test
105
+ test/views/nested.str
106
+ test/views/utf8.haml
74
107
  ]
75
108
  # = MANIFEST =
76
109
 
77
110
  s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/}
78
111
 
79
- s.extra_rdoc_files = %w[README.rdoc LICENSE]
80
- s.add_dependency 'rack', '>= 1.0'
81
- s.add_development_dependency 'shotgun', '>= 0.6', '< 1.0'
82
- s.add_development_dependency 'rack-test', '>= 0.3.0'
83
- s.add_development_dependency 'haml'
112
+ s.extra_rdoc_files = %w[README.rdoc README.de.rdoc README.jp.rdoc README.fr.rdoc README.es.rdoc README.hu.rdoc LICENSE]
113
+ s.add_dependency 'rack', '~> 1.1'
114
+ s.add_dependency 'tilt', '~> 1.1'
115
+ s.add_development_dependency 'rake'
116
+ s.add_development_dependency 'shotgun', '~> 0.6'
117
+ s.add_development_dependency 'rack-test', '>= 0.5.6'
118
+ s.add_development_dependency 'haml', '>= 3.0'
84
119
  s.add_development_dependency 'builder'
85
120
  s.add_development_dependency 'erubis'
86
121
  s.add_development_dependency 'less'
122
+ s.add_development_dependency 'liquid'
123
+ s.add_development_dependency 'rdiscount'
124
+ s.add_development_dependency 'RedCloth'
125
+ s.add_development_dependency 'radius'
126
+ s.add_development_dependency 'markaby'
127
+ s.add_development_dependency 'coffee-script'
128
+ s.add_development_dependency 'rdoc'
129
+ s.add_development_dependency 'nokogiri'
87
130
 
88
131
  s.has_rdoc = true
89
132
  s.homepage = "http://sinatra.rubyforge.org"
@@ -2,9 +2,10 @@ require File.dirname(__FILE__) + '/helper'
2
2
  require 'builder'
3
3
 
4
4
  class BuilderTest < Test::Unit::TestCase
5
- def builder_app(&block)
5
+ def builder_app(options = {}, &block)
6
6
  mock_app {
7
7
  set :views, File.dirname(__FILE__) + '/views'
8
+ set options
8
9
  get '/', &block
9
10
  }
10
11
  get '/'
@@ -16,6 +17,29 @@ class BuilderTest < Test::Unit::TestCase
16
17
  assert_equal %{<?xml version="1.0" encoding="UTF-8"?>\n}, body
17
18
  end
18
19
 
20
+ it 'defaults content type to xml' do
21
+ builder_app { builder 'xml.instruct!' }
22
+ assert ok?
23
+ assert_equal "application/xml;charset=utf-8", response['Content-Type']
24
+ end
25
+
26
+ it 'defaults allows setting content type per route' do
27
+ builder_app do
28
+ content_type :html
29
+ builder 'xml.instruct!'
30
+ end
31
+ assert ok?
32
+ assert_equal "text/html;charset=utf-8", response['Content-Type']
33
+ end
34
+
35
+ it 'defaults allows setting content type globally' do
36
+ builder_app(:builder => { :content_type => 'html' }) do
37
+ builder 'xml.instruct!'
38
+ end
39
+ assert ok?
40
+ assert_equal "text/html;charset=utf-8", response['Content-Type']
41
+ end
42
+
19
43
  it 'renders inline blocks' do
20
44
  builder_app {
21
45
  @name = "Frank & Mary"
@@ -0,0 +1,88 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ begin
4
+ require 'coffee-script'
5
+
6
+ class CoffeeTest < Test::Unit::TestCase
7
+ def coffee_app(options = {}, &block)
8
+ mock_app {
9
+ set :views, File.dirname(__FILE__) + '/views'
10
+ set(options)
11
+ get '/', &block
12
+ }
13
+ get '/'
14
+ end
15
+
16
+ it 'renders inline Coffee strings' do
17
+ coffee_app { coffee "alert 'Aye!'\n" }
18
+ assert ok?
19
+ assert_equal "(function() {\n alert('Aye!');\n})();\n", body
20
+ end
21
+
22
+ it 'defaults content type to javascript' do
23
+ coffee_app { coffee "alert 'Aye!'\n" }
24
+ assert ok?
25
+ assert_equal "application/javascript;charset=utf-8", response['Content-Type']
26
+ end
27
+
28
+ it 'defaults allows setting content type per route' do
29
+ coffee_app do
30
+ content_type :html
31
+ coffee "alert 'Aye!'\n"
32
+ end
33
+ assert ok?
34
+ assert_equal "text/html;charset=utf-8", response['Content-Type']
35
+ end
36
+
37
+ it 'defaults allows setting content type globally' do
38
+ coffee_app(:coffee => { :content_type => 'html' }) do
39
+ coffee "alert 'Aye!'\n"
40
+ end
41
+ assert ok?
42
+ assert_equal "text/html;charset=utf-8", response['Content-Type']
43
+ end
44
+
45
+ it 'renders .coffee files in views path' do
46
+ coffee_app { coffee :hello }
47
+ assert ok?
48
+ assert_equal "(function() {\n alert(\"Aye!\");\n})();\n", body
49
+ end
50
+
51
+ it 'ignores the layout option' do
52
+ coffee_app { coffee :hello, :layout => :layout2 }
53
+ assert ok?
54
+ assert_equal "(function() {\n alert(\"Aye!\");\n})();\n", body
55
+ end
56
+
57
+ it "raises error if template not found" do
58
+ mock_app {
59
+ get('/') { coffee :no_such_template }
60
+ }
61
+ assert_raise(Errno::ENOENT) { get('/') }
62
+ end
63
+
64
+ it "passes coffee options to the coffee engine" do
65
+ coffee_app {
66
+ coffee "alert 'Aye!'\n",
67
+ :no_wrap => true
68
+ }
69
+ assert ok?
70
+ assert_equal "alert('Aye!');", body
71
+ end
72
+
73
+ it "passes default coffee options to the coffee engine" do
74
+ mock_app {
75
+ set :coffee, :no_wrap => true # default coffee style is :nested
76
+ get '/' do
77
+ coffee "alert 'Aye!'\n"
78
+ end
79
+ }
80
+ get '/'
81
+ assert ok?
82
+ assert_equal "alert('Aye!');", body
83
+ end
84
+ end
85
+
86
+ rescue
87
+ warn "#{$!.to_s}: skipping coffee tests"
88
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+ require File.dirname(__FILE__) + '/helper'
3
+
4
+ class BaseTest < Test::Unit::TestCase
5
+ setup do
6
+ @base = Sinatra.new(Sinatra::Base)
7
+ @base.set :views, File.dirname(__FILE__) + "/views"
8
+ end
9
+
10
+ it 'allows unicode strings in ascii templates per default (1.9)' do
11
+ @base.new.haml(:ascii, {}, :value => "åkej")
12
+ end
13
+
14
+ it 'allows ascii strings in unicode templates per default (1.9)' do
15
+ next unless defined? Encoding
16
+ @base.new.haml(:utf8, {}, :value => "Some Lyrics".encode("ASCII"))
17
+ end
18
+ end
@@ -55,7 +55,7 @@ class BeforeFilterTest < Test::Unit::TestCase
55
55
 
56
56
  get '/foo'
57
57
  assert redirect?
58
- assert_equal '/bar', response['Location']
58
+ assert_equal 'http://example.org/bar', response['Location']
59
59
  assert_equal '', body
60
60
  end
61
61
 
@@ -121,6 +121,29 @@ class BeforeFilterTest < Test::Unit::TestCase
121
121
  assert_equal File.read(__FILE__), body
122
122
  assert !ran_filter
123
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
124
147
  end
125
148
 
126
149
  class AfterFilterTest < Test::Unit::TestCase
@@ -166,7 +189,7 @@ class AfterFilterTest < Test::Unit::TestCase
166
189
 
167
190
  get '/foo'
168
191
  assert redirect?
169
- assert_equal '/bar', response['Location']
192
+ assert_equal 'http://example.org/bar', response['Location']
170
193
  assert_equal '', body
171
194
  end
172
195
 
@@ -218,4 +241,40 @@ class AfterFilterTest < Test::Unit::TestCase
218
241
  assert_equal File.read(__FILE__), body
219
242
  assert !ran_filter
220
243
  end
244
+
245
+ it 'takes an optional route pattern' do
246
+ ran_filter = false
247
+ mock_app do
248
+ after("/b*") { ran_filter = true }
249
+ get('/foo') { }
250
+ get('/bar') { }
251
+ end
252
+ get '/foo'
253
+ assert !ran_filter
254
+ get '/bar'
255
+ assert ran_filter
256
+ end
257
+
258
+ it 'generates block arguments from route pattern' do
259
+ subpath = nil
260
+ mock_app do
261
+ after("/foo/:sub") { |s| subpath = s }
262
+ get('/foo/*') { }
263
+ end
264
+ get '/foo/bar'
265
+ assert_equal subpath, 'bar'
266
+ end
267
+
268
+ it 'is possible to access url params from the route param' do
269
+ ran = false
270
+ mock_app do
271
+ get('/foo/*') { }
272
+ before('/foo/:sub') do
273
+ assert_equal params[:sub], 'bar'
274
+ ran = true
275
+ end
276
+ end
277
+ get '/foo/bar'
278
+ assert ran
279
+ end
221
280
  end
@@ -0,0 +1 @@
1
+ h1 "Hello From Markaby"
@@ -1,4 +1,5 @@
1
1
  ENV['RACK_ENV'] = 'test'
2
+ Encoding.default_external = "UTF-8" if defined? Encoding
2
3
 
3
4
  begin
4
5
  require 'rack'
@@ -1,4 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
+ require 'date'
2
3
 
3
4
  class HelpersTest < Test::Unit::TestCase
4
5
  def test_default
@@ -57,7 +58,7 @@ class HelpersTest < Test::Unit::TestCase
57
58
  get '/'
58
59
  assert_equal 302, status
59
60
  assert_equal '', body
60
- assert_equal '/foo', response['Location']
61
+ assert_equal 'http://example.org/foo', response['Location']
61
62
  end
62
63
 
63
64
  it 'uses the code given when specified' do
@@ -71,7 +72,7 @@ class HelpersTest < Test::Unit::TestCase
71
72
  get '/'
72
73
  assert_equal 301, status
73
74
  assert_equal '', body
74
- assert_equal '/foo', response['Location']
75
+ assert_equal 'http://example.org/foo', response['Location']
75
76
  end
76
77
 
77
78
  it 'redirects back to request.referer when passed back' do
@@ -84,7 +85,31 @@ class HelpersTest < Test::Unit::TestCase
84
85
  request = Rack::MockRequest.new(@app)
85
86
  response = request.get('/try_redirect', 'HTTP_REFERER' => '/foo')
86
87
  assert_equal 302, response.status
87
- assert_equal '/foo', response['Location']
88
+ assert_equal 'http://example.org/foo', response['Location']
89
+ end
90
+
91
+ it 'redirects using a non-standard HTTP port' do
92
+ mock_app {
93
+ get '/' do
94
+ redirect '/foo'
95
+ end
96
+ }
97
+
98
+ request = Rack::MockRequest.new(@app)
99
+ response = request.get('/', 'SERVER_PORT' => '81')
100
+ assert_equal 'http://example.org:81/foo', response['Location']
101
+ end
102
+
103
+ it 'redirects using a non-standard HTTPS port' do
104
+ mock_app {
105
+ get '/' do
106
+ redirect '/foo'
107
+ end
108
+ }
109
+
110
+ request = Rack::MockRequest.new(@app)
111
+ response = request.get('/', 'SERVER_PORT' => '444')
112
+ assert_equal 'http://example.org:444/foo', response['Location']
88
113
  end
89
114
  end
90
115
 
@@ -266,21 +291,21 @@ class HelpersTest < Test::Unit::TestCase
266
291
  }
267
292
 
268
293
  get '/'
269
- assert_equal 'text/plain', response['Content-Type']
294
+ assert_equal 'text/plain;charset=utf-8', response['Content-Type']
270
295
  assert_equal 'Hello World', body
271
296
  end
272
297
 
273
298
  it 'takes media type parameters (like charset=)' do
274
299
  mock_app {
275
300
  get '/' do
276
- content_type 'text/html', :charset => 'utf-8'
301
+ content_type 'text/html', :charset => 'latin1'
277
302
  "<h1>Hello, World</h1>"
278
303
  end
279
304
  }
280
305
 
281
306
  get '/'
282
307
  assert ok?
283
- assert_equal 'text/html;charset=utf-8', response['Content-Type']
308
+ assert_equal 'text/html;charset=latin1', response['Content-Type']
284
309
  assert_equal "<h1>Hello, World</h1>", body
285
310
  end
286
311
 
@@ -295,7 +320,7 @@ class HelpersTest < Test::Unit::TestCase
295
320
 
296
321
  get '/foo.xml'
297
322
  assert ok?
298
- assert_equal 'application/foo', response['Content-Type']
323
+ assert_equal 'application/foo;charset=utf-8', response['Content-Type']
299
324
  assert_equal 'I AM FOO', body
300
325
  end
301
326
 
@@ -341,7 +366,19 @@ class HelpersTest < Test::Unit::TestCase
341
366
  it 'sets the Content-Type response header if a mime-type can be located' do
342
367
  send_file_app
343
368
  get '/file.txt'
344
- assert_equal 'text/plain', response['Content-Type']
369
+ assert_equal 'text/plain;charset=utf-8', response['Content-Type']
370
+ end
371
+
372
+ it 'sets the Content-Type response header if type option is set to a file extesion' do
373
+ send_file_app :type => 'html'
374
+ get '/file.txt'
375
+ assert_equal 'text/html;charset=utf-8', response['Content-Type']
376
+ end
377
+
378
+ it 'sets the Content-Type response header if type option is set to a mime type' do
379
+ send_file_app :type => 'application/octet-stream'
380
+ get '/file.txt'
381
+ assert_equal 'application/octet-stream;charset=utf-8', response['Content-Type']
345
382
  end
346
383
 
347
384
  it 'sets the Content-Length response header' do
@@ -423,42 +460,109 @@ class HelpersTest < Test::Unit::TestCase
423
460
  end
424
461
 
425
462
  describe 'last_modified' do
426
- setup do
427
- now = Time.now
428
- mock_app {
429
- get '/' do
430
- body { 'Hello World' }
431
- last_modified now
432
- 'Boo!'
433
- end
434
- }
435
- @now = now
436
- end
463
+ it 'ignores nil' do
464
+ mock_app do
465
+ get '/' do last_modified nil; 200; end
466
+ end
437
467
 
438
- it 'sets the Last-Modified header to a valid RFC 2616 date value' do
439
468
  get '/'
440
- assert_equal @now.httpdate, response['Last-Modified']
469
+ assert ! response['Last-Modified']
441
470
  end
442
471
 
443
- it 'returns a body when conditional get misses' do
444
- get '/'
445
- assert_equal 200, status
446
- assert_equal 'Boo!', body
447
- end
472
+ [Time, DateTime].each do |klass|
473
+ describe "with #{klass.name}" do
474
+ setup do
475
+ last_modified_time = klass.now
476
+ mock_app do
477
+ get '/' do
478
+ last_modified last_modified_time
479
+ 'Boo!'
480
+ end
481
+ end
482
+ @last_modified_time = Time.parse last_modified_time.to_s
483
+ end
448
484
 
449
- it 'halts when a conditional GET matches' do
450
- get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @now.httpdate }
451
- assert_equal 304, status
452
- assert_equal '', body
453
- end
485
+ # fixes strange missing test error when running complete test suite.
486
+ it("does not complain about missing tests") { }
454
487
 
455
- it 'ignores nil' do
456
- mock_app {
457
- get '/' do last_modified nil; 200; end
458
- }
488
+ context "when there's no If-Modified-Since header" do
489
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
490
+ get '/'
491
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
492
+ end
459
493
 
460
- get '/'
461
- assert ! response['Last-Modified']
494
+ it 'conditional GET misses and returns a body' do
495
+ get '/'
496
+ assert_equal 200, status
497
+ assert_equal 'Boo!', body
498
+ end
499
+ end
500
+
501
+ context "when there's an invalid If-Modified-Since header" do
502
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
503
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'a really weird date' }
504
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
505
+ end
506
+
507
+ it 'conditional GET misses and returns a body' do
508
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'a really weird date' }
509
+ assert_equal 200, status
510
+ assert_equal 'Boo!', body
511
+ end
512
+ end
513
+
514
+ context "when the resource has been modified since the If-Modified-Since header date" do
515
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
516
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time - 1).httpdate }
517
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
518
+ end
519
+
520
+ it 'conditional GET misses and returns a body' do
521
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time - 1).httpdate }
522
+ assert_equal 200, status
523
+ assert_equal 'Boo!', body
524
+ end
525
+
526
+ it 'does not rely on string comparison' do
527
+ mock_app do
528
+ get '/compare' do
529
+ last_modified "Mon, 18 Oct 2010 20:57:11 GMT"
530
+ "foo"
531
+ end
532
+ end
533
+
534
+ get '/compare', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2010 23:43:52 GMT' }
535
+ assert_equal 200, status
536
+ assert_equal 'foo', body
537
+ end
538
+ end
539
+
540
+ context "when the resource has been modified on the exact If-Modified-Since header date" do
541
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
542
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @last_modified_time.httpdate }
543
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
544
+ end
545
+
546
+ it 'conditional GET matches and halts' do
547
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @last_modified_time.httpdate }
548
+ assert_equal 304, status
549
+ assert_equal '', body
550
+ end
551
+ end
552
+
553
+ context "when the resource hasn't been modified since the If-Modified-Since header date" do
554
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
555
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time + 1).httpdate }
556
+ assert_equal @last_modified_time.httpdate, response['Last-Modified']
557
+ end
558
+
559
+ it 'conditional GET matches and halts' do
560
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time + 1).httpdate }
561
+ assert_equal 304, status
562
+ assert_equal '', body
563
+ end
564
+ end
565
+ end
462
566
  end
463
567
  end
464
568