From 64a0bdee40daa08f0d258f92c9c2dfad63147cd2 Mon Sep 17 00:00:00 2001 From: alexradzin Date: Wed, 22 May 2024 11:42:37 +0300 Subject: [PATCH] fix: FIR-33174: parse boolean in old (0/1) and new (false/true) formats --- .../Unit/FireboltDataReaderTest.cs | 10 +++++- .../Unit/TypesConverterTest.cs | 31 ++++++++++++++----- FireboltNETSDK/Client/FireboltDataReader.cs | 2 +- FireboltNETSDK/Utils/Types.cs | 15 ++++++++- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/FireboltDotNetSdk.Tests/Unit/FireboltDataReaderTest.cs b/FireboltDotNetSdk.Tests/Unit/FireboltDataReaderTest.cs index f59f750..02def26 100644 --- a/FireboltDotNetSdk.Tests/Unit/FireboltDataReaderTest.cs +++ b/FireboltDotNetSdk.Tests/Unit/FireboltDataReaderTest.cs @@ -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>() { - new List() { byteValue, shortValue, intValue, longValue, floatValue, 3.1415926, true, "2.71828", "123", "true" } + new List() { byteValue, shortValue, intValue, longValue, floatValue, 3.1415926, true, "2.71828", "123", "true", "0" } } }; @@ -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)); diff --git a/FireboltDotNetSdk.Tests/Unit/TypesConverterTest.cs b/FireboltDotNetSdk.Tests/Unit/TypesConverterTest.cs index be09b8e..7f37d51 100644 --- a/FireboltDotNetSdk.Tests/Unit/TypesConverterTest.cs +++ b/FireboltDotNetSdk.Tests/Unit/TypesConverterTest.cs @@ -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")] @@ -46,6 +48,10 @@ 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); @@ -53,18 +59,27 @@ public void ConvertProvidedValues(string columnTypeName, string value, object ex 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(() => 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] diff --git a/FireboltNETSDK/Client/FireboltDataReader.cs b/FireboltNETSDK/Client/FireboltDataReader.cs index cda2093..ee2ec11 100644 --- a/FireboltNETSDK/Client/FireboltDataReader.cs +++ b/FireboltNETSDK/Client/FireboltDataReader.cs @@ -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"); } } diff --git a/FireboltNETSDK/Utils/Types.cs b/FireboltNETSDK/Utils/Types.cs index 5584015..0e345c6 100644 --- a/FireboltNETSDK/Utils/Types.cs +++ b/FireboltNETSDK/Utils/Types.cs @@ -38,6 +38,13 @@ public static class TypesConverter { double.PositiveInfinity, double.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity }; + private static IDictionary booleanValues = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "true", true }, + { "false", false }, + { "1", true }, + { "0", false }, + }; public static object? ConvertToCSharpVal(string? val, ColumnType columnType) { @@ -68,7 +75,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: @@ -80,6 +87,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