-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]
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]
public void FloatParseHandling_ReadAsString()
{
@@ -486,7 +575,7 @@ third line", jsonTextReader.Value);
Assert.IsTrue(reader.Read());
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]
+77 -27
View File
@@ -598,6 +598,15 @@ namespace Newtonsoft.Json
throw new ArgumentOutOfRangeException(nameof(readType));
}
case '-':
if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I')
{
return ParseNumberNegativeInfinity(readType);
}
else
{
ParseNumber(readType);
return Value;
}
case '.':
case '0':
case '1':
@@ -630,6 +639,10 @@ namespace Newtonsoft.Json
}
SetToken(JsonToken.String, expected);
return expected;
case 'I':
return ParseNumberPositiveInfinity(readType);
case 'N':
return ParseNumberNaN(readType);
case 'n':
HandleNull();
return null;
@@ -858,7 +871,20 @@ namespace Newtonsoft.Json
case 'n':
HandleNull();
return null;
case 'N':
return ParseNumberNaN(readType);
case 'I':
return ParseNumberPositiveInfinity(readType);
case '-':
if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I')
{
return ParseNumberNegativeInfinity(readType);
}
else
{
ParseNumber(readType);
return Value;
}
case '.':
case '0':
case '1':
@@ -1567,15 +1593,15 @@ namespace Newtonsoft.Json
}
return true;
case 'N':
ParseNumberNaN();
ParseNumberNaN(ReadType.Read);
return true;
case 'I':
ParseNumberPositiveInfinity();
ParseNumberPositiveInfinity(ReadType.Read);
return true;
case '-':
if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I')
{
ParseNumberNegativeInfinity();
ParseNumberNegativeInfinity(ReadType.Read);
}
else
{
@@ -2293,55 +2319,79 @@ namespace Newtonsoft.Json
}
}
private void ParseNumberNegativeInfinity()
private object ParseNumberNegativeInfinity(ReadType readType)
{
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);
}
else
{
throw JsonReaderException.Create(this, "Error parsing negative infinity value.");
throw JsonReaderException.Create(this, "Cannot read -Infinity value.");
}
throw JsonReaderException.Create(this, "Error parsing -Infinity value.");
}
private void ParseNumberPositiveInfinity()
private object ParseNumberPositiveInfinity(ReadType readType)
{
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);
}
else
{
throw JsonReaderException.Create(this, "Error parsing positive infinity value.");
throw JsonReaderException.Create(this, "Cannot read Infinity value.");
}
throw JsonReaderException.Create(this, "Error parsing Infinity value.");
}
private void ParseNumberNaN()
private object ParseNumberNaN(ReadType readType)
{
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);
}
else
{
throw JsonReaderException.Create(this, "Error parsing NaN value.");
throw JsonReaderException.Create(this, "Cannot read NaN value.");
}
throw JsonReaderException.Create(this, "Error parsing NaN value.");
}
/// <summary>