Skip to content

Commit

Permalink
fix: FIR-33174: parse boolean in old (0/1) and new (false/true) forma…
Browse files Browse the repository at this point in the history
…ts (#86)
  • Loading branch information
alexradzin authored May 22, 2024
1 parent 64b335d commit c6f51ad
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 11 deletions.
10 changes: 9 additions & 1 deletion FireboltDotNetSdk.Tests/Unit/FireboltDataReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,11 @@ public void Numbers()
new Meta() { Name = "real_number", Type = "text" },
new Meta() { Name = "int_number", Type = "text" },
new Meta() { Name = "bool_string", Type = "text" },
new Meta() { Name = "num_bool_string", Type = "text" },
},
Data = new List<List<object?>>()
{
new List<object?>() { byteValue, shortValue, intValue, longValue, floatValue, 3.1415926, true, "2.71828", "123", "true" }
new List<object?>() { byteValue, shortValue, intValue, longValue, floatValue, 3.1415926, true, "2.71828", "123", "true", "0" }
}
};

Expand Down Expand Up @@ -244,6 +245,13 @@ public void Numbers()
Assert.That(reader.GetBoolean(9), Is.EqualTo(true));
Assert.That(reader.GetChar(9), Is.EqualTo('t'));

Assert.That(reader.GetBoolean(10), Is.EqualTo(false));
Assert.That(reader.GetChar(10), Is.EqualTo('0'));
Assert.That(reader.GetByte(10), Is.EqualTo(0));
Assert.That(reader.GetInt16(10), Is.EqualTo(0));
Assert.That(reader.GetInt32(10), Is.EqualTo(0));
Assert.That(reader.GetInt64(10), Is.EqualTo(0));

Assert.That(reader.Read(), Is.EqualTo(false));

Assert.That(reader.IsClosed, Is.EqualTo(false));
Expand Down
31 changes: 23 additions & 8 deletions FireboltDotNetSdk.Tests/Unit/TypesConverterTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace FireboltDotNetSdk.Tests;

public class TypesConverterTest
{
private const string WRONG_NUMERIC_FORMAT_ERROR_MESSAGE = "Input string was not in a correct format.";

[TestCase("string", "Hello", "Hello")]
[TestCase("string", null, null)]
[TestCase("text", "Hello", "Hello")]
Expand Down Expand Up @@ -46,25 +48,38 @@ public class TypesConverterTest
[TestCase("double", "-inf", double.NegativeInfinity)]
[TestCase("double", "nan", double.NaN)]
[TestCase("double", "-nan", double.NaN)]
[TestCase("boolean", "true", true)]
[TestCase("boolean", "false", false)]
[TestCase("boolean", "1", true)]
[TestCase("boolean", "0", false)]
public void ConvertProvidedValues(string columnTypeName, string value, object expectedValue)
{
ColumnType columnType = ColumnType.Of(columnTypeName);
object? result = TypesConverter.ConvertToCSharpVal(value, columnType);
Assert.That(expectedValue, Is.EqualTo(result));
}

[TestCase("int", "+inf")]
[TestCase("int", "-inf")]
[TestCase("int", "inf")]
[TestCase("long", "+inf")]
[TestCase("long", "-inf")]
[TestCase("long", "inf")]
public void FailingConvertProvidedValues(string columnTypeName, string value)
[TestCase("int", "+inf", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("int", "-inf", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("int", "inf", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("long", "+inf", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("long", "-inf", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("long", "inf", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("int", "hello", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("int", "bye", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("int", "not a number", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("long", "some text", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("long", "", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("long", "not empty text", WRONG_NUMERIC_FORMAT_ERROR_MESSAGE)]
[TestCase("boolean", "2", "String '2' was not recognized as a valid Boolean.")]
[TestCase("boolean", "t", "String 't' was not recognized as a valid Boolean.")]
[TestCase("boolean", "yes", "String 'yes' was not recognized as a valid Boolean.")]
public void FailingConvertProvidedValues(string columnTypeName, string value, string expectedErrorMessage)
{
ColumnType columnType = ColumnType.Of(columnTypeName);
FormatException? e = Assert.Throws<FormatException>(() => TypesConverter.ConvertToCSharpVal(value, columnType));
string visualTypeName = char.ToUpper(columnTypeName[0]) + columnTypeName.Substring(1);
Assert.That(e?.Message, Is.EqualTo($"Input string was not in a correct format."));
Assert.That(e?.Message, Is.EqualTo(expectedErrorMessage));
}

[Test]
Expand Down
2 changes: 1 addition & 1 deletion FireboltNETSDK/Client/FireboltDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public override bool GetBoolean(int ordinal)
case short s: return s != 0;
case int i: return i != 0;
case long l: return l != 0;
case string s: return bool.Parse(s);
case string s: return TypesConverter.ParseBoolean(s);
default: throw new InvalidCastException($"Cannot cast ({value.GetType()}){value} to boolean");
}
}
Expand Down
19 changes: 18 additions & 1 deletion FireboltNETSDK/Utils/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ public static class TypesConverter
{
double.PositiveInfinity, double.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity
};
// when ParseBoolean is called from ConvertToCSharpVal that in turn invoked from FireboltDataReader.GetValueSafely() that calls ToString()
// to create string value representation. In case of boolean ToString() performs capitalization,
// so true becomes string True and false becomes False. However when ParseBoolean is invoked directly from GetBoolean()
// the value may be true (lower case). This is the reason to use case insensitive comparison.
private static IDictionary<string, bool> booleanValues = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase)
{
{ "true", true },
{ "false", false },
{ "1", true },
{ "0", false },
};

public static object? ConvertToCSharpVal(string? val, ColumnType columnType)
{
Expand Down Expand Up @@ -68,7 +79,7 @@ public static class TypesConverter
case FireboltDataType.Float:
return floatInfinity.ContainsKey(str) ? floatInfinity[str] : Convert.ToSingle(str.Trim('"'), CultureInfo.InvariantCulture);
case FireboltDataType.Boolean:
return bool.Parse(str);
return ParseBoolean(str);
case FireboltDataType.Array:
return ArrayHelper.TransformToSqlArray(str, columnType);
case FireboltDataType.ByteA:
Expand All @@ -80,6 +91,12 @@ public static class TypesConverter
}
}

public static bool ParseBoolean(string str)
{
bool b;
return booleanValues.TryGetValue(str, out b) ? b : throw new FormatException($"String '{str}' was not recognized as a valid Boolean.");
}

public static DateTime ParseDateTime(string str)
{
try
Expand Down

0 comments on commit c6f51ad

Please sign in to comment.