Fixing the BuiltInCommandTests to not mutate global shared state.

The BuiltInCommandTests sets the current Console.Out and Console.Error, which causes the test to fail if some other test is running and writes to the console at the same time.

Fix #2768
This commit is contained in:
Eric Erhardt 2016-05-02 17:46:48 -05:00
parent 9a85205781
commit 16b996f25b
5 changed files with 121 additions and 17 deletions

View file

@ -18,6 +18,7 @@ namespace Microsoft.DotNet.Cli.Utils
{
private readonly IEnumerable<string> _commandArgs;
private readonly Func<string[], int> _builtInCommand;
private readonly IBuiltInCommandEnvironment _environment;
private readonly StreamForwarder _stdOut;
private readonly StreamForwarder _stdErr;
private string _workingDirectory;
@ -26,10 +27,16 @@ namespace Microsoft.DotNet.Cli.Utils
public string CommandArgs => string.Join(" ", _commandArgs);
public BuiltInCommand(string commandName, IEnumerable<string> commandArgs, Func<string[], int> builtInCommand)
: this(commandName, commandArgs, builtInCommand, new BuiltInCommandEnvironment())
{
}
internal BuiltInCommand(string commandName, IEnumerable<string> commandArgs, Func<string[], int> builtInCommand, IBuiltInCommandEnvironment environment)
{
CommandName = commandName;
_commandArgs = commandArgs;
_builtInCommand = builtInCommand;
_environment = environment;
_stdOut = new StreamForwarder();
_stdErr = new StreamForwarder();
@ -37,9 +44,9 @@ namespace Microsoft.DotNet.Cli.Utils
public CommandResult Execute()
{
TextWriter originalConsoleOut = Console.Out;
TextWriter originalConsoleError = Console.Error;
string originalWorkingDirectory = Directory.GetCurrentDirectory();
TextWriter originalConsoleOut = _environment.GetConsoleOut();
TextWriter originalConsoleError = _environment.GetConsoleError();
string originalWorkingDirectory = _environment.GetWorkingDirectory();
try
{
@ -48,15 +55,15 @@ namespace Microsoft.DotNet.Cli.Utils
using (BlockingMemoryStream outStream = new BlockingMemoryStream())
using (BlockingMemoryStream errorStream = new BlockingMemoryStream())
{
Console.SetOut(new StreamWriter(outStream) { AutoFlush = true });
Console.SetError(new StreamWriter(errorStream) { AutoFlush = true });
_environment.SetConsoleOut(new StreamWriter(outStream) { AutoFlush = true });
_environment.SetConsoleError(new StreamWriter(errorStream) { AutoFlush = true });
// Reset the Reporters to the new Console Out and Error.
Reporter.Reset();
if (!string.IsNullOrEmpty(_workingDirectory))
{
Directory.SetCurrentDirectory(_workingDirectory);
_environment.SetWorkingDirectory(_workingDirectory);
}
var taskOut = _stdOut.BeginRead(new StreamReader(outStream));
@ -76,9 +83,9 @@ namespace Microsoft.DotNet.Cli.Utils
}
finally
{
Console.SetOut(originalConsoleOut);
Console.SetError(originalConsoleError);
Directory.SetCurrentDirectory(originalWorkingDirectory);
_environment.SetConsoleOut(originalConsoleOut);
_environment.SetConsoleError(originalConsoleError);
_environment.SetWorkingDirectory(originalWorkingDirectory);
Reporter.Reset();
}
@ -115,6 +122,39 @@ namespace Microsoft.DotNet.Cli.Utils
return this;
}
private class BuiltInCommandEnvironment : IBuiltInCommandEnvironment
{
public TextWriter GetConsoleOut()
{
return Console.Out;
}
public void SetConsoleOut(TextWriter newOut)
{
Console.SetOut(newOut);
}
public TextWriter GetConsoleError()
{
return Console.Error;
}
public void SetConsoleError(TextWriter newError)
{
Console.SetError(newError);
}
public string GetWorkingDirectory()
{
return Directory.GetCurrentDirectory();
}
public void SetWorkingDirectory(string path)
{
Directory.SetCurrentDirectory(path);
}
}
public CommandResolutionStrategy ResolutionStrategy
{
get

View file

@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
namespace Microsoft.DotNet.Cli.Utils
{
internal interface IBuiltInCommandEnvironment
{
TextWriter GetConsoleOut();
void SetConsoleOut(TextWriter newOut);
TextWriter GetConsoleError();
void SetConsoleError(TextWriter newError);
string GetWorkingDirectory();
void SetWorkingDirectory(string path);
}
}

View file

@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.DotNet.Cli.Utils.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View file

@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
@ -35,16 +36,20 @@ namespace Microsoft.DotNet.Cli.Utils
[Fact]
public void TestOnOutputLines()
{
int exitCode = 29;
const int exitCode = 29;
TestBuiltInCommandEnvironment environment = new TestBuiltInCommandEnvironment();
Func<string[], int> testCommand = args =>
{
Console.Out.Write("first");
Console.Out.WriteLine("second");
Console.Out.WriteLine("third");
TextWriter outWriter = environment.GetConsoleOut();
outWriter.Write("first");
outWriter.WriteLine("second");
outWriter.WriteLine("third");
Console.Error.WriteLine("fourth");
Console.Error.WriteLine("fifth");
TextWriter errorWriter = environment.GetConsoleError();
errorWriter.WriteLine("fourth");
errorWriter.WriteLine("fifth");
return exitCode;
};
@ -52,7 +57,7 @@ namespace Microsoft.DotNet.Cli.Utils
int onOutputLineCallCount = 0;
int onErrorLineCallCount = 0;
CommandResult result = new BuiltInCommand("fakeCommand", Enumerable.Empty<string>(), testCommand)
CommandResult result = new BuiltInCommand("fakeCommand", Enumerable.Empty<string>(), testCommand, environment)
.OnOutputLine(line =>
{
onOutputLineCallCount++;
@ -85,5 +90,41 @@ namespace Microsoft.DotNet.Cli.Utils
Assert.Equal(2, onOutputLineCallCount);
Assert.Equal(2, onErrorLineCallCount);
}
private class TestBuiltInCommandEnvironment : IBuiltInCommandEnvironment
{
private TextWriter _consoleOut;
private TextWriter _consoleError;
public TextWriter GetConsoleOut()
{
return _consoleOut;
}
public void SetConsoleOut(TextWriter newOut)
{
_consoleOut = newOut;
}
public TextWriter GetConsoleError()
{
return _consoleError;
}
public void SetConsoleError(TextWriter newError)
{
_consoleError = newError;
}
public string GetWorkingDirectory()
{
return Directory.GetCurrentDirectory();
}
public void SetWorkingDirectory(string path)
{
// no-op
}
}
}
}

View file

@ -1,7 +1,8 @@
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
"emitEntryPoint": true,
"keyFile": "../../tools/Key.snk"
},
"dependencies": {
"Microsoft.NETCore.App": {