Merge pull request #1240 from dotnet/brthor/stream_forwarding_changes

Stream Forwarding Changes.
This commit is contained in:
Bryan Thornbury 2016-02-09 10:45:35 -08:00
commit 0b27dba299
14 changed files with 231 additions and 159 deletions

View file

@ -206,7 +206,7 @@ namespace Microsoft.DotNet.Tests.ArgumentForwarding
/// <returns></returns>
private string[] ParseReflectorOutput(string reflectorOutput)
{
return reflectorOutput.Split(',');
return reflectorOutput.TrimEnd('\r', '\n').Split(',');
}
/// <summary>

View file

@ -32,8 +32,8 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
var stdOut = new StreamForwarder();
var stdErr = new StreamForwarder();
stdOut.ForwardTo(write: Reporter.Output.Write, writeLine: Reporter.Output.WriteLine);
stdErr.ForwardTo(write: Reporter.Error.Write, writeLine: Reporter.Output.WriteLine);
stdOut.ForwardTo(writeLine: Reporter.Output.WriteLine);
stdErr.ForwardTo(writeLine: Reporter.Output.WriteLine);
return RunProcess(commandPath, args, stdOut, stdErr);
}
@ -82,8 +82,8 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
var result = new CommandResult(
process.StartInfo,
process.ExitCode,
stdOut.GetCapturedOutput(),
stdErr.GetCapturedOutput());
stdOut.CapturedOutput,
stdErr.CapturedOutput);
return result;
}

View file

@ -10,109 +10,138 @@ using Xunit;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.Extensions.PlatformAbstractions;
using System.Threading;
namespace StreamForwarderTests
{
public class StreamForwarderTests
public class StreamForwarderTests : TestBase
{
private static readonly string s_rid = PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier();
private static readonly string s_testProjectRoot = Path.Combine(AppContext.BaseDirectory, "TestProjects");
private TempDirectory _root;
public static void Main()
{
Console.WriteLine("Dummy Entrypoint");
}
[Fact]
public void Unbuffered()
public StreamForwarderTests()
{
Forward(4, true, "");
Forward(4, true, "123", "123");
Forward(4, true, "1234", "1234");
Forward(3, true, "123456789", "123", "456", "789");
Forward(4, true, "\r\n", "\n");
Forward(4, true, "\r\n34", "\n", "34");
Forward(4, true, "1\r\n4", "1\n", "4");
Forward(4, true, "12\r\n", "12\n");
Forward(4, true, "123\r\n", "123\n");
Forward(4, true, "1234\r\n", "1234", "\n");
Forward(3, true, "\r\n3456\r\n9", "\n", "3456", "\n", "9");
Forward(4, true, "\n", "\n");
Forward(4, true, "\n234", "\n", "234");
Forward(4, true, "1\n34", "1\n", "34");
Forward(4, true, "12\n4", "12\n", "4");
Forward(4, true, "123\n", "123\n");
Forward(4, true, "1234\n", "1234", "\n");
Forward(3, true, "\n23456\n89", "\n", "23456", "\n", "89");
_root = Temp.CreateDirectory();
}
[Fact]
public void LineBuffered()
public static IEnumerable<object[]> ForwardingTheoryVariations
{
Forward(4, false, "");
Forward(4, false, "123", "123\n");
Forward(4, false, "1234", "1234\n");
Forward(3, false, "123456789", "123456789\n");
Forward(4, false, "\r\n", "\n");
Forward(4, false, "\r\n34", "\n", "34\n");
Forward(4, false, "1\r\n4", "1\n", "4\n");
Forward(4, false, "12\r\n", "12\n");
Forward(4, false, "123\r\n", "123\n");
Forward(4, false, "1234\r\n", "1234\n");
Forward(3, false, "\r\n3456\r\n9", "\n", "3456\n", "9\n");
Forward(4, false, "\n", "\n");
Forward(4, false, "\n234", "\n", "234\n");
Forward(4, false, "1\n34", "1\n", "34\n");
Forward(4, false, "12\n4", "12\n", "4\n");
Forward(4, false, "123\n", "123\n");
Forward(4, false, "1234\n", "1234\n");
Forward(3, false, "\n23456\n89", "\n", "23456\n", "89\n");
get
{
return new[]
{
new object[] { "123", new string[]{"123"} },
new object[] { "123\n", new string[] {"123"} },
new object[] { "123\r\n", new string[] {"123"} },
new object[] { "1234\n5678", new string[] {"1234", "5678"} },
new object[] { "1234\r\n5678", new string[] {"1234", "5678"} },
new object[] { "1234\n5678\n", new string[] {"1234", "5678"} },
new object[] { "1234\r\n5678\r\n", new string[] {"1234", "5678"} },
new object[] { "1234\n5678\nabcdefghijklmnopqrstuvwxyz", new string[] {"1234", "5678", "abcdefghijklmnopqrstuvwxyz"} },
new object[] { "1234\r\n5678\r\nabcdefghijklmnopqrstuvwxyz", new string[] {"1234", "5678", "abcdefghijklmnopqrstuvwxyz"} },
new object[] { "1234\n5678\nabcdefghijklmnopqrstuvwxyz\n", new string[] {"1234", "5678", "abcdefghijklmnopqrstuvwxyz"} },
new object[] { "1234\r\n5678\r\nabcdefghijklmnopqrstuvwxyz\r\n", new string[] {"1234", "5678", "abcdefghijklmnopqrstuvwxyz"} }
};
}
}
private static void Forward(int bufferSize, bool unbuffered, string str, params string[] expectedWrites)
[Theory]
[InlineData("123")]
[InlineData("123\n")]
public void TestNoForwardingNoCapture(string inputStr)
{
TestCapturingAndForwardingHelper(ForwardOptions.None, inputStr, null, new string[0]);
}
[Theory]
[MemberData("ForwardingTheoryVariations")]
public void TestForwardingOnly(string inputStr, string[] expectedWrites)
{
var expectedCaptured = str.Replace("\r", "").Replace("\n", Environment.NewLine);
for(int i = 0; i < expectedWrites.Length; ++i)
{
expectedWrites[i] += Environment.NewLine;
}
TestCapturingAndForwardingHelper(ForwardOptions.WriteLine, inputStr, null, expectedWrites);
}
// No forwarding.
Forward(bufferSize, ForwardOptions.None, str, null, new string[0]);
[Theory]
[MemberData("ForwardingTheoryVariations")]
public void TestCaptureOnly(string inputStr, string[] expectedWrites)
{
for(int i = 0; i < expectedWrites.Length; ++i)
{
expectedWrites[i] += Environment.NewLine;
}
// Capture only.
Forward(bufferSize, ForwardOptions.Capture, str, expectedCaptured, new string[0]);
var expectedCaptured = string.Join("", expectedWrites);
TestCapturingAndForwardingHelper(ForwardOptions.Capture, inputStr, expectedCaptured, new string[0]);
}
var writeOptions = unbuffered ?
ForwardOptions.Write | ForwardOptions.WriteLine :
ForwardOptions.WriteLine;
[Theory]
[MemberData("ForwardingTheoryVariations")]
public void TestCaptureAndForwardingTogether(string inputStr, string[] expectedWrites)
{
for(int i = 0; i < expectedWrites.Length; ++i)
{
expectedWrites[i] += Environment.NewLine;
}
// Forward.
Forward(bufferSize, writeOptions, str, null, expectedWrites);
var expectedCaptured = string.Join("", expectedWrites);
// Forward and capture.
Forward(bufferSize, writeOptions | ForwardOptions.Capture, str, expectedCaptured, expectedWrites);
TestCapturingAndForwardingHelper(ForwardOptions.WriteLine | ForwardOptions.Capture, inputStr, expectedCaptured, expectedWrites);
}
private enum ForwardOptions
{
None = 0x0,
Capture = 0x1,
Write = 0x02,
WriteLine = 0x04,
WriteLine = 0x02,
}
private static void Forward(int bufferSize, ForwardOptions options, string str, string expectedCaptured, string[] expectedWrites)
private void TestCapturingAndForwardingHelper(ForwardOptions options, string str, string expectedCaptured, string[] expectedWrites)
{
var forwarder = new StreamForwarder(bufferSize);
var forwarder = new StreamForwarder();
var writes = new List<string>();
if ((options & ForwardOptions.WriteLine) != 0)
{
forwarder.ForwardTo(
write: (options & ForwardOptions.Write) == 0 ? (Action<string>)null : writes.Add,
writeLine: s => writes.Add(s + "\n"));
forwarder.ForwardTo(writeLine: s => writes.Add(s + Environment.NewLine));
}
if ((options & ForwardOptions.Capture) != 0)
{
forwarder.Capture();
}
forwarder.Read(new StringReader(str));
Assert.Equal(expectedWrites, writes);
var captured = forwarder.GetCapturedOutput();
var captured = forwarder.CapturedOutput;
Assert.Equal(expectedCaptured, captured);
}
private string SetupTestProject()
{
var sourceTestProjectPath = Path.Combine(s_testProjectRoot, "OutputStandardOutputAndError");
var binTestProjectPath = _root.CopyDirectory(sourceTestProjectPath).Path;
var buildCommand = new BuildCommand(Path.Combine(binTestProjectPath, "project.json"));
buildCommand.Execute();
var buildOutputExe = "OutputStandardOutputAndError" + Constants.ExeSuffix;
var buildOutputPath = Path.Combine(binTestProjectPath, "bin/Debug/dnxcore50", buildOutputExe);
return buildOutputPath;
}
}
}

View file

@ -22,5 +22,9 @@
}
},
"content": [
"../TestProjects/OutputStandardOutputAndError/*"
],
"testRunner": "xunit"
}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>58808bbc-371e-47d6-a3d0-4902145eda4e</ProjectGuid>
<RootNamespace>OutputStandardOutputAndError</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

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;
using System.Diagnostics;
namespace TestApp
{
public class Program
{
public static void Main(string[] args)
{
Console.Out.WriteLine("** Standard Out 1 **");
Console.Error.WriteLine("** Standard Error 1 **");
Console.Out.WriteLine("** Standard Out 2 **");
Console.Error.WriteLine("** Standard Error 2 **");
}
}
}

View file

@ -0,0 +1,14 @@
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": {
"NETStandard.Library": "1.0.0-rc2-23728"
},
"frameworks": {
"dnxcore50": { }
}
}

View file

@ -62,7 +62,7 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
Assert.False(File.Exists(lockFile));
buildResult = BuildProject(expectBuildFailure : true);
Assert.Contains("does not have a lock file", buildResult.StdOut);
Assert.Contains("does not have a lock file", buildResult.StdErr);
}
[Fact]

View file

@ -58,7 +58,8 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
var buildCmd = new BuildCommand(testProject, output: outputDir, framework: DefaultFramework);
var result = buildCmd.ExecuteWithCapturedOutput();
result.Should().Pass();
Assert.Contains("CA1018", result.StdOut);
Assert.Contains("CA1018", result.StdErr);
}
private void CopyProjectToTempDir(string projectDir, TempDirectory tempDir)