зеркало из https://github.com/dotnet/msbuild.git
Add sample LiveLogger unit tests
This commit is contained in:
Родитель
8c385b0066
Коммит
aa5cf68300
|
@ -0,0 +1,201 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Logging.LiveLogger;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Build.UnitTests
|
||||
{
|
||||
public class LiveLogger_Tests : IEventSource, IDisposable
|
||||
{
|
||||
private const int _nodeCount = 8;
|
||||
private const int _terminalWidth = 80;
|
||||
private const string _eventSender = "Test";
|
||||
private const string _projectFile = @"C:\src\project.proj";
|
||||
|
||||
private readonly MockTerminal _mockTerminal;
|
||||
private readonly LiveLogger _liveLogger;
|
||||
|
||||
private readonly DateTime _buildStartTime = new DateTime(2023, 3, 30, 16, 30, 0);
|
||||
private readonly DateTime _buildFinishTime = new DateTime(2023, 3, 30, 16, 30, 5);
|
||||
|
||||
public LiveLogger_Tests()
|
||||
{
|
||||
_mockTerminal = new MockTerminal(_terminalWidth);
|
||||
_liveLogger = new LiveLogger(_mockTerminal);
|
||||
|
||||
_liveLogger.Initialize(this, _nodeCount);
|
||||
}
|
||||
|
||||
#region IEventSource implementation
|
||||
|
||||
public event BuildMessageEventHandler? MessageRaised;
|
||||
public event BuildErrorEventHandler? ErrorRaised;
|
||||
public event BuildWarningEventHandler? WarningRaised;
|
||||
public event BuildStartedEventHandler? BuildStarted;
|
||||
public event BuildFinishedEventHandler? BuildFinished;
|
||||
public event ProjectStartedEventHandler? ProjectStarted;
|
||||
public event ProjectFinishedEventHandler? ProjectFinished;
|
||||
public event TargetStartedEventHandler? TargetStarted;
|
||||
public event TargetFinishedEventHandler? TargetFinished;
|
||||
public event TaskStartedEventHandler? TaskStarted;
|
||||
public event TaskFinishedEventHandler? TaskFinished;
|
||||
public event CustomBuildEventHandler? CustomEventRaised;
|
||||
public event BuildStatusEventHandler? StatusEventRaised;
|
||||
public event AnyEventHandler? AnyEventRaised;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable implementation
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_liveLogger.Shutdown();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event args helpers
|
||||
|
||||
private BuildEventContext MakeBuildEventContext()
|
||||
{
|
||||
return new BuildEventContext(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
private BuildStartedEventArgs MakeBuildStartedEventArgs()
|
||||
{
|
||||
return new BuildStartedEventArgs(null, null, _buildStartTime);
|
||||
}
|
||||
|
||||
private BuildFinishedEventArgs MakeBuildFinishedEventArgs(bool succeeded)
|
||||
{
|
||||
return new BuildFinishedEventArgs(null, null, succeeded, _buildFinishTime);
|
||||
}
|
||||
|
||||
private ProjectStartedEventArgs MakeProjectStartedEventArgs(string projectFile, string targetNames = "Build")
|
||||
{
|
||||
return new ProjectStartedEventArgs("", "", projectFile, targetNames, new Dictionary<string, string>(), new List<DictionaryEntry>())
|
||||
{
|
||||
BuildEventContext = MakeBuildEventContext(),
|
||||
};
|
||||
}
|
||||
|
||||
private ProjectFinishedEventArgs MakeProjectFinishedEventArgs(string projectFile, bool succeeded)
|
||||
{
|
||||
return new ProjectFinishedEventArgs(null, null, projectFile, succeeded)
|
||||
{
|
||||
BuildEventContext = MakeBuildEventContext(),
|
||||
};
|
||||
}
|
||||
|
||||
private TargetStartedEventArgs MakeTargetStartedEventArgs(string projectFile, string targetName)
|
||||
{
|
||||
return new TargetStartedEventArgs("", "", targetName, projectFile, targetFile: projectFile)
|
||||
{
|
||||
BuildEventContext = MakeBuildEventContext(),
|
||||
};
|
||||
}
|
||||
|
||||
private TargetFinishedEventArgs MakeTargetFinishedEventArgs(string projectFile, string targetName, bool succeeded)
|
||||
{
|
||||
return new TargetFinishedEventArgs("", "", targetName, projectFile, targetFile: projectFile, succeeded)
|
||||
{
|
||||
BuildEventContext = MakeBuildEventContext(),
|
||||
};
|
||||
}
|
||||
|
||||
private TaskStartedEventArgs MakeTaskStartedEventArgs(string projectFile, string taskName)
|
||||
{
|
||||
return new TaskStartedEventArgs("", "", projectFile, taskFile: projectFile, taskName)
|
||||
{
|
||||
BuildEventContext = MakeBuildEventContext(),
|
||||
};
|
||||
}
|
||||
|
||||
private TaskFinishedEventArgs MakeTaskFinishedEventArgs(string projectFile, string taskName, bool succeeded)
|
||||
{
|
||||
return new TaskFinishedEventArgs("", "", projectFile, taskFile: projectFile, taskName, succeeded)
|
||||
{
|
||||
BuildEventContext = MakeBuildEventContext(),
|
||||
};
|
||||
}
|
||||
|
||||
private BuildWarningEventArgs MakeWarningEventArgs(string warning)
|
||||
{
|
||||
return new BuildWarningEventArgs("", "", "", 0, 0, 0, 0, warning, null, null)
|
||||
{
|
||||
BuildEventContext = MakeBuildEventContext(),
|
||||
};
|
||||
}
|
||||
|
||||
private BuildErrorEventArgs MakeErrorEventArgs(string error)
|
||||
{
|
||||
return new BuildErrorEventArgs("", "", "", 0, 0, 0, 0, error, null, null)
|
||||
{
|
||||
BuildEventContext = MakeBuildEventContext(),
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Build summary tests
|
||||
|
||||
private void InvokeLoggerCallbacksForSimpleProject(bool succeeded, Action additionalCallbacks)
|
||||
{
|
||||
BuildStarted?.Invoke(_eventSender, MakeBuildStartedEventArgs());
|
||||
ProjectStarted?.Invoke(_eventSender, MakeProjectStartedEventArgs(_projectFile));
|
||||
|
||||
TargetStarted?.Invoke(_eventSender, MakeTargetStartedEventArgs(_projectFile, "Build"));
|
||||
TaskStarted?.Invoke(_eventSender, MakeTaskStartedEventArgs(_projectFile, "Task"));
|
||||
|
||||
additionalCallbacks();
|
||||
|
||||
TaskFinished?.Invoke(_eventSender, MakeTaskFinishedEventArgs(_projectFile, "Task", succeeded));
|
||||
TargetFinished?.Invoke(_eventSender, MakeTargetFinishedEventArgs(_projectFile, "Build", succeeded));
|
||||
|
||||
ProjectFinished?.Invoke(_eventSender, MakeProjectFinishedEventArgs(_projectFile, succeeded));
|
||||
BuildFinished?.Invoke(_eventSender, MakeBuildFinishedEventArgs(succeeded));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PrintsBuildSummary_Succeeded()
|
||||
{
|
||||
InvokeLoggerCallbacksForSimpleProject(succeeded: true, () => { });
|
||||
_mockTerminal.GetLastLine().ShouldBe("Build succeeded in 5.0s");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PrintBuildSummary_SucceededWithWarnings()
|
||||
{
|
||||
InvokeLoggerCallbacksForSimpleProject(succeeded: true, () =>
|
||||
{
|
||||
WarningRaised?.Invoke(_eventSender, MakeWarningEventArgs("Warning!"));
|
||||
});
|
||||
_mockTerminal.GetLastLine().ShouldBe("Build succeeded with warnings in 5.0s");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PrintBuildSummary_Failed()
|
||||
{
|
||||
InvokeLoggerCallbacksForSimpleProject(succeeded: false, () => { });
|
||||
_mockTerminal.GetLastLine().ShouldBe("Build failed in 5.0s");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PrintBuildSummary_FailedWithErrors()
|
||||
{
|
||||
InvokeLoggerCallbacksForSimpleProject(succeeded: false, () =>
|
||||
{
|
||||
ErrorRaised?.Invoke(_eventSender, MakeErrorEventArgs("Error!"));
|
||||
});
|
||||
_mockTerminal.GetLastLine().ShouldBe("Build failed with errors in 5.0s");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -45,6 +45,9 @@
|
|||
<Compile Include="..\UnitTests.Shared\EnvironmentProvider.cs" />
|
||||
<Compile Include="..\UnitTests.Shared\RunnerUtilities.cs" />
|
||||
|
||||
<Compile Remove="LiveLogger_Tests.cs" Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'" />
|
||||
<Compile Remove="MockTerminal.cs" Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'" />
|
||||
|
||||
<EmbeddedResource Include="..\MSBuild\MSBuild\Microsoft.Build.Core.xsd">
|
||||
<Link>Microsoft.Build.Core.xsd</Link>
|
||||
<SubType>
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Build.Logging.LiveLogger;
|
||||
|
||||
namespace Microsoft.Build.UnitTests
|
||||
{
|
||||
/// <summary>
|
||||
/// A test implementation of <see cref="ITerminal"/>.
|
||||
/// </summary>
|
||||
internal sealed class MockTerminal : ITerminal
|
||||
{
|
||||
private readonly int _width;
|
||||
|
||||
/// <summary>
|
||||
/// Contains output lines written to the terminal.
|
||||
/// </summary>
|
||||
private List<string> _outputLines = new();
|
||||
|
||||
private StringBuilder _bufferedOutput = new();
|
||||
private bool _isBuffering = false;
|
||||
|
||||
public MockTerminal(int width)
|
||||
{
|
||||
_width = width;
|
||||
_outputLines.Add("");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last line written to the terminal.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the last character was \n, it returns characters between the second to last \n and last \n.
|
||||
/// If the last character was not \n, it returns characters between the last \n and the end of the output.
|
||||
/// </remarks>
|
||||
public string GetLastLine()
|
||||
{
|
||||
string lastLine = _outputLines[^1];
|
||||
if (lastLine.Length == 0 && _outputLines.Count > 1)
|
||||
{
|
||||
lastLine = _outputLines[^2];
|
||||
}
|
||||
return lastLine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a string to <see cref="_outputLines"/>.
|
||||
/// </summary>
|
||||
private void AddOutput(string text)
|
||||
{
|
||||
if (_isBuffering)
|
||||
{
|
||||
_bufferedOutput.Append(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] lines = text.Split('\n');
|
||||
_outputLines[^1] += lines[0];
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
_outputLines.Add("");
|
||||
_outputLines[^1] += lines[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region ITerminal implementation
|
||||
|
||||
public void BeginUpdate()
|
||||
{
|
||||
if (_isBuffering)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
_isBuffering = true;
|
||||
}
|
||||
|
||||
public void EndUpdate()
|
||||
{
|
||||
if (!_isBuffering)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
_isBuffering = false;
|
||||
|
||||
AddOutput(_bufferedOutput.ToString());
|
||||
_bufferedOutput.Clear();
|
||||
}
|
||||
|
||||
public void Write(string text) => AddOutput(text);
|
||||
public void WriteColor(TerminalColor color, string text) => AddOutput(text);
|
||||
public void WriteColorLine(TerminalColor color, string text) { AddOutput(text); AddOutput("\n"); }
|
||||
public void WriteLine(string text) { AddOutput(text); AddOutput("\n"); }
|
||||
public void WriteLine(ReadOnlySpan<char> text) { AddOutput(text.ToString()); AddOutput("\n"); }
|
||||
public void WriteLineFitToWidth(ReadOnlySpan<char> input)
|
||||
{
|
||||
AddOutput(input.Slice(0, Math.Min(input.Length, _width - 1)).ToString());
|
||||
AddOutput("\n");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable implementation
|
||||
|
||||
public void Dispose()
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -172,7 +172,8 @@
|
|||
<Compile Include="DistributedLoggerRecord.cs">
|
||||
<ExcludeFromStyleCop>true</ExcludeFromStyleCop>
|
||||
</Compile>
|
||||
<Compile Include="LiveLogger\*.cs" />
|
||||
<!-- LiveLogger is supported only in Core builds -->
|
||||
<Compile Include="LiveLogger\*.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'" />
|
||||
<Compile Include="InitializationException.cs">
|
||||
<ExcludeFromStyleCop>true</ExcludeFromStyleCop>
|
||||
</Compile>
|
||||
|
@ -189,8 +190,6 @@
|
|||
<Compile Include="XMake.cs">
|
||||
<ExcludeFromStyleCop>true</ExcludeFromStyleCop>
|
||||
</Compile>
|
||||
<!-- LiveLogger is supported only in Core builds -->
|
||||
<Compile Remove="LiveLogger\**\*.*" Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'" />
|
||||
<!-- This is to enable CodeMarkers in MSBuild.exe -->
|
||||
<!-- Win32 RC Files -->
|
||||
<RCResourceFile Include="native.rc" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче