forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathManualTests.cs
375 lines (332 loc) · 15.5 KB
/
ManualTests.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Xunit;
namespace System
{
public class ConsoleManualTests
{
public static bool ManualTestsEnabled => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MANUAL_TESTS"));
[ConditionalTheory(nameof(ManualTestsEnabled))]
[InlineData(false)]
[InlineData(true)]
public static void ReadLine(bool consoleIn)
{
string expectedLine = $"This is a test of Console.{(consoleIn ? "In." : "")}ReadLine.";
Console.WriteLine($"Please type the sentence (without the quotes): \"{expectedLine}\"");
string result = consoleIn ? Console.In.ReadLine() : Console.ReadLine();
Assert.Equal(expectedLine, result);
AssertUserExpectedResults("the characters you typed properly echoed as you typed");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void ReadLineFromOpenStandardInput()
{
string expectedLine = "aab";
// Use Console.ReadLine
Console.WriteLine($"Please type 'a' 3 times, press 'Backspace' to erase 1, then type a single 'b' and press 'Enter'.");
string result = Console.ReadLine();
Assert.Equal(expectedLine, result);
AssertUserExpectedResults("the characters you typed properly echoed as you typed");
// ReadLine from Console.OpenStandardInput
Console.WriteLine($"Please type 'a' 3 times, press 'Backspace' to erase 1, then type a single 'b' and press 'Enter'.");
using Stream inputStream = Console.OpenStandardInput();
using StreamReader reader = new StreamReader(inputStream);
result = reader.ReadLine();
Assert.Equal(expectedLine, result);
AssertUserExpectedResults("the characters you typed properly echoed as you typed");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void ReadFromOpenStandardInput()
{
// The implementation in StdInReader uses a StringBuilder for caching. We want this builder to use
// multiple chunks. So the expectedLine is longer than 16 characters (StringBuilder.DefaultCapacity).
string expectedLine = $"This is a test for ReadFromOpenStandardInput.";
Assert.True(expectedLine.Length > new StringBuilder().Capacity);
Console.WriteLine($"Please type the sentence (without the quotes): \"{expectedLine}\"");
using Stream inputStream = Console.OpenStandardInput();
for (int i = 0; i < expectedLine.Length; i++)
{
Assert.Equal((byte)expectedLine[i], inputStream.ReadByte());
}
Assert.Equal((byte)'\n', inputStream.ReadByte());
AssertUserExpectedResults("the characters you typed properly echoed as you typed");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void ConsoleReadSupportsBackspace()
{
const string expectedLine = "aab\r";
Console.WriteLine($"Please type 'a' 3 times, press 'Backspace' to erase 1, then type a single 'b' and press 'Enter'.");
foreach (char c in expectedLine)
{
Assert.Equal((int)c, Console.Read());
}
AssertUserExpectedResults("the characters you typed properly echoed as you typed");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void ReadLine_BackSpaceCanMoveAcrossWrappedLines()
{
Console.WriteLine("Please press 'a' until it wraps to the next terminal line, then press 'Backspace' until the input is erased, and then type a single 'a' and press 'Enter'.");
Console.Write("Input: ");
Console.Out.Flush();
string result = Console.ReadLine();
Assert.Equal("a", result);
AssertUserExpectedResults("the previous line is 'Input: a'");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/40735", TestPlatforms.Windows)]
public static void InPeek()
{
Console.WriteLine("Please type \"peek\" (without the quotes). You should see it as you type:");
foreach (char c in new[] { 'p', 'e', 'e', 'k' })
{
Assert.Equal(c, Console.In.Peek());
Assert.Equal(c, Console.In.Peek());
Assert.Equal(c, Console.In.Read());
}
Console.In.ReadLine(); // enter
AssertUserExpectedResults("the characters you typed properly echoed as you typed");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void Beep()
{
Console.Beep();
AssertUserExpectedResults("hear a beep");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void ReadKey()
{
Console.WriteLine("Please type \"console\" (without the quotes). You shouldn't see it as you type:");
foreach (ConsoleKey k in new[] { ConsoleKey.C, ConsoleKey.O, ConsoleKey.N, ConsoleKey.S, ConsoleKey.O, ConsoleKey.L, ConsoleKey.E })
{
Assert.Equal(k, Console.ReadKey(intercept: true).Key);
}
AssertUserExpectedResults("\"console\" correctly not echoed as you typed it");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void ReadKeyNoIntercept()
{
Console.WriteLine("Please type \"console\" (without the quotes). You should see it as you type:");
foreach (ConsoleKey k in new[] { ConsoleKey.C, ConsoleKey.O, ConsoleKey.N, ConsoleKey.S, ConsoleKey.O, ConsoleKey.L, ConsoleKey.E })
{
Assert.Equal(k, Console.ReadKey(intercept: false).Key);
}
AssertUserExpectedResults("\"console\" correctly echoed as you typed it");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void EnterKeyIsEnterAfterKeyAvailableCheck()
{
Console.WriteLine("Please hold down the 'Enter' key for some time. You shouldn't see new lines appear:");
int keysRead = 0;
while (keysRead < 50)
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo keyInfo = Console.ReadKey(true);
Assert.Equal(ConsoleKey.Enter, keyInfo.Key);
keysRead++;
}
}
while (Console.KeyAvailable)
{
ConsoleKeyInfo keyInfo = Console.ReadKey(true);
Assert.Equal(ConsoleKey.Enter, keyInfo.Key);
}
AssertUserExpectedResults("no empty newlines appear");
}
[ConditionalTheory(nameof(ManualTestsEnabled))]
[MemberData(nameof(GetKeyChords))]
public static void ReadKey_KeyChords(string requestedKeyChord, ConsoleKeyInfo expected)
{
Console.Write($"Please type key chord {requestedKeyChord}: ");
var actual = Console.ReadKey(intercept: true);
Console.WriteLine();
Assert.Equal(expected.Key, actual.Key);
Assert.Equal(expected.Modifiers, actual.Modifiers);
Assert.Equal(expected.KeyChar, actual.KeyChar);
}
public static IEnumerable<object[]> GetKeyChords()
{
yield return MkConsoleKeyInfo("Ctrl+B", '\x02', ConsoleKey.B, ConsoleModifiers.Control);
yield return MkConsoleKeyInfo("Ctrl+Alt+B", OperatingSystem.IsWindows() ? '\x00' : '\x02', ConsoleKey.B, ConsoleModifiers.Control | ConsoleModifiers.Alt);
yield return MkConsoleKeyInfo("Enter", '\r', ConsoleKey.Enter, default);
if (OperatingSystem.IsWindows())
{
yield return MkConsoleKeyInfo("Ctrl+J", '\n', ConsoleKey.J, ConsoleModifiers.Control);
}
else
{
// Validate current Unix console behaviour: '\n' is reported as '\r'
yield return MkConsoleKeyInfo("Ctrl+J", '\r', ConsoleKey.Enter, default);
}
static object[] MkConsoleKeyInfo (string requestedKeyChord, char keyChar, ConsoleKey consoleKey, ConsoleModifiers modifiers)
{
return new object[]
{
requestedKeyChord,
new ConsoleKeyInfo(keyChar, consoleKey,
control: modifiers.HasFlag(ConsoleModifiers.Control),
alt: modifiers.HasFlag(ConsoleModifiers.Alt),
shift: modifiers.HasFlag(ConsoleModifiers.Shift))
};
}
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void ConsoleOutWriteLine()
{
Console.Out.WriteLine("abcdefghijklmnopqrstuvwxyz");
AssertUserExpectedResults("the alphabet above");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void KeyAvailable()
{
Console.WriteLine("Wait a few seconds, then press any key...");
while (Console.KeyAvailable)
{
Console.ReadKey();
}
while (!Console.KeyAvailable)
{
Task.Delay(500).Wait();
Console.WriteLine("\t...waiting...");
}
Console.ReadKey();
AssertUserExpectedResults("several wait messages get printed out");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void Clear()
{
Console.Clear();
AssertUserExpectedResults("the screen get cleared");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void Colors()
{
const int squareSize = 20;
var colors = new[] { ConsoleColor.Red, ConsoleColor.Green, ConsoleColor.Blue, ConsoleColor.Yellow };
for (int row = 0; row < 2; row++)
{
for (int i = 0; i < squareSize / 2; i++)
{
Console.WriteLine();
Console.Write(" ");
for (int col = 0; col < 2; col++)
{
Console.BackgroundColor = colors[row * 2 + col];
Console.ForegroundColor = colors[row * 2 + col];
for (int j = 0; j < squareSize; j++) Console.Write('@');
Console.ResetColor();
}
}
}
Console.WriteLine();
AssertUserExpectedResults("a Microsoft flag in solid color");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void CursorPositionAndArrowKeys()
{
Console.WriteLine("Use the up, down, left, and right arrow keys to move around. When done, press enter.");
while (true)
{
ConsoleKeyInfo k = Console.ReadKey(intercept: true);
if (k.Key == ConsoleKey.Enter)
{
break;
}
int left = Console.CursorLeft, top = Console.CursorTop;
switch (k.Key)
{
case ConsoleKey.UpArrow:
if (top > 0) Console.CursorTop = top - 1;
break;
case ConsoleKey.LeftArrow:
if (left > 0) Console.CursorLeft = left - 1;
break;
case ConsoleKey.RightArrow:
Console.CursorLeft = left + 1;
break;
case ConsoleKey.DownArrow:
Console.CursorTop = top + 1;
break;
}
}
AssertUserExpectedResults("the arrow keys move around the screen as expected with no other bad artifacts");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
[PlatformSpecific(TestPlatforms.AnyUnix)] // .NET echo handling is Unix specific.
public static void EchoWorksDuringAndAfterProcessThatUsesTerminal()
{
Console.WriteLine($"Please type \"test\" without the quotes and press Enter.");
string line = Console.ReadLine();
Assert.Equal("test", line);
AssertUserExpectedResults("the characters you typed properly echoed as you typed");
Console.WriteLine($"Now type \"test\" without the quotes and press Ctrl+D twice.");
using Process p = Process.Start(new ProcessStartInfo
{
FileName = "cat",
RedirectStandardOutput = true,
});
string stdout = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Assert.Equal("test", stdout);
Console.WriteLine();
AssertUserExpectedResults("the characters you typed properly echoed as you typed");
Console.WriteLine($"Please type \"test\" without the quotes and press Enter.");
line = Console.ReadLine();
Assert.Equal("test", line);
AssertUserExpectedResults("the characters you typed properly echoed as you typed");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
public static void EncodingTest()
{
Console.WriteLine(Console.OutputEncoding);
Console.WriteLine("'\u03A0\u03A3'.");
AssertUserExpectedResults("Pi and Sigma or question marks");
}
[ConditionalFact(nameof(ManualTestsEnabled))]
[SkipOnPlatform(TestPlatforms.Browser | TestPlatforms.iOS | TestPlatforms.MacCatalyst | TestPlatforms.tvOS, "Not supported on Browser, iOS, MacCatalyst, or tvOS.")]
public static void ResizeTest()
{
bool wasResized = false;
using (ManualResetEvent manualResetEvent = new(false))
using (PosixSignalRegistration.Create(PosixSignal.SIGWINCH,
ctx =>
{
wasResized = true;
Assert.Equal(PosixSignal.SIGWINCH, ctx.Signal);
manualResetEvent.Set();
}))
{
int widthBefore = Console.WindowWidth;
int heightBefore = Console.WindowHeight;
Assert.False(wasResized);
Console.SetWindowSize(widthBefore / 2, heightBefore / 2);
Assert.True(manualResetEvent.WaitOne(TimeSpan.FromMilliseconds(50)));
Assert.True(wasResized);
Assert.Equal(widthBefore / 2, Console.WindowWidth );
Assert.Equal(heightBefore / 2, Console.WindowHeight );
Console.SetWindowSize(widthBefore, heightBefore);
}
}
private static void AssertUserExpectedResults(string expected)
{
Console.Write($"Did you see {expected}? [y/n] ");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
switch (info.Key)
{
case ConsoleKey.Y or ConsoleKey.N:
Assert.Equal(ConsoleKey.Y, info.Key);
break;
default:
AssertUserExpectedResults(expected);
break;
};
}
}
}