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:
parent
9a85205781
commit
16b996f25b
5 changed files with 121 additions and 17 deletions
|
@ -18,6 +18,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<string> _commandArgs;
|
private readonly IEnumerable<string> _commandArgs;
|
||||||
private readonly Func<string[], int> _builtInCommand;
|
private readonly Func<string[], int> _builtInCommand;
|
||||||
|
private readonly IBuiltInCommandEnvironment _environment;
|
||||||
private readonly StreamForwarder _stdOut;
|
private readonly StreamForwarder _stdOut;
|
||||||
private readonly StreamForwarder _stdErr;
|
private readonly StreamForwarder _stdErr;
|
||||||
private string _workingDirectory;
|
private string _workingDirectory;
|
||||||
|
@ -26,10 +27,16 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
public string CommandArgs => string.Join(" ", _commandArgs);
|
public string CommandArgs => string.Join(" ", _commandArgs);
|
||||||
|
|
||||||
public BuiltInCommand(string commandName, IEnumerable<string> commandArgs, Func<string[], int> builtInCommand)
|
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;
|
CommandName = commandName;
|
||||||
_commandArgs = commandArgs;
|
_commandArgs = commandArgs;
|
||||||
_builtInCommand = builtInCommand;
|
_builtInCommand = builtInCommand;
|
||||||
|
_environment = environment;
|
||||||
|
|
||||||
_stdOut = new StreamForwarder();
|
_stdOut = new StreamForwarder();
|
||||||
_stdErr = new StreamForwarder();
|
_stdErr = new StreamForwarder();
|
||||||
|
@ -37,9 +44,9 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
public CommandResult Execute()
|
public CommandResult Execute()
|
||||||
{
|
{
|
||||||
TextWriter originalConsoleOut = Console.Out;
|
TextWriter originalConsoleOut = _environment.GetConsoleOut();
|
||||||
TextWriter originalConsoleError = Console.Error;
|
TextWriter originalConsoleError = _environment.GetConsoleError();
|
||||||
string originalWorkingDirectory = Directory.GetCurrentDirectory();
|
string originalWorkingDirectory = _environment.GetWorkingDirectory();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -48,15 +55,15 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
using (BlockingMemoryStream outStream = new BlockingMemoryStream())
|
using (BlockingMemoryStream outStream = new BlockingMemoryStream())
|
||||||
using (BlockingMemoryStream errorStream = new BlockingMemoryStream())
|
using (BlockingMemoryStream errorStream = new BlockingMemoryStream())
|
||||||
{
|
{
|
||||||
Console.SetOut(new StreamWriter(outStream) { AutoFlush = true });
|
_environment.SetConsoleOut(new StreamWriter(outStream) { AutoFlush = true });
|
||||||
Console.SetError(new StreamWriter(errorStream) { AutoFlush = true });
|
_environment.SetConsoleError(new StreamWriter(errorStream) { AutoFlush = true });
|
||||||
|
|
||||||
// Reset the Reporters to the new Console Out and Error.
|
// Reset the Reporters to the new Console Out and Error.
|
||||||
Reporter.Reset();
|
Reporter.Reset();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_workingDirectory))
|
if (!string.IsNullOrEmpty(_workingDirectory))
|
||||||
{
|
{
|
||||||
Directory.SetCurrentDirectory(_workingDirectory);
|
_environment.SetWorkingDirectory(_workingDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
var taskOut = _stdOut.BeginRead(new StreamReader(outStream));
|
var taskOut = _stdOut.BeginRead(new StreamReader(outStream));
|
||||||
|
@ -76,9 +83,9 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Console.SetOut(originalConsoleOut);
|
_environment.SetConsoleOut(originalConsoleOut);
|
||||||
Console.SetError(originalConsoleError);
|
_environment.SetConsoleError(originalConsoleError);
|
||||||
Directory.SetCurrentDirectory(originalWorkingDirectory);
|
_environment.SetWorkingDirectory(originalWorkingDirectory);
|
||||||
|
|
||||||
Reporter.Reset();
|
Reporter.Reset();
|
||||||
}
|
}
|
||||||
|
@ -115,6 +122,39 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
return this;
|
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
|
public CommandResolutionStrategy ResolutionStrategy
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
19
src/Microsoft.DotNet.Cli.Utils/IBuiltInCommandEnvironment.cs
Normal file
19
src/Microsoft.DotNet.Cli.Utils/IBuiltInCommandEnvironment.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("Microsoft.DotNet.Cli.Utils.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -35,16 +36,20 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestOnOutputLines()
|
public void TestOnOutputLines()
|
||||||
{
|
{
|
||||||
int exitCode = 29;
|
const int exitCode = 29;
|
||||||
|
|
||||||
|
TestBuiltInCommandEnvironment environment = new TestBuiltInCommandEnvironment();
|
||||||
|
|
||||||
Func<string[], int> testCommand = args =>
|
Func<string[], int> testCommand = args =>
|
||||||
{
|
{
|
||||||
Console.Out.Write("first");
|
TextWriter outWriter = environment.GetConsoleOut();
|
||||||
Console.Out.WriteLine("second");
|
outWriter.Write("first");
|
||||||
Console.Out.WriteLine("third");
|
outWriter.WriteLine("second");
|
||||||
|
outWriter.WriteLine("third");
|
||||||
|
|
||||||
Console.Error.WriteLine("fourth");
|
TextWriter errorWriter = environment.GetConsoleError();
|
||||||
Console.Error.WriteLine("fifth");
|
errorWriter.WriteLine("fourth");
|
||||||
|
errorWriter.WriteLine("fifth");
|
||||||
|
|
||||||
return exitCode;
|
return exitCode;
|
||||||
};
|
};
|
||||||
|
@ -52,7 +57,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
int onOutputLineCallCount = 0;
|
int onOutputLineCallCount = 0;
|
||||||
int onErrorLineCallCount = 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 =>
|
.OnOutputLine(line =>
|
||||||
{
|
{
|
||||||
onOutputLineCallCount++;
|
onOutputLineCallCount++;
|
||||||
|
@ -85,5 +90,41 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
Assert.Equal(2, onOutputLineCallCount);
|
Assert.Equal(2, onOutputLineCallCount);
|
||||||
Assert.Equal(2, onErrorLineCallCount);
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
"compilationOptions": {
|
"compilationOptions": {
|
||||||
"emitEntryPoint": true
|
"emitEntryPoint": true,
|
||||||
|
"keyFile": "../../tools/Key.snk"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.NETCore.App": {
|
"Microsoft.NETCore.App": {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue