From ad1a13728a2f155d6b4f2ca39bcac4b9873e344a Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Sat, 22 Jul 2017 13:41:14 +1200 Subject: [PATCH] -Fixed JValue.CompareTo with number and string values --- Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs | 112 ++++++++++++++++++ .../Linq/JsonPath/JPathExecuteTests.cs | 46 +++++++ .../Linq/JsonPath/QueryExpressionTests.cs | 42 +++++++ Src/Newtonsoft.Json/Linq/JValue.cs | 23 +++- 4 files changed, 220 insertions(+), 3 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs index b519d787..9a03cb33 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs @@ -858,5 +858,117 @@ namespace Newtonsoft.Json.Tests.Linq ValueA } #endif + + [Test] + public void CompareTo_MismatchedTypes() + { + JValue v1 = new JValue(1); + JValue v2 = new JValue("2"); + + Assert.AreEqual(-1, v1.CompareTo(v2)); + Assert.AreEqual(-1, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(1, v2.CompareTo(v1)); + Assert.AreEqual(1, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue(1.5); + v2 = new JValue("2"); + + Assert.AreEqual(-1, v1.CompareTo(v2)); + Assert.AreEqual(-1, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(1, v2.CompareTo(v1)); + Assert.AreEqual(1, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue(1.5m); + v2 = new JValue("2"); + + Assert.AreEqual(-1, v1.CompareTo(v2)); + Assert.AreEqual(-1, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(1, v2.CompareTo(v1)); + Assert.AreEqual(1, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue(1.5m); + v2 = new JValue(2); + + Assert.AreEqual(-1, v1.CompareTo(v2)); + Assert.AreEqual(-1, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(1, v2.CompareTo(v1)); + Assert.AreEqual(1, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue(1.5m); + v2 = new JValue(2.1); + + Assert.AreEqual(-1, v1.CompareTo(v2)); + Assert.AreEqual(-1, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(1, v2.CompareTo(v1)); + Assert.AreEqual(1, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue(2); + v2 = new JValue("2"); + + Assert.AreEqual(0, v1.CompareTo(v2)); + Assert.AreEqual(0, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(0, v2.CompareTo(v1)); + Assert.AreEqual(0, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue(2); + v2 = new JValue(2m); + + Assert.AreEqual(0, v1.CompareTo(v2)); + Assert.AreEqual(0, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(0, v2.CompareTo(v1)); + Assert.AreEqual(0, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue(2f); + v2 = new JValue(2m); + + Assert.AreEqual(0, v1.CompareTo(v2)); + Assert.AreEqual(0, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(0, v2.CompareTo(v1)); + Assert.AreEqual(0, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue(2); + v2 = new JValue("10"); + + Assert.AreEqual(-1, v1.CompareTo(v2)); + Assert.AreEqual(-1, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(1, v2.CompareTo(v1)); + Assert.AreEqual(1, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue(2); + v2 = new JValue((object)null); + + Assert.AreEqual(1, v1.CompareTo(v2)); + Assert.AreEqual(1, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(-1, v2.CompareTo(v1)); + Assert.AreEqual(-1, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue("2"); + v2 = new JValue((object)null); + + Assert.AreEqual(1, v1.CompareTo(v2)); + Assert.AreEqual(1, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(-1, v2.CompareTo(v1)); + Assert.AreEqual(-1, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue((object)null); + v2 = new JValue("2"); + + Assert.AreEqual(-1, v1.CompareTo(v2)); + Assert.AreEqual(-1, ((IComparable)v1).CompareTo(v2)); + Assert.AreEqual(1, v2.CompareTo(v1)); + Assert.AreEqual(1, ((IComparable)v2).CompareTo(v1)); + + v1 = new JValue("2"); + v2 = null; + + Assert.AreEqual(1, v1.CompareTo(v2)); + Assert.AreEqual(1, ((IComparable)v1).CompareTo(v2)); + + v1 = new JValue((object)null); + v2 = null; + + Assert.AreEqual(1, v1.CompareTo(v2)); + Assert.AreEqual(1, ((IComparable)v1).CompareTo(v2)); + } } } diff --git a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs index 379a49a6..e3f50c31 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs @@ -51,6 +51,52 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath [TestFixture] public class JPathExecuteTests : TestFixtureBase { + [Test] + public void GreaterThanWithIntegerParameterAndStringValue() + { + string json = @"{ + ""persons"": [ + { + ""name"" : ""John"", + ""age"": ""26"" + }, + { + ""name"" : ""Jane"", + ""age"": ""2"" + } + ] +}"; + + JObject models = JObject.Parse(json); + + var results = models.SelectTokens("$.persons[?(@.age > 3)]").ToList(); + + Assert.AreEqual(1, results.Count); + } + + [Test] + public void GreaterThanWithStringParameterAndIntegerValue() + { + string json = @"{ + ""persons"": [ + { + ""name"" : ""John"", + ""age"": 26 + }, + { + ""name"" : ""Jane"", + ""age"": 2 + } + ] +}"; + + JObject models = JObject.Parse(json); + + var results = models.SelectTokens("$.persons[?(@.age > '3')]").ToList(); + + Assert.AreEqual(1, results.Count); + } + [Test] public void RecursiveWildcard() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/QueryExpressionTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/QueryExpressionTests.cs index 1ca720b0..fb93794b 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/QueryExpressionTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/QueryExpressionTests.cs @@ -175,6 +175,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath Assert.IsTrue(e1.IsMatch(null, new JArray(2, 3, 4, 5))); Assert.IsFalse(e1.IsMatch(null, new JArray(3, 4, 5))); Assert.IsFalse(e1.IsMatch(null, new JArray(4, 5))); + Assert.IsFalse(e1.IsMatch(null, new JArray("11", 5))); BooleanQueryExpression e2 = new BooleanQueryExpression { @@ -190,6 +191,47 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath Assert.IsTrue(e2.IsMatch(null, new JArray(2, 3, 4, 5))); Assert.IsTrue(e2.IsMatch(null, new JArray(3, 4, 5))); Assert.IsFalse(e2.IsMatch(null, new JArray(4, 5))); + Assert.IsFalse(e1.IsMatch(null, new JArray("11", 5))); + } + + [Test] + public void BooleanExpressionTest_GreaterThanOperator() + { + BooleanQueryExpression e1 = new BooleanQueryExpression + { + Operator = QueryOperator.GreaterThan, + Right = new JValue(3), + Left = new List + { + new ArrayIndexFilter() + } + }; + + Assert.IsTrue(e1.IsMatch(null, new JArray("2", "26"))); + Assert.IsTrue(e1.IsMatch(null, new JArray(2, 26))); + Assert.IsFalse(e1.IsMatch(null, new JArray(2, 3))); + Assert.IsFalse(e1.IsMatch(null, new JArray("2", "3"))); + } + + [Test] + public void BooleanExpressionTest_GreaterThanOrEqualsOperator() + { + BooleanQueryExpression e1 = new BooleanQueryExpression + { + Operator = QueryOperator.GreaterThanOrEquals, + Right = new JValue(3), + Left = new List + { + new ArrayIndexFilter() + } + }; + + Assert.IsTrue(e1.IsMatch(null, new JArray("2", "26"))); + Assert.IsTrue(e1.IsMatch(null, new JArray(2, 26))); + Assert.IsTrue(e1.IsMatch(null, new JArray(2, 3))); + Assert.IsTrue(e1.IsMatch(null, new JArray("2", "3"))); + Assert.IsFalse(e1.IsMatch(null, new JArray(2, 1))); + Assert.IsFalse(e1.IsMatch(null, new JArray("2", "1"))); } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs index 14fd5749..3c58f116 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.cs @@ -1043,9 +1043,22 @@ namespace Newtonsoft.Json.Linq } JValue value = obj as JValue; - object otherValue = value != null ? value.Value : obj; + JTokenType comparisonType; + object otherValue; + if (value != null) + { + otherValue = value.Value; + comparisonType = (_valueType == JTokenType.String && _valueType != value._valueType) + ? value._valueType + : _valueType; + } + else + { + otherValue = obj; + comparisonType = _valueType; + } - return Compare(_valueType, _value, otherValue); + return Compare(comparisonType, _value, otherValue); } /// @@ -1073,7 +1086,11 @@ namespace Newtonsoft.Json.Linq return 1; } - return Compare(_valueType, _value, obj._value); + JTokenType comparisonType = (_valueType == JTokenType.String && _valueType != obj._valueType) + ? obj._valueType + : _valueType; + + return Compare(comparisonType, _value, obj._value); } #if HAVE_ICONVERTIBLE