File: mapped_error_test.rb

package info (click to toggle)
ruby-sinatra 1.3.2-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 1,200 kB
  • sloc: ruby: 7,675; makefile: 5
file content (259 lines) | stat: -rw-r--r-- 6,195 bytes parent folder | download
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
require File.expand_path('../helper', __FILE__)

class FooError < RuntimeError
end

class FooNotFound < Sinatra::NotFound
end

class FooSpecialError < RuntimeError
  def code; 501 end
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 {
        set :raise_errors, false
        error(FooError) { 'Foo!' }
        get '/' do
          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 {
        set :raise_errors, false
        error(Exception) { 'Exception!' }
        get '/' do
          raise FooError
        end
      }

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

    it 'walks down inheritance chain for errors' do
      mock_app {
        set :raise_errors, false
        error(RuntimeError) { 'Exception!' }
        get '/' do
          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 {
        set :raise_errors, false
        error(Exception) { 'Exception!' }
        error(FooError) { 'FooError!' }
        error(RuntimeError) { 'Exception!' }
        get '/' do
          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 {
        set :raise_errors, false
        error(FooError) {
          assert env.include?('sinatra.error')
          assert env['sinatra.error'].kind_of?(FooError)
          'looks good'
        }
        get '/' do
          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 {
        set :raise_errors, true
        get '/' do
          raise FooError
        end
      }
      assert_raise(FooError) { get '/' }
    end

    it "calls error handlers before raising errors even when raise_errors is set" do
      mock_app {
        set :raise_errors, true
        error(FooError) { "she's there." }
        get '/' do
          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) { get('/') { raise Sinatra::NotFound }}
      assert_nothing_raised { get '/' }
      assert_equal 404, status
    end

    it "cascades for subclasses of Sinatra::NotFound" do
      mock_app {
        set :raise_errors, true
        error(FooNotFound) { "foo! not found." }
        get '/' do
          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 do
          "Lost, are we?"
        end
      }

      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) {
        set :raise_errors, false
        get '/' do
          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) {
        set :raise_errors, false
        error(FooError) { 'subclass' }
        get '/' do
          raise FooError
        end
      }

      get '/'
      assert_equal 'subclass', body
    end

    it 'honors Exception#code 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
  end

  describe 'Custom Error Pages' do
    it 'allows numeric status code mappings to be registered with ::error' do
      mock_app {
        set :raise_errors, false
        error(500) { 'Foo!' }
        get '/' do
          [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 {
        set :raise_errors, false
        error(500..550) { "Error: #{response.status}" }
        get '/' do
          [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 {
        set :raise_errors, false
        error(409..411, 503..509) { "Error: #{response.status}" }
        get '/' do
          [507, {}, 'A very special error']
        end
      }
      get '/'
      assert_equal 507, status
      assert_equal 'Error: 507', body
    end

    class FooError < RuntimeError
    end

    it 'runs after exception mappings and overwrites body' do
      mock_app {
        set :raise_errors, false
        error FooError do
          response.status = 502
          'from exception mapping'
        end
        error(500) { 'from 500 handler' }
        error(502) { 'from custom error page' }

        get '/' do
          raise FooError
        end
      }
      get '/'
      assert_equal 502, status
      assert_equal 'from custom error page', body
    end
  end
end