doze 0.0.11

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 (50) hide show
  1. data/README +6 -0
  2. data/lib/doze/application.rb +92 -0
  3. data/lib/doze/collection/object.rb +14 -0
  4. data/lib/doze/entity.rb +62 -0
  5. data/lib/doze/error.rb +75 -0
  6. data/lib/doze/media_type.rb +135 -0
  7. data/lib/doze/negotiator.rb +107 -0
  8. data/lib/doze/request.rb +119 -0
  9. data/lib/doze/resource/error.rb +21 -0
  10. data/lib/doze/resource/proxy.rb +81 -0
  11. data/lib/doze/resource.rb +193 -0
  12. data/lib/doze/responder/error.rb +34 -0
  13. data/lib/doze/responder/main.rb +41 -0
  14. data/lib/doze/responder/resource.rb +262 -0
  15. data/lib/doze/responder.rb +58 -0
  16. data/lib/doze/response.rb +78 -0
  17. data/lib/doze/router/anchored_route_set.rb +68 -0
  18. data/lib/doze/router/route.rb +88 -0
  19. data/lib/doze/router/route_set.rb +34 -0
  20. data/lib/doze/router.rb +100 -0
  21. data/lib/doze/serialization/entity.rb +34 -0
  22. data/lib/doze/serialization/form_data_helpers.rb +40 -0
  23. data/lib/doze/serialization/html.rb +116 -0
  24. data/lib/doze/serialization/json.rb +29 -0
  25. data/lib/doze/serialization/multipart_form_data.rb +162 -0
  26. data/lib/doze/serialization/resource.rb +30 -0
  27. data/lib/doze/serialization/resource_proxy.rb +14 -0
  28. data/lib/doze/serialization/www_form_encoded.rb +42 -0
  29. data/lib/doze/serialization/yaml.rb +25 -0
  30. data/lib/doze/uri_template.rb +220 -0
  31. data/lib/doze/utils.rb +53 -0
  32. data/lib/doze/version.rb +3 -0
  33. data/lib/doze.rb +5 -0
  34. data/test/functional/auth_test.rb +69 -0
  35. data/test/functional/base.rb +159 -0
  36. data/test/functional/cache_header_test.rb +76 -0
  37. data/test/functional/direct_response_test.rb +16 -0
  38. data/test/functional/error_handling_test.rb +131 -0
  39. data/test/functional/get_and_conneg_test.rb +182 -0
  40. data/test/functional/media_type_extensions_test.rb +102 -0
  41. data/test/functional/media_type_test.rb +40 -0
  42. data/test/functional/method_support_test.rb +49 -0
  43. data/test/functional/non_get_method_test.rb +173 -0
  44. data/test/functional/precondition_test.rb +84 -0
  45. data/test/functional/raw_path_info_test.rb +69 -0
  46. data/test/functional/resource_representation_test.rb +14 -0
  47. data/test/functional/router_test.rb +196 -0
  48. data/test/functional/serialization_test.rb +142 -0
  49. data/test/functional/uri_template_test.rb +51 -0
  50. metadata +221 -0
@@ -0,0 +1,40 @@
1
+ require 'functional/base'
2
+
3
+ require 'doze/media_type'
4
+
5
+ class MediaTypeTest < Test::Unit::TestCase
6
+ include Doze::Utils
7
+ include Doze::TestCase
8
+ include Doze::MediaTypeTestCase
9
+
10
+ def test_put_registered_media_type_same_instance
11
+ foobar = Doze::MediaType.register('application/x-foo-bar')
12
+ root.expects(:supports_put?).returns(true)
13
+ root.expects(:accepts_put_with_media_type?).returns(true)
14
+ root.expects(:put).with {|entity| entity.media_type.equal?(foobar)}.returns(nil).once
15
+ put('CONTENT_TYPE' => 'application/x-foo-bar', :input => 'foo')
16
+ assert_equal STATUS_NO_CONTENT, last_response.status
17
+ end
18
+
19
+ def test_put_unregistered_media_type_equal
20
+ boo = Doze::MediaType.new('application/x-boo')
21
+ root.expects(:supports_put?).returns(true)
22
+ root.expects(:accepts_put_with_media_type?).returns(true)
23
+ root.expects(:put).with {|entity| entity && entity.media_type == boo}.returns(nil).once
24
+ put('CONTENT_TYPE' => 'application/x-boo', :input => 'foo')
25
+ assert_equal STATUS_NO_CONTENT, last_response.status
26
+ end
27
+
28
+
29
+
30
+ def test_lookup_name
31
+ mt = Doze::MediaType.register("application/foo")
32
+ assert Doze::MediaType["application/foo"].equal?(mt)
33
+ end
34
+
35
+ def test_lookup_alias
36
+ mt = Doze::MediaType.register("application/foo", :aliases => ['bar/foo'])
37
+ assert_equal Doze::MediaType["bar/foo"], mt
38
+ assert_equal ['application/foo', 'bar/foo'], mt.names
39
+ end
40
+ end
@@ -0,0 +1,49 @@
1
+ require 'functional/base'
2
+
3
+ class MethodSupportTest < Test::Unit::TestCase
4
+ include Doze::Utils
5
+ include Doze::TestCase
6
+
7
+ def test_unrecognized_method
8
+ app(:recognized_methods => [:get,:put,:post,:delete])
9
+ root.expects(:supports_method?).never
10
+ assert_equal STATUS_NOT_IMPLEMENTED, other_request_method('FOO').status
11
+ end
12
+
13
+ def test_recognized_but_not_supported_method
14
+ app(:recognized_methods => [:foo,:bar])
15
+
16
+ seq = sequence('support_calls')
17
+ root.expects(:supports_method?).with(:foo).returns(false).at_least_once.in_sequence(seq)
18
+ root.expects(:supports_method?).with(:bar).returns(true).at_least_once.in_sequence(seq)
19
+
20
+ assert_equal STATUS_METHOD_NOT_ALLOWED, other_request_method('FOO').status
21
+ allow = last_response.headers['Allow'] and allow = allow.split(', ')
22
+ assert_equal ['BAR','OPTIONS'], allow.sort
23
+ end
24
+
25
+ def test_recognized_and_supported_method_via_supports_foo
26
+ app(:recognized_methods => [:foo,:bar])
27
+
28
+ root.expects(:supports_foo?).returns(true).at_least_once
29
+ root.expects(:accepts_method_with_media_type?).with(:foo, anything).returns(true).at_least_once
30
+ root.expects(:supports_bar?).never
31
+ root.expects(:other_method).with(:foo, anything).returns(nil).once
32
+ assert_equal STATUS_NO_CONTENT, other_request_method('FOO').status
33
+ end
34
+
35
+ def test_options_with_get_supported_with_head_and_options_handled_automatically
36
+ root.expects(:supports_get?).returns(true).once
37
+ assert_equal STATUS_NO_CONTENT, other_request_method('OPTIONS').status
38
+
39
+ allow = last_response.headers['Allow'] and allow = allow.split(', ')
40
+ assert_not_nil allow
41
+ assert_equal ['GET','HEAD','OPTIONS'], allow.sort
42
+ end
43
+
44
+ def test_options_on_missing_resource
45
+ assert_equal STATUS_NO_CONTENT, other_request_method('OPTIONS', '/blah').status
46
+ allow = last_response.headers['Allow'] and allow = allow.split(', ')
47
+ assert_equal ['OPTIONS'], allow
48
+ end
49
+ end
@@ -0,0 +1,173 @@
1
+ require 'functional/base'
2
+
3
+ class NonGetMethodTest < Test::Unit::TestCase
4
+ include Doze::Utils
5
+ include Doze::TestCase
6
+ include Doze::MediaTypeTestCase
7
+
8
+ def setup
9
+ super
10
+ @foo = Doze::MediaType.new('text/foo')
11
+ @bar = Doze::MediaType.new('text/bar')
12
+ end
13
+
14
+ def test_put_with_unacceptable_media_type
15
+ root.expects(:supports_put?).returns(true)
16
+ root.expects(:accepts_put_with_media_type?).with do |a|
17
+ a.is_a?(Doze::Entity) && a.media_type == @foo &&
18
+ a.binary_data_stream.respond_to?(:read) && a.binary_data_stream.read == 'foo' &&
19
+ a.binary_data == 'foo'
20
+ end.returns(false)
21
+ root.expects(:put).never
22
+ put('CONTENT_TYPE' => 'text/foo', :input => 'foo')
23
+ assert_equal STATUS_UNSUPPORTED_MEDIA_TYPE, last_response.status
24
+ end
25
+
26
+ def test_put
27
+ root.expects(:supports_put?).returns(true)
28
+ root.expects(:accepts_put_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
29
+ root.expects(:put).with do |value|
30
+ value.is_a?(Doze::Entity) and
31
+ value.binary_data == 'foo' and value.media_type == @foo and value.encoding == 'foobar'
32
+ end.returns(nil).once
33
+
34
+ put('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foo')
35
+ assert_equal STATUS_NO_CONTENT, last_response.status
36
+ end
37
+
38
+ def test_put_where_not_exists
39
+ root.expects(:exists?).returns(false)
40
+ root.expects(:supports_put?).returns(true)
41
+ root.expects(:accepts_put_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
42
+ root.expects(:put).returns(nil).once
43
+
44
+ put('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foo')
45
+ assert_equal STATUS_CREATED, last_response.status
46
+ end
47
+
48
+ def test_post_with_unacceptable_media_type
49
+ root.expects(:supports_post?).returns(true)
50
+ root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(false)
51
+ root.expects(:post).never
52
+ post('CONTENT_TYPE' => 'text/foo', :input => 'foo')
53
+ assert_equal STATUS_UNSUPPORTED_MEDIA_TYPE, last_response.status
54
+ end
55
+
56
+ def test_post_returning_created_resource
57
+ root.expects(:supports_post?).returns(true)
58
+ root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
59
+ created = mock_resource('/uri', 'foo')
60
+ root.expects(:post).with do |value|
61
+ value.is_a?(Doze::Entity) and
62
+ value.binary_data == 'foob' and value.media_type == @foo and value.encoding == 'foobar'
63
+ end.returns(created).once
64
+
65
+ post('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
66
+ assert_equal STATUS_CREATED, last_response.status
67
+ assert_response_header 'Location', 'http://example.org/uri'
68
+ assert_equal 'foo', last_response.body
69
+ end
70
+
71
+ def test_post_returning_nothing
72
+ root.expects(:supports_post?).returns(true)
73
+ root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
74
+ root.expects(:post).returns(nil).once
75
+
76
+ post('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
77
+ assert_equal STATUS_NO_CONTENT, last_response.status
78
+ end
79
+
80
+ def test_post_with_extra_arity_gets_session
81
+ root.expects(:supports_post?).returns(true)
82
+ root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
83
+
84
+ # Because mocha doesn't set the arity right
85
+ def root.post(a, b)
86
+ post_actually_called(a, b)
87
+ end
88
+ root.expects(:post_actually_called).with(instance_of(Doze::Entity), "user").once
89
+
90
+ post('REMOTE_USER' => 'user', 'CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
91
+ assert_equal STATUS_NO_CONTENT, last_response.status
92
+ end
93
+
94
+ def test_post_returning_entity
95
+ root.expects(:supports_post?).returns(true)
96
+ root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
97
+ root.expects(:post).returns(mock_entity('bar', @bar)).once
98
+
99
+ post('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
100
+ assert_equal STATUS_OK, last_response.status
101
+ assert_equal 'bar', last_response.body
102
+ assert_equal 'text/bar', last_response.media_type
103
+ end
104
+
105
+ def test_post_returning_anonymous_resource
106
+ root.expects(:supports_post?).returns(true)
107
+ root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
108
+ resource = mock_resource(nil)
109
+ resource.expects(:get).returns(mock_entity('bar', @bar))
110
+ root.expects(:post).returns(resource).once
111
+
112
+ post('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
113
+ assert_equal STATUS_OK, last_response.status
114
+ assert_equal 'bar', last_response.body
115
+ assert_equal 'text/bar', last_response.media_type
116
+ end
117
+
118
+ def test_delete
119
+ root.expects(:supports_delete?).returns(true)
120
+ root.expects(:accepts_delete_with_media_type?).never
121
+ root.expects(:delete_resource).returns(nil).once
122
+
123
+ delete
124
+ assert_equal STATUS_NO_CONTENT, last_response.status
125
+ assert last_response.body.empty?
126
+ end
127
+
128
+ def test_other_method_with_no_response
129
+ # PATCH used as an example here
130
+ app(:recognized_methods => [:get,:post,:put,:delete,:patch])
131
+
132
+ root.expects(:supports_patch?).returns(true)
133
+ root.expects(:accepts_method_with_media_type?).with {|m,a| m == :patch && a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
134
+ root.expects(:patch).with do |value|
135
+ value.is_a?(Doze::Entity) and
136
+ value.binary_data == 'foob' and value.media_type == @foo and value.encoding == 'foobar'
137
+ end.returns(nil).once
138
+
139
+ other_request_method('PATCH', {'CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob'})
140
+ assert_equal STATUS_NO_CONTENT, last_response.status
141
+ end
142
+
143
+ def test_other_method_with_anonymous_resource_response
144
+ # PATCH used as an example here
145
+ app(:recognized_methods => [:get,:post,:put,:delete,:patch])
146
+
147
+ root.expects(:supports_patch?).returns(true)
148
+ root.expects(:accepts_method_with_media_type?).with {|m,a| m == :patch && a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
149
+ resource = mock_resource(nil)
150
+ resource.expects(:get).returns(mock_entity('bar', @bar))
151
+ root.expects(:patch).returns(resource).once
152
+
153
+ other_request_method('PATCH', {'CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob'})
154
+ assert_equal STATUS_OK, last_response.status
155
+ assert_equal 'bar', last_response.body
156
+ assert_equal 'text/bar', last_response.media_type
157
+ end
158
+
159
+ def test_other_method_with_resource_response
160
+ # PATCH used as an example here
161
+ app(:recognized_methods => [:get,:post,:put,:delete,:patch])
162
+
163
+ root.expects(:supports_patch?).returns(true)
164
+ root.expects(:accepts_method_with_media_type?).with {|m,a| m == :patch && a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
165
+ resource = mock_resource('/foo', 'bar')
166
+ root.expects(:patch).returns(resource).once
167
+
168
+ other_request_method('PATCH', {'CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob'})
169
+ assert_equal STATUS_CREATED, last_response.status
170
+ assert_response_header 'Location', 'http://example.org/foo'
171
+ assert_equal 'bar', last_response.body
172
+ end
173
+ end
@@ -0,0 +1,84 @@
1
+ require 'functional/base'
2
+
3
+ class PreconditionTest < Test::Unit::TestCase
4
+ include Doze::Utils
5
+ include Doze::TestCase
6
+
7
+ def setup
8
+ @last_modified = Time.now - 30
9
+ root.expects(:last_modified).returns(@last_modified).at_least_once
10
+ end
11
+
12
+ def test_if_modified_since
13
+ get('HTTP_IF_MODIFIED_SINCE' => (@last_modified-10).httpdate)
14
+ assert_equal STATUS_OK, last_response.status
15
+ get('HTTP_IF_MODIFIED_SINCE' => (@last_modified+10).httpdate)
16
+ assert_equal STATUS_NOT_MODIFIED, last_response.status
17
+ end
18
+
19
+ def test_if_unmodified_since
20
+ get('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified+10).httpdate)
21
+ assert_equal STATUS_OK, last_response.status
22
+ get('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified-10).httpdate)
23
+ assert_equal STATUS_PRECONDITION_FAILED, last_response.status
24
+ end
25
+
26
+ def test_status_for_non_get
27
+ root.expects(:supports_post?).returns(true).at_least_once
28
+ root.expects(:supports_put?).returns(true).at_least_once
29
+ root.expects(:supports_delete?).returns(true).at_least_once
30
+ root.expects(:accepts_method_with_media_type?).returns(true).at_least_once
31
+ root.expects(:post).never
32
+ root.expects(:put).never
33
+ root.expects(:delete).never
34
+
35
+ assert_equal STATUS_PRECONDITION_FAILED, post('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified-10).httpdate).status
36
+ assert_equal STATUS_PRECONDITION_FAILED, put('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified-10).httpdate).status
37
+ assert_equal STATUS_PRECONDITION_FAILED, delete('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified-10).httpdate).status
38
+ assert_equal STATUS_PRECONDITION_FAILED, post('HTTP_IF_MODIFIED_SINCE' => (@last_modified+10).httpdate).status
39
+ assert_equal STATUS_PRECONDITION_FAILED, put('HTTP_IF_MODIFIED_SINCE' => (@last_modified+10).httpdate).status
40
+ assert_equal STATUS_PRECONDITION_FAILED, delete('HTTP_IF_MODIFIED_SINCE' => (@last_modified+10).httpdate).status
41
+ end
42
+ end
43
+
44
+ class EntityPreconditionTest < Test::Unit::TestCase
45
+ include Doze::Utils
46
+ include Doze::TestCase
47
+
48
+ def setup
49
+ @last_modified = Time.now - 30
50
+ root.expects(:last_modified).returns(@last_modified).at_least_once
51
+
52
+ @entity = mock_entity('foo')
53
+ @etag = '123abc'
54
+ @entity.expects(:etag).returns(@etag).at_least_once
55
+ root.expects(:get).returns(@entity).at_least_once
56
+ end
57
+
58
+ def test_if_match
59
+ get('HTTP_IF_MATCH' => quote(@etag))
60
+ assert_equal STATUS_OK, last_response.status
61
+ get('HTTP_IF_MATCH' => quote("not-the-etag"))
62
+ assert_equal STATUS_PRECONDITION_FAILED, last_response.status
63
+ end
64
+
65
+ def test_if_none_match
66
+ get('HTTP_IF_NONE_MATCH' => quote(@etag))
67
+ assert_equal STATUS_NOT_MODIFIED, last_response.status
68
+ get('HTTP_IF_NONE_MATCH' => quote("not-the-etag"))
69
+ assert_equal STATUS_OK, last_response.status
70
+ end
71
+
72
+ def test_non_get_method_not_called_when_precondition_fails
73
+ root.expects(:supports_post?).returns(true).once
74
+ root.expects(:supports_put?).returns(true).once
75
+ root.expects(:supports_delete?).returns(true).once
76
+ root.expects(:accepts_method_with_media_type?).returns(true).at_least_once
77
+ root.expects(:post).never
78
+ root.expects(:put).never
79
+ root.expects(:delete).never
80
+ assert_equal STATUS_PRECONDITION_FAILED, post('HTTP_IF_MATCH' => quote('not-the-etag')).status
81
+ assert_equal STATUS_PRECONDITION_FAILED, put('HTTP_IF_MATCH' => quote('not-the-etag')).status
82
+ assert_equal STATUS_PRECONDITION_FAILED, delete('HTTP_IF_MATCH' => quote('not-the-etag')).status
83
+ end
84
+ end
@@ -0,0 +1,69 @@
1
+ require "test/unit"
2
+ require 'mocha/setup'
3
+ require 'doze/request'
4
+
5
+ class RawPathInfoTest < Test::Unit::TestCase
6
+ include Doze::Utils
7
+ include Doze::TestCase
8
+
9
+ def mock_request(path, host="localhost", scheme="http", port=-1, context="")
10
+
11
+ port_str = if port == -1 then "" ; else ":#{port}" ; end
12
+
13
+ path_parts = ["/", context, path].join("")
14
+ if path_parts[0...2] == "//" then path_parts = path_parts[1..-1] end
15
+
16
+ url = stub()
17
+ url.stubs(:toString).returns("#{scheme}://#{host}#{port_str}#{path_parts}")
18
+
19
+ s_request = stub("")
20
+ s_request.stubs(:getRequestURL).returns(url)
21
+ s_request.stubs(:getContextPath).returns(context)
22
+
23
+ app = stub()
24
+ env = stub()
25
+ env.stubs(:[]).with('java.servlet_request').returns(s_request)
26
+ Doze::Request.new(app, env)
27
+ end
28
+
29
+ def test_bland_path
30
+ dr = mock_request("/path/is/good")
31
+ assert_equal dr.raw_path_info, "/path/is/good"
32
+ end
33
+
34
+ def test_path_with_host_and_port
35
+ dr = mock_request("/how/do", "x23.awesome-server.playlouder---com.com", 5432)
36
+ assert_equal dr.raw_path_info, "/how/do"
37
+ end
38
+
39
+ def test_path_with_naughty_chars
40
+ dr = mock_request("/how/do%20", "awesome-server", 5432)
41
+ assert_equal dr.raw_path_info, "/how/do%20"
42
+ end
43
+
44
+ def test_context_is_chomped
45
+ ['bob', 'bob-y', 'the%20bobster'].each do |context|
46
+ dr = mock_request('/path-s/of/life', 'www.awesome.com', 'https', 8080, context)
47
+ assert_equal dr.raw_path_info, "/path-s/of/life"
48
+ end
49
+ end
50
+
51
+ def test_searchpart_excluded
52
+ {
53
+ '/path' => '/path', '?false=true' => '/', '/path?you=suck&bob&nick=awesome' => '/path'
54
+ }.each do |raw, exp_raw_path_info|
55
+ dr = mock_request(raw, 'some.host-rocks', 'http', 1234)
56
+ assert_equal dr.raw_path_info, exp_raw_path_info
57
+ end
58
+ end
59
+
60
+ def test_servlet_is_missing
61
+ app = stub()
62
+ env = stub()
63
+ env.stubs(:[]).with('java.servlet_request').returns(nil)
64
+ dr = Doze::Request.new(app, env)
65
+ dr.expects(:path_info).twice.returns("/omg/im/a/path")
66
+ assert_equal dr.raw_path_info, dr.path_info
67
+ end
68
+
69
+ end
@@ -0,0 +1,14 @@
1
+ require 'functional/base'
2
+
3
+ class ResourceRepresentationTest < Test::Unit::TestCase
4
+ include Doze::Utils
5
+ include Doze::TestCase
6
+
7
+ def test_get_with_resource_representation
8
+ resource = mock_resource('/foo/bar')
9
+ root.expects(:get).returns(resource)
10
+ get
11
+ assert_equal STATUS_SEE_OTHER, last_response.status
12
+ assert_response_header 'Location', 'http://example.org/foo/bar'
13
+ end
14
+ end
@@ -0,0 +1,196 @@
1
+ require 'functional/base'
2
+
3
+ class RouterInterfaceTest < Test::Unit::TestCase
4
+ include Doze::Utils
5
+ include Doze::TestCase
6
+
7
+ # tests how the basic Router interface is exposed by the framework
8
+
9
+ def test_router_no_match
10
+ root_router.expects(:perform_routing).with('/foo', nil, '').returns(nil).once
11
+ assert_equal STATUS_NOT_FOUND, get('/foo').status
12
+ end
13
+
14
+ def test_router_match_resource_with_no_trailing_path
15
+ resource = mock_resource('/foo')
16
+ root_router.expects(:perform_routing).with('/foo', nil, '').returns([resource, '/foo', nil]).once
17
+ resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
18
+ assert_equal STATUS_OK, get('/foo').status
19
+ end
20
+
21
+ def test_router_match_resource_but_with_trailing
22
+ # here we route to a resource, but there is some trailing path which can't be routed any further
23
+ resource = mock_resource('/foo')
24
+ root_router.expects(:perform_routing).with('/foo/bar', nil, '').returns([resource, '/foo', '/bar']).once
25
+ resource.expects(:get).never
26
+ assert_equal STATUS_NOT_FOUND, get('/foo/bar').status
27
+ end
28
+
29
+ def test_router_match_router_with_trailing_then_resource
30
+ # here we route to another router which is matched but with some trailing path that's passed on to it.
31
+
32
+ second_router = mock_router
33
+ resource = mock_resource('/foo/bar')
34
+
35
+ root_router.expects(:perform_routing).with('/foo/bar', nil, '').returns([second_router, '/foo', '/bar']).once
36
+ second_router.expects(:perform_routing).with('/bar', nil, '/foo').returns([resource, '/foo/bar', nil]).once
37
+
38
+ resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
39
+ assert_equal STATUS_OK, get('/foo/bar').status
40
+ end
41
+
42
+ def test_router_match_router_resource_with_trailing_then_resource
43
+ # as above but this time our second router is also a resource - check that it does actually act as a router
44
+
45
+ second_router = mock_router(Doze::MockResource)
46
+ resource = mock_resource('/foo/bar')
47
+
48
+ root_router.expects(:perform_routing).with('/foo/bar', nil, '').returns([second_router, '/foo', '/bar']).once
49
+ second_router.expects(:perform_routing).with('/bar', nil, '/foo').returns([resource, '/foo/bar', nil]).once
50
+
51
+ second_router.expects(:get).never
52
+ resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
53
+ assert_equal STATUS_OK, get('/foo/bar').status
54
+ end
55
+
56
+ def test_router_match_router_resource_with_no_trailing
57
+ resource = mock_router(Doze::MockResource)
58
+
59
+ root_router.expects(:perform_routing).with('/foo', nil, '').returns([resource, '/foo', nil]).once
60
+ resource.expects(:perform_routing).never
61
+ resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
62
+
63
+ assert_equal STATUS_OK, get('/foo').status
64
+ end
65
+
66
+ def test_router_gets_passed_user
67
+ root_router.expects(:perform_routing).with('/foo', 'Mack', '').returns(nil).once
68
+ assert_equal STATUS_NOT_FOUND, get('/foo', 'REMOTE_USER' => 'Mack').status
69
+ end
70
+ end
71
+
72
+
73
+ class RouterDefaultImplementationTest < Test::Unit::TestCase
74
+ include Doze::Utils
75
+ include Doze::TestCase
76
+
77
+ # tests the default implementation of Router based on routes defined in class method helpers
78
+
79
+ def test_route_fixed_uri_to_resource_class
80
+ resource = mock_resource('/foo')
81
+ resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
82
+ klass = Class.new
83
+ klass.expects(:new).with("/foo").returns(resource)
84
+
85
+ root_router do
86
+ route '/foo', :to => klass
87
+ end
88
+
89
+ assert_equal STATUS_OK, get('/foo').status
90
+ end
91
+
92
+ def test_route_fixed_uri_to_resource_instance
93
+ resource = mock_resource('/foo')
94
+ resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
95
+
96
+ root_router do
97
+ route '/foo', :to => resource
98
+ end
99
+
100
+ assert_equal STATUS_OK, get('/foo').status
101
+ end
102
+
103
+ def test_route_with_params_to_block_returning_resource
104
+ root_router do
105
+ route('/foo/{x}/{y}') do |router, uri, params|
106
+ Doze::MockResource.new(uri, [uri, params].inspect)
107
+ end
108
+ end
109
+
110
+ get('/foo/abc/123')
111
+
112
+ assert_equal STATUS_OK, last_response.status
113
+ assert_equal(['/foo/abc/123', {:x => 'abc', :y => '123'}].inspect, last_response.body)
114
+ end
115
+
116
+ # More complex two-level routing scenario with params at both levels
117
+ def test_route_with_params_to_block_returning_router_routing_to_resource_with_more_params
118
+ root_router do
119
+ route('/foo/{x}') do |router1, uri1, params1|
120
+
121
+ Class.new do
122
+ include Doze::Router
123
+ route("/{y}") do |router2, uri2, params2|
124
+ Doze::MockResource.new(uri2, [uri1, params1, uri2, params2].inspect)
125
+ end
126
+ end.new
127
+ end
128
+ end
129
+
130
+ get('/foo/abc/123')
131
+
132
+ assert_equal STATUS_OK, last_response.status
133
+ # bit of a messy way to test it but this was getting fiddly to mock nicely
134
+ # expecting [uri1, params1, uri2, params2].inspect from above
135
+ assert_equal(['/foo/abc', {:x => 'abc'}, '/foo/abc/123', {:y => '123'}].inspect, last_response.body)
136
+ end
137
+
138
+ def test_route_with_special_param_regexp
139
+ root_router do
140
+ route('/foo/{x}', :regexps => {:x => /\d+/}) do |router, uri, params|
141
+ Doze::MockResource.new(uri, params[:x])
142
+ end
143
+ end
144
+
145
+ assert_equal STATUS_NOT_FOUND, get('/foo/abc').status
146
+ assert_equal STATUS_OK, get('/foo/123').status
147
+ assert_equal "123", last_response.body
148
+ end
149
+
150
+ def test_route_with_uri_template_passed_directly
151
+ root_router do
152
+ route(Doze::URITemplate.compile('/foo/{x}', :x => /\d+/)) do |router, uri, params|
153
+ Doze::MockResource.new(uri, params[:x])
154
+ end
155
+ end
156
+
157
+ assert_equal STATUS_NOT_FOUND, get('/foo/abc').status
158
+ assert_equal STATUS_OK, get('/foo/123').status
159
+ assert_equal "123", last_response.body
160
+ end
161
+
162
+ def test_user_specific_route
163
+ root_router do
164
+ route('/foo/{x}/{y}', :session_specific => true) do |router, uri, params, user|
165
+ Doze::MockResource.new(uri, [uri, params, user].inspect)
166
+ end
167
+ end
168
+
169
+ get('/foo/abc/123', 'REMOTE_USER' => 'Mo')
170
+
171
+ assert_equal STATUS_OK, last_response.status
172
+ assert_equal(['/foo/abc/123', {:x => 'abc', :y => '123'}, 'Mo'].inspect, last_response.body)
173
+ end
174
+
175
+ def test_propagate_static_routes
176
+ klass = Class.new
177
+ klass.send(:include, Doze::Router)
178
+ router = mock_router
179
+ router2 = mock_router
180
+
181
+ root_router do
182
+ route "/bar", :uniquely_to => klass
183
+ route "/baz", :uniquely_to => router
184
+ route "/baz", :to => router2
185
+ end
186
+
187
+ root_router.propagate_static_routes("/foo")
188
+
189
+ assert_equal "/foo", root_router.router_uri_prefix
190
+
191
+ assert_equal "/foo/bar", klass.router_uri_prefix
192
+ assert_equal "/foo/bar", klass.new.router_uri_prefix
193
+ assert_equal "/foo/baz", router.router_uri_prefix
194
+ assert_equal nil, router2.router_uri_prefix
195
+ end
196
+ end