From 0319263756212f4a1875cda6534b9b8e1fb53188 Mon Sep 17 00:00:00 2001 From: JamesNK Date: Fri, 2 Jan 2009 05:29:31 +0000 Subject: [PATCH] -Added JSON Schema implementation -Move test serialization objects to TestObjects namespace -Fixed JsonConvert to always write a floating point number with a decimal place -Changed Type values to serialize and deserialize to type name string -Fixed JsonWriter to allow objects and arrays to be written in a constructor -Added JsonContainerAttribute with Id, Title and Description members. JsonObject and JsonArray inherit from this attribute -Added JsonArrayAttribute. Has flag to control whether array can contain null items. -Added IsRequired to JsonProperty -Replaced protected method GetSerializableMembers with GetMemberMappings on JsonSerializer -Fixed QuoteChar not getting set when parsing property name -Added Load(JsonReader) to JProperty, JConstructor -Fixed error when populating JProperty with content from collection -Added the ability for JsonTokenWriter to write individual values as well as arrays and objects -Added CreateReader to JToken -Added FromObject to JToken -Added ReadFrom to JToken --- Src/Doc/SerializingJSON.html | 3 + .../Converters/IsoDateTimeConverterTests.cs | 1 + .../JavaScriptDateTimeConverterTests.cs | 1 + Src/Newtonsoft.Json.Tests/JsonConvertTest.cs | 17 + .../JsonSerializerTest.cs | 546 +------- .../JsonTextReaderTest.cs | 76 ++ .../JsonTextWriterTest.cs | 56 + .../JsonTokenWriterTest.cs | 2 +- .../JsonValidatingReaderTests.cs | 1150 +++++++++++++++++ .../Linq/JConstructorTests.cs | 35 + .../Linq/JObjectTests.cs | 9 +- .../Linq/JPropertyTests.cs | 52 + Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs | 36 + .../Linq/LinqToJsonTest.cs | 5 +- .../Newtonsoft.Json.Tests.Compact.csproj | 60 +- .../Newtonsoft.Json.Tests.Silverlight.csproj | 60 +- .../Newtonsoft.Json.Tests.csproj | 52 +- Src/Newtonsoft.Json.Tests/PerformanceTests.cs | 2 +- .../Schema/ExtensionsTests.cs | 84 ++ .../Schema/JsonSchemaBuilderTests.cs | 436 +++++++ .../Schema/JsonSchemaGeneratorTests.cs | 265 ++++ .../Schema/JsonSchemaModelBuilderTests.cs | 166 +++ .../Schema/JsonSchemaNodeTests.cs | 118 ++ .../Schema/JsonSchemaTests.cs | 344 +++++ .../TestObjects/AbstractGenericBase.cs | 32 + ...gumentConverterPrecedenceClassConverter.cs | 35 + .../TestObjects/Article.cs | 41 + .../TestObjects/ArticleCollection.cs | 33 + .../TestObjects/BadJsonPropertyClass.cs | 35 + .../TestObjects/CircularReferenceClass.cs | 39 + .../CircularReferenceWithIdClass.cs | 40 + .../ClassAndMemberConverterClass.cs | 34 + .../ClassConverterPrecedenceClassConverter.cs | 35 + .../TestObjects/ClassWithArray.cs | 54 + .../TestObjects/ClassWithGuid.cs | 34 + .../ConstructorCaseSensitivityClass.cs | 41 + .../TestObjects/ConverableMembers.cs | 48 + .../TestObjects/ConverterPrecedenceClass.cs | 38 + .../ConverterPrecedenceClassConverter.cs | 63 + .../{ => TestObjects}/DateTimeTestClass.cs | 2 +- .../DefaultValueAttributeTestClass.cs | 41 + .../TestObjects/DoubleClass.cs | 32 + .../TestObjects/GenericImpl.cs | 32 + .../TestObjects/GetOnlyPropertyClass.cs | 37 + .../IncompatibleJsonAttributeClass.cs | 34 + .../TestObjects/Invoice.cs | 40 + .../JsonIgnoreAttributeOnClassTestClass.cs | 52 + .../JsonIgnoreAttributeTestClass.cs | 51 + .../TestObjects/MemberConverterClass.cs | 37 + ...MemberConverterPrecedenceClassConverter.cs | 35 + .../TestObjects/MethodExecutorObject.cs | 34 + .../TestObjects/MyClass.cs | 34 + Src/Newtonsoft.Json.Tests/TestObjects/Name.cs | 41 + .../TestObjects/Person.cs | 54 + .../TestObjects/PersonRaw.cs | 64 + .../TestObjects/PhoneNumber.cs | 37 + .../TestObjects/Product.cs | 54 + .../TestObjects/ProductCollection.cs | 33 + .../TestObjects/ProductShort.cs | 37 + .../TestObjects/RequiredMembersClass.cs | 47 + .../TestObjects/SetOnlyPropertyClass.cs | 37 + .../TestObjects/Store.cs | 62 + .../TestObjects/StoreColor.cs | 35 + .../TestObjects/TypeClass.cs | 34 + .../TestObjects/TypedSubHashtable.cs | 37 + .../TestObjects/UserNullable.cs | 40 + Src/Newtonsoft.Json/JsonArrayAttribute.cs | 72 ++ Src/Newtonsoft.Json/JsonContainerAttribute.cs | 59 + Src/Newtonsoft.Json/JsonConvert.cs | 14 +- Src/Newtonsoft.Json/JsonObjectAttribute.cs | 11 +- Src/Newtonsoft.Json/JsonPropertyAttribute.cs | 7 + Src/Newtonsoft.Json/JsonReader.cs | 18 +- Src/Newtonsoft.Json/JsonSerializer.cs | 157 +-- Src/Newtonsoft.Json/JsonTextReader.cs | 5 + Src/Newtonsoft.Json/JsonValidatingReader.cs | 535 ++++++++ Src/Newtonsoft.Json/JsonWriter.cs | 7 +- Src/Newtonsoft.Json/Linq/JArray.cs | 19 +- Src/Newtonsoft.Json/Linq/JConstructor.cs | 28 + Src/Newtonsoft.Json/Linq/JContainer.cs | 25 +- Src/Newtonsoft.Json/Linq/JObject.cs | 18 +- Src/Newtonsoft.Json/Linq/JProperty.cs | 48 +- Src/Newtonsoft.Json/Linq/JToken.cs | 63 +- Src/Newtonsoft.Json/Linq/JsonTokenReader.cs | 2 +- Src/Newtonsoft.Json/Linq/JsonTokenWriter.cs | 25 +- .../Newtonsoft.Json.Compact.csproj | 81 +- .../Newtonsoft.Json.Silverlight.csproj | 28 +- Src/Newtonsoft.Json/Newtonsoft.Json.csproj | 27 +- Src/Newtonsoft.Json/Schema/Extensions.cs | 66 + Src/Newtonsoft.Json/Schema/JsonSchema.cs | 134 ++ .../Schema/JsonSchemaBuilder.cs | 393 ++++++ .../Schema/JsonSchemaConstants.cs | 80 ++ .../Schema/JsonSchemaException.cs | 63 + .../Schema/JsonSchemaGenerator.cs | 334 +++++ Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs | 103 ++ .../Schema/JsonSchemaModelBuilder.cs | 159 +++ Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs | 70 + .../Schema/JsonSchemaNodeCollection.cs | 37 + .../Schema/JsonSchemaResolver.cs | 51 + Src/Newtonsoft.Json/Schema/JsonSchemaType.cs | 46 + .../Schema/JsonSchemaWriter.cs | 213 +++ .../Schema/UndefinedSchemaIdHandling.cs | 34 + .../Schema/ValidationEventArgs.cs | 51 + .../Schema/ValidationEventHandler.cs | 29 + .../JsonMemberMapping.cs} | 13 +- .../JsonMemberMappingCollection.cs} | 14 +- .../Serialization/JsonTypeReflector.cs | 153 +++ .../Utilities/CollectionUtils.cs | 67 +- Src/Newtonsoft.Json/Utilities/ConvertUtils.cs | 60 +- Src/Newtonsoft.Json/Utilities/EnumUtils.cs | 236 ++++ Src/Newtonsoft.Json/Utilities/EnumValue.cs | 53 + Src/Newtonsoft.Json/Utilities/EnumValues.cs | 41 + Src/Newtonsoft.Json/Utilities/MathUtils.cs | 57 + .../Utilities/ReflectionUtils.cs | 2 +- 113 files changed, 8321 insertions(+), 738 deletions(-) create mode 100644 Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Linq/JConstructorTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Linq/JPropertyTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Schema/ExtensionsTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Schema/JsonSchemaBuilderTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Schema/JsonSchemaModelBuilderTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Schema/JsonSchemaNodeTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Schema/JsonSchemaTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/AbstractGenericBase.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ArgumentConverterPrecedenceClassConverter.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/Article.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ArticleCollection.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/BadJsonPropertyClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/CircularReferenceClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/CircularReferenceWithIdClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ClassAndMemberConverterClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ClassConverterPrecedenceClassConverter.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ClassWithArray.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ClassWithGuid.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ConstructorCaseSensitivityClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ConverableMembers.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs rename Src/Newtonsoft.Json.Tests/{ => TestObjects}/DateTimeTestClass.cs (94%) create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/DefaultValueAttributeTestClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/DoubleClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/GenericImpl.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/GetOnlyPropertyClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/IncompatibleJsonAttributeClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/Invoice.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/JsonIgnoreAttributeOnClassTestClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/JsonIgnoreAttributeTestClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/MemberConverterClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/MemberConverterPrecedenceClassConverter.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/MethodExecutorObject.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/MyClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/Name.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/Person.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/PersonRaw.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/PhoneNumber.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/Product.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ProductCollection.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/ProductShort.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/RequiredMembersClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/SetOnlyPropertyClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/Store.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/StoreColor.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/TypeClass.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/TypedSubHashtable.cs create mode 100644 Src/Newtonsoft.Json.Tests/TestObjects/UserNullable.cs create mode 100644 Src/Newtonsoft.Json/JsonArrayAttribute.cs create mode 100644 Src/Newtonsoft.Json/JsonContainerAttribute.cs create mode 100644 Src/Newtonsoft.Json/JsonValidatingReader.cs create mode 100644 Src/Newtonsoft.Json/Schema/Extensions.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchema.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaException.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaNodeCollection.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaResolver.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaType.cs create mode 100644 Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs create mode 100644 Src/Newtonsoft.Json/Schema/UndefinedSchemaIdHandling.cs create mode 100644 Src/Newtonsoft.Json/Schema/ValidationEventArgs.cs create mode 100644 Src/Newtonsoft.Json/Schema/ValidationEventHandler.cs rename Src/Newtonsoft.Json/{MemberMapping.cs => Serialization/JsonMemberMapping.cs} (82%) rename Src/Newtonsoft.Json/{MemberMappingCollection.cs => Serialization/JsonMemberMappingCollection.cs} (80%) create mode 100644 Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs create mode 100644 Src/Newtonsoft.Json/Utilities/EnumUtils.cs create mode 100644 Src/Newtonsoft.Json/Utilities/EnumValue.cs create mode 100644 Src/Newtonsoft.Json/Utilities/EnumValues.cs diff --git a/Src/Doc/SerializingJSON.html b/Src/Doc/SerializingJSON.html index 26f400795..9307c5cb5 100644 --- a/Src/Doc/SerializingJSON.html +++ b/Src/Doc/SerializingJSON.html @@ -87,6 +87,9 @@
MissingMemberHandling
NullValueHandling

Controls how null values are handled during serialization and deserialization. Include or ignore.

+
DefaultValueHandling
+

Controls whether a value will be written to JSON or not if it matches the value specified in +the member's DefaultValueAttribute. Include or ignore.

ObjectCreationHandling

Controls how objects are created during deserialization. Auto, reuse, replace.

Converters
diff --git a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs index 19ac57548..26dde0a9b 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs @@ -27,6 +27,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Newtonsoft.Json.Tests.TestObjects; using NUnit.Framework; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Utilities; diff --git a/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs index db5eacf52..31a947ea6 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs @@ -27,6 +27,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Newtonsoft.Json.Tests.TestObjects; using NUnit.Framework; using Newtonsoft.Json.Converters; diff --git a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs index 799bdf285..e7b59df58 100644 --- a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs @@ -274,5 +274,22 @@ public void DeserializeValueObjects() object u = JsonConvert.DeserializeObject("undefined"); Assert.AreEqual(null, u); } + + [Test] + public void FloatToString() + { + Assert.AreEqual("1.1", JsonConvert.ToString(1.1)); + Assert.AreEqual("1.11", JsonConvert.ToString(1.11)); + Assert.AreEqual("1.111", JsonConvert.ToString(1.111)); + Assert.AreEqual("1.1111", JsonConvert.ToString(1.1111)); + Assert.AreEqual("1.11111", JsonConvert.ToString(1.11111)); + Assert.AreEqual("1.111111", JsonConvert.ToString(1.111111)); + Assert.AreEqual("1.0", JsonConvert.ToString(1.0)); + Assert.AreEqual("1.01", JsonConvert.ToString(1.01)); + Assert.AreEqual("1.001", JsonConvert.ToString(1.001)); + Assert.AreEqual(JsonConvert.PositiveInfinity, JsonConvert.ToString(double.PositiveInfinity)); + Assert.AreEqual(JsonConvert.NegativeInfinity, JsonConvert.ToString(double.NegativeInfinity)); + Assert.AreEqual(JsonConvert.NaN, JsonConvert.ToString(double.NaN)); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs index 388e1c837..c1bd43cbf 100644 --- a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs @@ -39,183 +39,10 @@ #if !PocketPC using System.Runtime.Serialization.Json; #endif -using Newtonsoft.Json.Utilities; -using System.Globalization; -using System.ComponentModel; +using Newtonsoft.Json.Tests.TestObjects; namespace Newtonsoft.Json.Tests { - public class Product - { - public string Name; - public DateTime Expiry = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc); - public decimal Price; - public string[] Sizes; - - public override bool Equals(object obj) - { - if (obj is Product) - { - Product p = (Product)obj; - - return (p.Name == Name && p.Expiry == Expiry && p.Price == Price); - } - - return base.Equals(obj); - } - - public override int GetHashCode() - { - return (Name ?? string.Empty).GetHashCode(); - } - } - - public class ProductCollection : List - { - } - - public class ProductShort - { - public string Name; - public DateTime Expiry; - //public decimal Price; - public string[] Sizes; - } - - public class Store - { - public StoreColor Color = StoreColor.Yellow; - public DateTimeOffset Establised = new DateTimeOffset(2010, 1, 22, 1, 1, 1, TimeSpan.Zero); - public double Width = 1.1; - public int Employees = 999; - public int[] RoomsPerFloor = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - public bool Open = false; - public char Symbol = '@'; - public List Mottos = new List(); - public decimal Cost = 100980.1M; - public string Escape = "\r\n\t\f\b?{\\r\\n\"\'"; - public List product = new List(); - - public Store() - { - Mottos.Add("Hello World"); - Mottos.Add("öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"); - Mottos.Add(null); - Mottos.Add(" "); - - Product rocket = new Product(); - rocket.Name = "Rocket"; - rocket.Expiry = new DateTime(2000, 2, 2, 23, 1, 30, DateTimeKind.Utc); - Product alien = new Product(); - alien.Name = "Alien"; - - product.Add(rocket); - product.Add(alien); - } - } - - public enum StoreColor - { - Black, - Red, - Yellow, - White - } - - public class ClassWithGuid - { - public Guid GuidField; - } - - public class ClassWithArray - { - private readonly IList bar; - private string foo; - - public ClassWithArray() - { - bar = new List() { int.MaxValue }; - } - - [JsonProperty("foo")] - public string Foo - { - get { return foo; } - set { foo = value; } - } - - [JsonProperty(PropertyName = "bar")] - public IList Bar - { - get { return bar; } - } - } - - [JsonObject] - public class ConverableMembers - { - public string String = "string"; - public int Int32 = int.MaxValue; - public uint UInt32 = uint.MaxValue; - public byte Byte = byte.MaxValue; - public sbyte SByte = sbyte.MaxValue; - public short Short = short.MaxValue; - public ushort UShort = ushort.MaxValue; - public long Long = long.MaxValue; - public ulong ULong = long.MaxValue; - public double Double = double.MaxValue; - public float Float = float.MaxValue; - public DBNull DBNull = DBNull.Value; - public bool Bool = true; - public char Char = '\0'; - } - - [JsonObject(MemberSerialization.OptIn)] - public class JsonIgnoreAttributeOnClassTestClass - { - private int _property = 21; - private int _ignoredProperty = 12; - - [JsonProperty("TheField")] - public int Field; - - [JsonProperty] - public int Property - { - get { return _property; } - } - - public int IgnoredField; - - [JsonProperty] - [JsonIgnore] // JsonIgnore should take priority - public int IgnoredProperty - { - get { return _ignoredProperty; } - } - } - - [JsonObject(MemberSerialization.OptIn)] - public class Person - { - // "John Smith" - [JsonProperty] - public string Name { get; set; } - - // "2000-12-15T22:11:03" - [JsonProperty] - //[JsonConverter(typeof(IsoDateTimeConverter))] - public DateTime BirthDate { get; set; } - - // new Date(976918263055) - [JsonProperty] - //[JsonConverter(typeof(JavaScriptDateTimeConverter))] - public DateTime LastModified { get; set; } - - // not serialized - public string Department { get; set; } - } - public class JsonSerializerTest : TestFixtureBase { [Test] @@ -314,13 +141,6 @@ public void DeserializeJavaScriptDate() Console.WriteLine(jsonText); } - public class MethodExecutorObject - { - public string serverClassName; - public object[] serverMethodParams; - public string clientGetResultFunction; - } - [Test] public void TestMethodExecutorObject() { @@ -351,12 +171,6 @@ public void HashtableDeserialization() Assert.AreEqual("Orange", p["Name"].ToString()); } - public class TypedSubHashtable - { - public string Name; - public Hashtable Hash; - } - [Test] public void TypedHashtableDeserialization() { @@ -371,16 +185,6 @@ public void TypedHashtableDeserialization() } #endif - public class GetOnlyPropertyClass - { - public string Field = "Field"; - - public string GetOnlyProperty - { - get { return "GetOnlyProperty"; } - } - } - [Test] public void SerializeDeserializeGetOnlyProperty() { @@ -392,16 +196,6 @@ public void SerializeDeserializeGetOnlyProperty() Assert.AreEqual(c.GetOnlyProperty, "GetOnlyProperty"); } - public class SetOnlyPropertyClass - { - public string Field = "Field"; - - public string SetOnlyProperty - { - set { } - } - } - [Test] public void SerializeDeserializeSetOnlyProperty() { @@ -412,30 +206,6 @@ public void SerializeDeserializeSetOnlyProperty() Assert.AreEqual(c.Field, "Field"); } - public class JsonIgnoreAttributeTestClass - { - private int _property = 21; - private int _ignoredProperty = 12; - - public int Field; - public int Property - { - get { return _property; } - } - - [JsonIgnore] - public int IgnoredField; - - [JsonIgnore] - public int IgnoredProperty - { - get { return _ignoredProperty; } - } - - [JsonIgnore] - public Product IgnoredObject = new Product(); - } - [Test] public void JsonIgnoreAttributeTest() { @@ -594,39 +364,13 @@ public void JsonPropertyClassSerialize() Assert.AreEqual(test.SweetCakesCount, test2.SweetCakesCount); } - public class BadJsonPropertyClass - { - [JsonProperty("pie")] - public string Pie = "Yum"; - - public string pie = "PieChart!"; - } - [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"A member with the name 'pie' already exists on Newtonsoft.Json.Tests.JsonSerializerTest+BadJsonPropertyClass. Use the JsonPropertyAttribute to specify another name.")] + [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"A member with the name 'pie' already exists on Newtonsoft.Json.Tests.TestObjects.BadJsonPropertyClass. Use the JsonPropertyAttribute to specify another name.")] public void BadJsonPropertyClassSerialize() { JsonConvert.SerializeObject(new BadJsonPropertyClass()); } - public class Article - { - public string Name; - - public Article() - { - } - - public Article(string name) - { - Name = name; - } - } - - public class ArticleCollection : List
- { - } - [Test] public void InheritedListSerialize() { @@ -657,26 +401,6 @@ public void ReadOnlyCollectionSerialize() CollectionAssert.AreEqual(r1, r2); } - public class Person - { - private Guid _internalId; - private string _firstName; - - [JsonIgnore] - public Guid InternalId - { - get { return _internalId; } - set { _internalId = value; } - } - - [JsonProperty("first_name")] - public string FirstName - { - get { return _firstName; } - set { _firstName = value; } - } - } - [Test] [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Could not find member 'Price' on object of type 'RuntimeType'")] public void MissingMemberDeserialize() @@ -1042,28 +766,6 @@ public void SerializeArrayAsArrayList() } #endif - public class Name - { - public string personsName; - - public List pNumbers = new List(); - - public Name(string personsName) - { - this.personsName = personsName; - } - } - - public class PhoneNumber - { - public string phoneNumber; - - public PhoneNumber(string phoneNumber) - { - this.phoneNumber = phoneNumber; - } - } - [Test] public void SerializeMemberGenericList() { @@ -1085,20 +787,6 @@ public void SerializeMemberGenericList() Assert.AreEqual(0, newName.pNumbers.Count); } - public class ConstructorCaseSensitivityClass - { - public string param1 { get; set; } - public string Param1 { get; set; } - public string Param2 { get; set; } - - public ConstructorCaseSensitivityClass(string param1, string Param1, string param2) - { - this.param1 = param1; - this.Param1 = Param1; - this.Param2 = param2; - } - } - [Test] public void ConstructorCaseSensitivity() { @@ -1113,72 +801,6 @@ public void ConstructorCaseSensitivity() Assert.AreEqual("Param2", deserialized.Param2); } - public class MemberConverterPrecedenceClassConverter : ConverterPrecedenceClassConverter - { - public override string ConverterType - { - get { return "Member"; } - } - } - - public class ClassConverterPrecedenceClassConverter : ConverterPrecedenceClassConverter - { - public override string ConverterType - { - get { return "Class"; } - } - } - - public class ArgumentConverterPrecedenceClassConverter : ConverterPrecedenceClassConverter - { - public override string ConverterType - { - get { return "Argument"; } - } - } - - public abstract class ConverterPrecedenceClassConverter : JsonConverter - { - public abstract string ConverterType { get; } - - public override void WriteJson(JsonWriter writer, object value) - { - ConverterPrecedenceClass c = (ConverterPrecedenceClass)value; - - JToken j = new JArray(ConverterType, c.TestValue); - - j.WriteTo(writer); - } - - public override object ReadJson(JsonReader reader, Type objectType) - { - JToken j = JArray.Load(reader); - - string converter = (string)j[0]; - if (converter != ConverterType) - throw new Exception("Serialize converter {0} and deserialize converter {1} do not match.".FormatWith(CultureInfo.InvariantCulture, converter, ConverterType)); - - string testValue = (string)j[1]; - return new ConverterPrecedenceClass(testValue); - } - - public override bool CanConvert(Type objectType) - { - return (objectType == typeof(ConverterPrecedenceClass)); - } - } - - [JsonConverter(typeof(ClassConverterPrecedenceClassConverter))] - public class ConverterPrecedenceClass - { - public string TestValue { get; set; } - - public ConverterPrecedenceClass(string testValue) - { - TestValue = testValue; - } - } - [Test] public void SerializerShouldUseClassConverter() { @@ -1205,13 +827,6 @@ public void SerializerShouldUseClassConverterOverArgumentConverter() Assert.AreEqual("!Test!", c2.TestValue); } - public class MemberConverterClass - { - public DateTime DefaultConverter { get; set; } - [JsonConverter(typeof(IsoDateTimeConverter))] - public DateTime MemberConverter { get; set; } - } - [Test] public void SerializerShouldUseMemberConverter() { @@ -1242,13 +857,6 @@ public void SerializerShouldUseMemberConverterOverArgumentConverter() Assert.AreEqual(testDate, m2.MemberConverter); } - public class ClassAndMemberConverterClass - { - public ConverterPrecedenceClass DefaultConverter { get; set; } - [JsonConverter(typeof(MemberConverterPrecedenceClassConverter))] - public ConverterPrecedenceClass MemberConverter { get; set; } - } - [Test] public void SerializerShouldUseMemberConverterOverClassAndArgumentConverter() { @@ -1265,29 +873,14 @@ public void SerializerShouldUseMemberConverterOverClassAndArgumentConverter() Assert.AreEqual("MemberConverterValue", c2.MemberConverter.TestValue); } - [JsonConverter(typeof(IsoDateTimeConverter))] - public class IncompatibleJsonAttributeClass - { - } - [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JsonConverter IsoDateTimeConverter on Newtonsoft.Json.Tests.JsonSerializerTest+IncompatibleJsonAttributeClass is not compatible with member type IncompatibleJsonAttributeClass.")] + [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JsonConverter IsoDateTimeConverter on Newtonsoft.Json.Tests.TestObjects.IncompatibleJsonAttributeClass is not compatible with member type IncompatibleJsonAttributeClass.")] public void IncompatibleJsonAttributeShouldThrow() { IncompatibleJsonAttributeClass c = new IncompatibleJsonAttributeClass(); JsonConvert.SerializeObject(c); } - public abstract class AbstractGenericBase - { - public abstract TKey Id { get; set; } - } - - public class GenericImpl : AbstractGenericBase - { - public override int Id { get; set; } - } - [Test] public void GenericAbstractProperty() { @@ -1295,15 +888,6 @@ public void GenericAbstractProperty() Assert.AreEqual(@"{""Id"":0}", json); } - public class DefaultValueAttributeTestClass - { - [DefaultValue("TestProperty1Value")] - public string TestProperty1 { get; set; } - - [DefaultValue(21)] - public int TestField1; - } - [Test] public void DefaultValueAttributeTest() { @@ -1324,16 +908,6 @@ public void DefaultValueAttributeTest() Assert.AreEqual(@"{}", json); } - public class Invoice - { - public string Company { get; set; } - public decimal Amount { get; set; } - [DefaultValue(false)] - public bool Paid { get; set; } - [DefaultValue(null)] - public DateTime? PaidDate { get; set; } - } - [Test] public void SerializeInvoice() { @@ -1369,41 +943,6 @@ public void DeserializeNullable() Assert.AreEqual("1", json); } - public class PersonRaw - { - private Guid _internalId; - private string _firstName; - private string _lastName; - private JsonRaw _rawContent; - - [JsonIgnore] - public Guid InternalId - { - get { return _internalId; } - set { _internalId = value; } - } - - [JsonProperty("first_name")] - public string FirstName - { - get { return _firstName; } - set { _firstName = value; } - } - - public JsonRaw RawContent - { - get { return _rawContent; } - set { _rawContent = value; } - } - - [JsonProperty("last_name")] - public string LastName - { - get { return _lastName; } - set { _lastName = value; } - } - } - [Test] public void SerializeJsonRaw() { @@ -1432,21 +971,11 @@ public void DeserializeJsonRaw() Assert.AreEqual("LastNameValue", personRaw.LastName); } - public class UserNullablle - { - public Guid Id; - public string FName; - public string LName; - public int RoleId; - public int? NullableRoleId; - public int? NullRoleId; - public bool? Active; - } [Test] public void DeserializeNullableMember() { - UserNullablle userNullablle = new UserNullablle + UserNullable userNullablle = new UserNullable { Id = new Guid("AD6205E8-0DF4-465d-AEA6-8BA18E93A7E7"), FName = "FirstValue", @@ -1461,7 +990,7 @@ public void DeserializeNullableMember() Assert.AreEqual(@"{""Id"":""ad6205e8-0df4-465d-aea6-8ba18e93a7e7"",""FName"":""FirstValue"",""LName"":""LastValue"",""RoleId"":5,""NullableRoleId"":6,""NullRoleId"":null,""Active"":true}", json); - UserNullablle userNullablleDeserialized = JsonConvert.DeserializeObject(json); + UserNullable userNullablleDeserialized = JsonConvert.DeserializeObject(json); Assert.AreEqual(new Guid("AD6205E8-0DF4-465d-AEA6-8BA18E93A7E7"), userNullablleDeserialized.Id); Assert.AreEqual("FirstValue", userNullablleDeserialized.FName); @@ -1472,13 +1001,6 @@ public void DeserializeNullableMember() Assert.AreEqual(true, userNullablleDeserialized.Active); } - public class MyClass - { - public int PreProperty { get; set; } - //public DateTime DateProperty { get; set; } - public int PostProperty { get; set; } - } - [Test] public void MissingMemberIgnoreComplexValue() { @@ -1492,5 +1014,63 @@ public void MissingMemberIgnoreComplexValue() Assert.AreEqual(1, myClass.PreProperty); Assert.AreEqual(2, myClass.PostProperty); } + + [Test] + public void DeserializeInt64ToNullableDouble() + { + string json = @"{""Height"":1}"; + + DoubleClass c = JsonConvert.DeserializeObject(json); + Assert.AreEqual(1, c.Height); + } + + [Test] + public void SerializeTypeProperty() + { + TypeClass typeClass = new TypeClass {TypeProperty = typeof (bool)}; + + string json = JsonConvert.SerializeObject(typeClass); + Assert.AreEqual(@"{""TypeProperty"":""System.Boolean""}", json); + + TypeClass typeClass2 = JsonConvert.DeserializeObject(json); + Assert.AreEqual(typeof(bool), typeClass2.TypeProperty); + } + + [Test] + public void RequiredMembersClass() + { + RequiredMembersClass c = new RequiredMembersClass() + { + BirthDate = new DateTime(2000, 12, 20, 10, 55, 55, DateTimeKind.Utc), + FirstName = "Bob", + LastName = "Smith", + MiddleName = "Cosmo" + }; + + string json = JsonConvert.SerializeObject(c, Formatting.Indented); + + Assert.AreEqual(@"{ + ""FirstName"": ""Bob"", + ""MiddleName"": ""Cosmo"", + ""LastName"": ""Smith"", + ""BirthDate"": ""\/Date(977309755000)\/"" +}", json); + + RequiredMembersClass c2 = JsonConvert.DeserializeObject(json); + + Assert.AreEqual("Bob", c2.FirstName); + Assert.AreEqual(new DateTime(2000, 12, 20, 10, 55, 55, DateTimeKind.Utc), c2.BirthDate); + } + + [Test] + [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Required property 'LastName' not found in JSON.")] + public void RequiredMembersClassMissingRequiredProperty() + { + string json = @"{ + ""FirstName"": ""Bob"" +}"; + + JsonConvert.DeserializeObject(json); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index d6348eef1..da144e717 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -348,5 +348,81 @@ public void EscapedUnicodeText() reader.Read(); Assert.AreEqual(JsonToken.EndArray, reader.TokenType); } + + [Test] + public void ReadFloatingPointNumber() + { + string json = + @"[0.0,0.0,0.1,1.0,1.000001,1E-06,4.94065645841247E-324,Infinity,-Infinity,NaN,1.7976931348623157E+308,-1.7976931348623157E+308,Infinity,-Infinity,NaN]"; + + using (JsonReader jsonReader = new JsonTextReader(new StringReader(json))) + { + jsonReader.Read(); + Assert.AreEqual(JsonToken.StartArray, jsonReader.TokenType); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(0.0, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(0.0, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(0.1, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(1.0, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(1.000001, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(1E-06, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(4.94065645841247E-324, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(double.PositiveInfinity, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(double.NegativeInfinity, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(double.NaN, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(double.MaxValue, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(double.MinValue, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(double.PositiveInfinity, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(double.NegativeInfinity, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.Float, jsonReader.TokenType); + Assert.AreEqual(double.NaN, jsonReader.Value); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.EndArray, jsonReader.TokenType); + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs index 245082628..788be2681 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs @@ -410,5 +410,61 @@ public void WriteRawValue() Assert.AreEqual(@"{""d0"":[1,2],""d1"":[1,2],""d2"":[1,2]}", sb.ToString()); } + + [Test] + public void WriteObjectNestedInConstructor() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.WriteStartObject(); + jsonWriter.WritePropertyName("con"); + + jsonWriter.WriteStartConstructor("Ext.data.JsonStore"); + jsonWriter.WriteStartObject(); + jsonWriter.WritePropertyName("aa"); + jsonWriter.WriteValue("aa"); + jsonWriter.WriteEndObject(); + jsonWriter.WriteEndConstructor(); + + jsonWriter.WriteEndObject(); + } + + Assert.AreEqual(@"{""con"":new Ext.data.JsonStore({""aa"":""aa""})}", sb.ToString()); + } + + [Test] + public void WriteFloatingPointNumber() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.WriteStartArray(); + + jsonWriter.WriteValue(0.0); + jsonWriter.WriteValue(0f); + jsonWriter.WriteValue(0.1); + jsonWriter.WriteValue(1.0); + jsonWriter.WriteValue(1.000001); + jsonWriter.WriteValue(0.000001); + jsonWriter.WriteValue(double.Epsilon); + jsonWriter.WriteValue(double.PositiveInfinity); + jsonWriter.WriteValue(double.NegativeInfinity); + jsonWriter.WriteValue(double.NaN); + jsonWriter.WriteValue(double.MaxValue); + jsonWriter.WriteValue(double.MinValue); + jsonWriter.WriteValue(float.PositiveInfinity); + jsonWriter.WriteValue(float.NegativeInfinity); + jsonWriter.WriteValue(float.NaN); + + jsonWriter.WriteEndArray(); + } + + Assert.AreEqual(@"[0.0,0.0,0.1,1.0,1.000001,1E-06,4.94065645841247E-324,Infinity,-Infinity,NaN,1.7976931348623157E+308,-1.7976931348623157E+308,Infinity,-Infinity,NaN]", sb.ToString()); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTokenWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTokenWriterTest.cs index cf4543392..f6c404a90 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTokenWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTokenWriterTest.cs @@ -39,7 +39,7 @@ public class JsonTokenWriterTest : TestFixtureBase [Test] public void ValueFormatting() { - JContainer root; + JToken root; using (JsonTokenWriter jsonWriter = new JsonTokenWriter()) { jsonWriter.WriteStartArray(); diff --git a/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs b/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs new file mode 100644 index 000000000..c757c3524 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs @@ -0,0 +1,1150 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using NUnit.Framework; +using System.Xml; +using System.Xml.Schema; +using Newtonsoft.Json.Schema; + +namespace Newtonsoft.Json.Tests +{ + public class JsonValidatingReaderTests : TestFixtureBase + { + [Test] + public void CheckInnerReader() + { + string json = "{'name':'James','hobbies':['pie','cake']}"; + JsonReader reader = new JsonTextReader(new StringReader(json)); + + JsonValidatingReader validatingReader = new JsonValidatingReader(reader); + Assert.AreEqual(reader, validatingReader.Reader); + } + + [Test] + public void ValidateTypes() + { + string schemaJson = @"{ + ""description"":""A person"", + ""type"":""object"", + ""properties"": + { + ""name"":{""type"":""string""}, + ""hobbies"": + { + ""type"":""array"", + ""items"": {""type"":""string""} + } + } +}"; + + string json = @"{'name':""James"",'hobbies':[""pie"",'cake']}"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + JsonSchema schema = JsonSchema.Parse(schemaJson); + reader.Schema = schema; + Assert.AreEqual(schema, reader.Schema); + + Assert.AreEqual(0, reader.Depth); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("name", reader.Value.ToString()); + + Assert.AreEqual(1, reader.Depth); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("James", reader.Value.ToString()); + Assert.AreEqual(typeof(string), reader.ValueType); + Assert.AreEqual('"', reader.QuoteChar); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("hobbies", reader.Value.ToString()); + Assert.AreEqual('\'', reader.QuoteChar); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("pie", reader.Value.ToString()); + Assert.AreEqual('"', reader.QuoteChar); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("cake", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsNull(validationEventArgs); + } + + [Test] + public void ValidateUnrestrictedArray() + { + string schemaJson = @"{ + ""type"":""array"" +}"; + + string json = "['pie','cake',['nested1','nested2'],{'nestedproperty1':1.1,'nestedproperty2':[null]}]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("pie", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("cake", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("nested1", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("nested2", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("nestedproperty1", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(1.1, reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("nestedproperty2", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsNull(validationEventArgs); + } + + [Test] + public void StringLessThanMinimumLength() + { + string schemaJson = @"{ + ""type"":""string"", + ""minLength"":5, + ""maxLength"":50, +}"; + + string json = "'pie'"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("String 'pie' is less than minimum length of 5.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void StringGreaterThanMaximumLength() + { + string schemaJson = @"{ + ""type"":""string"", + ""minLength"":5, + ""maxLength"":10 +}"; + + string json = "'The quick brown fox jumps over the lazy dog.'"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' exceeds maximum length of 10.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void StringIsNotInEnum() + { + string schemaJson = @"{ + ""type"":""array"", + ""items"":{ + ""type"":""string"", + ""enum"":[""one"",""two""] + }, + ""maxItems"":3 +}"; + + string json = "['one','two','THREE']"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual(@"Value ""THREE"" is not defined in enum.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void StringDoesNotMatchPattern() + { + string schemaJson = @"{ + ""type"":""string"", + ""pattern"":""foo"" +}"; + + string json = "'The quick brown fox jumps over the lazy dog.'"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' does not match regex pattern 'foo'.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void IntegerGreaterThanMaximumValue() + { + string schemaJson = @"{ + ""type"":""integer"", + ""maximum"":5 +}"; + + string json = "10"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + Assert.AreEqual("Integer 10 exceeds maximum value of 5.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + [ExpectedException(typeof(JsonSchemaException), ExpectedMessage = "Integer 10 exceeds maximum value of 5.")] + public void ThrowExceptionWhenNoValidationEventHandler() + { + string schemaJson = @"{ + ""type"":""integer"", + ""maximum"":5 +}"; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader("10"))); + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + } + + [Test] + public void IntegerLessThanMinimumValue() + { + string schemaJson = @"{ + ""type"":""integer"", + ""minimum"":5 +}"; + + string json = "1"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + Assert.AreEqual("Integer 1 is less than minimum value of 5.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void IntegerIsNotInEnum() + { + string schemaJson = @"{ + ""type"":""array"", + ""items"":{ + ""type"":""integer"", + ""enum"":[1,2] + }, + ""maxItems"":3 +}"; + + string json = "[1,2,3]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + Assert.AreEqual(@"Value 3 is not defined in enum.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void FloatGreaterThanMaximumValue() + { + string schemaJson = @"{ + ""type"":""number"", + ""maximum"":5 +}"; + + string json = "10.0"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual("Float 10.0 exceeds maximum value of 5.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void FloatLessThanMinimumValue() + { + string schemaJson = @"{ + ""type"":""number"", + ""minimum"":5 +}"; + + string json = "1.1"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual("Float 1.1 is less than minimum value of 5.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void FloatIsNotInEnum() + { + string schemaJson = @"{ + ""type"":""array"", + ""items"":{ + ""type"":""number"", + ""enum"":[1.1,2.2] + }, + ""maxItems"":3 +}"; + + string json = "[1.1,2.2,3.0]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(@"Value 3.0 is not defined in enum.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void FloatExceedsMaxDecimalPlaces() + { + string schemaJson = @"{ + ""type"":""array"", + ""items"":{ + ""type"":""number"", + ""maxDecimal"":2 + } +}"; + + string json = "[1.1,2.2,4.001]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(@"Float 4.001 exceeds the maximum allowed number decimal places of 2.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void NullNotInEnum() + { + string schemaJson = @"{ + ""type"":""array"", + ""items"":{ + ""type"":""null"", + ""enum"":[] + }, + ""maxItems"":3 +}"; + + string json = "[null]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + Assert.AreEqual(@"Value null is not defined in enum.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void BooleanNotInEnum() + { + string schemaJson = @"{ + ""type"":""array"", + ""items"":{ + ""type"":""boolean"", + ""enum"":[true] + }, + ""maxItems"":3 +}"; + + string json = "[true,false]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Boolean, reader.TokenType); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Boolean, reader.TokenType); + Assert.AreEqual(@"Value false is not defined in enum.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void ArrayCountGreaterThanMaximumItems() + { + string schemaJson = @"{ + ""type"":""array"", + ""minItems"":2, + ""maxItems"":3 +}"; + + string json = "[null,null,null,null]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + Assert.AreEqual("Array item count 4 exceeds maximum count of 3.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void ArrayCountLessThanMinimumItems() + { + string schemaJson = @"{ + ""type"":""array"", + ""minItems"":2, + ""maxItems"":3 +}"; + + string json = "[null]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + Assert.AreEqual("Array item count 1 is less than minimum count of 2.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void InvalidDataType() + { + string schemaJson = @"{ + ""type"":""string"", + ""minItems"":2, + ""maxItems"":3, + ""items"":{} +}"; + + string json = "[null,null,null,null]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + Assert.AreEqual(@"Invalid type. Expected String but got Array.", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void StringDisallowed() + { + string schemaJson = @"{ + ""type"":""array"", + ""items"":{ + ""disallow"":[""number""] + }, + ""maxItems"":3 +}"; + + string json = "['pie',1.1]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(@"Type Float is disallowed.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void MissingNonoptionalProperties() + { + string schemaJson = @"{ + ""description"":""A person"", + ""type"":""object"", + ""properties"": + { + ""name"":{""type"":""string""}, + ""hobbies"":{""type"":""string""}, + ""age"":{""type"":""integer""} + } +}"; + + string json = "{'name':'James'}"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("name", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("James", reader.Value.ToString()); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + Assert.AreEqual("Non-optional properties are missing from object: hobbies, age", validationEventArgs.Message); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void MissingOptionalProperties() + { + string schemaJson = @"{ + ""description"":""A person"", + ""type"":""object"", + ""properties"": + { + ""name"":{""type"":""string""}, + ""hobbies"":{""type"":""string"",optional:true}, + ""age"":{""type"":""integer"",optional:true} + } +}"; + + string json = "{'name':'James'}"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("name", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("James", reader.Value.ToString()); + Assert.IsNull(validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsNull(validationEventArgs); + } + + [Test] + public void DisableAdditionalProperties() + { + string schemaJson = @"{ + ""description"":""A person"", + ""type"":""object"", + ""properties"": + { + ""name"":{""type"":""string""} + }, + ""additionalProperties"":false +}"; + + string json = "{'name':'James','additionalProperty1':null,'additionalProperty2':null}"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("name", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("James", reader.Value.ToString()); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("additionalProperty1", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + Assert.AreEqual(null, reader.Value); + Assert.AreEqual("Property 'additionalProperty1' has not been defined and schema does not allow additional properties.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("additionalProperty2", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + Assert.AreEqual(null, reader.Value); + Assert.AreEqual("Property 'additionalProperty2' has not been defined and schema does not allow additional properties.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsNotNull(validationEventArgs); + } + + [Test] + public void ExtendsStringGreaterThanMaximumLength() + { + string schemaJson = @"{ + ""extends"":{ + ""type"":""string"", + ""minLength"":5, + ""maxLength"":10 + }, + ""maxLength"":9 +}"; + + List errors = new List(); + string json = "'The quick brown fox jumps over the lazy dog.'"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; errors.Add(validationEventArgs.Message); }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual(1, errors.Count); + Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' exceeds maximum length of 9.", errors[0]); + + Assert.IsNotNull(validationEventArgs); + } + + private JsonSchema GetExtendedSchema() + { + string first = @"{ + ""id"":""first"", + ""type"":""object"", + ""properties"": + { + ""firstproperty"":{""type"":""string""} + }, + ""additionalProperties"":{} +}"; + + string second = @"{ + ""id"":""second"", + ""type"":""object"", + ""extends"":{""$ref"":""first""}, + ""properties"": + { + ""secondproperty"":{""type"":""string""} + }, + ""additionalProperties"":false +}"; + + JsonSchemaResolver resolver = new JsonSchemaResolver(); + JsonSchema firstSchema = JsonSchema.Parse(first, resolver); + JsonSchema secondSchema = JsonSchema.Parse(second, resolver); + + return secondSchema; + } + + [Test] + public void ExtendsDisallowAdditionProperties() + { + string json = "{'firstproperty':'blah','secondproperty':'blah2','additional':'blah3','additional2':'blah4'}"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = GetExtendedSchema(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("firstproperty", reader.Value.ToString()); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("blah", reader.Value.ToString()); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("secondproperty", reader.Value.ToString()); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("blah2", reader.Value.ToString()); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("additional", reader.Value.ToString()); + Assert.AreEqual("Property 'additional' has not been defined and schema does not allow additional properties.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("blah3", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("additional2", reader.Value.ToString()); + Assert.AreEqual("Property 'additional2' has not been defined and schema does not allow additional properties.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("blah4", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsFalse(reader.Read()); + } + + [Test] + public void ExtendsMissingNonoptionalProperties() + { + string json = "{}"; + + List errors = new List(); + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { errors.Add(args.Message); }; + reader.Schema = GetExtendedSchema(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.AreEqual(1, errors.Count); + Assert.AreEqual("Non-optional properties are missing from object: secondproperty, firstproperty", errors[0]); + } + + [Test] + public void sdfsdf() + { + string schemaJson = @"{ + ""type"":""array"", + ""items"": [{""type"":""string""},{""type"":""integer""}], + ""additionalProperties"": false +}"; + + string json = @"[1, 'a', null]"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; }; + reader.Schema = JsonSchema.Parse(schemaJson); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + Assert.AreEqual("Invalid type. Expected String but got Integer.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("Invalid type. Expected Integer but got String.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + Assert.AreEqual("Index 3 has not been defined and schema does not allow additional items.", validationEventArgs.Message); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsFalse(reader.Read()); + } + + [Test] + public void ExtendedComplex() + { + string first = @"{ + ""id"":""first"", + ""type"":""object"", + ""properties"": + { + ""firstproperty"":{""type"":""string""}, + ""secondproperty"":{""type"":""string"",""maxLength"":10}, + ""thirdproperty"":{ + ""type"":""object"", + ""properties"": + { + ""thirdproperty_firstproperty"":{""type"":""string"",""maxLength"":10,""minLength"":7} + } + } + }, + ""additionalProperties"":{} +}"; + + string second = @"{ + ""id"":""second"", + ""type"":""object"", + ""extends"":{""$ref"":""first""}, + ""properties"": + { + ""secondproperty"":{""type"":""any""}, + ""thirdproperty"":{ + ""extends"":{ + ""properties"": + { + ""thirdproperty_firstproperty"":{""maxLength"":9,""minLength"":6,""pattern"":""hi2u""} + }, + ""additionalProperties"":{""maxLength"":9,""minLength"":6,""enum"":[""one"",""two""]} + }, + ""type"":""object"", + ""properties"": + { + ""thirdproperty_firstproperty"":{""pattern"":""hi""} + }, + ""additionalProperties"":{""type"":""string"",""enum"":[""two"",""three""]} + }, + ""fourthproperty"":{""type"":""string""} + }, + ""additionalProperties"":false +}"; + + JsonSchemaResolver resolver = new JsonSchemaResolver(); + JsonSchema firstSchema = JsonSchema.Parse(first, resolver); + JsonSchema secondSchema = JsonSchema.Parse(second, resolver); + + JsonSchemaModelBuilder modelBuilder = new JsonSchemaModelBuilder(); + + string json = @"{ + 'firstproperty':'blahblahblahblahblahblah', + 'secondproperty':'secasecasecasecaseca', + 'thirdproperty':{ + 'thirdproperty_firstproperty':'aaa', + 'additional':'three' + } +}"; + + Json.Schema.ValidationEventArgs validationEventArgs = null; + List errors = new List(); + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => { validationEventArgs = args; errors.Add(validationEventArgs.Message); }; + reader.Schema = secondSchema; + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("firstproperty", reader.Value.ToString()); + Assert.AreEqual(null, validationEventArgs); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("blahblahblahblahblahblah", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("secondproperty", reader.Value.ToString()); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("secasecasecasecaseca", reader.Value.ToString()); + Assert.AreEqual(1, errors.Count); + Assert.AreEqual("String 'secasecasecasecaseca' exceeds maximum length of 10.", errors[0]); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("thirdproperty", reader.Value.ToString()); + Assert.AreEqual(1, errors.Count); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + Assert.AreEqual(1, errors.Count); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("thirdproperty_firstproperty", reader.Value.ToString()); + Assert.AreEqual(1, errors.Count); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("aaa", reader.Value.ToString()); + Assert.AreEqual(4, errors.Count); + Assert.AreEqual("String 'aaa' is less than minimum length of 7.", errors[1]); + Assert.AreEqual("String 'aaa' does not match regex pattern 'hi'.", errors[2]); + Assert.AreEqual("String 'aaa' does not match regex pattern 'hi2u'.", errors[3]); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("additional", reader.Value.ToString()); + Assert.AreEqual(4, errors.Count); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("three", reader.Value.ToString()); + Assert.AreEqual(5, errors.Count); + Assert.AreEqual("String 'three' is less than minimum length of 6.", errors[4]); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsFalse(reader.Read()); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JConstructorTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JConstructorTests.cs new file mode 100644 index 000000000..353691d09 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Linq/JConstructorTests.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using System.IO; + +namespace Newtonsoft.Json.Tests.Linq +{ + public class JConstructorTests : TestFixtureBase + { + [Test] + public void Load() + { + JsonReader reader = new JsonTextReader(new StringReader("new Date(123)")); + reader.Read(); + + JConstructor constructor = JConstructor.Load(reader); + Assert.AreEqual("Date", constructor.Name); + Assert.IsTrue(JToken.DeepEquals(new JValue(123), constructor.Values().ElementAt(0))); + } + + [Test] + public void CreateWithMultiValue() + { + JConstructor constructor = new JConstructor("Test", new List { 1, 2, 3 }); + Assert.AreEqual("Test", constructor.Name); + Assert.AreEqual(3, constructor.Children().Count()); + Assert.AreEqual(1, (int)constructor.Children().ElementAt(0)); + Assert.AreEqual(2, (int)constructor.Children().ElementAt(1)); + Assert.AreEqual(3, (int)constructor.Children().ElementAt(2)); + } + } +} diff --git a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs index 9323a27d5..af5303ac4 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Newtonsoft.Json.Tests.TestObjects; using NUnit.Framework; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Converters; @@ -235,7 +236,7 @@ public void GenericCollectionCopyToInsufficientArrayCapacity() [Test] public void FromObjectRaw() { - JsonSerializerTest.PersonRaw raw = new JsonSerializerTest.PersonRaw + PersonRaw raw = new PersonRaw { FirstName = "FirstNameValue", RawContent = new JsonRaw("[1,2,3,4,5]"), @@ -253,7 +254,7 @@ public void FromObjectRaw() [Test] public void JsonTokenReader() { - JsonSerializerTest.PersonRaw raw = new JsonSerializerTest.PersonRaw + PersonRaw raw = new PersonRaw { FirstName = "FirstNameValue", RawContent = new JsonRaw("[1,2,3,4,5]"), @@ -294,7 +295,7 @@ public void JsonTokenReader() [Test] public void DeserializeFromRaw() { - JsonSerializerTest.PersonRaw raw = new JsonSerializerTest.PersonRaw + PersonRaw raw = new PersonRaw { FirstName = "FirstNameValue", RawContent = new JsonRaw("[1,2,3,4,5]"), @@ -305,7 +306,7 @@ public void DeserializeFromRaw() JsonReader reader = new JsonTokenReader(o); JsonSerializer serializer = new JsonSerializer(); - raw = (JsonSerializerTest.PersonRaw)serializer.Deserialize(reader, typeof(JsonSerializerTest.PersonRaw)); + raw = (PersonRaw)serializer.Deserialize(reader, typeof(PersonRaw)); Assert.AreEqual("FirstNameValue", raw.FirstName); Assert.AreEqual("LastNameValue", raw.LastName); diff --git a/Src/Newtonsoft.Json.Tests/Linq/JPropertyTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JPropertyTests.cs new file mode 100644 index 000000000..a8b1ed859 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Linq/JPropertyTests.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using System.IO; + +namespace Newtonsoft.Json.Tests.Linq +{ + public class JPropertyTests : TestFixtureBase + { + [Test] + public void Load() + { + JsonReader reader = new JsonTextReader(new StringReader("{'propertyname':['value1']}")); + reader.Read(); + + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + reader.Read(); + + JProperty property = JProperty.Load(reader); + Assert.AreEqual("propertyname", property.Name); + Assert.IsTrue(JToken.DeepEquals(JArray.Parse("['value1']"), property.Value)); + + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + reader = new JsonTextReader(new StringReader("{'propertyname':null}")); + reader.Read(); + + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + reader.Read(); + + property = JProperty.Load(reader); + Assert.AreEqual("propertyname", property.Name); + Assert.IsTrue(JToken.DeepEquals(new JValue(null, JsonTokenType.Null), property.Value)); + + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + } + + [Test] + public void MultiContentConstructor() + { + JProperty p = new JProperty("error", new List { "one", "two" }); + JArray a = (JArray) p.Value; + + Assert.AreEqual(a.Count, 2); + Assert.AreEqual("one", (string)a[0]); + Assert.AreEqual("two", (string)a[1]); + } + } +} diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs index d35b5f5a2..ecf8e0b9b 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs @@ -29,11 +29,47 @@ using System.Text; using NUnit.Framework; using Newtonsoft.Json.Linq; +using System.IO; namespace Newtonsoft.Json.Tests.Linq { public class JTokenTests : TestFixtureBase { + [Test] + public void ReadFrom() + { + JObject o = (JObject)JToken.ReadFrom(new JsonTextReader(new StringReader("{'pie':true}"))); + Assert.AreEqual(true, (bool)o["pie"]); + + JArray a = (JArray)JToken.ReadFrom(new JsonTextReader(new StringReader("[1,2,3]"))); + Assert.AreEqual(1, (int)a[0]); + Assert.AreEqual(2, (int)a[1]); + Assert.AreEqual(3, (int)a[2]); + + JsonReader reader = new JsonTextReader(new StringReader("{'pie':true}")); + reader.Read(); + reader.Read(); + + JProperty p = (JProperty)JToken.ReadFrom(reader); + Assert.AreEqual("pie", p.Name); + Assert.AreEqual(true, (bool)p.Value); + + JConstructor c = (JConstructor)JToken.ReadFrom(new JsonTextReader(new StringReader("new Date(1)"))); + Assert.AreEqual("Date", c.Name); + Assert.IsTrue(JToken.DeepEquals(new JValue(1), c.Values().ElementAt(0))); + + JValue v; + + v = (JValue)JToken.ReadFrom(new JsonTextReader(new StringReader(@"""stringvalue"""))); + Assert.AreEqual("stringvalue", (string)v); + + v = (JValue)JToken.ReadFrom(new JsonTextReader(new StringReader(@"1"))); + Assert.AreEqual(1, (int)v); + + v = (JValue)JToken.ReadFrom(new JsonTextReader(new StringReader(@"1.1"))); + Assert.AreEqual(1.1, (double)v); + } + [Test] public void Parent() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs index 8b52a5feb..82740cfb4 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs @@ -32,6 +32,7 @@ using System.Xml; using System.IO; using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Tests.TestObjects; namespace Newtonsoft.Json.Tests.Linq { @@ -351,13 +352,13 @@ public void CreateJTokenTree() [ ""1"", 2, - 3, + 3.0, ""\/Date(-62030076711000)\/"" ], new ConstructorName( ""param1"", 2, - 3 + 3.0 ) ]", a.ToString()); } diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj index 2fe5a847b..009dff6d1 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj @@ -58,12 +58,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + @@ -75,11 +122,14 @@ - + + + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj index 0ab0c0692..f5202b284 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj @@ -63,12 +63,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + @@ -80,11 +127,14 @@ - + + + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 6ff2c78d5..602c090ae 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -76,9 +76,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -98,6 +145,9 @@ + + + diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs index 83d366900..fdc76e27c 100644 --- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs +++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs @@ -20,7 +20,7 @@ namespace Newtonsoft.Json.Tests /// public class PerformanceTests : TestFixtureBase { - private int Iterations = 5000; + private int Iterations = 100; public enum SerializeMethod { diff --git a/Src/Newtonsoft.Json.Tests/Schema/ExtensionsTests.cs b/Src/Newtonsoft.Json.Tests/Schema/ExtensionsTests.cs new file mode 100644 index 000000000..bad8accdf --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Schema/ExtensionsTests.cs @@ -0,0 +1,84 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json.Schema; +using Newtonsoft.Json.Linq; + +namespace Newtonsoft.Json.Tests.Schema +{ + public class ExtensionsTests : TestFixtureBase + { + [Test] + public void IsValid() + { + JsonSchema schema = JsonSchema.Parse("{'type':'integer'}"); + JToken stringToken = JToken.FromObject("pie"); + JToken integerToken = JToken.FromObject(1); + + Assert.AreEqual(false, stringToken.IsValid(schema)); + Assert.AreEqual(true, integerToken.IsValid(schema)); + } + + [Test] + public void ValidateWithEventHandler() + { + JsonSchema schema = JsonSchema.Parse("{'pattern':'lol'}"); + JToken stringToken = JToken.FromObject("pie lol"); + + List errors = new List(); + stringToken.Validate(schema, (sender, args) => errors.Add(args.Message)); + Assert.AreEqual(0, errors.Count); + + stringToken = JToken.FromObject("pie"); + + stringToken.Validate(schema, (sender, args) => errors.Add(args.Message)); + Assert.AreEqual(1, errors.Count); + + Assert.AreEqual("String 'pie' does not match regex pattern 'lol'.", errors[0]); + } + + [Test] + [ExpectedException(typeof(JsonSchemaException), ExpectedMessage = @"String 'pie' does not match regex pattern 'lol'.")] + public void ValidateWithOutEventHandlerFailure() + { + JsonSchema schema = JsonSchema.Parse("{'pattern':'lol'}"); + JToken stringToken = JToken.FromObject("pie"); + stringToken.Validate(schema); + } + + [Test] + public void ValidateWithOutEventHandlerSuccess() + { + JsonSchema schema = JsonSchema.Parse("{'pattern':'lol'}"); + JToken stringToken = JToken.FromObject("pie lol"); + stringToken.Validate(schema); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaBuilderTests.cs b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaBuilderTests.cs new file mode 100644 index 000000000..43f912e3d --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaBuilderTests.cs @@ -0,0 +1,436 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json.Schema; +using System.IO; +using Newtonsoft.Json.Linq; + +namespace Newtonsoft.Json.Tests.Schema +{ + public class JsonSchemaBuilderTests : TestFixtureBase + { + [Test] + public void Simple() + { + string json = @"{ + ""description"":""A person"", + ""type"":""object"", + ""properties"": + { + ""name"":{""type"":""string""}, + ""hobbies"": + { + ""type"":""array"", + ""items"": {""type"":""string""} + } + } +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("A person", schema.Description); + Assert.AreEqual(JsonSchemaType.Object, schema.Type); + + Assert.AreEqual(2, schema.Properties.Count); + + Assert.AreEqual(JsonSchemaType.String, schema.Properties["name"].Type); + Assert.AreEqual(JsonSchemaType.Array, schema.Properties["hobbies"].Type); + Assert.AreEqual(JsonSchemaType.String, schema.Properties["hobbies"].Items[0].Type); + } + + [Test] + public void MultipleTypes() + { + string json = @"{ + ""description"":""Age"", + ""type"":[""string"", ""integer""] +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Age", schema.Description); + Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Integer, schema.Type); + } + + [Test] + public void MultipleItems() + { + string json = @"{ + ""description"":""MultipleItems"", + ""type"":""array"", + ""items"": [{""type"":""string""},{""type"":""array""}] +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("MultipleItems", schema.Description); + Assert.AreEqual(JsonSchemaType.String, schema.Items[0].Type); + Assert.AreEqual(JsonSchemaType.Array, schema.Items[1].Type); + } + + [Test] + public void AdditionalProperties() + { + string json = @"{ + ""description"":""AdditionalProperties"", + ""type"":[""string"", ""integer""], + ""additionalProperties"":{""type"":[""object"", ""boolean""]} +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("AdditionalProperties", schema.Description); + Assert.AreEqual(JsonSchemaType.Object | JsonSchemaType.Boolean, schema.AdditionalProperties.Type); + } + + [Test] + public void Optional() + { + string json = @"{ + ""description"":""Optional"", + ""optional"":true +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Optional", schema.Description); + Assert.AreEqual(true, schema.Optional); + } + + [Test] + public void ReadOnly() + { + string json = @"{ + ""description"":""ReadOnly"", + ""readonly"":true +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("ReadOnly", schema.Description); + Assert.AreEqual(true, schema.ReadOnly); + } + + [Test] + public void Hidden() + { + string json = @"{ + ""description"":""Hidden"", + ""hidden"":true +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Hidden", schema.Description); + Assert.AreEqual(true, schema.Hidden); + } + + [Test] + public void Id() + { + string json = @"{ + ""description"":""Id"", + ""id"":""testid"" +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Id", schema.Description); + Assert.AreEqual("testid", schema.Id); + } + + [Test] + public void Title() + { + string json = @"{ + ""description"":""Title"", + ""title"":""testtitle"" +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Title", schema.Description); + Assert.AreEqual("testtitle", schema.Title); + } + + [Test] + public void Pattern() + { + string json = @"{ + ""description"":""Pattern"", + ""pattern"":""testpattern"" +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Pattern", schema.Description); + Assert.AreEqual("testpattern", schema.Pattern); + } + + [Test] + public void Format() + { + string json = @"{ + ""description"":""Format"", + ""format"":""testformat"" +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Format", schema.Description); + Assert.AreEqual("testformat", schema.Format); + } + + [Test] + public void Requires() + { + string json = @"{ + ""description"":""Requires"", + ""requires"":""PurpleMonkeyDishwasher"" +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Requires", schema.Description); + Assert.AreEqual("PurpleMonkeyDishwasher", schema.Requires); + } + + [Test] + public void IdentitySingle() + { + string json = @"{ + ""description"":""Identity"", + ""identity"":""PurpleMonkeyDishwasher"" +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Identity", schema.Description); + Assert.AreEqual(1, schema.Identity.Count); + Assert.AreEqual("PurpleMonkeyDishwasher", schema.Identity[0]); + } + + [Test] + public void IdentityMultiple() + { + string json = @"{ + ""description"":""Identity"", + ""identity"":[""PurpleMonkeyDishwasher"",""Antelope""] +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Identity", schema.Description); + Assert.AreEqual(2, schema.Identity.Count); + Assert.AreEqual("PurpleMonkeyDishwasher", schema.Identity[0]); + Assert.AreEqual("Antelope", schema.Identity[1]); + } + + [Test] + public void MinimumMaximum() + { + string json = @"{ + ""description"":""MinimumMaximum"", + ""minimum"":1.1, + ""maximum"":1.2, + ""minItems"":1, + ""maxItems"":2, + ""minLength"":5, + ""maxLength"":50, + ""maxDecimal"":3, +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("MinimumMaximum", schema.Description); + Assert.AreEqual(1.1, schema.Minimum); + Assert.AreEqual(1.2, schema.Maximum); + Assert.AreEqual(1, schema.MinimumItems); + Assert.AreEqual(2, schema.MaximumItems); + Assert.AreEqual(5, schema.MinimumLength); + Assert.AreEqual(50, schema.MaximumLength); + Assert.AreEqual(3, schema.MaximumDecimals); + } + + [Test] + public void DisallowSingleType() + { + string json = @"{ + ""description"":""DisallowSingleType"", + ""disallow"":""string"" +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("DisallowSingleType", schema.Description); + Assert.AreEqual(JsonSchemaType.String, schema.Disallow); + } + + [Test] + public void DisallowMultipleTypes() + { + string json = @"{ + ""description"":""DisallowMultipleTypes"", + ""disallow"":[""string"",""number""] +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("DisallowMultipleTypes", schema.Description); + Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Float, schema.Disallow); + } + + [Test] + public void DefaultPrimitiveType() + { + string json = @"{ + ""description"":""DefaultPrimitiveType"", + ""default"":1.1 +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("DefaultPrimitiveType", schema.Description); + Assert.AreEqual(1.1, (double)schema.Default); + } + + [Test] + public void DefaultComplexType() + { + string json = @"{ + ""description"":""DefaultComplexType"", + ""default"":{""pie"":true} +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("DefaultComplexType", schema.Description); + Assert.IsTrue(JToken.DeepEquals(JObject.Parse(@"{""pie"":true}"), schema.Default)); + } + + [Test] + public void Options() + { + string json = @"{ + ""description"":""NZ Island"", + ""type"":""string"", + ""options"": + [ + {""value"":""NI"",""label"":""North Island""}, + {""value"":""SI"",""label"":""South Island""} + ] +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("NZ Island", schema.Description); + Assert.AreEqual(JsonSchemaType.String, schema.Type); + + Assert.AreEqual(2, schema.Options.Count); + Assert.AreEqual("North Island", schema.Options[new JValue("NI")]); + Assert.AreEqual("South Island", schema.Options[new JValue("SI")]); + } + + [Test] + public void Enum() + { + string json = @"{ + ""description"":""Type"", + ""type"":[""string"",""array""], + ""enum"":[""string"",""object"",""array"",""boolean"",""number"",""integer"",""null"",""any""] +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("Type", schema.Description); + Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Array, schema.Type); + + Assert.AreEqual(8, schema.Enum.Count); + Assert.AreEqual("string", (string)schema.Enum[0]); + Assert.AreEqual("any", (string)schema.Enum[schema.Enum.Count - 1]); + } + + [Test] + public void CircularReference() + { + string json = @"{ + ""id"":""CircularReferenceArray"", + ""description"":""CircularReference"", + ""type"":[""array""], + ""items"":{""$ref"":""CircularReferenceArray""} +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + + Assert.AreEqual("CircularReference", schema.Description); + Assert.AreEqual("CircularReferenceArray", schema.Id); + Assert.AreEqual(JsonSchemaType.Array, schema.Type); + + Assert.AreEqual(schema, schema.Items[0]); + } + + [Test] + [ExpectedException(typeof(Exception), ExpectedMessage = @"Could not resolve schema reference for Id 'MyUnresolvedReference'.")] + public void UnresolvedReference() + { + string json = @"{ + ""id"":""CircularReferenceArray"", + ""description"":""CircularReference"", + ""type"":[""array""], + ""items"":{""$ref"":""MyUnresolvedReference""} +}"; + + JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); + JsonSchema schema = builder.Parse(new JsonTextReader(new StringReader(json))); + } + } +} diff --git a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs new file mode 100644 index 000000000..7b34c5fd0 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs @@ -0,0 +1,265 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Globalization; +using Newtonsoft.Json.Tests.TestObjects; +using NUnit.Framework; +using Newtonsoft.Json.Schema; + +namespace Newtonsoft.Json.Tests.Schema +{ + public class JsonSchemaGeneratorTests : TestFixtureBase + { + [Test] + public void Generate_GenericDictionary() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + JsonSchema schema = generator.Generate(typeof (Dictionary>)); + + string json = schema.ToString(); + + Assert.AreEqual(@"{ + ""type"": ""object"", + ""additionalProperties"": { + ""type"": ""array"", + ""items"": { + ""type"": ""string"" + } + } +}", json); + } + +#if !PocketPC + [Test] + public void Generate_DefaultValueAttributeTestClass() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + JsonSchema schema = generator.Generate(typeof(DefaultValueAttributeTestClass)); + + string json = schema.ToString(); + + Assert.AreEqual(@"{ + ""description"": ""DefaultValueAttributeTestClass description!"", + ""type"": ""object"", + ""properties"": { + ""TestField1"": { + ""type"": ""integer"", + ""default"": 21 + }, + ""TestProperty1"": { + ""type"": [ + ""string"", + ""null"" + ], + ""default"": ""TestProperty1Value"" + } + } +}", json); + } +#endif + + [Test] + public void Generate_Person() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + JsonSchema schema = generator.Generate(typeof(Person)); + + string json = schema.ToString(); + + Assert.AreEqual(@"{ + ""id"": ""Person"", + ""title"": ""Title!"", + ""description"": ""JsonObjectAttribute description!"", + ""type"": ""object"", + ""properties"": { + ""Name"": { + ""type"": [ + ""string"", + ""null"" + ] + }, + ""BirthDate"": { + ""type"": ""string"" + }, + ""LastModified"": { + ""type"": ""string"" + } + } +}", json); + } + + [Test] + public void Generate_UserNullable() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + JsonSchema schema = generator.Generate(typeof(UserNullable)); + + string json = schema.ToString(); + + Assert.AreEqual(@"{ + ""type"": ""object"", + ""properties"": { + ""Id"": { + ""type"": ""string"" + }, + ""FName"": { + ""type"": [ + ""string"", + ""null"" + ] + }, + ""LName"": { + ""type"": [ + ""string"", + ""null"" + ] + }, + ""RoleId"": { + ""type"": ""integer"" + }, + ""NullableRoleId"": { + ""type"": [ + ""integer"", + ""null"" + ] + }, + ""NullRoleId"": { + ""type"": [ + ""integer"", + ""null"" + ] + }, + ""Active"": { + ""type"": [ + ""boolean"", + ""null"" + ] + } + } +}", json); + } + + [Test] + public void Generate_RequiredMembersClass() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + JsonSchema schema = generator.Generate(typeof(RequiredMembersClass)); + + Assert.AreEqual(JsonSchemaType.String, schema.Properties["FirstName"].Type); + Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Null, schema.Properties["MiddleName"].Type); + Assert.AreEqual(JsonSchemaType.String, schema.Properties["LastName"].Type); + Assert.AreEqual(JsonSchemaType.String, schema.Properties["BirthDate"].Type); + } + + [Test] + public void Generate_Store() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + JsonSchema schema = generator.Generate(typeof(Store)); + + Assert.AreEqual(11, schema.Properties.Count); + + JsonSchema productArraySchema = schema.Properties["product"]; + JsonSchema productSchema = productArraySchema.Items[0]; + + Assert.AreEqual(4, productSchema.Properties.Count); + } + + [Test] + public void MissingSchemaIdHandlingTest() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + + JsonSchema schema = generator.Generate(typeof(Store)); + Assert.AreEqual(null, schema.Id); + + generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName; + schema = generator.Generate(typeof (Store)); + Assert.AreEqual(typeof(Store).FullName, schema.Id); + + generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseAssemblyQualifiedName; + schema = generator.Generate(typeof(Store)); + Assert.AreEqual(typeof(Store).AssemblyQualifiedName, schema.Id); + } + + [Test] + public void Generate_NumberFormatInfo() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + JsonSchema schema = generator.Generate(typeof(NumberFormatInfo)); + + string json = schema.ToString(); + + Console.WriteLine(json); + + // Assert.AreEqual(@"{ + // ""type"": ""object"", + // ""additionalProperties"": { + // ""type"": ""array"", + // ""items"": { + // ""type"": ""string"" + // } + // } + //}", json); + } + + [Test] + [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.")] + public void CircularReferenceError() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + generator.Generate(typeof(CircularReferenceClass)); + } + + [Test] + public void CircularReferenceWithTypeNameId() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName; + + JsonSchema schema = generator.Generate(typeof(CircularReferenceClass), true); + + Assert.AreEqual(JsonSchemaType.String, schema.Properties["Name"].Type); + Assert.AreEqual(typeof(CircularReferenceClass).FullName, schema.Id); + Assert.AreEqual(JsonSchemaType.Object | JsonSchemaType.Null, schema.Properties["Child"].Type); + Assert.AreEqual(schema, schema.Properties["Child"]); + } + + [Test] + public void CircularReferenceWithExplicitId() + { + JsonSchemaGenerator generator = new JsonSchemaGenerator(); + + JsonSchema schema = generator.Generate(typeof(CircularReferenceWithIdClass)); + + Assert.AreEqual(JsonSchemaType.String, schema.Properties["Name"].Type); + Assert.AreEqual("MyExplicitId", schema.Id); + Assert.AreEqual(JsonSchemaType.Object, schema.Properties["Child"].Type); + Assert.AreEqual(schema, schema.Properties["Child"]); + } + } +} diff --git a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaModelBuilderTests.cs b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaModelBuilderTests.cs new file mode 100644 index 000000000..220047e87 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaModelBuilderTests.cs @@ -0,0 +1,166 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Schema; +using NUnit.Framework; + +namespace Newtonsoft.Json.Tests.Schema +{ + public class JsonSchemaModelBuilderTests : TestFixtureBase + { + [Test] + public void ExtendedComplex() + { + string first = @"{ + ""id"":""first"", + ""type"":""object"", + ""properties"": + { + ""firstproperty"":{""type"":""string""}, + ""secondproperty"":{""type"":""string"",""maxLength"":10}, + ""thirdproperty"":{ + ""type"":""object"", + ""properties"": + { + ""thirdproperty_firstproperty"":{""type"":""string"",""maxLength"":10,""minLength"":7} + } + } + }, + ""additionalProperties"":{} +}"; + + string second = @"{ + ""id"":""second"", + ""type"":""object"", + ""extends"":{""$ref"":""first""}, + ""properties"": + { + ""secondproperty"":{""type"":""any""}, + ""thirdproperty"":{ + ""extends"":{ + ""properties"": + { + ""thirdproperty_firstproperty"":{""maxLength"":9,""minLength"":6,""pattern"":""hi2u""} + }, + ""additionalProperties"":{""maxLength"":9,""minLength"":6,""enum"":[""one"",""two""]} + }, + ""type"":""object"", + ""properties"": + { + ""thirdproperty_firstproperty"":{""pattern"":""hi""} + }, + ""additionalProperties"":{""type"":""string"",""enum"":[""two"",""three""]} + }, + ""fourthproperty"":{""type"":""string""} + }, + ""additionalProperties"":false +}"; + + JsonSchemaResolver resolver = new JsonSchemaResolver(); + JsonSchema firstSchema = JsonSchema.Parse(first, resolver); + JsonSchema secondSchema = JsonSchema.Parse(second, resolver); + + JsonSchemaModelBuilder modelBuilder = new JsonSchemaModelBuilder(); + + JsonSchemaModel model = modelBuilder.Build(secondSchema); + + Assert.AreEqual(4, model.Properties.Count); + + Assert.AreEqual(JsonSchemaType.String, model.Properties["firstproperty"].Type); + + Assert.AreEqual(JsonSchemaType.String, model.Properties["secondproperty"].Type); + Assert.AreEqual(10, model.Properties["secondproperty"].MaximumLength); + Assert.AreEqual(null, model.Properties["secondproperty"].Enum); + Assert.AreEqual(null, model.Properties["secondproperty"].Patterns); + + Assert.AreEqual(JsonSchemaType.Object, model.Properties["thirdproperty"].Type); + Assert.AreEqual(3, model.Properties["thirdproperty"].AdditionalProperties.Enum.Count); + Assert.AreEqual("two", (string)model.Properties["thirdproperty"].AdditionalProperties.Enum[0]); + Assert.AreEqual("three", (string)model.Properties["thirdproperty"].AdditionalProperties.Enum[1]); + Assert.AreEqual("one", (string)model.Properties["thirdproperty"].AdditionalProperties.Enum[2]); + + Assert.AreEqual(JsonSchemaType.String, model.Properties["thirdproperty"].Properties["thirdproperty_firstproperty"].Type); + Assert.AreEqual(9, model.Properties["thirdproperty"].Properties["thirdproperty_firstproperty"].MaximumLength); + Assert.AreEqual(7, model.Properties["thirdproperty"].Properties["thirdproperty_firstproperty"].MinimumLength); + Assert.AreEqual(2, model.Properties["thirdproperty"].Properties["thirdproperty_firstproperty"].Patterns.Count); + Assert.AreEqual("hi", model.Properties["thirdproperty"].Properties["thirdproperty_firstproperty"].Patterns[0]); + Assert.AreEqual("hi2u", model.Properties["thirdproperty"].Properties["thirdproperty_firstproperty"].Patterns[1]); + Assert.AreEqual(null, model.Properties["thirdproperty"].Properties["thirdproperty_firstproperty"].Properties); + Assert.AreEqual(null, model.Properties["thirdproperty"].Properties["thirdproperty_firstproperty"].Items); + Assert.AreEqual(null, model.Properties["thirdproperty"].Properties["thirdproperty_firstproperty"].AdditionalProperties); + } + + [Test] + public void CircularReference() + { + string json = @"{ + ""id"":""CircularReferenceArray"", + ""description"":""CircularReference"", + ""type"":[""array""], + ""items"":{""$ref"":""CircularReferenceArray""} +}"; + + JsonSchema schema = JsonSchema.Parse(json); + + JsonSchemaModelBuilder modelBuilder = new JsonSchemaModelBuilder(); + + JsonSchemaModel model = modelBuilder.Build(schema); + + Assert.AreEqual(JsonSchemaType.Array, model.Type); + + Assert.AreEqual(model, model.Items[0]); + } + + [Test] + public void Optional() + { + string schemaJson = @"{ + ""description"":""A person"", + ""type"":""object"", + ""properties"": + { + ""name"":{""type"":""string""}, + ""hobbies"":{""type"":""string"",optional:true}, + ""age"":{""type"":""integer"",optional:true} + } +}"; + + JsonSchema schema = JsonSchema.Parse(schemaJson); + JsonSchemaModelBuilder modelBuilder = new JsonSchemaModelBuilder(); + JsonSchemaModel model = modelBuilder.Build(schema); + + Assert.AreEqual(JsonSchemaType.Object, model.Type); + Assert.AreEqual(3, model.Properties.Count); + Assert.AreEqual(false, model.Properties["name"].Optional); + Assert.AreEqual(true, model.Properties["hobbies"].Optional); + Assert.AreEqual(true, model.Properties["age"].Optional); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaNodeTests.cs b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaNodeTests.cs new file mode 100644 index 000000000..d5a8de128 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaNodeTests.cs @@ -0,0 +1,118 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Schema; +using NUnit.Framework; + +namespace Newtonsoft.Json.Tests.Schema +{ + public class JsonSchemaNodeTests : TestFixtureBase + { + [Test] + public void AddSchema() + { + string first = @"{ + ""id"":""first"", + ""type"":""object"", + ""properties"": + { + ""firstproperty"":{""type"":""string"",""maxLength"":10}, + ""secondproperty"":{ + ""type"":""object"", + ""properties"": + { + ""secondproperty_firstproperty"":{""type"":""string"",""maxLength"":10,""minLength"":7} + } + } + }, + ""additionalProperties"":{} +}"; + + string second = @"{ + ""id"":""second"", + ""type"":""object"", + ""extends"":{""$ref"":""first""}, + ""properties"": + { + ""firstproperty"":{""type"":""string""}, + ""secondproperty"":{ + ""extends"":{ + ""properties"": + { + ""secondproperty_firstproperty"":{""maxLength"":9,""minLength"":6} + } + }, + ""type"":""object"", + ""properties"": + { + ""secondproperty_firstproperty"":{} + } + }, + ""thirdproperty"":{""type"":""string""} + }, + ""additionalProperties"":false +}"; + + JsonSchemaResolver resolver = new JsonSchemaResolver(); + JsonSchema firstSchema = JsonSchema.Parse(first, resolver); + JsonSchema secondSchema = JsonSchema.Parse(second, resolver); + + JsonSchemaModelBuilder modelBuilder = new JsonSchemaModelBuilder(); + + JsonSchemaNode node = modelBuilder.AddSchema(null, secondSchema); + + Assert.AreEqual(2, node.Schemas.Count); + Assert.AreEqual(2, node.Properties["firstproperty"].Schemas.Count); + Assert.AreEqual(3, node.Properties["secondproperty"].Schemas.Count); + Assert.AreEqual(3, node.Properties["secondproperty"].Properties["secondproperty_firstproperty"].Schemas.Count); + } + + [Test] + public void CircularReference() + { + string json = @"{ + ""id"":""CircularReferenceArray"", + ""description"":""CircularReference"", + ""type"":[""array""], + ""items"":{""$ref"":""CircularReferenceArray""} +}"; + + JsonSchema schema = JsonSchema.Parse(json); + + JsonSchemaModelBuilder modelBuilder = new JsonSchemaModelBuilder(); + + JsonSchemaNode node = modelBuilder.AddSchema(null, schema); + + Assert.AreEqual(1, node.Schemas.Count); + + Assert.AreEqual(node, node.Items[0]); + } + + } +} diff --git a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaTests.cs b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaTests.cs new file mode 100644 index 000000000..4051ea953 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaTests.cs @@ -0,0 +1,344 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Schema; +using NUnit.Framework; + +namespace Newtonsoft.Json.Tests.Schema +{ + public class JsonSchemaTests : TestFixtureBase + { + [Test] + public void Extends() + { + string json; + JsonSchemaResolver resolver = new JsonSchemaResolver(); + + json = @"{ + ""id"":""first"", + ""type"":""object"", + ""additionalProperties"":{} +}"; + + JsonSchema first = JsonSchema.Parse(json, resolver); + + json = + @"{ + ""id"":""second"", + ""type"":""object"", + ""extends"":{""$ref"":""first""}, + ""additionalProperties"":{""type"":""string""} +}"; + + JsonSchema second = JsonSchema.Parse(json, resolver); + Assert.AreEqual(first, second.Extends); + + json = + @"{ + ""id"":""third"", + ""type"":""object"", + ""extends"":{""$ref"":""second""}, + ""additionalProperties"":false +}"; + + JsonSchema third = JsonSchema.Parse(json, resolver); + Assert.AreEqual(second, third.Extends); + Assert.AreEqual(first, third.Extends.Extends); + + StringWriter writer = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(writer); + jsonWriter.Formatting = Formatting.Indented; + + third.WriteTo(jsonWriter, resolver); + + string writtenJson = writer.ToString(); + Assert.AreEqual(@"{ + ""id"": ""third"", + ""type"": ""object"", + ""additionalProperties"": false, + ""extends"": { + ""$ref"": ""second"" + } +}", writtenJson); + + StringWriter writer1 = new StringWriter(); + JsonTextWriter jsonWriter1 = new JsonTextWriter(writer1); + jsonWriter1.Formatting = Formatting.Indented; + + third.WriteTo(jsonWriter1); + + writtenJson = writer1.ToString(); + Assert.AreEqual(@"{ + ""id"": ""third"", + ""type"": ""object"", + ""additionalProperties"": false, + ""extends"": { + ""id"": ""second"", + ""type"": ""object"", + ""additionalProperties"": { + ""type"": ""string"" + }, + ""extends"": { + ""id"": ""first"", + ""type"": ""object"", + ""additionalProperties"": {} + } + } +}", writtenJson); + } + [Test] + public void WriteTo_AdditionalProperties() + { + StringWriter writer = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(writer); + jsonWriter.Formatting = Formatting.Indented; + + JsonSchema schema = JsonSchema.Parse(@"{ + ""description"":""AdditionalProperties"", + ""type"":[""string"", ""integer""], + ""additionalProperties"":{""type"":[""object"", ""boolean""]} +}"); + + schema.WriteTo(jsonWriter); + + string json = writer.ToString(); + + Assert.AreEqual(@"{ + ""description"": ""AdditionalProperties"", + ""type"": [ + ""string"", + ""integer"" + ], + ""additionalProperties"": { + ""type"": [ + ""boolean"", + ""object"" + ] + } +}", json); + } + + [Test] + public void WriteTo_Properties() + { + JsonSchema schema = JsonSchema.Parse(@"{ + ""description"":""A person"", + ""type"":""object"", + ""properties"": + { + ""name"":{""type"":""string""}, + ""hobbies"": + { + ""type"":""array"", + ""items"": {""type"":""string""} + } + } +}"); + + StringWriter writer = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(writer); + jsonWriter.Formatting = Formatting.Indented; + + schema.WriteTo(jsonWriter); + + string json = writer.ToString(); + + Assert.AreEqual(@"{ + ""description"": ""A person"", + ""type"": ""object"", + ""properties"": { + ""name"": { + ""type"": ""string"" + }, + ""hobbies"": { + ""type"": ""array"", + ""items"": { + ""type"": ""string"" + } + } + } +}", json); + + } + + [Test] + public void WriteTo_Enum() + { + JsonSchema schema = JsonSchema.Parse(@"{ + ""description"":""Type"", + ""type"":[""string"",""array""], + ""items"":{}, + ""enum"":[""string"",""object"",""array"",""boolean"",""number"",""integer"",""null"",""any""] +}"); + + StringWriter writer = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(writer); + jsonWriter.Formatting = Formatting.Indented; + + schema.WriteTo(jsonWriter); + + string json = writer.ToString(); + + Assert.AreEqual(@"{ + ""description"": ""Type"", + ""type"": [ + ""string"", + ""array"" + ], + ""items"": {}, + ""enum"": [ + ""string"", + ""object"", + ""array"", + ""boolean"", + ""number"", + ""integer"", + ""null"", + ""any"" + ] +}", json); + } + + [Test] + public void WriteTo_CircularReference() + { + string json = @"{ + ""id"":""CircularReferenceArray"", + ""description"":""CircularReference"", + ""type"":[""array""], + ""items"":{""$ref"":""CircularReferenceArray""} +}"; + + JsonSchema schema = JsonSchema.Parse(json); + + StringWriter writer = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(writer); + jsonWriter.Formatting = Formatting.Indented; + + schema.WriteTo(jsonWriter); + + string writtenJson = writer.ToString(); + + Assert.AreEqual(@"{ + ""id"": ""CircularReferenceArray"", + ""description"": ""CircularReference"", + ""type"": ""array"", + ""items"": { + ""$ref"": ""CircularReferenceArray"" + } +}", writtenJson); + } + + [Test] + public void WriteTo_DisallowMultiple() + { + JsonSchema schema = JsonSchema.Parse(@"{ + ""description"":""Type"", + ""type"":[""string"",""array""], + ""items"":{}, + ""disallow"":[""string"",""object"",""array""] +}"); + + StringWriter writer = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(writer); + jsonWriter.Formatting = Formatting.Indented; + + schema.WriteTo(jsonWriter); + + string json = writer.ToString(); + + Assert.AreEqual(@"{ + ""description"": ""Type"", + ""type"": [ + ""string"", + ""array"" + ], + ""items"": {}, + ""disallow"": [ + ""string"", + ""object"", + ""array"" + ] +}", json); + } + + [Test] + public void WriteTo_DisallowSingle() + { + JsonSchema schema = JsonSchema.Parse(@"{ + ""description"":""Type"", + ""type"":[""string"",""array""], + ""items"":{}, + ""disallow"":""any"" +}"); + + StringWriter writer = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(writer); + jsonWriter.Formatting = Formatting.Indented; + + schema.WriteTo(jsonWriter); + + string json = writer.ToString(); + + Assert.AreEqual(@"{ + ""description"": ""Type"", + ""type"": [ + ""string"", + ""array"" + ], + ""items"": {}, + ""disallow"": ""any"" +}", json); + } + + [Test] + public void WriteTo_MultipleItems() + { + JsonSchema schema = JsonSchema.Parse(@"{ + ""items"":[{},{}] +}"); + + StringWriter writer = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(writer); + jsonWriter.Formatting = Formatting.Indented; + + schema.WriteTo(jsonWriter); + + string json = writer.ToString(); + + Assert.AreEqual(@"{ + ""items"": [ + {}, + {} + ] +}", json); + } + } +} diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/AbstractGenericBase.cs b/Src/Newtonsoft.Json.Tests/TestObjects/AbstractGenericBase.cs new file mode 100644 index 000000000..50d510ed3 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/AbstractGenericBase.cs @@ -0,0 +1,32 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public abstract class AbstractGenericBase + { + public abstract TKey Id { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ArgumentConverterPrecedenceClassConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ArgumentConverterPrecedenceClassConverter.cs new file mode 100644 index 000000000..c7e46a209 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ArgumentConverterPrecedenceClassConverter.cs @@ -0,0 +1,35 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ArgumentConverterPrecedenceClassConverter : ConverterPrecedenceClassConverter + { + public override string ConverterType + { + get { return "Argument"; } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Article.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Article.cs new file mode 100644 index 000000000..2139c4c43 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Article.cs @@ -0,0 +1,41 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class Article + { + public string Name; + + public Article() + { + } + + public Article(string name) + { + Name = name; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ArticleCollection.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ArticleCollection.cs new file mode 100644 index 000000000..3a1198bf0 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ArticleCollection.cs @@ -0,0 +1,33 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System.Collections.Generic; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ArticleCollection : List
+ { + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/BadJsonPropertyClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/BadJsonPropertyClass.cs new file mode 100644 index 000000000..5190017e5 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/BadJsonPropertyClass.cs @@ -0,0 +1,35 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class BadJsonPropertyClass + { + [JsonProperty("pie")] + public string Pie = "Yum"; + + public string pie = "PieChart!"; + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/CircularReferenceClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/CircularReferenceClass.cs new file mode 100644 index 000000000..fe92bd1d8 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/CircularReferenceClass.cs @@ -0,0 +1,39 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class CircularReferenceClass + { + [JsonProperty(IsRequired = true)] + public string Name { get; set; } + public CircularReferenceClass Child { get; set; } + } +} diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/CircularReferenceWithIdClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/CircularReferenceWithIdClass.cs new file mode 100644 index 000000000..8c1824136 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/CircularReferenceWithIdClass.cs @@ -0,0 +1,40 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + [JsonObject(Id = "MyExplicitId")] + public class CircularReferenceWithIdClass + { + [JsonProperty(IsRequired = true)] + public string Name { get; set; } + public CircularReferenceWithIdClass Child { get; set; } + } +} diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ClassAndMemberConverterClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ClassAndMemberConverterClass.cs new file mode 100644 index 000000000..83dc23973 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ClassAndMemberConverterClass.cs @@ -0,0 +1,34 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ClassAndMemberConverterClass + { + public ConverterPrecedenceClass DefaultConverter { get; set; } + [JsonConverter(typeof(MemberConverterPrecedenceClassConverter))] + public ConverterPrecedenceClass MemberConverter { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ClassConverterPrecedenceClassConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ClassConverterPrecedenceClassConverter.cs new file mode 100644 index 000000000..90b123638 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ClassConverterPrecedenceClassConverter.cs @@ -0,0 +1,35 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ClassConverterPrecedenceClassConverter : ConverterPrecedenceClassConverter + { + public override string ConverterType + { + get { return "Class"; } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ClassWithArray.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ClassWithArray.cs new file mode 100644 index 000000000..971fc422d --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ClassWithArray.cs @@ -0,0 +1,54 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ClassWithArray + { + private readonly IList bar; + private string foo; + + public ClassWithArray() + { + bar = new List() { int.MaxValue }; + } + + [JsonProperty("foo")] + public string Foo + { + get { return foo; } + set { foo = value; } + } + + [JsonProperty(PropertyName = "bar")] + public IList Bar + { + get { return bar; } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ClassWithGuid.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ClassWithGuid.cs new file mode 100644 index 000000000..84141fd6d --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ClassWithGuid.cs @@ -0,0 +1,34 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ClassWithGuid + { + public Guid GuidField; + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConstructorCaseSensitivityClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConstructorCaseSensitivityClass.cs new file mode 100644 index 000000000..41e535d6d --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConstructorCaseSensitivityClass.cs @@ -0,0 +1,41 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ConstructorCaseSensitivityClass + { + public string param1 { get; set; } + public string Param1 { get; set; } + public string Param2 { get; set; } + + public ConstructorCaseSensitivityClass(string param1, string Param1, string param2) + { + this.param1 = param1; + this.Param1 = Param1; + this.Param2 = param2; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConverableMembers.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConverableMembers.cs new file mode 100644 index 000000000..9b2e10143 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConverableMembers.cs @@ -0,0 +1,48 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + [JsonObject] + public class ConverableMembers + { + public string String = "string"; + public int Int32 = int.MaxValue; + public uint UInt32 = uint.MaxValue; + public byte Byte = byte.MaxValue; + public sbyte SByte = sbyte.MaxValue; + public short Short = short.MaxValue; + public ushort UShort = ushort.MaxValue; + public long Long = long.MaxValue; + public ulong ULong = long.MaxValue; + public double Double = double.MaxValue; + public float Float = float.MaxValue; + public DBNull DBNull = DBNull.Value; + public bool Bool = true; + public char Char = '\0'; + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClass.cs new file mode 100644 index 000000000..dfd2e2bdc --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClass.cs @@ -0,0 +1,38 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + [JsonConverter(typeof(ClassConverterPrecedenceClassConverter))] + public class ConverterPrecedenceClass + { + public string TestValue { get; set; } + + public ConverterPrecedenceClass(string testValue) + { + TestValue = testValue; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs new file mode 100644 index 000000000..7f5879862 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs @@ -0,0 +1,63 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Globalization; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public abstract class ConverterPrecedenceClassConverter : JsonConverter + { + public abstract string ConverterType { get; } + + public override void WriteJson(JsonWriter writer, object value) + { + ConverterPrecedenceClass c = (ConverterPrecedenceClass)value; + + JToken j = new JArray(ConverterType, c.TestValue); + + j.WriteTo(writer); + } + + public override object ReadJson(JsonReader reader, Type objectType) + { + JToken j = JArray.Load(reader); + + string converter = (string)j[0]; + if (converter != ConverterType) + throw new Exception(StringUtils.FormatWith("Serialize converter {0} and deserialize converter {1} do not match.", CultureInfo.InvariantCulture, converter, ConverterType)); + + string testValue = (string)j[1]; + return new ConverterPrecedenceClass(testValue); + } + + public override bool CanConvert(Type objectType) + { + return (objectType == typeof(ConverterPrecedenceClass)); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/DateTimeTestClass.cs similarity index 94% rename from Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs rename to Src/Newtonsoft.Json.Tests/TestObjects/DateTimeTestClass.cs index ad79bd7ed..fe49cd322 100644 --- a/Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/DateTimeTestClass.cs @@ -28,7 +28,7 @@ using System.Linq; using System.Text; -namespace Newtonsoft.Json.Tests +namespace Newtonsoft.Json.Tests.TestObjects { public class DateTimeTestClass { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/DefaultValueAttributeTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/DefaultValueAttributeTestClass.cs new file mode 100644 index 000000000..861c709a6 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/DefaultValueAttributeTestClass.cs @@ -0,0 +1,41 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System.ComponentModel; + +namespace Newtonsoft.Json.Tests.TestObjects +{ +#if !PocketPC + [Description("DefaultValueAttributeTestClass description!")] +#endif + public class DefaultValueAttributeTestClass + { + [DefaultValue("TestProperty1Value")] + public string TestProperty1 { get; set; } + + [DefaultValue(21)] + public int TestField1; + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/DoubleClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/DoubleClass.cs new file mode 100644 index 000000000..2de57336a --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/DoubleClass.cs @@ -0,0 +1,32 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class DoubleClass + { + public double? Height { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/GenericImpl.cs b/Src/Newtonsoft.Json.Tests/TestObjects/GenericImpl.cs new file mode 100644 index 000000000..cd6d11a18 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/GenericImpl.cs @@ -0,0 +1,32 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class GenericImpl : AbstractGenericBase + { + public override int Id { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/GetOnlyPropertyClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/GetOnlyPropertyClass.cs new file mode 100644 index 000000000..a45ffcee8 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/GetOnlyPropertyClass.cs @@ -0,0 +1,37 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class GetOnlyPropertyClass + { + public string Field = "Field"; + + public string GetOnlyProperty + { + get { return "GetOnlyProperty"; } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/IncompatibleJsonAttributeClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/IncompatibleJsonAttributeClass.cs new file mode 100644 index 000000000..eb86156ed --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/IncompatibleJsonAttributeClass.cs @@ -0,0 +1,34 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using Newtonsoft.Json.Converters; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + [JsonConverter(typeof(IsoDateTimeConverter))] + public class IncompatibleJsonAttributeClass + { + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Invoice.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Invoice.cs new file mode 100644 index 000000000..7d0554b6e --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Invoice.cs @@ -0,0 +1,40 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.ComponentModel; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class Invoice + { + public string Company { get; set; } + public decimal Amount { get; set; } + [DefaultValue(false)] + public bool Paid { get; set; } + [DefaultValue(null)] + public DateTime? PaidDate { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/JsonIgnoreAttributeOnClassTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/JsonIgnoreAttributeOnClassTestClass.cs new file mode 100644 index 000000000..733c8d0cc --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/JsonIgnoreAttributeOnClassTestClass.cs @@ -0,0 +1,52 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + [JsonObject(MemberSerialization.OptIn)] + public class JsonIgnoreAttributeOnClassTestClass + { + private int _property = 21; + private int _ignoredProperty = 12; + + [JsonProperty("TheField")] + public int Field; + + [JsonProperty] + public int Property + { + get { return _property; } + } + + public int IgnoredField; + + [JsonProperty] + [JsonIgnore] // JsonIgnore should take priority + public int IgnoredProperty + { + get { return _ignoredProperty; } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/JsonIgnoreAttributeTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/JsonIgnoreAttributeTestClass.cs new file mode 100644 index 000000000..bf688271e --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/JsonIgnoreAttributeTestClass.cs @@ -0,0 +1,51 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class JsonIgnoreAttributeTestClass + { + private int _property = 21; + private int _ignoredProperty = 12; + + public int Field; + public int Property + { + get { return _property; } + } + + [JsonIgnore] + public int IgnoredField; + + [JsonIgnore] + public int IgnoredProperty + { + get { return _ignoredProperty; } + } + + [JsonIgnore] + public Product IgnoredObject = new Product(); + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/MemberConverterClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/MemberConverterClass.cs new file mode 100644 index 000000000..4a5e983c6 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/MemberConverterClass.cs @@ -0,0 +1,37 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using Newtonsoft.Json.Converters; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class MemberConverterClass + { + public DateTime DefaultConverter { get; set; } + [JsonConverter(typeof(IsoDateTimeConverter))] + public DateTime MemberConverter { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/MemberConverterPrecedenceClassConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/MemberConverterPrecedenceClassConverter.cs new file mode 100644 index 000000000..8df807fbf --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/MemberConverterPrecedenceClassConverter.cs @@ -0,0 +1,35 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class MemberConverterPrecedenceClassConverter : ConverterPrecedenceClassConverter + { + public override string ConverterType + { + get { return "Member"; } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/MethodExecutorObject.cs b/Src/Newtonsoft.Json.Tests/TestObjects/MethodExecutorObject.cs new file mode 100644 index 000000000..c7c5edd49 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/MethodExecutorObject.cs @@ -0,0 +1,34 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class MethodExecutorObject + { + public string serverClassName; + public object[] serverMethodParams; + public string clientGetResultFunction; + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/MyClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/MyClass.cs new file mode 100644 index 000000000..f80a2c54a --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/MyClass.cs @@ -0,0 +1,34 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class MyClass + { + public int PreProperty { get; set; } + //public DateTime DateProperty { get; set; } + public int PostProperty { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Name.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Name.cs new file mode 100644 index 000000000..5663e00b5 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Name.cs @@ -0,0 +1,41 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System.Collections.Generic; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class Name + { + public string personsName; + + public List pNumbers = new List(); + + public Name(string personsName) + { + this.personsName = personsName; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Person.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Person.cs new file mode 100644 index 000000000..159473c97 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Person.cs @@ -0,0 +1,54 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.ComponentModel; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + [JsonObject(Id = "Person", Title = "Title!", Description = "JsonObjectAttribute description!", MemberSerialization = MemberSerialization.OptIn)] +#if !PocketPC + [Description("DescriptionAttribute description!")] +#endif + public class Person + { + // "John Smith" + [JsonProperty] + public string Name { get; set; } + + // "2000-12-15T22:11:03" + [JsonProperty] + //[JsonConverter(typeof(IsoDateTimeConverter))] + public DateTime BirthDate { get; set; } + + // new Date(976918263055) + [JsonProperty] + //[JsonConverter(typeof(JavaScriptDateTimeConverter))] + public DateTime LastModified { get; set; } + + // not serialized + public string Department { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PersonRaw.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PersonRaw.cs new file mode 100644 index 000000000..2797fff24 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PersonRaw.cs @@ -0,0 +1,64 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class PersonRaw + { + private Guid _internalId; + private string _firstName; + private string _lastName; + private JsonRaw _rawContent; + + [JsonIgnore] + public Guid InternalId + { + get { return _internalId; } + set { _internalId = value; } + } + + [JsonProperty("first_name")] + public string FirstName + { + get { return _firstName; } + set { _firstName = value; } + } + + public JsonRaw RawContent + { + get { return _rawContent; } + set { _rawContent = value; } + } + + [JsonProperty("last_name")] + public string LastName + { + get { return _lastName; } + set { _lastName = value; } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PhoneNumber.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PhoneNumber.cs new file mode 100644 index 000000000..541b2fe0b --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PhoneNumber.cs @@ -0,0 +1,37 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class PhoneNumber + { + public string phoneNumber; + + public PhoneNumber(string phoneNumber) + { + this.phoneNumber = phoneNumber; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Product.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Product.cs new file mode 100644 index 000000000..466987946 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Product.cs @@ -0,0 +1,54 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class Product + { + public string Name; + public DateTime Expiry = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc); + public decimal Price; + public string[] Sizes; + + public override bool Equals(object obj) + { + if (obj is Product) + { + Product p = (Product)obj; + + return (p.Name == Name && p.Expiry == Expiry && p.Price == Price); + } + + return base.Equals(obj); + } + + public override int GetHashCode() + { + return (Name ?? string.Empty).GetHashCode(); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ProductCollection.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ProductCollection.cs new file mode 100644 index 000000000..c2ae85417 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ProductCollection.cs @@ -0,0 +1,33 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System.Collections.Generic; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ProductCollection : List + { + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ProductShort.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ProductShort.cs new file mode 100644 index 000000000..718d2aa95 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ProductShort.cs @@ -0,0 +1,37 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ProductShort + { + public string Name; + public DateTime Expiry; + //public decimal Price; + public string[] Sizes; + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/RequiredMembersClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/RequiredMembersClass.cs new file mode 100644 index 000000000..ae62e9d82 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/RequiredMembersClass.cs @@ -0,0 +1,47 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class RequiredMembersClass + { + [JsonProperty(IsRequired = true)] + public string FirstName { get; set; } + + [JsonProperty] + public string MiddleName { get; set; } + + [JsonProperty(IsRequired = true)] + public string LastName { get; set; } + + [JsonProperty(IsRequired = true)] + public DateTime BirthDate { get; set; } + } +} diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/SetOnlyPropertyClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/SetOnlyPropertyClass.cs new file mode 100644 index 000000000..5af03cd29 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/SetOnlyPropertyClass.cs @@ -0,0 +1,37 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class SetOnlyPropertyClass + { + public string Field = "Field"; + + public string SetOnlyProperty + { + set { } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Store.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Store.cs new file mode 100644 index 000000000..faffddb84 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Store.cs @@ -0,0 +1,62 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class Store + { + public StoreColor Color = StoreColor.Yellow; + public DateTimeOffset Establised = new DateTimeOffset(2010, 1, 22, 1, 1, 1, TimeSpan.Zero); + public double Width = 1.1; + public int Employees = 999; + public int[] RoomsPerFloor = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + public bool Open = false; + public char Symbol = '@'; + public List Mottos = new List(); + public decimal Cost = 100980.1M; + public string Escape = "\r\n\t\f\b?{\\r\\n\"\'"; + public List product = new List(); + + public Store() + { + Mottos.Add("Hello World"); + Mottos.Add("öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"); + Mottos.Add(null); + Mottos.Add(" "); + + Product rocket = new Product(); + rocket.Name = "Rocket"; + rocket.Expiry = new DateTime(2000, 2, 2, 23, 1, 30, DateTimeKind.Utc); + Product alien = new Product(); + alien.Name = "Alien"; + + product.Add(rocket); + product.Add(alien); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/StoreColor.cs b/Src/Newtonsoft.Json.Tests/TestObjects/StoreColor.cs new file mode 100644 index 000000000..43cf7fbc1 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/StoreColor.cs @@ -0,0 +1,35 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public enum StoreColor + { + Black, + Red, + Yellow, + White + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/TypeClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/TypeClass.cs new file mode 100644 index 000000000..5bf2fc9b7 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/TypeClass.cs @@ -0,0 +1,34 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class TypeClass + { + public Type TypeProperty { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/TypedSubHashtable.cs b/Src/Newtonsoft.Json.Tests/TestObjects/TypedSubHashtable.cs new file mode 100644 index 000000000..1c8efe8bb --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/TypedSubHashtable.cs @@ -0,0 +1,37 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System.Collections; + +namespace Newtonsoft.Json.Tests.TestObjects +{ +#if !SILVERLIGHT + public class TypedSubHashtable + { + public string Name; + public Hashtable Hash; + } +#endif +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/UserNullable.cs b/Src/Newtonsoft.Json.Tests/TestObjects/UserNullable.cs new file mode 100644 index 000000000..9c16dbe7e --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/UserNullable.cs @@ -0,0 +1,40 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class UserNullable + { + public Guid Id; + public string FName; + public string LName; + public int RoleId; + public int? NullableRoleId; + public int? NullRoleId; + public bool? Active; + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonArrayAttribute.cs b/Src/Newtonsoft.Json/JsonArrayAttribute.cs new file mode 100644 index 000000000..4ea4b400e --- /dev/null +++ b/Src/Newtonsoft.Json/JsonArrayAttribute.cs @@ -0,0 +1,72 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// Instructs the how to serialize the object. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] + public sealed class JsonArrayAttribute : JsonContainerAttribute + { + private bool _allowNullItems; + + public bool AllowNullItems + { + get { return _allowNullItems; } + set { _allowNullItems = value; } + } + + /// + /// Initializes a new instance of the class. + /// + public JsonArrayAttribute() + { + } + + /// + /// Initializes a new instance of the class with a flag indicating whether the array can contain null items + /// + /// A flag indicating whether the array can contain null items. + public JsonArrayAttribute(bool allowNullItems) + { + _allowNullItems = allowNullItems; + } + + /// + /// Initializes a new instance of the class with the specified container Id. + /// + /// The container Id. + public JsonArrayAttribute(string id) + : base(id) + { + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonContainerAttribute.cs b/Src/Newtonsoft.Json/JsonContainerAttribute.cs new file mode 100644 index 000000000..bb88c1689 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonContainerAttribute.cs @@ -0,0 +1,59 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// Instructs the how to serialize the object. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] + public abstract class JsonContainerAttribute : Attribute + { + public string Id { get; set; } + public string Title { get; set; } + public string Description { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public JsonContainerAttribute() + { + } + + /// + /// Initializes a new instance of the class with the specified container Id. + /// + /// The container Id. + public JsonContainerAttribute(string id) + { + Id = id; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs index dc8226e7c..2fa505f33 100644 --- a/Src/Newtonsoft.Json/JsonConvert.cs +++ b/Src/Newtonsoft.Json/JsonConvert.cs @@ -38,7 +38,7 @@ namespace Newtonsoft.Json { /// - /// Provides methods for converting between common language runtime types and JavaScript types. + /// Provides methods for converting between common language runtime types and JSON types. /// public static class JsonConvert { @@ -255,7 +255,7 @@ public static string ToString(ulong value) /// A Json string representation of the . public static string ToString(float value) { - return value.ToString("R", CultureInfo.InvariantCulture); + return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)); } /// @@ -265,7 +265,15 @@ public static string ToString(float value) /// A Json string representation of the . public static string ToString(double value) { - return value.ToString("R", CultureInfo.InvariantCulture); + return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)); + } + + private static string EnsureDecimalPlace(double value, string text) + { + if (double.IsNaN(value) || double.IsInfinity(value) || text.IndexOf('.') != -1 || text.IndexOf('E') != -1) + return text; + + return text + ".0"; } /// diff --git a/Src/Newtonsoft.Json/JsonObjectAttribute.cs b/Src/Newtonsoft.Json/JsonObjectAttribute.cs index 568b71e98..79b5e8b23 100644 --- a/Src/Newtonsoft.Json/JsonObjectAttribute.cs +++ b/Src/Newtonsoft.Json/JsonObjectAttribute.cs @@ -34,7 +34,7 @@ namespace Newtonsoft.Json /// Instructs the how to serialize the object. /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] - public sealed class JsonObjectAttribute : Attribute + public sealed class JsonObjectAttribute : JsonContainerAttribute { private MemberSerialization _memberSerialization = MemberSerialization.OptOut; @@ -63,5 +63,14 @@ public JsonObjectAttribute(MemberSerialization memberSerialization) { MemberSerialization = memberSerialization; } + + /// + /// Initializes a new instance of the class with the specified container Id. + /// + /// The container Id. + public JsonObjectAttribute(string id) + : base(id) + { + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs index e6049ea83..c05f449e0 100644 --- a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs +++ b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs @@ -9,6 +9,7 @@ namespace Newtonsoft.Json public sealed class JsonPropertyAttribute : Attribute { private string _propertyName; + private bool _isRequired; /// /// Gets or sets the name of the property. @@ -20,6 +21,12 @@ public string PropertyName set { _propertyName = value; } } + public bool IsRequired + { + get { return _isRequired; } + set { _isRequired = value; } + } + /// /// Initializes a new instance of the class. /// diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index cc3ab4c94..7dd7dd7d1 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -25,9 +25,7 @@ using System; using System.Collections.Generic; -using System.Text; using System.IO; -using System.Xml; using System.Globalization; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Utilities; @@ -117,21 +115,21 @@ protected State CurrentState private int _top; - private List _stack; + private readonly List _stack; /// /// Gets the quotation mark character used to enclose the value of a string. /// - public char QuoteChar + public virtual char QuoteChar { get { return _quoteChar; } - protected set { _quoteChar = value; } + protected internal set { _quoteChar = value; } } /// /// Gets the type of the current Json token. /// - public JsonToken TokenType + public virtual JsonToken TokenType { get { return _token; } } @@ -139,7 +137,7 @@ public JsonToken TokenType /// /// Gets the text value of the current Json token. /// - public object Value + public virtual object Value { get { return _value; } } @@ -147,7 +145,7 @@ public object Value /// /// Gets The Common Language Runtime (CLR) type for the current Json token. /// - public Type ValueType + public virtual Type ValueType { get { return _valueType; } } @@ -156,7 +154,7 @@ public Type ValueType /// Gets the depth of the current token in the JSON document. /// /// The depth of the current token in the JSON document. - public int Depth + public virtual int Depth { get { @@ -331,7 +329,7 @@ protected void SetStateBasedOnCurrent() } } - private bool IsStartToken(JsonToken token) + internal static bool IsStartToken(JsonToken token) { switch (token) { diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs index d282ba6b3..511e8ecd0 100644 --- a/Src/Newtonsoft.Json/JsonSerializer.cs +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -30,6 +30,7 @@ using System.Collections; using System.Reflection; using System.ComponentModel; +using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Utilities; using System.Globalization; using System.Linq; @@ -44,9 +45,7 @@ namespace Newtonsoft.Json /// public class JsonSerializer { - private static readonly Dictionary ConverterTypeCache = new Dictionary(); - private static readonly Dictionary TypeMemberMappingsCache = new Dictionary(); - + #region Properties private ReferenceLoopHandling _referenceLoopHandling; private MissingMemberHandling _missingMemberHandling; private ObjectCreationHandling _objectCreationHandling; @@ -145,6 +144,7 @@ public JsonConverterCollection Converters return _converters; } } + #endregion /// /// Initializes a new instance of the class. @@ -244,7 +244,7 @@ private bool HasClassConverter(Type objectType, out JsonConverter converter) if (objectType == null) throw new ArgumentNullException("objectType"); - converter = GetConverter(objectType, objectType); + converter = JsonTypeReflector.GetConverter(objectType, objectType); return (converter != null); } @@ -282,7 +282,7 @@ private object CreateObject(JsonReader reader, Type objectType, object existingV { value = CreateJToken(reader); } - else if (typeof(IDictionary).IsAssignableFrom(objectType) || ReflectionUtils.ImplementsGenericDefinition(objectType, typeof(IDictionary<,>))) + else if (CollectionUtils.IsDictionaryType(objectType)) { if (existingValue == null) value = CreateAndPopulateDictionary(reader, objectType); @@ -363,110 +363,16 @@ private object EnsureType(object value, Type targetType) } } - private MemberMappingCollection GetMemberMappings(Type objectType) + protected virtual JsonMemberMappingCollection GetMemberMappings(Type objectType) { - MemberMappingCollection memberMappings; - - if (TypeMemberMappingsCache.TryGetValue(objectType, out memberMappings)) - return memberMappings; - - memberMappings = CreateMemberMappings(objectType); - TypeMemberMappingsCache[objectType] = memberMappings; + ValidationUtils.ArgumentNotNull(objectType, "objectType"); - return memberMappings; - } - - private MemberMappingCollection CreateMemberMappings(Type objectType) - { - MemberSerialization memberSerialization = GetObjectMemberSerialization(objectType); - - List members = GetSerializableMembers(objectType); - if (members == null) - throw new JsonSerializationException("Null collection of seralizable members returned."); - - MemberMappingCollection memberMappings = new MemberMappingCollection(); - - foreach (MemberInfo member in members) - { - JsonPropertyAttribute propertyAttribute = ReflectionUtils.GetAttribute(member, true); - bool hasIgnoreAttribute = member.IsDefined(typeof(JsonIgnoreAttribute), true); - - string mappedName = (propertyAttribute != null && propertyAttribute.PropertyName != null) - ? propertyAttribute.PropertyName - : member.Name; - - bool ignored = (hasIgnoreAttribute - || (memberSerialization == MemberSerialization.OptIn && propertyAttribute == null)); - - bool readable = ReflectionUtils.CanReadMemberValue(member); - bool writable = ReflectionUtils.CanSetMemberValue(member); - - JsonConverter memberConverter = GetConverter(member, ReflectionUtils.GetMemberUnderlyingType(member)); - - DefaultValueAttribute defaultValueAttribute = ReflectionUtils.GetAttribute(member, true); - object defaultValue = (defaultValueAttribute != null) ? defaultValueAttribute.Value : null; - - MemberMapping memberMapping = new MemberMapping(mappedName, member, ignored, readable, writable, memberConverter, defaultValue); - - memberMappings.AddMapping(memberMapping); - } - - return memberMappings; - } - - /// - /// Gets the serializable members for the given . - /// - /// The object to get seralizable members for. - /// Seralizable members for the given type. - protected virtual List GetSerializableMembers(Type objectType) - { - return ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.Instance); - } - - private static MemberSerialization GetObjectMemberSerialization(Type objectType) - { - JsonObjectAttribute objectAttribute = ReflectionUtils.GetAttribute(objectType, true); - - if (objectAttribute == null) - return MemberSerialization.OptOut; - else - return objectAttribute.MemberSerialization; - } - - private JsonConverter GetConverter(ICustomAttributeProvider attributeProvider, Type targetConvertedType) - { - Type converterType; - - if (!ConverterTypeCache.TryGetValue(attributeProvider, out converterType)) - { - JsonConverterAttribute converterAttribute = ReflectionUtils.GetAttribute(attributeProvider, true); - converterType = (converterAttribute != null) - ? converterAttribute.ConverterType - : null; - - ConverterTypeCache[attributeProvider] = converterType; - } - - if (converterType != null) - { - JsonConverter memberConverter = JsonConverterAttribute.CreateJsonConverterInstance(converterType); - - if (!memberConverter.CanConvert(targetConvertedType)) - throw new JsonSerializationException("JsonConverter {0} on {1} is not compatible with member type {2}.".FormatWith(CultureInfo.InvariantCulture, memberConverter.GetType().Name, attributeProvider, targetConvertedType.Name)); - - return memberConverter; - } - - return null; + return JsonTypeReflector.GetMemberMappings(objectType); } private void SetObjectMember(JsonReader reader, object target, Type targetType, string memberName) { - if (!reader.Read()) - throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); - - MemberMappingCollection memberMappings = GetMemberMappings(targetType); + JsonMemberMappingCollection memberMappings = GetMemberMappings(targetType); Type memberType; object value; @@ -474,7 +380,7 @@ private void SetObjectMember(JsonReader reader, object target, Type targetType, // otherwise test if target is a dictionary and assign value with the key if it is if (memberMappings.Contains(memberName)) { - MemberMapping memberMapping = memberMappings[memberName]; + JsonMemberMapping memberMapping = memberMappings[memberName]; if (memberMapping.Ignored) { @@ -503,7 +409,7 @@ private void SetObjectMember(JsonReader reader, object target, Type targetType, return; } - value = CreateObject(reader, memberType, (useExistingValue) ? currentValue : null, GetConverter(memberMapping.Member, memberType)); + value = CreateObject(reader, memberType, (useExistingValue) ? currentValue : null, JsonTypeReflector.GetConverter(memberMapping.Member, memberType)); if (_nullValueHandling == NullValueHandling.Ignore && value == null) return; @@ -603,7 +509,7 @@ private object CreateAndPopulateObject(JsonReader reader, Type objectType) // create a dictionary to put retrieved values into IDictionary constructorParameters = c.GetParameters().ToDictionary(p => p, p => (object)null); - MemberMappingCollection mappings = GetMemberMappings(objectType); + JsonMemberMappingCollection mappings = GetMemberMappings(objectType); bool exit = false; while (!exit && reader.Read()) @@ -616,7 +522,7 @@ private object CreateAndPopulateObject(JsonReader reader, Type objectType) throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, memberName).Key; - MemberMapping mapping; + JsonMemberMapping mapping; if (matchingConstructorParameter != null && mappings.TryGetMapping(memberName, out mapping) && !mapping.Ignored) { @@ -644,6 +550,15 @@ private object CreateAndPopulateObject(JsonReader reader, Type objectType) private object PopulateObject(object newObject, JsonReader reader, Type objectType) { + JsonMemberMappingCollection memberMappings = GetMemberMappings(objectType); + Dictionary requiredMappings = + memberMappings.Where(m => m.Required).ToDictionary(m => m.MappingName, m => false); + //List requiredMappingContexts = + // memberMappings.Where(m => m.Required).Select(m => new RequiredMemberContext(m.MappingName, false)).ToList(); + + //ObjectContext context = new ObjectContext(newObject, requiredMappingContexts); + //DeserializeStack.Add(context); + while (reader.Read()) { switch (reader.TokenType) @@ -651,9 +566,25 @@ private object PopulateObject(object newObject, JsonReader reader, Type objectTy case JsonToken.PropertyName: string memberName = reader.Value.ToString(); + if (!reader.Read()) + throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); + + if (reader.TokenType != JsonToken.Null) + { + if (requiredMappings.ContainsKey(memberName)) + requiredMappings[memberName] = true; + } + SetObjectMember(reader, newObject, objectType, memberName); break; case JsonToken.EndObject: + foreach (KeyValuePair requiredMapping in requiredMappings) + { + if (!requiredMapping.Value) + throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredMapping.Key)); + } + // TODO: move below, change to RemoveAt + //DeserializeStack.Remove(context); return newObject; default: throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType); @@ -772,7 +703,7 @@ internal static bool HasMatchingConverter(IList converters, Type return false; } - private void WriteMemberInfoProperty(JsonWriter writer, object value, MemberMapping memberMapping) + private void WriteMemberInfoProperty(JsonWriter writer, object value, JsonMemberMapping memberMapping) { MemberInfo member = memberMapping.Member; string propertyName = memberMapping.MappingName; @@ -819,7 +750,7 @@ private void SerializeObject(JsonWriter writer, object value) TypeConverter converter = TypeDescriptor.GetConverter(objectType); // use the objectType's TypeConverter if it has one and can convert to a string - if (converter != null && !(converter is ComponentConverter) && converter.GetType() != typeof(TypeConverter)) + if (converter != null && !(converter is ComponentConverter) && (converter.GetType() != typeof(TypeConverter) || value is Type)) { if (converter.CanConvertTo(typeof(string))) { @@ -828,7 +759,7 @@ private void SerializeObject(JsonWriter writer, object value) } } #else - if (value is Guid) + if (value is Guid || value is Type) { writer.WriteValue(value.ToString()); return; @@ -839,9 +770,9 @@ private void SerializeObject(JsonWriter writer, object value) writer.WriteStartObject(); - MemberMappingCollection memberMappings = GetMemberMappings(objectType); + JsonMemberMappingCollection memberMappings = GetMemberMappings(objectType); - foreach (MemberMapping memberMapping in memberMappings) + foreach (JsonMemberMapping memberMapping in memberMappings) { if (!memberMapping.Ignored && memberMapping.Readable) WriteMemberInfoProperty(writer, value, memberMapping); @@ -849,7 +780,7 @@ private void SerializeObject(JsonWriter writer, object value) writer.WriteEndObject(); - writer.SerializeStack.Remove(value); + writer.SerializeStack.RemoveAt(writer.SerializeStack.Count - 1); } private void SerializeEnumerable(JsonWriter writer, IEnumerable values) diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index 74f751c13..db67b261c 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -381,12 +381,16 @@ private bool ParseObject() private bool ParseProperty() { + char quoteChar; + if (ValidIdentifierChar(_currentChar)) { + quoteChar = '\0'; ParseUnquotedProperty(); } else if (_currentChar == '"' || _currentChar == '\'') { + quoteChar = _currentChar; ParseQuotedProperty(_currentChar); } else @@ -401,6 +405,7 @@ private bool ParseProperty() } SetToken(JsonToken.PropertyName, _buffer.ToString()); + QuoteChar = quoteChar; _buffer.Position = 0; return true; diff --git a/Src/Newtonsoft.Json/JsonValidatingReader.cs b/Src/Newtonsoft.Json/JsonValidatingReader.cs new file mode 100644 index 000000000..faa2b62e1 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonValidatingReader.cs @@ -0,0 +1,535 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; +using Newtonsoft.Json.Utilities; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace Newtonsoft.Json +{ + public class JsonValidatingReader : JsonReader + { + private class SchemaScope + { + private readonly JsonTokenType _tokenType; + private readonly JsonSchemaModel _schema; + private readonly Dictionary _requiredProperties; + + public string CurrentPropertyName { get; set; } + public int ArrayItemCount { get; set; } + + public JsonSchemaModel Schema + { + get { return _schema; } + } + + public Dictionary RequiredProperties + { + get { return _requiredProperties; } + } + + public JsonTokenType TokenType + { + get { return _tokenType; } + } + + public SchemaScope(JsonTokenType tokenType, JsonSchemaModel schema) + { + _tokenType = tokenType; + _schema = schema; + + if (_schema != null && _schema.Properties != null) + { + _requiredProperties = GetRequiredProperties(_schema).Distinct().ToDictionary(p => p, p => false); + } + } + + private IEnumerable GetRequiredProperties(JsonSchemaModel schema) + { + return schema.Properties.Where(p => !p.Value.Optional).Select(p => p.Key); + //if (schema == null) + // return Enumerable.Empty(); + + //IEnumerable extendedRequiredProperties = GetRequiredProperties(schema.Extends); + + //if (_schema.Properties == null) + // return extendedRequiredProperties; + + //return extendedRequiredProperties.Union(schema.Properties.Where(p => !(p.Value.Optional ?? false)).Select(p => p.Key)); + } + } + + private readonly JsonReader _reader; + private readonly Stack _stack; + private JsonSchema _schema; + private JsonSchemaModel _model; + private SchemaScope _currentScope; + + public event ValidationEventHandler ValidationEventHandler; + + public override object Value + { + get { return _reader.Value; } + } + + public override int Depth + { + get { return _reader.Depth; } + } + + public override char QuoteChar + { + get { return _reader.QuoteChar; } + protected internal set { } + } + + public override JsonToken TokenType + { + get { return _reader.TokenType; } + } + + public override Type ValueType + { + get { return _reader.ValueType; } + } + + private void Push(SchemaScope scope) + { + _stack.Push(scope); + _currentScope = scope; + } + + private SchemaScope Pop() + { + SchemaScope poppedScope = _stack.Pop(); + _currentScope = (_stack.Count != 0) + ? _stack.Peek() + : null; + + return poppedScope; + } + + private JsonSchemaModel CurrentSchema + { + get { return _currentScope.Schema; } + } + + private JsonSchemaModel CurrentMemberSchema + { + get + { + if (_currentScope == null) + return _model; + + if (_currentScope.Schema == null) + return null; + + switch (_currentScope.TokenType) + { + case JsonTokenType.None: + return _currentScope.Schema; + case JsonTokenType.Object: + if (_currentScope.CurrentPropertyName == null) + throw new Exception("CurrentPropertyName has not been set on scope."); + + JsonSchemaModel propertySchema; + if (CurrentSchema.Properties.TryGetValue(_currentScope.CurrentPropertyName, out propertySchema)) + return propertySchema; + + return (CurrentSchema.AllowAdditionalProperties) ? CurrentSchema.AdditionalProperties : null; + case JsonTokenType.Array: + if (!CollectionUtils.IsNullOrEmpty(CurrentSchema.Items)) + { + if (CurrentSchema.Items.Count == 1) + return CurrentSchema.Items[0]; + + if (CurrentSchema.Items.Count > (_currentScope.ArrayItemCount - 1)) + return CurrentSchema.Items[_currentScope.ArrayItemCount - 1]; + } + + return (CurrentSchema.AllowAdditionalProperties) ? CurrentSchema.AdditionalProperties : null; + case JsonTokenType.Constructor: + return null; + default: + throw new ArgumentOutOfRangeException("TokenType", "Unexpected token type: {0}".FormatWith(CultureInfo.InvariantCulture, _currentScope.TokenType)); + } + } + } + + private void RaiseError(string message, JsonSchemaModel schema) + { + OnValidationEvent(new JsonSchemaException(message)); + } + + private void OnValidationEvent(JsonSchemaException exception) + { + ValidationEventHandler handler = ValidationEventHandler; + if (handler != null) + handler(this, new ValidationEventArgs(exception)); + else + throw exception; + } + + public JsonValidatingReader(JsonReader reader) + { + ValidationUtils.ArgumentNotNull(reader, "reader"); + _reader = reader; + _stack = new Stack(); + } + + public JsonSchema Schema + { + get { return _schema; } + set + { + if (TokenType != JsonToken.None) + throw new Exception("Cannot change schema while validating JSON."); + + _schema = value; + _model = null; + } + } + + public JsonReader Reader + { + get { return _reader; } + } + + private void ValidateInEnumAndNotDisallowed(JsonSchemaModel schema) + { + if (schema == null) + return; + + JToken value = new JValue(_reader.Value); + + if (schema.Enum != null) + { + if (!schema.Enum.Contains(value, new JTokenEqualityComparer())) + RaiseError("Value {0} is not defined in enum.".FormatWith(CultureInfo.InvariantCulture, value), + schema); + } + + JsonSchemaType? currentNodeType = GetCurrentNodeSchemaType(); + if (currentNodeType != null) + { + if (JsonSchemaGenerator.HasFlag(schema.Disallow, currentNodeType.Value)) + RaiseError("Type {0} is disallowed.".FormatWith(CultureInfo.InvariantCulture, currentNodeType), schema); + } + } + + private JsonSchemaType? GetCurrentNodeSchemaType() + { + switch (_reader.TokenType) + { + case JsonToken.StartObject: + return JsonSchemaType.Object; + case JsonToken.StartArray: + return JsonSchemaType.Array; + case JsonToken.Integer: + return JsonSchemaType.Integer; + case JsonToken.Float: + return JsonSchemaType.Float; + case JsonToken.String: + return JsonSchemaType.String; + case JsonToken.Boolean: + return JsonSchemaType.Boolean; + case JsonToken.Null: + return JsonSchemaType.Null; + default: + return null; + } + } + + public override bool Read() + { + if (!_reader.Read()) + return false; + + if (_reader.TokenType == JsonToken.Comment) + return true; + + // first time Read has been called. build model + if (_model == null) + { + JsonSchemaModelBuilder builder = new JsonSchemaModelBuilder(); + _model = builder.Build(_schema); + } + + switch (_reader.TokenType) + { + case JsonToken.StartObject: + ProcessValue(); + JsonSchemaModel objectSchema = (ValidateObject(CurrentMemberSchema)) + ? CurrentMemberSchema + : null; + Push(new SchemaScope(JsonTokenType.Object, objectSchema)); + break; + case JsonToken.StartArray: + ProcessValue(); + JsonSchemaModel arraySchema = (ValidateArray(CurrentMemberSchema)) + ? CurrentMemberSchema + : null; + Push(new SchemaScope(JsonTokenType.Array, arraySchema)); + break; + case JsonToken.StartConstructor: + Push(new SchemaScope(JsonTokenType.Constructor, null)); + break; + case JsonToken.PropertyName: + ValidatePropertyName(CurrentSchema); + break; + case JsonToken.Raw: + break; + case JsonToken.Integer: + ProcessValue(); + ValidateInteger(CurrentMemberSchema); + break; + case JsonToken.Float: + ProcessValue(); + ValidateFloat(CurrentMemberSchema); + break; + case JsonToken.String: + ProcessValue(); + ValidateString(CurrentMemberSchema); + break; + case JsonToken.Boolean: + ProcessValue(); + ValidateBoolean(CurrentMemberSchema); + break; + case JsonToken.Null: + ProcessValue(); + ValidateNull(CurrentMemberSchema); + break; + case JsonToken.Undefined: + break; + case JsonToken.EndObject: + ValidateEndObject(CurrentSchema); + Pop(); + break; + case JsonToken.EndArray: + ValidateEndArray(CurrentSchema); + Pop(); + break; + case JsonToken.EndConstructor: + Pop(); + break; + case JsonToken.Date: + break; + default: + throw new ArgumentOutOfRangeException(); + } + + return true; + } + + private void ValidateEndObject(JsonSchemaModel schema) + { + if (schema == null) + return; + + Dictionary requiredProperties = _currentScope.RequiredProperties; + + if (requiredProperties != null) + { + List unmatchedRequiredProperties = + requiredProperties.Where(kv => !kv.Value).Select(kv => kv.Key).ToList(); + + if (unmatchedRequiredProperties.Count > 0) + RaiseError("Non-optional properties are missing from object: {0}".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", unmatchedRequiredProperties.ToArray())), schema); + } + } + + private void ValidateEndArray(JsonSchemaModel schema) + { + if (schema == null) + return; + + int arrayItemCount = _currentScope.ArrayItemCount; + + if (schema.MaximumItems != null && arrayItemCount > schema.MaximumItems) + RaiseError("Array item count {0} exceeds maximum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MaximumItems), schema); + + if (schema.MinimumItems != null && arrayItemCount < schema.MinimumItems) + RaiseError("Array item count {0} is less than minimum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MinimumItems), schema); + } + + private void ValidateNull(JsonSchemaModel schema) + { + if (schema == null) + return; + + if (!TestType(schema, JsonSchemaType.Null)) + return; + + ValidateInEnumAndNotDisallowed(schema); + } + + private void ValidateBoolean(JsonSchemaModel schema) + { + if (schema == null) + return; + + if (!TestType(schema, JsonSchemaType.Boolean)) + return; + + ValidateInEnumAndNotDisallowed(schema); + } + + private void ValidateString(JsonSchemaModel schema) + { + if (schema == null) + return; + + if (!TestType(schema, JsonSchemaType.String)) + return; + + ValidateInEnumAndNotDisallowed(schema); + + string value = _reader.Value.ToString(); + + if (schema.MaximumLength != null && value.Length > schema.MaximumLength) + RaiseError("String '{0}' exceeds maximum length of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.MaximumLength), schema); + + if (schema.MinimumLength != null && value.Length < schema.MinimumLength) + RaiseError("String '{0}' is less than minimum length of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.MinimumLength), schema); + + if (schema.Patterns != null) + { + foreach (string pattern in schema.Patterns) + { + if (!Regex.IsMatch(value, pattern)) + RaiseError("String '{0}' does not match regex pattern '{1}'.".FormatWith(CultureInfo.InvariantCulture, value, pattern), schema); + } + } + } + + private void ValidateInteger(JsonSchemaModel schema) + { + if (schema == null) + return; + + if (!TestType(schema, JsonSchemaType.Integer)) + return; + + ValidateInEnumAndNotDisallowed(schema); + + long value = Convert.ToInt64(_reader.Value, CultureInfo.InvariantCulture); + + if (schema.Maximum != null && value > schema.Maximum) + RaiseError("Integer {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema); + + if (schema.Minimum != null && value < schema.Minimum) + RaiseError("Integer {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema); + } + + private void ProcessValue() + { + if (_currentScope != null && _currentScope.TokenType == JsonTokenType.Array) + { + _currentScope.ArrayItemCount++; + + if (CurrentSchema != null && CurrentSchema.Items != null && CurrentSchema.Items.Count > 1 && _currentScope.ArrayItemCount >= CurrentSchema.Items.Count) + RaiseError("Index {0} has not been defined and schema does not allow additional items.".FormatWith(CultureInfo.InvariantCulture, _currentScope.ArrayItemCount), CurrentSchema); + } + } + + private void ValidateFloat(JsonSchemaModel schema) + { + if (schema == null) + return; + + if (!TestType(schema, JsonSchemaType.Float)) + return; + + ValidateInEnumAndNotDisallowed(schema); + + double value = Convert.ToDouble(_reader.Value); + + if (schema.Maximum != null && value > schema.Maximum) + RaiseError("Float {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Maximum), schema); + + if (schema.Minimum != null && value < schema.Minimum) + RaiseError("Float {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Minimum), schema); + + if (schema.MaximumDecimals != null && MathUtils.GetDecimalPlaces(value) > schema.MaximumDecimals) + RaiseError("Float {0} exceeds the maximum allowed number decimal places of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.MaximumDecimals), schema); + } + + private void ValidatePropertyName(JsonSchemaModel schema) + { + if (schema == null) + return; + + string propertyName = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture); + + if (_currentScope.RequiredProperties.ContainsKey(propertyName)) + _currentScope.RequiredProperties[propertyName] = true; + + if (!schema.Properties.ContainsKey(propertyName)) + { + IList definedProperties = schema.Properties.Select(p => p.Key).ToList(); + + if (!schema.AllowAdditionalProperties && !definedProperties.Contains(propertyName)) + { + RaiseError("Property '{0}' has not been defined and schema does not allow additional properties.".FormatWith(CultureInfo.InvariantCulture, propertyName), schema); + } + } + + _currentScope.CurrentPropertyName = propertyName; + } + + private bool ValidateArray(JsonSchemaModel schema) + { + if (schema == null) + return true; + + return (TestType(schema, JsonSchemaType.Array)); + } + + private bool ValidateObject(JsonSchemaModel schema) + { + if (schema == null) + return true; + + return (TestType(schema, JsonSchemaType.Object)); + } + + private bool TestType(JsonSchemaModel currentSchema, JsonSchemaType currentType) + { + if (!JsonSchemaGenerator.HasFlag(currentSchema.Type, currentType)) + { + RaiseError("Invalid type. Expected {0} but got {1}.".FormatWith(CultureInfo.InvariantCulture, currentSchema.Type, currentType), currentSchema); + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 2a940e472..888dbadd9 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -122,9 +122,9 @@ private enum State private int _top; private List _stack; - private List _serializeStack; private State _currentState; private Formatting _formatting; + private List _serializeStack; internal List SerializeStack { @@ -192,7 +192,7 @@ public Formatting Formatting /// public JsonWriter() { - _stack = new List(1); + _stack = new List(8); _stack.Add(JsonTokenType.None); _currentState = State.Start; _formatting = Formatting.None; @@ -529,6 +529,9 @@ private void AutoCompleteClose(JsonToken tokenBeingClosed) case JsonTokenType.Array: _currentState = State.Array; break; + case JsonTokenType.Constructor: + _currentState = State.Array; + break; case JsonTokenType.None: _currentState = State.Start; break; diff --git a/Src/Newtonsoft.Json/Linq/JArray.cs b/Src/Newtonsoft.Json/Linq/JArray.cs index 55dfd054e..5466efe9c 100644 --- a/Src/Newtonsoft.Json/Linq/JArray.cs +++ b/Src/Newtonsoft.Json/Linq/JArray.cs @@ -96,7 +96,7 @@ internal override JToken CloneNode() /// Loads an from a . /// /// A that will be read for the content of the . - /// A that contains the XML that was read from the specified . + /// A that contains the JSON that was read from the specified . public static JArray Load(JsonReader reader) { if (reader.TokenType == JsonToken.None) @@ -105,14 +105,13 @@ public static JArray Load(JsonReader reader) throw new Exception("Error reading JArray from JsonReader."); } if (reader.TokenType != JsonToken.StartArray) - { - throw new Exception("Error reading JArray from JsonReader. Current JsonReader item is not an array: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); - } - else - { - if (!reader.Read()) - throw new Exception("Error reading JArray from JsonReader."); - } + throw new Exception( + "Error reading JArray from JsonReader. Current JsonReader item is not an array: {0}".FormatWith( + CultureInfo.InvariantCulture, reader.TokenType)); + + if (!reader.Read()) + throw new Exception("Error reading JArray from JsonReader."); + JArray a = new JArray(); a.ReadContentFrom(reader); @@ -145,7 +144,7 @@ internal override void ValidateObject(JToken o, JToken previous) /// /// The object that will be used to create . /// A with the values of the specified object - public static JArray FromObject(object o) + public static new JArray FromObject(object o) { JToken token = FromObjectInternal(o); diff --git a/Src/Newtonsoft.Json/Linq/JConstructor.cs b/Src/Newtonsoft.Json/Linq/JConstructor.cs index c381aaeac..dba14b855 100644 --- a/Src/Newtonsoft.Json/Linq/JConstructor.cs +++ b/Src/Newtonsoft.Json/Linq/JConstructor.cs @@ -160,5 +160,33 @@ internal override int GetDeepHashCode() { return _name.GetHashCode() ^ ContentsHashCode(); } + + /// + /// Loads an from a . + /// + /// A that will be read for the content of the . + /// A that contains the JSON that was read from the specified . + public static JConstructor Load(JsonReader reader) + { + if (reader.TokenType == JsonToken.None) + { + if (!reader.Read()) + throw new Exception("Error reading JConstructor from JsonReader."); + } + + if (reader.TokenType != JsonToken.StartConstructor) + throw new Exception( + "Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith( + CultureInfo.InvariantCulture, reader.TokenType)); + + JConstructor c = new JConstructor((string)reader.Value); + + if (!reader.Read()) + throw new Exception("Error reading JConstructor from JsonReader."); + + c.ReadContentFrom(reader); + + return c; + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index 557ffd899..043c6d98f 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -26,7 +26,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using Newtonsoft.Json.Utilities; using System.Collections; using System.Diagnostics; @@ -191,22 +190,6 @@ public IEnumerable Descendants() } } - internal static JToken FromObjectInternal(object o) - { - ValidationUtils.ArgumentNotNull(o, "o"); - - JsonSerializer jsonSerializer = new JsonSerializer(); - - JToken token; - using (JsonTokenWriter jsonWriter = new JsonTokenWriter()) - { - jsonSerializer.Serialize(jsonWriter, o); - token = jsonWriter.Token; - } - - return token; - } - internal static JToken GetIndex(JContainer c, object o) { return c.Children().ElementAt((int)o); @@ -387,10 +370,12 @@ internal void ReadContentFrom(JsonReader r) do { - if (parent is JProperty) + if (parent is JProperty && ((JProperty)parent).Value != null) { - if (((JProperty)parent).Value != null) - parent = parent.Parent; + if (parent == this) + return; + + parent = parent.Parent; } switch (r.TokenType) diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs index d0fd004dc..993155402 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.cs @@ -181,7 +181,7 @@ public JEnumerable PropertyValues() /// Loads an from a . /// /// A that will be read for the content of the . - /// A that contains the XML that was read from the specified . + /// A that contains the JSON that was read from the specified . public static JObject Load(JsonReader reader) { ValidationUtils.ArgumentNotNull(reader, "reader"); @@ -192,14 +192,12 @@ public static JObject Load(JsonReader reader) throw new Exception("Error reading JObject from JsonReader."); } if (reader.TokenType != JsonToken.StartObject) - { - throw new Exception("Error reading JObject from JsonReader. Current JsonReader item is not an object: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); - } - else - { - if (!reader.Read()) - throw new Exception("Error reading JObject from JsonReader."); - } + throw new Exception( + "Error reading JObject from JsonReader. Current JsonReader item is not an object: {0}".FormatWith( + CultureInfo.InvariantCulture, reader.TokenType)); + + if (!reader.Read()) + throw new Exception("Error reading JObject from JsonReader."); JObject o = new JObject(); o.ReadContentFrom(reader); @@ -224,7 +222,7 @@ public static JObject Parse(string json) /// /// The object that will be used to create . /// A with the values of the specified object - public static JObject FromObject(object o) + public static new JObject FromObject(object o) { JToken token = FromObjectInternal(o); diff --git a/Src/Newtonsoft.Json/Linq/JProperty.cs b/Src/Newtonsoft.Json/Linq/JProperty.cs index 2a26df0c3..61c011011 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.cs @@ -54,7 +54,7 @@ public string Name /// Gets or sets the property value. /// /// The property value. - public JToken Value + public new JToken Value { [DebuggerStepThrough] get { return Last; } @@ -107,13 +107,26 @@ public JProperty(string name) /// Initializes a new instance of the class. /// /// The property name. - /// The property value. - public JProperty(string name, object value) + /// The property content. + public JProperty(string name, params object[] content) + : this(name, (object)content) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The property name. + /// The property content. + public JProperty(string name, object content) { ValidationUtils.ArgumentNotNull(name, "name"); _name = name; - Value = CreateFromContent(value); + + Value = IsMultiContent(content) + ? new JArray(content) + : CreateFromContent(content); } internal override void ValidateObject(JToken o, JToken previous) @@ -154,5 +167,32 @@ internal override int GetDeepHashCode() { return _name.GetHashCode() ^ ((Value != null) ? Value.GetDeepHashCode() : 0); } + + /// + /// Loads an from a . + /// + /// A that will be read for the content of the . + /// A that contains the JSON that was read from the specified . + public static JProperty Load(JsonReader reader) + { + if (reader.TokenType == JsonToken.None) + { + if (!reader.Read()) + throw new Exception("Error reading JProperty from JsonReader."); + } + if (reader.TokenType != JsonToken.PropertyName) + throw new Exception( + "Error reading JProperty from JsonReader. Current JsonReader item is not a property: {0}".FormatWith( + CultureInfo.InvariantCulture, reader.TokenType)); + + JProperty p = new JProperty((string)reader.Value); + + if (!reader.Read()) + throw new Exception("Error reading JProperty from JsonReader."); + + p.ReadContentFrom(reader); + + return p; + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 7a2b5928a..beb7201b3 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -146,7 +146,7 @@ public JToken Previous if (_parent == null) return null; - JToken parentNext = ((JToken)_parent.Content)._next; + JToken parentNext = _parent.Content._next; JToken parentNextBefore = null; while (parentNext != this) { @@ -736,5 +736,66 @@ IEnumerator IEnumerable.GetEnumerator() { get { return this[key]; } } + + public JsonReader CreateReader() + { + return new JsonTokenReader(this); + } + + internal static JToken FromObjectInternal(object o) + { + ValidationUtils.ArgumentNotNull(o, "o"); + + JsonSerializer jsonSerializer = new JsonSerializer(); + + JToken token; + using (JsonTokenWriter jsonWriter = new JsonTokenWriter()) + { + jsonSerializer.Serialize(jsonWriter, o); + token = jsonWriter.Token; + } + + return token; + } + + /// + /// Creates a from an object. + /// + /// The object that will be used to create . + /// A with the value of the specified object + public static JToken FromObject(object o) + { + return FromObjectInternal(o); + } + + public static JToken ReadFrom(JsonReader reader) + { + ValidationUtils.ArgumentNotNull(reader, "reader"); + + if (reader.TokenType == JsonToken.None) + { + if (!reader.Read()) + throw new Exception("Error reading JToken from JsonReader."); + } + + if (reader.TokenType == JsonToken.StartObject) + return JObject.Load(reader); + + if (reader.TokenType == JsonToken.StartArray) + return JArray.Load(reader); + + if (reader.TokenType == JsonToken.PropertyName) + return JProperty.Load(reader); + + if (reader.TokenType == JsonToken.StartConstructor) + return JConstructor.Load(reader); + + // hack. change to look at TokenType rather than using value + if (!JsonReader.IsStartToken(reader.TokenType)) + return new JValue(reader.Value); + + // TODO: loading constructor and parameters? + throw new Exception("Error reading JToken from JsonReader. Unexpected token: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JsonTokenReader.cs b/Src/Newtonsoft.Json/Linq/JsonTokenReader.cs index 31e16438c..6cb6bae74 100644 --- a/Src/Newtonsoft.Json/Linq/JsonTokenReader.cs +++ b/Src/Newtonsoft.Json/Linq/JsonTokenReader.cs @@ -11,7 +11,7 @@ namespace Newtonsoft.Json.Linq /// public class JsonTokenReader : JsonReader { - private JToken _root; + private readonly JToken _root; private JToken _parent; private JToken _current; diff --git a/Src/Newtonsoft.Json/Linq/JsonTokenWriter.cs b/Src/Newtonsoft.Json/Linq/JsonTokenWriter.cs index a3c86ec1c..2ce793793 100644 --- a/Src/Newtonsoft.Json/Linq/JsonTokenWriter.cs +++ b/Src/Newtonsoft.Json/Linq/JsonTokenWriter.cs @@ -13,14 +13,22 @@ public class JsonTokenWriter : JsonWriter { private JContainer _token; private JContainer _parent; + // used when writer is writing single value and the value has no containing parent + private JValue _value; /// /// Gets the token being writen. /// /// The token being writen. - public JContainer Token + public JToken Token { - get { return _token; } + get + { + if (_token != null) + return _token; + + return _value; + } } /// @@ -133,10 +141,17 @@ private void AddValue(object value, JsonToken token) private void AddValue(JValue value, JsonToken token) { - _parent.Add(value); + if (_parent != null) + { + _parent.Add(value); - if (_parent.Type == JsonTokenType.Property) - _parent = _parent.Parent; + if (_parent.Type == JsonTokenType.Property) + _parent = _parent.Parent; + } + else + { + _value = value; + } } #region WriteValue methods diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj index a4147f969..fe3dc84ad 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj @@ -55,60 +55,83 @@ - - - - - + + - - - - + + + + + + + + + + + + + + + + + + - + - - - - - - - - - + - - + + - - - + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj index 424a3a13a..f49c490a8 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj @@ -53,7 +53,10 @@ + + + @@ -70,6 +73,7 @@ + @@ -86,8 +90,6 @@ - - @@ -100,6 +102,9 @@ + + + @@ -107,6 +112,25 @@ + + + + + + + + + + + + + + + + + + +