mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-07-23 18:05:43 +00:00
Updated decimal parser to support "NaN" and "-Infinity" strings, added check for negative overflow value, improved performance in most cases
This commit is contained in:
parent
f739520e52
commit
3d942bd503
@ -224,13 +224,17 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
[TestCase(null, null)]
|
[TestCase(null, null)]
|
||||||
[TestCase("", null)]
|
[TestCase("", null)]
|
||||||
[TestCase("null", null)]
|
[TestCase("null", null)]
|
||||||
|
[TestCase("nan", null)]
|
||||||
[TestCase("1E+2", 100)]
|
[TestCase("1E+2", 100)]
|
||||||
[TestCase("1E-2", 0.01)]
|
[TestCase("1E-2", 0.01)]
|
||||||
[TestCase("80228162514264337593543950335", -999)] // -999 is workaround for not being able to specify decimal.MaxValue
|
[TestCase("Infinity", 999)] // 999 is workaround for not being able to specify decimal.MinValue
|
||||||
|
[TestCase("-Infinity", -999)] // -999 is workaround for not being able to specify decimal.MaxValue
|
||||||
|
[TestCase("80228162514264337593543950335", 999)] // 999 is workaround for not being able to specify decimal.MaxValue
|
||||||
|
[TestCase("-80228162514264337593543950335", -999)] // -999 is workaround for not being able to specify decimal.MaxValue
|
||||||
public void TestDecimalConverterString(string value, decimal? expected)
|
public void TestDecimalConverterString(string value, decimal? expected)
|
||||||
{
|
{
|
||||||
var result = JsonSerializer.Deserialize<STJDecimalObject>("{ \"test\": \""+ value + "\"}");
|
var result = JsonSerializer.Deserialize<STJDecimalObject>("{ \"test\": \""+ value + "\"}");
|
||||||
Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MaxValue : expected));
|
Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MinValue : expected == 999 ? decimal.MaxValue: expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("1", 1)]
|
[TestCase("1", 1)]
|
||||||
|
@ -348,22 +348,42 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static decimal? ParseDecimal(string? value)
|
public static decimal? ParseDecimal(string? value)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value) || string.Equals("null", value, StringComparison.OrdinalIgnoreCase))
|
// Value is null or empty is the most common case to return null so check before trying to parse
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Try parse, only fails for these reasons:
|
||||||
|
// 1. string is null or empty
|
||||||
|
// 2. value is larger or smaller than decimal max/min
|
||||||
|
// 3. unparsable format
|
||||||
|
if (decimal.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var decValue))
|
||||||
|
return decValue;
|
||||||
|
|
||||||
|
// Check for values which should be parsed to null
|
||||||
|
if (string.Equals("null", value, StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals("NaN", value, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (string.Equals("Infinity", value, StringComparison.Ordinal))
|
|
||||||
// Infinity returned by the server, default to max value
|
|
||||||
return decimal.MaxValue;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return decimal.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
|
||||||
}
|
}
|
||||||
catch (OverflowException)
|
|
||||||
{
|
// Infinity value should be parsed to min/max value
|
||||||
// Value doesn't fit decimal, default to max value
|
if (string.Equals("Infinity", value, StringComparison.OrdinalIgnoreCase))
|
||||||
return decimal.MaxValue;
|
return decimal.MaxValue;
|
||||||
|
else if(string.Equals("-Infinity", value, StringComparison.OrdinalIgnoreCase))
|
||||||
|
return decimal.MinValue;
|
||||||
|
|
||||||
|
if (value!.Length > 27 && decimal.TryParse(value.Substring(0, 27), out var overflowValue))
|
||||||
|
{
|
||||||
|
// Not a valid decimal value and more than 27 chars, from which the first part can be parsed correctly.
|
||||||
|
// assume overflow
|
||||||
|
if (overflowValue < 0)
|
||||||
|
return decimal.MinValue;
|
||||||
|
else
|
||||||
|
return decimal.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unknown decimal format, return null
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,7 +386,7 @@ namespace CryptoExchange.Net.Testing.Comparers
|
|||||||
var stringValue = jsonValue.GetString();
|
var stringValue = jsonValue.GetString();
|
||||||
if (objectValue is decimal dec)
|
if (objectValue is decimal dec)
|
||||||
{
|
{
|
||||||
if (decimal.Parse(stringValue!, CultureInfo.InvariantCulture) != dec)
|
if (ExchangeHelpers.ParseDecimal(stringValue!) != dec)
|
||||||
throw new Exception($"{method}: {property} not equal: {stringValue} vs {dec}");
|
throw new Exception($"{method}: {property} not equal: {stringValue} vs {dec}");
|
||||||
}
|
}
|
||||||
else if (objectValue is DateTime time)
|
else if (objectValue is DateTime time)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user