All files
[pithos-ms-client] / trunk / Libraries / Json40r2 / Source / Src / Newtonsoft.Json.Tests / JsonValidatingReaderTests.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using NUnit.Framework;
7 using System.Xml;
8 using System.Xml.Schema;
9 using Newtonsoft.Json.Schema;
10
11 namespace Newtonsoft.Json.Tests
12 {
13   public class JsonValidatingReaderTests : TestFixtureBase
14   {
15     [Test]
16     public void CheckInnerReader()
17     {
18       string json = "{'name':'James','hobbies':['pie','cake']}";
19       JsonReader reader = new JsonTextReader(new StringReader(json));
20
21       JsonValidatingReader validatingReader = new JsonValidatingReader(reader);
22       Assert.AreEqual(reader, validatingReader.Reader);
23     }
24
25     [Test]
26     public void ValidateTypes()
27     {
28       string schemaJson = @"{
29   ""description"":""A person"",
30   ""type"":""object"",
31   ""properties"":
32   {
33     ""name"":{""type"":""string""},
34     ""hobbies"":
35     {
36       ""type"":""array"",
37       ""items"": {""type"":""string""}
38     }
39   }
40 }";
41
42       string json = @"{'name':""James"",'hobbies':[""pie"",'cake']}";
43
44       Json.Schema.ValidationEventArgs validationEventArgs = null;
45
46       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
47       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
48       JsonSchema schema = JsonSchema.Parse(schemaJson);
49       reader.Schema = schema;
50       Assert.AreEqual(schema, reader.Schema);
51
52       Assert.AreEqual(0, reader.Depth);
53
54       Assert.IsTrue(reader.Read());
55       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
56
57       Assert.IsTrue(reader.Read());
58       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
59       Assert.AreEqual("name", reader.Value.ToString());
60
61       Assert.AreEqual(1, reader.Depth);
62
63       Assert.IsTrue(reader.Read());
64       Assert.AreEqual(JsonToken.String, reader.TokenType);
65       Assert.AreEqual("James", reader.Value.ToString());
66       Assert.AreEqual(typeof(string), reader.ValueType);
67       Assert.AreEqual('"', reader.QuoteChar);
68
69       Assert.IsTrue(reader.Read());
70       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
71       Assert.AreEqual("hobbies", reader.Value.ToString());
72       Assert.AreEqual('\'', reader.QuoteChar);
73
74       Assert.IsTrue(reader.Read());
75       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
76
77       Assert.IsTrue(reader.Read());
78       Assert.AreEqual(JsonToken.String, reader.TokenType);
79       Assert.AreEqual("pie", reader.Value.ToString());
80       Assert.AreEqual('"', reader.QuoteChar);
81
82       Assert.IsTrue(reader.Read());
83       Assert.AreEqual(JsonToken.String, reader.TokenType);
84       Assert.AreEqual("cake", reader.Value.ToString());
85
86       Assert.IsTrue(reader.Read());
87       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
88
89       Assert.IsTrue(reader.Read());
90       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
91
92       Assert.IsNull(validationEventArgs);
93     }
94
95     [Test]
96     public void ValidateUnrestrictedArray()
97     {
98       string schemaJson = @"{
99   ""type"":""array""
100 }";
101
102       string json = "['pie','cake',['nested1','nested2'],{'nestedproperty1':1.1,'nestedproperty2':[null]}]";
103
104       Json.Schema.ValidationEventArgs validationEventArgs = null;
105
106       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
107       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
108       reader.Schema = JsonSchema.Parse(schemaJson);
109
110       Assert.IsTrue(reader.Read());
111       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
112
113       Assert.IsTrue(reader.Read());
114       Assert.AreEqual(JsonToken.String, reader.TokenType);
115       Assert.AreEqual("pie", reader.Value.ToString());
116
117       Assert.IsTrue(reader.Read());
118       Assert.AreEqual(JsonToken.String, reader.TokenType);
119       Assert.AreEqual("cake", reader.Value.ToString());
120
121       Assert.IsTrue(reader.Read());
122       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
123
124       Assert.IsTrue(reader.Read());
125       Assert.AreEqual(JsonToken.String, reader.TokenType);
126       Assert.AreEqual("nested1", reader.Value.ToString());
127
128       Assert.IsTrue(reader.Read());
129       Assert.AreEqual(JsonToken.String, reader.TokenType);
130       Assert.AreEqual("nested2", reader.Value.ToString());
131
132       Assert.IsTrue(reader.Read());
133       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
134
135       Assert.IsTrue(reader.Read());
136       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
137
138       Assert.IsTrue(reader.Read());
139       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
140       Assert.AreEqual("nestedproperty1", reader.Value.ToString());
141
142       Assert.IsTrue(reader.Read());
143       Assert.AreEqual(JsonToken.Float, reader.TokenType);
144       Assert.AreEqual(1.1, reader.Value);
145
146       Assert.IsTrue(reader.Read());
147       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
148       Assert.AreEqual("nestedproperty2", reader.Value.ToString());
149
150       Assert.IsTrue(reader.Read());
151       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
152
153       Assert.IsTrue(reader.Read());
154       Assert.AreEqual(JsonToken.Null, reader.TokenType);
155
156       Assert.IsTrue(reader.Read());
157       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
158
159       Assert.IsTrue(reader.Read());
160       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
161
162       Assert.IsTrue(reader.Read());
163       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
164
165       Assert.IsNull(validationEventArgs);
166     }
167
168     [Test]
169     public void StringLessThanMinimumLength()
170     {
171       string schemaJson = @"{
172   ""type"":""string"",
173   ""minLength"":5,
174   ""maxLength"":50,
175 }";
176
177       string json = "'pie'";
178
179       Json.Schema.ValidationEventArgs validationEventArgs = null;
180
181       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
182       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
183       reader.Schema = JsonSchema.Parse(schemaJson);
184
185       Assert.IsTrue(reader.Read());
186       Assert.AreEqual(JsonToken.String, reader.TokenType);
187       Assert.AreEqual("String 'pie' is less than minimum length of 5. Line 1, position 5.", validationEventArgs.Message);
188
189       Assert.IsNotNull(validationEventArgs);
190     }
191
192     [Test]
193     public void StringGreaterThanMaximumLength()
194     {
195       string schemaJson = @"{
196   ""type"":""string"",
197   ""minLength"":5,
198   ""maxLength"":10
199 }";
200
201       string json = "'The quick brown fox jumps over the lazy dog.'";
202
203       Json.Schema.ValidationEventArgs validationEventArgs = null;
204
205       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
206       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
207       reader.Schema = JsonSchema.Parse(schemaJson);
208
209       Assert.IsTrue(reader.Read());
210       Assert.AreEqual(JsonToken.String, reader.TokenType);
211       Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' exceeds maximum length of 10. Line 1, position 46.", validationEventArgs.Message);
212
213       Assert.IsNotNull(validationEventArgs);
214     }
215
216     [Test]
217     public void StringIsNotInEnum()
218     {
219       string schemaJson = @"{
220   ""type"":""array"",
221   ""items"":{
222     ""type"":""string"",
223     ""enum"":[""one"",""two""]
224   },
225   ""maxItems"":3
226 }";
227
228       string json = "['one','two','THREE']";
229
230       Json.Schema.ValidationEventArgs validationEventArgs = null;
231
232       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
233       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
234       reader.Schema = JsonSchema.Parse(schemaJson);
235
236       Assert.IsTrue(reader.Read());
237       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
238
239       Assert.IsTrue(reader.Read());
240       Assert.AreEqual(JsonToken.String, reader.TokenType);
241
242       Assert.IsTrue(reader.Read());
243       Assert.AreEqual(JsonToken.String, reader.TokenType);
244       Assert.AreEqual(null, validationEventArgs);
245
246       Assert.IsTrue(reader.Read());
247       Assert.AreEqual(JsonToken.String, reader.TokenType);
248       Assert.AreEqual(@"Value ""THREE"" is not defined in enum. Line 1, position 20.", validationEventArgs.Message);
249
250       Assert.IsTrue(reader.Read());
251       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
252
253       Assert.IsNotNull(validationEventArgs);
254     }
255
256     [Test]
257     public void StringDoesNotMatchPattern()
258     {
259       string schemaJson = @"{
260   ""type"":""string"",
261   ""pattern"":""foo""
262 }";
263
264       string json = "'The quick brown fox jumps over the lazy dog.'";
265
266       Json.Schema.ValidationEventArgs validationEventArgs = null;
267
268       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
269       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
270       reader.Schema = JsonSchema.Parse(schemaJson);
271
272       Assert.IsTrue(reader.Read());
273       Assert.AreEqual(JsonToken.String, reader.TokenType);
274       Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' does not match regex pattern 'foo'. Line 1, position 46.", validationEventArgs.Message);
275
276       Assert.IsNotNull(validationEventArgs);
277     }
278
279     [Test]
280     public void IntegerGreaterThanMaximumValue()
281     {
282       string schemaJson = @"{
283   ""type"":""integer"",
284   ""maximum"":5
285 }";
286
287       string json = "10";
288
289       Json.Schema.ValidationEventArgs validationEventArgs = null;
290
291       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
292       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
293       reader.Schema = JsonSchema.Parse(schemaJson);
294
295       Assert.IsTrue(reader.Read());
296       Assert.AreEqual(JsonToken.Integer, reader.TokenType);
297       Assert.AreEqual("Integer 10 exceeds maximum value of 5. Line 1, position 2.", validationEventArgs.Message);
298
299       Assert.IsNotNull(validationEventArgs);
300     }
301
302     [Test]
303     [ExpectedException(typeof(JsonSchemaException), ExpectedMessage = "Integer 10 exceeds maximum value of 5. Line 1, position 2.")]
304     public void ThrowExceptionWhenNoValidationEventHandler()
305     {
306       string schemaJson = @"{
307   ""type"":""integer"",
308   ""maximum"":5
309 }";
310
311       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader("10")));
312       reader.Schema = JsonSchema.Parse(schemaJson);
313
314       Assert.IsTrue(reader.Read());
315     }
316
317     [Test]
318     public void IntegerLessThanMinimumValue()
319     {
320       string schemaJson = @"{
321   ""type"":""integer"",
322   ""minimum"":5
323 }";
324
325       string json = "1";
326
327       Json.Schema.ValidationEventArgs validationEventArgs = null;
328
329       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
330       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
331       reader.Schema = JsonSchema.Parse(schemaJson);
332
333       Assert.IsTrue(reader.Read());
334       Assert.AreEqual(JsonToken.Integer, reader.TokenType);
335       Assert.AreEqual("Integer 1 is less than minimum value of 5. Line 1, position 1.", validationEventArgs.Message);
336
337       Assert.IsNotNull(validationEventArgs);
338     }
339
340     [Test]
341     public void IntegerIsNotInEnum()
342     {
343       string schemaJson = @"{
344   ""type"":""array"",
345   ""items"":{
346     ""type"":""integer"",
347     ""enum"":[1,2]
348   },
349   ""maxItems"":3
350 }";
351
352       string json = "[1,2,3]";
353
354       Json.Schema.ValidationEventArgs validationEventArgs = null;
355
356       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
357       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
358       reader.Schema = JsonSchema.Parse(schemaJson);
359
360       Assert.IsTrue(reader.Read());
361       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
362
363       Assert.IsTrue(reader.Read());
364       Assert.AreEqual(JsonToken.Integer, reader.TokenType);
365
366       Assert.IsTrue(reader.Read());
367       Assert.AreEqual(JsonToken.Integer, reader.TokenType);
368       Assert.AreEqual(null, validationEventArgs);
369
370       Assert.IsTrue(reader.Read());
371       Assert.AreEqual(JsonToken.Integer, reader.TokenType);
372       Assert.AreEqual(@"Value 3 is not defined in enum. Line 1, position 7.", validationEventArgs.Message);
373
374       Assert.IsTrue(reader.Read());
375       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
376
377       Assert.IsNotNull(validationEventArgs);
378     }
379
380     [Test]
381     public void FloatGreaterThanMaximumValue()
382     {
383       string schemaJson = @"{
384   ""type"":""number"",
385   ""maximum"":5
386 }";
387
388       string json = "10.0";
389
390       Json.Schema.ValidationEventArgs validationEventArgs = null;
391
392       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
393       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
394       reader.Schema = JsonSchema.Parse(schemaJson);
395
396       Assert.IsTrue(reader.Read());
397       Assert.AreEqual(JsonToken.Float, reader.TokenType);
398       Assert.AreEqual("Float 10.0 exceeds maximum value of 5. Line 1, position 4.", validationEventArgs.Message);
399
400       Assert.IsNotNull(validationEventArgs);
401     }
402
403     [Test]
404     public void FloatLessThanMinimumValue()
405     {
406       string schemaJson = @"{
407   ""type"":""number"",
408   ""minimum"":5
409 }";
410
411       string json = "1.1";
412
413       Json.Schema.ValidationEventArgs validationEventArgs = null;
414
415       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
416       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
417       reader.Schema = JsonSchema.Parse(schemaJson);
418
419       Assert.IsTrue(reader.Read());
420       Assert.AreEqual(JsonToken.Float, reader.TokenType);
421       Assert.AreEqual("Float 1.1 is less than minimum value of 5. Line 1, position 3.", validationEventArgs.Message);
422
423       Assert.IsNotNull(validationEventArgs);
424     }
425
426     [Test]
427     public void FloatIsNotInEnum()
428     {
429       string schemaJson = @"{
430   ""type"":""array"",
431   ""items"":{
432     ""type"":""number"",
433     ""enum"":[1.1,2.2]
434   },
435   ""maxItems"":3
436 }";
437
438       string json = "[1.1,2.2,3.0]";
439
440       Json.Schema.ValidationEventArgs validationEventArgs = null;
441
442       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
443       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
444       reader.Schema = JsonSchema.Parse(schemaJson);
445
446       Assert.IsTrue(reader.Read());
447       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
448
449       Assert.IsTrue(reader.Read());
450       Assert.AreEqual(JsonToken.Float, reader.TokenType);
451
452       Assert.IsTrue(reader.Read());
453       Assert.AreEqual(JsonToken.Float, reader.TokenType);
454       Assert.AreEqual(null, validationEventArgs);
455
456       Assert.IsTrue(reader.Read());
457       Assert.AreEqual(JsonToken.Float, reader.TokenType);
458       Assert.AreEqual(@"Value 3.0 is not defined in enum. Line 1, position 13.", validationEventArgs.Message);
459
460       Assert.IsTrue(reader.Read());
461       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
462
463       Assert.IsNotNull(validationEventArgs);
464     }
465
466     [Test]
467     public void FloatExceedsMaxDecimalPlaces()
468     {
469       string schemaJson = @"{
470   ""type"":""array"",
471   ""items"":{
472     ""type"":""number"",
473     ""divisibleBy"":0.1
474   }
475 }";
476
477       string json = "[1.1,2.2,4.001]";
478
479       Json.Schema.ValidationEventArgs validationEventArgs = null;
480
481       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
482       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
483       reader.Schema = JsonSchema.Parse(schemaJson);
484
485       Assert.IsTrue(reader.Read());
486       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
487
488       Assert.IsTrue(reader.Read());
489       Assert.AreEqual(JsonToken.Float, reader.TokenType);
490
491       Assert.IsTrue(reader.Read());
492       Assert.AreEqual(JsonToken.Float, reader.TokenType);
493       Assert.AreEqual(null, validationEventArgs);
494
495       Assert.IsTrue(reader.Read());
496       Assert.AreEqual(JsonToken.Float, reader.TokenType);
497       Assert.AreEqual(@"Float 4.001 is not evenly divisible by 0.1. Line 1, position 15.", validationEventArgs.Message);
498
499       Assert.IsTrue(reader.Read());
500       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
501
502       Assert.IsNotNull(validationEventArgs);
503     }
504
505     [Test]
506     public void NullNotInEnum()
507     {
508       string schemaJson = @"{
509   ""type"":""array"",
510   ""items"":{
511     ""type"":""null"",
512     ""enum"":[]
513   },
514   ""maxItems"":3
515 }";
516
517       string json = "[null]";
518
519       Json.Schema.ValidationEventArgs validationEventArgs = null;
520
521       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
522       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
523       reader.Schema = JsonSchema.Parse(schemaJson);
524
525       Assert.IsTrue(reader.Read());
526       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
527
528       Assert.IsTrue(reader.Read());
529       Assert.AreEqual(JsonToken.Null, reader.TokenType);
530       Assert.AreEqual(@"Value null is not defined in enum. Line 1, position 5.", validationEventArgs.Message);
531
532       Assert.IsTrue(reader.Read());
533       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
534
535       Assert.IsNotNull(validationEventArgs);
536     }
537
538     [Test]
539     public void BooleanNotInEnum()
540     {
541       string schemaJson = @"{
542   ""type"":""array"",
543   ""items"":{
544     ""type"":""boolean"",
545     ""enum"":[true]
546   },
547   ""maxItems"":3
548 }";
549
550       string json = "[true,false]";
551
552       Json.Schema.ValidationEventArgs validationEventArgs = null;
553
554       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
555       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
556       reader.Schema = JsonSchema.Parse(schemaJson);
557
558       Assert.IsTrue(reader.Read());
559       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
560
561       Assert.IsTrue(reader.Read());
562       Assert.AreEqual(JsonToken.Boolean, reader.TokenType);
563       Assert.AreEqual(null, validationEventArgs);
564
565       Assert.IsTrue(reader.Read());
566       Assert.AreEqual(JsonToken.Boolean, reader.TokenType);
567       Assert.AreEqual(@"Value false is not defined in enum. Line 1, position 11.", validationEventArgs.Message);
568       
569       Assert.IsTrue(reader.Read());
570       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
571
572       Assert.IsNotNull(validationEventArgs);
573     }
574     
575     [Test]
576     public void ArrayCountGreaterThanMaximumItems()
577     {
578       string schemaJson = @"{
579   ""type"":""array"",
580   ""minItems"":2,
581   ""maxItems"":3
582 }";
583
584       string json = "[null,null,null,null]";
585
586       Json.Schema.ValidationEventArgs validationEventArgs = null;
587
588       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
589       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
590       reader.Schema = JsonSchema.Parse(schemaJson);
591
592       Assert.IsTrue(reader.Read());
593       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
594
595       Assert.IsTrue(reader.Read());
596       Assert.AreEqual(JsonToken.Null, reader.TokenType);
597       Assert.IsTrue(reader.Read());
598       Assert.AreEqual(JsonToken.Null, reader.TokenType);
599       Assert.IsTrue(reader.Read());
600       Assert.AreEqual(JsonToken.Null, reader.TokenType);
601       Assert.IsTrue(reader.Read());
602       Assert.AreEqual(JsonToken.Null, reader.TokenType);
603
604       Assert.IsTrue(reader.Read());
605       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
606       Assert.AreEqual("Array item count 4 exceeds maximum count of 3. Line 1, position 21.", validationEventArgs.Message);
607
608       Assert.IsNotNull(validationEventArgs);
609     }
610
611     [Test]
612     public void ArrayCountLessThanMinimumItems()
613     {
614       string schemaJson = @"{
615   ""type"":""array"",
616   ""minItems"":2,
617   ""maxItems"":3
618 }";
619
620       string json = "[null]";
621
622       Json.Schema.ValidationEventArgs validationEventArgs = null;
623
624       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
625       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
626       reader.Schema = JsonSchema.Parse(schemaJson);
627
628       Assert.IsTrue(reader.Read());
629       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
630
631       Assert.IsTrue(reader.Read());
632       Assert.AreEqual(JsonToken.Null, reader.TokenType);
633
634       Assert.IsTrue(reader.Read());
635       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
636       Assert.AreEqual("Array item count 1 is less than minimum count of 2. Line 1, position 6.", validationEventArgs.Message);
637
638       Assert.IsNotNull(validationEventArgs);
639     }
640
641     [Test]
642     public void InvalidDataType()
643     {
644       string schemaJson = @"{
645   ""type"":""string"",
646   ""minItems"":2,
647   ""maxItems"":3,
648   ""items"":{}
649 }";
650
651       string json = "[null,null,null,null]";
652
653       Json.Schema.ValidationEventArgs validationEventArgs = null;
654
655       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
656       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
657       reader.Schema = JsonSchema.Parse(schemaJson);
658
659       Assert.IsTrue(reader.Read());
660       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
661       Assert.AreEqual(@"Invalid type. Expected String but got Array. Line 1, position 1.", validationEventArgs.Message);
662
663       Assert.IsNotNull(validationEventArgs);
664     }
665
666     [Test]
667     public void StringDisallowed()
668     {
669       string schemaJson = @"{
670   ""type"":""array"",
671   ""items"":{
672     ""disallow"":[""number""]
673   },
674   ""maxItems"":3
675 }";
676
677       string json = "['pie',1.1]";
678
679       Json.Schema.ValidationEventArgs validationEventArgs = null;
680
681       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
682       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
683       reader.Schema = JsonSchema.Parse(schemaJson);
684
685       Assert.IsTrue(reader.Read());
686       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
687
688       Assert.IsTrue(reader.Read());
689       Assert.AreEqual(JsonToken.String, reader.TokenType);
690       Assert.AreEqual(null, validationEventArgs);
691
692       Assert.IsTrue(reader.Read());
693       Assert.AreEqual(JsonToken.Float, reader.TokenType);
694       Assert.AreEqual(@"Type Float is disallowed. Line 1, position 11.", validationEventArgs.Message);
695
696       Assert.IsTrue(reader.Read());
697       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
698
699       Assert.IsNotNull(validationEventArgs);
700     }
701
702     [Test]
703     public void MissingRequiredProperties()
704     {
705       string schemaJson = @"{
706   ""description"":""A person"",
707   ""type"":""object"",
708   ""properties"":
709   {
710     ""name"":{""type"":""string""},
711     ""hobbies"":{""type"":""string"",""required"":true},
712     ""age"":{""type"":""integer"",""required"":true}
713   }
714 }";
715
716       string json = "{'name':'James'}";
717
718       Json.Schema.ValidationEventArgs validationEventArgs = null;
719
720       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
721       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
722       reader.Schema = JsonSchema.Parse(schemaJson);
723
724       Assert.IsTrue(reader.Read());
725       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
726
727       Assert.IsTrue(reader.Read());
728       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
729       Assert.AreEqual("name", reader.Value.ToString());
730
731       Assert.IsTrue(reader.Read());
732       Assert.AreEqual(JsonToken.String, reader.TokenType);
733       Assert.AreEqual("James", reader.Value.ToString());
734       Assert.AreEqual(null, validationEventArgs);
735
736       Assert.IsTrue(reader.Read());
737       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
738       Assert.AreEqual("Required properties are missing from object: hobbies, age. Line 1, position 16.", validationEventArgs.Message);
739
740       Assert.IsNotNull(validationEventArgs);
741     }
742
743     [Test]
744     public void MissingNonRequiredProperties()
745     {
746       string schemaJson = @"{
747   ""description"":""A person"",
748   ""type"":""object"",
749   ""properties"":
750   {
751     ""name"":{""type"":""string"",""required"":true},
752     ""hobbies"":{""type"":""string"",""required"":false},
753     ""age"":{""type"":""integer""}
754   }
755 }";
756
757       string json = "{'name':'James'}";
758
759       Json.Schema.ValidationEventArgs validationEventArgs = null;
760
761       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
762       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
763       reader.Schema = JsonSchema.Parse(schemaJson);
764
765       Assert.IsTrue(reader.Read());
766       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
767
768       Assert.IsTrue(reader.Read());
769       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
770       Assert.AreEqual("name", reader.Value.ToString());
771
772       Assert.IsTrue(reader.Read());
773       Assert.AreEqual(JsonToken.String, reader.TokenType);
774       Assert.AreEqual("James", reader.Value.ToString());
775       Assert.IsNull(validationEventArgs);
776
777       Assert.IsTrue(reader.Read());
778       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
779
780       Assert.IsNull(validationEventArgs);
781     }
782
783     [Test]
784     public void DisableAdditionalProperties()
785     {
786       string schemaJson = @"{
787   ""description"":""A person"",
788   ""type"":""object"",
789   ""properties"":
790   {
791     ""name"":{""type"":""string""}
792   },
793   ""additionalProperties"":false
794 }";
795
796       string json = "{'name':'James','additionalProperty1':null,'additionalProperty2':null}";
797
798       Json.Schema.ValidationEventArgs validationEventArgs = null;
799
800       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
801       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
802       reader.Schema = JsonSchema.Parse(schemaJson);
803
804       Assert.IsTrue(reader.Read());
805       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
806
807       Assert.IsTrue(reader.Read());
808       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
809       Assert.AreEqual("name", reader.Value.ToString());
810
811       Assert.IsTrue(reader.Read());
812       Assert.AreEqual(JsonToken.String, reader.TokenType);
813       Assert.AreEqual("James", reader.Value.ToString());
814       Assert.AreEqual(null, validationEventArgs);
815
816       Assert.IsTrue(reader.Read());
817       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
818       Assert.AreEqual("additionalProperty1", reader.Value.ToString());
819
820       Assert.IsTrue(reader.Read());
821       Assert.AreEqual(JsonToken.Null, reader.TokenType);
822       Assert.AreEqual(null, reader.Value);
823       Assert.AreEqual("Property 'additionalProperty1' has not been defined and the schema does not allow additional properties. Line 1, position 38.", validationEventArgs.Message);
824
825       Assert.IsTrue(reader.Read());
826       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
827       Assert.AreEqual("additionalProperty2", reader.Value.ToString());
828
829       Assert.IsTrue(reader.Read());
830       Assert.AreEqual(JsonToken.Null, reader.TokenType);
831       Assert.AreEqual(null, reader.Value);
832       Assert.AreEqual("Property 'additionalProperty2' has not been defined and the schema does not allow additional properties. Line 1, position 65.", validationEventArgs.Message);
833
834       Assert.IsTrue(reader.Read());
835       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
836
837       Assert.IsNotNull(validationEventArgs);
838     }
839
840     [Test]
841     public void ExtendsStringGreaterThanMaximumLength()
842     {
843       string schemaJson = @"{
844   ""extends"":{
845     ""type"":""string"",
846     ""minLength"":5,
847     ""maxLength"":10
848   },
849   ""maxLength"":9
850 }";
851
852       List<string> errors = new List<string>();
853       string json = "'The quick brown fox jumps over the lazy dog.'";
854
855       Json.Schema.ValidationEventArgs validationEventArgs = null;
856
857       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
858       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; errors.Add(validationEventArgs.Message); };
859       reader.Schema = JsonSchema.Parse(schemaJson);
860
861       Assert.IsTrue(reader.Read());
862       Assert.AreEqual(JsonToken.String, reader.TokenType);
863       Assert.AreEqual(1, errors.Count);
864       Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' exceeds maximum length of 9. Line 1, position 46.", errors[0]);
865
866       Assert.IsNotNull(validationEventArgs);
867     }
868
869     private JsonSchema GetExtendedSchema()
870     {
871       string first = @"{
872   ""id"":""first"",
873   ""type"":""object"",
874   ""properties"":
875   {
876     ""firstproperty"":{""type"":""string"",""required"":true}
877   },
878   ""additionalProperties"":{}
879 }";
880
881       string second = @"{
882   ""id"":""second"",
883   ""type"":""object"",
884   ""extends"":{""$ref"":""first""},
885   ""properties"":
886   {
887     ""secondproperty"":{""type"":""string"",""required"":true}
888   },
889   ""additionalProperties"":false
890 }";
891
892       JsonSchemaResolver resolver = new JsonSchemaResolver();
893       JsonSchema firstSchema = JsonSchema.Parse(first, resolver);
894       JsonSchema secondSchema = JsonSchema.Parse(second, resolver);
895
896       return secondSchema;
897     }
898
899     [Test]
900     public void ExtendsDisallowAdditionProperties()
901     {
902       string json = "{'firstproperty':'blah','secondproperty':'blah2','additional':'blah3','additional2':'blah4'}";
903
904       Json.Schema.ValidationEventArgs validationEventArgs = null;
905
906       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
907       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
908       reader.Schema = GetExtendedSchema();
909
910       Assert.IsTrue(reader.Read());
911       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
912
913       Assert.IsTrue(reader.Read());
914       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
915       Assert.AreEqual("firstproperty", reader.Value.ToString());
916       Assert.AreEqual(null, validationEventArgs);
917
918       Assert.IsTrue(reader.Read());
919       Assert.AreEqual(JsonToken.String, reader.TokenType);
920       Assert.AreEqual("blah", reader.Value.ToString());
921       Assert.AreEqual(null, validationEventArgs);
922
923       Assert.IsTrue(reader.Read());
924       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
925       Assert.AreEqual("secondproperty", reader.Value.ToString());
926       Assert.AreEqual(null, validationEventArgs);
927
928       Assert.IsTrue(reader.Read());
929       Assert.AreEqual(JsonToken.String, reader.TokenType);
930       Assert.AreEqual("blah2", reader.Value.ToString());
931       Assert.AreEqual(null, validationEventArgs);
932
933       Assert.IsTrue(reader.Read());
934       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
935       Assert.AreEqual("additional", reader.Value.ToString());
936       Assert.AreEqual("Property 'additional' has not been defined and the schema does not allow additional properties. Line 1, position 62.", validationEventArgs.Message);
937
938       Assert.IsTrue(reader.Read());
939       Assert.AreEqual(JsonToken.String, reader.TokenType);
940       Assert.AreEqual("blah3", reader.Value.ToString());
941
942       Assert.IsTrue(reader.Read());
943       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
944       Assert.AreEqual("additional2", reader.Value.ToString());
945       Assert.AreEqual("Property 'additional2' has not been defined and the schema does not allow additional properties. Line 1, position 84.", validationEventArgs.Message);
946
947       Assert.IsTrue(reader.Read());
948       Assert.AreEqual(JsonToken.String, reader.TokenType);
949       Assert.AreEqual("blah4", reader.Value.ToString());
950
951       Assert.IsTrue(reader.Read());
952       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
953
954       Assert.IsFalse(reader.Read());
955     }
956
957     [Test]
958     public void ExtendsMissingRequiredProperties()
959     {
960       string json = "{}";
961
962       List<string> errors = new List<string>();
963
964       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
965       reader.ValidationEventHandler += (sender, args) => { errors.Add(args.Message); };
966       reader.Schema = GetExtendedSchema();
967
968       Assert.IsTrue(reader.Read());
969       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
970
971       Assert.IsTrue(reader.Read());
972       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
973
974       Assert.AreEqual(1, errors.Count);
975       Assert.AreEqual("Required properties are missing from object: secondproperty, firstproperty. Line 1, position 2.", errors[0]);
976     }
977
978     [Test]
979     public void NoAdditionalProperties()
980     {
981       string schemaJson = @"{
982   ""type"":""array"",
983   ""items"": [{""type"":""string""},{""type"":""integer""}],
984   ""additionalProperties"": false
985 }";
986
987       string json = @"[1, 'a', null]";
988
989       Json.Schema.ValidationEventArgs validationEventArgs = null;
990
991       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
992       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
993       reader.Schema = JsonSchema.Parse(schemaJson);
994
995       Assert.IsTrue(reader.Read());
996       Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
997
998       Assert.IsTrue(reader.Read());
999       Assert.AreEqual(JsonToken.Integer, reader.TokenType);
1000       Assert.AreEqual("Invalid type. Expected String but got Integer. Line 1, position 3.", validationEventArgs.Message);
1001
1002       Assert.IsTrue(reader.Read());
1003       Assert.AreEqual(JsonToken.String, reader.TokenType);
1004       Assert.AreEqual("Invalid type. Expected Integer but got String. Line 1, position 7.", validationEventArgs.Message);
1005
1006       Assert.IsTrue(reader.Read());
1007       Assert.AreEqual(JsonToken.Null, reader.TokenType);
1008       Assert.AreEqual("Index 3 has not been defined and the schema does not allow additional items. Line 1, position 13.", validationEventArgs.Message);
1009
1010       Assert.IsTrue(reader.Read());
1011       Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
1012
1013       Assert.IsFalse(reader.Read());
1014     }
1015
1016     [Test]
1017     public void PatternPropertiesNoAdditionalProperties()
1018     {
1019       string schemaJson = @"{
1020   ""type"":""object"",
1021   ""patternProperties"": {
1022      ""hi"": {""type"":""string""},
1023      ""ho"": {""type"":""string""}
1024   },
1025   ""additionalProperties"": false
1026 }";
1027
1028       string json = @"{
1029   ""hi"": ""A string!"",
1030   ""hide"": ""A string!"",
1031   ""ho"": 1,
1032   ""hey"": ""A string!""
1033 }";
1034
1035       Json.Schema.ValidationEventArgs validationEventArgs = null;
1036
1037       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
1038       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; };
1039       reader.Schema = JsonSchema.Parse(schemaJson);
1040
1041       Assert.IsTrue(reader.Read());
1042       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
1043
1044       Assert.IsTrue(reader.Read());
1045       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
1046       Assert.AreEqual(null, validationEventArgs);
1047
1048       Assert.IsTrue(reader.Read());
1049       Assert.AreEqual(JsonToken.String, reader.TokenType);
1050
1051       Assert.IsTrue(reader.Read());
1052       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
1053       Assert.AreEqual(null, validationEventArgs);
1054
1055       Assert.IsTrue(reader.Read());
1056       Assert.AreEqual(JsonToken.String, reader.TokenType);
1057
1058       Assert.IsTrue(reader.Read());
1059       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
1060       Assert.AreEqual(null, validationEventArgs);
1061
1062       Assert.IsTrue(reader.Read());
1063       Assert.AreEqual(JsonToken.Integer, reader.TokenType);
1064       Assert.AreEqual("Invalid type. Expected String but got Integer. Line 4, position 10.", validationEventArgs.Message);
1065
1066       Assert.IsTrue(reader.Read());
1067       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
1068       Assert.AreEqual("Property 'hey' has not been defined and the schema does not allow additional properties. Line 5, position 8.", validationEventArgs.Message);
1069
1070       Assert.IsTrue(reader.Read());
1071       Assert.AreEqual(JsonToken.String, reader.TokenType);
1072
1073       Assert.IsTrue(reader.Read());
1074       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
1075
1076       Assert.IsFalse(reader.Read());
1077     }
1078
1079     [Test]
1080     public void ExtendedComplex()
1081     {
1082       string first = @"{
1083   ""id"":""first"",
1084   ""type"":""object"",
1085   ""properties"":
1086   {
1087     ""firstproperty"":{""type"":""string""},
1088     ""secondproperty"":{""type"":""string"",""maxLength"":10},
1089     ""thirdproperty"":{
1090       ""type"":""object"",
1091       ""properties"":
1092       {
1093         ""thirdproperty_firstproperty"":{""type"":""string"",""maxLength"":10,""minLength"":7}
1094       }
1095     }
1096   },
1097   ""additionalProperties"":{}
1098 }";
1099
1100       string second = @"{
1101   ""id"":""second"",
1102   ""type"":""object"",
1103   ""extends"":{""$ref"":""first""},
1104   ""properties"":
1105   {
1106     ""secondproperty"":{""type"":""any""},
1107     ""thirdproperty"":{
1108       ""extends"":{
1109         ""properties"":
1110         {
1111           ""thirdproperty_firstproperty"":{""maxLength"":9,""minLength"":6,""pattern"":""hi2u""}
1112         },
1113         ""additionalProperties"":{""maxLength"":9,""minLength"":6,""enum"":[""one"",""two""]}
1114       },
1115       ""type"":""object"",
1116       ""properties"":
1117       {
1118         ""thirdproperty_firstproperty"":{""pattern"":""hi""}
1119       },
1120       ""additionalProperties"":{""type"":""string"",""enum"":[""two"",""three""]}
1121     },
1122     ""fourthproperty"":{""type"":""string""}
1123   },
1124   ""additionalProperties"":false
1125 }";
1126
1127       JsonSchemaResolver resolver = new JsonSchemaResolver();
1128       JsonSchema firstSchema = JsonSchema.Parse(first, resolver);
1129       JsonSchema secondSchema = JsonSchema.Parse(second, resolver);
1130
1131       JsonSchemaModelBuilder modelBuilder = new JsonSchemaModelBuilder();
1132
1133       string json = @"{
1134   'firstproperty':'blahblahblahblahblahblah',
1135   'secondproperty':'secasecasecasecaseca',
1136   'thirdproperty':{
1137     'thirdproperty_firstproperty':'aaa',
1138     'additional':'three'
1139   }
1140 }";
1141
1142       Json.Schema.ValidationEventArgs validationEventArgs = null;
1143       List<string> errors = new List<string>();
1144
1145       JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json)));
1146       reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; errors.Add(validationEventArgs.Message); };
1147       reader.Schema = secondSchema;
1148
1149       Assert.IsTrue(reader.Read());
1150       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
1151
1152       Assert.IsTrue(reader.Read());
1153       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
1154       Assert.AreEqual("firstproperty", reader.Value.ToString());
1155       Assert.AreEqual(null, validationEventArgs);
1156
1157       Assert.IsTrue(reader.Read());
1158       Assert.AreEqual(JsonToken.String, reader.TokenType);
1159       Assert.AreEqual("blahblahblahblahblahblah", reader.Value.ToString());
1160
1161       Assert.IsTrue(reader.Read());
1162       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
1163       Assert.AreEqual("secondproperty", reader.Value.ToString());
1164
1165       Assert.IsTrue(reader.Read());
1166       Assert.AreEqual(JsonToken.String, reader.TokenType);
1167       Assert.AreEqual("secasecasecasecaseca", reader.Value.ToString());
1168       Assert.AreEqual(1, errors.Count);
1169       Assert.AreEqual("String 'secasecasecasecaseca' exceeds maximum length of 10. Line 3, position 41.", errors[0]);
1170
1171       Assert.IsTrue(reader.Read());
1172       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
1173       Assert.AreEqual("thirdproperty", reader.Value.ToString());
1174       Assert.AreEqual(1, errors.Count);
1175
1176       Assert.IsTrue(reader.Read());
1177       Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
1178       Assert.AreEqual(1, errors.Count);
1179
1180       Assert.IsTrue(reader.Read());
1181       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
1182       Assert.AreEqual("thirdproperty_firstproperty", reader.Value.ToString());
1183       Assert.AreEqual(1, errors.Count);
1184
1185       Assert.IsTrue(reader.Read());
1186       Assert.AreEqual(JsonToken.String, reader.TokenType);
1187       Assert.AreEqual("aaa", reader.Value.ToString());
1188       Assert.AreEqual(4, errors.Count);
1189       Assert.AreEqual("String 'aaa' is less than minimum length of 7. Line 5, position 39.", errors[1]);
1190       Assert.AreEqual("String 'aaa' does not match regex pattern 'hi'. Line 5, position 39.", errors[2]);
1191       Assert.AreEqual("String 'aaa' does not match regex pattern 'hi2u'. Line 5, position 39.", errors[3]);
1192
1193       Assert.IsTrue(reader.Read());
1194       Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
1195       Assert.AreEqual("additional", reader.Value.ToString());
1196       Assert.AreEqual(4, errors.Count);
1197
1198       Assert.IsTrue(reader.Read());
1199       Assert.AreEqual(JsonToken.String, reader.TokenType);
1200       Assert.AreEqual("three", reader.Value.ToString());
1201       Assert.AreEqual(5, errors.Count);
1202       Assert.AreEqual("String 'three' is less than minimum length of 6. Line 6, position 24.", errors[4]);
1203       
1204       Assert.IsTrue(reader.Read());
1205       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
1206
1207       Assert.IsTrue(reader.Read());
1208       Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
1209
1210       Assert.IsFalse(reader.Read());
1211     }
1212   }
1213 }