-Improved number parsing error message

This commit is contained in:
James Newton-King
2013-12-26 22:04:56 +13:00
parent 40c24307de
commit cc730cc860
6 changed files with 136 additions and 42 deletions
+85 -11
View File
@@ -799,8 +799,8 @@ Parameter name: reader",
for (int j = 1; j < 1000; j++)
{
long total = j + i;
ExceptionAssert.Throws<OverflowException>(
"Arithmetic operation resulted in an overflow.",
ExceptionAssert.Throws<JsonReaderException>(
"JSON integer " + total + " is too large or small for an Int32. Path '', line 1, position 10.",
() =>
{
reader = new JsonTextReader(new StringReader(total.ToString(CultureInfo.InvariantCulture)));
@@ -822,8 +822,8 @@ Parameter name: reader",
for (int j = 1; j < 1000; j++)
{
long total = -j + i;
ExceptionAssert.Throws<OverflowException>(
"Arithmetic operation resulted in an overflow.",
ExceptionAssert.Throws<JsonReaderException>(
"JSON integer " + total + " is too large or small for an Int32. Path '', line 1, position 11.",
() =>
{
reader = new JsonTextReader(new StringReader(total.ToString(CultureInfo.InvariantCulture)));
@@ -1230,22 +1230,96 @@ bye", reader.Value);
Assert.AreEqual(int.MinValue, reader.ReadAsInt32());
reader = new JsonTextReader(new StringReader(long.MaxValue.ToString()));
ExceptionAssert.Throws<OverflowException>("Arithmetic operation resulted in an overflow.", () => reader.ReadAsInt32());
ExceptionAssert.Throws<JsonReaderException>("JSON integer 9223372036854775807 is too large or small for an Int32. Path '', line 1, position 19.", () => reader.ReadAsInt32());
reader = new JsonTextReader(new StringReader("9999999999999999999999999999999999999999999999999999999999999999999999999999asdasdasd"));
ExceptionAssert.Throws<FormatException>("Input string was not in a correct format.", () => reader.ReadAsInt32());
ExceptionAssert.Throws<JsonReaderException>("Input string '9999999999999999999999999999999999999999999999999999999999999999999999999999a' is not a valid integer. Path '', line 1, position 77.", () => reader.ReadAsInt32());
reader = new JsonTextReader(new StringReader("1E-06"));
ExceptionAssert.Throws<FormatException>("Input string was not in a correct format.", () => reader.ReadAsInt32());
ExceptionAssert.Throws<JsonReaderException>("Input string '1E-06' is not a valid integer. Path '', line 1, position 5.", () => reader.ReadAsInt32());
reader = new JsonTextReader(new StringReader("1.1"));
ExceptionAssert.Throws<FormatException>("Input string was not in a correct format.", () => reader.ReadAsInt32());
ExceptionAssert.Throws<JsonReaderException>("Input string '1.1' is not a valid integer. Path '', line 1, position 3.", () => reader.ReadAsInt32());
reader = new JsonTextReader(new StringReader(""));
Assert.AreEqual(null, reader.ReadAsInt32());
reader = new JsonTextReader(new StringReader("-"));
ExceptionAssert.Throws<FormatException>("Input string was not in a correct format.", () => reader.ReadAsInt32());
ExceptionAssert.Throws<JsonReaderException>("Input string '-' is not a valid integer. Path '', line 1, position 1.", () => reader.ReadAsInt32());
}
[Test]
public void ParseDecimals()
{
JsonTextReader reader = null;
reader = new JsonTextReader(new StringReader("1.1"));
Assert.AreEqual(1.1m, reader.ReadAsDecimal());
reader = new JsonTextReader(new StringReader("-1.1"));
Assert.AreEqual(-1.1m, reader.ReadAsDecimal());
reader = new JsonTextReader(new StringReader("0.0"));
Assert.AreEqual(0.0m, reader.ReadAsDecimal());
reader = new JsonTextReader(new StringReader("-0.0"));
Assert.AreEqual(0, reader.ReadAsDecimal());
reader = new JsonTextReader(new StringReader("9999999999999999999999999999999999999999999999999999999999999999999999999999asdasdasd"));
ExceptionAssert.Throws<JsonReaderException>("Input string '9999999999999999999999999999999999999999999999999999999999999999999999999999a' is not a valid decimal. Path '', line 1, position 77.", () => reader.ReadAsDecimal());
reader = new JsonTextReader(new StringReader("9999999999999999999999999999999999999999999999999999999999999999999999999999asdasdasd"));
reader.FloatParseHandling = Json.FloatParseHandling.Decimal;
ExceptionAssert.Throws<JsonReaderException>("Input string '9999999999999999999999999999999999999999999999999999999999999999999999999999a' is not a valid decimal. Path '', line 1, position 77.", () => reader.Read());
reader = new JsonTextReader(new StringReader("1E-06"));
Assert.AreEqual(0.000001m, reader.ReadAsDecimal());
reader = new JsonTextReader(new StringReader(""));
Assert.AreEqual(null, reader.ReadAsDecimal());
reader = new JsonTextReader(new StringReader("-"));
ExceptionAssert.Throws<JsonReaderException>("Input string '-' is not a valid decimal. Path '', line 1, position 1.", () => reader.ReadAsDecimal());
}
[Test]
public void ParseDoubles()
{
JsonTextReader reader = null;
reader = new JsonTextReader(new StringReader("1.1"));
Assert.IsTrue(reader.Read());
Assert.AreEqual(typeof(double), reader.ValueType);
Assert.AreEqual(1.1d, reader.Value);
reader = new JsonTextReader(new StringReader("-1.1"));
Assert.IsTrue(reader.Read());
Assert.AreEqual(typeof(double), reader.ValueType);
Assert.AreEqual(-1.1d, reader.Value);
reader = new JsonTextReader(new StringReader("0.0"));
Assert.IsTrue(reader.Read());
Assert.AreEqual(typeof(double), reader.ValueType);
Assert.AreEqual(0.0d, reader.Value);
reader = new JsonTextReader(new StringReader("-0.0"));
Assert.IsTrue(reader.Read());
Assert.AreEqual(typeof(double), reader.ValueType);
Assert.AreEqual(-0.0m, reader.Value);
reader = new JsonTextReader(new StringReader("9999999999999999999999999999999999999999999999999999999999999999999999999999asdasdasd"));
ExceptionAssert.Throws<JsonReaderException>("Input string '9999999999999999999999999999999999999999999999999999999999999999999999999999a' is not a valid number. Path '', line 1, position 77.", () => reader.Read());
reader = new JsonTextReader(new StringReader("1E-06"));
Assert.IsTrue(reader.Read());
Assert.AreEqual(typeof(double), reader.ValueType);
Assert.AreEqual(0.000001m, reader.Value);
reader = new JsonTextReader(new StringReader(""));
Assert.IsFalse(reader.Read());
reader = new JsonTextReader(new StringReader("-"));
ExceptionAssert.Throws<JsonReaderException>("Input string '-' is not a valid number. Path '', line 1, position 1.", () => reader.Read());
}
[Test]
@@ -1975,8 +2049,8 @@ bye", reader.Value);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
ExceptionAssert.Throws<FormatException>(
"Input string was not in a correct format.",
ExceptionAssert.Throws<JsonReaderException>(
"Input string '1.1' is not a valid integer. Path 'Name', line 1, position 12.",
() => { reader.ReadAsInt32(); });
}
@@ -75,4 +75,4 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
[assembly: AssemblyFileVersion("5.0.8.16823")]
[assembly: AssemblyFileVersion("5.0.8.16826")]
+1
View File
@@ -2,4 +2,5 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_MULTIPLICATIVE_OP/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>
+33 -15
View File
@@ -1195,7 +1195,14 @@ namespace Newtonsoft.Json
}
else
{
numberValue = ConvertUtils.Int32Parse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
int value;
ParseResult parseResult = ConvertUtils.Int32TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out value);
if (parseResult == ParseResult.Success)
numberValue = value;
else if (parseResult == ParseResult.Overflow)
throw JsonReaderException.Create(this, "JSON integer {0} is too large or small for an Int32.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
else
throw JsonReaderException.Create(this, "Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
}
numberType = JsonToken.Integer;
@@ -1222,7 +1229,11 @@ namespace Newtonsoft.Json
{
string number = _stringReference.ToString();
numberValue = decimal.Parse(number, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
decimal value;
if (decimal.TryParse(number, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out value))
numberValue = value;
else
throw JsonReaderException.Create(this, "Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
}
numberType = JsonToken.Float;
@@ -1253,17 +1264,6 @@ namespace Newtonsoft.Json
numberValue = value;
numberType = JsonToken.Integer;
}
else if (parseResult == ParseResult.Invalid)
{
string number = _stringReference.ToString();
if (_floatParseHandling == FloatParseHandling.Decimal)
numberValue = decimal.Parse(number, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
else
numberValue = Convert.ToDouble(number, CultureInfo.InvariantCulture);
numberType = JsonToken.Float;
}
else if (parseResult == ParseResult.Overflow)
{
#if !(NET20 || NET35 || PORTABLE40 || PORTABLE)
@@ -1271,13 +1271,31 @@ namespace Newtonsoft.Json
numberValue = BigInteger.Parse(number, CultureInfo.InvariantCulture);
numberType = JsonToken.Integer;
#else
// todo - validate number was a valid integer to make sure overflow was the reason for failure
throw JsonReaderException.Create(this, "JSON integer {0} is too large or small for an Int64.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
#endif
}
else
{
throw JsonReaderException.Create(this, "Unknown error parsing integer.");
string number = _stringReference.ToString();
if (_floatParseHandling == FloatParseHandling.Decimal)
{
decimal d;
if (decimal.TryParse(number, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out d))
numberValue = d;
else
throw JsonReaderException.Create(this, "Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, number));
}
else
{
double d;
if (double.TryParse(number, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out d))
numberValue = d;
else
throw JsonReaderException.Create(this, "Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, number));
}
numberType = JsonToken.Float;
}
}
}
@@ -91,5 +91,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
[assembly: AssemblyFileVersion("5.0.8.16823")]
[assembly: AssemblyFileVersion("5.0.8.16826")]
[assembly: CLSCompliant(true)]
+15 -14
View File
@@ -565,10 +565,12 @@ namespace Newtonsoft.Json.Utilities
}
}
public static int Int32Parse(char[] chars, int start, int length)
public static ParseResult Int32TryParse(char[] chars, int start, int length, out int value)
{
value = 0;
if (length == 0)
throw new FormatException("Input string was not in a correct format.");
return ParseResult.Invalid;
bool isNegative = (chars[start] == '-');
@@ -576,13 +578,12 @@ namespace Newtonsoft.Json.Utilities
{
// text just a negative sign
if (length == 1)
throw new FormatException("Input string was not in a correct format.");
return ParseResult.Invalid;
start++;
length--;
}
int result = 0;
int end = start + length;
for (int i = start; i < end; i++)
@@ -590,12 +591,12 @@ namespace Newtonsoft.Json.Utilities
int c = chars[i] - '0';
if (c < 0 || c > 9)
throw new FormatException("Input string was not in a correct format.");
return ParseResult.Invalid;
int newValue = (10 * result) - c;
int newValue = (10 * value) - c;
// overflow has caused the number to loop around
if (newValue > result)
if (newValue > value)
{
i++;
@@ -606,13 +607,13 @@ namespace Newtonsoft.Json.Utilities
c = chars[i] - '0';
if (c < 0 || c > 9)
throw new FormatException("Input string was not in a correct format.");
return ParseResult.Invalid;
}
throw new OverflowException();
return ParseResult.Overflow;
}
result = newValue;
value = newValue;
}
// go from negative to positive to avoids overflow
@@ -620,13 +621,13 @@ namespace Newtonsoft.Json.Utilities
if (!isNegative)
{
// negative integer can be one bigger than positive
if (result == int.MinValue)
throw new OverflowException();
if (value == int.MinValue)
return ParseResult.Overflow;
result = -result;
value = -value;
}
return result;
return ParseResult.Success;
}
public static ParseResult Int64TryParse(char[] chars, int start, int length, out long value)