autoparse 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,904 @@
1
+ # Copyright 2010 Google Inc
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ spec_dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
17
+
18
+ require 'spec_helper'
19
+
20
+ require 'json'
21
+ require 'autoparse'
22
+ require 'addressable/uri'
23
+
24
+ describe AutoParse::Instance, 'with an empty schema' do
25
+ before do
26
+ @parser = AutoParse::EMPTY_SCHEMA
27
+ end
28
+
29
+ it 'should accept all inputs' do
30
+ instance = @parser.new({
31
+ "this" => "doesn't",
32
+ "really" => ["matter", "at", "all"],
33
+ "!" => 1.2345
34
+ })
35
+ instance.should be_valid
36
+ end
37
+
38
+ it 'should expose values via index methods' do
39
+ instance = @parser.new({
40
+ "this" => "doesn't",
41
+ "really" => ["matter", "at", "all"],
42
+ "!" => 1.2345
43
+ })
44
+ instance["this"].should == "doesn't"
45
+ instance["really"].should == ["matter", "at", "all"]
46
+ instance["!"].should == 1.2345
47
+ end
48
+
49
+ it 'should be coerceable to a Hash value' do
50
+ instance = @parser.new({
51
+ "this" => "doesn't",
52
+ "really" => ["matter", "at", "all"],
53
+ "!" => 1.2345
54
+ })
55
+ instance.to_hash.should == {
56
+ "this" => "doesn't",
57
+ "really" => ["matter", "at", "all"],
58
+ "!" => 1.2345
59
+ }
60
+ end
61
+
62
+ it 'should convert to a JSON string' do
63
+ instance = @parser.new({"be" => "brief"})
64
+ instance.to_json.should == '{"be":"brief"}'
65
+ end
66
+ end
67
+
68
+ describe AutoParse::Instance, 'with the geo schema' do
69
+ before do
70
+ @uri = Addressable::URI.new(
71
+ :scheme => 'file',
72
+ :host => '',
73
+ :path => File.expand_path(File.join(spec_dir, './data/geo.json'))
74
+ )
75
+ @schema_data = JSON.parse(File.open(@uri.path, 'r') { |f| f.read })
76
+ @parser = AutoParse.generate(@schema_data, @uri)
77
+ end
78
+
79
+ it 'should accept a valid geographic coordinate input' do
80
+ instance = @parser.new({
81
+ "latitude" => 37.422,
82
+ "longitude" => -122.084
83
+ })
84
+ instance.should be_valid
85
+ end
86
+
87
+ it 'should not accept an invalid geographic coordinate input' do
88
+ instance = @parser.new({
89
+ "latitude" => "not",
90
+ "longitude" => "valid"
91
+ })
92
+ instance.should_not be_valid
93
+ end
94
+
95
+ it 'should accept extra fields' do
96
+ instance = @parser.new({
97
+ "latitude" => 37.422,
98
+ "longitude" => -122.084,
99
+ "extra" => "bonus!"
100
+ })
101
+ instance.should be_valid
102
+ end
103
+
104
+ it 'should expose values via generated accessors' do
105
+ instance = @parser.new({
106
+ "latitude" => 37.422,
107
+ "longitude" => -122.084
108
+ })
109
+ instance.latitude.should == 37.422
110
+ instance.longitude.should == -122.084
111
+ end
112
+
113
+ it 'should be coerceable to a Hash value' do
114
+ instance = @parser.new({
115
+ "latitude" => 37.422,
116
+ "longitude" => -122.084
117
+ })
118
+ instance.to_hash.should == {
119
+ "latitude" => 37.422,
120
+ "longitude" => -122.084
121
+ }
122
+ end
123
+
124
+ it 'should convert to a JSON string' do
125
+ instance = @parser.new({
126
+ "latitude" => 37.422,
127
+ "longitude" => -122.084
128
+ })
129
+ instance.to_json.should == '{"latitude":37.422,"longitude":-122.084}'
130
+ end
131
+ end
132
+
133
+
134
+ describe AutoParse::Instance, 'with the address schema' do
135
+ before do
136
+ @uri = Addressable::URI.new(
137
+ :scheme => 'file',
138
+ :host => '',
139
+ :path => File.expand_path(File.join(spec_dir, './data/address.json'))
140
+ )
141
+ @schema_data = JSON.parse(File.open(@uri.path, 'r') { |f| f.read })
142
+ @parser = AutoParse.generate(@schema_data, @uri)
143
+ end
144
+
145
+ it 'should accept a valid address input' do
146
+ instance = @parser.new({
147
+ "post-office-box" => "PO Box 3.14159",
148
+ "street-address" => "1600 Amphitheatre Parkway",
149
+ "locality" => "Mountain View",
150
+ "region" => "CA",
151
+ "postal-code" => "94043",
152
+ "country-name" => "United States"
153
+ })
154
+ instance.should be_valid
155
+ end
156
+
157
+ it 'should accept extra fields' do
158
+ instance = @parser.new({
159
+ "post-office-box" => "PO Box 3.14159",
160
+ "street-address" => "1600 Amphitheatre Parkway",
161
+ "locality" => "Mountain View",
162
+ "region" => "CA",
163
+ "postal-code" => "94043",
164
+ "country-name" => "United States",
165
+ "extra" => "bonus!"
166
+ })
167
+ instance.should be_valid
168
+ end
169
+
170
+ it 'should accept a minimally valid address input' do
171
+ instance = @parser.new({
172
+ "locality" => "Mountain View",
173
+ "region" => "CA",
174
+ "country-name" => "United States"
175
+ })
176
+ instance.should be_valid
177
+ end
178
+
179
+ it 'should not accept an address with unmet dependencies' do
180
+ instance = @parser.new({
181
+ "post-office-box" => "PO Box 3.14159",
182
+ "extended-address" => "Apt 2.71828",
183
+ "locality" => "Mountain View",
184
+ "region" => "CA",
185
+ "country-name" => "United States"
186
+ })
187
+ instance.should_not be_valid
188
+ end
189
+
190
+ it 'should expose values via generated accessors' do
191
+ instance = @parser.new({
192
+ "post-office-box" => "PO Box 3.14159",
193
+ "street-address" => "1600 Amphitheatre Parkway",
194
+ "locality" => "Mountain View",
195
+ "region" => "CA",
196
+ "postal-code" => "94043",
197
+ "country-name" => "United States"
198
+ })
199
+ instance.post_office_box.should == "PO Box 3.14159"
200
+ instance.street_address.should == "1600 Amphitheatre Parkway"
201
+ instance.locality.should == "Mountain View"
202
+ instance.region.should == "CA"
203
+ instance.postal_code.should == "94043"
204
+ instance.country_name.should == "United States"
205
+ end
206
+
207
+ it 'should be coerceable to a Hash value' do
208
+ instance = @parser.new({
209
+ "post-office-box" => "PO Box 3.14159",
210
+ "street-address" => "1600 Amphitheatre Parkway",
211
+ "locality" => "Mountain View",
212
+ "region" => "CA",
213
+ "postal-code" => "94043",
214
+ "country-name" => "United States"
215
+ })
216
+ instance.to_hash.should == {
217
+ "post-office-box" => "PO Box 3.14159",
218
+ "street-address" => "1600 Amphitheatre Parkway",
219
+ "locality" => "Mountain View",
220
+ "region" => "CA",
221
+ "postal-code" => "94043",
222
+ "country-name" => "United States"
223
+ }
224
+ end
225
+ end
226
+
227
+ describe AutoParse::Instance, 'with the person schema' do
228
+ before do
229
+ @uri = Addressable::URI.new(
230
+ :scheme => 'file',
231
+ :host => '',
232
+ :path => File.expand_path(File.join(spec_dir, './data/person.json'))
233
+ )
234
+ @schema_data = JSON.parse(File.open(@uri.path, 'r') { |f| f.read })
235
+ @parser = AutoParse.generate(@schema_data, @uri)
236
+ end
237
+
238
+ it 'should accept a valid person input' do
239
+ instance = @parser.new({
240
+ "name" => "Bob Aman",
241
+ "age" => 29
242
+ })
243
+ instance.should be_valid
244
+ end
245
+
246
+ it 'should accept extra fields' do
247
+ instance = @parser.new({
248
+ "name" => "Bob Aman",
249
+ "age" => 29,
250
+ "extra" => "bonus!"
251
+ })
252
+ instance.should be_valid
253
+ end
254
+
255
+ it 'should validate a person whose age is equal to the maximum' do
256
+ instance = @parser.new({
257
+ "name" => "Aged Outlier",
258
+ "age" => 125
259
+ })
260
+ instance.should be_valid
261
+ end
262
+
263
+ it 'should validate a young person' do
264
+ instance = @parser.new({
265
+ "name" => "Joe Teenager",
266
+ "age" => 15
267
+ })
268
+ instance.should be_valid
269
+ end
270
+
271
+ it 'should not accept an invalid person input' do
272
+ instance = @parser.new({
273
+ "name" => "Methuselah",
274
+ "age" => 969
275
+ })
276
+ instance.should_not be_valid
277
+ end
278
+
279
+ it 'should not accept ages which are not integers' do
280
+ instance = @parser.new({
281
+ "name" => "Bob Aman",
282
+ "age" => 29.7
283
+ })
284
+ instance.should_not be_valid
285
+ end
286
+
287
+ it 'should expose values via generated accessors' do
288
+ instance = @parser.new({
289
+ "name" => "Bob Aman",
290
+ "age" => 29
291
+ })
292
+ instance.name.should == "Bob Aman"
293
+ instance.age.should == 29
294
+ end
295
+
296
+ it 'should be coerceable to a Hash value' do
297
+ instance = @parser.new({
298
+ "name" => "Bob Aman",
299
+ "age" => 29
300
+ })
301
+ instance.to_hash.should == {
302
+ "name" => "Bob Aman",
303
+ "age" => 29
304
+ }
305
+ end
306
+
307
+ it 'should convert to a JSON string' do
308
+ instance = @parser.new({
309
+ "name" => "Bob Aman",
310
+ "age" => 29
311
+ })
312
+ instance.to_json.should == '{"name":"Bob Aman","age":29}'
313
+ end
314
+ end
315
+
316
+ describe AutoParse::Instance, 'with the adult schema' do
317
+ before do
318
+ @person_uri = Addressable::URI.new(
319
+ :scheme => 'file',
320
+ :host => '',
321
+ :path => File.expand_path(File.join(spec_dir, './data/person.json'))
322
+ )
323
+ @person_schema_data =
324
+ JSON.parse(File.open(@person_uri.path, 'r') { |f| f.read })
325
+ @person_parser = AutoParse.generate(@person_schema_data, @person_uri)
326
+
327
+ @adult_uri = Addressable::URI.new(
328
+ :scheme => 'file',
329
+ :host => '',
330
+ :path => File.expand_path(File.join(spec_dir, './data/adult.json'))
331
+ )
332
+ @adult_schema_data =
333
+ JSON.parse(File.open(@adult_uri.path, 'r') { |f| f.read })
334
+ @adult_parser = AutoParse.generate(@adult_schema_data, @adult_uri)
335
+ end
336
+
337
+ it 'should accept a valid person input' do
338
+ instance = @adult_parser.new({
339
+ "name" => "Bob Aman",
340
+ "age" => 29
341
+ })
342
+ instance.should be_valid
343
+ end
344
+
345
+ it 'should accept extra fields' do
346
+ instance = @adult_parser.new({
347
+ "name" => "Bob Aman",
348
+ "age" => 29,
349
+ "extra" => "bonus!"
350
+ })
351
+ instance.should be_valid
352
+ end
353
+
354
+ it 'should validate a person whose age is equal to the maximum' do
355
+ instance = @adult_parser.new({
356
+ "name" => "Aged Outlier",
357
+ "age" => 125
358
+ })
359
+ instance.should be_valid
360
+ end
361
+
362
+ it 'should not validate a young person' do
363
+ instance = @adult_parser.new({
364
+ "name" => "Joe Teenager",
365
+ "age" => 15
366
+ })
367
+ instance.should_not be_valid
368
+ end
369
+
370
+ it 'should not accept an invalid person input' do
371
+ instance = @adult_parser.new({
372
+ "name" => "Methuselah",
373
+ "age" => 969
374
+ })
375
+ instance.should_not be_valid
376
+ end
377
+
378
+ it 'should not accept ages which are not integers' do
379
+ instance = @adult_parser.new({
380
+ "name" => "Bob Aman",
381
+ "age" => 29.7
382
+ })
383
+ instance.should_not be_valid
384
+ end
385
+
386
+ it 'should expose values via generated accessors' do
387
+ instance = @adult_parser.new({
388
+ "name" => "Bob Aman",
389
+ "age" => 29
390
+ })
391
+ instance.name.should == "Bob Aman"
392
+ instance.age.should == 29
393
+ end
394
+
395
+ it 'should be coerceable to a Hash value' do
396
+ instance = @adult_parser.new({
397
+ "name" => "Bob Aman",
398
+ "age" => 29
399
+ })
400
+ instance.to_hash.should == {
401
+ "name" => "Bob Aman",
402
+ "age" => 29
403
+ }
404
+ end
405
+
406
+ it 'should convert to a JSON string' do
407
+ instance = @adult_parser.new({
408
+ "name" => "Bob Aman",
409
+ "age" => 29
410
+ })
411
+ instance.to_json.should == '{"name":"Bob Aman","age":29}'
412
+ end
413
+ end
414
+
415
+ describe AutoParse::Instance, 'with the positive schema' do
416
+ before do
417
+ @positive_uri = Addressable::URI.new(
418
+ :scheme => 'file',
419
+ :host => '',
420
+ :path => File.expand_path(File.join(spec_dir, './data/positive.json'))
421
+ )
422
+ @positive_schema_data =
423
+ JSON.parse(File.open(@positive_uri.path, 'r') { |f| f.read })
424
+ @positive_parser = AutoParse.generate(@positive_schema_data, @positive_uri)
425
+ end
426
+
427
+ it 'should not allow instantiation' do
428
+ (lambda do
429
+ instance = @positive_parser.new(-1000)
430
+ end).should raise_error(TypeError)
431
+ end
432
+
433
+ it 'should not allow instantiation, even for a valid positive integer' do
434
+ (lambda do
435
+ instance = @positive_parser.new(1000)
436
+ end).should raise_error(TypeError)
437
+ end
438
+ end
439
+
440
+ describe AutoParse::Instance, 'with the account schema' do
441
+ before do
442
+ @positive_uri = Addressable::URI.new(
443
+ :scheme => 'file',
444
+ :host => '',
445
+ :path => File.expand_path(File.join(spec_dir, './data/positive.json'))
446
+ )
447
+ @positive_schema_data =
448
+ JSON.parse(File.open(@positive_uri.path, 'r') { |f| f.read })
449
+ @positive_parser = AutoParse.generate(@positive_schema_data, @positive_uri)
450
+
451
+ @account_uri = Addressable::URI.new(
452
+ :scheme => 'file',
453
+ :host => '',
454
+ :path => File.expand_path(File.join(spec_dir, './data/account.json'))
455
+ )
456
+ @account_schema_data =
457
+ JSON.parse(File.open(@account_uri.path, 'r') { |f| f.read })
458
+ @account_parser = AutoParse.generate(@account_schema_data, @account_uri)
459
+ end
460
+
461
+ it 'should accept a valid account input' do
462
+ instance = @account_parser.new({
463
+ "accountNumber" => "12345",
464
+ "balance" => 1000
465
+ })
466
+ instance.should be_valid
467
+ end
468
+
469
+ it 'should accept extra fields' do
470
+ instance = @account_parser.new({
471
+ "accountNumber" => "12345",
472
+ "balance" => 1000,
473
+ "extra" => "bonus!"
474
+ })
475
+ instance.should be_valid
476
+ end
477
+
478
+ it 'should validate an account with a zero balance' do
479
+ instance = @account_parser.new({
480
+ "accountNumber" => "12345",
481
+ "balance" => 0
482
+ })
483
+ instance.should be_valid
484
+ end
485
+
486
+ it 'should not validate a negative account balance' do
487
+ instance = @account_parser.new({
488
+ "accountNumber" => "12345",
489
+ "balance" => -1000
490
+ })
491
+ instance.should_not be_valid
492
+ end
493
+
494
+ it 'should not accept an invalid account input' do
495
+ instance = @account_parser.new({
496
+ "accountNumber" => "12345",
497
+ "balance" => "bogus"
498
+ })
499
+ instance.should_not be_valid
500
+ end
501
+
502
+ it 'should expose values via generated accessors' do
503
+ instance = @account_parser.new({
504
+ "accountNumber" => "12345",
505
+ "balance" => 1000
506
+ })
507
+ instance.account_number.should == "12345"
508
+ instance.balance.should == 1000
509
+ end
510
+
511
+ it 'should be coerceable to a Hash value' do
512
+ instance = @account_parser.new({
513
+ "accountNumber" => "12345",
514
+ "balance" => 1000
515
+ })
516
+ instance.to_hash.should == {
517
+ "accountNumber" => "12345",
518
+ "balance" => 1000
519
+ }
520
+ end
521
+
522
+ it 'should convert to a JSON string' do
523
+ instance = @account_parser.new({
524
+ "accountNumber" => "12345",
525
+ "balance" => 1000
526
+ })
527
+ instance.to_json.should == '{"accountNumber":"12345","balance":1000}'
528
+ end
529
+ end
530
+
531
+ describe AutoParse::Instance, 'with the card schema' do
532
+ before do
533
+ @address_uri = Addressable::URI.new(
534
+ :scheme => 'file',
535
+ :host => '',
536
+ :path => File.expand_path(File.join(spec_dir, './data/address.json'))
537
+ )
538
+ @address_schema_data =
539
+ JSON.parse(File.open(@address_uri.path, 'r') { |f| f.read })
540
+ @address_parser = AutoParse.generate(@address_schema_data, @address_uri)
541
+
542
+ @geo_uri = Addressable::URI.new(
543
+ :scheme => 'file',
544
+ :host => '',
545
+ :path => File.expand_path(File.join(spec_dir, './data/geo.json'))
546
+ )
547
+ @geo_schema_data =
548
+ JSON.parse(File.open(@geo_uri.path, 'r') { |f| f.read })
549
+ @geo_parser = AutoParse.generate(@geo_schema_data, @geo_uri)
550
+
551
+ @card_uri = Addressable::URI.new(
552
+ :scheme => 'file',
553
+ :host => '',
554
+ :path => File.expand_path(File.join(spec_dir, './data/card.json'))
555
+ )
556
+ @card_schema_data =
557
+ JSON.parse(File.open(@card_uri.path, 'r') { |f| f.read })
558
+ @card_parser = AutoParse.generate(@card_schema_data, @card_uri)
559
+ end
560
+
561
+ it 'should accept a valid card input' do
562
+ instance = @card_parser.new({
563
+ "givenName" => "Robert",
564
+ "familyName" => "Aman"
565
+ })
566
+ instance.should be_valid
567
+ end
568
+
569
+ it 'should accept extra fields' do
570
+ instance = @card_parser.new({
571
+ "givenName" => "Robert",
572
+ "familyName" => "Aman",
573
+ "extra" => "bonus!"
574
+ })
575
+ instance.should be_valid
576
+ end
577
+
578
+ it 'should accept a more complete card input' do
579
+ instance = @card_parser.new({
580
+ "givenName" => "Robert",
581
+ "familyName" => "Aman",
582
+ "additionalName" => ["Danger"],
583
+ "nickname" => "Bob",
584
+ "url" => "https://plus.google.com/116452824309856782163",
585
+ "email" => {
586
+ "type" => "work",
587
+ "value" => "bobaman@google.com"
588
+ },
589
+ "tel" => {
590
+ "type" => "fake",
591
+ "value" => "867-5309"
592
+ },
593
+ "tz" => "+03:00",
594
+ "logo" =>
595
+ "https://secure.gravatar.com/avatar/56ee28134dd0776825445e3551979b14",
596
+ "org" => {
597
+ "organizationName" => "Google, Inc.",
598
+ "organizationUnit" => "Developer Relations"
599
+ }
600
+ })
601
+ instance.should be_valid
602
+ end
603
+
604
+ it 'should accept a card input with an externally referenced schema' do
605
+ instance = @card_parser.new({
606
+ "givenName" => "Robert",
607
+ "familyName" => "Aman",
608
+ "adr" => {
609
+ "locality" => "Lavington",
610
+ "region" => "Nairobi",
611
+ "country-name" => "Kenya"
612
+ },
613
+ "geo" => {
614
+ "latitude" => -1.290034,
615
+ "longitude" => 36.771584
616
+ }
617
+ })
618
+ instance.adr.should be_valid
619
+ instance.geo.should be_valid
620
+ instance.should be_valid
621
+ end
622
+
623
+ it 'should not validate a card input with invalid array values' do
624
+ instance = @card_parser.new({
625
+ "givenName" => "Robert",
626
+ "familyName" => "Aman",
627
+ "additionalName" => [3.14159]
628
+ })
629
+ instance.should_not be_valid
630
+ end
631
+
632
+ it 'should not validate a card input when external schema is invalid' do
633
+ instance = @card_parser.new({
634
+ "givenName" => "Robert",
635
+ "familyName" => "Aman",
636
+ "adr" => {
637
+ "extended-address" => "Apt 2.71828",
638
+ "locality" => "Lavington",
639
+ "region" => "Nairobi",
640
+ "country-name" => "Kenya"
641
+ },
642
+ "geo" => {
643
+ "latitude" => -1.290034,
644
+ "longitude" => 36.771584
645
+ }
646
+ })
647
+ instance.adr.should_not be_valid
648
+ instance.should_not be_valid
649
+ instance = @card_parser.new({
650
+ "givenName" => "Robert",
651
+ "familyName" => "Aman",
652
+ "adr" => {
653
+ "locality" => "Lavington",
654
+ "region" => "Nairobi",
655
+ "country-name" => "Kenya"
656
+ },
657
+ "geo" => {
658
+ "latitude" => "not",
659
+ "longitude" => "valid"
660
+ }
661
+ })
662
+ instance.geo.should_not be_valid
663
+ instance.should_not be_valid
664
+ end
665
+
666
+ it 'should expose values via generated accessors' do
667
+ instance = @card_parser.new({
668
+ "givenName" => "Robert",
669
+ "familyName" => "Aman",
670
+ "additionalName" => ["Danger"],
671
+ "nickname" => "Bob",
672
+ "url" => "https://plus.google.com/116452824309856782163",
673
+ "email" => {
674
+ "type" => "work",
675
+ "value" => "bobaman@google.com"
676
+ },
677
+ "tel" => {
678
+ "type" => "fake",
679
+ "value" => "867-5309"
680
+ },
681
+ "tz" => "+03:00",
682
+ "logo" =>
683
+ "https://secure.gravatar.com/avatar/56ee28134dd0776825445e3551979b14",
684
+ "org" => {
685
+ "organizationName" => "Google, Inc.",
686
+ "organizationUnit" => "Developer Relations"
687
+ }
688
+ })
689
+ instance.given_name.should == "Robert"
690
+ instance.family_name.should == "Aman"
691
+ instance.additional_name.should == ["Danger"]
692
+ instance.nickname.should == "Bob"
693
+ instance.url.should be_kind_of(Addressable::URI)
694
+ instance.url.should === "https://plus.google.com/116452824309856782163"
695
+ instance.email.type.should == "work"
696
+ instance.email.value.should == "bobaman@google.com"
697
+ instance.tel.type.should == "fake"
698
+ instance.tel.value.should == "867-5309"
699
+ instance.tz.should == "+03:00"
700
+ instance.logo.should ==
701
+ "https://secure.gravatar.com/avatar/56ee28134dd0776825445e3551979b14"
702
+ instance.org.organization_name.should == "Google, Inc."
703
+ instance.org.organization_unit.should == "Developer Relations"
704
+ end
705
+
706
+ it 'should be coerceable to a Hash value' do
707
+ instance = @card_parser.new({
708
+ "givenName" => "Robert",
709
+ "familyName" => "Aman",
710
+ "additionalName" => ["Danger"],
711
+ "nickname" => "Bob",
712
+ "url" => "https://plus.google.com/116452824309856782163",
713
+ "email" => {
714
+ "type" => "work",
715
+ "value" => "bobaman@google.com"
716
+ },
717
+ "tel" => {
718
+ "type" => "fake",
719
+ "value" => "867-5309"
720
+ },
721
+ "tz" => "+03:00",
722
+ "logo" =>
723
+ "https://secure.gravatar.com/avatar/56ee28134dd0776825445e3551979b14",
724
+ "org" => {
725
+ "organizationName" => "Google, Inc.",
726
+ "organizationUnit" => "Developer Relations"
727
+ }
728
+ })
729
+ instance.to_hash.should == {
730
+ "givenName" => "Robert",
731
+ "familyName" => "Aman",
732
+ "additionalName" => ["Danger"],
733
+ "nickname" => "Bob",
734
+ "url" => "https://plus.google.com/116452824309856782163",
735
+ "email" => {
736
+ "type" => "work",
737
+ "value" => "bobaman@google.com"
738
+ },
739
+ "tel" => {
740
+ "type" => "fake",
741
+ "value" => "867-5309"
742
+ },
743
+ "tz" => "+03:00",
744
+ "logo" =>
745
+ "https://secure.gravatar.com/avatar/56ee28134dd0776825445e3551979b14",
746
+ "org" => {
747
+ "organizationName" => "Google, Inc.",
748
+ "organizationUnit" => "Developer Relations"
749
+ }
750
+ }
751
+ end
752
+
753
+ it 'should convert to a JSON string' do
754
+ instance = @card_parser.new({
755
+ "givenName" => "Robert",
756
+ "familyName" => "Aman"
757
+ })
758
+ instance.to_json.should == '{"givenName":"Robert","familyName":"Aman"}'
759
+ end
760
+ end
761
+
762
+ describe AutoParse::Instance, 'with the calendar schema' do
763
+ before do
764
+ @geo_uri = Addressable::URI.new(
765
+ :scheme => 'file',
766
+ :host => '',
767
+ :path => File.expand_path(File.join(spec_dir, './data/geo.json'))
768
+ )
769
+ @geo_schema_data =
770
+ JSON.parse(File.open(@geo_uri.path, 'r') { |f| f.read })
771
+ @geo_parser = AutoParse.generate(@geo_schema_data, @geo_uri)
772
+
773
+ @calendar_uri = Addressable::URI.new(
774
+ :scheme => 'file',
775
+ :host => '',
776
+ :path => File.expand_path(File.join(spec_dir, './data/calendar.json'))
777
+ )
778
+ @calendar_schema_data =
779
+ JSON.parse(File.open(@calendar_uri.path, 'r') { |f| f.read })
780
+ @calendar_parser = AutoParse.generate(@calendar_schema_data, @calendar_uri)
781
+ end
782
+
783
+ it 'should accept a valid calendar input' do
784
+ instance = @calendar_parser.new({
785
+ "dtstart" => "1592-03-14T00:00:00Z",
786
+ "dtend" => "1592-03-14T23:59:59Z",
787
+ "summary" => "Pi Day",
788
+ "location" => "Googleplex",
789
+ "url" => "http://www.piday.org/",
790
+ "rrule" => "FREQ=YEARLY"
791
+ })
792
+ instance.should be_valid
793
+ end
794
+
795
+ it 'should accept extra fields' do
796
+ instance = @calendar_parser.new({
797
+ "dtstart" => "1592-03-14T00:00:00Z",
798
+ "dtend" => "1592-03-14T23:59:59Z",
799
+ "summary" => "Pi Day",
800
+ "location" => "Googleplex",
801
+ "url" => "http://www.piday.org/",
802
+ "rrule" => "FREQ=YEARLY",
803
+ "extra" => "bonus!"
804
+ })
805
+ instance.should be_valid
806
+ end
807
+
808
+ it 'should accept a calendar input with an externally referenced schema' do
809
+ instance = @calendar_parser.new({
810
+ "dtstart" => "1592-03-14T00:00:00Z",
811
+ "dtend" => "1592-03-14T23:59:59Z",
812
+ "summary" => "Pi Day",
813
+ "location" => "Googleplex",
814
+ "url" => "http://www.piday.org/",
815
+ "rrule" => "FREQ=YEARLY",
816
+ "geo" => {
817
+ "latitude" => 37.422,
818
+ "longitude" => -122.084
819
+ }
820
+ })
821
+ instance.geo.should be_valid
822
+ instance.should be_valid
823
+ end
824
+
825
+ it 'should not validate a calendar input when external schema is invalid' do
826
+ instance = @calendar_parser.new({
827
+ "dtstart" => "1592-03-14T00:00:00Z",
828
+ "dtend" => "1592-03-14T23:59:59Z",
829
+ "summary" => "Pi Day",
830
+ "location" => "Googleplex",
831
+ "url" => "http://www.piday.org/",
832
+ "rrule" => "FREQ=YEARLY",
833
+ "geo" => {
834
+ "latitude" => "not",
835
+ "longitude" => "valid"
836
+ }
837
+ })
838
+ instance.geo.should_not be_valid
839
+ instance.should_not be_valid
840
+ end
841
+
842
+ it 'should expose values via generated accessors' do
843
+ instance = @calendar_parser.new({
844
+ "dtstart" => "1592-03-14T00:00:00Z",
845
+ "dtend" => "1592-03-14T23:59:59Z",
846
+ "summary" => "Pi Day",
847
+ "location" => "Googleplex",
848
+ "url" => "http://www.piday.org/",
849
+ "rrule" => "FREQ=YEARLY",
850
+ "geo" => {
851
+ "latitude" => 37.422,
852
+ "longitude" => -122.084
853
+ }
854
+ })
855
+ instance.dtstart.should == Time.utc(1592, 3, 14)
856
+ instance.dtend.should == Time.utc(1592, 3, 14, 23, 59, 59)
857
+ instance.summary.should == "Pi Day"
858
+ instance.location.should == "Googleplex"
859
+ instance.url.should == Addressable::URI.parse("http://www.piday.org/")
860
+ instance.rrule.should == "FREQ=YEARLY"
861
+ instance.geo.latitude.should == 37.422
862
+ instance.geo.longitude.should == -122.084
863
+ end
864
+
865
+ it 'should be coerceable to a Hash value' do
866
+ instance = @calendar_parser.new({
867
+ "dtstart" => "1592-03-14T00:00:00Z",
868
+ "dtend" => "1592-03-14T23:59:59Z",
869
+ "summary" => "Pi Day",
870
+ "location" => "Googleplex",
871
+ "url" => "http://www.piday.org/",
872
+ "rrule" => "FREQ=YEARLY",
873
+ "geo" => {
874
+ "latitude" => 37.422,
875
+ "longitude" => -122.084
876
+ }
877
+ })
878
+ instance.to_hash.should == {
879
+ "dtstart" => "1592-03-14T00:00:00Z",
880
+ "dtend" => "1592-03-14T23:59:59Z",
881
+ "summary" => "Pi Day",
882
+ "location" => "Googleplex",
883
+ "url" => "http://www.piday.org/",
884
+ "rrule" => "FREQ=YEARLY",
885
+ "geo" => {
886
+ "latitude" => 37.422,
887
+ "longitude" => -122.084
888
+ }
889
+ }
890
+ end
891
+
892
+ it 'should convert to a JSON string' do
893
+ instance = @calendar_parser.new({
894
+ "dtstart" => "1592-03-14T00:00:00Z",
895
+ "dtend" => "1592-03-14T23:59:59Z",
896
+ "summary" => "Pi Day"
897
+ })
898
+ instance.to_json.should == (
899
+ '{"dtend":"1592-03-14T23:59:59Z",' +
900
+ '"dtstart":"1592-03-14T00:00:00Z",'+
901
+ '"summary":"Pi Day"}'
902
+ )
903
+ end
904
+ end