From 5831b11de11c13761dc82706da5e349ba2739b2e Mon Sep 17 00:00:00 2001 From: JamesNK Date: Fri, 18 Nov 2011 09:36:01 +0000 Subject: [PATCH] -Fixed flag enum items not being correctly camel cased -Fixed JsonValidatingReader not validating the first array item twice -Fixed JsonSchema not correctly validating integers as a subset of decimal -Changed JsonTextReader.Culture to be CultureInfo.InvariantCulture by default --- .../Converters/StringEnumConverterTests.cs | 33 ++++ .../JsonValidatingReaderTests.cs | 151 ++++++++++++++++++ .../Serialization/JsonSerializerTest.cs | 32 ++++ .../Converters/StringEnumConverter.cs | 5 +- Src/Newtonsoft.Json/JsonTextReader.cs | 4 +- Src/Newtonsoft.Json/JsonTextWriter.cs | 4 +- Src/Newtonsoft.Json/JsonValidatingReader.cs | 10 +- .../Schema/JsonSchemaGenerator.cs | 10 +- 8 files changed, 240 insertions(+), 9 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs index 2d5c8f53..685495bb 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs @@ -23,6 +23,14 @@ namespace Newtonsoft.Json.Tests.Converters public T Enum { get; set; } } + [Flags] + public enum FlagsTestEnum + { + Default = 0, + First = 1, + Second = 2 + } + public enum NegativeEnum { Negative = -1, @@ -256,5 +264,30 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual((StoreColor)1000, enumClass.NullableStoreColor1); Assert.AreEqual(null, enumClass.NullableStoreColor2); } + + [Test] + public void CamelCaseTextFlagEnumSerialization() + { + EnumContainer c = new EnumContainer + { + Enum = FlagsTestEnum.First | FlagsTestEnum.Second + }; + + string json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter { CamelCaseText = true }); + Assert.AreEqual(@"{ + ""Enum"": ""first, second"" +}", json); + } + + [Test] + public void CamelCaseTextFlagEnumDeserialization() + { + string json = @"{ + ""Enum"": ""first, second"" +}"; + + EnumContainer c = JsonConvert.DeserializeObject>(json, new StringEnumConverter { CamelCaseText = true }); + Assert.AreEqual(FlagsTestEnum.First | FlagsTestEnum.Second, c.Enum); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs b/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs index 72556ad1..432cf9b7 100644 --- a/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs @@ -7,6 +7,8 @@ using NUnit.Framework; using System.Xml; using System.Xml.Schema; using Newtonsoft.Json.Schema; +using Newtonsoft.Json.Utilities; +using ValidationEventArgs = Newtonsoft.Json.Schema.ValidationEventArgs; namespace Newtonsoft.Json.Tests { @@ -502,6 +504,36 @@ namespace Newtonsoft.Json.Tests Assert.IsNotNull(validationEventArgs); } + [Test] + public void IntValidForNumber() + { + string schemaJson = @"{ + ""type"":""array"", + ""items"":{ + ""type"":""number"" + } +}"; + + 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.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsNull(validationEventArgs); + } + [Test] public void NullNotInEnum() { @@ -1209,5 +1241,124 @@ namespace Newtonsoft.Json.Tests Assert.IsFalse(reader.Read()); } + + [Test] + public void DuplicateErrorsTest() + { + string schema = @"{ + ""id"":""ErrorDemo.Database"", + ""properties"":{ + ""ErrorDemoDatabase"":{ + ""type"":""object"", + ""required"":true, + ""properties"":{ + ""URL"":{ + ""type"":""string"", + ""required"":true + }, + ""Version"":{ + ""type"":""string"", + ""required"":true + }, + ""Date"":{ + ""type"":""string"", + ""format"":""date-time"", + ""required"":true + }, + ""MACLevels"":{ + ""type"":""object"", + ""required"":true, + ""properties"":{ + ""MACLevel"":{ + ""type"":""array"", + ""required"":true, + ""items"":[ + { + ""required"":true, + ""properties"":{ + ""IDName"":{ + ""type"":""string"", + ""required"":true + }, + ""Order"":{ + ""type"":""string"", + ""required"":true + }, + ""IDDesc"":{ + ""type"":""string"", + ""required"":true + }, + ""IsActive"":{ + ""type"":""string"", + ""required"":true + } + } + } + ] + } + } + } + } + } + } +}"; + + string json = @"{ + ""ErrorDemoDatabase"":{ + ""URL"":""localhost:3164"", + ""Version"":""1.0"", + ""Date"":""6.23.2010, 9:35:18.121"", + ""MACLevels"":{ + ""MACLevel"":[ + { + ""@IDName"":""Developer"", + ""Order"":""0"", + ""IDDesc"":""DeveloperDesc"", + ""IsActive"":""True"" + }, + { + ""IDName"":""Technician"", + ""Order"":""1"", + ""IDDesc"":""TechnicianDesc"", + ""IsActive"":""True"" + }, + { + ""IDName"":""Administrator"", + ""Order"":""2"", + ""IDDesc"":""AdministratorDesc"", + ""IsActive"":""True"" + }, + { + ""IDName"":""PowerUser"", + ""Order"":""3"", + ""IDDesc"":""PowerUserDesc"", + ""IsActive"":""True"" + }, + { + ""IDName"":""Operator"", + ""Order"":""4"", + ""IDDesc"":""OperatorDesc"", + ""IsActive"":""True"" + } + ] + } + } +}"; + + IList validationEventArgs = new List(); + + JsonValidatingReader reader = new JsonValidatingReader(new JsonTextReader(new StringReader(json))); + reader.ValidationEventHandler += (sender, args) => + { + validationEventArgs.Add(args); + }; + reader.Schema = JsonSchema.Parse(schema); + + while (reader.Read()) + { + } + + Assert.AreEqual(1, validationEventArgs.Count); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 38ffce62..fd1930ea 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -5045,6 +5045,38 @@ keyword such as type of business."" Assert.AreEqual(new byte[] { 72, 63, 62, 71, 92, 55 }, newObject.Data); } } + + [Test] + public void DeserializeDecimalsWithCulture() + { + CultureInfo initialCulture = Thread.CurrentThread.CurrentCulture; + + try + { + CultureInfo testCulture = CultureInfo.CreateSpecificCulture("nb-NO"); + + Thread.CurrentThread.CurrentCulture = testCulture; + Thread.CurrentThread.CurrentUICulture = testCulture; + + string json = @"{ 'Quantity': '1.5', 'OptionalQuantity': '2.2' }"; + + DecimalTestClass c = JsonConvert.DeserializeObject(json); + + Assert.AreEqual(1.5m, c.Quantity); + Assert.AreEqual(2.2d, c.OptionalQuantity); + } + finally + { + Thread.CurrentThread.CurrentCulture = initialCulture; + Thread.CurrentThread.CurrentUICulture = initialCulture; + } + } + } + + public class DecimalTestClass + { + public decimal Quantity { get; set; } + public double OptionalQuantity { get; set; } } public class TestObject diff --git a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs b/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs index 16087562..e463ca29 100644 --- a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs +++ b/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs @@ -80,7 +80,10 @@ namespace Newtonsoft.Json.Converters resolvedEnumName = resolvedEnumName ?? enumName; if (CamelCaseText) - resolvedEnumName = StringUtils.ToCamelCase(resolvedEnumName); + { + var names = resolvedEnumName.Split(',').Select(item => StringUtils.ToCamelCase(item.Trim())); + resolvedEnumName = string.Join(", ", names); + } writer.WriteValue(resolvedEnumName); } diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index ba999a60..34835898 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -58,11 +58,11 @@ namespace Newtonsoft.Json private CultureInfo _culture; /// - /// Gets or sets the culture used when reading JSON. Defaults to . + /// Gets or sets the culture used when reading JSON. Defaults to . /// public CultureInfo Culture { - get { return _culture ?? CultureInfo.CurrentCulture; } + get { return _culture ?? CultureInfo.InvariantCulture; } set { _culture = value; } } diff --git a/Src/Newtonsoft.Json/JsonTextWriter.cs b/Src/Newtonsoft.Json/JsonTextWriter.cs index 71cce015..7ffc941a 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.cs @@ -479,7 +479,7 @@ namespace Newtonsoft.Json public override void WriteValue(TimeSpan value) { base.WriteValue(value); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Date); + WriteValueInternal(JsonConvert.ToString(value), JsonToken.String); } /// @@ -489,7 +489,7 @@ namespace Newtonsoft.Json public override void WriteValue(Uri value) { base.WriteValue(value); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Date); + WriteValueInternal(JsonConvert.ToString(value), JsonToken.String); } #endregion diff --git a/Src/Newtonsoft.Json/JsonValidatingReader.cs b/Src/Newtonsoft.Json/JsonValidatingReader.cs index 795fb3f2..83d7a1b3 100644 --- a/Src/Newtonsoft.Json/JsonValidatingReader.cs +++ b/Src/Newtonsoft.Json/JsonValidatingReader.cs @@ -214,10 +214,14 @@ namespace Newtonsoft.Json if (!CollectionUtils.IsNullOrEmpty(schema.Items)) { if (schema.Items.Count == 1) + { schemas.Add(schema.Items[0]); - - if (schema.Items.Count > (_currentScope.ArrayItemCount - 1)) - schemas.Add(schema.Items[_currentScope.ArrayItemCount - 1]); + } + else + { + if (schema.Items.Count > (_currentScope.ArrayItemCount - 1)) + schemas.Add(schema.Items[_currentScope.ArrayItemCount - 1]); + } } if (schema.AllowAdditionalProperties && schema.AdditionalProperties != null) diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs index cf6408b4..30d35bda 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs @@ -395,7 +395,15 @@ namespace Newtonsoft.Json.Schema if (value == null) return true; - return ((value & flag) == flag); + bool match = ((value & flag) == flag); + if (match) + return true; + + // integer is a subset of float + if (value == JsonSchemaType.Float && flag == JsonSchemaType.Integer) + return true; + + return false; } private JsonSchemaType GetJsonSchemaType(Type type, Required valueRequired)