-Fixed property after empty array JSONPath queries
-Fixed error handling when last value in array or object fails
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user