renee-url-generation 0.4.0.pre1

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.
@@ -0,0 +1,128 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe Renee::Core::Responding do
4
+ describe "#interpret_response" do
5
+ it "should render from a number" do
6
+ mock_app do
7
+ path('/') { halt 200 }
8
+ end
9
+ get '/'
10
+ assert_equal 200, response.status
11
+ assert_equal 'Status code 200', response.body
12
+ end
13
+
14
+ it "should render from a symbol" do
15
+ mock_app do
16
+ path('/') { halt :not_found }
17
+ end
18
+ get '/'
19
+ assert_equal 404, response.status
20
+ assert_equal 'Status code 404', response.body
21
+ end
22
+
23
+ it "should render from a string" do
24
+ mock_app do
25
+ path('/') { halt "hello!" }
26
+ end
27
+ get '/'
28
+ assert_equal 200, response.status
29
+ assert_equal 'hello!', response.body
30
+ end
31
+
32
+ it "should render from an array" do
33
+ mock_app do
34
+ path('/') { halt 500, "hello!" }
35
+ end
36
+ get '/'
37
+ assert_equal 500, response.status
38
+ assert_equal 'hello!', response.body
39
+ end
40
+
41
+ it "should render from an array with a symbol" do
42
+ mock_app do
43
+ path('/') { halt :payment_required, "hello!" }
44
+ end
45
+ get '/'
46
+ assert_equal 403, response.status
47
+ assert_equal 'hello!', response.body
48
+ end
49
+
50
+ it "should render a rack-sized array as a rack response" do
51
+ mock_app do
52
+ path('/') { halt [200, {'Content-Type' => 'text/plain'}, []] }
53
+ end
54
+ get '/'
55
+ assert_equal 200, response.status
56
+ end
57
+ end
58
+
59
+ describe "#respond" do
60
+ it "should allow respond! with response init arguments" do
61
+ mock_app do
62
+ get do
63
+ respond!("hello!", 403, "foo" => "bar")
64
+ end
65
+ end
66
+ get "/"
67
+ assert_equal 403, response.status
68
+ assert_equal "bar", response.headers["foo"]
69
+ assert_equal "hello!", response.body
70
+ end # respond!
71
+
72
+ it "should allow respond!" do
73
+ mock_app do
74
+ get do
75
+ respond! { status 403; headers :foo => "bar"; body "hello!" }
76
+ end
77
+ end
78
+ get "/"
79
+ assert_equal 403, response.status
80
+ assert_equal "bar", response.headers["foo"]
81
+ assert_equal "hello!", response.body
82
+ end # respond!
83
+
84
+ it "should allow respond" do
85
+ mock_app do
86
+ get do
87
+ halt(respond { status 403; headers :foo => "bar"; body "hello!" })
88
+ end
89
+ end
90
+ get "/"
91
+ assert_equal 403, response.status
92
+ assert_equal "bar", response.headers["foo"]
93
+ assert_equal "hello!", response.body
94
+ end # respond
95
+ end
96
+
97
+ describe "#redirect" do
98
+ it "should allow redirects" do
99
+ mock_app do
100
+ get { halt redirect('/hello') }
101
+ end
102
+
103
+ get '/'
104
+ assert_equal 302, response.status
105
+ assert_equal "/hello", response.headers['Location']
106
+ end
107
+
108
+ it "should accept custom status codes" do
109
+ mock_app do
110
+ get { halt redirect('/hello', 303) }
111
+ end
112
+
113
+ get '/'
114
+ assert_equal 303, response.status
115
+ assert_equal "/hello", response.headers['Location']
116
+ end
117
+
118
+ it "should allow redirect!" do
119
+ mock_app do
120
+ get { redirect!('/hello') }
121
+ end
122
+
123
+ get '/'
124
+ assert_equal 302, response.status
125
+ assert_equal "/hello", response.headers['Location']
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,443 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe Renee::Core::Routing do
4
+
5
+ def renee_for(path, options = {}, &block)
6
+ Renee.core(&block).call(Rack::MockRequest.env_for(path, options))
7
+ end
8
+
9
+ describe "with paths" do
10
+ it "generates a basic route" do
11
+ type = { 'Content-Type' => 'text/plain' }
12
+ mock_app do
13
+ path('/') { get { halt [200,type,['foo']] } }
14
+ path('bar') { put { halt [200,type,['bar']] } }
15
+
16
+ path '/foo' do
17
+ delete { halt [200,type,['hi']] }
18
+
19
+ path '/bar/har' do
20
+ get { halt [200,type,['foobar']] }
21
+ post { halt [200,type,['posted']] }
22
+ end
23
+
24
+ end
25
+ end
26
+ get '/'
27
+ assert_equal 200, response.status
28
+ assert_equal 'foo', response.body
29
+ put '/bar'
30
+ assert_equal 200, response.status
31
+ assert_equal 'bar', response.body
32
+ delete '/foo'
33
+ assert_equal 200, response.status
34
+ assert_equal 'hi', response.body
35
+ get '/foo/bar/har'
36
+ assert_equal 200, response.status
37
+ assert_equal 'foobar', response.body
38
+ post '/foo/bar/har'
39
+ assert_equal 200, response.status
40
+ assert_equal 'posted', response.body
41
+ end
42
+
43
+ describe "with trailing slashes" do
44
+ it "should ignore trailing slashes normally" do
45
+ type = { 'Content-Type' => 'text/plain' }
46
+ mock_app do
47
+ path('test') { get { halt [200,type,['test']] } }
48
+ end
49
+
50
+ get '/test/'
51
+ assert_equal 200, response.status
52
+ assert_equal 'test', response.body
53
+ get '/test'
54
+ assert_equal 200, response.status
55
+ assert_equal 'test', response.body
56
+ end
57
+
58
+ it "should not ignore trailing slashes if told not to" do
59
+ type = { 'Content-Type' => 'text/plain' }
60
+ mock_app do
61
+ path('test').empty { get { halt [200,type,['test']] } }
62
+ end
63
+ get '/test/'
64
+ assert_equal 404, response.status
65
+ get '/test'
66
+ assert_equal 200, response.status
67
+ assert_equal 'test', response.body
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "with variables" do
73
+
74
+ it "generates for path" do
75
+ type = { 'Content-Type' => 'text/plain' }
76
+ mock_app do
77
+ path 'test' do
78
+ variable do |id|
79
+ get { halt [200,type,[id]] }
80
+ end
81
+ end
82
+
83
+ path 'two' do
84
+ var.var do |foo, bar|
85
+ get { halt [200, type,["#{foo}-#{bar}"]] }
86
+ end
87
+ end
88
+
89
+ path 'multi' do
90
+ multi_var(3) do |foo, bar, lol|
91
+ post { halt [200, type,["#{foo}-#{bar}-#{lol}"]] }
92
+ end
93
+ end
94
+ end
95
+
96
+ get '/test/hello'
97
+ assert_equal 200, response.status
98
+ assert_equal 'hello', response.body
99
+ get '/two/1/2'
100
+ assert_equal 200, response.status
101
+ assert_equal '1-2', response.body
102
+ post '/multi/1/2/3'
103
+ assert_equal 200, response.status
104
+ assert_equal '1-2-3', response.body
105
+ end
106
+
107
+ it "generates nested paths" do
108
+ type = { 'Content-Type' => 'text/plain' }
109
+ mock_app do
110
+ path 'test' do
111
+ var do |id|
112
+ path 'moar' do
113
+ post { halt [200, type, [id]] }
114
+ end
115
+
116
+ path 'more' do
117
+ var.var do |foo, bar|
118
+ get { halt [200, type, ["#{foo}-#{bar}"]] }
119
+
120
+ path 'woo' do
121
+ get { halt [200, type, ["#{foo}-#{bar}-woo"]] }
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ post '/test/world/moar'
130
+ assert_equal 200, response.status
131
+ assert_equal 'world', response.body
132
+ get '/test/world/more/1/2'
133
+ assert_equal 200, response.status
134
+ assert_equal '1-2', response.body
135
+ get '/test/world/more/1/2/woo'
136
+ assert_equal 200, response.status
137
+ assert_equal '1-2-woo', response.body
138
+ end
139
+
140
+ it "accepts an typcasts integers" do
141
+ type = { 'Content-Type' => 'text/plain' }
142
+ mock_app do
143
+ path 'add' do
144
+ var(:integer).var(:integer) do |a, b|
145
+ halt [200, type, ["#{a + b}"]]
146
+ end
147
+ end
148
+ end
149
+
150
+ get '/add/3/4'
151
+ assert_equal 200, response.status
152
+ assert_equal '7', response.body
153
+ end
154
+
155
+ it "can take an optional variable" do
156
+ type = { 'Content-Type' => 'text/plain' }
157
+ mock_app do
158
+ path 'add' do
159
+ var(:integer).optional(:integer) do |a, b|
160
+ b ||= a
161
+ halt [200, type, ["#{a + b}"]]
162
+ end
163
+ end
164
+ end
165
+
166
+ get '/add/3/4'
167
+ assert_equal 200, response.status
168
+ assert_equal '7', response.body
169
+ get '/add/3'
170
+ assert_equal 200, response.status
171
+ assert_equal '6', response.body
172
+ end
173
+
174
+ it "allows arbitrary ranges of values" do
175
+ type = { 'Content-Type' => 'text/plain' }
176
+ mock_app do
177
+ path 'add' do
178
+ multi_var(2..5, :integer).get do |numbers|
179
+ halt [200, type, ["Add up to #{numbers.inject(numbers.shift) {|m, i| m += i}}"]]
180
+ end
181
+ end
182
+ end
183
+
184
+ get '/add/3/4'
185
+ assert_equal 200, response.status
186
+ assert_equal 'Add up to 7', response.body
187
+ get '/add/3/4/6/7'
188
+ assert_equal 200, response.status
189
+ assert_equal 'Add up to 20', response.body
190
+ get '/add/3/4/6/7/8/10/2'
191
+ assert_equal 404, response.status
192
+ end
193
+
194
+ it "accepts allows repeating vars" do
195
+ type = { 'Content-Type' => 'text/plain' }
196
+ mock_app do
197
+ path 'add' do
198
+ glob :integer do |numbers|
199
+ halt [200, type, ["Add up to #{numbers.inject(numbers.shift) {|m, i| m += i}}"]]
200
+ end
201
+ end
202
+ end
203
+
204
+ get '/add/3/4'
205
+ assert_equal 200, response.status
206
+ assert_equal 'Add up to 7', response.body
207
+ get '/add/3/4/6/7'
208
+ assert_equal 200, response.status
209
+ assert_equal 'Add up to 20', response.body
210
+ end
211
+
212
+ it "accepts a regexp" do
213
+ type = { 'Content-Type' => 'text/plain' }
214
+ mock_app do
215
+ path 'add' do
216
+ var(/foo|bar/).var(/foo|bar/) do |a, b|
217
+ halt [200, type, ["#{a + b}"]]
218
+ end
219
+ end
220
+ end
221
+
222
+ get '/add/bar/foo'
223
+ assert_equal 200, response.status
224
+ assert_equal 'barfoo', response.body
225
+ end
226
+ end
227
+
228
+ describe "with remainder" do
229
+
230
+ it "matches the rest of the routes" do
231
+ type = { 'Content-Type' => 'text/plain' }
232
+ mock_app do
233
+ path 'test' do
234
+ get { halt [200,type,['test']] }
235
+
236
+ remainder do |rest|
237
+ post { halt [200, type, ["test-#{rest}"]] }
238
+ end
239
+ end
240
+
241
+ remainder do |rest|
242
+ halt [200, type, [rest]]
243
+ end
244
+ end
245
+
246
+ get '/a/b/c'
247
+ assert_equal 200, response.status
248
+ assert_equal '/a/b/c', response.body
249
+ post '/test/world/moar'
250
+ assert_equal 200, response.status
251
+ assert_equal 'test-/world/moar', response.body
252
+ end
253
+ end
254
+
255
+ describe "with extensions" do
256
+ it "should match an extension" do
257
+ type = { 'Content-Type' => 'text/plain' }
258
+ mock_app do
259
+ path('/test').get do
260
+ case extension
261
+ when 'html' then halt [200, type, ['test html']]
262
+ when 'json' then halt [200, type, ['test json']]
263
+ when nil then halt [200, type, ['test nope']]
264
+ else halt [406, type, ['unknown']]
265
+ end
266
+ end
267
+
268
+ extension 'html' do
269
+ halt [200, type, ['test html']]
270
+ end
271
+ end
272
+ get '/test.html'
273
+ assert_equal 200, response.status
274
+ assert_equal 'test html', response.body
275
+ get '/test.json'
276
+ assert_equal 200, response.status
277
+ assert_equal 'test json', response.body
278
+ get '/test.xml'
279
+ assert_equal 406, response.status
280
+ end
281
+
282
+ it "should match an extension when there is a non-specific variable before" do
283
+ mock_app do
284
+ var do |id|
285
+ case extension
286
+ when 'html' then halt "html #{id}"
287
+ when 'xml' then halt "xml #{id}"
288
+ when nil then halt "none #{id}"
289
+ end
290
+ end
291
+ end
292
+ get '/var.html'
293
+ assert_equal 200, response.status
294
+ assert_equal 'html var', response.body
295
+ get '/var.xml'
296
+ assert_equal 200, response.status
297
+ assert_equal 'xml var', response.body
298
+ get '/var'
299
+ assert_equal 200, response.status
300
+ assert_equal 'none var', response.body
301
+ end
302
+ end
303
+
304
+ describe "with part and part_var" do
305
+ it "should match a part" do
306
+ mock_app do
307
+ part '/test' do
308
+ part 'more' do
309
+ halt :ok
310
+ end
311
+ end
312
+ end
313
+ get '/testmore'
314
+ assert_equal 200, response.status
315
+ end
316
+
317
+ it "should match a part_var" do
318
+ mock_app do
319
+ part '/test' do
320
+ part 'more' do
321
+ part_var do |var|
322
+ path 'test' do
323
+ halt var
324
+ end
325
+ end
326
+ end
327
+ end
328
+ end
329
+ get '/testmorethisvar/test'
330
+ assert_equal 'thisvar', response.body
331
+ end
332
+
333
+ it "should match a part_var with Integer" do
334
+ mock_app do
335
+ part '/test' do
336
+ part 'more' do
337
+ part_var :integer do |var|
338
+ path 'test' do
339
+ halt var.to_s
340
+ end
341
+ end
342
+ end
343
+ end
344
+ end
345
+ get '/testmore123/test'
346
+ assert_equal '123', response.body
347
+ get '/testmore123a/test'
348
+ assert_equal 404, response.status
349
+ end
350
+ end
351
+
352
+ describe "multiple Renee's" do
353
+ it "should pass between them normally" do
354
+ type = { 'Content-Type' => 'text/plain' }
355
+ mock_app do
356
+ path 'test' do
357
+ halt run Renee.core {
358
+ path 'time' do
359
+ halt halt [200,type,['test']]
360
+ end
361
+ }
362
+ end
363
+ end
364
+ get '/test/time'
365
+ assert_equal 200, response.status
366
+ assert_equal 'test', response.body
367
+ end
368
+
369
+ it "should support run! passing between" do
370
+ type = { 'Content-Type' => 'text/plain' }
371
+ mock_app do
372
+ path 'test' do
373
+ run! Renee.core {
374
+ path 'time' do
375
+ halt halt [200,type,['test']]
376
+ end
377
+ }
378
+ end
379
+ end
380
+ get '/test/time'
381
+ assert_equal 200, response.status
382
+ assert_equal 'test', response.body
383
+ end
384
+ end
385
+
386
+ describe "#build" do
387
+ it "should allow building in-place rack apps" do
388
+ type = { 'Content-Type' => 'text/plain' }
389
+ mock_app do
390
+ path('test') do
391
+ halt build {
392
+ run proc {|env| [200, type, ['someone built me!']] }
393
+ }
394
+ end
395
+ end
396
+
397
+ get '/test'
398
+ assert_equal 200, response.status
399
+ assert_equal 'someone built me!', response.body
400
+ end
401
+ end
402
+
403
+ describe "#part and #part_var" do
404
+ it "should match parts and partial vars" do
405
+ mock_app do
406
+ part('test') {
407
+ part_var(:integer) { |id|
408
+ part('more') {
409
+ halt "the id is #{id}"
410
+ }
411
+ }
412
+ }
413
+ end
414
+ get '/test123more'
415
+ assert_equal 200, response.status
416
+ assert_equal 'the id is 123', response.body
417
+ end
418
+ end
419
+
420
+ describe "request methods" do
421
+ it "should allow request method routing when you're matching on /" do
422
+ type = { 'Content-Type' => 'text/plain' }
423
+ mock_app do
424
+ get { halt [200, type, ["hiya"]] }
425
+ end
426
+
427
+ get '/'
428
+ assert_equal 200, response.status
429
+ assert_equal 'hiya', response.body
430
+ end
431
+
432
+ it "should raise if you fail to halt" do
433
+ type = { 'Content-Type' => 'text/plain' }
434
+ mock_app do
435
+ get { }
436
+ halt :ok
437
+ end
438
+
439
+ get '/'
440
+ assert_equal 404, response.status
441
+ end
442
+ end
443
+ end
@@ -0,0 +1,4 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'renee/core'
3
+ # Load shared test helpers
4
+ require File.expand_path('../../test_helper', __FILE__)
@@ -0,0 +1,57 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe Renee::Core::Matcher do
4
+ it "should transform variables" do
5
+ mock_app {
6
+ var :symbol do |i|
7
+ halt i.inspect
8
+ end
9
+ }.setup {
10
+ register_variable_type(:symbol, /[a-z_]+/).on_transform{|v| v.to_sym}
11
+ }
12
+ get '/test'
13
+ assert_equal ":test", response.body
14
+ end
15
+
16
+ it "should halt on errors if told to" do
17
+ mock_app {
18
+ var :symbol do |i|
19
+ halt i.inspect
20
+ end
21
+ }.setup {
22
+ register_variable_type(:symbol, /[a-z_]+/).on_transform{|v| v.to_sym}.raise_on_error!
23
+ }
24
+ get '/123'
25
+ assert_equal 400, response.status
26
+ end
27
+
28
+ it "should allow custom error handling behaviour on values that don't match" do
29
+ mock_app {
30
+ var :symbol do |i|
31
+ halt i.inspect
32
+ end
33
+ }.setup {
34
+ register_variable_type(:symbol, /[a-z_]+/).on_transform{|v| v.to_sym}.on_error{|v| halt 500 }
35
+ }
36
+ get '/123'
37
+ assert_equal 500, response.status
38
+ end
39
+
40
+ it "should allow composite variable types" do
41
+ mock_app {
42
+ path("plus10").var(:int_or_hex) do |i|
43
+ halt "plus10: #{i + 10}"
44
+ end
45
+ }.setup {
46
+ register_variable_type(:int, /[0-9]+/).on_transform{|v| Integer(v)}
47
+ register_variable_type(:hex, /0x[0-9a-f]+/).on_transform{|v| v.to_i(16)}
48
+ register_variable_type(:int_or_hex, [:hex, :int])
49
+ }
50
+ get '/plus10/123'
51
+ assert_equal 'plus10: 133', response.body
52
+ get '/plus10/0x7b'
53
+ assert_equal 'plus10: 133', response.body
54
+ end
55
+ end
56
+
57
+
@@ -0,0 +1,70 @@
1
+ require 'rubygems'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ gem 'rack-test'
5
+ require 'rack/test'
6
+
7
+ class ColoredIO
8
+ ESC = "\e["
9
+ NND = "#{ESC}0m"
10
+
11
+ def initialize(io)
12
+ @io = io
13
+ end
14
+
15
+ def print(o)
16
+ case o
17
+ when "."
18
+ @io.send(:print, "#{ESC}32m#{o}#{NND}")
19
+ when "E"
20
+ @io.send(:print, "#{ESC}33m#{o}#{NND}")
21
+ when "F"
22
+ @io.send(:print, "#{ESC}31m#{o}#{NND}")
23
+ else
24
+ @io.send(:print, o)
25
+ end
26
+ end
27
+
28
+ def puts(*o)
29
+ super
30
+ end
31
+ end
32
+
33
+ MiniTest::Unit.output = ColoredIO.new(MiniTest::Unit.output)
34
+
35
+ ## TEST HELPERS
36
+ class MiniTest::Spec
37
+ include Rack::Test::Methods
38
+
39
+ # Sets up a Sinatra::Base subclass defined with the block
40
+ # given. Used in setup or individual spec methods to establish
41
+ # the application.
42
+ def mock_app(&block)
43
+ path = default_views_path
44
+ @app = Renee.core(&block).setup {
45
+ views_path(path) if respond_to?(:views_path)
46
+ }
47
+ end
48
+
49
+ def default_views_path
50
+ File.dirname(__FILE__) + "/views"
51
+ end
52
+
53
+ def app
54
+ Rack::Lint.new(@app)
55
+ end
56
+
57
+ alias :response :last_response
58
+
59
+ # create_view :index, "test", :haml
60
+ def create_view(name, content, engine=:erb)
61
+ FileUtils.mkdir_p(default_views_path)
62
+ file = File.join(default_views_path, name.to_s + ".#{engine}")
63
+ File.open(file, 'w') { |io| io.write content }
64
+ end
65
+
66
+ # Removes the view folder after the test
67
+ def remove_views
68
+ FileUtils.rm_rf(File.dirname(__FILE__) + "/views")
69
+ end
70
+ end