roar-jsonapi 0.0.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.
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+
3
+ require 'test_helper'
4
+ require 'roar/json/json_api'
5
+ require 'json'
6
+ require 'jsonapi/representer'
7
+
8
+ class MemberNameTest < MiniTest::Spec
9
+ MemberName = Roar::JSON::JSONAPI::MemberName
10
+
11
+ # http://jsonapi.org/format/#document-member-names-reserved-characters
12
+ UNICODE_RESERVED_CHARACTERS = [
13
+ "\u002B",
14
+ "\u002C",
15
+ "\u002E",
16
+ "\u005B",
17
+ "\u005D",
18
+ "\u0021",
19
+ "\u0022",
20
+ "\u0023",
21
+ "\u0024",
22
+ "\u0025",
23
+ "\u0026",
24
+ "\u0027",
25
+ "\u0028",
26
+ "\u0029",
27
+ "\u002A",
28
+ "\u002F",
29
+ "\u003A",
30
+ "\u003B",
31
+ "\u003C",
32
+ "\u003D",
33
+ "\u003E",
34
+ "\u003F",
35
+ "\u0040",
36
+ "\u005C",
37
+ "\u005E",
38
+ "\u0060",
39
+ "\u007B",
40
+ "\u007C",
41
+ "\u007D",
42
+ "\u007E"
43
+ ].freeze
44
+
45
+ describe 'strict (default)' do
46
+ it 'permits alphanumeric ASCII characters, hyphens' do
47
+ MemberName.('99 Luftballons').must_equal '99luftballons'
48
+ MemberName.('Artist').must_equal 'artist'
49
+ MemberName.('Актер').must_equal ''
50
+ MemberName.('おまかせ').must_equal ''
51
+ MemberName.('auf-der-bühne').must_equal 'auf-der-bhne'
52
+ MemberName.('nouvelle_interprétation').must_equal 'nouvelle-interprtation'
53
+ end
54
+
55
+ it 'does not permit any reserved characters' do
56
+ MemberName.(UNICODE_RESERVED_CHARACTERS.join).must_equal ''
57
+ end
58
+
59
+ it 'hyphenates underscored words' do
60
+ MemberName.('playtime_report').must_equal 'playtime-report'
61
+ end
62
+ end
63
+
64
+ describe 'non-strict' do
65
+ it 'permits alphanumeric unicode characters, hyphens, underscores and spaces' do
66
+ MemberName.('99 Luftballons', strict: false).must_equal '99 Luftballons'
67
+ MemberName.('Artist', strict: false).must_equal 'Artist'
68
+ MemberName.('Актер', strict: false).must_equal 'Актер'
69
+ MemberName.('おまかせ', strict: false).must_equal 'おまかせ'
70
+ MemberName.('auf-der-bühne', strict: false).must_equal 'auf-der-bühne'
71
+ MemberName.('nouvelle_interprétation', strict: false).must_equal 'nouvelle_interprétation'
72
+ end
73
+
74
+ it 'does not permit any reserved characters' do
75
+ MemberName.(UNICODE_RESERVED_CHARACTERS.join, strict: false).must_equal ''
76
+ end
77
+
78
+ it 'does not permit hyphens, underscores or spaces at beginning or end' do
79
+ MemberName.(' 99 Luftballons ', strict: false).must_equal '99 Luftballons'
80
+ MemberName.('-Artist_', strict: false).must_equal 'Artist'
81
+ MemberName.('_Актер', strict: false).must_equal 'Актер'
82
+ MemberName.(' おまかせ', strict: false).must_equal 'おまかせ'
83
+ MemberName.('-auf-der-bühne', strict: false).must_equal 'auf-der-bühne'
84
+ MemberName.('nouvelle_interprétation_', strict: false).must_equal 'nouvelle_interprétation'
85
+ end
86
+
87
+ it 'preserves underscored words' do
88
+ MemberName.('playtime_report', strict: false).must_equal 'playtime_report'
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,78 @@
1
+ require 'test_helper'
2
+ require 'roar/json/json_api'
3
+ require 'json'
4
+
5
+ class JsonapiPostTest < MiniTest::Spec
6
+ describe 'Parse' do
7
+ let(:post_article) {
8
+ %({
9
+ "data": {
10
+ "type": "articles",
11
+ "attributes": {
12
+ "title": "Ember Hamster"
13
+ },
14
+ "relationships": {
15
+ "author": {
16
+ "data": {
17
+ "type": "people",
18
+ "id": "9",
19
+ "name": "Celsito"
20
+ }
21
+ },
22
+ "comments": {
23
+ "data": [{
24
+ "type": "comment",
25
+ "id": "2"
26
+ }, {
27
+ "type": "comment",
28
+ "id": "3"
29
+ }]
30
+ }
31
+ }
32
+ }
33
+ })
34
+ }
35
+
36
+ subject { ArticleDecorator.new(Article.new(nil, nil, nil, nil, [])).from_json(post_article) }
37
+
38
+ it do
39
+ subject.title.must_equal 'Ember Hamster'
40
+ subject.author.id.must_equal '9'
41
+ subject.author.email.must_equal '9@nine.to'
42
+ # subject.author.name.must_be_nil
43
+
44
+ subject.comments.must_equal [Comment.new('2'), Comment.new('3')]
45
+ end
46
+ end
47
+
48
+ describe 'Parse Simple' do
49
+ let(:post_article) {
50
+ %({
51
+ "data": {
52
+ "type": "articles",
53
+ "attributes": {
54
+ "title": "Ember Hamster"
55
+ }
56
+ }
57
+ })
58
+ }
59
+
60
+ subject { ArticleDecorator.new(Article.new(nil, nil, nil, nil, [])).from_json(post_article) }
61
+
62
+ it do
63
+ subject.title.must_equal 'Ember Hamster'
64
+ end
65
+ end
66
+
67
+ describe 'Parse Badly Formed Document' do
68
+ let(:post_article) {
69
+ %({"title":"Ember Hamster"})
70
+ }
71
+
72
+ subject { ArticleDecorator.new(Article.new(nil, nil, nil, nil, [])).from_json(post_article) }
73
+
74
+ it do
75
+ subject.title.must_be_nil
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,281 @@
1
+ require 'test_helper'
2
+ require 'roar/json/json_api'
3
+ require 'json'
4
+
5
+ class JsonapiRenderTest < MiniTest::Spec
6
+ let(:article) { Article.new(1, 'Health walk', Author.new(2), Author.new('editor:1'), [Comment.new('comment:1', 'Ice and Snow'), Comment.new('comment:2', 'Red Stripe Skank')]) }
7
+ let(:decorator) { ArticleDecorator.new(article) }
8
+
9
+ it 'renders full document' do
10
+ json = decorator.to_json
11
+ json.must_equal_json(%({
12
+ "data": {
13
+ "id": "1",
14
+ "relationships": {
15
+ "author": {
16
+ "data": {
17
+ "id": "2",
18
+ "type": "authors"
19
+ },
20
+ "links": {
21
+ "self": "/articles/1/relationships/author",
22
+ "related": "/articles/1/author"
23
+ }
24
+ },
25
+ "editor": {
26
+ "data": {
27
+ "id": "editor:1",
28
+ "type": "editors"
29
+ },
30
+ "meta": {
31
+ "peer-reviewed": false
32
+ }
33
+ },
34
+ "comments": {
35
+ "data": [{
36
+ "id": "comment:1",
37
+ "type": "comments"
38
+ }, {
39
+ "id": "comment:2",
40
+ "type": "comments"
41
+ }],
42
+ "links": {
43
+ "self": "/articles/1/relationships/comments",
44
+ "related": "/articles/1/comments"
45
+ },
46
+ "meta": {
47
+ "comment-count": 5
48
+ }
49
+ }
50
+ },
51
+ "attributes": {
52
+ "title": "Health walk"
53
+ },
54
+ "type": "articles",
55
+ "links": {
56
+ "self": "http://Article/1"
57
+ }
58
+ },
59
+ "included": [{
60
+ "id": "2",
61
+ "type": "authors",
62
+ "links": {
63
+ "self": "http://authors/2"
64
+ }
65
+ }, {
66
+ "id": "editor:1",
67
+ "type": "editors"
68
+ }, {
69
+ "id": "comment:1",
70
+ "attributes": {
71
+ "body": "Ice and Snow"
72
+ },
73
+ "type": "comments",
74
+ "links": {
75
+ "self": "http://comments/comment:1"
76
+ }
77
+ }, {
78
+ "id": "comment:2",
79
+ "attributes": {
80
+ "body": "Red Stripe Skank"
81
+ },
82
+ "type": "comments",
83
+ "links": {
84
+ "self": "http://comments/comment:2"
85
+ }
86
+ }],
87
+ "meta": {
88
+ "reviewers": ["Christian Bernstein"],
89
+ "reviewer-initials": "C.B."
90
+ }
91
+ }))
92
+ end
93
+
94
+ it 'included: false suppresses compound docs' do
95
+ json = decorator.to_json(included: false)
96
+ json.must_equal_json(%({
97
+ "data": {
98
+ "id": "1",
99
+ "relationships": {
100
+ "author": {
101
+ "data": {
102
+ "id": "2",
103
+ "type": "authors"
104
+ },
105
+ "links": {
106
+ "self": "/articles/1/relationships/author",
107
+ "related": "/articles/1/author"
108
+ }
109
+ },
110
+ "editor": {
111
+ "data": {
112
+ "id": "editor:1",
113
+ "type": "editors"
114
+ },
115
+ "meta": {
116
+ "peer-reviewed": false
117
+ }
118
+ },
119
+ "comments": {
120
+ "data": [{
121
+ "id": "comment:1",
122
+ "type": "comments"
123
+ }, {
124
+ "id": "comment:2",
125
+ "type": "comments"
126
+ }],
127
+ "links": {
128
+ "self": "/articles/1/relationships/comments",
129
+ "related": "/articles/1/comments"
130
+ },
131
+ "meta": {
132
+ "comment-count": 5
133
+ }
134
+ }
135
+ },
136
+ "attributes": {
137
+ "title": "Health walk"
138
+ },
139
+ "type": "articles",
140
+ "links": {
141
+ "self": "http://Article/1"
142
+ }
143
+ },
144
+ "meta": {
145
+ "reviewers": ["Christian Bernstein"],
146
+ "reviewer-initials": "C.B."
147
+ }
148
+ }))
149
+ end
150
+
151
+ it 'renders additional meta information if meta option supplied' do
152
+ hash = decorator.to_hash(meta: {
153
+ 'copyright' => 'Nick Sutterer', 'reviewers' => []
154
+ })
155
+ hash['meta']['copyright'].must_equal('Nick Sutterer')
156
+ hash['meta']['reviewers'].must_equal([])
157
+ hash['meta']['reviewer-initials'].must_equal('C.B.')
158
+ end
159
+
160
+ it 'does not render additonal meta information if meta option is empty' do
161
+ hash = decorator.to_hash(meta: {})
162
+ hash['meta']['copyright'].must_be_nil
163
+ hash['meta']['reviewers'].must_equal(['Christian Bernstein'])
164
+ hash['meta']['reviewer-initials'].must_equal('C.B.')
165
+ end
166
+
167
+ describe 'Single Resource Object with simple attributes' do
168
+ class DocumentSingleResourceObjectDecorator < Roar::Decorator
169
+ include Roar::JSON::JSONAPI.resource :articles
170
+
171
+ attributes do
172
+ property :title
173
+ end
174
+ end
175
+
176
+ let(:document) {
177
+ %({
178
+ "data": {
179
+ "id": "1",
180
+ "attributes": {
181
+ "title": "My Article"
182
+ },
183
+ "type": "articles"
184
+ }
185
+ })
186
+ }
187
+
188
+ let(:collection_document) {
189
+ %({
190
+ "data": [
191
+ {
192
+ "type": "articles",
193
+ "id": "1",
194
+ "attributes": {
195
+ "title": "My Article"
196
+ }
197
+ }
198
+ ]
199
+ })
200
+ }
201
+
202
+ it { DocumentSingleResourceObjectDecorator.new(Article.new(1, 'My Article')).to_json.must_equal_json document }
203
+ it { DocumentSingleResourceObjectDecorator.for_collection.new([Article.new(1, 'My Article')]).to_json.must_equal_json collection_document }
204
+ end
205
+
206
+ describe 'Single Resource Object with complex attributes' do
207
+ class VisualArtistDecorator < Roar::Decorator
208
+ include Roar::JSON::JSONAPI.resource :visual_artists
209
+
210
+ attributes do
211
+ property :name
212
+ collection :known_aliases
213
+ property :movement
214
+ collection :noteable_works
215
+ end
216
+
217
+ link(:self) { "http://visual_artists/#{represented.id}" }
218
+ link(:wikipedia_page) { "https://en.wikipedia.org/wiki/#{represented.name}" }
219
+ end
220
+
221
+ Painter = Struct.new(:id, :name, :known_aliases, :movement, :noteable_works)
222
+
223
+ let(:document) {
224
+ %({
225
+ "data": {
226
+ "type": "visual-artists",
227
+ "id": "p1",
228
+ "attributes": {
229
+ "name": "Pablo Picasso",
230
+ "known-aliases": [
231
+ "Pablo Ruiz Picasso"
232
+ ],
233
+ "movement": "Cubism",
234
+ "noteable-works": [
235
+ "Kahnweiler",
236
+ "Guernica"
237
+ ]
238
+ },
239
+ "links": {
240
+ "self": "http://visual_artists/p1",
241
+ "wikipedia-page": "https://en.wikipedia.org/wiki/Pablo Picasso"
242
+ }
243
+ }
244
+ })
245
+ }
246
+
247
+ let(:collection_document) {
248
+ %({
249
+ "data": [
250
+ {
251
+ "type": "visual-artists",
252
+ "id": "p1",
253
+ "attributes": {
254
+ "name": "Pablo Picasso",
255
+ "known-aliases": [
256
+ "Pablo Ruiz Picasso"
257
+ ],
258
+ "movement": "Cubism",
259
+ "noteable-works": [
260
+ "Kahnweiler",
261
+ "Guernica"
262
+ ]
263
+ },
264
+ "links": {
265
+ "self": "http://visual_artists/p1",
266
+ "wikipedia-page": "https://en.wikipedia.org/wiki/Pablo Picasso"
267
+ }
268
+ }
269
+ ]
270
+ })
271
+ }
272
+
273
+ let(:painter) {
274
+ Painter.new('p1', 'Pablo Picasso', ['Pablo Ruiz Picasso'], 'Cubism',
275
+ %w(Kahnweiler Guernica))
276
+ }
277
+
278
+ it { VisualArtistDecorator.new(painter).to_json.must_equal_json document }
279
+ it { VisualArtistDecorator.for_collection.new([painter]).to_json.must_equal_json collection_document }
280
+ end
281
+ end