Add tests for NaN and Infinity float/double.

This commit is contained in:
Nicolas Musset 2016-05-16 15:27:54 +09:00
Родитель 4d76ec9370
Коммит d9a5b8bdf1
2 изменённых файлов: 91 добавлений и 58 удалений

Просмотреть файл

@ -339,6 +339,39 @@ Float: 1E-05
SerialRoundTrip(settings, text); SerialRoundTrip(settings, text);
} }
public class ObjectFloatDoubleNaNInfinity
{
public double DoubleNaN { get; set; }
public double DoubleNegativeInfinity { get; set; }
public double DoublePositiveInfinity { get; set; }
public float FloatNaN { get; set; }
public float FloatNegativeInfinity { get; set; }
public float FloatPositiveInfinity { get; set; }
}
[Test]
public void TestFloatDoubleNaNInfinity()
{
var settings = new SerializerSettings() { LimitPrimitiveFlowSequence = 20 };
settings.RegisterTagMapping("ObjectFloatDoubleNaNInfinity", typeof(ObjectFloatDoubleNaNInfinity));
var text = @"!ObjectFloatDoubleNaNInfinity
DoubleNaN: NaN
DoubleNegativeInfinity: -Infinity
DoublePositiveInfinity: Infinity
FloatNaN: NaN
FloatNegativeInfinity: -Infinity
FloatPositiveInfinity: Infinity
".Trim();
SerialRoundTrip(settings, text);
}
public class MyObjectAndCollection public class MyObjectAndCollection
{ {
public MyObjectAndCollection() public MyObjectAndCollection()

Просмотреть файл

@ -58,7 +58,7 @@ namespace SharpYaml.Serialization.Serializers
public override object ConvertFrom(ref ObjectContext context, Scalar scalar) public override object ConvertFrom(ref ObjectContext context, Scalar scalar)
{ {
var primitiveType = (PrimitiveDescriptor)context.Descriptor; var primitiveType = (PrimitiveDescriptor)context.Descriptor;
var type = primitiveType.Type; var type = primitiveType.Type;
var text = scalar.Value; var text = scalar.Value;
@ -80,21 +80,21 @@ namespace SharpYaml.Serialization.Serializers
// If type is an enum, try to parse it // If type is an enum, try to parse it
if (type.IsEnum) if (type.IsEnum)
{ {
bool enumRemapped; bool enumRemapped;
var result = primitiveType.ParseEnum(text, out enumRemapped); var result = primitiveType.ParseEnum(text, out enumRemapped);
if (enumRemapped) if (enumRemapped)
{ {
context.SerializerContext.HasRemapOccurred = true; context.SerializerContext.HasRemapOccurred = true;
} }
return result; return result;
} }
// Parse default types // Parse default types
switch (Type.GetTypeCode(type)) switch (Type.GetTypeCode(type))
{ {
case TypeCode.Boolean: case TypeCode.Boolean:
object value; object value;
context.SerializerContext.Schema.TryParse(scalar, type, out value); context.SerializerContext.Schema.TryParse(scalar, type, out value);
return value; return value;
case TypeCode.DateTime: case TypeCode.DateTime:
return DateTime.Parse(text, CultureInfo.InvariantCulture); return DateTime.Parse(text, CultureInfo.InvariantCulture);
@ -102,9 +102,9 @@ namespace SharpYaml.Serialization.Serializers
return text; return text;
} }
if (type == typeof (TimeSpan)) if (type == typeof(TimeSpan))
{ {
return TimeSpan.Parse(text, CultureInfo.InvariantCulture); return TimeSpan.Parse(text, CultureInfo.InvariantCulture);
} }
// Remove _ character from numeric values // Remove _ character from numeric values
@ -145,7 +145,7 @@ namespace SharpYaml.Serialization.Serializers
} }
// If we are expecting a type object, return directly the string // If we are expecting a type object, return directly the string
if (type == typeof (object)) if (type == typeof(object))
{ {
// Try to parse the scalar directly // Try to parse the scalar directly
string defaultTag; string defaultTag;
@ -154,43 +154,43 @@ namespace SharpYaml.Serialization.Serializers
{ {
return scalarValue; return scalarValue;
} }
return text; return text;
} }
throw new YamlException(scalar.Start, scalar.End, "Unable to decode scalar [{0}] not supported by current schema".DoFormat(scalar)); throw new YamlException(scalar.Start, scalar.End, "Unable to decode scalar [{0}] not supported by current schema".DoFormat(scalar));
} }
/// <summary> /// <summary>
/// Appends decimal point to arg if it does not exist /// Appends decimal point to arg if it does not exist
/// </summary> /// </summary>
/// <param name="text"></param> /// <param name="text"></param>
/// <param name="hasNaN">True if the floating point type supports NaN or Infinity.</param> /// <param name="hasNaN">True if the floating point type supports NaN or Infinity.</param>
/// <returns></returns> /// <returns></returns>
private static string AppendDecimalPoint(string text, bool hasNaN) private static string AppendDecimalPoint(string text, bool hasNaN)
{ {
for (var i = 0; i < text.Length; i++) for (var i = 0; i < text.Length; i++)
{ {
var c = text[i]; var c = text[i];
// Do not append a decimal point if floating point type value // Do not append a decimal point if floating point type value
// - is in exponential form, or // - is in exponential form, or
// - already has a decimal point // - already has a decimal point
if (c == 'e' || c == 'E' || c == '.') if (c == 'e' || c == 'E' || c == '.')
{ {
return text; return text;
} }
} }
// Special cases for floating point type supporting NaN and Infinity // Special cases for floating point type supporting NaN and Infinity
if (hasNaN && (string.Equals(text, "NaN") || text.Contains("Infinity"))) if (hasNaN && (string.Equals(text, "NaN") || text.Contains("Infinity")))
return text; return text;
return text + ".0"; return text + ".0";
} }
public override string ConvertTo(ref ObjectContext objectContext) public override string ConvertTo(ref ObjectContext objectContext)
{ {
var text = string.Empty; var text = string.Empty;
var value = objectContext.Instance; var value = objectContext.Instance;
// Return null if expected type is an object and scalar is null // Return null if expected type is an object and scalar is null
if (value == null) if (value == null)
@ -203,60 +203,60 @@ namespace SharpYaml.Serialization.Serializers
// Handle string // Handle string
if (valueType.IsEnum) if (valueType.IsEnum)
{ {
text = ((Enum) Enum.ToObject(valueType, value)).ToString("G"); text = ((Enum)Enum.ToObject(valueType, value)).ToString("G");
} }
else else
{ {
// Parse default types // Parse default types
switch (Type.GetTypeCode(valueType)) switch (Type.GetTypeCode(valueType))
{ {
case TypeCode.String: case TypeCode.String:
case TypeCode.Char: case TypeCode.Char:
text = value.ToString(); text = value.ToString();
break; break;
case TypeCode.Boolean: case TypeCode.Boolean:
text = (bool) value ? "true" : "false"; text = (bool)value ? "true" : "false";
break; break;
case TypeCode.Byte: case TypeCode.Byte:
text = ((byte) value).ToString("G", CultureInfo.InvariantCulture); text = ((byte)value).ToString("G", CultureInfo.InvariantCulture);
break; break;
case TypeCode.SByte: case TypeCode.SByte:
text = ((sbyte) value).ToString("G", CultureInfo.InvariantCulture); text = ((sbyte)value).ToString("G", CultureInfo.InvariantCulture);
break; break;
case TypeCode.Int16: case TypeCode.Int16:
text = ((short) value).ToString("G", CultureInfo.InvariantCulture); text = ((short)value).ToString("G", CultureInfo.InvariantCulture);
break; break;
case TypeCode.UInt16: case TypeCode.UInt16:
text = ((ushort) value).ToString("G", CultureInfo.InvariantCulture); text = ((ushort)value).ToString("G", CultureInfo.InvariantCulture);
break; break;
case TypeCode.Int32: case TypeCode.Int32:
text = ((int) value).ToString("G", CultureInfo.InvariantCulture); text = ((int)value).ToString("G", CultureInfo.InvariantCulture);
break; break;
case TypeCode.UInt32: case TypeCode.UInt32:
text = ((uint) value).ToString("G", CultureInfo.InvariantCulture); text = ((uint)value).ToString("G", CultureInfo.InvariantCulture);
break; break;
case TypeCode.Int64: case TypeCode.Int64:
text = ((long) value).ToString("G", CultureInfo.InvariantCulture); text = ((long)value).ToString("G", CultureInfo.InvariantCulture);
break; break;
case TypeCode.UInt64: case TypeCode.UInt64:
text = ((ulong) value).ToString("G", CultureInfo.InvariantCulture); text = ((ulong)value).ToString("G", CultureInfo.InvariantCulture);
break; break;
case TypeCode.Single: case TypeCode.Single:
//Append decimal point to floating point type values //Append decimal point to floating point type values
//because type changes in round trip conversion if ( value * 10.0 ) % 10.0 == 0 //because type changes in round trip conversion if ( value * 10.0 ) % 10.0 == 0
text = AppendDecimalPoint(((float)value).ToString("R", CultureInfo.InvariantCulture), true); text = AppendDecimalPoint(((float)value).ToString("R", CultureInfo.InvariantCulture), true);
break; break;
case TypeCode.Double: case TypeCode.Double:
text = AppendDecimalPoint(((double)value).ToString("R", CultureInfo.InvariantCulture), true); text = AppendDecimalPoint(((double)value).ToString("R", CultureInfo.InvariantCulture), true);
break; break;
case TypeCode.Decimal: case TypeCode.Decimal:
text = AppendDecimalPoint(((decimal)value).ToString("G", CultureInfo.InvariantCulture), false); text = AppendDecimalPoint(((decimal)value).ToString("G", CultureInfo.InvariantCulture), false);
break; break;
case TypeCode.DateTime: case TypeCode.DateTime:
text = ((DateTime) value).ToString("o", CultureInfo.InvariantCulture); text = ((DateTime)value).ToString("o", CultureInfo.InvariantCulture);
break; break;
default: default:
if (valueType == typeof (TimeSpan)) if (valueType == typeof(TimeSpan))
{ {
text = ((TimeSpan)value).ToString("G", CultureInfo.InvariantCulture); text = ((TimeSpan)value).ToString("G", CultureInfo.InvariantCulture);
} }