raml_ruby 0.1.1

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 (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