-Fixed property after empty array JSONPath queries

-Fixed error handling when last value in array or object fails
This commit is contained in:
James Newton-King
2014-06-28 00:42:41 +12:00
parent b96f8ed254
commit 3335ae4e20
9 changed files with 265 additions and 63 deletions
@@ -26,6 +26,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json.Linq;
#if !(NET20 || NET35 || PORTABLE40 || PORTABLE)
using System.Numerics;
#endif
@@ -47,6 +48,157 @@ namespace Newtonsoft.Json.Tests
[TestFixture]
public class JsonTextReaderTest : TestFixtureBase
{
#if !(NET20 || NET35 || PORTABLE40 || PORTABLE)
[Test]
public void ReadBigInteger()
{
string json = @"{
ParentId: 1,
ChildId: 333333333333333333333333333333333333333,
}";
JsonTextReader jsonTextReader = new JsonTextReader(new StringReader(json));
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.StartObject, jsonTextReader.TokenType);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.PropertyName, jsonTextReader.TokenType);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.Integer, jsonTextReader.TokenType);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.PropertyName, jsonTextReader.TokenType);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.Integer, jsonTextReader.TokenType);
Assert.AreEqual(typeof(BigInteger), jsonTextReader.ValueType);
Assert.AreEqual(BigInteger.Parse("333333333333333333333333333333333333333"), jsonTextReader.Value);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.EndObject, jsonTextReader.TokenType);
Assert.IsFalse(jsonTextReader.Read());
JObject o = JObject.Parse(json);
var i = (BigInteger)((JValue)o["ChildId"]).Value;
Assert.AreEqual(BigInteger.Parse("333333333333333333333333333333333333333"), i);
}
#endif
[Test]
public void ReadIntegerWithError()
{
string json = @"{
ChildId: 333333333333333333333333333333333333333
}";
JsonTextReader jsonTextReader = new JsonTextReader(new StringReader(json));
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.StartObject, jsonTextReader.TokenType);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.PropertyName, jsonTextReader.TokenType);
ExceptionAssert.Throws<JsonReaderException>(
"JSON integer 333333333333333333333333333333333333333 is too large or small for an Int32. Path 'ChildId', line 2, position 53.",
() => jsonTextReader.ReadAsInt32());
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.EndObject, jsonTextReader.TokenType);
Assert.IsFalse(jsonTextReader.Read());
}
[Test]
public void ReadIntegerWithErrorInArray()
{
string json = @"[
333333333333333333333333333333333333333,
3.3,
,
0f
]";
JsonTextReader jsonTextReader = new JsonTextReader(new StringReader(json));
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.StartArray, jsonTextReader.TokenType);
ExceptionAssert.Throws<JsonReaderException>(
"JSON integer 333333333333333333333333333333333333333 is too large or small for an Int32. Path '[0]', line 2, position 42.",
() => jsonTextReader.ReadAsInt32());
ExceptionAssert.Throws<JsonReaderException>(
"Input string '3.3' is not a valid integer. Path '[1]', line 3, position 6.",
() => jsonTextReader.ReadAsInt32());
ExceptionAssert.Throws<JsonReaderException>(
"Error reading integer. Unexpected token: Undefined. Path '[2]', line 4, position 3.",
() => jsonTextReader.ReadAsInt32());
ExceptionAssert.Throws<JsonReaderException>(
"Input string '0f' is not a valid integer. Path '[3]', line 5, position 5.",
() => jsonTextReader.ReadAsInt32());
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.EndArray, jsonTextReader.TokenType);
Assert.IsFalse(jsonTextReader.Read());
}
[Test]
public void ReadBytesWithError()
{
string json = @"{
ChildId: '123'
}";
JsonTextReader jsonTextReader = new JsonTextReader(new StringReader(json));
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.StartObject, jsonTextReader.TokenType);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.PropertyName, jsonTextReader.TokenType);
ExceptionAssert.Throws<FormatException>(
"Invalid length for a Base-64 char array or string.",
() => jsonTextReader.ReadAsBytes());
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.EndObject, jsonTextReader.TokenType);
Assert.IsFalse(jsonTextReader.Read());
}
[Test]
public void ReadBadMSDateAsString()
{
string json = @"{
ChildId: '\/Date(9467082_PIE_340000-0631)\/'
}";
JsonTextReader jsonTextReader = new JsonTextReader(new StringReader(json));
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.StartObject, jsonTextReader.TokenType);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.PropertyName, jsonTextReader.TokenType);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.String, jsonTextReader.TokenType);
Assert.AreEqual(@"/Date(9467082_PIE_340000-0631)/", jsonTextReader.Value);
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(JsonToken.EndObject, jsonTextReader.TokenType);
Assert.IsFalse(jsonTextReader.Read());
}
[Test]
public void ReadInvalidNonBase10Number()
{
@@ -50,6 +50,22 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
[TestFixture]
public class JPathExecuteTests : TestFixtureBase
{
[Test]
public void SelectTokenAfterEmptyContainer()
{
string json = @"{
'cont': [],
'test': 'no one will find me'
}";
JObject o = JObject.Parse(json);
IList<JToken> results = o.SelectTokens("$..test").ToList();
Assert.AreEqual(1, results.Count);
Assert.AreEqual("no one will find me", (string)results[0]);
}
[Test]
public void EvaluatePropertyWithRequired()
{
@@ -75,4 +75,4 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.0.0.0")]
[assembly: AssemblyFileVersion("6.0.3.17421")]
[assembly: AssemblyFileVersion("6.0.3.17428")]
@@ -91,6 +91,42 @@ namespace Newtonsoft.Json.Tests.Serialization
[TestFixture]
public class JsonSerializerTest : TestFixtureBase
{
public class Link
{
/// <summary>
/// The unique identifier.
/// </summary>
public int Id;
/// <summary>
/// The parent information identifier.
/// </summary>
public int ParentId;
/// <summary>
/// The child information identifier.
/// </summary>
public int ChildId;
}
#if !(NET20 || NET35 || PORTABLE40 || PORTABLE)
[Test]
public void ReadIntegerWithError()
{
string json = @"{
ParentId: 1,
ChildId: 333333333333333333333333333333333333333
}";
Link l = JsonConvert.DeserializeObject<Link>(json, new JsonSerializerSettings
{
Error = (s, a) => a.ErrorContext.Handled = true
});
Assert.AreEqual(0, l.ChildId);
}
#endif
#if !NET20
[Test]
public void PopulateResetSettings()
+15 -10
View File
@@ -439,7 +439,6 @@ namespace Newtonsoft.Json
if (t == JsonToken.Null)
return null;
DateTimeOffset dt;
if (t == JsonToken.String)
{
string s = (string)Value;
@@ -450,6 +449,7 @@ namespace Newtonsoft.Json
}
object temp;
DateTimeOffset dt;
if (DateTimeUtils.TryParseDateTime(s, DateParseHandling.DateTimeOffset, DateTimeZoneHandling, _dateFormatString, Culture, out temp))
{
dt = (DateTimeOffset)temp;
@@ -587,7 +587,6 @@ namespace Newtonsoft.Json
if (t == JsonToken.Null)
return null;
decimal d;
if (t == JsonToken.String)
{
string s = (string)Value;
@@ -597,6 +596,7 @@ namespace Newtonsoft.Json
return null;
}
decimal d;
if (decimal.TryParse(s, NumberStyles.Number, Culture, out d))
{
SetToken(JsonToken.Float, d, false);
@@ -736,7 +736,6 @@ namespace Newtonsoft.Json
if (TokenType == JsonToken.Null)
return null;
DateTime dt;
if (TokenType == JsonToken.String)
{
string s = (string)Value;
@@ -746,6 +745,7 @@ namespace Newtonsoft.Json
return null;
}
DateTime dt;
object temp;
if (DateTimeUtils.TryParseDateTime(s, DateParseHandling.DateTime, DateTimeZoneHandling, _dateFormatString, Culture, out temp))
{
@@ -878,17 +878,22 @@ namespace Newtonsoft.Json
case JsonToken.String:
case JsonToken.Raw:
case JsonToken.Bytes:
if (Peek() != JsonContainerType.None)
_currentState = State.PostValue;
else
SetFinished();
if (updateIndex)
UpdateScopeWithFinishedValue();
SetPostValueState(updateIndex);
break;
}
}
internal void SetPostValueState(bool updateIndex)
{
if (Peek() != JsonContainerType.None)
_currentState = State.PostValue;
else
SetFinished();
if (updateIndex)
UpdateScopeWithFinishedValue();
}
private void UpdateScopeWithFinishedValue()
{
if (_currentPosition.HasIndex)
+15 -20
View File
@@ -115,6 +115,7 @@ namespace Newtonsoft.Json
ShiftBufferIfNeeded();
ReadStringIntoBuffer(quote);
SetPostValueState(true);
if (_readType == ReadType.ReadAsBytes)
{
@@ -128,13 +129,13 @@ namespace Newtonsoft.Json
data = Convert.FromBase64CharArray(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
}
SetToken(JsonToken.Bytes, data);
SetToken(JsonToken.Bytes, data, false);
}
else if (_readType == ReadType.ReadAsString)
{
string text = _stringReference.ToString();
SetToken(JsonToken.String, text);
SetToken(JsonToken.String, text, false);
_quoteChar = quote;
}
else
@@ -156,12 +157,12 @@ namespace Newtonsoft.Json
object dt;
if (DateTimeUtils.TryParseDateTime(text, dateParseHandling, DateTimeZoneHandling, DateFormatString, Culture, out dt))
{
SetToken(JsonToken.Date, dt);
SetToken(JsonToken.Date, dt, false);
return;
}
}
SetToken(JsonToken.String, text);
SetToken(JsonToken.String, text, false);
_quoteChar = quote;
}
}
@@ -381,8 +382,6 @@ namespace Newtonsoft.Json
case State.Constructor:
case State.ConstructorStart:
return ParseValue();
case State.Complete:
break;
case State.Object:
case State.ObjectStart:
return ParseObject();
@@ -405,16 +404,10 @@ namespace Newtonsoft.Json
ParseComment();
return true;
}
else
{
throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
}
throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
}
return false;
case State.Closed:
break;
case State.Error:
break;
default:
throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
}
@@ -1004,15 +997,13 @@ namespace Newtonsoft.Json
_charPos++;
break;
}
else if (char.IsNumber(currentChar) || currentChar == '-' || currentChar == '.')
if (char.IsNumber(currentChar) || currentChar == '-' || currentChar == '.')
{
ParseNumber();
return true;
}
else
{
throw JsonReaderException.Create(this, "Unexpected character encountered while parsing value: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
}
throw JsonReaderException.Create(this, "Unexpected character encountered while parsing value: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
}
}
}
@@ -1165,6 +1156,9 @@ namespace Newtonsoft.Json
ReadNumberIntoBuffer();
// set state to PostValue now so that if there is an error parsing the number then the reader can continue
SetPostValueState(true);
_stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition);
object numberValue;
@@ -1328,7 +1322,8 @@ namespace Newtonsoft.Json
ClearRecentString();
SetToken(numberType, numberValue);
// index has already been updated
SetToken(numberType, numberValue, false);
}
private void ParseComment()
@@ -91,5 +91,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.0.0.0")]
[assembly: AssemblyFileVersion("6.0.3.17421")]
[assembly: AssemblyFileVersion("6.0.3.17428")]
[assembly: CLSCompliant(true)]
+21 -19
View File
@@ -332,7 +332,12 @@ namespace Newtonsoft.Json.Utilities
value = value.Substring(0, index);
}
long javaScriptTicks = long.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
long javaScriptTicks;
if (!long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out javaScriptTicks))
{
dt = null;
return false;
}
DateTime utcDateTime = ConvertJavaScriptTicksToDateTime(javaScriptTicks);
@@ -342,27 +347,24 @@ namespace Newtonsoft.Json.Utilities
dt = new DateTimeOffset(utcDateTime.Add(offset).Ticks, offset);
return true;
}
else
#endif
DateTime dateTime;
switch (kind)
{
DateTime dateTime;
switch (kind)
{
case DateTimeKind.Unspecified:
dateTime = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified);
break;
case DateTimeKind.Local:
dateTime = utcDateTime.ToLocalTime();
break;
default:
dateTime = utcDateTime;
break;
}
dt = EnsureDateTime(dateTime, dateTimeZoneHandling);
return true;
case DateTimeKind.Unspecified:
dateTime = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified);
break;
case DateTimeKind.Local:
dateTime = utcDateTime.ToLocalTime();
break;
default:
dateTime = utcDateTime;
break;
}
dt = EnsureDateTime(dateTime, dateTimeZoneHandling);
return true;
}
private static bool TryParseDateExact(string text, DateParseHandling dateParseHandling, DateTimeZoneHandling dateTimeZoneHandling, string dateFormatString, CultureInfo culture, out object dt)
@@ -367,21 +367,19 @@ namespace Newtonsoft.Json.Utilities
{
return type.GetElementType();
}
else if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out genericListType))
if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out genericListType))
{
if (genericListType.IsGenericTypeDefinition())
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
return genericListType.GetGenericArguments()[0];
}
else if (typeof(IEnumerable).IsAssignableFrom(type))
if (typeof(IEnumerable).IsAssignableFrom(type))
{
return null;
}
else
{
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
}
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
}
public static void GetDictionaryKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType)
@@ -400,16 +398,14 @@ namespace Newtonsoft.Json.Utilities
valueType = dictionaryGenericArguments[1];
return;
}
else if (typeof(IDictionary).IsAssignableFrom(dictionaryType))
if (typeof(IDictionary).IsAssignableFrom(dictionaryType))
{
keyType = null;
valueType = null;
return;
}
else
{
throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType));
}
throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType));
}
/// <summary>
@@ -432,7 +428,7 @@ namespace Newtonsoft.Json.Utilities
case MemberTypes.Method:
return ((MethodInfo)member).ReturnType;
default:
throw new ArgumentException("MemberInfo must be of type FieldInfo, PropertyInfo or EventInfo", "member");
throw new ArgumentException("MemberInfo must be of type FieldInfo, PropertyInfo, EventInfo or MethodInfo", "member");
}
}