-Fixed reading NaN, Infinity, -Infinity with ReadAsDouble and ReadAsString

This commit is contained in:
James Newton-King
2016-05-15 17:45:54 +12:00
parent cdecb70915
commit 1c4160cd84
2 changed files with 167 additions and 28 deletions
@@ -61,6 +61,95 @@ namespace Newtonsoft.Json.Tests
[TestFixture] [TestFixture]
public class JsonTextReaderTest : TestFixtureBase public class JsonTextReaderTest : TestFixtureBase
{ {
[Test]
public void Float_NaN_Read()
{
const string testJson = "{float: NaN}";
JsonTextReader reader = new JsonTextReader(new StringReader(testJson));
Assert.IsTrue(reader.Read());
Assert.IsTrue(reader.Read());
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Float, reader.TokenType);
Assert.AreEqual(double.NaN, reader.Value);
Assert.IsTrue(reader.Read());
Assert.IsFalse(reader.Read());
}
[Test]
public void Float_NaN_ReadAsInt32()
{
const string testJson = "{float: NaN}";
JsonTextReader reader = new JsonTextReader(new StringReader(testJson));
Assert.IsTrue(reader.Read());
Assert.IsTrue(reader.Read());
ExceptionAssert.Throws<JsonReaderException>(() => reader.ReadAsInt32(), "Cannot read NaN value. Path 'float', line 1, position 11.");
}
[Test]
public void Float_NaNAndInifinity_ReadAsDouble()
{
const string testJson = @"[
NaN,
Infinity,
-Infinity
]"; ;
JsonTextReader reader = new JsonTextReader(new StringReader(testJson));
Assert.IsTrue(reader.Read());
Assert.AreEqual(double.NaN, reader.ReadAsDouble());
Assert.AreEqual(JsonToken.Float, reader.TokenType);
Assert.AreEqual(double.NaN, reader.Value);
Assert.AreEqual(double.PositiveInfinity, reader.ReadAsDouble());
Assert.AreEqual(JsonToken.Float, reader.TokenType);
Assert.AreEqual(double.PositiveInfinity, reader.Value);
Assert.AreEqual(double.NegativeInfinity, reader.ReadAsDouble());
Assert.AreEqual(JsonToken.Float, reader.TokenType);
Assert.AreEqual(double.NegativeInfinity, reader.Value);
Assert.IsTrue(reader.Read());
Assert.IsFalse(reader.Read());
}
[Test]
public void Float_NaNAndInifinity_ReadAsString()
{
const string testJson = @"[
NaN,
Infinity,
-Infinity
]"; ;
JsonTextReader reader = new JsonTextReader(new StringReader(testJson));
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonConvert.NaN, reader.ReadAsString());
Assert.AreEqual(JsonToken.String, reader.TokenType);
Assert.AreEqual(JsonConvert.NaN, reader.Value);
Assert.AreEqual(JsonConvert.PositiveInfinity, reader.ReadAsString());
Assert.AreEqual(JsonToken.String, reader.TokenType);
Assert.AreEqual(JsonConvert.PositiveInfinity, reader.Value);
Assert.AreEqual(JsonConvert.NegativeInfinity, reader.ReadAsString());
Assert.AreEqual(JsonToken.String, reader.TokenType);
Assert.AreEqual(JsonConvert.NegativeInfinity, reader.Value);
Assert.IsTrue(reader.Read());
Assert.IsFalse(reader.Read());
}
[Test] [Test]
public void FloatParseHandling_ReadAsString() public void FloatParseHandling_ReadAsString()
{ {
@@ -486,7 +575,7 @@ third line", jsonTextReader.Value);
Assert.IsTrue(reader.Read()); Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.StartArray, reader.TokenType); Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
ExceptionAssert.Throws<JsonReaderException>(() => reader.Read(), "Cannot read NaN as a decimal."); ExceptionAssert.Throws<JsonReaderException>(() => reader.Read(), "Cannot read NaN value. Path '', line 1, position 4.");
} }
[Test] [Test]
+77 -27
View File
@@ -598,6 +598,15 @@ namespace Newtonsoft.Json
throw new ArgumentOutOfRangeException(nameof(readType)); throw new ArgumentOutOfRangeException(nameof(readType));
} }
case '-': case '-':
if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I')
{
return ParseNumberNegativeInfinity(readType);
}
else
{
ParseNumber(readType);
return Value;
}
case '.': case '.':
case '0': case '0':
case '1': case '1':
@@ -630,6 +639,10 @@ namespace Newtonsoft.Json
} }
SetToken(JsonToken.String, expected); SetToken(JsonToken.String, expected);
return expected; return expected;
case 'I':
return ParseNumberPositiveInfinity(readType);
case 'N':
return ParseNumberNaN(readType);
case 'n': case 'n':
HandleNull(); HandleNull();
return null; return null;
@@ -858,7 +871,20 @@ namespace Newtonsoft.Json
case 'n': case 'n':
HandleNull(); HandleNull();
return null; return null;
case 'N':
return ParseNumberNaN(readType);
case 'I':
return ParseNumberPositiveInfinity(readType);
case '-': case '-':
if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I')
{
return ParseNumberNegativeInfinity(readType);
}
else
{
ParseNumber(readType);
return Value;
}
case '.': case '.':
case '0': case '0':
case '1': case '1':
@@ -1567,15 +1593,15 @@ namespace Newtonsoft.Json
} }
return true; return true;
case 'N': case 'N':
ParseNumberNaN(); ParseNumberNaN(ReadType.Read);
return true; return true;
case 'I': case 'I':
ParseNumberPositiveInfinity(); ParseNumberPositiveInfinity(ReadType.Read);
return true; return true;
case '-': case '-':
if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I') if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I')
{ {
ParseNumberNegativeInfinity(); ParseNumberNegativeInfinity(ReadType.Read);
} }
else else
{ {
@@ -2293,55 +2319,79 @@ namespace Newtonsoft.Json
} }
} }
private void ParseNumberNegativeInfinity() private object ParseNumberNegativeInfinity(ReadType readType)
{ {
if (MatchValueWithTrailingSeparator(JsonConvert.NegativeInfinity)) if (MatchValueWithTrailingSeparator(JsonConvert.NegativeInfinity))
{ {
if (_floatParseHandling == FloatParseHandling.Decimal) switch (readType)
{ {
throw new JsonReaderException("Cannot read -Infinity as a decimal."); case ReadType.Read:
case ReadType.ReadAsDouble:
if (_floatParseHandling == FloatParseHandling.Double)
{
SetToken(JsonToken.Float, double.NegativeInfinity);
return double.NegativeInfinity;
}
break;
case ReadType.ReadAsString:
SetToken(JsonToken.String, JsonConvert.NegativeInfinity);
return JsonConvert.NegativeInfinity;
} }
SetToken(JsonToken.Float, double.NegativeInfinity); throw JsonReaderException.Create(this, "Cannot read -Infinity value.");
}
else
{
throw JsonReaderException.Create(this, "Error parsing negative infinity value.");
} }
throw JsonReaderException.Create(this, "Error parsing -Infinity value.");
} }
private void ParseNumberPositiveInfinity() private object ParseNumberPositiveInfinity(ReadType readType)
{ {
if (MatchValueWithTrailingSeparator(JsonConvert.PositiveInfinity)) if (MatchValueWithTrailingSeparator(JsonConvert.PositiveInfinity))
{ {
if (_floatParseHandling == FloatParseHandling.Decimal) switch (readType)
{ {
throw new JsonReaderException("Cannot read Infinity as a decimal."); case ReadType.Read:
case ReadType.ReadAsDouble:
if (_floatParseHandling == FloatParseHandling.Double)
{
SetToken(JsonToken.Float, double.PositiveInfinity);
return double.PositiveInfinity;
}
break;
case ReadType.ReadAsString:
SetToken(JsonToken.String, JsonConvert.PositiveInfinity);
return JsonConvert.PositiveInfinity;
} }
SetToken(JsonToken.Float, double.PositiveInfinity); throw JsonReaderException.Create(this, "Cannot read Infinity value.");
}
else
{
throw JsonReaderException.Create(this, "Error parsing positive infinity value.");
} }
throw JsonReaderException.Create(this, "Error parsing Infinity value.");
} }
private void ParseNumberNaN() private object ParseNumberNaN(ReadType readType)
{ {
if (MatchValueWithTrailingSeparator(JsonConvert.NaN)) if (MatchValueWithTrailingSeparator(JsonConvert.NaN))
{ {
if (_floatParseHandling == FloatParseHandling.Decimal) switch (readType)
{ {
throw new JsonReaderException("Cannot read NaN as a decimal."); case ReadType.Read:
case ReadType.ReadAsDouble:
if (_floatParseHandling == FloatParseHandling.Double)
{
SetToken(JsonToken.Float, double.NaN);
return double.NaN;
}
break;
case ReadType.ReadAsString:
SetToken(JsonToken.String, JsonConvert.NaN);
return JsonConvert.NaN;
} }
SetToken(JsonToken.Float, double.NaN); throw JsonReaderException.Create(this, "Cannot read NaN value.");
}
else
{
throw JsonReaderException.Create(this, "Error parsing NaN value.");
} }
throw JsonReaderException.Create(this, "Error parsing NaN value.");
} }
/// <summary> /// <summary>