rack-jet_router 1.2.0 → 1.3.0

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.
@@ -1,726 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- ###
4
- ### $Release: 1.2.0 $
5
- ### $Copyright: copyright(c) 2015 kuwata-lab.com all rights reserved $
6
- ### $License: MIT License $
7
- ###
8
-
9
- require_relative '../test_helper'
10
-
11
-
12
- describe Rack::JetRouter do
13
-
14
- welcome_app = proc {|env| [200, {}, ["welcome_app"]]}
15
- #
16
- book_list_api = proc {|env| [200, {}, ["book_list_api"]]}
17
- book_create_api = proc {|env| [200, {}, ["book_create_api"]]}
18
- book_new_api = proc {|env| [200, {}, ["book_new_api"]]}
19
- book_show_api = proc {|env| [200, {}, ["book_show_api"]]}
20
- book_update_api = proc {|env| [200, {}, ["book_update_api"]]}
21
- book_delete_api = proc {|env| [200, {}, ["book_delete_api"]]}
22
- book_edit_api = proc {|env| [200, {}, ["book_edit_api"]]}
23
- #
24
- comment_create_api = proc {|env| [200, {}, ["comment_create_api"]]}
25
- comment_update_api = proc {|env| [200, {}, ["comment_update_api"]]}
26
- #
27
- admin_book_list_app = proc {|env| [200, {}, ["admin_book_list_app"]]}
28
- admin_book_create_app = proc {|env| [200, {}, ["admin_book_create_app"]]}
29
- admin_book_new_app = proc {|env| [200, {}, ["admin_book_new_app"]]}
30
- admin_book_show_app = proc {|env| [200, {}, ["admin_book_show_app"]]}
31
- admin_book_update_app = proc {|env| [200, {}, ["admin_book_update_app"]]}
32
- admin_book_delete_app = proc {|env| [200, {}, ["admin_book_delete_app"]]}
33
- admin_book_edit_app = proc {|env| [200, {}, ["admin_book_edit_app"]]}
34
- #
35
- whole_urlpath_mapping = [
36
- ['/' , welcome_app],
37
- ['/index.html' , welcome_app],
38
- ['/api' , [
39
- ['/books' , [
40
- ['' , book_list_api],
41
- ['/new' , book_new_api],
42
- ['/:id' , book_show_api],
43
- ['/:id/edit' , book_edit_api],
44
- ]],
45
- ['/books/:book_id/comments', [
46
- ['' , comment_create_api],
47
- ['/:comment_id' , comment_update_api],
48
- ]],
49
- ]],
50
- ['/admin' , [
51
- ['/books' , [
52
- ['' , {:GET=>admin_book_list_app, :POST=>admin_book_create_app}],
53
- ['/:id' , {:GET=>admin_book_show_app, :PUT=>admin_book_update_app, :DELETE=>admin_book_delete_app}],
54
- ]],
55
- ]],
56
- ]
57
- #
58
- jet_router = Rack::JetRouter.new(whole_urlpath_mapping)
59
- #
60
- def new_env(req_method, req_path, opts={})
61
- opts[:method] = req_method.to_s
62
- env = ::Rack::MockRequest.env_for(req_path, opts)
63
- return env
64
- end
65
-
66
-
67
- describe '#range_of_urlpath_param()' do
68
-
69
- it "[!syrdh] returns Range object when urlpath_pattern contains just one param." do
70
- jet_router.instance_exec(self) do |_|
71
- r1 = range_of_urlpath_param('/books/:id')
72
- _.ok {r1} == (7..-1)
73
- _.ok {'/books/123'[r1]} == '123'
74
- r2 = range_of_urlpath_param('/books/:id.html')
75
- _.ok {r2} == (7..-6)
76
- _.ok {'/books/4567.html'[r2]} == '4567'
77
- end
78
- end
79
-
80
- it "[!skh4z] returns nil when urlpath_pattern contains more than two params." do
81
- jet_router.instance_exec(self) do |_|
82
- _.ok {range_of_urlpath_param('/books/:book_id/comments/:comment_id')} == nil
83
- _.ok {range_of_urlpath_param('/books/:id(:format)')} == nil
84
- end
85
- end
86
-
87
- it "[!acj5b] returns nil when urlpath_pattern contains no params." do
88
- jet_router.instance_exec(self) do |_|
89
- _.ok {range_of_urlpath_param('/books')} == nil
90
- end
91
- end
92
-
93
- end
94
-
95
-
96
- describe '#compile_urlpath_pattern()' do
97
-
98
- it "[!joozm] escapes metachars with backslash in text part." do
99
- jet_router.instance_exec(self) do |_|
100
- _.ok {compile_urlpath_pattern('/foo.html')} == ['/foo\.html', nil]
101
- end
102
- end
103
-
104
- it "[!rpezs] converts '/books/:id' into '/books/([^./]+)'." do
105
- jet_router.instance_exec(self) do |_|
106
- _.ok {compile_urlpath_pattern('/books/:id')} == ['/books/([^./]+)', ['id']]
107
- end
108
- end
109
-
110
- it "[!4dcsa] converts '/index(.:format)' into '/index(?:\.([^./]+))?'." do
111
- jet_router.instance_exec(self) do |_|
112
- _.ok {compile_urlpath_pattern('/index(.:format)')} == ['/index(?:\.([^./]+))?', ['format']]
113
- end
114
- end
115
-
116
- it "[!1d5ya] rethrns compiled string and nil when no urlpath parameters nor parens." do
117
- jet_router.instance_exec(self) do |_|
118
- _.ok {compile_urlpath_pattern('/index')} == ['/index', nil]
119
- end
120
- end
121
-
122
- it "[!of1zq] returns compiled string and urlpath param names when urlpath param or parens exist." do
123
- jet_router.instance_exec(self) do |_|
124
- _.ok {compile_urlpath_pattern('/books/:id')} == ['/books/([^./]+)', ['id']]
125
- _.ok {compile_urlpath_pattern('/books/:id(.:format)')} == ['/books/([^./]+)(?:\.([^./]+))?', ['id', 'format']]
126
- _.ok {compile_urlpath_pattern('/index(.html)')} == ['/index(?:\.html)?', []]
127
- end
128
- end
129
-
130
- end
131
-
132
-
133
- describe '#compile_mapping()' do
134
-
135
- it "[!xzo7k] returns regexp, hash, and array." do
136
- mapping = [
137
- ['/', welcome_app],
138
- ['/books/:id' , book_show_api],
139
- ]
140
- expected = '
141
- \A
142
- /books/[^./]+(\z)
143
- \z
144
- '.gsub(/\s+/, '')
145
- jet_router.instance_exec(self) do |_|
146
- rexp, dict, list = compile_mapping(mapping)
147
- _.ok {rexp} == Regexp.new(expected)
148
- _.ok {dict} == {
149
- '/' => welcome_app,
150
- }
151
- _.ok {list} == [
152
- [%r'\A/books/([^./]+)\z', ['id'], book_show_api, (7..-1)],
153
- ]
154
- end
155
- end
156
-
157
- it "[!iza1g] adds grouping if necessary." do
158
- mapping = [
159
- ['/api', [
160
- ['/books', [
161
- ['/:id' , book_show_api],
162
- ]],
163
- ]],
164
- ['/admin', [
165
- ['/books', [
166
- ['/:id' , admin_book_show_app],
167
- ]],
168
- ]],
169
- ]
170
- expected = '
171
- \A
172
- (?:
173
- /api
174
- /books
175
- /[^./]+(\z)
176
- |
177
- /admin
178
- /books
179
- /[^./]+(\z)
180
- )
181
- \z
182
- '.gsub(/\s+/, '')
183
- jet_router.instance_exec(self) do |_|
184
- rexp, dict, list = compile_mapping(mapping)
185
- _.ok {rexp} == Regexp.new(expected)
186
- _.ok {dict} == {}
187
- _.ok {list} == [
188
- [%r'\A/api/books/([^./]+)\z', ['id'], book_show_api, (11..-1)],
189
- [%r'\A/admin/books/([^./]+)\z', ['id'], admin_book_show_app, (13..-1)],
190
- ]
191
- end
192
- end
193
-
194
- it "[!pv2au] deletes unnecessary urlpath regexp." do
195
- mapping = [
196
- ['/' , welcome_app],
197
- ['/api', [
198
- ['/books', [
199
- ['' , book_list_api],
200
- ['/new' , book_new_api],
201
- ]],
202
- ['/books2', [
203
- ['/:id' , book_show_api],
204
- ]],
205
- ]],
206
- ]
207
- expected = '\A/api/books2/[^./]+(\z)\z'
208
- jet_router.instance_exec(self) do |_|
209
- rexp, dict, list = compile_mapping(mapping)
210
- _.ok {rexp} == Regexp.new(expected)
211
- _.ok {dict} == {
212
- '/' => welcome_app,
213
- '/api/books' => book_list_api,
214
- '/api/books/new' => book_new_api,
215
- }
216
- _.ok {list} == [
217
- [%r'\A/api/books2/([^./]+)\z', ['id'], book_show_api, (12..-1)],
218
- ]
219
- end
220
- end
221
-
222
- it "[!bh9lo] deletes unnecessary grouping." do
223
- mapping = [
224
- ['/api', [
225
- ['/books', [
226
- ['/:id' , book_show_api],
227
- ]],
228
- ]],
229
- ]
230
- expected = '
231
- \A
232
- /api
233
- /books
234
- /[^./]+(\z)
235
- \z
236
- '.gsub(/\s+/, '')
237
- jet_router.instance_exec(self) do |_|
238
- rexp, dict, list = compile_mapping(mapping)
239
- _.ok {rexp} == Regexp.new(expected)
240
- _.ok {dict} == {}
241
- _.ok {list} == [
242
- [%r'\A/api/books/([^./]+)\z', ['id'], book_show_api, (11..-1)],
243
- ]
244
- end
245
- end
246
-
247
- it "[!l63vu] handles urlpath pattern as fixed when no urlpath params." do
248
- mapping = [
249
- ['/api/books' , book_list_api],
250
- ]
251
- expected = '
252
- \A
253
- \z
254
- '.gsub(/\s+/, '')
255
- jet_router.instance_exec(self) do |_|
256
- rexp, dict, list = compile_mapping(mapping)
257
- _.ok {rexp} == Regexp.new(expected)
258
- _.ok {dict} == {
259
- '/api/books' => book_list_api,
260
- }
261
- _.ok {list} == [
262
- ]
263
- end
264
- end
265
-
266
- it "[!vfytw] handles urlpath pattern as variable when urlpath param exists." do
267
- mapping = [
268
- ['/api/books/:id' , book_show_api],
269
- ]
270
- expected = '
271
- \A
272
- /api/books/[^./]+(\z)
273
- \z
274
- '.gsub(/\s+/, '')
275
- jet_router.instance_exec(self) do |_|
276
- rexp, dict, list = compile_mapping(mapping)
277
- _.ok {rexp} == Regexp.new(expected)
278
- _.ok {dict} == {
279
- }
280
- _.ok {list} == [
281
- [%r'\A/api/books/([^./]+)\z', ['id'], book_show_api, (11..-1)],
282
- ]
283
- end
284
- end
285
-
286
- it "[!2ktpf] handles end-point." do
287
- mapping = [
288
- ['/' , welcome_app],
289
- ['/api/books' , book_list_api],
290
- ['/api/books/:id' , book_show_api],
291
- ]
292
- expected = '
293
- \A
294
- /api/books/[^./]+(\z)
295
- \z
296
- '.gsub(/\s+/, '')
297
- jet_router.instance_exec(self) do |_|
298
- rexp, dict, list = compile_mapping(mapping)
299
- _.ok {rexp} == Regexp.new(expected)
300
- _.ok {dict} == {
301
- '/' => welcome_app,
302
- '/api/books' => book_list_api,
303
- }
304
- _.ok {list} == [
305
- [%r'\A/api/books/([^./]+)\z', ['id'], book_show_api, (11..-1)],
306
- ]
307
- end
308
- end
309
-
310
- it "[!ospaf] accepts nested mapping." do
311
- mapping = [
312
- ['/admin', [
313
- ['/api', [
314
- ['/books', [
315
- ['', book_list_api],
316
- ['/:id', book_show_api],
317
- ]],
318
- ]],
319
- ]],
320
- ]
321
- expected = '
322
- \A
323
- /admin
324
- /api
325
- /books
326
- /[^./]+(\z)
327
- \z
328
- '.gsub(/\s+/, '')
329
- jet_router.instance_exec(self) do |_|
330
- rexp, dict, list = compile_mapping(mapping)
331
- _.ok {rexp} == Regexp.new(expected)
332
- _.ok {dict} == {
333
- '/admin/api/books' => book_list_api,
334
- }
335
- _.ok {list} == [
336
- [%r'\A/admin/api/books/([^./]+)\z', ['id'], book_show_api, (17..-1)],
337
- ]
338
- end
339
- end
340
-
341
- describe "[!guhdc] if mapping dict is specified..." do
342
-
343
- it "[!r7cmk] converts keys into string." do
344
- mapping = [
345
- ['/books', {:GET=>book_list_api, :POST=>book_create_api}]
346
- ]
347
- Rack::JetRouter.new([]).instance_exec(self) do |_|
348
- rexp, dict, list = compile_mapping(mapping)
349
- _.ok {dict['/books']} == {'GET'=>book_list_api, 'POST'=>book_create_api}
350
- end
351
- end
352
-
353
- it "[!z9kww] allows 'ANY' as request method." do
354
- mapping = [
355
- ['/books', {'ANY'=>book_list_api, 'POST'=>book_create_api}]
356
- ]
357
- Rack::JetRouter.new([]).instance_exec(self) do |_|
358
- rexp, dict, list = compile_mapping(mapping)
359
- _.ok {dict['/books']} == {'ANY'=>book_list_api, 'POST'=>book_create_api}
360
- end
361
- end
362
-
363
- it "[!k7sme] raises error when unknown request method specified." do
364
- mapping = [
365
- ['/books', {"UNLOCK"=>book_list_api}]
366
- ]
367
- Rack::JetRouter.new([]).instance_exec(self) do |_|
368
- pr = proc { compile_mapping(mapping) }
369
- _.ok {pr}.raise?(ArgumentError, '"UNLOCK": unknown request method.')
370
- end
371
- end
372
-
373
- end
374
-
375
- end
376
-
377
-
378
- describe '#should_redirect?' do
379
-
380
- it "[!dsu34] returns false when request path is '/'." do
381
- jet_router.instance_exec(self) do |_|
382
- _.ok {should_redirect?(_.new_env('GET' , '/'))} == false
383
- _.ok {should_redirect?(_.new_env('POST' , '/'))} == false
384
- _.ok {should_redirect?(_.new_env('PUT' , '/'))} == false
385
- _.ok {should_redirect?(_.new_env('DELETE', '/'))} == false
386
- _.ok {should_redirect?(_.new_env('HEAD' , '/'))} == false
387
- _.ok {should_redirect?(_.new_env('PATCH' , '/'))} == false
388
- end
389
- end
390
-
391
- it "[!ycpqj] returns true when request method is GET or HEAD." do
392
- jet_router.instance_exec(self) do |_|
393
- _.ok {should_redirect?(_.new_env('GET' , '/index'))} == true
394
- _.ok {should_redirect?(_.new_env('HEAD' , '/index'))} == true
395
- end
396
- end
397
-
398
- it "[!7q8xu] returns false when request method is POST, PUT or DELETE." do
399
- jet_router.instance_exec(self) do |_|
400
- _.ok {should_redirect?(_.new_env('POST' , '/index'))} == false
401
- _.ok {should_redirect?(_.new_env('PUT' , '/index'))} == false
402
- _.ok {should_redirect?(_.new_env('DELETE', '/index'))} == false
403
- _.ok {should_redirect?(_.new_env('PATCH' , '/index'))} == false
404
- end
405
- end
406
-
407
- end
408
-
409
-
410
- describe '#error_not_found()' do
411
-
412
- it "[!mlruv] returns 404 response." do
413
- expected = [404, {"Content-Type"=>"text/plain"}, ["404 Not Found"]]
414
- env = new_env('GET', '/xxx')
415
- jet_router.instance_exec(self) do |_|
416
- _.ok {error_not_found(env)} == expected
417
- end
418
- end
419
-
420
- end
421
-
422
-
423
- describe '#error_not_allowed()' do
424
-
425
- it "[!mjigf] returns 405 response." do
426
- expected = [405, {"Content-Type"=>"text/plain"}, ["405 Method Not Allowed"]]
427
- env = new_env('POST', '/')
428
- jet_router.instance_exec(self) do |_|
429
- _.ok {error_not_allowed(env)} == expected
430
- end
431
- end
432
-
433
- end
434
-
435
-
436
- describe '#initialize()' do
437
-
438
- it "[!u2ff4] compiles urlpath mapping." do
439
- jet_router.instance_exec(self) do |_|
440
- expected = '
441
- \A
442
- (?:
443
- /api
444
- (?:
445
- /books
446
- (?:/[^./]+(\z)|/[^./]+/edit(\z))
447
- |
448
- /books/[^./]+/comments
449
- (?:(\z)|/[^./]+(\z))
450
- )
451
- |
452
- /admin
453
- /books
454
- /[^./]+(\z)
455
- )
456
- \z
457
- '.gsub(/\s+/, '')
458
- _.ok {@urlpath_rexp} == Regexp.new(expected)
459
- _.ok {@fixed_urlpath_dict} == {
460
- '/' => welcome_app,
461
- '/index.html' => welcome_app,
462
- '/api/books' => book_list_api,
463
- '/api/books/new' => book_new_api,
464
- '/admin/books' => {
465
- 'GET'=>admin_book_list_app,
466
- 'POST'=>admin_book_create_app,
467
- },
468
- }
469
- _.ok {@variable_urlpath_list} == [
470
- [%r'\A/api/books/([^./]+)\z', ['id'], book_show_api, (11..-1)],
471
- [%r'\A/api/books/([^./]+)/edit\z', ['id'], book_edit_api, (11..-6)],
472
- [%r'\A/api/books/([^./]+)/comments\z', ['book_id'], comment_create_api, (11..-10)],
473
- [%r'\A/api/books/([^./]+)/comments/([^./]+)\z', ['book_id', 'comment_id'], comment_update_api, nil],
474
- [%r'\A/admin/books/([^./]+)\z', ['id'], {'GET' => admin_book_show_app,
475
- 'PUT' => admin_book_update_app,
476
- 'DELETE' => admin_book_delete_app}, (13..-1)],
477
- ]
478
- end
479
- end
480
-
481
- end
482
-
483
-
484
- describe '#lookup()' do
485
-
486
- it "[!ijqws] returns mapped object and urlpath parameter values when urlpath found." do
487
- ret = jet_router.lookup('/api/books/123')
488
- ok {ret} == [book_show_api, {"id"=>"123"}]
489
- end
490
-
491
- it "[!vpdzn] returns nil when urlpath not found." do
492
- ok {jet_router.lookup('/api')} == nil
493
- ok {jet_router.lookup('/api/book')} == nil
494
- ok {jet_router.lookup('/api/books/')} == nil
495
- end
496
-
497
- it "[!24khb] finds in fixed urlpaths at first." do
498
- ok {jet_router.lookup('/')} == [welcome_app, nil]
499
- ok {jet_router.lookup('/api/books')} == [book_list_api, nil]
500
- dict = {'GET'=>admin_book_list_app, 'POST'=>admin_book_create_app}
501
- ok {jet_router.lookup('/admin/books')} == [dict, nil]
502
- end
503
-
504
- it "[!iwyzd] urlpath param value is nil when found in fixed urlpaths." do
505
- obj, vars = jet_router.lookup('/')
506
- ok {vars} == nil
507
- obj, vars = jet_router.lookup('/api/books')
508
- ok {vars} == nil
509
- end
510
-
511
- it "[!upacd] finds in variable urlpath cache if it is enabled." do
512
- mapping = [
513
- ['/api/books/:id', book_show_api],
514
- ]
515
- r = Rack::JetRouter.new(mapping, urlpath_cache_size: 3)
516
- pair = r.lookup('/api/books/123')
517
- ok {pair} == [book_show_api, {"id"=>"123"}]
518
- r.instance_exec(self) do |_|
519
- _.ok {@variable_urlpath_cache} == {'/api/books/123'=>pair}
520
- #
521
- @variable_urlpath_cache['/api/books/999'] = [book_list_api, {"ID"=>"111"}]
522
- end
523
- pair = r.lookup('/api/books/999')
524
- ok {pair} == [book_list_api, {"ID"=>"111"}]
525
- end
526
-
527
- it "[!84inr] caches result when variable urlpath cache enabled." do
528
- mapping = [
529
- ['/books/:id', book_show_api],
530
- ]
531
- r = Rack::JetRouter.new(mapping, urlpath_cache_size: 3)
532
- #
533
- pair1 = r.lookup('/books/1'); ok {pair1} == [book_show_api, {"id"=>"1"}]
534
- pair2 = r.lookup('/books/2'); ok {pair2} == [book_show_api, {"id"=>"2"}]
535
- pair3 = r.lookup('/books/3'); ok {pair3} == [book_show_api, {"id"=>"3"}]
536
- r.instance_exec(self) do |_|
537
- _.ok {@variable_urlpath_cache} == {
538
- '/books/1'=>pair1,
539
- '/books/2'=>pair2,
540
- '/books/3'=>pair3,
541
- }
542
- end
543
- #
544
- pair4 = r.lookup('/books/4'); ok {pair4} == [book_show_api, {"id"=>"4"}]
545
- r.instance_exec(self) do |_|
546
- _.ok {@variable_urlpath_cache} == {
547
- '/books/2'=>pair2,
548
- '/books/3'=>pair3,
549
- '/books/4'=>pair4,
550
- }
551
- end
552
- end
553
-
554
- it "[!1zx7t] variable urlpath cache is based on LRU." do
555
- mapping = [
556
- ['/books/:id', book_show_api],
557
- ]
558
- r = Rack::JetRouter.new(mapping, urlpath_cache_size: 3)
559
- #
560
- pair1 = r.lookup('/books/1')
561
- pair2 = r.lookup('/books/2')
562
- pair3 = r.lookup('/books/3')
563
- pair4 = r.lookup('/books/4')
564
- r.instance_exec(self) do |_|
565
- _.ok {@variable_urlpath_cache} == {
566
- '/books/2'=>pair2,
567
- '/books/3'=>pair3,
568
- '/books/4'=>pair4,
569
- }
570
- end
571
- #
572
- ok {r.lookup('/books/3')} == pair3
573
- r.instance_exec(self) do |_|
574
- _.ok {@variable_urlpath_cache} == {
575
- '/books/2'=>pair2,
576
- '/books/4'=>pair4,
577
- '/books/3'=>pair3,
578
- }
579
- end
580
- #
581
- ok {r.lookup('/books/1')} == pair1
582
- r.instance_exec(self) do |_|
583
- _.ok {@variable_urlpath_cache} == {
584
- '/books/4'=>pair4,
585
- '/books/3'=>pair3,
586
- '/books/1'=>pair1,
587
- }
588
- end
589
- end
590
-
591
- end
592
-
593
-
594
- describe '#call()' do
595
-
596
- it "[!hse47] invokes app mapped to request urlpath." do
597
- ok {jet_router.call(new_env(:GET, '/api/books/123'))} == [200, {}, ["book_show_api"]]
598
- ok {jet_router.call(new_env(:PUT, '/admin/books/123'))} == [200, {}, ["admin_book_update_app"]]
599
- end
600
-
601
- it "[!fpw8x] finds mapped app according to env['PATH_INFO']." do
602
- ok {jet_router.call(new_env(:GET, '/api/books'))} == [200, {}, ["book_list_api"]]
603
- ok {jet_router.call(new_env(:GET, '/api/books/123'))} == [200, {}, ["book_show_api"]]
604
- end
605
-
606
- it "[!wxt2g] guesses correct urlpath and redirects to it automaticaly when request path not found." do
607
- headers = {"Content-Type"=>"text/plain", "Location"=>"/api/books"}
608
- content = "Redirect to /api/books"
609
- ok {jet_router.call(new_env(:GET, '/api/books/'))} == [301, headers, [content]]
610
- #
611
- headers = {"Content-Type"=>"text/plain", "Location"=>"/api/books/78"}
612
- content = "Redirect to /api/books/78"
613
- ok {jet_router.call(new_env(:GET, '/api/books/78/'))} == [301, headers, [content]]
614
- end
615
-
616
- it "[!3vsua] doesn't redict automatically when request path is '/'." do
617
- r = Rack::JetRouter.new([['/api/books', book_list_api]])
618
- ok {r.call(new_env(:GET, '/'))} == [404, {"Content-Type"=>"text/plain"}, ["404 Not Found"]]
619
- end
620
-
621
- it "[!hyk62] adds QUERY_STRING to redirect location." do
622
- headers = {"Content-Type"=>"text/plain", "Location"=>"/api/books?x=1&y=2"}
623
- content = "Redirect to /api/books?x=1&y=2"
624
- env = new_env(:GET, '/api/books/', {"QUERY_STRING"=>"x=1&y=2"})
625
- ok {jet_router.call(env)} == [301, headers, [content]]
626
- end
627
-
628
- it "[!30x0k] returns 404 when request urlpath not found." do
629
- expected = [404, {"Content-Type"=>"text/plain"}, ["404 Not Found"]]
630
- ok {jet_router.call(new_env(:GET, '/xxx'))} == expected
631
- ok {jet_router.call(new_env(:GET, '/api/book'))} == expected
632
- end
633
-
634
- describe "[!gclbs] if mapped object is a Hash..." do
635
-
636
- it "[!p1fzn] invokes app mapped to request method." do
637
- ok {jet_router.call(new_env(:GET, '/admin/books'))} == [200, {}, ["admin_book_list_app"]]
638
- ok {jet_router.call(new_env(:POST, '/admin/books'))} == [200, {}, ["admin_book_create_app"]]
639
- ok {jet_router.call(new_env(:GET, '/admin/books/123'))} == [200, {}, ["admin_book_show_app"]]
640
- ok {jet_router.call(new_env(:PUT, '/admin/books/123'))} == [200, {}, ["admin_book_update_app"]]
641
- ok {jet_router.call(new_env(:DELETE, '/admin/books/123'))} == [200, {}, ["admin_book_delete_app"]]
642
- end
643
-
644
- it "[!5m64a] returns 405 when request method is not allowed." do
645
- expected = [405, {"Content-Type"=>"text/plain"}, ["405 Method Not Allowed"]]
646
- ok {jet_router.call(new_env(:PUT, '/admin/books'))} == expected
647
- ok {jet_router.call(new_env(:FOOBAR, '/admin/books'))} == expected
648
- end
649
-
650
- it "[!ys1e2] uses GET method when HEAD is not mapped." do
651
- ok {jet_router.call(new_env(:HEAD, '/admin/books'))} == [200, {}, ["admin_book_list_app"]]
652
- ok {jet_router.call(new_env(:HEAD, '/admin/books/123'))} == [200, {}, ["admin_book_show_app"]]
653
- end
654
-
655
- it "[!2hx6j] try ANY method when request method is not mapped." do
656
- mapping = [
657
- ['/admin/books', {:ANY=>admin_book_list_app}]
658
- ]
659
- r = Rack::JetRouter.new(mapping)
660
- expected = [200, {}, ["admin_book_list_app"]]
661
- ok {r.call(new_env(:GET, '/admin/books'))} == expected
662
- ok {r.call(new_env(:POST, '/admin/books'))} == expected
663
- ok {r.call(new_env(:PUT, '/admin/books'))} == expected
664
- ok {r.call(new_env(:DELETE, '/admin/books'))} == expected
665
- end
666
-
667
- end
668
-
669
- it "[!2c32f] stores urlpath parameters as env['rack.urlpath_params']." do
670
- env = new_env(:GET, '/api/books')
671
- jet_router.call(env)
672
- ok {env['rack.urlpath_params']} == nil
673
- env = new_env(:GET, '/api/books/123')
674
- jet_router.call(env)
675
- ok {env['rack.urlpath_params']} == {"id"=>"123"}
676
- env = new_env(:GET, '/api/books/123/comments/999')
677
- jet_router.call(env)
678
- ok {env['rack.urlpath_params']} == {"book_id"=>"123", "comment_id"=>"999"}
679
- #
680
- env = new_env(:GET, '/admin/books')
681
- jet_router.call(env)
682
- ok {env['rack.urlpath_params']} == nil
683
- env = new_env(:GET, '/admin/books/123')
684
- jet_router.call(env)
685
- ok {env['rack.urlpath_params']} == {"id"=>"123"}
686
- end
687
-
688
- end
689
-
690
-
691
- describe '#each()' do
692
-
693
- it "[!ep0pw] yields pair of urlpath pattern and app." do
694
- arr = []
695
- jet_router.each do |upath, app|
696
- arr << [upath, app]
697
- end
698
- ok {arr[0]} == ["/", welcome_app]
699
- ok {arr[1]} == ["/index.html", welcome_app]
700
- ok {arr[2]} == ["/api/books", book_list_api]
701
- ok {arr[3]} == ["/api/books/new", book_new_api]
702
- ok {arr[4]} == ["/api/books/:id", book_show_api]
703
- ok {arr[5]} == ["/api/books/:id/edit", book_edit_api]
704
- ok {arr[6]} == ["/api/books/:book_id/comments", comment_create_api]
705
- ok {arr[7]} == ["/api/books/:book_id/comments/:comment_id", comment_update_api]
706
- ok {arr[8]} == ["/admin/books", {"GET"=>admin_book_list_app, "POST"=>admin_book_create_app}]
707
- ok {arr[9]} == ["/admin/books/:id", {"GET"=>admin_book_show_app, "PUT"=>admin_book_update_app, "DELETE"=>admin_book_delete_app}]
708
- end
709
-
710
- end
711
-
712
-
713
- describe 'REQUEST_METHODS' do
714
-
715
- it "[!haggu] contains available request methods." do
716
- Rack::JetRouter::REQUEST_METHODS.each do |k, v|
717
- ok {k}.is_a?(String)
718
- ok {v}.is_a?(Symbol)
719
- ok {v.to_s} == k
720
- end
721
- end
722
-
723
- end
724
-
725
-
726
- end