diff --git a/src/ConfigCat.Client.Tests/UtilsTest.cs b/src/ConfigCat.Client.Tests/UtilsTest.cs index d1ce7945..05caa6c3 100644 --- a/src/ConfigCat.Client.Tests/UtilsTest.cs +++ b/src/ConfigCat.Client.Tests/UtilsTest.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; using ConfigCat.Client.Utils; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -12,9 +15,28 @@ public class UtilsTest [DataRow(new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, "0123456789abcdef")] [DataRow(new byte[] { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, "fedcba9876543210")] [DataTestMethod] - public void ArrayUtils_ToHexString_Works(byte[] bytes, string expected) + public void ArrayUtils_ToHexString_Works(byte[] bytes, string expectedResult) { - Assert.AreEqual(expected, bytes.ToHexString()); + Assert.AreEqual(expectedResult, bytes.ToHexString()); + } + + [DataRow(new byte[] { }, "", true)] + [DataRow(new byte[] { }, "00", false)] + [DataRow(new byte[] { }, " ", false)] + [DataRow(new byte[] { }, "0", false)] + [DataRow(new byte[] { 0 }, "00", true)] + [DataRow(new byte[] { 0 }, "0000", false)] + [DataRow(new byte[] { 0 }, "01", false)] + [DataRow(new byte[] { 0 }, "000", false)] + [DataRow(new byte[] { 0 }, " 00 ", false)] + [DataRow(new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, "0123456789abcdef", true)] + [DataRow(new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, "0123456789abcdee", false)] + [DataRow(new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, "0123456789abcdeg", false)] + [DataRow(new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, "0123456789a_bcde", false)] + [DataTestMethod] + public void ArrayUtils_EqualsToHexString_Works(byte[] bytes, string hexString, bool expectedResult) + { + Assert.AreEqual(expectedResult, bytes.Equals(hexString.AsSpan())); } [DataRow("-62135596800001", -1L)] @@ -42,4 +64,97 @@ public void DateTimeUtils_UnixTimeStampConversion_Works(string dateString, long Assert.IsFalse(success); } } + + [DataRow(-62135596800.001, -1L)] + [DataRow(-62135596800.000, 0L)] + [DataRow(0, 621355968000000000L)] + [DataRow(+253402300799.999, 3155378975999990000L)] + [DataRow(+253402300800.000, -1L)] + [DataTestMethod] + public void DateTimeUtils_UnixTimeSecondsConversion_Works(double seconds, long ticks) + { + var success = DateTimeUtils.TryConvertFromUnixTimeSeconds(seconds, out var dateTime); + if (ticks >= 0) + { + Assert.IsTrue(success); + Assert.AreEqual(ticks, dateTime.Ticks); + } + else + { + Assert.IsFalse(success); + } + } + + [DataRow(new string[] { }, 0, false, null, "")] + [DataRow(new string[] { }, 1, true, null, "")] + [DataRow(new string[] { "a" }, 0, false, null, "'a'")] + [DataRow(new string[] { "a" }, 1, true, null, "'a'")] + [DataRow(new string[] { "a" }, 1, true, "a", "'a'")] + [DataRow(new string[] { "a", "b", "c" }, 0, false, null, "'a', 'b', 'c'")] + [DataRow(new string[] { "a", "b", "c" }, 3, false, null, "'a', 'b', 'c'")] + [DataRow(new string[] { "a", "b", "c" }, 2, false, null, "'a', 'b'")] + [DataRow(new string[] { "a", "b", "c" }, 2, true, null, "'a', 'b', ...1 item(s) omitted")] + [DataRow(new string[] { "a", "b", "c" }, 0, true, "a", "'a' -> 'b' -> 'c'")] + [DataTestMethod] + public void StringListFormatter_ToString_Works(string[] items, int maxLength, bool addOmittedItemsText, string? format, string expectedResult) + { + var actualResult = new StringListFormatter(items, maxLength, addOmittedItemsText ? static (count) => $", ...{count} item(s) omitted" : null) + .ToString(format, CultureInfo.InvariantCulture); + + Assert.AreEqual(expectedResult, actualResult); + } + + [TestMethod] + public void ModelHelper_SetOneOf_Works() + { + object? field = null; + + Assert.IsFalse(ModelHelper.IsValidOneOf(field)); + + ModelHelper.SetOneOf(ref field, null); + Assert.IsNull(field); + Assert.IsFalse(ModelHelper.IsValidOneOf(field)); + + ModelHelper.SetOneOf(ref field, true); + Assert.AreEqual(true, field); + Assert.IsTrue(ModelHelper.IsValidOneOf(field)); + + ModelHelper.SetOneOf(ref field, null); + Assert.AreEqual(true, field); + Assert.IsTrue(ModelHelper.IsValidOneOf(field)); + + ModelHelper.SetOneOf(ref field, true); + Assert.IsNotNull(field); + Assert.AreNotEqual(true, field); + Assert.AreNotEqual(false, field); + Assert.IsFalse(ModelHelper.IsValidOneOf(field)); + + ModelHelper.SetOneOf(ref field, null); + Assert.IsNotNull(field); + Assert.AreNotEqual(true, field); + Assert.AreNotEqual(false, field); + Assert.IsFalse(ModelHelper.IsValidOneOf(field)); + } + + private static IEnumerable GetEnumValues() => Enum.GetValues(typeof(SettingType)) + .Cast() + .Concat(new[] { Setting.UnknownType }) + .Select(t => new object?[] { t }); + + [DataTestMethod] + [DynamicData(nameof(GetEnumValues), DynamicDataSourceType.Method)] + public void ModelHelper_SetEnum_Works(SettingType enumValue) + { + SettingType field = default; + + if (Enum.IsDefined(typeof(SettingType), enumValue)) + { + ModelHelper.SetEnum(ref field, enumValue); + Assert.AreEqual(enumValue, field); + } + else + { + Assert.ThrowsException(() => ModelHelper.SetEnum(ref field, enumValue)); + } + } } diff --git a/src/ConfigCatClient/Utils/ArrayUtils.cs b/src/ConfigCatClient/Utils/ArrayUtils.cs index 1fa0eb4f..b9cd24c5 100644 --- a/src/ConfigCatClient/Utils/ArrayUtils.cs +++ b/src/ConfigCatClient/Utils/ArrayUtils.cs @@ -56,7 +56,7 @@ public static bool Equals(this byte[] bytes, ReadOnlySpan hexString) if ((hi = GetDigitValue(hexString[j++])) < 0 || (lo = GetDigitValue(hexString[j++])) < 0) { - throw new FormatException(); + return false; } var decodedByte = (byte)(hi << 4 | lo); diff --git a/src/ConfigCatClient/Utils/ModelHelper.cs b/src/ConfigCatClient/Utils/ModelHelper.cs index f71196bc..8a9eae3b 100644 --- a/src/ConfigCatClient/Utils/ModelHelper.cs +++ b/src/ConfigCatClient/Utils/ModelHelper.cs @@ -8,7 +8,7 @@ internal static class ModelHelper public static void SetOneOf(ref object? field, T? value) { - if (value is not null && !ReferenceEquals(field, value)) + if (value is not null) { field = field is null ? value : MultipleValuesToken; }