Skip to content

Commit

Permalink
Add test coverage for public surface of MouseGestureConverter (dotnet…
Browse files Browse the repository at this point in the history
  • Loading branch information
h3xds1nz authored Jan 21, 2025
1 parent a7acd6a commit 928d828
Showing 1 changed file with 217 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// 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.Command;

public sealed class MouseGestureConverterTests
{
[Theory]
// Valid type
[InlineData(true, typeof(string))]
// Invalid types
[InlineData(false, typeof(MouseAction))]
[InlineData(false, typeof(ModifierKeys))]
[InlineData(false, typeof(KeyGesture))]
[InlineData(false, typeof(MouseGesture))]
[InlineData(false, typeof(InstanceDescriptor))]
public void CanConvertFrom_ReturnsExpected(bool expected, Type sourceType)
{
MouseGestureConverter converter = new();

Assert.Equal(expected, converter.CanConvertFrom(sourceType));
}

[Theory]
[MemberData(nameof(CanConvertTo_Data))]
public void CanConvertTo_ReturnsExpected(bool expected, bool passContext, object? value, Type? destinationType)
{
MouseGestureConverter 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, new MouseGesture(MouseAction.None, ModifierKeys.Control), typeof(string) };
yield return new object[] { true, true, new MouseGesture(MouseAction.None, ModifierKeys.Alt), typeof(string) };
yield return new object[] { true, true, new MouseGesture(MouseAction.MiddleDoubleClick, ModifierKeys.Shift), typeof(string) };
yield return new object[] { true, true, new MouseGesture(MouseAction.LeftDoubleClick, ModifierKeys.Control | ModifierKeys.Windows | ModifierKeys.Alt), typeof(string) };
yield return new object[] { true, true, new MouseGesture(MouseAction.WheelClick, ModifierKeys.Control | ModifierKeys.Windows), typeof(string) };
yield return new object[] { true, true, new MouseGesture(MouseAction.LeftClick, ModifierKeys.Alt | ModifierKeys.Windows), typeof(string) };
yield return new object[] { true, true, new MouseGesture(MouseAction.RightClick, ModifierKeys.Alt | ModifierKeys.Control), typeof(string) };
yield return new object[] { true, true, new MouseGesture(MouseAction.RightDoubleClick, ModifierKeys.Alt | ModifierKeys.Windows | ModifierKeys.Control), typeof(string) };
yield return new object[] { true, true, new MouseGesture(MouseAction.RightDoubleClick, ModifierKeys.None), typeof(string) };

// Unsupported cases (Null Context)
yield return new object?[] { false, false, null, typeof(string) };
// Unsupported cases (Null Context/Destination Type)
yield return new object?[] { false, false, null, null };
// Unsupported cases (Null Instance)
yield return new object?[] { false, true, null, typeof(string) };
// Unsupported cases (Null Instance/Destination Type)
yield return new object?[] { false, true, null, null };
// Unsupported cases (Wrong destination type)
yield return new object?[] { false, true, new MouseGesture(MouseAction.None, ModifierKeys.Control), null };
yield return new object?[] { false, true, new MouseGesture(MouseAction.WheelClick, ModifierKeys.Control | ModifierKeys.Windows), typeof(KeyGesture) };
yield return new object?[] { false, true, new MouseGesture(MouseAction.LeftClick, ModifierKeys.Alt | ModifierKeys.Windows), typeof(MouseGesture) };
yield return new object?[] { false, true, new MouseGesture(MouseAction.None, ModifierKeys.Control), typeof(MouseAction) };
yield return new object?[] { false, true, new MouseGesture(MouseAction.RightDoubleClick, ModifierKeys.Alt | ModifierKeys.Windows | ModifierKeys.Control), typeof(Key) };
yield return new object?[] { false, true, new MouseGesture(MouseAction.RightDoubleClick, ModifierKeys.None), typeof(ModifierKeys) };
// Unsupported cases (Wrong Context Instance)
yield return new object?[] { false, true, new KeyGesture(Key.None, ModifierKeys.Alt), typeof(string) };
yield return new object?[] { false, true, MouseAction.WheelClick, typeof(string) };
yield return new object?[] { false, true, Key.F1, typeof(string) };

// We do not test for malformed MouseGesture as MouseGesture has to perform its own validation and shall be enforced via its own unit tests
}
}

[Theory]
[MemberData(nameof(ConvertFrom_ReturnsExpected_Data))]
public void ConvertFrom_ReturnsExpected(MouseGesture expected, ITypeDescriptorContext context, CultureInfo? cultureInfo, string value)
{
MouseGestureConverter converter = new();

MouseGesture converted = (MouseGesture)converter.ConvertFrom(context, cultureInfo, value);
Assert.Equal(expected.Modifiers, converted.Modifiers);
Assert.Equal(expected.MouseAction, converted.MouseAction);
}

public static IEnumerable<object?[]> ConvertFrom_ReturnsExpected_Data
{
get
{
// Supported cases (Culture must stay irrelevant, MouseAction/ModifierKeys also do not care)
yield return new object?[] { new MouseGesture(MouseAction.None, ModifierKeys.None), null, CultureInfo.InvariantCulture, string.Empty };
yield return new object?[] { new MouseGesture(MouseAction.LeftClick, ModifierKeys.None), null, new CultureInfo("ru-RU"), "LeftClick" };
yield return new object?[] { new MouseGesture(MouseAction.None, ModifierKeys.Control), null, CultureInfo.InvariantCulture, "Ctrl+" };
yield return new object?[] { new MouseGesture(MouseAction.LeftClick, ModifierKeys.Control), null, CultureInfo.InvariantCulture, "Ctrl+LeftClick" };
yield return new object?[] { new MouseGesture(MouseAction.MiddleDoubleClick, ModifierKeys.Alt), null, new CultureInfo("no-NO"), "Alt+MiddleDoubleClick" };
yield return new object?[] { new MouseGesture(MouseAction.WheelClick, ModifierKeys.Shift), null, CultureInfo.InvariantCulture, "Shift+WheelClick" };
yield return new object?[] { new MouseGesture(MouseAction.LeftDoubleClick, ModifierKeys.Windows), null, CultureInfo.InvariantCulture, "Windows+LeftDoubleClick" };
yield return new object?[] { new MouseGesture(MouseAction.RightClick, ModifierKeys.Control | ModifierKeys.Alt), null, CultureInfo.InvariantCulture, "Ctrl+Alt+RightClick" };
yield return new object?[] { new MouseGesture(MouseAction.RightDoubleClick, ModifierKeys.Control | ModifierKeys.Windows | ModifierKeys.Alt), null, CultureInfo.InvariantCulture, "Ctrl+Alt+Windows+RightDoubleClick" };

// Supported cases (fuzzed)
yield return new object?[] { new MouseGesture(MouseAction.None, ModifierKeys.Alt), null, CultureInfo.InvariantCulture, "Alt+ " };
yield return new object?[] { new MouseGesture(MouseAction.LeftClick, ModifierKeys.None), null, CultureInfo.InvariantCulture, " LeftClick " };
yield return new object?[] { new MouseGesture(MouseAction.None, ModifierKeys.None), null, CultureInfo.InvariantCulture, " " };
yield return new object?[] { new MouseGesture(MouseAction.WheelClick, ModifierKeys.Shift), null, CultureInfo.InvariantCulture, "Shift +WheelClick" };
yield return new object?[] { new MouseGesture(MouseAction.MiddleClick, ModifierKeys.Windows | ModifierKeys.Shift), null, new CultureInfo("no-NO"), " Shift + Windows + MiddleClick " };
yield return new object?[] { new MouseGesture(MouseAction.LeftDoubleClick, ModifierKeys.Windows), null, CultureInfo.InvariantCulture, "Windows+ LeftDoubleClick " };
yield return new object?[] { new MouseGesture(MouseAction.RightClick, ModifierKeys.Control | ModifierKeys.Alt), null, CultureInfo.InvariantCulture, "Ctrl+Alt+ RightClick" };
}
}

[Theory]
[MemberData(nameof(ConvertFrom_ThrowsNotSupportedException_Data))]
public void ConvertFrom_ThrowsNotSupportedException(CultureInfo? cultureInfo, object value)
{
MouseGestureConverter converter = new();

Assert.Throws<NotSupportedException>(() => converter.ConvertFrom(null, cultureInfo, value));
}

public static IEnumerable<object?[]> ConvertFrom_ThrowsNotSupportedException_Data
{
get
{
// Nulls are not supported
yield return new object?[] { CultureInfo.InvariantCulture, null };
// Anything that isn't a string ain't supported
yield return new object?[] { CultureInfo.InvariantCulture, new MouseGesture(MouseAction.LeftClick, ModifierKeys.Control) };
yield return new object?[] { CultureInfo.InvariantCulture, new KeyGesture(Key.V, ModifierKeys.Control) };
yield return new object?[] { CultureInfo.InvariantCulture, ModifierKeys.Control };
yield return new object?[] { CultureInfo.InvariantCulture, MouseAction.LeftDoubleClick };
yield return new object?[] { CultureInfo.InvariantCulture, Key.V };
}
}

[Theory]
[MemberData(nameof(ConvertTo_ReturnsExpected_Data))]
public void ConvertTo_ReturnsExpected(string expected, ITypeDescriptorContext context, CultureInfo? cultureInfo, object? value)
{
MouseGestureConverter converter = new();

// Culture and context must not have any meaning
Assert.Equal(expected, converter.ConvertTo(context, cultureInfo, value, typeof(string)));
}

public static IEnumerable<object?[]> ConvertTo_ReturnsExpected_Data
{
get
{
// Supported null value case that returns string.Empty
yield return new object?[] { string.Empty, null, CultureInfo.InvariantCulture, null };

// Supported cases (Culture must stay irrelevant, MouseAction/ModifierKeys also do not care)
yield return new object?[] { string.Empty, null, CultureInfo.InvariantCulture, new MouseGesture(MouseAction.None, ModifierKeys.None) };
yield return new object?[] { "Alt+", null, CultureInfo.InvariantCulture, new MouseGesture(MouseAction.None, ModifierKeys.Alt) };
yield return new object?[] { "Windows+", null, new CultureInfo("de-DE"), new MouseGesture(MouseAction.None, ModifierKeys.Windows) };
yield return new object?[] { "Shift+", null, new CultureInfo("ru-RU"), new MouseGesture(MouseAction.None, ModifierKeys.Shift) };
yield return new object?[] { "LeftClick", null, CultureInfo.InvariantCulture, new MouseGesture(MouseAction.LeftClick) };
yield return new object?[] { "Ctrl+LeftClick", null, CultureInfo.InvariantCulture, new MouseGesture(MouseAction.LeftClick, ModifierKeys.Control) };
yield return new object?[] { "Alt+RightClick", null, CultureInfo.InvariantCulture, new MouseGesture(MouseAction.RightClick, ModifierKeys.Alt) };
yield return new object?[] { "Windows+WheelClick", null, CultureInfo.InvariantCulture, new MouseGesture(MouseAction.WheelClick, ModifierKeys.Windows) };
yield return new object?[] { "Alt+RightDoubleClick", null, CultureInfo.InvariantCulture, new MouseGesture(MouseAction.RightDoubleClick, ModifierKeys.Alt) };
yield return new object?[] { "Ctrl+Alt+Windows+WheelClick", null, new CultureInfo("de-DE"), new MouseGesture(MouseAction.WheelClick, ModifierKeys.Control | ModifierKeys.Windows | ModifierKeys.Alt) };
yield return new object?[] { "Alt+Windows+MiddleDoubleClick", null, new CultureInfo("ru-RU"), new MouseGesture(MouseAction.MiddleDoubleClick, ModifierKeys.Alt | ModifierKeys.Windows) };
yield return new object?[] { "Ctrl+Alt+Windows+MiddleClick", null, CultureInfo.InvariantCulture, new MouseGesture(MouseAction.MiddleClick, ModifierKeys.Alt | ModifierKeys.Windows | ModifierKeys.Control) };
}
}

[Fact]
public void ConvertTo_ThrowsArgumentNullException()
{
MouseGestureConverter converter = new();

Assert.Throws<ArgumentNullException>(() => converter.ConvertTo(null, CultureInfo.InvariantCulture, new MouseGesture(MouseAction.LeftClick, ModifierKeys.Control), null));
}

[Theory]
[MemberData(nameof(ConvertTo_ThrowsNotSupportedException_Data))]
public void ConvertTo_ThrowsNotSupportedException(object? value, Type? destinationType)
{
MouseGestureConverter converter = new();

Assert.Throws<NotSupportedException>(() => converter.ConvertTo(null, CultureInfo.InvariantCulture, value, destinationType));
}

public static IEnumerable<object?[]> ConvertTo_ThrowsNotSupportedException_Data
{
get
{
// Wrong destination types
yield return new object?[] { new MouseGesture(MouseAction.LeftClick, ModifierKeys.Control), typeof(MouseGesture) };
yield return new object?[] { new MouseGesture(MouseAction.LeftClick, ModifierKeys.Control), typeof(KeyGesture) };
yield return new object?[] { new MouseGesture(MouseAction.LeftClick, ModifierKeys.Control), typeof(MouseAction) };
yield return new object?[] { new MouseGesture(MouseAction.LeftClick, ModifierKeys.Control), typeof(Key) };
yield return new object?[] { new MouseGesture(MouseAction.WheelClick, ModifierKeys.Control), typeof(ModifierKeys) };
// Wrong value types
yield return new object?[] { new KeyGesture(Key.V, ModifierKeys.Control), typeof(string) };
yield return new object?[] { MouseAction.MiddleDoubleClick, typeof(string) };
yield return new object?[] { ModifierKeys.Control, typeof(string) };
yield return new object?[] { Key.V, 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();
}
}

0 comments on commit 928d828

Please sign in to comment.