From ffe2d91279d88d568306693a4dbac8fe81b3db2f Mon Sep 17 00:00:00 2001 From: JamesNK Date: Fri, 4 Apr 2008 22:45:52 +0000 Subject: [PATCH] Change - Heaps of small changes and bug fixes around LINQ to JSON. Many unit tests added. Change - CultureInfo is now always passed into FormatWith --- .../IsoDateTimeConverterTests.cs | 29 +- .../JavaScriptDateTimeConverterTests.cs | 29 +- .../{ => Converters}/XmlNodeConverterTest.cs | 2 +- .../DateTimeTestClass.cs | 27 +- Src/Newtonsoft.Json.Tests/JTokenTests.cs | 88 ---- .../JavaScriptConvertTest.cs | 25 + .../JsonSerializerTest.cs | 51 +- .../JsonTextReaderTest.cs | 2 +- Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs | 467 ++++++++++++++++++ Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs | 164 ++++++ .../{ => Linq}/LinqToJsonTest.cs | 46 +- .../Newtonsoft.Json.Tests.csproj | 11 +- Src/Newtonsoft.Json.Tests/TestFixtureBase.cs | 27 +- .../Converters/IsoDateTimeConverter.cs | 2 +- .../Converters/JavaScriptDateTimeConverter.cs | 6 +- Src/Newtonsoft.Json/JavaScriptConvert.cs | 2 +- Src/Newtonsoft.Json/JsonReader.cs | 2 +- Src/Newtonsoft.Json/JsonSerializer.cs | 10 +- Src/Newtonsoft.Json/JsonWriter.cs | 3 +- Src/Newtonsoft.Json/Linq/Extensions.cs | 7 +- Src/Newtonsoft.Json/Linq/JArray.cs | 7 +- Src/Newtonsoft.Json/Linq/JConstructor.cs | 6 +- Src/Newtonsoft.Json/Linq/JContainer.cs | 74 +-- Src/Newtonsoft.Json/Linq/JObject.cs | 29 +- Src/Newtonsoft.Json/Linq/JProperty.cs | 18 +- Src/Newtonsoft.Json/Linq/JToken.cs | 112 +++-- Src/Newtonsoft.Json/Linq/JValue.cs | 58 ++- .../MemberMappingCollection.cs | 3 +- .../Utilities/CollectionUtils.cs | 11 +- Src/Newtonsoft.Json/Utilities/ListWrapper.cs | 3 +- .../Utilities/MiscellaneousUtils.cs | 3 +- .../Utilities/ReflectionUtils.cs | 23 +- Src/Newtonsoft.Json/Utilities/StringUtils.cs | 8 +- .../Utilities/ValidationUtils.cs | 11 +- 34 files changed, 1104 insertions(+), 262 deletions(-) rename Src/Newtonsoft.Json.Tests/{ => Converters}/IsoDateTimeConverterTests.cs (75%) rename Src/Newtonsoft.Json.Tests/{ => Converters}/JavaScriptDateTimeConverterTests.cs (58%) rename Src/Newtonsoft.Json.Tests/{ => Converters}/XmlNodeConverterTest.cs (96%) delete mode 100644 Src/Newtonsoft.Json.Tests/JTokenTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs rename Src/Newtonsoft.Json.Tests/{ => Linq}/LinqToJsonTest.cs (90%) diff --git a/Src/Newtonsoft.Json.Tests/IsoDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs similarity index 75% rename from Src/Newtonsoft.Json.Tests/IsoDateTimeConverterTests.cs rename to Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs index 8b3580db..80cb943f 100644 --- a/Src/Newtonsoft.Json.Tests/IsoDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs @@ -1,4 +1,29 @@ -using System; +#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; @@ -7,7 +32,7 @@ using Newtonsoft.Json.Converters; using Newtonsoft.Json.Utilities; using System.Globalization; -namespace Newtonsoft.Json.Tests +namespace Newtonsoft.Json.Tests.Converters { public class IsoDateTimeConverterTests : TestFixtureBase { diff --git a/Src/Newtonsoft.Json.Tests/JavaScriptDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs similarity index 58% rename from Src/Newtonsoft.Json.Tests/JavaScriptDateTimeConverterTests.cs rename to Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs index cf7288be..8c29d71d 100644 --- a/Src/Newtonsoft.Json.Tests/JavaScriptDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs @@ -1,11 +1,36 @@ -using System; +#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.Converters; -namespace Newtonsoft.Json.Tests +namespace Newtonsoft.Json.Tests.Converters { public class JavaScriptDateTimeConverterTests : TestFixtureBase { diff --git a/Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs similarity index 96% rename from Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs rename to Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs index 5e7c4e2b..d9a0bf96 100644 --- a/Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs @@ -31,7 +31,7 @@ using System.Xml; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Utilities; -namespace Newtonsoft.Json.Tests +namespace Newtonsoft.Json.Tests.Converters { public class XmlNodeConverterTest : TestFixtureBase { diff --git a/Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs b/Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs index 558a7404..1cf57929 100644 --- a/Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs @@ -1,4 +1,29 @@ -using System; +#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; diff --git a/Src/Newtonsoft.Json.Tests/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/JTokenTests.cs deleted file mode 100644 index f8667abf..00000000 --- a/Src/Newtonsoft.Json.Tests/JTokenTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; -using Newtonsoft.Json.Linq; -using System.Xml.Linq; - -namespace Newtonsoft.Json.Tests -{ - public class JTokenTests : TestFixtureBase - { - [Test] - public void Parent() - { - JValue v = new JValue(new DateTime(2000, 12, 20)); - - Assert.AreEqual(null, v.Parent); - - JObject o = - new JObject( - new JProperty("Test1", v), - new JProperty("Test2", "Test2Value"), - new JProperty("Test3", "Test3Value"), - new JProperty("Test4", null) - ); - - Assert.AreEqual(o.Property("Test1"), v.Parent); - - JProperty p = new JProperty("NewProperty", v); - - // existing value should still have same parent - Assert.AreEqual(o.Property("Test1"), v.Parent); - - // new value should be cloned - Assert.AreNotEqual(p.Value, v); - - Assert.AreEqual((DateTime)p.Value, (DateTime)v.Value); - - Assert.AreEqual(v, o["Test1"]); - - XText t = new XText("XText"); - Assert.AreEqual(null, t.Parent); - - Assert.AreEqual(null, o.Parent); - JProperty o1 = new JProperty("O1", o); - Assert.AreEqual(o, o1.Value); - - Assert.AreNotEqual(null, o.Parent); - JProperty o2 = new JProperty("O2", o); - - Assert.AreNotEqual(o1.Value, o2.Value); - Assert.AreEqual(o1.Value.Children().Count(), o2.Value.Children().Count()); - Assert.AreEqual(false, JToken.DeepEquals(o1, o2)); - Assert.AreEqual(true, JToken.DeepEquals(o1.Value, o2.Value)); - } - - [Test] - public void Children() - { - JArray a = - new JArray( - 5, - new JArray(1, 2, 3), - new JArray(1, 2, 3), - new JArray(1, 2, 3) - ); - - Assert.AreEqual(4, a.Count()); - Assert.AreEqual(3, a.Children().Count()); - } - - [Test] - public void Casting() - { - //JToken t = new JValue(new DateTime(2000, 12, 20)); - //DateTime d = (DateTime)t; - - Assert.AreEqual(new DateTime(2000, 12, 20), (DateTime)new JValue(new DateTime(2000, 12, 20))); - Assert.AreEqual(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero), (DateTimeOffset)new JValue(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero))); - Assert.AreEqual(true, (bool)new JValue(true)); - Assert.AreEqual(true, (bool?)new JValue(true)); - Assert.AreEqual(null, (bool?)((JValue)null)); - Assert.AreEqual(null, (bool?)JValue.Null); - Assert.AreEqual(null, (bool?)JValue.Undefined); - } - } -} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JavaScriptConvertTest.cs b/Src/Newtonsoft.Json.Tests/JavaScriptConvertTest.cs index 041b1362..bee8354b 100644 --- a/Src/Newtonsoft.Json.Tests/JavaScriptConvertTest.cs +++ b/Src/Newtonsoft.Json.Tests/JavaScriptConvertTest.cs @@ -1,3 +1,28 @@ +#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.Text; diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs index 1cf018f2..2cc64977 100644 --- a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs @@ -147,6 +147,7 @@ namespace Newtonsoft.Json.Tests } } + [JsonObject] public class ConverableMembers { public string String = "string"; @@ -165,6 +166,31 @@ namespace Newtonsoft.Json.Tests 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; } + } + } + public class JsonSerializerTest : TestFixtureBase { [Test] @@ -942,31 +968,6 @@ keyword such as type of business."" Assert.AreEqual(StringComparison.CurrentCultureIgnoreCase, s); } - [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; } - } - } - [Test] public void JsonIgnoreAttributeOnClassTest() { diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index 0d5b9a60..84a6268e 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -207,7 +207,7 @@ namespace Newtonsoft.Json.Tests { string input = @"{ CPU: 'Intel', - Drives: [ + Drives: [ /* Com*ment */ 'DVD read/writer', ""500 gigabyte hard drive"" ] diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs new file mode 100644 index 00000000..86eccf66 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs @@ -0,0 +1,467 @@ +#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.Linq; +using System.Xml.Linq; + +namespace Newtonsoft.Json.Tests.Linq +{ + public class JTokenTests : TestFixtureBase + { + [Test] + public void Parent() + { + JArray v = new JArray(new JConstructor("TestConstructor"), new JValue(new DateTime(2000, 12, 20))); + + Assert.AreEqual(null, v.Parent); + + JObject o = + new JObject( + new JProperty("Test1", v), + new JProperty("Test2", "Test2Value"), + new JProperty("Test3", "Test3Value"), + new JProperty("Test4", null) + ); + + Assert.AreEqual(o.Property("Test1"), v.Parent); + + JProperty p = new JProperty("NewProperty", v); + + // existing value should still have same parent + Assert.AreEqual(o.Property("Test1"), v.Parent); + + // new value should be cloned + Assert.AreNotEqual(p.Value, v); + + Assert.AreEqual((DateTime)((JValue)p.Value[1]).Value, (DateTime)((JValue)v[1]).Value); + + Assert.AreEqual(v, o["Test1"]); + + XText t = new XText("XText"); + Assert.AreEqual(null, t.Parent); + + Assert.AreEqual(null, o.Parent); + JProperty o1 = new JProperty("O1", o); + Assert.AreEqual(o, o1.Value); + + Assert.AreNotEqual(null, o.Parent); + JProperty o2 = new JProperty("O2", o); + + Assert.AreNotEqual(o1.Value, o2.Value); + Assert.AreEqual(o1.Value.Children().Count(), o2.Value.Children().Count()); + Assert.AreEqual(false, JToken.DeepEquals(o1, o2)); + Assert.AreEqual(true, JToken.DeepEquals(o1.Value, o2.Value)); + } + + [Test] + public void Next() + { + JArray a = + new JArray( + 5, + 6, + new JArray(7, 8), + new JArray(9, 10) + ); + + JToken next = a[0].Next; + Assert.AreEqual(6, (int)next); + + next = next.Next; + Assert.IsTrue(JToken.DeepEquals(new JArray(7, 8), next)); + + next = next.Next; + Assert.IsTrue(JToken.DeepEquals(new JArray(9, 10), next)); + + next = next.Next; + Assert.IsNull(next); + } + + [Test] + public void Previous() + { + JArray a = + new JArray( + 5, + 6, + new JArray(7, 8), + new JArray(9, 10) + ); + + JToken previous = a[3].Previous; + Assert.IsTrue(JToken.DeepEquals(new JArray(7, 8), previous)); + + previous = previous.Previous; + Assert.AreEqual(6, (int)previous); + + previous = previous.Previous; + Assert.AreEqual(5, (int)previous); + + previous = previous.Previous; + Assert.IsNull(previous); + } + + [Test] + public void Children() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + Assert.AreEqual(4, a.Count()); + Assert.AreEqual(3, a.Children().Count()); + } + + [Test] + public void BeforeAfter() + { + JArray a = + new JArray( + 5, + new JArray(1, 2, 3), + new JArray(1, 2, 3), + new JArray(1, 2, 3) + ); + + Assert.AreEqual(5, (int)a[1].Previous); + Assert.AreEqual(2, a[2].BeforeSelf().Count()); + //Assert.AreEqual(2, a[2].AfterSelf().Count()); + } + + [Test] + public void Casting() + { + Assert.AreEqual(new DateTime(2000, 12, 20), (DateTime)new JValue(new DateTime(2000, 12, 20))); + Assert.AreEqual(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero), (DateTimeOffset)new JValue(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero))); + Assert.AreEqual(true, (bool)new JValue(true)); + Assert.AreEqual(true, (bool?)new JValue(true)); + Assert.AreEqual(null, (bool?)((JValue)null)); + Assert.AreEqual(null, (bool?)JValue.Null); + Assert.AreEqual(null, (bool?)JValue.Undefined); + Assert.AreEqual(10, (long)new JValue(10)); + Assert.AreEqual(null, (long?)new JValue((long?)null)); + Assert.AreEqual(null, (long?)(JValue)null); + Assert.AreEqual(null, (int?)new JValue((int?)null)); + Assert.AreEqual(null, (int?)(JValue)null); + Assert.AreEqual(null, (DateTime?)new JValue((DateTime?)null)); + Assert.AreEqual(null, (DateTimeOffset?)new JValue((DateTimeOffset?)null)); + Assert.AreEqual(null, (DateTime?)(JValue)null); + Assert.AreEqual(null, (DateTimeOffset?)(JValue)null); + Assert.AreEqual(null, (short?)new JValue((short?)null)); + Assert.AreEqual(null, (short?)(JValue)null); + Assert.AreEqual(null, (float?)new JValue((float?)null)); + Assert.AreEqual(null, (float?)(JValue)null); + Assert.AreEqual(null, (double?)new JValue((double?)null)); + Assert.AreEqual(null, (double?)(JValue)null); + Assert.AreEqual(null, (decimal?)new JValue((decimal?)null)); + Assert.AreEqual(null, (decimal?)(JValue)null); + Assert.AreEqual(null, (uint?)new JValue((uint?)null)); + Assert.AreEqual(null, (uint?)(JValue)null); + Assert.AreEqual(null, (sbyte?)new JValue((sbyte?)null)); + Assert.AreEqual(null, (sbyte?)(JValue)null); + Assert.AreEqual(null, (ulong?)new JValue((ulong?)null)); + Assert.AreEqual(null, (ulong?)(JValue)null); + Assert.AreEqual(null, (uint?)new JValue((uint?)null)); + Assert.AreEqual(null, (uint?)(JValue)null); + Assert.AreEqual(11.1f, (float)new JValue(11.1)); + Assert.AreEqual(float.MinValue, (float)new JValue(float.MinValue)); + Assert.AreEqual(1.1, (double)new JValue(1.1)); + Assert.AreEqual(uint.MaxValue, (uint)new JValue(uint.MaxValue)); + Assert.AreEqual(ulong.MaxValue, (ulong)new JValue(ulong.MaxValue)); + Assert.AreEqual(ulong.MaxValue, (ulong)new JProperty("Test", new JValue(ulong.MaxValue))); + Assert.AreEqual(null, (string)new JValue((string)null)); + } + + [Test] + public void Root() + { + JArray a = + new JArray( + 5, + 6, + new JArray(7, 8), + new JArray(9, 10) + ); + + Assert.AreEqual(a, a.Root); + Assert.AreEqual(a, a[0].Root); + Assert.AreEqual(a, ((JArray)a[2])[0].Root); + } + + [Test] + public void Remove() + { + JToken t; + JArray a = + new JArray( + 5, + 6, + new JArray(7, 8), + new JArray(9, 10) + ); + + a[0].Remove(); + + Assert.AreEqual(6, (int)a[0]); + + a[1].Remove(); + + Assert.AreEqual(6, (int)a[0]); + Assert.IsTrue(JToken.DeepEquals(new JArray(9, 10), a[1])); + Assert.AreEqual(2, a.Count()); + + t = a[1]; + t.Remove(); + Assert.AreEqual(6, (int)a[0]); + Assert.IsNull(t.Next); + Assert.IsNull(t.Previous); + Assert.IsNull(t.Parent); + + t = a[0]; + t.Remove(); + Assert.AreEqual(0, a.Count()); + + Assert.IsNull(t.Next); + Assert.IsNull(t.Previous); + Assert.IsNull(t.Parent); + } + + [Test] + public void AfterSelf() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + JToken t = a[1]; + List afterTokens = t.AfterSelf().ToList(); + + Assert.AreEqual(2, afterTokens.Count); + Assert.IsTrue(JToken.DeepEquals(new JArray(1, 2), afterTokens[0])); + Assert.IsTrue(JToken.DeepEquals(new JArray(1, 2, 3), afterTokens[1])); + } + + [Test] + public void BeforeSelf() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + JToken t = a[2]; + List beforeTokens = t.BeforeSelf().ToList(); + + Assert.AreEqual(2, beforeTokens.Count); + Assert.IsTrue(JToken.DeepEquals(new JValue(5), beforeTokens[0])); + Assert.IsTrue(JToken.DeepEquals(new JArray(1), beforeTokens[1])); + } + + [Test] + public void HasValues() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + Assert.IsTrue(a.HasValues); + } + + [Test] + public void Ancestors() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + JToken t = a[1][0]; + List ancestors = t.Ancestors().ToList(); + Assert.AreEqual(2, ancestors.Count()); + Assert.AreEqual(a[1], ancestors[0]); + Assert.AreEqual(a, ancestors[1]); + } + + [Test] + public void Descendants() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + List descendants = a.Descendants().ToList(); + Assert.AreEqual(10, descendants.Count()); + Assert.AreEqual(5, (int)descendants[0]); + Assert.IsTrue(JToken.DeepEquals(new JArray(1, 2, 3), descendants[descendants.Count - 4])); + Assert.AreEqual(1, (int)descendants[descendants.Count - 3]); + Assert.AreEqual(2, (int)descendants[descendants.Count - 2]); + Assert.AreEqual(3, (int)descendants[descendants.Count - 1]); + } + + [Test] + public void CreateWriter() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + JsonWriter writer = a.CreateWriter(); + Assert.IsNotNull(writer); + Assert.AreEqual(4, a.Count()); + + writer.WriteValue("String"); + Assert.AreEqual(5, a.Count()); + Assert.AreEqual("String", (string)a[4]); + + writer.WriteStartObject(); + writer.WritePropertyName("Property"); + writer.WriteValue("PropertyValue"); + writer.WriteEnd(); + + Assert.AreEqual(6, a.Count()); + Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("Property", "PropertyValue")), a[5])); + } + + [Test] + public void AddFirst() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + a.AddFirst("First"); + + Assert.AreEqual("First", (string)a[0]); + Assert.AreEqual(a, a[0].Parent); + Assert.AreEqual(a[1], a[0].Next); + Assert.AreEqual(5, a.Count()); + + a.AddFirst("NewFirst"); + Assert.AreEqual("NewFirst", (string)a[0]); + Assert.AreEqual(a, a[0].Parent); + Assert.AreEqual(a[1], a[0].Next); + Assert.AreEqual(6, a.Count()); + + Assert.AreEqual(a[0], a[0].Next.Previous); + } + + [Test] + public void RemoveAll() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + JToken first = a.First; + Assert.AreEqual(5, (int)first); + + a.RemoveAll(); + Assert.AreEqual(0, a.Count()); + + Assert.IsNull(first.Parent); + Assert.IsNull(first.Next); + } + + [Test] + [ExpectedException(typeof(Exception), ExpectedMessage = "Can not add Newtonsoft.Json.Linq.JProperty to Newtonsoft.Json.Linq.JArray")] + public void AddPropertyToArray() + { + JArray a = new JArray(); + a.Add(new JProperty("PropertyName")); + } + + [Test] + [ExpectedException(typeof(Exception), ExpectedMessage = "Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject")] + public void AddValueToObject() + { + JObject o = new JObject(); + o.Add(5); + } + + [Test] + public void Replace() + { + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + a[0].Replace(new JValue(int.MaxValue)); + Assert.AreEqual(int.MaxValue, (int)a[0]); + Assert.AreEqual(4, a.Count()); + + a[1][0].Replace(new JValue("Test")); + Assert.AreEqual("Test", (string)a[1][0]); + + a[2].Replace(new JValue(int.MaxValue)); + Assert.AreEqual(int.MaxValue, (int)a[2]); + Assert.AreEqual(4, a.Count()); + + Assert.IsTrue(JToken.DeepEquals(new JArray(int.MaxValue, new JArray("Test"), int.MaxValue, new JArray(1, 2, 3)), a)); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs new file mode 100644 index 00000000..539b1295 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs @@ -0,0 +1,164 @@ +#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.Linq; + +namespace Newtonsoft.Json.Tests.Linq +{ + public class JValueTests : TestFixtureBase + { + [Test] + public void ChangeValue() + { + JValue v = new JValue(true); + Assert.AreEqual(true, v.Value); + Assert.AreEqual(JsonTokenType.Boolean, v.Type); + + v.Value = "Pie"; + Assert.AreEqual("Pie", v.Value); + Assert.AreEqual(JsonTokenType.String, v.Type); + + v.Value = null; + Assert.AreEqual(null, v.Value); + Assert.AreEqual(JsonTokenType.Null, v.Type); + + v.Value = (int?)null; + Assert.AreEqual(null, v.Value); + Assert.AreEqual(JsonTokenType.Null, v.Type); + + v.Value = "Pie"; + Assert.AreEqual("Pie", v.Value); + Assert.AreEqual(JsonTokenType.String, v.Type); + } + + [Test] + public void CreateComment() + { + JValue commentValue = JValue.CreateComment(null); + Assert.AreEqual(null, commentValue.Value); + Assert.AreEqual(JsonTokenType.Comment, commentValue.Type); + + commentValue.Value = "Comment"; + Assert.AreEqual("Comment", commentValue.Value); + Assert.AreEqual(JsonTokenType.Comment, commentValue.Type); + } + + [Test] + public void CreateString() + { + JValue stringValue = JValue.CreateString(null); + Assert.AreEqual(null, stringValue.Value); + Assert.AreEqual(JsonTokenType.String, stringValue.Type); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Cannot access child value on Newtonsoft.Json.Linq.JValue.")] + public void Last() + { + JValue v = new JValue(true); + JToken last = v.Last; + } + + [Test] + [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Cannot access child value on Newtonsoft.Json.Linq.JValue.")] + public void Children() + { + JValue v = new JValue(true); + var c = v.Children(); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Cannot access child value on Newtonsoft.Json.Linq.JValue.")] + public void First() + { + JValue v = new JValue(true); + JToken first = v.First; + } + + [Test] + [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Cannot access child value on Newtonsoft.Json.Linq.JValue.")] + public void Item() + { + JValue v = new JValue(true); + JToken first = v[0]; + } + + [Test] + [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Cannot access child value on Newtonsoft.Json.Linq.JValue.")] + public void Values() + { + JValue v = new JValue(true); + v.Values(); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "The parent is missing.")] + public void RemoveParentNull() + { + JValue v = new JValue(true); + v.Remove(); + } + + [Test] + public void Root() + { + JValue v = new JValue(true); + Assert.AreEqual(v, v.Root); + } + + [Test] + public void Previous() + { + JValue v = new JValue(true); + Assert.IsNull(v.Previous); + } + + [Test] + public void Next() + { + JValue v = new JValue(true); + Assert.IsNull(v.Next); + } + + [Test] + public void DeepEquals() + { + Assert.IsTrue(JToken.DeepEquals(new JValue(5L), new JValue(5))); + Assert.IsFalse(JToken.DeepEquals(new JValue(5M), new JValue(5))); + Assert.IsTrue(JToken.DeepEquals(new JValue((ulong)long.MaxValue), new JValue(long.MaxValue))); + } + + [Test] + public void HasValues() + { + Assert.IsFalse((new JValue(5L)).HasValues); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/LinqToJsonTest.cs b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs similarity index 90% rename from Src/Newtonsoft.Json.Tests/LinqToJsonTest.cs rename to Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs index f0489325..74d860ae 100644 --- a/Src/Newtonsoft.Json.Tests/LinqToJsonTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs @@ -33,7 +33,7 @@ using System.Xml; using System.IO; using Newtonsoft.Json.Converters; -namespace Newtonsoft.Json.Tests +namespace Newtonsoft.Json.Tests.Linq { public class LinqToJsonTest : TestFixtureBase { @@ -170,6 +170,13 @@ keyword such as type of business."" List resultObjects = o["results"].Children().ToList(); + Assert.AreEqual(32, resultObjects.Properties().Count()); + + Assert.AreEqual(32, resultObjects.Cast().Values().Count()); + + Assert.AreEqual(4, resultObjects.Cast().Values("GsearchResultClass").Count()); + + Assert.AreEqual(5, o.PropertyValues().Cast().Children().Count()); List resultUrls = o["results"].Children().Values("url").ToList(); @@ -577,5 +584,42 @@ keyword such as type of business."" Assert.IsInstanceOfType(typeof(JArray), a); Assert.AreEqual(5, a.Count()); } + + [Test] + public void FromAnonDictionary() + { + List posts = GetPosts(); + + JObject o = JObject.FromObject(new + { + channel = new Dictionary + { + { "title", "James Newton-King" }, + { "link", "http://james.newtonking.com" }, + { "description", "James Newton-King's blog." }, + { "item", + (from p in posts + orderby p.Title + select new + { + title = p.Title, + description = p.Description, + link = p.Link, + category = p.Categories + }) + } + } + }); + + Console.WriteLine(o.ToString()); + Assert.IsInstanceOfType(typeof(JObject), o); + Assert.IsInstanceOfType(typeof(JObject), o["channel"]); + Assert.AreEqual("James Newton-King", (string)o["channel"]["title"]); + Assert.AreEqual(2, o["channel"]["item"].Children().Count()); + + JArray a = JArray.FromObject(new List() { 0, 1, 2, 3, 4 }); + Assert.IsInstanceOfType(typeof(JArray), a); + Assert.AreEqual(5, a.Count()); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index a98a09db..29f702be 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -70,19 +70,20 @@ - + - + - - + + + - + diff --git a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs index 6b0b9a90..e04fba57 100644 --- a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs +++ b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs @@ -1,4 +1,29 @@ -using System; +#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; diff --git a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs index 61ca3c0e..7a1a6ce3 100644 --- a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs @@ -49,7 +49,7 @@ namespace Newtonsoft.Json.Converters public override object ReadJson(JsonReader reader, Type objectType) { if (reader.TokenType != JsonToken.String) - throw new Exception("Unexpected token parsing date. Expected String, got {0}.".FormatWith(reader.TokenType)); + throw new Exception("Unexpected token parsing date. Expected String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); string dateText = reader.Value.ToString(); diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs index fb798c73..3b569596 100644 --- a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs @@ -34,12 +34,12 @@ namespace Newtonsoft.Json.Converters public override object ReadJson(JsonReader reader, Type objectType) { if (reader.TokenType != JsonToken.StartConstructor || string.Compare(reader.Value.ToString(), "Date", StringComparison.Ordinal) != 0) - throw new Exception("Unexpected token or value when parsing date. Token: {0}, Value: {1}".FormatWith(reader.TokenType, reader.Value)); + throw new Exception("Unexpected token or value when parsing date. Token: {0}, Value: {1}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType, reader.Value)); reader.Read(); if (reader.TokenType != JsonToken.Integer) - throw new Exception("Unexpected token parsing date. Expected Integer, got {0}.".FormatWith(reader.TokenType)); + throw new Exception("Unexpected token parsing date. Expected Integer, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); long ticks = (long)reader.Value; @@ -48,7 +48,7 @@ namespace Newtonsoft.Json.Converters reader.Read(); if (reader.TokenType != JsonToken.EndConstructor) - throw new Exception("Unexpected token parsing date. Expected EndConstructor, got {0}.".FormatWith(reader.TokenType)); + throw new Exception("Unexpected token parsing date. Expected EndConstructor, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); if (objectType == typeof(DateTimeOffset)) return new DateTimeOffset(d); diff --git a/Src/Newtonsoft.Json/JavaScriptConvert.cs b/Src/Newtonsoft.Json/JavaScriptConvert.cs index 075f609a..5c628e16 100644 --- a/Src/Newtonsoft.Json/JavaScriptConvert.cs +++ b/Src/Newtonsoft.Json/JavaScriptConvert.cs @@ -384,7 +384,7 @@ namespace Newtonsoft.Json return ToString((Guid)value); } - throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(value.GetType())); + throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())); } /// diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index 1c4c99b1..267f6e90 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -239,7 +239,7 @@ namespace Newtonsoft.Json JsonTokenType currentObject = Pop(); if (GetTypeForCloseToken(endToken) != currentObject) - throw new JsonReaderException("JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(endToken, currentObject)); + throw new JsonReaderException("JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, currentObject)); } protected void SetStateBasedOnCurrent() diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs index 7ff34d07..431ef99e 100644 --- a/Src/Newtonsoft.Json/JsonSerializer.cs +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -290,7 +290,7 @@ namespace Newtonsoft.Json return new DateTimeOffset((DateTime)value); if (!targetType.IsAssignableFrom(valueType)) - throw new InvalidOperationException("Cannot convert object of type '{0}' to type '{1}'".FormatWith(value.GetType(), targetType)); + throw new InvalidOperationException("Cannot convert object of type '{0}' to type '{1}'".FormatWith(CultureInfo.InvariantCulture, value.GetType(), targetType)); return value; } @@ -369,7 +369,7 @@ namespace Newtonsoft.Json 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(memberName)); + throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); MemberMappingCollection memberMappings = GetMemberMappings(targetType); Type memberType; @@ -413,7 +413,7 @@ namespace Newtonsoft.Json else { if (_missingMemberHandling == MissingMemberHandling.Error) - throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(memberName, targetType.GetType().Name)); + throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, targetType.GetType().Name)); } } @@ -511,7 +511,7 @@ namespace Newtonsoft.Json .SingleOrDefault(); if (!reader.Read()) - throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(memberName)); + throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); if (matchingConstructorParameter != null) constructorParameters[matchingConstructorParameter] = CreateObject(reader, matchingConstructorParameter.ParameterType, null); @@ -731,7 +731,7 @@ namespace Newtonsoft.Json // continue break; default: - throw new InvalidOperationException("Unexpected ReferenceLoopHandling value: '{0}'".FormatWith(_referenceLoopHandling)); + throw new InvalidOperationException("Unexpected ReferenceLoopHandling value: '{0}'".FormatWith(CultureInfo.InvariantCulture, _referenceLoopHandling)); } } diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 83f3d506..05061143 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -30,6 +30,7 @@ using System.IO; using System.Xml; using Newtonsoft.Json.Utilities; using Newtonsoft.Json.Linq; +using System.Globalization; namespace Newtonsoft.Json { @@ -513,7 +514,7 @@ namespace Newtonsoft.Json State newState = stateArray[token, (int)_currentState]; if (newState == State.Error) - throw new JsonWriterException("Token {0} in state {1} would result in an invalid JavaScript object.".FormatWith(tokenBeingWritten.ToString(), _currentState.ToString())); + throw new JsonWriterException("Token {0} in state {1} would result in an invalid JavaScript object.".FormatWith(CultureInfo.InvariantCulture, tokenBeingWritten.ToString(), _currentState.ToString())); if ((_currentState == State.Object || _currentState == State.Array || _currentState == State.Constructor) && tokenBeingWritten != JsonToken.Comment) { diff --git a/Src/Newtonsoft.Json/Linq/Extensions.cs b/Src/Newtonsoft.Json/Linq/Extensions.cs index 01b1a1c0..02ea7e9a 100644 --- a/Src/Newtonsoft.Json/Linq/Extensions.cs +++ b/Src/Newtonsoft.Json/Linq/Extensions.cs @@ -142,6 +142,11 @@ namespace Newtonsoft.Json.Linq // return source.SelectMany(c => c.Children()); //} + public static IEnumerable Children(this IEnumerable source) + { + return Children(source); + } + public static IEnumerable Children(this IEnumerable source) { ValidationUtils.ArgumentNotNull(source, "source"); @@ -182,7 +187,7 @@ namespace Newtonsoft.Json.Linq JValue value = token as JValue; if (value == null) - throw new InvalidCastException("Cannot cast {0} to {1}.".FormatWith(token.GetType(), typeof(T))); + throw new InvalidCastException("Cannot cast {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, token.GetType(), typeof(T))); return (U)System.Convert.ChangeType(value.Value, typeof(U), CultureInfo.InvariantCulture); } diff --git a/Src/Newtonsoft.Json/Linq/JArray.cs b/Src/Newtonsoft.Json/Linq/JArray.cs index f6fbc598..a35c4677 100644 --- a/Src/Newtonsoft.Json/Linq/JArray.cs +++ b/Src/Newtonsoft.Json/Linq/JArray.cs @@ -29,6 +29,7 @@ using System.Linq; using System.Text; using Newtonsoft.Json.Utilities; using System.IO; +using System.Globalization; namespace Newtonsoft.Json.Linq { @@ -109,7 +110,7 @@ namespace Newtonsoft.Json.Linq ValidationUtils.ArgumentNotNull(o, "o"); if (o.Type == JsonTokenType.Property) - throw new ArgumentException("An item of type {0} cannot be added to content.".FormatWith(o.Type)); + throw new ArgumentException("An item of type {0} cannot be added to content.".FormatWith(CultureInfo.InvariantCulture, o.Type)); } public static JArray FromObject(object o) @@ -117,7 +118,7 @@ namespace Newtonsoft.Json.Linq JToken token = FromObjectInternal(o); if (token.Type != JsonTokenType.Array) - throw new ArgumentException("Object serialized to {0}. JArray instance expected.".FormatWith(token.Type)); + throw new ArgumentException("Object serialized to {0}. JArray instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type)); return (JArray)token; } @@ -141,7 +142,7 @@ namespace Newtonsoft.Json.Linq ValidationUtils.ArgumentNotNull(key, "o"); if (!(key is int)) - throw new ArgumentException("Accessed JArray values with invalid key value: {0}. Array position index expected.".FormatWith(MiscellaneousUtils.ToString(key))); + throw new ArgumentException("Accessed JArray values with invalid key value: {0}. Array position index expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key))); return GetIndex(this, (int)key); } diff --git a/Src/Newtonsoft.Json/Linq/JConstructor.cs b/Src/Newtonsoft.Json/Linq/JConstructor.cs index 0e75a9c0..9b7f2f9a 100644 --- a/Src/Newtonsoft.Json/Linq/JConstructor.cs +++ b/Src/Newtonsoft.Json/Linq/JConstructor.cs @@ -28,6 +28,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using Newtonsoft.Json.Utilities; +using System.Globalization; namespace Newtonsoft.Json.Linq { @@ -53,6 +54,7 @@ namespace Newtonsoft.Json.Linq public JConstructor(JConstructor other) : base(other) { + _name = other.Name; } public JConstructor(string name, params object[] content) @@ -89,7 +91,7 @@ namespace Newtonsoft.Json.Linq switch (o.Type) { case JsonTokenType.Property: - throw new ArgumentException("An item of type {0} cannot be added to content.".FormatWith(o.Type)); + throw new ArgumentException("An item of type {0} cannot be added to content.".FormatWith(CultureInfo.InvariantCulture, o.Type)); } } @@ -112,7 +114,7 @@ namespace Newtonsoft.Json.Linq ValidationUtils.ArgumentNotNull(key, "o"); if (!(key is int)) - throw new ArgumentException("Accessed JConstructor values with invalid key value: {0}. Argument position index expected.".FormatWith(MiscellaneousUtils.ToString(key))); + throw new ArgumentException("Accessed JConstructor values with invalid key value: {0}. Argument position index expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key))); return GetIndex(this, (int)key); } diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index 55bc923e..ac62949e 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -30,6 +30,7 @@ using System.Text; using Newtonsoft.Json.Utilities; using System.Collections; using System.Diagnostics; +using System.Globalization; namespace Newtonsoft.Json.Linq { @@ -56,13 +57,18 @@ namespace Newtonsoft.Json.Linq { do { - content = content.Next; + content = content._next; Add(content.CloneNode()); } while (content != other.Last); } } + public override bool HasValues + { + get { return (_content != null); } + } + internal bool ContentsEqual(JContainer container) { JToken t1 = First; @@ -96,7 +102,7 @@ namespace Newtonsoft.Json.Linq if (Last == null) return null; - return Last.Next; + return Last._next; } } @@ -121,7 +127,9 @@ namespace Newtonsoft.Json.Linq do { yield return current; - } while ((current = current.Next) != first); + } + while (current != null + && ((current = current.Next) != null)); } public override IEnumerable Values() @@ -178,14 +186,17 @@ namespace Newtonsoft.Json.Linq return (content is IEnumerable && !(content is string)); } - public virtual void Add(object content) + internal void AddInternal(bool isLast, JToken previous, object content) { if (IsMultiContent(content)) { IEnumerable enumerable = content as IEnumerable; + + JToken multiPrevious = previous; foreach (object c in enumerable) { - Add(c); + AddInternal(isLast, multiPrevious, c); + multiPrevious = (previous != null) ? previous._next : Last; } } else @@ -211,46 +222,48 @@ namespace Newtonsoft.Json.Linq } } - JToken last = Last; - JToken next = First ?? o; + JToken next = (previous != null) ? previous._next : o; o.Parent = this; o.Next = next; - if (last != null) - last.Next = o; - _content = o; + if (previous != null) + previous.Next = o; + + if (isLast) + _content = o; } } internal virtual void ValidateToken(JToken o) { - //throw new NotImplementedException(); + ValidationUtils.ArgumentNotNull(o, "o"); + + if (o.Type == JsonTokenType.Property) + throw new Exception("Can not add {0} to {1}".FormatWith(CultureInfo.InvariantCulture, o.GetType(), GetType())); + } + + public virtual void Add(object content) + { + AddInternal(true, Last, content); } public void AddFirst(object content) { - JToken o = CreateFromContent(content); - - JToken last = Parent.Last; - - o.Parent = Parent; - o.Next = last.Next; - - last.Next = o; + AddInternal(false, Last, content); } protected JToken CreateFromContent(object content) { if (content is JToken) return (JToken)content; - - return new JValue(content); + else + return new JValue(content); } public JsonWriter CreateWriter() { - return null; + return new JsonTokenWriter(this); } public void ReplaceAll(object content) @@ -265,17 +278,17 @@ namespace Newtonsoft.Json.Linq { JToken o = _content; - JToken next = o.Next; - if (o != _content || next != o.Next) + JToken next = o._next; + if (o != _content || next != o._next) throw new InvalidOperationException("This operation was corrupted by external code."); if (next != o) - o.Next = next.Next; + o._next = next._next; else _content = null; next.Parent = null; - next.Next = null; + next._next = null; } } @@ -286,12 +299,13 @@ namespace Newtonsoft.Json.Linq JToken content = _content; - while (_content.Next != o) + while (content._next != o) { - content = content.Next; + content = content._next; } if (content == o) { + // token is containers last child _content = null; } else @@ -300,7 +314,7 @@ namespace Newtonsoft.Json.Linq { _content = content; } - content.Next = o.Next; + content._next = o._next; } o.Parent = null; o.Next = null; @@ -391,7 +405,7 @@ namespace Newtonsoft.Json.Linq parent = property; break; default: - throw new InvalidOperationException("The JsonReader should not be on a token of type {0}.".FormatWith(r.TokenType)); + throw new InvalidOperationException("The JsonReader should not be on a token of type {0}.".FormatWith(CultureInfo.InvariantCulture, r.TokenType)); } } while (r.Read()); diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs index a64f0959..7e37a1ed 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.cs @@ -29,6 +29,7 @@ using System.Linq; using System.Text; using System.IO; using Newtonsoft.Json.Utilities; +using System.Globalization; namespace Newtonsoft.Json.Linq { @@ -59,6 +60,14 @@ namespace Newtonsoft.Json.Linq return (t != null && ContentsEqual(t)); } + internal override void ValidateToken(JToken o) + { + ValidationUtils.ArgumentNotNull(o, "o"); + + if (o.Type != JsonTokenType.Property) + throw new Exception("Can not add {0} to {1}".FormatWith(CultureInfo.InvariantCulture, o.GetType(), GetType())); + } + internal override JToken CloneNode() { return new JObject(this); @@ -86,15 +95,15 @@ namespace Newtonsoft.Json.Linq return new JEnumerable(Properties().Select(p => p.Value)); } - public override void Add(object content) - { - ValidationUtils.ArgumentNotNull(content, "content"); + //public override void Add(object content) + //{ + // ValidationUtils.ArgumentNotNull(content, "content"); - if (!(content is JProperty) && !IsMultiContent(content)) - throw new ArgumentException("Error adding {0} to JObject. JObject only supports JProperty content.".FormatWith(content.GetType().Name)); + // if (!(content is JProperty) && !IsMultiContent(content)) + // throw new ArgumentException("Error adding {0} to JObject. JObject only supports JProperty content.".FormatWith(CultureInfo.InvariantCulture, content.GetType().Name)); - base.Add(content); - } + // base.Add(content); + //} public override JToken this[object key] { @@ -104,7 +113,7 @@ namespace Newtonsoft.Json.Linq string propertyName = key as string; if (propertyName == null) - throw new ArgumentException("Accessed JObject values with invalid key value: {0}. Object property name expected.".FormatWith(MiscellaneousUtils.ToString(key))); + throw new ArgumentException("Accessed JObject values with invalid key value: {0}. Object property name expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key))); JProperty property = Property(propertyName); @@ -149,7 +158,7 @@ namespace Newtonsoft.Json.Linq JToken token = FromObjectInternal(o); if (token.Type != JsonTokenType.Object) - throw new ArgumentException("Object serialized to {0}. JObject instance expected.".FormatWith(token.Type)); + throw new ArgumentException("Object serialized to {0}. JObject instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type)); return (JObject)token; } @@ -159,7 +168,7 @@ namespace Newtonsoft.Json.Linq ValidationUtils.ArgumentNotNull(o, "o"); if (o.Type != JsonTokenType.Property) - throw new ArgumentException("An item of type {0} cannot be added to content.".FormatWith(o.Type)); + throw new ArgumentException("An item of type {0} cannot be added to content.".FormatWith(CultureInfo.InvariantCulture, o.Type)); } public override void WriteTo(JsonWriter writer, params JsonConverter[] converters) diff --git a/Src/Newtonsoft.Json/Linq/JProperty.cs b/Src/Newtonsoft.Json/Linq/JProperty.cs index cdc35ec6..d5728d06 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.cs @@ -29,6 +29,7 @@ using System.Linq; using System.Text; using Newtonsoft.Json.Utilities; using System.Diagnostics; +using System.Globalization; namespace Newtonsoft.Json.Linq { @@ -95,7 +96,7 @@ namespace Newtonsoft.Json.Linq ValidationUtils.ArgumentNotNull(o, "o"); if (o.Type == JsonTokenType.Property) - throw new ArgumentException("An item of type {0} cannot be added to content.".FormatWith(o.Type)); + throw new ArgumentException("An item of type {0} cannot be added to content.".FormatWith(CultureInfo.InvariantCulture, o.Type)); } public override void WriteTo(JsonWriter writer, params JsonConverter[] converters) @@ -103,5 +104,20 @@ namespace Newtonsoft.Json.Linq writer.WritePropertyName(_name); Value.WriteTo(writer, converters); } + + //public static explicit operator JValue(JProperty property) + //{ + // if (property == null) + // return null; + + // JToken value = property.Value; + // if (value == null) + // return null; + + // if (!(value is JValue)) + // throw new Exception("Could not cast {0} to JValue".FormatWith(CultureInfo.InvariantCulture, value.GetType())); + + // return (JValue)value; + //} } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 939cf809..5400905f 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -37,7 +37,7 @@ namespace Newtonsoft.Json.Linq public abstract class JToken { private JContainer _parent; - private JToken _next; + internal JToken _next; public JContainer Parent { @@ -48,13 +48,26 @@ namespace Newtonsoft.Json.Linq public JToken Root { - get { return null; } + get + { + JContainer parent = Parent; + if (parent == null) + return this; + + while (parent.Parent != null) + { + parent = parent.Parent; + } + + return parent; + } } internal abstract JToken CloneNode(); internal abstract bool DeepEquals(JToken node); public abstract JsonTokenType Type { get; } + public abstract bool HasValues { get; } public static bool DeepEquals(JToken t1, JToken t2) { @@ -65,10 +78,10 @@ namespace Newtonsoft.Json.Linq { get { - if (_parent == null) - return null; + if (_parent != null && _next != _parent.First) + return _next; - return _next; + return null; } internal set { _next = value; } } @@ -80,7 +93,7 @@ namespace Newtonsoft.Json.Linq if (_parent == null) return null; - JToken parentNext = ((JToken)_parent.Content).Next; + JToken parentNext = ((JToken)_parent.Content)._next; JToken parentNextBefore = null; while (parentNext != this) { @@ -91,11 +104,6 @@ namespace Newtonsoft.Json.Linq } } - public bool HasValues - { - get { return false; } - } - public IEnumerable Ancestors() { for (JToken parent = Parent; parent != null; parent = parent.Parent) @@ -121,7 +129,7 @@ namespace Newtonsoft.Json.Linq public virtual JToken this[object key] { - get { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(GetType())); } + get { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } } public virtual T Value(object key) @@ -133,19 +141,19 @@ namespace Newtonsoft.Json.Linq public virtual JToken First { - get { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(GetType())); } + get { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } //get { return null; } } public virtual JToken Last { - get { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(GetType())); } + get { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } //get { return null; } } public virtual JEnumerable Children() { - throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(GetType())); + throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); //return JEnumerable.Empty; } @@ -156,12 +164,12 @@ namespace Newtonsoft.Json.Linq public virtual IEnumerable Values() { - throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(GetType())); + throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } //public virtual IEnumerable Children() // { - // throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(GetType())); + // throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); // //return Enumerable.Empty(); // } @@ -175,6 +183,23 @@ namespace Newtonsoft.Json.Linq public void Replace(JToken value) { + if (_parent == null) + throw new InvalidOperationException("The parent is missing."); + + JContainer parent = _parent; + + JToken previous = this; + while (previous._next != this) + { + previous = previous._next; + } + if (previous == this) + previous = null; + + bool isLast = (this == _parent.Last); + + Remove(); + parent.AddInternal(isLast, previous, value); } public abstract void WriteTo(JsonWriter writer, params JsonConverter[] converters); @@ -240,12 +265,17 @@ namespace Newtonsoft.Json.Linq return (o.Type == JsonTokenType.String || IsNullable(o)); } + private static string GetType(JToken t) + { + return (t != null) ? t.Type.ToString() : "{null}"; + } + #region Cast operators public static explicit operator bool(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateBoolean(v, false)) - throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (bool)v.Value; } @@ -254,7 +284,7 @@ namespace Newtonsoft.Json.Linq { JValue v = EnsureValue(value); if (v == null || !ValidateDate(v, false)) - throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (DateTimeOffset)v.Value; } @@ -266,7 +296,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateBoolean(v, true)) - throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (bool?)v.Value; } @@ -275,7 +305,7 @@ namespace Newtonsoft.Json.Linq { JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, false)) - throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (long)v.Value; } @@ -287,7 +317,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateDate(v, true)) - throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (DateTime?)v.Value; } @@ -299,7 +329,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateDate(v, true)) - throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (DateTimeOffset?)v.Value; } @@ -311,7 +341,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, true)) - throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (decimal?)v.Value; } @@ -323,7 +353,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, true)) - throw new ArgumentException("Can not convert {0} to Double.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (double?)v.Value; } @@ -332,7 +362,7 @@ namespace Newtonsoft.Json.Linq { JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, false)) - throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return Convert.ToInt32(v.Value, CultureInfo.InvariantCulture); } @@ -344,7 +374,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, true)) - throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (v.Value != null) ? (int?)Convert.ToInt32(v.Value, CultureInfo.InvariantCulture) : null; } @@ -353,7 +383,7 @@ namespace Newtonsoft.Json.Linq { JValue v = EnsureValue(value); if (v == null || !ValidateDate(v, false)) - throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (DateTime)v.Value; } @@ -365,7 +395,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, true)) - throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (long?)v.Value; } @@ -377,7 +407,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, true)) - throw new ArgumentException("Can not convert {0} to Single.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (float?)v.Value; } @@ -386,7 +416,7 @@ namespace Newtonsoft.Json.Linq { JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, false)) - throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (decimal)v.Value; } @@ -398,7 +428,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, true)) - throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (uint?)v.Value; } @@ -410,7 +440,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, true)) - throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (ulong?)v.Value; } @@ -419,7 +449,7 @@ namespace Newtonsoft.Json.Linq { JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, false)) - throw new ArgumentException("Can not convert {0} to Double.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (double)v.Value; } @@ -428,9 +458,9 @@ namespace Newtonsoft.Json.Linq { JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, false)) - throw new ArgumentException("Can not convert {0} to Single.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); - return (float)v.Value; + return Convert.ToSingle(v.Value, CultureInfo.InvariantCulture); } public static explicit operator string(JToken value) @@ -440,7 +470,7 @@ namespace Newtonsoft.Json.Linq JValue v = EnsureValue(value); if (v == null || !ValidateString(v)) - throw new ArgumentException("Can not convert {0} to String.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to String.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); return (string)v.Value; } @@ -449,18 +479,18 @@ namespace Newtonsoft.Json.Linq { JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, false)) - throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); - return (uint)v.Value; + return Convert.ToUInt32(v.Value, CultureInfo.InvariantCulture); } public static explicit operator ulong(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, false)) - throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(v.Type)); + throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); - return (ulong)v.Value; + return Convert.ToUInt64(v.Value, CultureInfo.InvariantCulture); } #endregion } diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs index 849ce116..7b81435f 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.cs @@ -56,6 +56,11 @@ namespace Newtonsoft.Json.Linq { } + public JValue(ulong value) + : this(value, JsonTokenType.Integer) + { + } + public JValue(double value) : this(value, JsonTokenType.Float) { @@ -77,7 +82,7 @@ namespace Newtonsoft.Json.Linq } public JValue(object value) - : this(value, GetValueType(value)) + : this(value, GetValueType(null, value)) { } @@ -87,7 +92,37 @@ namespace Newtonsoft.Json.Linq if (other == null) return false; - return (this == other || (_valueType == other.Type && _value == other.Value)); + return (this == other || (_valueType == other.Type && Compare(_value, other.Value))); + } + + public override bool HasValues + { + get { return false; } + } + + public bool Compare(object objA, object objB) + { + if (objA == null && objB == null) + return true; + + switch (_valueType) + { + case JsonTokenType.Integer: + if (objA is ulong || objB is ulong) + return Convert.ToDecimal(objA).Equals(Convert.ToDecimal(objB)); + else + return Convert.ToInt64(objA).Equals(Convert.ToInt64(objB)); + case JsonTokenType.Float: + return Convert.ToDouble(objA).Equals(Convert.ToDouble(objB)); + case JsonTokenType.Comment: + case JsonTokenType.String: + case JsonTokenType.Boolean: + return objA.Equals(objB); + case JsonTokenType.Date: + return objA.Equals(objB); + default: + throw new ArgumentOutOfRangeException("valueType", _valueType, "Unexpected value type: {0}".FormatWith(CultureInfo.InvariantCulture, _valueType)); + } } internal override JToken CloneNode() @@ -100,12 +135,12 @@ namespace Newtonsoft.Json.Linq return new JValue(value, JsonTokenType.Comment); } - private static JsonTokenType GetValueType(object value) + private static JsonTokenType GetValueType(JsonTokenType? current, object value) { if (value == null) return JsonTokenType.Null; else if (value is string) - return JsonTokenType.String; + return (current == JsonTokenType.Comment) ? JsonTokenType.Comment : JsonTokenType.String; else if (value is long || value is int || value is short || value is sbyte || value is ulong || value is uint || value is ushort || value is byte) return JsonTokenType.Integer; @@ -116,7 +151,7 @@ namespace Newtonsoft.Json.Linq else if (value is bool) return JsonTokenType.Boolean; - throw new ArgumentException("Could not determin JSON object type for type {0}.".FormatWith(value.GetType())); + throw new ArgumentException("Could not determin JSON object type for type {0}.".FormatWith(CultureInfo.InvariantCulture, value.GetType())); } public override JsonTokenType Type @@ -127,10 +162,19 @@ namespace Newtonsoft.Json.Linq public object Value { get { return _value; } - set { _value = value; } + set + { + Type currentType = (_value != null) ? _value.GetType() : null; + Type newType = (value != null) ? value.GetType() : null; + + if (currentType != newType) + _valueType = GetValueType(_valueType, value); + + _value = value; + } } - public static JToken CreateString(string value) + public static JValue CreateString(string value) { return new JValue(value, JsonTokenType.String); } diff --git a/Src/Newtonsoft.Json/MemberMappingCollection.cs b/Src/Newtonsoft.Json/MemberMappingCollection.cs index 362da80c..807fb0ff 100644 --- a/Src/Newtonsoft.Json/MemberMappingCollection.cs +++ b/Src/Newtonsoft.Json/MemberMappingCollection.cs @@ -28,6 +28,7 @@ using System.Collections.Generic; using System.Text; using System.Collections.ObjectModel; using Newtonsoft.Json.Utilities; +using System.Globalization; namespace Newtonsoft.Json { @@ -51,7 +52,7 @@ namespace Newtonsoft.Json if (!existingMemberMapping.Ignored) { throw new JsonSerializationException( - "A member with the name '{0}' already exists on {1}. Use the JsonPropertyAttribute to specify another name.".FormatWith(memberMapping.MappingName, memberMapping.Member.DeclaringType)); + "A member with the name '{0}' already exists on {1}. Use the JsonPropertyAttribute to specify another name.".FormatWith(CultureInfo.InvariantCulture, memberMapping.MappingName, memberMapping.Member.DeclaringType)); } else { diff --git a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs index 23b4671a..94f123e7 100644 --- a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs @@ -30,6 +30,7 @@ using System.Reflection; using System.Text; using System.Collections; using System.Linq; +using System.Globalization; namespace Newtonsoft.Json.Utilities { @@ -315,7 +316,7 @@ namespace Newtonsoft.Json.Utilities else if (returnDefaultIfEmpty && list.Count == 0) return default(T); else - throw new Exception("Expected single {0} in list but got {1}.".FormatWith(typeof(T), list.Count)); + throw new Exception("Expected single {0} in list but got {1}.".FormatWith(CultureInfo.InvariantCulture, typeof(T), list.Count)); } #endregion @@ -389,7 +390,7 @@ namespace Newtonsoft.Json.Utilities } else { - throw new Exception("Can not create ListWrapper for type {0}.".FormatWith(list.GetType())); + throw new Exception("Can not create ListWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, list.GetType())); } } @@ -418,7 +419,7 @@ namespace Newtonsoft.Json.Utilities } else { - throw new Exception("Can not create DictionaryWrapper for type {0}.".FormatWith(dictionary.GetType())); + throw new Exception("Can not create DictionaryWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, dictionary.GetType())); } } @@ -459,7 +460,7 @@ namespace Newtonsoft.Json.Utilities } if (!suitableConstructor) - throw new Exception("Read-only type {0} does not have a public constructor that takes a type that implements {1}.".FormatWith(listType, genericEnumerable)); + throw new Exception("Read-only type {0} does not have a public constructor that takes a type that implements {1}.".FormatWith(CultureInfo.InvariantCulture, listType, genericEnumerable)); // can't add or modify a readonly list // use List and convert once populated @@ -485,7 +486,7 @@ namespace Newtonsoft.Json.Utilities } if (list == null) - throw new Exception("Cannot create and populate list type {0}.".FormatWith(listType)); + throw new Exception("Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, listType)); populateList(list); diff --git a/Src/Newtonsoft.Json/Utilities/ListWrapper.cs b/Src/Newtonsoft.Json/Utilities/ListWrapper.cs index 976bfc37..9e18d062 100644 --- a/Src/Newtonsoft.Json/Utilities/ListWrapper.cs +++ b/Src/Newtonsoft.Json/Utilities/ListWrapper.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.Threading; using Newtonsoft.Json.Utilities; using System.Linq; +using System.Globalization; namespace Newtonsoft.Json.Utilities { @@ -261,7 +262,7 @@ namespace Newtonsoft.Json.Utilities private static void VerifyValueType(object value) { if (!IsCompatibleObject(value)) - throw new ArgumentException("The value '{0}' is not of type '{1}' and cannot be used in this generic collection.".FormatWith(value, typeof(T)), "value"); + throw new ArgumentException("The value '{0}' is not of type '{1}' and cannot be used in this generic collection.".FormatWith(CultureInfo.InvariantCulture, value, typeof(T)), "value"); } private static bool IsCompatibleObject(object value) diff --git a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs index 0f55c86e..c365b75a 100644 --- a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Reflection; using System.Text; +using System.Globalization; namespace Newtonsoft.Json.Utilities { @@ -55,7 +56,7 @@ namespace Newtonsoft.Json.Utilities if (descriptionAttribute != null) return descriptionAttribute.Description; else - throw new Exception("No DescriptionAttribute on '{0}'.".FormatWith(o.GetType())); + throw new Exception("No DescriptionAttribute on '{0}'.".FormatWith(CultureInfo.InvariantCulture, o.GetType())); } public static IList GetDescriptions(IList values) diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index 097c8d86..79799ad3 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -30,6 +30,7 @@ using System.Reflection; using System.Collections; using System.ComponentModel; using System.Linq; +using System.Globalization; namespace Newtonsoft.Json.Utilities { @@ -106,14 +107,14 @@ namespace Newtonsoft.Json.Utilities ValidationUtils.ArgumentNotNull(type, "type"); if (type.IsGenericTypeDefinition) - throw new ArgumentException("Type {0} is a generic type definition and cannot be instantiated.".FormatWith(type), "type"); + throw new ArgumentException("Type {0} is a generic type definition and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, type), "type"); if (type.IsClass || type.IsInterface || type == typeof(void)) return null; else if (type.IsValueType) return Activator.CreateInstance(type); else - throw new ArgumentException("Type {0} cannot be instantiated.".FormatWith(type), "type"); + throw new ArgumentException("Type {0} cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, type), "type"); } public static bool IsPropertyIndexed(PropertyInfo property) @@ -196,7 +197,7 @@ namespace Newtonsoft.Json.Utilities else if (IsSubClass(type, typeof(IList<>), out genericListType)) { if (genericListType.IsGenericTypeDefinition) - throw new Exception("Type {0} is not a list.".FormatWith(type)); + throw new Exception("Type {0} is not a list.".FormatWith(CultureInfo.InvariantCulture, type)); return genericListType.GetGenericArguments()[0]; } @@ -206,7 +207,7 @@ namespace Newtonsoft.Json.Utilities } else { - throw new Exception("Type {0} is not a list.".FormatWith(type)); + throw new Exception("Type {0} is not a list.".FormatWith(CultureInfo.InvariantCulture, type)); } } @@ -218,7 +219,7 @@ namespace Newtonsoft.Json.Utilities if (IsSubClass(dictionaryType, typeof(IDictionary<,>), out genericDictionaryType)) { if (genericDictionaryType.IsGenericTypeDefinition) - throw new Exception("Type {0} is not a dictionary.".FormatWith(dictionaryType)); + throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType)); Type[] dictionaryGenericArguments = genericDictionaryType.GetGenericArguments(); @@ -234,7 +235,7 @@ namespace Newtonsoft.Json.Utilities } else { - throw new Exception("Type {0} is not a dictionary.".FormatWith(dictionaryType)); + throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType)); } } @@ -289,7 +290,7 @@ namespace Newtonsoft.Json.Utilities } else { - throw new Exception("Type {0} is neither a ValueType or a Class.".FormatWith(elementType)); + throw new Exception("Type {0} is neither a ValueType or a Class.".FormatWith(CultureInfo.InvariantCulture, elementType)); } return true; @@ -387,10 +388,10 @@ namespace Newtonsoft.Json.Utilities } catch (TargetParameterCountException e) { - throw new ArgumentException("MemberInfo '{0}' has index parameters".FormatWith(member.Name), "member", e); + throw new ArgumentException("MemberInfo '{0}' has index parameters".FormatWith(CultureInfo.InvariantCulture, member.Name), "member", e); } default: - throw new ArgumentException("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo".FormatWith(member.Name), "member"); + throw new ArgumentException("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo".FormatWith(CultureInfo.InvariantCulture, CultureInfo.InvariantCulture, member.Name), "member"); } } @@ -414,7 +415,7 @@ namespace Newtonsoft.Json.Utilities ((PropertyInfo)member).SetValue(target, value, null); break; default: - throw new ArgumentException("MemberInfo '{0}' must be of type FieldInfo or PropertyInfo".FormatWith(member.Name), "member"); + throw new ArgumentException("MemberInfo '{0}' must be of type FieldInfo or PropertyInfo".FormatWith(CultureInfo.InvariantCulture, member.Name), "member"); } } @@ -526,7 +527,7 @@ namespace Newtonsoft.Json.Utilities { ValidationUtils.ArgumentNotNull(genericTypeDefinition, "genericTypeDefinition"); ValidationUtils.ArgumentNotNullOrEmpty(innerTypes, "innerTypes"); - ValidationUtils.ArgumentConditionTrue(genericTypeDefinition.IsGenericTypeDefinition, "genericTypeDefinition", "Type {0} is not a generic type definition.".FormatWith(genericTypeDefinition)); + ValidationUtils.ArgumentConditionTrue(genericTypeDefinition.IsGenericTypeDefinition, "genericTypeDefinition", "Type {0} is not a generic type definition.".FormatWith(CultureInfo.InvariantCulture, genericTypeDefinition)); return genericTypeDefinition.MakeGenericType(innerTypes); } diff --git a/Src/Newtonsoft.Json/Utilities/StringUtils.cs b/Src/Newtonsoft.Json/Utilities/StringUtils.cs index a9bdd756..67073557 100644 --- a/Src/Newtonsoft.Json/Utilities/StringUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/StringUtils.cs @@ -42,10 +42,10 @@ namespace Newtonsoft.Json.Utilities public const char LineFeed = '\n'; public const char Tab = '\t'; - public static string FormatWith(this string format, params object[] args) - { - return FormatWith(format, CultureInfo.InvariantCulture, args); - } + //public static string FormatWith(this string format, params object[] args) + //{ + // return FormatWith(format, null, args); + //} public static string FormatWith(this string format, IFormatProvider provider, params object[] args) { diff --git a/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs b/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs index 31739635..9796fb63 100644 --- a/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs @@ -27,6 +27,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Text; +using System.Globalization; namespace Newtonsoft.Json.Utilities { @@ -44,7 +45,7 @@ namespace Newtonsoft.Json.Utilities throw new ArgumentNullException(parameterName); if (value.Length == 0) - throw new ArgumentException("'{0}' cannot be empty.".FormatWith(parameterName), parameterName); + throw new ArgumentException("'{0}' cannot be empty.".FormatWith(CultureInfo.InvariantCulture, parameterName), parameterName); } public static void ArgumentNotNullOrEmptyOrWhitespace(string value, string parameterName) @@ -52,7 +53,7 @@ namespace Newtonsoft.Json.Utilities ArgumentNotNullOrEmpty(value, parameterName); if (StringUtils.IsWhiteSpace(value)) - throw new ArgumentException("'{0}' cannot only be whitespace.".FormatWith(parameterName), parameterName); + throw new ArgumentException("'{0}' cannot only be whitespace.".FormatWith(CultureInfo.InvariantCulture, parameterName), parameterName); } public static void ArgumentTypeIsEnum(Type enumType, string parameterName) @@ -60,12 +61,12 @@ namespace Newtonsoft.Json.Utilities ArgumentNotNull(enumType, "enumType"); if (!enumType.IsEnum) - throw new ArgumentException("Type {0} is not an Enum.".FormatWith(enumType), parameterName); + throw new ArgumentException("Type {0} is not an Enum.".FormatWith(CultureInfo.InvariantCulture, enumType), parameterName); } public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName) { - ArgumentNotNullOrEmpty(collection, parameterName, "Collection '{0}' cannot be empty.".FormatWith(parameterName)); + ArgumentNotNullOrEmpty(collection, parameterName, "Collection '{0}' cannot be empty.".FormatWith(CultureInfo.InvariantCulture, parameterName)); } public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName, string message) @@ -79,7 +80,7 @@ namespace Newtonsoft.Json.Utilities public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName) { - ArgumentNotNullOrEmpty(collection, parameterName, "Collection '{0}' cannot be empty.".FormatWith(parameterName)); + ArgumentNotNullOrEmpty(collection, parameterName, "Collection '{0}' cannot be empty.".FormatWith(CultureInfo.InvariantCulture, parameterName)); } public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName, string message)