rack-jet_router 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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