Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 6179876

Browse files
committed
Add more tests for System.Console
This improves code coverage as much as we can reasonably, given the difficulty in automating certain console-related functionality in inner loop testing, e.g. allowing ctrl-c to take down the testing process.
1 parent 109063a commit 6179876

File tree

6 files changed

+233
-13
lines changed

6 files changed

+233
-13
lines changed

src/System.Console/tests/CancelKeyPress.cs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,66 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System;
5+
using System.Runtime.InteropServices;
6+
using System.Threading;
57
using Xunit;
68

79
public class CancelKeyPress
810
{
11+
private const int WaitFailTestTimeoutSeconds = 30;
12+
913
[Fact]
1014
public static void CanAddAndRemoveHandler()
1115
{
12-
ConsoleCancelEventHandler handler = new ConsoleCancelEventHandler(Console_CancelKeyPress);
13-
16+
ConsoleCancelEventHandler handler = (sender, e) =>
17+
{
18+
// We don't actually want to do anything here. This will only get called on the off chance
19+
// that someone CTRL+C's the test run while the handler is hooked up. This is just used to
20+
// validate that we can add and remove a handler, we don't care about exercising it.
21+
};
1422
Console.CancelKeyPress += handler;
1523
Console.CancelKeyPress -= handler;
1624
}
1725

18-
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
26+
[Fact]
27+
[PlatformSpecific(PlatformID.AnyUnix)]
28+
public static void InvokingCancelKeyPressHandler()
1929
{
20-
// We don't actually want to do anything here. This will only get called on the off chance
21-
// that someone CTRL+C's the test run while the handler is hooked up. This is just used to
22-
// validate that we can add and remove a handler, we don't care about exercising it.
30+
// On Windows we could use GenerateConsoleCtrlEvent to send a ctrl-C to the process,
31+
// however that'll apply to all processes associated with the same group, which will
32+
// include processes like the code coverage tool when doing code coverage runs, causing
33+
// those other processes to exit. As such, we test this only on Unix, where we can
34+
// send a SIGINT signal to this specific process only.
35+
36+
using (var mres = new ManualResetEventSlim())
37+
{
38+
ConsoleCancelEventHandler handler = (sender, e) => {
39+
e.Cancel = true;
40+
mres.Set();
41+
};
42+
43+
Console.CancelKeyPress += handler;
44+
try
45+
{
46+
Assert.Equal(0, kill(getpid(), SIGINT));
47+
Assert.True(mres.Wait(WaitFailTestTimeoutSeconds));
48+
}
49+
finally
50+
{
51+
Console.CancelKeyPress -= handler;
52+
}
53+
}
2354
}
55+
56+
#region Unix Imports
57+
// P/Invokes included here rather than being pulled from Interop\Unix
58+
// to avoid platform-dependent includes in csproj
59+
[DllImport("libc", SetLastError = true)]
60+
private static extern int kill(int pid, int sig);
61+
62+
[DllImport("libc")]
63+
private static extern int getpid();
64+
65+
private const int SIGINT = 2;
66+
#endregion
2467
}

src/System.Console/tests/Color.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,32 @@
99

1010
public class Color
1111
{
12+
[Fact]
13+
public static void InvalidColors()
14+
{
15+
Assert.Throws<ArgumentException>(() => Console.BackgroundColor = (ConsoleColor)42);
16+
Assert.Throws<ArgumentException>(() => Console.ForegroundColor = (ConsoleColor)42);
17+
}
18+
19+
[Fact]
20+
public static void RoundtrippingColor()
21+
{
22+
if (Interop.IsWindows)
23+
{
24+
Console.BackgroundColor = Console.BackgroundColor;
25+
Console.ForegroundColor = Console.ForegroundColor;
26+
// Changing color on Windows doesn't have effect in some testing environments
27+
// when there is no associated console, such as when run under a profiler like
28+
// our code coverage tools, so we don't assert that the change took place and
29+
// simple ensure that getting/setting doesn't throw.
30+
}
31+
else
32+
{
33+
Assert.Throws<PlatformNotSupportedException>(() => Console.BackgroundColor);
34+
Assert.Throws<PlatformNotSupportedException>(() => Console.ForegroundColor);
35+
}
36+
}
37+
1238
[Fact]
1339
[PlatformSpecific(PlatformID.AnyUnix)]
1440
public static void RedirectedOutputDoesNotUseAnsiSequences()

src/System.Console/tests/Helpers.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ public static void SetAndReadHelper(Action<TextWriter> setHelper, Func<TextWrite
1111
{
1212
const string TestString = "Test";
1313

14-
TextWriter oldErrorToRestore = getHelper();
14+
TextWriter oldWriterToRestore = getHelper();
15+
Assert.NotNull(oldWriterToRestore);
16+
1517
try
1618
{
1719
using (MemoryStream memStream = new MemoryStream())
@@ -40,7 +42,7 @@ public static void SetAndReadHelper(Action<TextWriter> setHelper, Func<TextWrite
4042
}
4143
finally
4244
{
43-
setHelper(oldErrorToRestore);
45+
setHelper(oldWriterToRestore);
4446
}
4547
}
4648
}

src/System.Console/tests/ReadAndWrite.cs

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System;
5-
using System.Collections.Generic;
65
using System.IO;
76
using System.Text;
7+
using System.Threading.Tasks;
88
using Xunit;
99

1010
public class ReadAndWrite
@@ -97,6 +97,11 @@ private static void WriteCore()
9797

9898
private static void WriteLineCore()
9999
{
100+
Assert.Equal(Environment.NewLine, Console.Out.NewLine);
101+
Console.Out.NewLine = "abcd";
102+
Assert.Equal("abcd", Console.Out.NewLine);
103+
Console.Out.NewLine = Environment.NewLine;
104+
100105
// We just want to ensure none of these throw exceptions, we don't actually validate
101106
// what was written.
102107

@@ -126,6 +131,133 @@ private static void WriteLineCore()
126131
Console.WriteLine("Hello World");
127132
}
128133

134+
[Fact]
135+
public static async Task OutWriteAndWriteLineOverloads()
136+
{
137+
TextWriter savedStandardOutput = Console.Out;
138+
try
139+
{
140+
using (var sw = new StreamWriter(new MemoryStream()))
141+
{
142+
Console.SetOut(sw);
143+
TextWriter writer = Console.Out;
144+
Assert.NotNull(writer);
145+
Assert.NotEqual(writer, sw); // the writer we provide gets wrapped
146+
147+
// We just want to ensure none of these throw exceptions, we don't actually validate
148+
// what was written.
149+
150+
writer.Write("{0}", 32);
151+
writer.Write("{0} {1}", 32, "Hello");
152+
writer.Write("{0} {1} {2}", 32, "Hello", (uint)50);
153+
writer.Write("{0} {1} {2} {3}", 32, "Hello", (uint)50, (ulong)5);
154+
writer.Write("{0} {1} {2} {3} {4}", 32, "Hello", (uint)50, (ulong)5, 'a');
155+
writer.Write(true);
156+
writer.Write('a');
157+
writer.Write(new char[] { 'a', 'b', 'c', 'd', });
158+
writer.Write(new char[] { 'a', 'b', 'c', 'd', }, 1, 2);
159+
writer.Write(1.23d);
160+
writer.Write(123.456M);
161+
writer.Write(1.234f);
162+
writer.Write(39);
163+
writer.Write(50u);
164+
writer.Write(50L);
165+
writer.Write(50UL);
166+
writer.Write(new object());
167+
writer.Write("Hello World");
168+
169+
writer.Flush();
170+
171+
await writer.WriteAsync('c');
172+
await writer.WriteAsync(new char[] { 'a', 'b', 'c', 'd' });
173+
await writer.WriteAsync(new char[] { 'a', 'b', 'c', 'd' }, 1, 2);
174+
await writer.WriteAsync("Hello World");
175+
176+
await writer.WriteLineAsync('c');
177+
await writer.WriteLineAsync(new char[] { 'a', 'b', 'c', 'd' });
178+
await writer.WriteLineAsync(new char[] { 'a', 'b', 'c', 'd' }, 1, 2);
179+
await writer.WriteLineAsync("Hello World");
180+
181+
await writer.FlushAsync();
182+
}
183+
}
184+
finally
185+
{
186+
Console.SetOut(savedStandardOutput);
187+
}
188+
}
189+
190+
[Fact]
191+
public static unsafe void ValidateConsoleEncoding()
192+
{
193+
Assert.Same(Console.Out, Console.Out);
194+
195+
Encoding encoding = Console.Out.Encoding;
196+
Assert.NotNull(encoding);
197+
Assert.Same(encoding, Console.Out.Encoding);
198+
199+
// The primary purpose of ConsoleEncoding is to return an empty preamble.
200+
Assert.Equal(Array.Empty<byte>(), encoding.GetPreamble());
201+
202+
// There's not much validation we can do, but we can at least invoke members
203+
// to ensure they don't throw exceptions as they delegate to the underlying
204+
// encoding wrapped by ConsoleEncoding.
205+
206+
Assert.False(string.IsNullOrWhiteSpace(encoding.EncodingName));
207+
Assert.False(string.IsNullOrWhiteSpace(encoding.WebName));
208+
Assert.True(encoding.CodePage >= 0);
209+
bool ignored = encoding.IsSingleByte;
210+
211+
// And we can validate that the encoding is self-consistent by roundtripping
212+
// data between chars and bytes.
213+
214+
string str = "This is the input string.";
215+
char[] strAsChars = str.ToCharArray();
216+
byte[] strAsBytes = encoding.GetBytes(str);
217+
Assert.Equal(strAsBytes.Length, encoding.GetByteCount(str));
218+
Assert.True(encoding.GetMaxByteCount(str.Length) >= strAsBytes.Length);
219+
220+
Assert.Equal(str, encoding.GetString(strAsBytes));
221+
Assert.Equal(str, encoding.GetString(strAsBytes, 0, strAsBytes.Length));
222+
Assert.Equal(str, new string(encoding.GetChars(strAsBytes)));
223+
Assert.Equal(str, new string(encoding.GetChars(strAsBytes, 0, strAsBytes.Length)));
224+
fixed (byte* bytesPtr = strAsBytes)
225+
{
226+
char[] outputArr = new char[encoding.GetMaxCharCount(strAsBytes.Length)];
227+
228+
int len = encoding.GetChars(strAsBytes, 0, strAsBytes.Length, outputArr, 0);
229+
Assert.Equal(str, new string(outputArr, 0, len));
230+
Assert.Equal(len, encoding.GetCharCount(strAsBytes));
231+
Assert.Equal(len, encoding.GetCharCount(strAsBytes, 0, strAsBytes.Length));
232+
233+
fixed (char* charsPtr = outputArr)
234+
{
235+
len = encoding.GetChars(bytesPtr, strAsBytes.Length, charsPtr, outputArr.Length);
236+
Assert.Equal(str, new string(charsPtr, 0, len));
237+
Assert.Equal(len, encoding.GetCharCount(bytesPtr, strAsBytes.Length));
238+
}
239+
240+
Assert.Equal(str, encoding.GetString(bytesPtr, strAsBytes.Length));
241+
}
242+
243+
Assert.Equal(strAsBytes, encoding.GetBytes(strAsChars));
244+
Assert.Equal(strAsBytes, encoding.GetBytes(strAsChars, 0, strAsChars.Length));
245+
Assert.Equal(strAsBytes.Length, encoding.GetByteCount(strAsChars));
246+
Assert.Equal(strAsBytes.Length, encoding.GetByteCount(strAsChars, 0, strAsChars.Length));
247+
fixed (char* charsPtr = strAsChars)
248+
{
249+
Assert.Equal(strAsBytes.Length, encoding.GetByteCount(charsPtr, strAsChars.Length));
250+
251+
byte[] outputArr = new byte[encoding.GetMaxByteCount(strAsChars.Length)];
252+
Assert.Equal(strAsBytes.Length, encoding.GetBytes(strAsChars, 0, strAsChars.Length, outputArr, 0));
253+
fixed (byte* bytesPtr = outputArr)
254+
{
255+
Assert.Equal(strAsBytes.Length, encoding.GetBytes(charsPtr, strAsChars.Length, bytesPtr, outputArr.Length));
256+
}
257+
Assert.Equal(strAsBytes.Length, encoding.GetBytes(str, 0, str.Length, outputArr, 0));
258+
}
259+
}
260+
129261
static readonly string[] s_testLines = new string[] {
130262
"3232 Hello32 Hello 5032 Hello 50 532 Hello 50 5 aTrueaabcdbc1.23123.4561.23439505050System.ObjectHello World",
131263
"32",

src/System.Console/tests/SyncTextReader.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,13 @@ private static void Test(string content, Action action)
6666
}
6767
finally
6868
{
69+
TextWriter oldWriter = Console.Out;
6970
Console.SetOut(savedStandardOutput);
71+
oldWriter.Dispose();
72+
73+
TextReader oldReader = Console.In;
7074
Console.SetIn(savedStandardInput);
75+
oldReader.Dispose();
7176
}
7277
}
7378

@@ -163,6 +168,12 @@ public void ReadBlockAsync()
163168
Assert.Equal(5, result);
164169
Assert.Equal(expected, buffer);
165170
Assert.Equal(-1, Console.Read()); // We should be at EOF now.
171+
172+
// Invalid args
173+
Assert.Throws<ArgumentNullException>(() => { Console.In.ReadBlockAsync(null, 0, 0); });
174+
Assert.Throws<ArgumentOutOfRangeException>(() => { Console.In.ReadBlockAsync(new char[1], -1, 0); });
175+
Assert.Throws<ArgumentOutOfRangeException>(() => { Console.In.ReadBlockAsync(new char[1], 0, -1); });
176+
Assert.Throws<ArgumentException>(() => { Console.In.ReadBlockAsync(new char[1], 1, 1); });
166177
});
167178
}
168179

@@ -181,6 +192,12 @@ public void ReadAsync()
181192
Assert.Equal(5, result);
182193
Assert.Equal(expected, buffer);
183194
Assert.Equal(-1, Console.Read()); // We should be at EOF now.
195+
196+
// Invalid args
197+
Assert.Throws<ArgumentNullException>(() => { Console.In.ReadAsync(null, 0, 0); });
198+
Assert.Throws<ArgumentOutOfRangeException>(() => { Console.In.ReadAsync(new char[1], -1, 0); });
199+
Assert.Throws<ArgumentOutOfRangeException>(() => { Console.In.ReadAsync(new char[1], 0, -1); });
200+
Assert.Throws<ArgumentException>(() => { Console.In.ReadAsync(new char[1], 1, 1); });
184201
});
185202
}
186203

src/System.Console/tests/System.Console.Tests.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
<OutputType>Library</OutputType>
99
<AssemblyName>System.Console.Tests</AssemblyName>
1010
<RootNamespace>System.Console.Tests</RootNamespace>
11+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
1112
</PropertyGroup>
1213
<!-- Default configurations to help VS understand the configurations -->
13-
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
14-
</PropertyGroup>
15-
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
16-
</PropertyGroup>
14+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU'" />
15+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU'" />
1716
<ItemGroup>
1817
<Compile Include="CancelKeyPress.cs" />
1918
<Compile Include="Helpers.cs" />
@@ -27,6 +26,7 @@
2726
<Compile Include="Timeout.cs" />
2827
<Compile Include="ThreadSafety.cs" />
2928
<Compile Include="XunitAssemblyAttributes.cs" />
29+
<Compile Include="$(CommonPath)\Interop\Interop.PlatformDetection.cs" />
3030
</ItemGroup>
3131
<ItemGroup>
3232
<ProjectReference Include="..\src\System.Console.csproj">

0 commit comments

Comments
 (0)