raml_ruby 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +71 -0
  7. data/Rakefile +1 -0
  8. data/fixtures/include_1.raml +7 -0
  9. data/fixtures/schemas/canonicalSchemas.raml +3 -0
  10. data/fixtures/schemas/filesystem/file.json +1 -0
  11. data/fixtures/schemas/filesystem/files.json +1 -0
  12. data/fixtures/schemas/filesystem/fileupdate.json +1 -0
  13. data/fixtures/schemas/filesystem/relative/test.json +1 -0
  14. data/lib/raml.rb +104 -0
  15. data/lib/raml/exceptions.rb +27 -0
  16. data/lib/raml/mixin/bodies.rb +32 -0
  17. data/lib/raml/mixin/documentable.rb +32 -0
  18. data/lib/raml/mixin/global.rb +20 -0
  19. data/lib/raml/mixin/headers.rb +22 -0
  20. data/lib/raml/mixin/merge.rb +24 -0
  21. data/lib/raml/mixin/parent.rb +54 -0
  22. data/lib/raml/mixin/validation.rb +49 -0
  23. data/lib/raml/node.rb +219 -0
  24. data/lib/raml/node/abstract_method.rb +61 -0
  25. data/lib/raml/node/abstract_resource.rb +165 -0
  26. data/lib/raml/node/abstract_resource_circular.rb +5 -0
  27. data/lib/raml/node/body.rb +94 -0
  28. data/lib/raml/node/documentation.rb +28 -0
  29. data/lib/raml/node/header.rb +4 -0
  30. data/lib/raml/node/method.rb +106 -0
  31. data/lib/raml/node/parameter/abstract_parameter.rb +251 -0
  32. data/lib/raml/node/parameter/base_uri_parameter.rb +6 -0
  33. data/lib/raml/node/parameter/form_parameter.rb +6 -0
  34. data/lib/raml/node/parameter/query_parameter.rb +6 -0
  35. data/lib/raml/node/parameter/uri_parameter.rb +7 -0
  36. data/lib/raml/node/parametized_reference.rb +15 -0
  37. data/lib/raml/node/reference.rb +4 -0
  38. data/lib/raml/node/resource.rb +26 -0
  39. data/lib/raml/node/resource_type.rb +20 -0
  40. data/lib/raml/node/resource_type_reference.rb +5 -0
  41. data/lib/raml/node/response.rb +32 -0
  42. data/lib/raml/node/root.rb +246 -0
  43. data/lib/raml/node/schema.rb +41 -0
  44. data/lib/raml/node/schema_reference.rb +5 -0
  45. data/lib/raml/node/template.rb +55 -0
  46. data/lib/raml/node/trait.rb +18 -0
  47. data/lib/raml/node/trait_reference.rb +5 -0
  48. data/lib/raml/parser.rb +57 -0
  49. data/lib/raml/parser/include.rb +25 -0
  50. data/lib/raml/patch/hash.rb +6 -0
  51. data/lib/raml/patch/module.rb +12 -0
  52. data/lib/raml/version.rb +3 -0
  53. data/raml_ruby.gemspec +35 -0
  54. data/raml_spec_reqs.md +276 -0
  55. data/templates/abstract_parameter.slim +68 -0
  56. data/templates/body.slim +15 -0
  57. data/templates/collapse.slim +10 -0
  58. data/templates/documentation.slim +2 -0
  59. data/templates/method.slim +38 -0
  60. data/templates/resource.slim +33 -0
  61. data/templates/response.slim +13 -0
  62. data/templates/root.slim +39 -0
  63. data/templates/style.sass +119 -0
  64. data/test/apis/box-api.raml +4224 -0
  65. data/test/apis/instagram-api.raml +3378 -0
  66. data/test/apis/stripe-api.raml +12227 -0
  67. data/test/apis/twilio-rest-api.raml +6618 -0
  68. data/test/apis/twitter-rest-api.raml +34284 -0
  69. data/test/raml/body_spec.rb +268 -0
  70. data/test/raml/documentation_spec.rb +49 -0
  71. data/test/raml/header_spec.rb +17 -0
  72. data/test/raml/include_spec.rb +40 -0
  73. data/test/raml/method_spec.rb +701 -0
  74. data/test/raml/parameter/abstract_parameter_spec.rb +564 -0
  75. data/test/raml/parameter/form_parameter_spec.rb +17 -0
  76. data/test/raml/parameter/query_parameter_spec.rb +33 -0
  77. data/test/raml/parameter/uri_parameter_spec.rb +44 -0
  78. data/test/raml/parser_spec.rb +53 -0
  79. data/test/raml/raml_spec.rb +32 -0
  80. data/test/raml/resource_spec.rb +440 -0
  81. data/test/raml/resource_type_spec.rb +51 -0
  82. data/test/raml/response_spec.rb +251 -0
  83. data/test/raml/root_spec.rb +655 -0
  84. data/test/raml/schema_spec.rb +110 -0
  85. data/test/raml/spec_helper.rb +11 -0
  86. data/test/raml/template_spec.rb +98 -0
  87. data/test/raml/trait_spec.rb +31 -0
  88. metadata +337 -0
@@ -0,0 +1,51 @@
1
+ # encoding: UTF-8
2
+ require_relative 'spec_helper'
3
+
4
+ describe Raml::ResourceType do
5
+ let(:name) { 'auditableResource' }
6
+ let(:data) {
7
+ YAML.load(%q(
8
+ post:
9
+ body:
10
+ application/x-www-form-urlencoded:
11
+ formParameters:
12
+ createAuthority:
13
+ description: |
14
+ If the resource has a post method defined, expect a createAuthority
15
+ property in its body
16
+ delete:
17
+ body:
18
+ multipart/form-data:
19
+ formParameters:
20
+ deleteAuthority:
21
+ description: |
22
+ If the resource has a delete method defined, expect a deleteAuthority
23
+ property in its body
24
+ ))
25
+ }
26
+ let(:root) { Raml::Root.new 'title' => 'x', 'baseUri' => 'http://foo.com' }
27
+
28
+ subject { Raml::ResourceType.new(name, data, root) }
29
+
30
+ describe '#new' do
31
+ context 'with valid arguments' do
32
+ it { expect { subject }.to_not raise_error }
33
+ it { should be_a Raml::ResourceType }
34
+ end
35
+ end
36
+
37
+ describe '#instantiate' do
38
+ context 'when the usage property is given' do
39
+ before { data['usage'] = 'Some text' }
40
+ it 'stores the usage property' do
41
+ subject.instantiate({}).usage.should eq data['usage']
42
+ end
43
+ end
44
+ context 'with invalid arguments' do
45
+ context 'when the resource type has nested resources' do
46
+ before { data['/foo'] = {} }
47
+ it { expect { subject.instantiate({}) }.to raise_error Raml::UnknownProperty, /\/foo/ }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,251 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Raml::Response do
4
+ let (:name) { 200 }
5
+ let (:response_data) {
6
+ YAML.load(%q(
7
+ displayName: Success
8
+ description: Successful response
9
+ body:
10
+ text/xml:
11
+ schema: some xml schema
12
+ example: |
13
+ <api-request>
14
+ <input>s3://zencodertesting/test.mov</input>
15
+ </api-request>
16
+ application/json:
17
+ schema: some json schema
18
+ example: |
19
+ {
20
+ "input": "s3://zencodertesting/test.mov"
21
+ }
22
+ headers:
23
+ Zencoder-Api-Key:
24
+ displayName: ZEncoder API Key
25
+ x-Zencoder-job-metadata-{*}:
26
+ displayName: Job Metadata
27
+ ))
28
+ }
29
+ let(:root) { Raml::Root.new 'title' => 'x', 'baseUri' => 'http://foo.com' }
30
+
31
+ subject { Raml::Response.new name, response_data, root }
32
+
33
+ describe '#new' do
34
+ it "inits with name" do
35
+ expect( subject.name ).to eq(name)
36
+ end
37
+
38
+ it "inits with headers" do
39
+ expect( subject.headers.size ).to eq(2)
40
+ end
41
+
42
+ context 'when a body property is given' do
43
+ context 'when the body property is well formed' do
44
+ it { expect { subject }.to_not raise_error }
45
+ it 'stores all as Raml::Body instances' do
46
+ expect( subject.bodies.values ).to all( be_a Raml::Body )
47
+ expect( subject.bodies.size ).to eq(2)
48
+ subject.bodies.keys.should contain_exactly('text/xml', 'application/json')
49
+ end
50
+ end
51
+ context 'when the body property is not a map' do
52
+ before { response_data['body'] = 1 }
53
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /body/ }
54
+ end
55
+ context 'when the body property is a map with non-string keys' do
56
+ before { response_data['body'] = { 1 => {}} }
57
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /body/ }
58
+ end
59
+ context 'when the body property is a map with non-map values' do
60
+ before { response_data['body'] = { 'text/xml' => 1 } }
61
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /body/ }
62
+ end
63
+ end
64
+
65
+ context 'when description property is not given' do
66
+ before { response_data.delete 'description' }
67
+ it { expect { subject }.to_not raise_error }
68
+ end
69
+ context 'when description property is given' do
70
+ context 'when the description property is not a string' do
71
+ before { response_data['description'] = 1 }
72
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /description/ }
73
+ end
74
+ context 'when the description property is a string' do
75
+ before { response_data['description'] = 'My Description' }
76
+ it { expect { subject }.to_not raise_error }
77
+ it 'should store the value' do
78
+ subject.description.should eq response_data['description']
79
+ end
80
+ it 'uses the description in the documentation' do
81
+ subject.document.should include response_data['description']
82
+ end
83
+ end
84
+ end
85
+
86
+ context 'when the headers parameter is given' do
87
+ context 'when the headers property is well formed' do
88
+ it { expect { subject }.to_not raise_error }
89
+ it 'stores all as Raml::Header instances' do
90
+ expect( subject.headers.values ).to all( be_a Raml::Header )
91
+ expect( subject.headers.keys ).to contain_exactly('Zencoder-Api-Key','x-Zencoder-job-metadata-{*}')
92
+ end
93
+ end
94
+ context 'when the headers property is not a map' do
95
+ before { response_data['headers'] = 1 }
96
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /headers/ }
97
+ end
98
+ context 'when the headers property is not a map with non-string keys' do
99
+ before { response_data['headers'] = { 1 => {}} }
100
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /headers/ }
101
+ end
102
+ context 'when the headers property is not a map with non-string keys' do
103
+ before { response_data['headers'] = { '1' => 'x'} }
104
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /headers/ }
105
+ end
106
+ end
107
+ end
108
+
109
+ describe '#merge' do
110
+ context 'when response and mixin have different status codes' do
111
+ let(:response) { Raml::Response.new 200, {}, root }
112
+ let(:mixin ) { Raml::Response.new 403, {}, root }
113
+ it { expect { response.merge mixin }.to raise_error Raml::MergeError }
114
+ end
115
+
116
+ context 'when response and mixin have different the same codes' do
117
+ let(:response) { Raml::Response.new 200, response_data, root }
118
+ let(:mixin ) { Raml::Response.new 200, mixin_data , root }
119
+ context 'when the mixin has a property set' do
120
+ context 'when the response does not have that property set' do
121
+ let(:response_data) { {} }
122
+ context 'displayName property' do
123
+ let(:mixin_data) { {displayName: 'mixin displayName'} }
124
+ it 'sets the property in the response' do
125
+ response.merge(mixin).display_name.should eq mixin.display_name
126
+ end
127
+ end
128
+ context 'description property' do
129
+ let(:mixin_data) { {description: 'mixin description'} }
130
+ it 'sets the property in the response' do
131
+ response.merge(mixin).description.should eq mixin.description
132
+ end
133
+ end
134
+ context 'headers properties' do
135
+ let(:mixin_data) { {
136
+ 'headers' => {
137
+ 'header1' => {'description' => 'foo'},
138
+ 'header2' => {'description' => 'bar'}
139
+ }
140
+ } }
141
+ it 'adds the headers to the response' do
142
+ response.merge(mixin).headers.keys.should contain_exactly('header1', 'header2')
143
+ end
144
+ end
145
+ context 'body property' do
146
+ let(:mixin_data) { {
147
+ 'body' => {
148
+ 'text/mime1' => {'schema' => 'foo'},
149
+ 'text/mime2' => {'schema' => 'bar'}
150
+ }
151
+ } }
152
+ it 'adds the body media types to the response' do
153
+ response.merge(mixin).bodies.keys.should contain_exactly('text/mime1', 'text/mime2')
154
+ end
155
+ end
156
+ end
157
+ context 'when the response has that property set' do
158
+ context 'displayName property' do
159
+ let(:response_data) { {displayName: 'response displayName'} }
160
+ let(:mixin_data ) { {displayName: 'mixin displayName' } }
161
+ it 'overrites the response property' do
162
+ response.merge(mixin).display_name.should eq 'mixin displayName'
163
+ end
164
+ end
165
+ context 'description property' do
166
+ let(:response_data) { {description: 'response description'} }
167
+ let(:mixin_data ) { {description: 'mixin description' } }
168
+ it 'overrites the response property' do
169
+ response.merge(mixin).description.should eq 'mixin description'
170
+ end
171
+ end
172
+ context 'headers properties' do
173
+ let(:response_data) { {
174
+ 'headers' => {
175
+ 'header1' => {'description' => 'foo'},
176
+ 'header2' => {'description' => 'bar'}
177
+ }
178
+ } }
179
+ context 'when the mixin headers are different from the response headers' do
180
+ let(:mixin_data) { {
181
+ 'headers' => {
182
+ 'header3' => {'description' => 'foo2'},
183
+ 'header4' => {'description' => 'bar2'}
184
+ }
185
+ } }
186
+ it 'adds the headers to the response' do
187
+ response.merge(mixin).headers.keys.should contain_exactly('header1', 'header2', 'header3', 'header4')
188
+ end
189
+ end
190
+ context 'when the mixin headers overlap the the response headers' do
191
+ let(:mixin_data) { {
192
+ 'headers' => {
193
+ 'header2' => {'description' => 'bar3', 'displayName' => 'Header 3'},
194
+ 'header3' => {'description' => 'foo2'},
195
+ 'header4' => {'description' => 'bar2'}
196
+ }
197
+ } }
198
+ it 'merges the matching headers and adds the non-matching headers to the response' do
199
+ response.merge(mixin).headers.keys.should contain_exactly('header1', 'header2', 'header3', 'header4')
200
+ response.headers['header2'].display_name.should eq mixin.headers['header2'].display_name
201
+ response.headers['header2'].description.should eq mixin.headers['header2'].description
202
+ end
203
+ end
204
+ end
205
+ context 'body property' do
206
+ let(:response_data) { {
207
+ 'body' => {
208
+ 'text/mime1' => {'schema' => 'foo'},
209
+ 'text/mime2' => {'schema' => 'bar'}
210
+ }
211
+ } }
212
+ context 'when the mixin query parameters are different from the response headers' do
213
+ let(:mixin_data) { {
214
+ 'body' => {
215
+ 'text/mime3' => {'schema' => 'foo2'},
216
+ 'text/mime4' => {'schema' => 'bar2'}
217
+ }
218
+ } }
219
+ it 'adds the body media types to the response' do
220
+ response.merge(mixin).bodies.keys.should contain_exactly('text/mime1', 'text/mime2', 'text/mime3', 'text/mime4')
221
+ end
222
+ end
223
+ context 'when the mixin query parameters overlap the the response query parameters' do
224
+ let(:mixin_data) { {
225
+ 'body' => {
226
+ 'text/mime2' => {'example' => 'Example 2'},
227
+ 'text/mime3' => {'schema' => 'foo2'},
228
+ 'text/mime4' => {'schema' => 'bar2'}
229
+ }
230
+ } }
231
+ it 'merges the matching media types and adds the non-matching media types to the response' do
232
+ response.merge(mixin).bodies.keys.should contain_exactly('text/mime1', 'text/mime2', 'text/mime3', 'text/mime4')
233
+ response.bodies['text/mime2'].example.should eq mixin.bodies['text/mime2'].example
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+
242
+ describe '#document' do
243
+ it 'returns a String' do
244
+ subject.document.should be_a String
245
+ end
246
+ it 'should render the template' do
247
+ mock(Slim::Template).new(/templates\/response.slim\z/, is_a(Hash)).mock!.render(is_a(Raml::Node)) { '' }
248
+ subject.document
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,655 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Raml::Root do
4
+ let(:data) {
5
+ YAML.load(
6
+ %q(
7
+ #%RAML 0.8
8
+ title: ZEncoder API
9
+ baseUri: https://app.zencoder.com/api
10
+ version: v2.0
11
+ documentation:
12
+ - title: Home
13
+ content: Doc content
14
+ )
15
+ )
16
+ }
17
+
18
+ subject { Raml::Root.new data }
19
+
20
+ describe '#new' do
21
+ it "should init root" do
22
+ expect { subject }.to_not raise_error
23
+ end
24
+
25
+ context 'when the title property is missing' do
26
+ let(:data) { { 'baseUri' => 'x' } }
27
+ it { expect{ subject }.to raise_error Raml::RequiredPropertyMissing, /title/ }
28
+ end
29
+ context 'when the title property is not a string' do
30
+ let(:data) { { 'title' => 1, 'baseUri' => 'x' } }
31
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /title/ }
32
+ end
33
+
34
+ context 'when the baseUri property is missing' do
35
+ let(:data) { { 'title' => 'x' } }
36
+ it { expect{ subject }.to raise_error Raml::RequiredPropertyMissing, /baseUri/ }
37
+ end
38
+ context 'when the baseUri property is not a string' do
39
+ let(:data) { { 'title' => 'x', 'baseUri' => 1 } }
40
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /baseUri/ }
41
+ end
42
+ context 'when the baseUri property is a valid URL' do
43
+ it 'should not raise an error' do
44
+ [
45
+ 'https://api.github.com',
46
+ 'https://app.zencoder.com/api'
47
+ ].each do |template|
48
+ expect { Raml::Root.new({ 'title' => 'x', 'baseUri' => template }) }.to_not raise_error
49
+ end
50
+ end
51
+ end
52
+ context 'when the baseUri property is an invalid URL template' do
53
+ let(:data) { { 'title' => 'x', 'baseUri' => '://app.zencoder.com/api' } }
54
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /baseUri/ }
55
+ end
56
+ context 'when the baseUri property is a URL template' do
57
+ it 'should not raise an error' do
58
+ [
59
+ 'https://{destinationBucket}.s3.amazonaws.com',
60
+ 'https://na1.salesforce.com/services/data/{version}/chatter',
61
+ 'https://api.stormpath.com/{version}',
62
+ 'https://{companyName}.freshbooks.com/api/{version}/xml-in',
63
+ 'https://{communityDomain}.force.com/{communityPath}',
64
+ 'https://app.zencoder.com/api/{version}',
65
+ 'https://{apiDomain}.dropbox.com/{version}'
66
+ ].each do |template|
67
+ expect { Raml::Root.new({ 'title' => 'x', 'baseUri' => template, 'version' => 'v1' }) }.to_not raise_error
68
+ end
69
+ end
70
+ end
71
+ context 'when the baseUri property is an invalid URL template' do
72
+ let(:data) { { 'title' => 'x', 'baseUri' => 'https://api.stormpath.com/}version}' } }
73
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /baseUri/ }
74
+ end
75
+
76
+ context 'when the protocols property is missing' do
77
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com' } }
78
+ it { expect{ subject }.to_not raise_error }
79
+ end
80
+ context 'when the protocol property is not an array' do
81
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'protocols' => 'HTTP' } }
82
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /protocols/ }
83
+ end
84
+ context 'when the protocol property is an array but not all elements are strings' do
85
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'protocols' => ['HTTP', 1] } }
86
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /protocols/ }
87
+ end
88
+ context 'when the protocol property is an array of strings with invalid values' do
89
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'protocols' => ['HTTP', 'foo'] } }
90
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /protocols/ }
91
+ end
92
+ [
93
+ [ 'HTTP' ],
94
+ [ 'HTTPS' ],
95
+ [ 'HTTP', 'HTTPS' ]
96
+ ].each do |protocols|
97
+ context "when the protocol property is #{protocols}" do
98
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'protocols' => protocols } }
99
+ it { expect{ subject }.to_not raise_error }
100
+ it 'stores the values' do
101
+ subject.protocols.should eq protocols
102
+ end
103
+ end
104
+ end
105
+ context 'when the protocol property is an array of valid values in lowercase' do
106
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'protocols' => ['http', 'https'] } }
107
+ it 'uppercases them' do
108
+ subject.protocols.should eq [ 'HTTP', 'HTTPS' ]
109
+ end
110
+ end
111
+
112
+ [
113
+ 'application/json',
114
+ 'application/x-yaml',
115
+ 'application/foo+json',
116
+ 'application/foo+xml'
117
+ ].each do |type|
118
+ context 'when the mediaType property is a well formed media type' do
119
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'media_type' => type} }
120
+ it { expect{ subject }.to_not raise_error }
121
+ end
122
+ end
123
+ context 'when the mediaType property is not a string' do
124
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'media_type' => 1 } }
125
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /mediaType/ }
126
+ end
127
+ context 'when the mediaType property is a malformed media type' do
128
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'media_type' => 'foo' } }
129
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /mediaType/ }
130
+ end
131
+
132
+ context 'when the schemas property is an array of maps with string keys and values' do
133
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'schemas' => [{'foo'=>'bar'}] } }
134
+ it { expect{ subject }.to_not raise_error }
135
+ end
136
+ context 'when the schemas property is an array with a single map' do
137
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'schemas' => [{'foo'=>'bar'}] } }
138
+ it 'returns that map in the #schema method' do
139
+ subject.schemas.should be_a Hash
140
+ subject.schemas.keys.should contain_exactly('foo')
141
+ subject.schemas['foo'].should be_a Raml::Schema
142
+ subject.schemas['foo'].value.should == 'bar'
143
+ end
144
+ end
145
+ context 'when the schemas property is an array with multiple maps' do
146
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'schemas' => [{'foo'=>'bar', 'roo'=>'rar'},{'boo'=>'bar'}] } }
147
+ it 'returns the merged maps in the #schema method' do
148
+ subject.schemas.should be_a Hash
149
+ subject.schemas.keys.should contain_exactly('foo', 'roo', 'boo')
150
+ subject.schemas.values.should all(be_a Raml::Schema)
151
+ subject.schemas.values.map(&:value).should contain_exactly('bar', 'rar', 'bar')
152
+ end
153
+ end
154
+ context 'when the schemas property is not an array' do
155
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'schemas' => 'x' } }
156
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /schemas/ }
157
+ end
158
+ context 'when the schemas property is an empty array' do
159
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'schemas' => [] } }
160
+ it { expect{ subject }.to_not raise_error }
161
+ end
162
+ context 'when the schemas property is an array with some non-map elements' do
163
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'schemas' => [{'foo'=>'bar'}, 1] } }
164
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /schemas/ }
165
+ end
166
+ context 'when the schemas property is an array of maps with non-string keys' do
167
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'schemas' => [{1=>'bar'}] } }
168
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /schemas/ }
169
+ end
170
+ context 'when the schemas property is an array of maps with non-string values' do
171
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'schemas' => [{'foo'=>1}] } }
172
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /schemas/ }
173
+ end
174
+ context 'when the schemas property has duplicate schema names' do
175
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'schemas' => [{'foo'=>'bar'},{'foo'=>'boo'}] } }
176
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /schemas/ }
177
+ end
178
+
179
+ context 'when the baseUriParameter property is well formed' do
180
+ let(:data) {
181
+ YAML.load(
182
+ %q(
183
+ title: Salesforce Chatter Communities REST API
184
+ version: v28.0
185
+ baseUri: https://{communityDomain}.force.com/{communityPath}
186
+ baseUriParameters:
187
+ communityDomain:
188
+ displayName: Community Domain
189
+ type: string
190
+ communityPath:
191
+ displayName: Community Path
192
+ type: string
193
+ pattern: ^[a-zA-Z0-9][-a-zA-Z0-9]*$
194
+ minLength: 1
195
+ )
196
+ )
197
+ }
198
+ it { expect { subject }.to_not raise_error }
199
+ it 'stores all as Raml::Parameter::BaseUriParameter instances' do
200
+ expect( subject.base_uri_parameters.values ).to all( be_a Raml::Parameter::BaseUriParameter )
201
+ end
202
+ context 'when the baseUri template does not include a version parameter' do
203
+ context 'and a version property is not provided' do
204
+ before { data.delete 'version' }
205
+ it { expect { subject }.to_not raise_error }
206
+ end
207
+ end
208
+ context 'when the baseUri template includes a version parameter' do
209
+ context 'and a version property is not provided' do
210
+ before do
211
+ data.delete 'version'
212
+ data['baseUri'] = 'https://{communityDomain}.force.com/{version}/{communityPath}'
213
+ end
214
+ it { expect { subject }.to raise_error Raml::RequiredPropertyMissing, /version/ }
215
+ end
216
+ end
217
+ end
218
+ context 'when the baseUriParameter property is not a map' do
219
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'baseUriParameters' => 1 } }
220
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /baseUriParameters/ }
221
+ end
222
+ context 'when the baseUriParameter property is not a map with non-string keys' do
223
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'baseUriParameters' => { 1 => {}} } }
224
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /baseUriParameters/ }
225
+ end
226
+ context 'when the baseUriParameter property is not a map with non-string keys' do
227
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'baseUriParameters' => { '1' => 'x'} } }
228
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /baseUriParameters/ }
229
+ end
230
+ context 'when the baseUriParameter property has a key for the reserved "version" parameter' do
231
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'baseUriParameters' => { 'version' => {}} } }
232
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /baseUriParameters/ }
233
+ end
234
+
235
+ context 'when the documentation parameter is given and valid' do
236
+ let(:data) {
237
+ YAML.load(
238
+ %q(
239
+ #%RAML 0.8
240
+ title: ZEncoder API
241
+ baseUri: https://app.zencoder.com/api
242
+ documentation:
243
+ - title: Home
244
+ content: |
245
+ Welcome to the _Zencoder API_ Documentation.
246
+ )
247
+ )
248
+ }
249
+ it { expect { subject }.to_not raise_error }
250
+ it 'stores all as Raml::Documentation instances' do
251
+ expect( subject.documents ).to all( be_a Raml::Documentation )
252
+ end
253
+ end
254
+ context 'when the documentation property is not a array' do
255
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'documentation' => 1 } }
256
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /documentation/ }
257
+ end
258
+ context 'when the documentation property is an empty array' do
259
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'documentation' => [] } }
260
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /documentation/ }
261
+ end
262
+ context 'when an entry in the documentation property is missing the title' do
263
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'documentation' => [{'content' => 'x'}] } }
264
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /document/ }
265
+ end
266
+ context 'when an entry in the documentation property has an empty title' do
267
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'documentation' => [{'title' => '', 'content' => 'x'}] } }
268
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /document/ }
269
+ end
270
+ context 'when an entry in the documentation property is missing the content' do
271
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'documentation' => [{'title' => 'x'}] } }
272
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /document/ }
273
+ end
274
+ context 'when an entry in the documentation property has an empty content' do
275
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'documentation' => [{'title' => 'x', 'content' => ''}] } }
276
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /document/ }
277
+ end
278
+
279
+ context 'when top-level resources are defined' do
280
+ let(:data) {
281
+ YAML.load(
282
+ %q(
283
+ #%RAML 0.8
284
+ title: GitHub API
285
+ version: v3
286
+ baseUri: https://api.github.com
287
+ /user:
288
+ displayName: Authenticated User
289
+ /users:
290
+ displayName: Users
291
+ )
292
+ )
293
+ }
294
+ it { expect { subject }.to_not raise_error }
295
+ it 'stores all as Raml::Resource instances' do
296
+ expect( subject.resources.values ).to all( be_a Raml::Resource )
297
+ expect( subject.resources.keys ).to contain_exactly('/user','/users')
298
+ end
299
+ end
300
+
301
+ context 'when the resourceTypes property is defined' do
302
+ context 'when the resourceTypes property is an array of maps with string keys and and map values' do
303
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [{'foo'=>{},'boo'=>{}}] } }
304
+ it { expect{ subject }.to_not raise_error }
305
+ end
306
+ context 'when the resourceTypes property is an array with a single map' do
307
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [{'foo'=>{}}] } }
308
+ it 'returns the ResourceType in the #resource_types method' do
309
+ subject.resource_types.should be_a Hash
310
+ subject.resource_types.keys.should contain_exactly('foo')
311
+ subject.resource_types['foo'].should be_a Raml::ResourceType
312
+ subject.resource_types['foo'].name.should == 'foo'
313
+ end
314
+ context 'when the resourceTypes property is an array with a single map with multiple types' do
315
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [{'foo'=>{},'boo'=>{}}] } }
316
+ it 'returns the ResourceTypes in the #resource_types method' do
317
+ subject.resource_types.should be_a Hash
318
+ subject.resource_types.keys.should contain_exactly('foo', 'boo')
319
+ subject.resource_types.values.should all(be_a Raml::ResourceType)
320
+ subject.resource_types.values.map(&:name).should contain_exactly('foo', 'boo')
321
+ end
322
+ end
323
+ end
324
+ context 'when the resourceTypes property is an array with multiple maps' do
325
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [{'foo'=>{}},{'boo'=>{}}] } }
326
+ it 'returns the merged maps in the #resource_types method' do
327
+ subject.resource_types.should be_a Hash
328
+ subject.resource_types.keys.should contain_exactly('foo', 'boo')
329
+ subject.resource_types.values.should all(be_a Raml::ResourceType)
330
+ subject.resource_types.values.map(&:name).should contain_exactly('foo', 'boo')
331
+ end
332
+ end
333
+ context 'when the resourceTypes property is not an array' do
334
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => 'x' } }
335
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /resourceTypes/ }
336
+ end
337
+ context 'when the resourceTypes property is an empty array' do
338
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [] } }
339
+ it { expect{ subject }.to_not raise_error }
340
+ end
341
+ context 'when the resourceTypes property is an array with some non-map elements' do
342
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [{'foo'=>{}}, 1] } }
343
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /resourceTypes/ }
344
+ end
345
+ context 'when the resourceTypes property is an array of maps with non-string keys' do
346
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [{1=>{}}] } }
347
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /resourceTypes/ }
348
+ end
349
+ context 'when the resourceTypes property is an array of maps with non-map values' do
350
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [{'foo'=>1}] } }
351
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /resourceTypes/ }
352
+ end
353
+ context 'when the resourceTypes property has duplicate type names' do
354
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [{'foo'=>{}},{'foo'=>{}}] } }
355
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /resourceTypes/ }
356
+ end
357
+ end
358
+
359
+ context 'when the traits property is defined' do
360
+ context 'when the traits property is an array of maps with string keys and and map values' do
361
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [{'foo'=>{},'boo'=>{}}] } }
362
+ it { expect{ subject }.to_not raise_error }
363
+ end
364
+ context 'when the traits property is an array with a single map' do
365
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [{'foo'=>{}}] } }
366
+ it 'returns the Trait in the #traits method' do
367
+ subject.traits.should be_a Hash
368
+ subject.traits.keys.should contain_exactly('foo')
369
+ subject.traits['foo'].should be_a Raml::Trait
370
+ subject.traits['foo'].name.should == 'foo'
371
+ end
372
+ context 'when the traits property is an array with a single map with multiple traits' do
373
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [{'foo'=>{},'boo'=>{}}] } }
374
+ it 'returns the Traits in the #traits method' do
375
+ subject.traits.should be_a Hash
376
+ subject.traits.keys.should contain_exactly('foo', 'boo')
377
+ subject.traits.values.should all(be_a Raml::Trait)
378
+ subject.traits.values.map(&:name).should contain_exactly('foo', 'boo')
379
+ end
380
+ end
381
+ end
382
+ context 'when the traits property is an array with multiple maps' do
383
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [{'foo'=>{}},{'boo'=>{}}] } }
384
+ it 'returns the merged maps in the #traits method' do
385
+ subject.traits.should be_a Hash
386
+ subject.traits.keys.should contain_exactly('foo', 'boo')
387
+ subject.traits.values.should all(be_a Raml::Trait)
388
+ subject.traits.values.map(&:name).should contain_exactly('foo', 'boo')
389
+ end
390
+ end
391
+ context 'when the traits property is not an array' do
392
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => 'x' } }
393
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /traits/ }
394
+ end
395
+ context 'when the traits property is an empty array' do
396
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [] } }
397
+ it { expect{ subject }.to_not raise_error }
398
+ end
399
+ context 'when the traits property is an array with some non-map elements' do
400
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [{'foo'=>{}}, 1] } }
401
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /traits/ }
402
+ end
403
+ context 'when the traits property is an array of maps with non-string keys' do
404
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [{1=>{}}] } }
405
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /traits/ }
406
+ end
407
+ context 'when the traits property is an array of maps with non-map values' do
408
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [{'foo'=>1}] } }
409
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /traits/ }
410
+ end
411
+ context 'when the traits property has duplicate trait names' do
412
+ let(:data) { { 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [{'foo'=>{}},{'foo'=>{}}] } }
413
+ it { expect{ subject }.to raise_error Raml::InvalidProperty, /traits/ }
414
+ end
415
+ end
416
+ end
417
+
418
+ describe '#expand' do
419
+ context 'when the syntax trees contains SchemaReferences' do
420
+ let(:data) {
421
+ YAML.load(
422
+ %q(
423
+ #%RAML 0.8
424
+ title: ZEncoder API
425
+ baseUri: https://app.zencoder.com/api
426
+ schemas:
427
+ - XMLJob: |
428
+ <xs:schema attributeFormDefault="unqualified"
429
+ elementFormDefault="qualified"
430
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
431
+ <xs:element name="api-request">
432
+ <xs:complexType>
433
+ <xs:sequence>
434
+ <xs:element type="xs:string" name="input"/>
435
+ </xs:sequence>
436
+ </xs:complexType>
437
+ </xs:element>
438
+ </xs:schema>
439
+ JSONJob: |
440
+ {
441
+ "$schema": "http://json-schema.org/draft-03/schema#",
442
+ "properties": {
443
+ "input": {
444
+ "required": false,
445
+ "type": "string"
446
+ }
447
+ },
448
+ "required": false,
449
+ "type": "object"
450
+ }
451
+ /jobs:
452
+ displayName: Jobs
453
+ post:
454
+ description: Create a Job
455
+ body:
456
+ text/xml:
457
+ schema: XMLJob
458
+ application/json:
459
+ schema: JSONJob
460
+ responses:
461
+ 200:
462
+ body:
463
+ text/xml:
464
+ schema: XMLJob
465
+ application/json:
466
+ schema: JSONJob
467
+ )
468
+ )
469
+ }
470
+ it 'replaces them with Schemas' do
471
+ subject.resources['/jobs'].methods['post'].bodies['text/xml' ].schema.should be_a Raml::SchemaReference
472
+ subject.resources['/jobs'].methods['post'].bodies['application/json'].schema.should be_a Raml::SchemaReference
473
+ subject.resources['/jobs'].methods['post'].responses[200].bodies['text/xml' ].schema.should be_a Raml::SchemaReference
474
+ subject.resources['/jobs'].methods['post'].responses[200].bodies['application/json'].schema.should be_a Raml::SchemaReference
475
+ subject.expand
476
+ subject.resources['/jobs'].methods['post'].bodies['text/xml' ].schema.should be_a Raml::Schema
477
+ subject.resources['/jobs'].methods['post'].bodies['application/json'].schema.should be_a Raml::Schema
478
+ subject.resources['/jobs'].methods['post'].responses[200].bodies['text/xml' ].schema.should be_a Raml::Schema
479
+ subject.resources['/jobs'].methods['post'].responses[200].bodies['application/json'].schema.should be_a Raml::Schema
480
+ end
481
+ end
482
+
483
+ context 'when the syntax tree contains Resources' do
484
+ let(:data) {
485
+ YAML.load(
486
+ %q(
487
+ #%RAML 0.8
488
+ title: Example API
489
+ version: v1
490
+ baseUri: https://app.zencoder.com/api
491
+ resourceTypes:
492
+ - collection:
493
+ description: The collection.
494
+ - member:
495
+ description: The member.
496
+ /jobs:
497
+ type: collection
498
+ /status:
499
+ type: member
500
+ /users:
501
+ type: collection
502
+ )
503
+ )
504
+ }
505
+ it 'applies traits to resources' do
506
+ subject.resources.size.should eq 2
507
+ subject.resources.values.each { |resource| mock(resource).apply_traits {} }
508
+ subject.expand
509
+ end
510
+ it 'applies resource types to the resources' do
511
+ subject.resources.size.should eq 2
512
+ subject.resources.values.each { |resource| mock(resource).apply_resource_type {} }
513
+ subject.expand
514
+ end
515
+ end
516
+
517
+ context 'when the syntax tree contains resource types and traits' do
518
+ let(:data) {
519
+ YAML.load(
520
+ %q(
521
+ #%RAML 0.8
522
+ title: Example API
523
+ version: v1
524
+ baseUri: https://app.zencoder.com/api
525
+ traits:
526
+ - trait1:
527
+ queryParameters:
528
+ param1:
529
+ description: <<methodName>> trait1 param1
530
+ param2:
531
+ description: trait1 param2
532
+ trait2:
533
+ queryParameters:
534
+ param2:
535
+ description: trait2 param2
536
+ param3:
537
+ description: trait2 param3 <<arg1 | !pluralize>>
538
+ trait3:
539
+ queryParameters:
540
+ param3:
541
+ description: trait3 param3
542
+ param4:
543
+ description: trait3 param4
544
+ trait4:
545
+ responses:
546
+ 200?:
547
+ body:
548
+ application/xml:
549
+ schema: schema3
550
+ 403?:
551
+ body:
552
+ application/xml:
553
+ schema: schema3
554
+ trait5:
555
+ responses:
556
+ 403:
557
+ body:
558
+ plain/text?:
559
+ schema: schema4
560
+ resourceTypes:
561
+ - resource_type1:
562
+ description: resource_type1 description
563
+ get?:
564
+ body:
565
+ application/json:
566
+ schema: schema1
567
+ post?:
568
+ body:
569
+ application/json:
570
+ schema: schema2
571
+ resource_type2:
572
+ description: resource_type2 description
573
+ displayName: resource_type2 displayName
574
+ get:
575
+ is: [ trait1 ]
576
+ description: resource_type2 get description
577
+ /resource1:
578
+ type: resource_type1
579
+ description: resource1 description
580
+ get:
581
+ description: resource1 get
582
+ /resource1_1:
583
+ type: resource_type2
584
+ description: resource1_1 description
585
+ /resource2:
586
+ type: resource_type2
587
+ is: [ trait3, trait2: { arg1: dog }, trait4, trait5 ]
588
+ get:
589
+ responses:
590
+ 403:
591
+ body:
592
+ application/json:
593
+ schema: schema4
594
+ )
595
+ )
596
+ }
597
+
598
+ it 'applies them correctly' do
599
+ subject.expand
600
+ subject.resources['/resource1'].description.should eq 'resource1 description'
601
+ subject.resources['/resource1'].methods.keys.should include 'get'
602
+ subject.resources['/resource1'].methods['get'].bodies['application/json'].schema.value.should eq 'schema1'
603
+ subject.resources['/resource1'].methods.keys.should_not include 'post'
604
+ subject.resources['/resource1'].resources['/resource1_1'].description.should eq 'resource1_1 description'
605
+ subject.resources['/resource1'].resources['/resource1_1'].display_name.should eq 'resource_type2 displayName'
606
+ subject.resources['/resource1'].resources['/resource1_1'].methods['get'].description.should eq 'resource_type2 get description'
607
+ subject.resources['/resource2'].description.should eq 'resource_type2 description'
608
+ subject.resources['/resource2'].display_name.should eq 'resource_type2 displayName'
609
+ subject.resources['/resource2'].methods['get'].description.should eq 'resource_type2 get description'
610
+ subject.resources['/resource2'].methods['get'].query_parameters['param1'].description.should eq 'get trait1 param1'
611
+ subject.resources['/resource2'].methods['get'].query_parameters['param2'].description.should eq 'trait1 param2'
612
+ subject.resources['/resource2'].methods['get'].query_parameters['param3'].description.should eq 'trait2 param3 dogs'
613
+ subject.resources['/resource2'].methods['get'].query_parameters['param4'].description.should eq 'trait3 param4'
614
+ subject.resources['/resource2'].methods['get'].responses.keys.should_not include '200'
615
+ subject.resources['/resource2'].methods['get'].responses.keys.should_not include 200
616
+ subject.resources['/resource2'].methods['get'].responses[403].bodies['application/xml'].schema.value.should eq 'schema3'
617
+ subject.resources['/resource2'].methods['get'].responses[403].bodies.keys.should_not include 'plain/text'
618
+ end
619
+ end
620
+
621
+ context 'when parsing large specs' do
622
+ subject { Raml::Parser.parse( File.open("test/apis/#{api_file}").read ) }
623
+ context 'when parsing the Twitter API' do
624
+ let(:api_file) { 'twitter-rest-api.raml' }
625
+ it { expect { subject.expand }.to_not raise_error }
626
+ end
627
+ context 'when parsing the Stripe API' do
628
+ let(:api_file) { 'stripe-api.raml' }
629
+ it { expect { subject.expand }.to_not raise_error }
630
+ end
631
+ context 'when parsing the Twilio API' do
632
+ let(:api_file) { 'twilio-rest-api.raml' }
633
+ it { expect { subject.expand }.to_not raise_error }
634
+ end
635
+ context 'when parsing the Box API' do
636
+ let(:api_file) { 'box-api.raml' }
637
+ it { expect { subject.expand }.to_not raise_error }
638
+ end
639
+ context 'when parsing the Instagram API' do
640
+ let(:api_file) { 'instagram-api.raml' }
641
+ it { expect { subject.expand }.to_not raise_error }
642
+ end
643
+ end
644
+ end
645
+
646
+ describe '#document' do
647
+ it 'returns a String' do
648
+ subject.document.should be_a String
649
+ end
650
+ it 'should render the template' do
651
+ mock(Slim::Template).new(/templates\/root.slim\z/, is_a(Hash)).mock!.render(is_a(Raml::Node)) { '' }
652
+ subject.document
653
+ end
654
+ end
655
+ end