Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #4686: Add ProgressTraceListener #4709

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 60 additions & 0 deletions src/NUnitFramework/framework/Diagnostics/ProgressTraceListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt

using System;
using System.Diagnostics;
#if !NET6_0_OR_GREATER
using System.Security.Permissions;
#endif

namespace NUnit.Framework.Diagnostics
{
/// <summary><para>
/// The ProgressTraceListener class allows directing tracing or
/// debugging output to <see cref="TestContext.Progress"/>.
/// </para><para>
/// To activate, place the following snippet into the one-time
/// set-up method of either a test's fixture or the set-up
/// fixture of a project:
/// <c>
/// System.Trace.Listeners.Add(new ProgressTraceListener());
/// </c>
/// </para><para>
/// Make sure to only add a listener once, e.g.:
/// <c>
/// if (!System.Trace.Listeners.OfType&lt;ProgressTraceListener&gt;().Any())
/// System.Trace.Listeners.Add(new ProgressTraceListener());
/// </c>
/// </para><para>
/// Or again remove in the one-time tear-down, e.g.:
/// <c>
/// System.Trace.Listeners.Remove(_progressTraceListener);
/// </c>
/// </para></summary>
/// <remarks><para>
/// Although named "Trace", <see cref="TextWriterTraceListener"/>
/// "directs tracing or debugging output".
/// </para><para>
/// This listener is provided by NUnit (i.e. the origin of
/// <see cref="TestContext.Progress"/>) same as the
/// <see cref="ConsoleTraceListener"/> is provided by .NET
/// (the origin of <see cref="Console"/>).
/// </para></remarks>
// Implemented following the ConsoleTraceListener implementation.
#if !NET6_0_OR_GREATER
[HostProtection(Synchronization = true)]
#endif
public class ProgressTraceListener : TextWriterTraceListener
{
#region Constructors

/// <summary>
/// Construct a ProgressTraceListener with trace
/// output written to <see cref="TestContext.Progress"/>
/// </summary>
public ProgressTraceListener() : base(TestContext.Progress)
{
}

#endregion
}
}
144 changes: 144 additions & 0 deletions src/NUnitFramework/tests/Diagnostics/ProgressTraceListenerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt

using System;
using System.Collections.Generic;
using System.Diagnostics;
using NUnit.Framework.Diagnostics;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;

namespace NUnit.Framework.Tests.Diagnostics
{
public abstract class ProgressTraceListenerTestsBase
{
protected const string SOME_TEXT = "Should go to the output";
protected static readonly string NL = Environment.NewLine;

protected TestListenerInterceptor TestResultListener { get; private set; }

[SetUp]
public void AddTestResultListener()
{
// Wrap the current listener, listening to events, and forwarding the original event
TestResultListener = new TestListenerInterceptor(TestExecutionContext.CurrentContext.Listener);
TestExecutionContext.CurrentContext.Listener = TestResultListener;
}

[TearDown]
public void RemoveTestResultListener()
{
// Restore the original listener
TestExecutionContext.CurrentContext.Listener = TestResultListener.DefaultListener;
}

[Test]
public void TestProgressIsOutput()
{
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(0));

TestContext.Progress.WriteLine(SOME_TEXT);
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(1));
Assert.That(TestResultListener.Outputs[0], Is.EqualTo(SOME_TEXT + NL));
}

#region ITestListener implementation

protected class TestListenerInterceptor : ITestListener
{
public IList<string> Outputs { get; }
public ITestListener DefaultListener { get; }

public TestListenerInterceptor(ITestListener defaultListener)
{
DefaultListener = defaultListener;
Outputs = new List<string>();
}

void ITestListener.TestStarted(ITest test)
{
DefaultListener?.TestStarted(test);
}

void ITestListener.TestFinished(ITestResult result)
{
DefaultListener?.TestFinished(result);
}

void ITestListener.TestOutput(TestOutput output)
{
Assert.That(output, Is.Not.Null);
Outputs.Add(output.Text);

DefaultListener?.TestOutput(output);
}

void ITestListener.SendMessage(TestMessage message)
{
}
}

#endregion
}

[TestFixture, NonParallelizable] // Adding the "ProgressTraceListener" may lead to side-effects in other tests.
public class ProgressTraceListenerTests : ProgressTraceListenerTestsBase
{
private ProgressTraceListener _progressTraceListener;

[OneTimeSetUp]
public void AddProgressTraceListener()
{
_progressTraceListener = new ProgressTraceListener();
Trace.Listeners.Add(_progressTraceListener);
}

[OneTimeTearDown]
public void RemoveProgressTraceListener()
{
Trace.Listeners.Remove(_progressTraceListener);
_progressTraceListener.Dispose();
}

[Test]
public void TestDebugIsDirectedToOutput()
{
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(0));

Debug.WriteLine(SOME_TEXT);
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(1));
Assert.That(TestResultListener.Outputs[0], Is.EqualTo(SOME_TEXT + NL));
}

[Test]
public void TestTraceIsDirectedToOutput()
{
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(0));

Trace.WriteLine(SOME_TEXT);
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(1));
Assert.That(TestResultListener.Outputs[0], Is.EqualTo(SOME_TEXT + NL));
}
}

[TestFixture, NonParallelizable] // Tests may be affected by adding the "ProgressTraceListener" in "ProgressTraceListenerTests".
public class NoProgressTraceListenerTests : ProgressTraceListenerTestsBase
{
[Test]
public void TestDebugIsNotDirectedToOutput()
{
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(0));

Debug.WriteLine(SOME_TEXT);
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(0));
}

[Test]
public void TestTraceIsNotDirectedToOutput()
{
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(0));

Trace.WriteLine(SOME_TEXT);
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(0));
}
}
}