Skip to content

Commit ffe6bc0

Browse files
committed
Convert string to Key
1 parent cf4a268 commit ffe6bc0

File tree

4 files changed

+151
-13
lines changed

4 files changed

+151
-13
lines changed

src/bunit.web/EventDispatchExtensions/Key.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,15 @@ static bool IsSuitableForCombination(Key key)
531531
/// <returns><c>True</c> if the instances of Key are equal; otherwise, <c>false</c>.</returns>
532532
public static bool operator ==(Key? x, Key? y)
533533
{
534-
if (object.ReferenceEquals(x, y))
534+
if (x is null && y is null)
535+
{
536+
return true;
537+
}
538+
else if (x is null || y is null)
539+
{
540+
return false;
541+
}
542+
else if (object.ReferenceEquals(x, y))
535543
{
536544
return true;
537545
}
@@ -557,6 +565,7 @@ static bool IsSuitableForCombination(Key key)
557565
[return: NotNullIfNotNull("x")]
558566
[return: NotNullIfNotNull("y")]
559567
[SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Alternative method is named " + nameof(Combine))]
568+
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", Justification = "False warning is caused by bug in Roslyn analyzer")]
560569
public static Key operator +(Key x, Key? y)
561570
{
562571
if (x is not null)
@@ -577,6 +586,16 @@ static bool IsSuitableForCombination(Key key)
577586
}
578587
}
579588

589+
/// <summary>
590+
/// Gets a new <see cref="Key" /> instance with value of string object.
591+
/// </summary>
592+
/// <param name="value">The string value to convert to Key instance.</param>
593+
/// <returns>The Key instance with the specified value.</returns>
594+
// It would make sense to convert null and "" to null Key instead of throwing ArgumentNullException,
595+
// but this would force consumers to use ! operator to enforce not-null value.
596+
[SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Alternative method is named " + nameof(Get))]
597+
public static implicit operator Key(string value) => Key.Get(value);
598+
580599
/// <summary>
581600
/// Gets a new <see cref="Key" /> instance with value of character.
582601
/// </summary>

src/bunit.web/EventDispatchExtensions/KeyboardEventDispatchExtensions.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,15 @@ public static void KeyDown(this IElement element, string key, string? code = def
4949
/// </summary>
5050
/// <param name="element">The element to raise the event on.</param>
5151
/// <param name="key">The keyboard key to pass to the event handler.</param>
52-
public static void KeyDown(this IElement element, Key key) => _ = KeyDownAsync(element, key);
52+
/// <param name="repeat"><c>true</c> if a key has been depressed long enough to trigger key repetition, otherwise <c>false</c>.</param>
53+
/// <param name="type">The type of the event.</param>
54+
public static void KeyDown(this IElement element, Key key, bool repeat = default, string? type = default)
55+
{
56+
KeyboardEventArgs eventArgs = key;
57+
eventArgs.Repeat = repeat;
58+
eventArgs.Type = type!; // Type property missing annotation
59+
KeyDownAsync(element, eventArgs);
60+
}
5361

5462
/// <summary>
5563
/// Raises the <c>@onkeydown</c> event on <paramref name="element"/>, passing the provided <paramref name="eventArgs"/>
@@ -100,7 +108,15 @@ public static void KeyUp(this IElement element, string key, string? code = defau
100108
/// </summary>
101109
/// <param name="element">The element to raise the event on.</param>
102110
/// <param name="key">The keyboard key to pass to the event handler.</param>
103-
public static void KeyUp(this IElement element, Key key) => _ = KeyUpAsync(element, key);
111+
/// <param name="repeat"><c>true</c> if a key has been depressed long enough to trigger key repetition, otherwise <c>false</c>.</param>
112+
/// <param name="type">The type of the event.</param>
113+
public static void KeyUp(this IElement element, Key key, bool repeat = default, string? type = default)
114+
{
115+
KeyboardEventArgs eventArgs = key;
116+
eventArgs.Repeat = repeat;
117+
eventArgs.Type = type!; // Type property missing annotation
118+
KeyUpAsync(element, eventArgs);
119+
}
104120

105121
/// <summary>
106122
/// Raises the <c>@onkeyup</c> event on <paramref name="element"/>, passing the provided <paramref name="eventArgs"/>
@@ -151,7 +167,15 @@ public static void KeyPress(this IElement element, string key, string? code = de
151167
/// </summary>
152168
/// <param name="element">The element to raise the event on.</param>
153169
/// <param name="key">The keyboard key to pass to the event handler.</param>
154-
public static void KeyPress(this IElement element, Key key) => _ = KeyPressAsync(element, key);
170+
/// <param name="repeat"><c>true</c> if a key has been depressed long enough to trigger key repetition, otherwise <c>false</c>.</param>
171+
/// <param name="type">The type of the event.</param>
172+
public static void KeyPress(this IElement element, Key key, bool repeat = default, string? type = default)
173+
{
174+
KeyboardEventArgs eventArgs = key;
175+
eventArgs.Repeat = repeat;
176+
eventArgs.Type = type!; // Type property missing annotation
177+
KeyPressAsync(element, eventArgs);
178+
}
155179

156180
/// <summary>
157181
/// Raises the <c>@onkeypress</c> event on <paramref name="element"/>, passing the provided <paramref name="eventArgs"/>

tests/bunit.web.tests/EventDispatchExtensions/KeyTest.cs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ namespace Bunit
1212
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", Justification = "Arguments are provided from test data")]
1313
public class KeyTest
1414
{
15+
public static IEnumerable<object[]> KeyValueTestData { get; } = GetKeyValueTestData().Select(c => new object[] { c }).ToList();
16+
1517
public static IEnumerable<object[]> CharTestData { get; } = new[] { ' ', 'x', 'A', '2', '0', '&', (char)0 }
1618
.Select(c => new object[] { c }).ToList();
1719

@@ -34,15 +36,7 @@ public class KeyTest
3436
public static IEnumerable<object[]> KeyboardEventArgsTestData { get; } = GetKeyboardEventArgsTestData();
3537

3638
[Theory(DisplayName = "Get method with value parameter should return initialized Key object")]
37-
[InlineData(" ")]
38-
[InlineData("x")]
39-
[InlineData("A")]
40-
[InlineData("2")]
41-
[InlineData("0")]
42-
[InlineData("&")]
43-
[InlineData("Key")]
44-
[InlineData("TEST_test$44")]
45-
[InlineData("F5")]
39+
[MemberData(nameof(KeyValueTestData))]
4640
public void GetWithValue(string value)
4741
{
4842
var key = Key.Get(value);
@@ -62,6 +56,30 @@ public void GetWithNullValue(string value)
6256
Should.Throw<ArgumentNullException>(() => Key.Get(value));
6357
}
6458

59+
[Theory(DisplayName = "Casting from string should return initialized Key object")]
60+
[MemberData(nameof(KeyValueTestData))]
61+
public void CanCastFromString(string value)
62+
{
63+
Key key = value;
64+
key.Value.ShouldBe(value);
65+
key.Code.ShouldBe(value);
66+
key.ControlKey.ShouldBeFalse();
67+
key.ShiftKey.ShouldBeFalse();
68+
key.AltKey.ShouldBeFalse();
69+
key.CommandKey.ShouldBeFalse();
70+
}
71+
72+
[Theory(DisplayName = "Custing from null or empty string throws ArgumentNullException")]
73+
[InlineData(null)]
74+
[InlineData("")]
75+
public void CastingFromNullStringThrowsException(string value)
76+
{
77+
Should.Throw<ArgumentNullException>(() =>
78+
{
79+
Key key = value;
80+
});
81+
}
82+
6583
[Theory(DisplayName = "Get method with value and code parameters should return initialized Key object")]
6684
[InlineData(" ", " ")]
6785
[InlineData("x", "x")]
@@ -333,6 +351,22 @@ public void NullToKeyboardEventArgs()
333351
result.ShouldBeNull();
334352
}
335353

354+
private static IEnumerable<string> GetKeyValueTestData()
355+
{
356+
return new[]
357+
{
358+
" ",
359+
"x",
360+
"A",
361+
"2",
362+
"0",
363+
"&",
364+
"Key",
365+
"TEST_test$44",
366+
"F5"
367+
};
368+
}
369+
336370
private static IEnumerable<ValueTuple<Key, Key>> GetEqualsTestData()
337371
{
338372
var xKey = Key.Get('x');

tests/bunit.web.tests/EventDispatchExtensions/KeyboardEventDispatchExtensionsTest.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,26 @@ public void CanRaiseKeyDownWithAKey()
6868
spy.RaisedEvent.ShouldBeEquivalentTo(expected);
6969
}
7070

71+
[Fact(DisplayName = "KeyDown event is raised correctly through helper specifying repeat and type")]
72+
public void CanRaiseKeyDownWithRepeatAndType()
73+
{
74+
var spy = CreateTriggerSpy(ElementName, "onkeydown");
75+
spy.Trigger(element =>
76+
{
77+
element.KeyDown(Key.Up + Key.Command, true, "Test Down");
78+
});
79+
80+
var expected = new KeyboardEventArgs
81+
{
82+
Key = "ArrowUp",
83+
Code = "ArrowUp",
84+
MetaKey = true,
85+
Repeat = true,
86+
Type = "Test Down"
87+
};
88+
spy.RaisedEvent.ShouldBeEquivalentTo(expected);
89+
}
90+
7191
[Fact(DisplayName = "KeyUp event is raised correctly through helper using special key")]
7292
public void CanRaiseKeyUpWithShiftSpace()
7393
{
@@ -105,6 +125,27 @@ public void CanRaiseKeyUpWithBKey()
105125
spy.RaisedEvent.ShouldBeEquivalentTo(expected);
106126
}
107127

128+
[Fact(DisplayName = "KeyUp event is raised correctly through helper specifying repeat and type")]
129+
public void CanRaiseKeyUpWithWithRepeatAndType()
130+
{
131+
var spy = CreateTriggerSpy(ElementName, "onkeyup");
132+
spy.Trigger(element =>
133+
{
134+
element.KeyUp(Key.Down + Key.Shift + Key.Command, true, "Test Up");
135+
});
136+
137+
var expected = new KeyboardEventArgs
138+
{
139+
Key = "ArrowDown",
140+
Code = "ArrowDown",
141+
ShiftKey = true,
142+
MetaKey = true,
143+
Repeat = true,
144+
Type = "Test Up"
145+
};
146+
spy.RaisedEvent.ShouldBeEquivalentTo(expected);
147+
}
148+
108149
[Fact(DisplayName = "KeyPress event is raised correctly through helper using special key")]
109150
public void CanRaiseKeyPressWithNum8Key()
110151
{
@@ -138,5 +179,25 @@ public void CanRaiseKeyPressWith8Key()
138179
};
139180
spy.RaisedEvent.ShouldBeEquivalentTo(expected);
140181
}
182+
183+
[Fact(DisplayName = "KeyPress event is raised correctly through specifying repeat and type")]
184+
public void CanRaiseKeyPressWithRepeatAndType()
185+
{
186+
var spy = CreateTriggerSpy(ElementName, "onkeypress");
187+
spy.Trigger(element =>
188+
{
189+
element.KeyPress(Key.Shift + "P", true, "Press Test");
190+
});
191+
192+
var expected = new KeyboardEventArgs
193+
{
194+
Key = "P",
195+
Code = "P",
196+
ShiftKey = true,
197+
Repeat = true,
198+
Type = "Press Test"
199+
};
200+
spy.RaisedEvent.ShouldBeEquivalentTo(expected);
201+
}
141202
}
142203
}

0 commit comments

Comments
 (0)