File: mapped_error_test.rb

package info (click to toggle)
ruby-sinatra 1.4.5-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,524 kB
  • ctags: 483
  • sloc: ruby: 9,521; makefile: 5
file content (285 lines) | stat: -rw-r--r-- 7,363 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
require File.expand_path('../helper', __FILE__)

class FooError < RuntimeError
end

class FooNotFound < Sinatra::NotFound
end

class FooSpecialError < RuntimeError
  def http_status; 501 end
end

class FooStatusOutOfRangeError < RuntimeError
  def code; 4000 end
end

class FooWithCode < RuntimeError
  def code; 419 end
end

class FirstError < RuntimeError; end
class SecondError < RuntimeError; end

class MappedErrorTest < Test::Unit::TestCase
  def test_default
    assert true
  end

  describe 'Exception Mappings' do
    it 'invokes handlers registered with ::error when raised' do
      mock_app do
        set :raise_errors, false
        error(FooError) { 'Foo!' }
        get('/') { raise FooError }
      end
      get '/'
      assert_equal 500, status
      assert_equal 'Foo!', body
    end

    it 'passes the exception object to the error handler' do
      mock_app do
        set :raise_errors, false
        error(FooError) { |e| assert_equal(FooError, e.class) }
        get('/') { raise FooError }
      end
      get('/')
    end

    it 'uses the Exception handler if no matching handler found' do
      mock_app do
        set :raise_errors, false
        error(Exception) { 'Exception!' }
        get('/') { raise FooError }
      end

      get '/'
      assert_equal 500, status
      assert_equal 'Exception!', body
    end

    it 'walks down inheritance chain for errors' do
      mock_app do
        set :raise_errors, false
        error(RuntimeError) { 'Exception!' }
        get('/') { raise FooError }
      end

      get '/'
      assert_equal 500, status
      assert_equal 'Exception!', body
    end

    it 'favors subclass handler over superclass handler if available' do
      mock_app do
        set :raise_errors, false
        error(Exception) { 'Exception!' }
        error(FooError) { 'FooError!' }
        error(RuntimeError) { 'Exception!' }
        get('/') { raise FooError }
      end

      get '/'
      assert_equal 500, status
      assert_equal 'FooError!', body
    end

    it "sets env['sinatra.error'] to the rescued exception" do
      mock_app do
        set :raise_errors, false
        error(FooError) do
          assert env.include?('sinatra.error')
          assert env['sinatra.error'].kind_of?(FooError)
          'looks good'
        end
        get('/') { raise FooError }
      end
      get '/'
      assert_equal 'looks good', body
    end

    it "raises errors from the app when raise_errors set and no handler defined" do
      mock_app do
        set :raise_errors, true
        get('/') { raise FooError }
      end
      assert_raise(FooError) { get '/' }
    end

    it "calls error handlers before raising errors even when raise_errors is set" do
      mock_app do
        set :raise_errors, true
        error(FooError) { "she's there." }
        get('/') { raise FooError }
      end
      assert_nothing_raised { get '/' }
      assert_equal 500, status
    end

    it "never raises Sinatra::NotFound beyond the application" do
      mock_app(Sinatra::Application) do
        get('/') { raise Sinatra::NotFound }
      end
      assert_nothing_raised { get '/' }
      assert_equal 404, status
    end

    it "cascades for subclasses of Sinatra::NotFound" do
      mock_app do
        set :raise_errors, true
        error(FooNotFound) { "foo! not found." }
        get('/') { raise FooNotFound }
      end
      assert_nothing_raised { get '/' }
      assert_equal 404, status
      assert_equal 'foo! not found.', body
    end

    it 'has a not_found method for backwards compatibility' do
      mock_app { not_found { "Lost, are we?" } }

      get '/test'
      assert_equal 404, status
      assert_equal "Lost, are we?", body
    end

    it 'inherits error mappings from base class' do
      base = Class.new(Sinatra::Base)
      base.error(FooError) { 'base class' }

      mock_app(base) do
        set :raise_errors, false
        get('/') { raise FooError }
      end

      get '/'
      assert_equal 'base class', body
    end

    it 'overrides error mappings in base class' do
      base = Class.new(Sinatra::Base)
      base.error(FooError) { 'base class' }

      mock_app(base) do
        set :raise_errors, false
        error(FooError) { 'subclass' }
        get('/') { raise FooError }
      end

      get '/'
      assert_equal 'subclass', body
    end

    it 'honors Exception#http_status if present' do
      mock_app do
        set :raise_errors, false
        error(501) { 'Foo!' }
        get('/') { raise FooSpecialError }
      end
      get '/'
      assert_equal 501, status
      assert_equal 'Foo!', body
    end

    it 'does not use Exception#code by default' do
      mock_app do
        set :raise_errors, false
        get('/') { raise FooWithCode }
      end
      get '/'
      assert_equal 500, status
    end

    it 'uses Exception#code if use_code is enabled' do
      mock_app do
        set :raise_errors, false
        set :use_code, true
        get('/') { raise FooWithCode }
      end
      get '/'
      assert_equal 419, status
    end

    it 'does not rely on Exception#code for invalid codes' do
      mock_app do
        set :raise_errors, false
        set :use_code, true
        get('/') { raise FooStatusOutOfRangeError }
      end
      get '/'
      assert_equal 500, status
    end

    it "allows a stack of exception_handlers" do
      mock_app do
        set :raise_errors, false
        error(FirstError) { 'First!' }
        error(SecondError) { 'Second!' }
        get('/'){ raise SecondError }
      end
      get '/'
      assert_equal 500, status
      assert_equal 'Second!', body
    end

    it "allows an exception handler to pass control to the next exception handler" do
      mock_app do
        set :raise_errors, false
        error(500, FirstError) { 'First!' }
        error(500, SecondError) { pass }
        get('/') { raise 500 }
      end
      get '/'
      assert_equal 500, status
      assert_equal 'First!', body
    end

    it "allows an exception handler to handle the exception" do
      mock_app do
        set :raise_errors, false
        error(500, FirstError) { 'First!' }
        error(500, SecondError) { 'Second!' }
        get('/') { raise 500 }
      end
      get '/'
      assert_equal 500, status
      assert_equal 'Second!', body
    end
  end

  describe 'Custom Error Pages' do
    it 'allows numeric status code mappings to be registered with ::error' do
      mock_app do
        set :raise_errors, false
        error(500) { 'Foo!' }
        get('/') { [500, {}, 'Internal Foo Error'] }
      end
      get '/'
      assert_equal 500, status
      assert_equal 'Foo!', body
    end

    it 'allows ranges of status code mappings to be registered with :error' do
      mock_app do
        set :raise_errors, false
        error(500..550) { "Error: #{response.status}" }
        get('/') { [507, {}, 'A very special error'] }
      end
      get '/'
      assert_equal 507, status
      assert_equal 'Error: 507', body
    end

    it 'allows passing more than one range' do
      mock_app do
        set :raise_errors, false
        error(409..411, 503..509) { "Error: #{response.status}" }
        get('/') { [507, {}, 'A very special error'] }
      end
      get '/'
      assert_equal 507, status
      assert_equal 'Error: 507', body
    end
  end
end