diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/TextCaseConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/TextCaseConverter_Tests.cs index 94782696f..e05912354 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/TextCaseConverter_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/TextCaseConverter_Tests.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Globalization; using Xamarin.CommunityToolkit.Converters; +using Xamarin.CommunityToolkit.UnitTests.Mocks; using Xunit; namespace Xamarin.CommunityToolkit.UnitTests.Converters @@ -10,35 +12,50 @@ public class TextCaseConverter_Tests const string test = nameof(test); const string t = nameof(t); + static IEnumerable GetTestData() + { + yield return new object[] { test, TextCaseType.Lower, test }; + yield return new object[] { test, TextCaseType.Upper, "TEST" }; + yield return new object[] { test, TextCaseType.None, test }; + yield return new object[] { test, TextCaseType.FirstUpperRestLower, "Test" }; + yield return new object[] { t, TextCaseType.Upper, "T" }; + yield return new object[] { t, TextCaseType.Lower, t }; + yield return new object[] { t, TextCaseType.None, t }; + yield return new object[] { t, TextCaseType.FirstUpperRestLower, "T" }; + yield return new object[] { string.Empty, TextCaseType.FirstUpperRestLower, string.Empty }; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + yield return new object[] { null, TextCaseType.None, null }; +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. + yield return new object[] { MockEnum.Foo, TextCaseType.Lower, "foo" }; + yield return new object[] { MockEnum.Bar, TextCaseType.None, "Bar" }; + yield return new object[] { MockEnum.Baz, TextCaseType.Upper, "BAZ" }; + yield return new object[] { new MockItem { Title = "Test Item", Completed = true }, TextCaseType.Upper, "TEST ITEM IS COMPLETED" }; + } + [Theory] - [InlineData(test, TextCaseType.Lower, test)] - [InlineData(test, TextCaseType.Upper, "TEST")] - [InlineData(test, TextCaseType.None, test)] - [InlineData(test, TextCaseType.FirstUpperRestLower, "Test")] - [InlineData(t, TextCaseType.Upper, "T")] - [InlineData(t, TextCaseType.Lower, t)] - [InlineData(t, TextCaseType.None, t)] - [InlineData(t, TextCaseType.FirstUpperRestLower, "T")] - [InlineData("", TextCaseType.FirstUpperRestLower, "")] + [MemberData(nameof(GetTestData))] [InlineData(null, null, null)] - public void TextCaseConverter(object value, object comparedValue, object expectedResult) + public void TextCaseConverterWithParameter(object? value, object? comparedValue, object? expectedResult) { var textCaseConverter = new TextCaseConverter(); - var result = textCaseConverter.Convert(value, typeof(TextCaseConverter_Tests), comparedValue, CultureInfo.CurrentCulture); + var result = textCaseConverter.Convert(value, typeof(string), comparedValue, CultureInfo.CurrentCulture); Assert.Equal(result, expectedResult); } [Theory] - [InlineData(0)] - [InlineData(int.MinValue)] - [InlineData(double.MaxValue)] - public void InValidConverterValuesThrowArgumenException(object value) + [MemberData(nameof(GetTestData))] + public void TextCaseConverterWithExplicitType(object? value, TextCaseType textCaseType, object? expectedResult) { - var textCaseConverter = new TextCaseConverter(); + var textCaseConverter = new TextCaseConverter + { + Type = textCaseType + }; + + var result = textCaseConverter.Convert(value, typeof(string), null, CultureInfo.CurrentCulture); - Assert.Throws(() => textCaseConverter.Convert(value, typeof(TextCaseConverter_Tests), null, CultureInfo.CurrentCulture)); + Assert.Equal(result, expectedResult); } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockEnum.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockEnum.cs new file mode 100644 index 000000000..6ceae3df9 --- /dev/null +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockEnum.cs @@ -0,0 +1,9 @@ +namespace Xamarin.CommunityToolkit.UnitTests.Mocks +{ + public enum MockEnum + { + Foo, + Bar, + Baz + } +} diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockItem.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockItem.cs new file mode 100644 index 000000000..df12403ec --- /dev/null +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockItem.cs @@ -0,0 +1,12 @@ +namespace Xamarin.CommunityToolkit.UnitTests.Mocks +{ + public class MockItem + { + public string? Title { get; set; } + + public bool Completed { get; set; } + + public override string ToString() => Completed ? + $"{Title} is completed" : $"{Title} has yet to be completed"; + } +} diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs index f1f7502a8..1e28938b2 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs @@ -25,9 +25,19 @@ public class TextCaseConverter : ValueConverterExtension, IValueConverter /// The culture to use in the converter. This is not implemented. /// The converted text representation with the desired casing. public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) - => value == null || value is string || value is char - ? Convert(value?.ToString(), parameter) - : throw new ArgumentException("Value is neither a string nor a char", nameof(value)); + { + var str = value?.ToString(); + if (str == null || string.IsNullOrWhiteSpace(str)) + return str; + + return GetParameter(parameter) switch + { + TextCaseType.Lower => str.ToLowerInvariant(), + TextCaseType.Upper => str.ToUpperInvariant(), + TextCaseType.FirstUpperRestLower => str.Substring(0, 1).ToUpperInvariant() + str.ToString().Substring(1).ToLowerInvariant(), + _ => str + }; + } /// /// This method is not implemented and will throw a . @@ -37,18 +47,10 @@ public class TextCaseConverter : ValueConverterExtension, IValueConverter /// N/A /// N/A /// N/A -public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture) + public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture) => throw new NotImplementedException(); - object? Convert(string? value, object? parameter) => GetParameter(parameter) switch - { - TextCaseType.Lower => value?.ToLowerInvariant(), - TextCaseType.Upper => value?.ToUpperInvariant(), - TextCaseType.FirstUpperRestLower when value != null && !string.IsNullOrWhiteSpace(value) => value.Substring(0, 1).ToUpperInvariant() + value.Substring(1).ToLowerInvariant(), - _ => value - }; - - TextCaseType GetParameter(object? parameter) => parameter == null ? Type : parameter switch + TextCaseType GetParameter(object? parameter) => parameter switch { TextCaseType type => type, string typeString => Enum.TryParse(typeString, out TextCaseType result) @@ -57,7 +59,7 @@ public object ConvertBack(object? value, Type? targetType, object? parameter, Cu int typeInt => Enum.IsDefined(typeof(TextCaseType), typeInt) ? (TextCaseType)typeInt : throw new ArgumentException("Cannot convert integer to text case enum value", nameof(parameter)), - _ => TextCaseType.None, + _ => Type, }; } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseType.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseType.shared.cs index c85ead61f..0c4e9aebd 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseType.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseType.shared.cs @@ -13,6 +13,8 @@ public enum TextCaseType /// Convert to lowercase Lower, + + /// Converts the first letter to upper only FirstUpperRestLower, } } \ No newline at end of file