From 3a1c6d1b91d82e977c3a2957d5f8a0ec530bf910 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Sun, 26 Jan 2025 11:13:04 +0100 Subject: [PATCH] Fix InvalidCastException in Can/ConvertTo --- .../Input/Command/MouseActionConverter.cs | 24 +++++++-------- .../Input/MouseActionConverter.Tests.cs | 30 +++++-------------- 2 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Command/MouseActionConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Command/MouseActionConverter.cs index 59fa1f97d6b..c69a7b1226e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Command/MouseActionConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Command/MouseActionConverter.cs @@ -1,6 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. using System.ComponentModel; using System.Globalization; @@ -8,12 +7,12 @@ namespace System.Windows.Input { /// - /// Converter class for converting between a and . + /// Converter class for converting between a and . /// public class MouseActionConverter : TypeConverter { /// - /// Used to check whether we can convert a into a . + /// Used to check whether we can convert a into a . /// ///ITypeDescriptorContext ///type to convert from @@ -25,11 +24,11 @@ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceT } /// - /// Used to check whether we can convert specified value to . + /// Used to check whether we can convert specified value to . /// /// ITypeDescriptorContext /// Type to convert to - /// if conversion to is possible, otherwise. + /// if conversion to is possible, otherwise. public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { // We can convert to an InstanceDescriptor or to a string @@ -37,20 +36,20 @@ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinati return false; // When invoked by the serialization engine we can convert to string only for known type - if (context is null || context.Instance is null) + if (context?.Instance is not MouseAction mouseAction) return false; // Make sure the value falls within defined set - return IsDefinedMouseAction((MouseAction)context.Instance); + return IsDefinedMouseAction(mouseAction); } /// - /// Converts of type to its represensation. + /// Converts of type to its representation. /// /// Parser Context /// Culture Info /// MouseAction String - /// A representing the specified by . + /// A representing the specified by . public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object source) { if (source is not string mouseAction) @@ -73,21 +72,20 @@ _ when mouseActionToken.Equals("MiddleDoubleClick", StringComparison.OrdinalIgno } /// - /// Converts a of to its represensation. + /// Converts a of to its representation. /// /// Serialization Context /// Culture Info /// MouseAction value /// Type to Convert - /// A representing the specified by . + /// A representing the specified by . public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { ArgumentNullException.ThrowIfNull(destinationType); - if (value is null || destinationType != typeof(string)) + if (value is not MouseAction mouseAction || destinationType != typeof(string)) throw GetConvertToException(value, destinationType); - MouseAction mouseAction = (MouseAction)value; return mouseAction switch { MouseAction.None => string.Empty, diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/System/Windows/Input/MouseActionConverter.Tests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/System/Windows/Input/MouseActionConverter.Tests.cs index 5fa2efad7d3..b189f9ffb92 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/System/Windows/Input/MouseActionConverter.Tests.cs +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/System/Windows/Input/MouseActionConverter.Tests.cs @@ -23,7 +23,7 @@ public void CanConvertFrom_ReturnsExpected(bool expected, Type sourceType) } [Theory] - [MemberData(nameof(CanConvertTo_Data))] + [MemberData(nameof(CanConvertTo_ReturnsExpected_Data))] public void CanConvertTo_ReturnsExpected(bool expected, bool passContext, object? value, Type? destinationType) { MouseActionConverter converter = new(); @@ -32,7 +32,7 @@ public void CanConvertTo_ReturnsExpected(bool expected, bool passContext, object Assert.Equal(expected, converter.CanConvertTo(passContext ? context : null, destinationType)); } - public static IEnumerable CanConvertTo_Data + public static IEnumerable CanConvertTo_ReturnsExpected_Data { get { @@ -46,6 +46,8 @@ public static IEnumerable CanConvertTo_Data // Unsupported cases yield return new object[] { false, false, MouseAction.None, typeof(string) }; yield return new object[] { false, false, MouseAction.MiddleDoubleClick, typeof(string) }; + yield return new object[] { false, true, (int)MouseAction.MiddleDoubleClick, typeof(string) }; + yield return new object[] { false, true, (short)MouseAction.LeftDoubleClick, typeof(string) }; yield return new object?[] { false, true, null, typeof(MouseAction) }; yield return new object?[] { false, true, null, typeof(string) }; yield return new object?[] { false, false, MouseAction.MiddleDoubleClick, typeof(string) }; @@ -56,16 +58,6 @@ public static IEnumerable CanConvertTo_Data } } - [Fact] - public void CanConvertTo_ThrowsInvalidCastException() - { - MouseActionConverter converter = new(); - StandardContextImpl context = new() { Instance = 10 }; - - // TODO: CanConvert* methods should not throw but the implementation is faulty - Assert.Throws(() => converter.CanConvertTo(context, typeof(string))); - } - [Theory] [MemberData(nameof(ConvertFrom_ReturnsExpected_Data))] public void ConvertFrom_ReturnsExpected(MouseAction expected, ITypeDescriptorContext context, CultureInfo? cultureInfo, string value) @@ -156,6 +148,9 @@ public void ConvertTo_ThrowsArgumentNullException() [Theory] // Unsupported value [InlineData(null, typeof(string))] + // Unsupported unboxing casts + [InlineData((int)MouseAction.RightClick, typeof(string))] + [InlineData((short)MouseAction.LeftDoubleClick, typeof(string))] // Unsupported destinationType [InlineData(MouseAction.None, typeof(int))] [InlineData(MouseAction.LeftClick, typeof(byte))] @@ -166,21 +161,12 @@ public void ConvertTo_ThrowsNotSupportedException(object? value, Type destinatio Assert.Throws(() => converter.ConvertTo(value, destinationType)); } - [Fact] - public void ConvertTo_ThrowsInvalidCastException() - { - MouseActionConverter converter = new(); - - // TODO: This should not throw InvalidCastException but NotSupportedException - Assert.Throws(() => converter.ConvertTo(null, null, (int)(MouseAction.MiddleDoubleClick), typeof(string))); - } - [Fact] public void ConvertTo_ThrowsInvalidEnumArgumentException() { MouseActionConverter converter = new(); - Assert.Throws(() => converter.ConvertTo(null, null, (MouseAction)(MouseAction.MiddleDoubleClick + 1), typeof(string))); + Assert.Throws(() => converter.ConvertTo(null, null, MouseAction.MiddleDoubleClick + 1, typeof(string))); } public sealed class StandardContextImpl : ITypeDescriptorContext