Skip to content

Commit 085c76e

Browse files
committed
Add more tests, theorize ConvertTo/ConvertFrom (ReturnsExpected)
1 parent 45b8830 commit 085c76e

File tree

1 file changed

+112
-82
lines changed

1 file changed

+112
-82
lines changed

src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/System/Windows/Input/MouseActionConverter.Tests.cs

Lines changed: 112 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,117 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.ComponentModel;
54
using System.ComponentModel.Design.Serialization;
5+
using System.ComponentModel;
6+
using System.Globalization;
67

78
namespace System.Windows.Input;
89

9-
public class MouseActionConverterTests
10+
public sealed class MouseActionConverterTests
1011
{
11-
[Fact]
12-
public void ConvertTo_ConvertFrom_ReturnsExpected()
12+
[Theory]
13+
// Supported type
14+
[InlineData(true, typeof(string))]
15+
// Unsupported types
16+
[InlineData(false, typeof(InstanceDescriptor))]
17+
[InlineData(false, typeof(MouseAction))]
18+
public void CanConvertFrom_ReturnsExpected(bool expected, Type sourceType)
1319
{
1420
MouseActionConverter converter = new();
1521

16-
// Test MouseAction.None (Special case)
17-
string emptyToNone = string.Empty;
18-
MouseAction constantName = MouseAction.None;
22+
Assert.Equal(expected, converter.CanConvertFrom(null, sourceType));
23+
}
1924

20-
MouseAction lowerCase = (MouseAction)converter.ConvertFrom(null, null, emptyToNone.ToLowerInvariant());
21-
MouseAction upperCase = (MouseAction)converter.ConvertFrom(null, null, emptyToNone.ToUpperInvariant());
22-
MouseAction normalColor = (MouseAction)converter.ConvertFrom(null, null, emptyToNone);
25+
[Theory]
26+
[MemberData(nameof(CanConvertTo_Data))]
27+
public void CanConvertTo_ReturnsExpected(bool expected, bool passContext, object? value, Type? destinationType)
28+
{
29+
MouseActionConverter converter = new();
30+
StandardContextImpl context = new() { Instance = value };
2331

24-
Assert.Equal<MouseAction>(constantName, lowerCase);
25-
Assert.Equal<MouseAction>(constantName, upperCase);
26-
Assert.Equal<MouseAction>(constantName, normalColor);
32+
Assert.Equal(expected, converter.CanConvertTo(passContext ? context : null, destinationType));
33+
}
2734

28-
// Test the rest of the enum
29-
foreach (string action in Enum.GetNames<MouseAction>())
35+
public static IEnumerable<object?[]> CanConvertTo_Data
36+
{
37+
get
3038
{
31-
constantName = Enum.Parse<MouseAction>(action);
39+
// Supported cases
40+
yield return new object[] { true, true, MouseAction.None, typeof(string) };
41+
yield return new object[] { true, true, MouseAction.MiddleDoubleClick, typeof(string) };
3242

33-
lowerCase = (MouseAction)converter.ConvertFrom(null, null, action.ToLowerInvariant());
34-
upperCase = (MouseAction)converter.ConvertFrom(null, null, action.ToUpperInvariant());
35-
normalColor = (MouseAction)converter.ConvertFrom(null, null, action);
43+
// Unsupported case (Value is above MouseAction range)
44+
yield return new object[] { false, true, MouseAction.MiddleDoubleClick + 1, typeof(string) };
3645

37-
Assert.Equal<MouseAction>(constantName, lowerCase);
38-
Assert.Equal<MouseAction>(constantName, upperCase);
39-
Assert.Equal<MouseAction>(constantName, normalColor);
46+
// Unsupported cases
47+
yield return new object[] { false, false, MouseAction.None, typeof(string) };
48+
yield return new object[] { false, false, MouseAction.MiddleDoubleClick, typeof(string) };
49+
yield return new object?[] { false, true, null, typeof(MouseAction) };
50+
yield return new object?[] { false, true, null, typeof(string) };
51+
yield return new object?[] { false, false, MouseAction.MiddleDoubleClick, typeof(string) };
52+
yield return new object?[] { false, false, null, typeof(string) };
53+
yield return new object?[] { false, false, null, null };
4054

41-
// Back to the original values
42-
string result = (string)converter.ConvertTo(null, null, constantName, typeof(string));
43-
result = result == string.Empty ? "None" : result; // Test for MouseAction.None (Special case)
44-
Assert.Equal(action, result);
55+
yield return new object[] { false, true, MouseAction.MiddleDoubleClick + 1, typeof(string) };
4556
}
4657
}
4758

4859
[Fact]
49-
public void ConvertTo_ThrowsArgumentNullException()
60+
public void CanConvertTo_ThrowsInvalidCastException()
5061
{
5162
MouseActionConverter converter = new();
63+
StandardContextImpl context = new() { Instance = 10 };
5264

53-
Assert.Throws<ArgumentNullException>(() => converter.ConvertTo(MouseAction.None, destinationType: null!));
65+
// TODO: CanConvert* methods should not throw but the implementation is faulty
66+
Assert.Throws<InvalidCastException>(() => converter.CanConvertTo(context, typeof(string)));
5467
}
5568

5669
[Theory]
57-
[InlineData(null, typeof(string))] // Unsupported value
58-
[InlineData(MouseAction.None, typeof(int))] // Unsupported destinationType
59-
public void ConvertTo_ThrowsNotSupportedException(object? value, Type destinationType)
70+
[MemberData(nameof(ConvertFrom_ReturnsExpected_Data))]
71+
public void ConvertFrom_ReturnsExpected(MouseAction expected, ITypeDescriptorContext context, CultureInfo? cultureInfo, string value)
6072
{
6173
MouseActionConverter converter = new();
6274

63-
Assert.Throws<NotSupportedException>(() => converter.ConvertTo(value, destinationType));
75+
Assert.Equal(expected, (MouseAction)converter.ConvertFrom(context, cultureInfo, value));
6476
}
6577

66-
[Fact]
67-
public void ConvertTo_ThrowsInvalidCastException()
78+
public static IEnumerable<object?[]> ConvertFrom_ReturnsExpected_Data
6879
{
69-
MouseActionConverter converter = new();
70-
71-
Assert.Throws<InvalidCastException>(() => converter.ConvertTo(null, null, (int)(MouseAction.MiddleDoubleClick), typeof(string)));
72-
}
73-
74-
[Fact]
75-
public void ConvertTo_ThrowsInvalidEnumArgumentException()
76-
{
77-
MouseActionConverter converter = new();
78-
79-
Assert.Throws<InvalidEnumArgumentException>(() => converter.ConvertTo(null, null, (MouseAction)(MouseAction.MiddleDoubleClick + 1), typeof(string)));
80+
get
81+
{
82+
// ConvertTo handles two different inputs as MouseAction.None
83+
yield return new object?[] { MouseAction.None, null, CultureInfo.InvariantCulture, string.Empty };
84+
yield return new object?[] { MouseAction.None, null, CultureInfo.InvariantCulture, "None" };
85+
86+
// Supported cases (Culture must stay irrelevant)
87+
yield return new object?[] { MouseAction.None, null, CultureInfo.InvariantCulture, string.Empty };
88+
yield return new object?[] { MouseAction.LeftClick, null, new CultureInfo("ru-RU"), "LeftClick" };
89+
yield return new object?[] { MouseAction.RightClick, null, CultureInfo.InvariantCulture, "RightClick" };
90+
yield return new object?[] { MouseAction.MiddleClick, null, CultureInfo.InvariantCulture, "MiddleClick" };
91+
yield return new object?[] { MouseAction.WheelClick, null, new CultureInfo("no-NO"), "WheelClick" };
92+
yield return new object?[] { MouseAction.LeftDoubleClick, null, CultureInfo.InvariantCulture, "LeftDoubleClick" };
93+
yield return new object?[] { MouseAction.RightDoubleClick, null, CultureInfo.InvariantCulture, "RightDoubleClick" };
94+
yield return new object?[] { MouseAction.MiddleDoubleClick, null, CultureInfo.InvariantCulture, "MiddleDoubleClick" };
95+
96+
// Supported cases (fuzzed via whitespace and casing)
97+
yield return new object?[] { MouseAction.None, null, CultureInfo.InvariantCulture, " " };
98+
yield return new object?[] { MouseAction.None, null, new CultureInfo("ru-RU"), " NoNE " };
99+
yield return new object?[] { MouseAction.LeftClick, null, CultureInfo.InvariantCulture, " LeFTCliCK " };
100+
yield return new object?[] { MouseAction.WheelClick, null, CultureInfo.InvariantCulture, " WHEELCLICK" };
101+
yield return new object?[] { MouseAction.MiddleClick, null, new CultureInfo("no-NO"), " MiDDLeCliCK " };
102+
yield return new object?[] { MouseAction.LeftDoubleClick, null, CultureInfo.InvariantCulture, " leftdoubleclick " };
103+
yield return new object?[] { MouseAction.RightClick, null, CultureInfo.InvariantCulture, " rightclick" };
104+
}
80105
}
81106

82107
[Theory]
83108
// Unsupported values (data type)
84109
[InlineData(null)]
110+
[InlineData(Key.VolumeDown)]
85111
[InlineData(MouseAction.None)]
86112
// Unsupported value (bad string)
87113
[InlineData("BadString")]
114+
[InlineData("MouseZClick")]
88115
public void ConvertFrom_ThrowsNotSupportedException(object? value)
89116
{
90117
MouseActionConverter converter = new();
@@ -93,64 +120,67 @@ public void ConvertFrom_ThrowsNotSupportedException(object? value)
93120
}
94121

95122
[Theory]
96-
// Supported type
97-
[InlineData(true, typeof(string))]
98-
// Unsupported types
99-
[InlineData(false, typeof(InstanceDescriptor))]
100-
[InlineData(false, typeof(MouseAction))]
101-
public void CanConvertFrom_ReturnsExpected(bool expected, Type sourceType)
123+
[MemberData(nameof(ConvertTo_ReturnsExpected_Data))]
124+
public void ConvertTo_ReturnsExpected(string expected, ITypeDescriptorContext context, CultureInfo? cultureInfo, object? value)
102125
{
103126
MouseActionConverter converter = new();
104127

105-
Assert.Equal(expected, converter.CanConvertFrom(null, sourceType));
128+
// Culture and context must not have any meaning
129+
Assert.Equal(expected, (string)converter.ConvertTo(context, cultureInfo, value, typeof(string)));
130+
}
131+
132+
public static IEnumerable<object?[]> ConvertTo_ReturnsExpected_Data
133+
{
134+
get
135+
{
136+
// Supported cases (Culture must stay irrelevant)
137+
yield return new object?[] { string.Empty, null, CultureInfo.InvariantCulture, MouseAction.None };
138+
yield return new object?[] { "LeftClick", null, CultureInfo.InvariantCulture, MouseAction.LeftClick };
139+
yield return new object?[] { "RightClick", null, new CultureInfo("ru-RU"), MouseAction.RightClick };
140+
yield return new object?[] { "MiddleClick", null, CultureInfo.InvariantCulture, MouseAction.MiddleClick };
141+
yield return new object?[] { "WheelClick", null, new CultureInfo("no-NO"), MouseAction.WheelClick };
142+
yield return new object?[] { "LeftDoubleClick", null, CultureInfo.InvariantCulture, MouseAction.LeftDoubleClick };
143+
yield return new object?[] { "RightDoubleClick", null, null, MouseAction.RightDoubleClick };
144+
yield return new object?[] { "MiddleDoubleClick", null, null, MouseAction.MiddleDoubleClick };
145+
}
106146
}
107147

108148
[Fact]
109-
public void CanConvertTo_ThrowsInvalidCastException()
149+
public void ConvertTo_ThrowsArgumentNullException()
110150
{
111151
MouseActionConverter converter = new();
112-
StandardContextImpl context = new();
113-
context.Instance = 10;
114152

115-
// NOTE: CanConvert* methods should not throw but the implementation is faulty
116-
Assert.Throws<InvalidCastException>(() => converter.CanConvertTo(context, typeof(string)));
153+
Assert.Throws<ArgumentNullException>(() => converter.ConvertTo(MouseAction.None, destinationType: null!));
117154
}
118155

119156
[Theory]
120-
[MemberData(nameof(CanConvertTo_Data))]
121-
public void CanConvertTo_ReturnsExpected(bool expected, bool passContext, object? value, Type? destinationType)
157+
// Unsupported value
158+
[InlineData(null, typeof(string))]
159+
// Unsupported destinationType
160+
[InlineData(MouseAction.None, typeof(int))]
161+
[InlineData(MouseAction.LeftClick, typeof(byte))]
162+
public void ConvertTo_ThrowsNotSupportedException(object? value, Type destinationType)
122163
{
123164
MouseActionConverter converter = new();
124-
StandardContextImpl context = new()
125-
{
126-
Instance = value
127-
};
128165

129-
Assert.Equal(expected, converter.CanConvertTo(passContext ? context : null, destinationType));
166+
Assert.Throws<NotSupportedException>(() => converter.ConvertTo(value, destinationType));
130167
}
131168

132-
public static IEnumerable<object?[]> CanConvertTo_Data
169+
[Fact]
170+
public void ConvertTo_ThrowsInvalidCastException()
133171
{
134-
get
135-
{
136-
// Supported cases
137-
yield return new object[] { true, true, MouseAction.None, typeof(string) };
138-
yield return new object[] { true, true, MouseAction.MiddleDoubleClick, typeof(string) };
172+
MouseActionConverter converter = new();
139173

140-
// Unsupported case (Value is above MouseAction range)
141-
yield return new object[] { false, true, MouseAction.MiddleDoubleClick + 1, typeof(string) };
174+
// TODO: This should not throw InvalidCastException but NotSupportedException
175+
Assert.Throws<InvalidCastException>(() => converter.ConvertTo(null, null, (int)(MouseAction.MiddleDoubleClick), typeof(string)));
176+
}
142177

143-
// Unsupported cases
144-
yield return new object[] { false, false, MouseAction.None, typeof(string) };
145-
yield return new object[] { false, false, MouseAction.MiddleDoubleClick, typeof(string) };
146-
yield return new object?[] { false, true, null, typeof(MouseAction) };
147-
yield return new object?[] { false, true, null, typeof(string) };
148-
yield return new object?[] { false, false, MouseAction.MiddleDoubleClick, typeof(string) };
149-
yield return new object?[] { false, false, null, typeof(string) };
150-
yield return new object?[] { false, false, null, null };
178+
[Fact]
179+
public void ConvertTo_ThrowsInvalidEnumArgumentException()
180+
{
181+
MouseActionConverter converter = new();
151182

152-
yield return new object[] { false, true, MouseAction.MiddleDoubleClick + 1, typeof(string) };
153-
}
183+
Assert.Throws<InvalidEnumArgumentException>(() => converter.ConvertTo(null, null, (MouseAction)(MouseAction.MiddleDoubleClick + 1), typeof(string)));
154184
}
155185

156186
public sealed class StandardContextImpl : ITypeDescriptorContext

0 commit comments

Comments
 (0)