A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System.Collections.Generic;
5using System.Linq;
6using NUnit.Framework;
7using osu.Framework.Input;
8using osu.Framework.Testing;
9using osuTK;
10using osuTK.Input;
11
12namespace osu.Framework.Tests.Visual.UserInterface
13{
14 public class TestSceneTextBoxEvents : ManualInputManagerTestScene
15 {
16 private EventQueuesTextBox textBox;
17
18 private const string default_text = "some default text";
19
20 [SetUpSteps]
21 public void SetUpSteps()
22 {
23 AddStep("add textbox", () => Child = textBox = new EventQueuesTextBox
24 {
25 CommitOnFocusLost = true,
26 ReleaseFocusOnCommit = false,
27 Size = new Vector2(200, 40),
28 Text = default_text,
29 });
30
31 AddStep("focus textbox", () =>
32 {
33 InputManager.MoveMouseTo(textBox);
34 InputManager.Click(MouseButton.Left);
35 });
36
37 AddStep("move caret to end", () => InputManager.Keys(PlatformAction.MoveForwardLine));
38 AddStep("dequeue caret event", () => textBox.CaretMovedQueue.Dequeue());
39 }
40
41 [Test]
42 public void TestCommitIsNewTextSecondTime()
43 {
44 AddStep("add handler to reset on commit", () => textBox.OnCommit += (sender, isNew) =>
45 {
46 if (!isNew)
47 return;
48
49 textBox.Text = default_text;
50 });
51
52 AddStep("insert text", () => textBox.InsertString("temporary text"));
53 AddStep("press enter key for committing text", () => InputManager.Key(Key.Enter));
54 AddAssert("text committed event raised with new", () => textBox.CommittedTextQueue.Dequeue());
55 AddAssert("text is restored to default by event", () => textBox.Text == default_text);
56
57 AddStep("insert text", () => textBox.InsertString("temporary text"));
58 AddStep("press enter key for committing text", () => InputManager.Key(Key.Enter));
59 AddAssert("text committed event raised with new", () => textBox.CommittedTextQueue.Dequeue());
60 AddAssert("text is restored to default by event", () => textBox.Text == default_text);
61 }
62
63 [Test]
64 public void TestMutatingTextPropertyDoesntInvokeEvent()
65 {
66 AddStep("set text property once more", () => textBox.Text = "set property once more");
67 AddStep("insert string via protected method", () => textBox.InsertString(" inserted string."));
68 AddAssert("no user text consumed event", () => textBox.UserConsumedTextQueue.Count == 0);
69 }
70
71 [Test]
72 [Ignore("not possible to test yet for attached reason.")]
73 public void TestInsertingUserTextInvokesEvent()
74 {
75 // todo: this is not straightforward to test at the moment (requires manipulating ITextInputSource, which is stored at host level), steps commented for now.
76 //AddStep("press letter key to insert text", () => addToPendingTextInput());
77 //AddAssert("user text consumed event", () => textBox.UserConsumedTextQueue.Dequeue() == "W" && textBox.UserConsumedTextQueue.Count == 0);
78 }
79
80 [Test]
81 public void TestDeletingPrevCharActionInvokesEvent()
82 {
83 string lastText = null;
84
85 AddStep("invoke delete action to remove text", () =>
86 {
87 lastText = textBox.Text;
88 InputManager.Keys(PlatformAction.DeleteBackwardChar);
89 });
90 AddAssert("user text removed event raised", () => textBox.UserRemovedTextQueue.Dequeue() == lastText.Last().ToString() && textBox.UserRemovedTextQueue.Count == 0);
91 }
92
93 [Test]
94 public void TestCommittingTextInvokesEvents()
95 {
96 AddStep("insert text", () => textBox.InsertString(" with another"));
97 AddStep("press enter key for committing text", () => InputManager.Key(Key.Enter));
98
99 AddAssert("text committed event raised", () =>
100 // Ensure dequeued text commit event has textChanged = true.
101 textBox.CommittedTextQueue.Dequeue() && textBox.CommittedTextQueue.Count == 0);
102
103 AddStep("click away", () =>
104 {
105 InputManager.MoveMouseTo(textBox.ScreenSpaceDrawQuad.BottomRight + Vector2.One * 20);
106 InputManager.Click(MouseButton.Left);
107 });
108
109 AddAssert("text committed event raised", () =>
110 // Ensure dequeued text commit event has textChanged = false.
111 textBox.CommittedTextQueue.Dequeue() == false && textBox.CommittedTextQueue.Count == 0);
112 }
113
114 [Test]
115 public void TestMovingOrExpandingSelectionInvokesEvent()
116 {
117 AddStep("invoke move action to move caret", () => InputManager.Keys(PlatformAction.MoveBackwardLine));
118 AddAssert("caret moved event", () =>
119 // Ensure dequeued caret move event has selecting = false.
120 textBox.CaretMovedQueue.Dequeue() == false && textBox.CommittedTextQueue.Count == 0);
121
122 AddStep("invoke select action to expand selection", () => InputManager.Keys(PlatformAction.SelectForwardChar));
123 AddAssert("caret moved event", () =>
124 // Ensure dequeued caret move event has selecting = true.
125 textBox.CaretMovedQueue.Dequeue() && textBox.CommittedTextQueue.Count == 0);
126 }
127
128 [TearDownSteps]
129 public void TearDownSteps()
130 {
131 AddAssert("all event queues emptied", () => textBox.UserConsumedTextQueue.Count == 0 &&
132 textBox.UserRemovedTextQueue.Count == 0 &&
133 textBox.CommittedTextQueue.Count == 0 &&
134 textBox.CaretMovedQueue.Count == 0);
135 }
136
137 private class EventQueuesTextBox : TestSceneTextBox.InsertableTextBox
138 {
139 public readonly Queue<string> UserConsumedTextQueue = new Queue<string>();
140 public readonly Queue<string> UserRemovedTextQueue = new Queue<string>();
141 public readonly Queue<bool> CommittedTextQueue = new Queue<bool>();
142 public readonly Queue<bool> CaretMovedQueue = new Queue<bool>();
143
144 protected override void OnUserTextAdded(string consumed) => UserConsumedTextQueue.Enqueue(consumed);
145 protected override void OnUserTextRemoved(string removed) => UserRemovedTextQueue.Enqueue(removed);
146 protected override void OnTextCommitted(bool textChanged) => CommittedTextQueue.Enqueue(textChanged);
147 protected override void OnCaretMoved(bool selecting) => CaretMovedQueue.Enqueue(selecting);
148 }
149 }
150}