2 // Copyright (c) 2007 James Newton-King
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
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
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.
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;
38 using Newtonsoft.Json.Linq;
40 using Extensions=Newtonsoft.Json.Schema.Extensions;
42 namespace Newtonsoft.Json.Tests.Schema
44 public class JsonSchemaGeneratorTests : TestFixtureBase
47 public void Generate_GenericDictionary()
49 JsonSchemaGenerator generator = new JsonSchemaGenerator();
50 JsonSchema schema = generator.Generate(typeof (Dictionary<string, List<string>>));
52 string json = schema.ToString();
56 ""additionalProperties"": {
70 Dictionary<string, List<string>> value = new Dictionary<string, List<string>>
72 {"HasValue", new List<string>() { "first", "second", null }},
76 string valueJson = JsonConvert.SerializeObject(value, Formatting.Indented);
77 JObject o = JObject.Parse(valueJson);
79 Assert.IsTrue(o.IsValid(schema));
84 public void Generate_DefaultValueAttributeTestClass()
86 JsonSchemaGenerator generator = new JsonSchemaGenerator();
87 JsonSchema schema = generator.Generate(typeof(DefaultValueAttributeTestClass));
89 string json = schema.ToString();
92 ""description"": ""DefaultValueAttributeTestClass description!"",
94 ""additionalProperties"": false,
98 ""type"": ""integer"",
107 ""default"": ""TestProperty1Value""
115 public void Generate_Person()
117 JsonSchemaGenerator generator = new JsonSchemaGenerator();
118 JsonSchema schema = generator.Generate(typeof(Person));
120 string json = schema.ToString();
124 ""title"": ""Title!"",
125 ""description"": ""JsonObjectAttribute description!"",
126 ""type"": ""object"",
148 public void Generate_UserNullable()
150 JsonSchemaGenerator generator = new JsonSchemaGenerator();
151 JsonSchema schema = generator.Generate(typeof(UserNullable));
153 string json = schema.ToString();
156 ""type"": ""object"",
178 ""type"": ""integer""
180 ""NullableRoleId"": {
206 public void Generate_RequiredMembersClass()
208 JsonSchemaGenerator generator = new JsonSchemaGenerator();
209 JsonSchema schema = generator.Generate(typeof(RequiredMembersClass));
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);
218 public void Generate_Store()
220 JsonSchemaGenerator generator = new JsonSchemaGenerator();
221 JsonSchema schema = generator.Generate(typeof(Store));
223 Assert.AreEqual(11, schema.Properties.Count);
225 JsonSchema productArraySchema = schema.Properties["product"];
226 JsonSchema productSchema = productArraySchema.Items[0];
228 Assert.AreEqual(4, productSchema.Properties.Count);
232 public void MissingSchemaIdHandlingTest()
234 JsonSchemaGenerator generator = new JsonSchemaGenerator();
236 JsonSchema schema = generator.Generate(typeof(Store));
237 Assert.AreEqual(null, schema.Id);
239 generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
240 schema = generator.Generate(typeof (Store));
241 Assert.AreEqual(typeof(Store).FullName, schema.Id);
243 generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseAssemblyQualifiedName;
244 schema = generator.Generate(typeof(Store));
245 Assert.AreEqual(typeof(Store).AssemblyQualifiedName, schema.Id);
249 public void Generate_NumberFormatInfo()
251 JsonSchemaGenerator generator = new JsonSchemaGenerator();
252 JsonSchema schema = generator.Generate(typeof(NumberFormatInfo));
254 string json = schema.ToString();
256 Console.WriteLine(json);
258 // Assert.AreEqual(@"{
259 // ""type"": ""object"",
260 // ""additionalProperties"": {
261 // ""type"": ""array"",
263 // ""type"": ""string""
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()
273 JsonSchemaGenerator generator = new JsonSchemaGenerator();
274 generator.Generate(typeof(CircularReferenceClass));
278 public void CircularReferenceWithTypeNameId()
280 JsonSchemaGenerator generator = new JsonSchemaGenerator();
281 generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
283 JsonSchema schema = generator.Generate(typeof(CircularReferenceClass), true);
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"]);
292 public void CircularReferenceWithExplicitId()
294 JsonSchemaGenerator generator = new JsonSchemaGenerator();
296 JsonSchema schema = generator.Generate(typeof(CircularReferenceWithIdClass));
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"]);
305 public void GenerateSchemaForType()
307 JsonSchemaGenerator generator = new JsonSchemaGenerator();
308 generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
310 JsonSchema schema = generator.Generate(typeof(Type));
312 Assert.AreEqual(JsonSchemaType.String, schema.Type);
314 string json = JsonConvert.SerializeObject(typeof(Version), Formatting.Indented);
316 JValue v = new JValue(json);
317 Assert.IsTrue(v.IsValid(schema));
320 #if !SILVERLIGHT && !PocketPC
322 public void GenerateSchemaForISerializable()
324 JsonSchemaGenerator generator = new JsonSchemaGenerator();
325 generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
327 JsonSchema schema = generator.Generate(typeof(Exception));
329 Assert.AreEqual(JsonSchemaType.Object, schema.Type);
330 Assert.AreEqual(true, schema.AllowAdditionalProperties);
331 Assert.AreEqual(null, schema.Properties);
336 public void GenerateSchemaForDBNull()
338 JsonSchemaGenerator generator = new JsonSchemaGenerator();
339 generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
341 JsonSchema schema = generator.Generate(typeof(DBNull));
343 Assert.AreEqual(JsonSchemaType.Null, schema.Type);
346 public class CustomDirectoryInfoMapper : DefaultContractResolver
348 public CustomDirectoryInfoMapper()
353 protected override JsonContract CreateContract(Type objectType)
355 if (objectType == typeof(DirectoryInfo))
356 return base.CreateObjectContract(objectType);
358 return base.CreateContract(objectType);
361 protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
363 IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
365 JsonPropertyCollection c = new JsonPropertyCollection(type);
366 CollectionUtils.AddRange(c, (IEnumerable)properties.Where(m => m.PropertyName != "Root"));
373 public void GenerateSchemaForDirectoryInfo()
375 JsonSchemaGenerator generator = new JsonSchemaGenerator();
376 generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
377 generator.ContractResolver = new CustomDirectoryInfoMapper();
379 JsonSchema schema = generator.Generate(typeof(DirectoryInfo), true);
381 string json = schema.ToString();
384 ""id"": ""System.IO.DirectoryInfo"",
390 ""additionalProperties"": false,
400 ""$ref"": ""System.IO.DirectoryInfo""
404 ""type"": ""boolean""
424 ""CreationTimeUtc"": {
428 ""LastAccessTime"": {
432 ""LastAccessTimeUtc"": {
440 ""LastWriteTimeUtc"": {
446 ""type"": ""integer""
451 DirectoryInfo temp = new DirectoryInfo(@"c:\temp");
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);
459 List<string> errors = new List<string>();
460 jsonWriter.Token.Validate(schema, (sender, args) => errors.Add(args.Message));
462 Assert.AreEqual(0, errors.Count);
466 public void GenerateSchemaCamelCase()
468 JsonSchemaGenerator generator = new JsonSchemaGenerator();
469 generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
470 generator.ContractResolver = new CamelCasePropertyNamesContractResolver();
472 JsonSchema schema = generator.Generate(typeof (Version), true);
474 string json = schema.ToString();
477 ""id"": ""System.Version"",
482 ""additionalProperties"": false,
486 ""type"": ""integer""
490 ""type"": ""integer""
494 ""type"": ""integer""
498 ""type"": ""integer""
502 ""type"": ""integer""
506 ""type"": ""integer""
512 public enum SortTypeFlag
521 public SortTypeFlag x;
525 public void GenerateSchemaWithNegativeEnum()
527 JsonSchemaGenerator jsonSchemaGenerator = new JsonSchemaGenerator();
528 JsonSchema schema = jsonSchemaGenerator.Generate(typeof(X));
530 string json = schema.ToString();
533 ""type"": ""object"",
537 ""type"": ""integer"",
563 public void CircularCollectionReferences()
565 Type type = typeof (Workspace);
566 JsonSchemaGenerator jsonSchemaGenerator = new JsonSchemaGenerator();
568 jsonSchemaGenerator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
569 JsonSchema jsonSchema = jsonSchemaGenerator.Generate(type);
572 Assert.IsNotNull(jsonSchema);
576 public void CircularReferenceWithMixedRequires()
578 JsonSchemaGenerator jsonSchemaGenerator = new JsonSchemaGenerator();
580 jsonSchemaGenerator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
581 JsonSchema jsonSchema = jsonSchemaGenerator.Generate(typeof(CircularReferenceClass));
582 string json = jsonSchema.ToString();
585 ""id"": ""Newtonsoft.Json.Tests.TestObjects.CircularReferenceClass"",
596 ""$ref"": ""Newtonsoft.Json.Tests.TestObjects.CircularReferenceClass""
603 public void JsonPropertyWithHandlingValues()
605 JsonSchemaGenerator jsonSchemaGenerator = new JsonSchemaGenerator();
607 jsonSchemaGenerator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
608 JsonSchema jsonSchema = jsonSchemaGenerator.Generate(typeof(JsonPropertyWithHandlingValues));
609 string json = jsonSchema.ToString();
612 ""id"": ""Newtonsoft.Json.Tests.TestObjects.JsonPropertyWithHandlingValues"",
619 ""DefaultValueHandlingIgnoreProperty"": {
624 ""default"": ""Default!""
626 ""DefaultValueHandlingIncludeProperty"": {
632 ""default"": ""Default!""
634 ""NullValueHandlingIgnoreProperty"": {
640 ""NullValueHandlingIncludeProperty"": {
647 ""ReferenceLoopHandlingErrorProperty"": {
648 ""$ref"": ""Newtonsoft.Json.Tests.TestObjects.JsonPropertyWithHandlingValues""
650 ""ReferenceLoopHandlingIgnoreProperty"": {
651 ""$ref"": ""Newtonsoft.Json.Tests.TestObjects.JsonPropertyWithHandlingValues""
653 ""ReferenceLoopHandlingSerializeProperty"": {
654 ""$ref"": ""Newtonsoft.Json.Tests.TestObjects.JsonPropertyWithHandlingValues""
661 public class DMDSLBase
663 public String Comment;
666 public class Workspace : DMDSLBase
668 public ControlFlowItemCollection Jobs = new ControlFlowItemCollection();
671 public class ControlFlowItemBase : DMDSLBase
676 public class ControlFlowItem : ControlFlowItemBase//A Job
678 public TaskCollection Tasks = new TaskCollection();
679 public ContainerCollection Containers = new ContainerCollection();
682 public class ControlFlowItemCollection : List<ControlFlowItem>
686 public class Task : ControlFlowItemBase
688 public DataFlowTaskCollection DataFlowTasks = new DataFlowTaskCollection();
689 public BulkInsertTaskCollection BulkInsertTask = new BulkInsertTaskCollection();
692 public class TaskCollection : List<Task>
696 public class Container : ControlFlowItemBase
698 public ControlFlowItemCollection ContainerJobs = new ControlFlowItemCollection();
701 public class ContainerCollection : List<Container>
705 public class DataFlowTask_DSL : ControlFlowItemBase
709 public class DataFlowTaskCollection : List<DataFlowTask_DSL>
713 public class SequenceContainer_DSL : Container
717 public class BulkInsertTaskCollection : List<BulkInsertTask_DSL>
721 public class BulkInsertTask_DSL