http_router 0.4.1 → 0.5.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.
Files changed (42) hide show
  1. data/Rakefile +6 -5
  2. data/benchmarks/rack_mount.rb +16 -45
  3. data/benchmarks/rec2.rb +8 -8
  4. data/http_router.gemspec +5 -4
  5. data/lib/http_router/interface/sinatra.rb +7 -7
  6. data/lib/http_router/node.rb +106 -105
  7. data/lib/http_router/optional_compiler.rb +14 -5
  8. data/lib/http_router/path.rb +18 -28
  9. data/lib/http_router/root.rb +17 -29
  10. data/lib/http_router/route.rb +47 -16
  11. data/lib/http_router/static.rb +5 -0
  12. data/lib/http_router/variable.rb +2 -5
  13. data/lib/http_router/version.rb +1 -1
  14. data/lib/http_router.rb +38 -65
  15. data/test/helper.rb +74 -0
  16. data/test/rack/test_dispatch.rb +120 -0
  17. data/test/rack/test_route.rb +44 -0
  18. data/test/rack/test_urlmap.rb +12 -0
  19. data/{spec → test}/sinatra/recognize_spec.rb +0 -0
  20. data/test/sinatra/test_recognize.rb +150 -0
  21. data/test/test_arbitrary.rb +50 -0
  22. data/test/test_generate.rb +93 -0
  23. data/test/test_greedy.rb +24 -0
  24. data/test/test_interstitial.rb +47 -0
  25. data/test/test_misc.rb +30 -0
  26. data/test/test_mounting.rb +89 -0
  27. data/test/test_recognize.rb +56 -0
  28. data/test/test_request.rb +85 -0
  29. data/test/test_trailing_slash.rb +28 -0
  30. data/test/test_variable.rb +108 -0
  31. metadata +41 -32
  32. data/lib/http_router/response.rb +0 -46
  33. data/spec/generate_spec.rb +0 -234
  34. data/spec/misc_spec.rb +0 -65
  35. data/spec/mounting_spec.rb +0 -5
  36. data/spec/rack/dispatch_spec.rb +0 -119
  37. data/spec/rack/generate_spec.rb +0 -29
  38. data/spec/rack/middleware_spec.rb +0 -22
  39. data/spec/rack/route_spec.rb +0 -72
  40. data/spec/rack/urlmap_spec.rb +0 -13
  41. data/spec/recognize_spec.rb +0 -497
  42. data/spec/spec_helper.rb +0 -25
@@ -0,0 +1,150 @@
1
+ require "sinatra"
2
+ require "http_router/interface/sinatra"
3
+
4
+ module CallWithMockRequestMixin
5
+ def call_with_mock_request(url = "/sample", method = "GET", params = Hash.new)
6
+ params.merge!(:method => method)
7
+ request = Rack::MockRequest.new(self)
8
+ request.request(method, url, params)
9
+ end
10
+ end
11
+
12
+ class TestRecognize < MiniTest::Unit::TestCase
13
+
14
+ def setup
15
+ @app = Sinatra.new { register HttpRouter::Interface::Sinatra::Extension }
16
+ @app.extend(CallWithMockRequestMixin)
17
+ @app.reset!
18
+ end
19
+
20
+ def test_basic
21
+ response = @app.call_with_mock_request('/bar')
22
+ assert_equal 404, response.status
23
+ end
24
+
25
+ def test_map_index
26
+ @app.get("/") { "index" }
27
+ response = @app.call_with_mock_request('/')
28
+ assert_equal 200, response.status
29
+ assert_equal "index", response.body
30
+ end
31
+
32
+ def test_trailing_slash
33
+ @app.get("/foo") { "foo" }
34
+ response = @app.call_with_mock_request('/foo')
35
+ assert_equal 200, response.status
36
+ assert_equal "foo", response.body
37
+ response = @app.call_with_mock_request('/foo/')
38
+ assert_equal 200, response.status
39
+ assert_equal "foo", response.body
40
+ end
41
+
42
+ def test_trailing_slash2
43
+ @app.get("/foo") { "foo" }
44
+ @app.get("/foo/bar") { "bar" }
45
+ response = @app.call_with_mock_request('/foo')
46
+ assert_equal 200, response.status
47
+ assert_equal "foo", response.body
48
+ response = @app.call_with_mock_request('/foo/bar')
49
+ assert_equal 200, response.status
50
+ assert_equal "bar", response.body
51
+ response = @app.call_with_mock_request('/foo/')
52
+ assert_equal 200, response.status
53
+ assert_equal "foo", response.body
54
+ response = @app.call_with_mock_request('/foo/bar/')
55
+ assert_equal 200, response.status
56
+ assert_equal "bar", response.body
57
+ end
58
+
59
+ def test_trailing_slash_with_optional_param
60
+ @app.get("/foo/(:bar)") { params[:bar] }
61
+ @app.get("/bar(/:foo)") { params[:foo] }
62
+ response = @app.call_with_mock_request('/foo/bar')
63
+ assert_equal 200, response.status
64
+ assert_equal "bar", response.body
65
+ response = @app.call_with_mock_request('/bar/foo')
66
+ assert_equal 200, response.status
67
+ assert_equal "foo", response.body
68
+ response = @app.call_with_mock_request('/bar')
69
+ assert_equal 200, response.status
70
+ assert_equal "", response.body
71
+ response = @app.call_with_mock_request('/bar/')
72
+ assert_equal 200, response.status
73
+ assert_equal "", response.body
74
+ end
75
+
76
+ def test_trailing_question_mark
77
+ @app.get("/foo/?") { "foo" }
78
+ response = @app.call_with_mock_request('/foo')
79
+ assert_equal 200, response.status
80
+ assert_equal "foo", response.body
81
+ response = @app.call_with_mock_request('/foo/')
82
+ assert_equal 200, response.status
83
+ assert_equal "foo", response.body
84
+ end
85
+
86
+ def test_map_basic
87
+ @app.get('/hi', :name => :hi) { generate(:hi) }
88
+ response = @app.call_with_mock_request('/hi')
89
+ assert_equal 200, response.status
90
+ assert_equal "/hi", response.body
91
+ end
92
+
93
+ def test_map_basic2
94
+ @app.get('/hi', :name => :hi) { generate(:hi) }
95
+ response = @app.call_with_mock_request('/hi/')
96
+ assert_equal 200, response.status
97
+ assert_equal "/hi", response.body
98
+ end
99
+
100
+ def test_map_param
101
+ @app.get('/hi/:id', :name => :hi) { generate(:hi, :id => 18) }
102
+ response = @app.call_with_mock_request('/hi/1')
103
+ assert_equal 200, response.status
104
+ assert_equal "/hi/18", response.body
105
+ end
106
+
107
+ def test_map_param2
108
+ @app.get('/hi-:id', :name => :hi) { generate(:hi, :id => 18) }
109
+ response = @app.call_with_mock_request('/hi-1')
110
+ assert_equal 200, response.status
111
+ assert_equal "/hi-18", response.body
112
+ end
113
+
114
+ def test_map_complex
115
+ @app.get('/hi/:foo/:bar/:baz(.:format)') { "/#{params[:foo]}/#{params[:bar]}/#{params[:baz]}/#{params[:format]}" }
116
+ response = @app.call_with_mock_request('/hi/foo/bar/baz')
117
+ assert_equal 200, response.status
118
+ assert_equal "/foo/bar/baz/", response.body
119
+ response = @app.call_with_mock_request('/hi/foo/bar-bax/baz')
120
+ assert_equal 200, response.status
121
+ assert_equal "/foo/bar-bax/baz/", response.body
122
+ end
123
+
124
+ def test_map_regexp
125
+ @app.get('/numbers/:digits', :matching => { :digits => /\d+/ }) { params[:digits] }
126
+ response = @app.call_with_mock_request('/numbers/2010')
127
+ assert_equal 200, response.status
128
+ assert_equal "2010", response.body
129
+ end
130
+
131
+ def test_not_map_regex
132
+ @app.get('/numbers/:digits', :matching => { :digits => /\d+/ }) { params[:digits] }
133
+ response = @app.call_with_mock_request('/numbers/nan')
134
+ assert_equal 404, response.status
135
+ end
136
+
137
+ def test_404
138
+ response = @app.call_with_mock_request('/bar')
139
+ assert_equal 404, response.status
140
+ assert_match response.body, /Sinatra doesn't know this ditty/
141
+ end
142
+
143
+ def test_405
144
+ @app.post('/bar') { 'found' }
145
+ @app.put('/bar') { 'found' }
146
+ response = @app.call_with_mock_request('/bar')
147
+ assert_equal 405, response.status
148
+ assert_equal ['POST', 'PUT'], response.headers['Allow'].split(/\s*,\s*/).sort
149
+ end
150
+ end
@@ -0,0 +1,50 @@
1
+ class TestArbitrary < MiniTest::Unit::TestCase
2
+ def test_match
3
+ hello, love80, love8080 = router {
4
+ add('test').arbitrary(Proc.new{|req, params| req.host == 'hellodooly' })
5
+ add("test").arbitrary(Proc.new{|req, params| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 80}
6
+ add("test").arbitrary(Proc.new{|req, params| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 8080}
7
+ }
8
+ assert_route love8080, 'http://lovelove:8080/test'
9
+ end
10
+
11
+ def test_less_specific_node
12
+ general, hello, love80, love8080 = router {
13
+ add("/test")
14
+ add("/test").arbitrary(Proc.new{|req, params| req.host == 'hellodooly' })
15
+ add("/test").arbitrary(Proc.new{|req, params| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 80}
16
+ add("/test").arbitrary(Proc.new{|req, params| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 8080}
17
+ }
18
+ assert_route general, 'http://lovelove:8081/test'
19
+ assert_route hello, 'http://hellodooly:8081/test'
20
+ assert_route love80, 'http://lovelove:80/test'
21
+ assert_route love8080, 'http://lovelove:8080/test'
22
+ end
23
+
24
+ def test_match_request
25
+ love80, love8080 = router {
26
+ add("/test").get.arbitrary(Proc.new{|req, params| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 80}
27
+ add("/test").get.arbitrary(Proc.new{|req, params| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 8080}
28
+ }
29
+ assert_route love80, 'http://lovelove:80/test'
30
+ assert_route love8080, 'http://lovelove:8080/test'
31
+ end
32
+
33
+ def test_less_specific_with_request
34
+ love80, love8080, general = router {
35
+ add("test").post.arbitrary(Proc.new{|req, params| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 80}
36
+ add("test").post.arbitrary(Proc.new{|req, params| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 8080}
37
+ add("test").post
38
+ }
39
+ assert_route love8080, Rack::MockRequest.env_for('http://lovelove:8080/test', :method => :post)
40
+ assert_route love80, Rack::MockRequest.env_for('http://lovelove:80/test', :method => :post)
41
+ assert_route general, Rack::MockRequest.env_for('/test', :method => :post)
42
+ end
43
+
44
+ def test_pass_params
45
+ r = router {
46
+ add(":test").get.arbitrary(Proc.new{|req, params, dest| params[:test] == 'test' })
47
+ }
48
+ assert_route r, '/test', {:test => 'test'}
49
+ end
50
+ end
@@ -0,0 +1,93 @@
1
+ class TestGenerate < MiniTest::Unit::TestCase
2
+
3
+ def test_static
4
+ router {
5
+ add('/').name(:a)
6
+ add('/test').name(:b)
7
+ add('/test/time').name(:c)
8
+ add('/one/more/what').name(:d)
9
+ add('/test.html').name(:e)
10
+ }
11
+ assert_generate '/', :a
12
+ assert_generate '/test', :b
13
+ assert_generate '/test/time', :c
14
+ assert_generate '/one/more/what', :d
15
+ assert_generate '/test.html', :e
16
+ end
17
+
18
+ def test_dynamic
19
+ assert_generate '/test', '/:var', :var => 'test'
20
+ assert_generate '/test', '/:var', 'test'
21
+ end
22
+
23
+ def test_array_with_extras
24
+ assert_generate '/test?query=string', '/:var', :var => 'test', :query => 'string'
25
+ assert_generate '/test?query=string', '/:var', 'test', :query => 'string'
26
+ end
27
+
28
+ def test_multiple_dynamics
29
+ assert_generate '/one/two', "/:var/:baz", :var => 'one', :baz => 'two'
30
+ assert_generate '/one/two', "/:var/:baz", 'one', 'two'
31
+ end
32
+
33
+ def test_extension
34
+ assert_generate '/test.html', "/test.:format", :format => 'html'
35
+ assert_generate '/test.html', "/test.:format", 'html'
36
+ end
37
+
38
+ def test_optional_extension
39
+ assert_generate '/test.html', "/test(.:format)", :format => 'html'
40
+ assert_generate '/test.html', "/test(.:format)", 'html'
41
+ assert_generate '/test', "/test(.:format)"
42
+ end
43
+
44
+ def test_variable_with_extension
45
+ assert_generate '/test.html', "/:var.:format", :var => 'test', :format => 'html'
46
+ assert_generate '/test.html', "/:var.:format", 'test', 'html'
47
+ end
48
+
49
+ def test_variable_with_optional_extension
50
+ assert_generate '/test.html', "/:var(.:format)", :var => 'test', :format => 'html'
51
+ assert_generate '/test.html', "/:var(.:format)", 'test', 'html'
52
+ assert_generate '/test', "/:var(.:format)", :var => 'test'
53
+ assert_generate '/test', "/:var(.:format)", 'test'
54
+ end
55
+
56
+ def test_optionals
57
+ assert_generate '/var', "/:var1(/:var2)", 'var'
58
+ assert_generate '/var/fooz', "/:var1(/:var2)", 'var', 'fooz'
59
+ assert_generate '/var', "/:var1(/:var2)", :var1 => 'var'
60
+ assert_generate '/var/fooz', "/:var1(/:var2)", :var1 => 'var', :var2 => 'fooz'
61
+ assert_raises(HttpRouter::UngeneratableRouteException) { router.url(router.add("/:var1(/:var2)").to(:test), :var2 => 'fooz') }
62
+ end
63
+
64
+ def test_optionals_with_format
65
+ assert_generate '/var', "/:var1(/:var2.:format)", 'var'
66
+ assert_generate '/var/fooz.html', "/:var1(/:var2.:format)", 'var', 'fooz', 'html'
67
+ assert_generate '/var', "/:var1(/:var2.:format)", :var1 => 'var'
68
+ assert_generate '/var/fooz.html', "/:var1(/:var2.:format)", :var1 => 'var', :var2 => 'fooz', :format => 'html'
69
+ end
70
+
71
+ def test_nested_optionals
72
+ assert_generate '/var', "/:var1(/:var2(/:var3))", 'var'
73
+ assert_generate '/var/fooz', "/:var1(/:var2(/:var3))", 'var', 'fooz'
74
+ assert_generate '/var/fooz/baz', "/:var1(/:var2(/:var3))", 'var', 'fooz', 'baz'
75
+ assert_generate '/var', "/:var1(/:var2(/:var3))", :var1 => 'var'
76
+ assert_generate '/var/fooz', "/:var1(/:var2(/:var3))", :var1 => 'var', :var2 => 'fooz'
77
+ assert_generate '/var/fooz/baz', "/:var1(/:var2(/:var3))", :var1 => 'var', :var2 => 'fooz', :var3 => 'baz'
78
+ end
79
+
80
+ def test_default_value
81
+ assert_generate "/123?page=1", router.add("/:var").default(:page => 1), 123
82
+ assert_generate "/1/123", router.add("/:page/:entry").default(:page => 1), :entry => '123'
83
+ end
84
+
85
+ def test_nil_values
86
+ assert_generate '/url', "/url(/:var)", :var => nil
87
+ end
88
+
89
+ def test_raise
90
+ r = router { add(':var').matching(:var => /\d+/) }
91
+ assert_raises(HttpRouter::InvalidRouteException) { router.url(r, 'asd') }
92
+ end
93
+ end
@@ -0,0 +1,24 @@
1
+ class TestGreedy < MiniTest::Unit::TestCase
2
+ def test_mix_regex_with_greedy
3
+ regex, greedy = router {
4
+ add("/:test/number").matching(:test => /\d+/)
5
+ add("/:test/anything")
6
+ }
7
+ assert_route regex, '/123/number', {:test => '123'}
8
+ assert_route greedy, '/123/anything', {:test => '123'}
9
+ end
10
+
11
+ def test_trailing_slash
12
+ assert_route router.add("/:test").matching(:test => /.*/), '/test/', {:test => 'test/'}
13
+ end
14
+
15
+ def test_extension
16
+ assert_route router.add("/:test").matching(:test => /.*/), '/test.html', {:test => 'test.html'}
17
+ end
18
+
19
+ def test_match_at_beginning
20
+ r = router { add(':test', :test => /\d+/)}
21
+ assert_route r, '/123', {:test => '123'}
22
+ assert_route nil, '/a123'
23
+ end
24
+ end
@@ -0,0 +1,47 @@
1
+ class TestInterstitial < MiniTest::Unit::TestCase
2
+ def test_recognize
3
+ assert_route '/one-:variable-time', '/one-value-time', {:variable => 'value'}
4
+ end
5
+
6
+ def test_regex
7
+ r = router { add('/one-:variable-time').matching(:variable => /\d+/) }
8
+ assert_route r, '/one-123-time', {:variable => '123'}
9
+ assert_route nil, '/one-value-time'
10
+ end
11
+
12
+ def test_regex_as_options
13
+ r = router { add('/one-:variable-time', :variable => /\d+/) }
14
+ assert_route r, '/one-123-time', {:variable => '123'}
15
+ assert_route nil, '/one-value-time'
16
+ end
17
+
18
+ def test_extension
19
+ assert_route 'hey.:greed.html', '/hey.greedybody.html', {:greed => 'greedybody'}
20
+ end
21
+
22
+ def test_multi
23
+ r1, r2, r3, r4, r5, r6 = router {
24
+ add('/:var1')
25
+ add('/:var1-:var2')
26
+ add('/:var1-:var2-:var3')
27
+ add('/:var1-:var2-:var3-:var4')
28
+ add('/:var1-:var2-:var3-:var4-:var5')
29
+ add('/:var1-:var2-:var3-:var4-:var5-:var6')
30
+ }
31
+ assert_route r1, '/one', {:var1 => 'one'}
32
+ assert_route r2, '/one-value', {:var1 => 'one', :var2 => 'value'}
33
+ assert_route r3, '/one-value-time', {:var1 => 'one', :var2 => 'value', :var3 => 'time'}
34
+ assert_route r4, '/one-value-time-one', {:var1 => 'one', :var2 => 'value', :var3 => 'time', :var4 => 'one'}
35
+ assert_route r5, '/one-value-time-one-variable', {:var1 => 'one', :var2 => 'value', :var3 => 'time', :var4 => 'one', :var5 => 'variable'}
36
+ assert_route r6, '/one-value-time-one-value-time', {:var1 => 'one', :var2 => 'value', :var3 => 'time', :var4 => 'one', :var5 => 'value', :var6 => 'time'}
37
+ end
38
+
39
+ def test_regex_with_mutliple_variables
40
+ with_regex, without_regex = router {
41
+ add("/:common_variable.:matched").matching(:matched => /\d+/)
42
+ add("/:common_variable.:unmatched")
43
+ }
44
+ assert_route with_regex, '/common.123', {:common_variable => 'common', :matched => '123'}
45
+ assert_route without_regex, '/common.other', {:common_variable => 'common', :unmatched => 'other'}
46
+ end
47
+ end
data/test/test_misc.rb ADDED
@@ -0,0 +1,30 @@
1
+ class TestMisc < MiniTest::Unit::TestCase
2
+ def test_exceptions
3
+ assert_raises(HttpRouter::AmbiguousRouteException) {HttpRouter.new.add("/:var1(/:var2)(/:var3)").compile}
4
+ assert_raises(HttpRouter::AmbiguousVariableException) {HttpRouter.new.add("/:var1(/:var1)(/:var1)").compile}
5
+ assert_raises(HttpRouter::UnsupportedRequestConditionError) {HttpRouter.new.add("/").condition(:flibberty => 'gibet').compile}
6
+ end
7
+
8
+ def test_cloning
9
+ r1 = HttpRouter.new {
10
+ add('/test').name(:test_route).to :test
11
+ }
12
+ r2 = r1.clone
13
+
14
+ r2.add('/test2').name(:test).to(:test2)
15
+ assert_equal 2, r2.routes.size
16
+
17
+ assert r1.recognize(Rack::MockRequest.env_for('/test2')).nil?
18
+ assert !r2.recognize(Rack::MockRequest.env_for('/test2')).nil?
19
+ assert_equal r1.routes.first, r1.named_routes[:test_route]
20
+ assert_equal r2.routes.first, r2.named_routes[:test_route]
21
+
22
+ r1.add('/another').name(:test).to(:test2)
23
+
24
+ assert_equal r1.routes.size, r2.routes.size
25
+ assert_equal '/another', r1.url(:test)
26
+ assert_equal '/test2', r2.url(:test)
27
+ assert_equal :test, r1.routes.first.dest
28
+ assert_equal :test, r2.routes.first.dest
29
+ end
30
+ end
@@ -0,0 +1,89 @@
1
+ class TestMounting < MiniTest::Unit::TestCase
2
+ def setup
3
+ @r1 = HttpRouter.new
4
+ @r2 = HttpRouter.new
5
+ @r2.add("/bar").name(:test).compile
6
+ end
7
+
8
+ def test_url_mount_for_child_route
9
+ route = @r1.add("/foo").to(@r2)
10
+ assert_equal "/foo", @r2.url_mount.url
11
+ assert_equal "/foo/bar", @r2.url(:test)
12
+ end
13
+
14
+ def test_default_values
15
+ route = @r1.add("/foo/:bar").default(:bar => "baz").to(@r2)
16
+ assert_equal "/foo/baz/bar", @r2.url(:test)
17
+ assert_equal "/foo/haha/bar", @r2.url(:test, :bar => "haha")
18
+ end
19
+
20
+ def test_multiple_values
21
+ @r1.add("/foo/:bar/:baz").default(:bar => "bar").to(@r2)
22
+ assert_equal "/foo/bar/baz/bar", @r2.url(:test, :baz => "baz")
23
+ end
24
+
25
+ def test_bubble_params
26
+ route = @r1.add("/foo/:bar").default(:bar => "baz").to(@r2)
27
+ assert_equal "/foo/baz/bar?bang=ers", @r2.url(:test, :bang => "ers")
28
+ assert_equal "/foo/haha/bar?bang=ers", @r2.url(:test, :bar => "haha", :bang => "ers")
29
+ end
30
+
31
+ def test_path_with_optional
32
+ @r1.add("/foo(/:bar)").to(@r2)
33
+ @r2.add("/hey(/:there)").name(:test).compile
34
+ assert_equal "/foo/hey", @r2.url(:test)
35
+ assert_equal "/foo/bar/hey", @r2.url(:test, :bar => "bar")
36
+ assert_equal "/foo/bar/hey/there", @r2.url(:test, :bar => "bar", :there => "there")
37
+ end
38
+
39
+ def test_nest3
40
+ @r3 = HttpRouter.new
41
+ @r1.add("/foo(/:bar)").default(:bar => "barry").to(@r2)
42
+ @r2.add("/hi").name(:hi).compile
43
+ @r2.add("/mounted").to(@r3)
44
+ @r3.add("/endpoint").name(:endpoint).compile
45
+
46
+ assert_equal "/foo/barry/hi", @r2.url(:hi)
47
+ assert_equal "/foo/barry/mounted/endpoint", @r3.url(:endpoint)
48
+ assert_equal "/foo/flower/mounted/endpoint", @r3.url(:endpoint, :bar => "flower")
49
+ end
50
+
51
+ def test_with_default_host
52
+ @r1.add("/mounted").default(:host => "example.com").to(@r2)
53
+ assert_equal "http://example.com/mounted/bar", @r2.url(:test)
54
+ end
55
+
56
+ def test_with_host
57
+ @r1.add("/mounted").to(@r2)
58
+ assert_equal "/mounted/bar", @r2.url(:test)
59
+ assert_equal "http://example.com/mounted/bar", @r2.url(:test, :host => "example.com")
60
+ end
61
+
62
+ def test_with_scheme
63
+ @r1.add("/mounted").to(@r2)
64
+ assert_equal "/mounted/bar", @r2.url(:test)
65
+ assert_equal "https://example.com/mounted/bar", @r2.url(:test, :scheme => "https", :host => "example.com")
66
+ end
67
+
68
+ def test_clone
69
+ @r3 = HttpRouter.new
70
+ @r1.add("/first").to(@r2)
71
+ @r2.add("/second").to(@r3)
72
+ r1 = @r1.clone
73
+ assert @r1.routes.first
74
+ r2 = r1.routes.first.dest
75
+ assert r2
76
+ assert_equal @r1.routes.first.dest.object_id, @r2.object_id
77
+ assert r2.object_id != @r2.object_id
78
+ assert_equal 2, r2.routes.size
79
+ r3 = r2.routes.last.dest
80
+ assert_instance_of HttpRouter, r3
81
+ assert r3.object_id != @r3.object_id
82
+ end
83
+ end
84
+
85
+ # it "should clone my nested structure" do
86
+ # end
87
+ # end
88
+ # end
89
+ #end
@@ -0,0 +1,56 @@
1
+ class TestRecognition < MiniTest::Unit::TestCase
2
+ def test_simple
3
+ assert_route router.add(''), '/'
4
+ assert_route router.add('/'), '/'
5
+ assert_route router.add('/test'), '/test'
6
+ assert_route router.add('/test/one'), '/test/one'
7
+ assert_route router.add('/test/one/two'), '/test/one/two'
8
+ assert_route router.add('/test.html'), '/test.html'
9
+ assert_route router.add('/.html'), '/.html'
10
+ end
11
+
12
+ def test_optional
13
+ route = router {
14
+ add 'one(/two(/three(/four)(/five)))'
15
+ }
16
+ assert_route route, '/one'
17
+ assert_route route, '/one/two'
18
+ assert_route route, '/one/two/three'
19
+ assert_route route, '/one/two/three/four'
20
+ assert_route route, '/one/two/three/five'
21
+ end
22
+
23
+ def test_escape_paren
24
+ assert_route router.add('/test\(:variable\)'), '/test(hello)', {:variable => 'hello'}
25
+ end
26
+
27
+ def test_escape_colon
28
+ assert_route router.add('/test\:variable'), '/test:variable'
29
+ end
30
+
31
+ def test_escape_star
32
+ assert_route router.add('/test\*variable'), '/test*variable'
33
+ end
34
+
35
+ def test_partial
36
+ router.add("/test*").to { |env| Rack::Response.new(env['PATH_INFO']).finish }
37
+ assert_body '/optional', router.call(Rack::MockRequest.env_for('/test/optional'))
38
+ assert_body '/', router.call(Rack::MockRequest.env_for('/test'))
39
+ end
40
+
41
+ def test_partial_root
42
+ router.add("/*").to { |env| Rack::Response.new(env['PATH_INFO']).finish }
43
+ assert_body '/optional', router.call(Rack::MockRequest.env_for('/optional'))
44
+ assert_body '/', router.call(Rack::MockRequest.env_for('/'))
45
+ end
46
+
47
+ def test_multiple_partial
48
+ test, root = router {
49
+ add("/test").partial.to{|env| [200, {}, ['/test',env['PATH_INFO']]]}
50
+ add("/").partial.to{|env| [200, {}, ['/',env['PATH_INFO']]]}
51
+ }
52
+ assert_body ['/test', '/optional'], router.call(Rack::MockRequest.env_for('/test/optional'))
53
+ assert_body ['/test', '/optional/'], router.call(Rack::MockRequest.env_for('/test/optional/'))
54
+ assert_body ['/', '/testing/optional'], router.call(Rack::MockRequest.env_for('/testing/optional'))
55
+ end
56
+ end
@@ -0,0 +1,85 @@
1
+ class TestRequest < MiniTest::Unit::TestCase
2
+ def test_simple_case
3
+ r = router { add('test').post }
4
+ assert_route r, Rack::MockRequest.env_for('/test', :method => 'POST')
5
+ assert_header({'Allow' => 'POST'}, Rack::MockRequest.env_for('/test', :method => 'GET'))
6
+ assert_status(405, Rack::MockRequest.env_for('/test', :method => 'GET'))
7
+ end
8
+
9
+ def test_with_optional_parts_and_405
10
+ get, post, delete = router {
11
+ get('test(.:format)')
12
+ post('test(.:format)')
13
+ delete('test(.:format)')
14
+ }
15
+ assert_route get, Rack::MockRequest.env_for('/test', :method => 'GET')
16
+ assert_route post, Rack::MockRequest.env_for('/test', :method => 'POST')
17
+ assert_route delete, Rack::MockRequest.env_for('/test', :method => 'DELETE')
18
+ assert_route get, Rack::MockRequest.env_for('/test.html', :method => 'GET'), {:format => 'html'}
19
+ assert_route post, Rack::MockRequest.env_for('/test.html', :method => 'POST'), {:format => 'html'}
20
+ assert_route delete, Rack::MockRequest.env_for('/test.html', :method => 'DELETE'), {:format => 'html'}
21
+ put = router.call(Rack::MockRequest.env_for('/test', :method => 'PUT'))
22
+ assert_status 405, put
23
+ assert_equal %w{DELETE GET POST}, put[1]['Allow'].split(/\s*,\s*/).sort
24
+ end
25
+
26
+ def test_deeply
27
+ test_post, test_post_post, test_get, test_post_get, test_post_catchall, test_catchall = router {
28
+ post("/test")
29
+ post("/test/post")
30
+ get("/test")
31
+ get("/test/post")
32
+ add("/test/post")
33
+ add("/test")
34
+ }
35
+ assert_route test_post, Rack::MockRequest.env_for('/test', :method => 'POST')
36
+ assert_route test_get, Rack::MockRequest.env_for('/test', :method => 'GET')
37
+ assert_route test_catchall, Rack::MockRequest.env_for('/test', :method => 'PUT')
38
+ assert_route test_post_post, Rack::MockRequest.env_for('/test/post', :method => 'POST')
39
+ assert_route test_post_get, Rack::MockRequest.env_for('/test/post', :method => 'GET')
40
+ assert_route test_post_catchall, Rack::MockRequest.env_for('/test/post', :method => 'PUT')
41
+ end
42
+
43
+ def test_move_node
44
+ general, post = router {
45
+ add("/test").default_destination
46
+ post("/test").default_destination
47
+ }
48
+ assert_route post, Rack::MockRequest.env_for('/test', :method => 'POST')
49
+ assert_route general, Rack::MockRequest.env_for('/test', :method => 'PUT')
50
+ end
51
+
52
+ def test_complex_routing
53
+ host2, post, host2_get, host2_post = router {
54
+ add("/test").host('host2')
55
+ add("/test").post
56
+ add("/test").host('host2').get
57
+ add("/test").post.host('host2')
58
+ }
59
+ assert_route host2, Rack::MockRequest.env_for('http://host2/test', :method => 'PUT')
60
+ assert_route post, Rack::MockRequest.env_for('http://host1/test', :method => 'POST')
61
+ assert_route host2_get, Rack::MockRequest.env_for('http://host2/test', :method => 'GET')
62
+ assert_route host2_post, Rack::MockRequest.env_for('http://host2/test', :method => 'POST')
63
+ end
64
+
65
+ def test_regexp
66
+ with, without = router {
67
+ get("/test").host(/host1/)
68
+ get("/test")
69
+ }
70
+ assert_route without, 'http://host2/test'
71
+ assert_route with, 'http://host2.host1.com/test'
72
+ end
73
+
74
+ def test_all_routes
75
+ router {
76
+ post("/test").host('host1')
77
+ }
78
+ assert_route router.add("/test").host('host2'), Rack::MockRequest.env_for('http://host2/test', :method => 'POST')
79
+ end
80
+
81
+ def test_match_on_scheme
82
+ http, https = router { get("/test").scheme('http'); get("/test").scheme('https') }
83
+ assert_status 405, Rack::MockRequest.env_for('https://example.org/test', :method => 'POST')
84
+ end
85
+ end
@@ -0,0 +1,28 @@
1
+ class TestVariable < MiniTest::Unit::TestCase
2
+ def test_ignore_trailing_slash
3
+ assert_route router.add('/test'), '/test/'
4
+ end
5
+
6
+ def test_ignore_trailing_slash_disabled
7
+ assert_route router(:ignore_trailing_slash => false).add('/test/?'), '/test/'
8
+ end
9
+
10
+ def test_ignore_trailing_slash_enabled
11
+ router(:ignore_trailing_slash => false).add('/test/?')
12
+ assert_route nil, '/test/'
13
+ end
14
+
15
+ def test_capture_with_trailing_slash
16
+ assert_route router.add('/:test'), '/test/', {:test => 'test'}
17
+ end
18
+
19
+ def test_trailing_slash_confusion
20
+ more_general, more_specific = router {
21
+ add('foo')
22
+ add('foo/:bar/:id')
23
+ }
24
+ assert_route more_general, '/foo'
25
+ assert_route more_general, '/foo/'
26
+ assert_route more_specific, '/foo/5/10', {:bar => '5', :id => '10'}
27
+ end
28
+ end