All files
[pithos-ms-client] / trunk / Libraries / Json40r2 / Source / Src / Newtonsoft.Json.Tests / Schema / JsonSchemaGeneratorTests.cs
1 #region License
2 // Copyright (c) 2007 James Newton-King
3 //
4 // Permission is hereby granted, free of charge, to any person
5 // obtaining a copy of this software and associated documentation
6 // files (the "Software"), to deal in the Software without
7 // restriction, including without limitation the rights to use,
8 // copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following
11 // conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 // OTHER DEALINGS IN THE SOFTWARE.
24 #endregion
25
26 using System;
27 using System.Collections;
28 using System.Collections.Generic;
29 using System.Globalization;
30 using Newtonsoft.Json.Converters;
31 using Newtonsoft.Json.Serialization;
32 using Newtonsoft.Json.Tests.TestObjects;
33 using Newtonsoft.Json.Utilities;
34 using NUnit.Framework;
35 using Newtonsoft.Json.Schema;
36 using System.IO;
37 using System.Linq;
38 using Newtonsoft.Json.Linq;
39 using System.Text;
40 using Extensions=Newtonsoft.Json.Schema.Extensions;
41
42 namespace Newtonsoft.Json.Tests.Schema
43 {
44   public class JsonSchemaGeneratorTests : TestFixtureBase
45   {
46     [Test]
47     public void Generate_GenericDictionary()
48     {
49       JsonSchemaGenerator generator = new JsonSchemaGenerator();
50       JsonSchema schema = generator.Generate(typeof (Dictionary<string, List<string>>));
51
52       string json = schema.ToString();
53
54       Assert.AreEqual(@"{
55   ""type"": ""object"",
56   ""additionalProperties"": {
57     ""type"": [
58       ""array"",
59       ""null""
60     ],
61     ""items"": {
62       ""type"": [
63         ""string"",
64         ""null""
65       ]
66     }
67   }
68 }", json);
69
70       Dictionary<string, List<string>> value = new Dictionary<string, List<string>>
71                                                  {
72                                                    {"HasValue", new List<string>() { "first", "second", null }},
73                                                    {"NoValue", null}
74                                                  };
75
76       string valueJson = JsonConvert.SerializeObject(value, Formatting.Indented);
77       JObject o = JObject.Parse(valueJson);
78
79       Assert.IsTrue(o.IsValid(schema));
80     }
81
82 #if !PocketPC
83     [Test]
84     public void Generate_DefaultValueAttributeTestClass()
85     {
86       JsonSchemaGenerator generator = new JsonSchemaGenerator();
87       JsonSchema schema = generator.Generate(typeof(DefaultValueAttributeTestClass));
88
89       string json = schema.ToString();
90
91       Assert.AreEqual(@"{
92   ""description"": ""DefaultValueAttributeTestClass description!"",
93   ""type"": ""object"",
94   ""additionalProperties"": false,
95   ""properties"": {
96     ""TestField1"": {
97       ""required"": true,
98       ""type"": ""integer"",
99       ""default"": 21
100     },
101     ""TestProperty1"": {
102       ""required"": true,
103       ""type"": [
104         ""string"",
105         ""null""
106       ],
107       ""default"": ""TestProperty1Value""
108     }
109   }
110 }", json);
111     }
112 #endif
113
114     [Test]
115     public void Generate_Person()
116     {
117       JsonSchemaGenerator generator = new JsonSchemaGenerator();
118       JsonSchema schema = generator.Generate(typeof(Person));
119
120       string json = schema.ToString();
121
122       Assert.AreEqual(@"{
123   ""id"": ""Person"",
124   ""title"": ""Title!"",
125   ""description"": ""JsonObjectAttribute description!"",
126   ""type"": ""object"",
127   ""properties"": {
128     ""Name"": {
129       ""required"": true,
130       ""type"": [
131         ""string"",
132         ""null""
133       ]
134     },
135     ""BirthDate"": {
136       ""required"": true,
137       ""type"": ""string""
138     },
139     ""LastModified"": {
140       ""required"": true,
141       ""type"": ""string""
142     }
143   }
144 }", json);
145     }
146
147     [Test]
148     public void Generate_UserNullable()
149     {
150       JsonSchemaGenerator generator = new JsonSchemaGenerator();
151       JsonSchema schema = generator.Generate(typeof(UserNullable));
152
153       string json = schema.ToString();
154
155       Assert.AreEqual(@"{
156   ""type"": ""object"",
157   ""properties"": {
158     ""Id"": {
159       ""required"": true,
160       ""type"": ""string""
161     },
162     ""FName"": {
163       ""required"": true,
164       ""type"": [
165         ""string"",
166         ""null""
167       ]
168     },
169     ""LName"": {
170       ""required"": true,
171       ""type"": [
172         ""string"",
173         ""null""
174       ]
175     },
176     ""RoleId"": {
177       ""required"": true,
178       ""type"": ""integer""
179     },
180     ""NullableRoleId"": {
181       ""required"": true,
182       ""type"": [
183         ""integer"",
184         ""null""
185       ]
186     },
187     ""NullRoleId"": {
188       ""required"": true,
189       ""type"": [
190         ""integer"",
191         ""null""
192       ]
193     },
194     ""Active"": {
195       ""required"": true,
196       ""type"": [
197         ""boolean"",
198         ""null""
199       ]
200     }
201   }
202 }", json);
203     }
204
205     [Test]
206     public void Generate_RequiredMembersClass()
207     {
208       JsonSchemaGenerator generator = new JsonSchemaGenerator();
209       JsonSchema schema = generator.Generate(typeof(RequiredMembersClass));
210
211       Assert.AreEqual(JsonSchemaType.String, schema.Properties["FirstName"].Type);
212       Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Null, schema.Properties["MiddleName"].Type);
213       Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Null, schema.Properties["LastName"].Type);
214       Assert.AreEqual(JsonSchemaType.String, schema.Properties["BirthDate"].Type);
215     }
216
217     [Test]
218     public void Generate_Store()
219     {
220       JsonSchemaGenerator generator = new JsonSchemaGenerator();
221       JsonSchema schema = generator.Generate(typeof(Store));
222
223       Assert.AreEqual(11, schema.Properties.Count);
224
225       JsonSchema productArraySchema = schema.Properties["product"];
226       JsonSchema productSchema = productArraySchema.Items[0];
227
228       Assert.AreEqual(4, productSchema.Properties.Count);
229     }
230
231     [Test]
232     public void MissingSchemaIdHandlingTest()
233     {
234       JsonSchemaGenerator generator = new JsonSchemaGenerator();
235
236       JsonSchema schema = generator.Generate(typeof(Store));
237       Assert.AreEqual(null, schema.Id);
238
239       generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
240       schema = generator.Generate(typeof (Store));
241       Assert.AreEqual(typeof(Store).FullName, schema.Id);
242
243       generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseAssemblyQualifiedName;
244       schema = generator.Generate(typeof(Store));
245       Assert.AreEqual(typeof(Store).AssemblyQualifiedName, schema.Id);
246     }
247
248     [Test]
249     public void Generate_NumberFormatInfo()
250     {
251       JsonSchemaGenerator generator = new JsonSchemaGenerator();
252       JsonSchema schema = generator.Generate(typeof(NumberFormatInfo));
253
254       string json = schema.ToString();
255
256       Console.WriteLine(json);
257
258       //      Assert.AreEqual(@"{
259       //  ""type"": ""object"",
260       //  ""additionalProperties"": {
261       //    ""type"": ""array"",
262       //    ""items"": {
263       //      ""type"": ""string""
264       //    }
265       //  }
266       //}", json);
267     }
268
269     [Test]
270     [ExpectedException(typeof(Exception), ExpectedMessage = @"Unresolved circular reference for type 'Newtonsoft.Json.Tests.TestObjects.CircularReferenceClass'. Explicitly define an Id for the type using a JsonObject/JsonArray attribute or automatically generate a type Id using the UndefinedSchemaIdHandling property.")]
271     public void CircularReferenceError()
272     {
273       JsonSchemaGenerator generator = new JsonSchemaGenerator();
274       generator.Generate(typeof(CircularReferenceClass));
275     }
276
277     [Test]
278     public void CircularReferenceWithTypeNameId()
279     {
280       JsonSchemaGenerator generator = new JsonSchemaGenerator();
281       generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
282
283       JsonSchema schema = generator.Generate(typeof(CircularReferenceClass), true);
284
285       Assert.AreEqual(JsonSchemaType.String, schema.Properties["Name"].Type);
286       Assert.AreEqual(typeof(CircularReferenceClass).FullName, schema.Id);
287       Assert.AreEqual(JsonSchemaType.Object | JsonSchemaType.Null, schema.Properties["Child"].Type);
288       Assert.AreEqual(schema, schema.Properties["Child"]);
289     }
290
291     [Test]
292     public void CircularReferenceWithExplicitId()
293     {
294       JsonSchemaGenerator generator = new JsonSchemaGenerator();
295
296       JsonSchema schema = generator.Generate(typeof(CircularReferenceWithIdClass));
297
298       Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Null, schema.Properties["Name"].Type);
299       Assert.AreEqual("MyExplicitId", schema.Id);
300       Assert.AreEqual(JsonSchemaType.Object | JsonSchemaType.Null, schema.Properties["Child"].Type);
301       Assert.AreEqual(schema, schema.Properties["Child"]);
302     }
303
304     [Test]
305     public void GenerateSchemaForType()
306     {
307       JsonSchemaGenerator generator = new JsonSchemaGenerator();
308       generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
309
310       JsonSchema schema = generator.Generate(typeof(Type));
311
312       Assert.AreEqual(JsonSchemaType.String, schema.Type);
313
314       string json = JsonConvert.SerializeObject(typeof(Version), Formatting.Indented);
315
316       JValue v = new JValue(json);
317       Assert.IsTrue(v.IsValid(schema));
318     }
319
320 #if !SILVERLIGHT && !PocketPC
321     [Test]
322     public void GenerateSchemaForISerializable()
323     {
324       JsonSchemaGenerator generator = new JsonSchemaGenerator();
325       generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
326
327       JsonSchema schema = generator.Generate(typeof(Exception));
328
329       Assert.AreEqual(JsonSchemaType.Object, schema.Type);
330       Assert.AreEqual(true, schema.AllowAdditionalProperties);
331       Assert.AreEqual(null, schema.Properties);
332     }
333 #endif
334
335     [Test]
336     public void GenerateSchemaForDBNull()
337     {
338       JsonSchemaGenerator generator = new JsonSchemaGenerator();
339       generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
340
341       JsonSchema schema = generator.Generate(typeof(DBNull));
342
343       Assert.AreEqual(JsonSchemaType.Null, schema.Type);
344     }
345
346     public class CustomDirectoryInfoMapper : DefaultContractResolver
347     {
348       public CustomDirectoryInfoMapper()
349         : base(true)
350       {
351       }
352
353       protected override JsonContract CreateContract(Type objectType)
354       {
355         if (objectType == typeof(DirectoryInfo))
356           return base.CreateObjectContract(objectType);
357
358         return base.CreateContract(objectType);
359       }
360
361       protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
362       {
363         IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
364
365         JsonPropertyCollection c = new JsonPropertyCollection(type);
366         CollectionUtils.AddRange(c, (IEnumerable)properties.Where(m => m.PropertyName != "Root"));
367
368         return c;
369       }
370     }
371
372     [Test]
373     public void GenerateSchemaForDirectoryInfo()
374     {
375       JsonSchemaGenerator generator = new JsonSchemaGenerator();
376       generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
377       generator.ContractResolver = new CustomDirectoryInfoMapper();
378
379       JsonSchema schema = generator.Generate(typeof(DirectoryInfo), true);
380
381       string json = schema.ToString();
382       
383       Assert.AreEqual(@"{
384   ""id"": ""System.IO.DirectoryInfo"",
385   ""required"": true,
386   ""type"": [
387     ""object"",
388     ""null""
389   ],
390   ""additionalProperties"": false,
391   ""properties"": {
392     ""Name"": {
393       ""required"": true,
394       ""type"": [
395         ""string"",
396         ""null""
397       ]
398     },
399     ""Parent"": {
400       ""$ref"": ""System.IO.DirectoryInfo""
401     },
402     ""Exists"": {
403       ""required"": true,
404       ""type"": ""boolean""
405     },
406     ""FullName"": {
407       ""required"": true,
408       ""type"": [
409         ""string"",
410         ""null""
411       ]
412     },
413     ""Extension"": {
414       ""required"": true,
415       ""type"": [
416         ""string"",
417         ""null""
418       ]
419     },
420     ""CreationTime"": {
421       ""required"": true,
422       ""type"": ""string""
423     },
424     ""CreationTimeUtc"": {
425       ""required"": true,
426       ""type"": ""string""
427     },
428     ""LastAccessTime"": {
429       ""required"": true,
430       ""type"": ""string""
431     },
432     ""LastAccessTimeUtc"": {
433       ""required"": true,
434       ""type"": ""string""
435     },
436     ""LastWriteTime"": {
437       ""required"": true,
438       ""type"": ""string""
439     },
440     ""LastWriteTimeUtc"": {
441       ""required"": true,
442       ""type"": ""string""
443     },
444     ""Attributes"": {
445       ""required"": true,
446       ""type"": ""integer""
447     }
448   }
449 }", json);
450
451       DirectoryInfo temp = new DirectoryInfo(@"c:\temp");
452
453       JTokenWriter jsonWriter = new JTokenWriter();
454       JsonSerializer serializer = new JsonSerializer();
455       serializer.Converters.Add(new IsoDateTimeConverter());
456       serializer.ContractResolver = new CustomDirectoryInfoMapper();
457       serializer.Serialize(jsonWriter, temp);
458
459       List<string> errors = new List<string>();
460       jsonWriter.Token.Validate(schema, (sender, args) => errors.Add(args.Message));
461
462       Assert.AreEqual(0, errors.Count);
463     }
464
465     [Test]
466     public void GenerateSchemaCamelCase()
467     {
468       JsonSchemaGenerator generator = new JsonSchemaGenerator();
469       generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
470       generator.ContractResolver = new CamelCasePropertyNamesContractResolver();
471
472       JsonSchema schema = generator.Generate(typeof (Version), true);
473
474       string json = schema.ToString();
475
476       Assert.AreEqual(@"{
477   ""id"": ""System.Version"",
478   ""type"": [
479     ""object"",
480     ""null""
481   ],
482   ""additionalProperties"": false,
483   ""properties"": {
484     ""major"": {
485       ""required"": true,
486       ""type"": ""integer""
487     },
488     ""minor"": {
489       ""required"": true,
490       ""type"": ""integer""
491     },
492     ""build"": {
493       ""required"": true,
494       ""type"": ""integer""
495     },
496     ""revision"": {
497       ""required"": true,
498       ""type"": ""integer""
499     },
500     ""majorRevision"": {
501       ""required"": true,
502       ""type"": ""integer""
503     },
504     ""minorRevision"": {
505       ""required"": true,
506       ""type"": ""integer""
507     }
508   }
509 }", json);
510     }
511
512     public enum SortTypeFlag
513     {
514       No = 0,
515       Asc = 1,
516       Desc = -1
517     }
518
519     public class X
520     {
521       public SortTypeFlag x;
522     }
523
524     [Test]
525     public void GenerateSchemaWithNegativeEnum()
526     {
527       JsonSchemaGenerator jsonSchemaGenerator = new JsonSchemaGenerator();
528       JsonSchema schema = jsonSchemaGenerator.Generate(typeof(X));
529
530       string json = schema.ToString();
531
532       Assert.AreEqual(@"{
533   ""type"": ""object"",
534   ""properties"": {
535     ""x"": {
536       ""required"": true,
537       ""type"": ""integer"",
538       ""enum"": [
539         0,
540         1,
541         -1
542       ],
543       ""options"": [
544         {
545           ""value"": 0,
546           ""label"": ""No""
547         },
548         {
549           ""value"": 1,
550           ""label"": ""Asc""
551         },
552         {
553           ""value"": -1,
554           ""label"": ""Desc""
555         }
556       ]
557     }
558   }
559 }", json);
560     }
561
562     [Test]
563     public void CircularCollectionReferences()
564     {
565       Type type = typeof (Workspace);
566       JsonSchemaGenerator jsonSchemaGenerator = new JsonSchemaGenerator();
567
568       jsonSchemaGenerator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
569       JsonSchema jsonSchema = jsonSchemaGenerator.Generate(type);
570
571       // should succeed
572       Assert.IsNotNull(jsonSchema);
573     }
574
575     [Test]
576     public void CircularReferenceWithMixedRequires()
577     {
578       JsonSchemaGenerator jsonSchemaGenerator = new JsonSchemaGenerator();
579
580       jsonSchemaGenerator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
581       JsonSchema jsonSchema = jsonSchemaGenerator.Generate(typeof(CircularReferenceClass));
582       string json = jsonSchema.ToString();
583
584       Assert.AreEqual(@"{
585   ""id"": ""Newtonsoft.Json.Tests.TestObjects.CircularReferenceClass"",
586   ""type"": [
587     ""object"",
588     ""null""
589   ],
590   ""properties"": {
591     ""Name"": {
592       ""required"": true,
593       ""type"": ""string""
594     },
595     ""Child"": {
596       ""$ref"": ""Newtonsoft.Json.Tests.TestObjects.CircularReferenceClass""
597     }
598   }
599 }", json);
600     }
601
602     [Test]
603     public void JsonPropertyWithHandlingValues()
604     {
605       JsonSchemaGenerator jsonSchemaGenerator = new JsonSchemaGenerator();
606
607       jsonSchemaGenerator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
608       JsonSchema jsonSchema = jsonSchemaGenerator.Generate(typeof(JsonPropertyWithHandlingValues));
609       string json = jsonSchema.ToString();
610
611       Assert.AreEqual(@"{
612   ""id"": ""Newtonsoft.Json.Tests.TestObjects.JsonPropertyWithHandlingValues"",
613   ""required"": true,
614   ""type"": [
615     ""object"",
616     ""null""
617   ],
618   ""properties"": {
619     ""DefaultValueHandlingIgnoreProperty"": {
620       ""type"": [
621         ""string"",
622         ""null""
623       ],
624       ""default"": ""Default!""
625     },
626     ""DefaultValueHandlingIncludeProperty"": {
627       ""required"": true,
628       ""type"": [
629         ""string"",
630         ""null""
631       ],
632       ""default"": ""Default!""
633     },
634     ""NullValueHandlingIgnoreProperty"": {
635       ""type"": [
636         ""string"",
637         ""null""
638       ]
639     },
640     ""NullValueHandlingIncludeProperty"": {
641       ""required"": true,
642       ""type"": [
643         ""string"",
644         ""null""
645       ]
646     },
647     ""ReferenceLoopHandlingErrorProperty"": {
648       ""$ref"": ""Newtonsoft.Json.Tests.TestObjects.JsonPropertyWithHandlingValues""
649     },
650     ""ReferenceLoopHandlingIgnoreProperty"": {
651       ""$ref"": ""Newtonsoft.Json.Tests.TestObjects.JsonPropertyWithHandlingValues""
652     },
653     ""ReferenceLoopHandlingSerializeProperty"": {
654       ""$ref"": ""Newtonsoft.Json.Tests.TestObjects.JsonPropertyWithHandlingValues""
655     }
656   }
657 }", json);
658     }
659   }
660
661   public class DMDSLBase
662   {
663     public String Comment;
664   }
665
666   public class Workspace : DMDSLBase
667   {
668     public ControlFlowItemCollection Jobs = new ControlFlowItemCollection();
669   }
670
671   public class ControlFlowItemBase : DMDSLBase
672   {
673     public String Name;
674   }
675
676   public class ControlFlowItem : ControlFlowItemBase//A Job
677   {
678     public TaskCollection Tasks = new TaskCollection();
679     public ContainerCollection Containers = new ContainerCollection();
680   }
681
682   public class ControlFlowItemCollection : List<ControlFlowItem>
683   {
684   }
685
686   public class Task : ControlFlowItemBase
687   {
688     public DataFlowTaskCollection DataFlowTasks = new DataFlowTaskCollection();
689     public BulkInsertTaskCollection BulkInsertTask = new BulkInsertTaskCollection();
690   }
691
692   public class TaskCollection : List<Task>
693   {
694   }
695
696   public class Container : ControlFlowItemBase
697   {
698     public ControlFlowItemCollection ContainerJobs = new ControlFlowItemCollection();
699   }
700
701   public class ContainerCollection : List<Container>
702   {
703   }
704
705   public class DataFlowTask_DSL : ControlFlowItemBase
706   {
707   }
708
709   public class DataFlowTaskCollection : List<DataFlowTask_DSL>
710   {
711   }
712
713   public class SequenceContainer_DSL : Container
714   {
715   }
716
717   public class BulkInsertTaskCollection : List<BulkInsertTask_DSL>
718   {
719   }
720
721   public class BulkInsertTask_DSL
722   {
723   }
724 }