File: System\Windows\Input\MouseActionConverter.Tests.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\tests\UnitTests\PresentationCore.Tests\PresentationCore.Tests.csproj (PresentationCore.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.ComponentModel.Design.Serialization;
using System.ComponentModel;
using System.Globalization;
 
namespace System.Windows.Input;
 
public sealed class MouseActionConverterTests
{
    [Theory]
    // Supported type
    [InlineData(true, typeof(string))]
    // Unsupported types
    [InlineData(false, typeof(InstanceDescriptor))]
    [InlineData(false, typeof(MouseAction))]
    public void CanConvertFrom_ReturnsExpected(bool expected, Type sourceType)
    {
        MouseActionConverter converter = new();
 
        Assert.Equal(expected, converter.CanConvertFrom(null, sourceType));
    }
 
    [Theory]
    [MemberData(nameof(CanConvertTo_Data))]
    public void CanConvertTo_ReturnsExpected(bool expected, bool passContext, object? value, Type? destinationType)
    {
        MouseActionConverter converter = new();
        StandardContextImpl context = new() { Instance = value };
 
        Assert.Equal(expected, converter.CanConvertTo(passContext ? context : null, destinationType));
    }
 
    public static IEnumerable<object?[]> CanConvertTo_Data
    {
        get
        {
            // Supported cases
            yield return new object[] { true, true, MouseAction.None, typeof(string) };
            yield return new object[] { true, true, MouseAction.MiddleDoubleClick, typeof(string) };
 
            // Unsupported case (Value is above MouseAction range)
            yield return new object[] { false, true, MouseAction.MiddleDoubleClick + 1, typeof(string) };
 
            // 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, null, typeof(MouseAction) };
            yield return new object?[] { false, true, null, typeof(string) };
            yield return new object?[] { false, false, MouseAction.MiddleDoubleClick, typeof(string) };
            yield return new object?[] { false, false, null, typeof(string) };
            yield return new object?[] { false, false, null, null };
 
            yield return new object[] { false, true, MouseAction.MiddleDoubleClick + 1, typeof(string) };
        }
    }
 
    [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<InvalidCastException>(() => converter.CanConvertTo(context, typeof(string)));
    }
 
    [Theory]
    [MemberData(nameof(ConvertFrom_ReturnsExpected_Data))]
    public void ConvertFrom_ReturnsExpected(MouseAction expected, ITypeDescriptorContext context, CultureInfo? cultureInfo, string value)
    {
        MouseActionConverter converter = new();
 
        Assert.Equal(expected, (MouseAction)converter.ConvertFrom(context, cultureInfo, value));
    }
 
    public static IEnumerable<object?[]> ConvertFrom_ReturnsExpected_Data
    {
        get
        {
            // ConvertTo handles two different inputs as MouseAction.None
            yield return new object?[] { MouseAction.None, null, CultureInfo.InvariantCulture, string.Empty };
            yield return new object?[] { MouseAction.None, null, CultureInfo.InvariantCulture, "None" };
 
            // Supported cases (Culture must stay irrelevant)
            yield return new object?[] { MouseAction.None, null, CultureInfo.InvariantCulture, string.Empty };
            yield return new object?[] { MouseAction.LeftClick, null, new CultureInfo("ru-RU"), "LeftClick" };
            yield return new object?[] { MouseAction.RightClick, null, CultureInfo.InvariantCulture, "RightClick" };
            yield return new object?[] { MouseAction.MiddleClick, null, CultureInfo.InvariantCulture, "MiddleClick" };
            yield return new object?[] { MouseAction.WheelClick, null, new CultureInfo("no-NO"), "WheelClick" };
            yield return new object?[] { MouseAction.LeftDoubleClick, null, CultureInfo.InvariantCulture, "LeftDoubleClick" };
            yield return new object?[] { MouseAction.RightDoubleClick, null, CultureInfo.InvariantCulture, "RightDoubleClick" };
            yield return new object?[] { MouseAction.MiddleDoubleClick, null, CultureInfo.InvariantCulture, "MiddleDoubleClick" };
 
            // Supported cases (fuzzed via whitespace and casing)  
            yield return new object?[] { MouseAction.None, null, CultureInfo.InvariantCulture, "                " };
            yield return new object?[] { MouseAction.None, null, new CultureInfo("ru-RU"), "         NoNE          " };
            yield return new object?[] { MouseAction.LeftClick, null, CultureInfo.InvariantCulture, "   LeFTCliCK  " };
            yield return new object?[] { MouseAction.WheelClick, null, CultureInfo.InvariantCulture, "         WHEELCLICK" };
            yield return new object?[] { MouseAction.MiddleClick, null, new CultureInfo("no-NO"), "   MiDDLeCliCK   " };
            yield return new object?[] { MouseAction.LeftDoubleClick, null, CultureInfo.InvariantCulture, "    leftdoubleclick   " };
            yield return new object?[] { MouseAction.RightClick, null, CultureInfo.InvariantCulture, " rightclick" };
        }
    }
 
    [Theory]
    // Unsupported values (data type)
    [InlineData(null)]
    [InlineData(Key.VolumeDown)]
    [InlineData(MouseAction.None)]
    // Unsupported value (bad string)
    [InlineData("BadString")]
    [InlineData("MouseZClick")]
    public void ConvertFrom_ThrowsNotSupportedException(object? value)
    {
        MouseActionConverter converter = new();
 
        Assert.Throws<NotSupportedException>(() => converter.ConvertFrom(null, null, value));
    }
 
    [Theory]
    [MemberData(nameof(ConvertTo_ReturnsExpected_Data))]
    public void ConvertTo_ReturnsExpected(string expected, ITypeDescriptorContext context, CultureInfo? cultureInfo, object? value)
    {
        MouseActionConverter converter = new();
 
        // Culture and context must not have any meaning
        Assert.Equal(expected, (string)converter.ConvertTo(context, cultureInfo, value, typeof(string)));
    }
 
    public static IEnumerable<object?[]> ConvertTo_ReturnsExpected_Data
    {
        get
        {
            // Supported cases (Culture must stay irrelevant)
            yield return new object?[] { string.Empty, null, CultureInfo.InvariantCulture, MouseAction.None };
            yield return new object?[] { "LeftClick", null, CultureInfo.InvariantCulture, MouseAction.LeftClick };
            yield return new object?[] { "RightClick", null, new CultureInfo("ru-RU"), MouseAction.RightClick };
            yield return new object?[] { "MiddleClick", null, CultureInfo.InvariantCulture, MouseAction.MiddleClick };
            yield return new object?[] { "WheelClick", null, new CultureInfo("no-NO"), MouseAction.WheelClick };
            yield return new object?[] { "LeftDoubleClick", null, CultureInfo.InvariantCulture, MouseAction.LeftDoubleClick };
            yield return new object?[] { "RightDoubleClick", null, null, MouseAction.RightDoubleClick };
            yield return new object?[] { "MiddleDoubleClick", null, null, MouseAction.MiddleDoubleClick };
        }
    }
 
    [Fact]
    public void ConvertTo_ThrowsArgumentNullException()
    {
        MouseActionConverter converter = new();
 
        Assert.Throws<ArgumentNullException>(() => converter.ConvertTo(MouseAction.None, destinationType: null!));
    }
 
    [Theory]
    // Unsupported value
    [InlineData(null, typeof(string))]
    // Unsupported destinationType
    [InlineData(MouseAction.None, typeof(int))]
    [InlineData(MouseAction.LeftClick, typeof(byte))]
    public void ConvertTo_ThrowsNotSupportedException(object? value, Type destinationType)
    {
        MouseActionConverter converter = new();
 
        Assert.Throws<NotSupportedException>(() => converter.ConvertTo(value, destinationType));
    }
 
    [Fact]
    public void ConvertTo_ThrowsInvalidCastException()
    {
        MouseActionConverter converter = new();
 
        // TODO: This should not throw InvalidCastException but NotSupportedException
        Assert.Throws<InvalidCastException>(() => converter.ConvertTo(null, null, (int)(MouseAction.MiddleDoubleClick), typeof(string)));
    }
 
    [Fact]
    public void ConvertTo_ThrowsInvalidEnumArgumentException()
    {
        MouseActionConverter converter = new();
 
        Assert.Throws<InvalidEnumArgumentException>(() => converter.ConvertTo(null, null, (MouseAction)(MouseAction.MiddleDoubleClick + 1), typeof(string)));
    }
 
    public sealed class StandardContextImpl : ITypeDescriptorContext
    {
        public IContainer? Container => throw new NotImplementedException();
 
        public object? Instance { get; set; }
 
        public PropertyDescriptor? PropertyDescriptor => throw new NotImplementedException();
        public object? GetService(Type serviceType) => throw new NotImplementedException();
        public void OnComponentChanged() => throw new NotImplementedException();
        public bool OnComponentChanging() => throw new NotImplementedException();
    }
}