Skip to content

Commit

Permalink
Merge pull request nunit#4709 from maettu-this/4686_ProgressTraceList…
Browse files Browse the repository at this point in the history
…ener

Issue nunit#4686: Add ProgressTraceListener
  • Loading branch information
stevenaw authored Aug 20, 2024
2 parents 2e436d7 + 972aa33 commit e59e1bf
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 0 deletions.
59 changes: 59 additions & 0 deletions src/NUnitFramework/framework/Diagnostics/ProgressTraceListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt

using System;
using System.Diagnostics;

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>
/// Alternatively, add it in the one-time set-up and again remove
/// it in the one-time tear-down, e.g.:
/// <c>
/// _progressTraceListener = new ProgressTraceListener();
/// System.Trace.Listeners.Add(_progressTraceListener);
/// </c>
/// <c>
/// System.Trace.Listeners.Remove(_progressTraceListener);
/// _progressTraceListener.Close();
/// </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>
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
}
}
152 changes: 152 additions & 0 deletions src/NUnitFramework/tests/Diagnostics/ProgressTraceListenerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// 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] // Non-parallelizable because 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);
#if DEBUG
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(1));
Assert.That(TestResultListener.Outputs[0], Is.EqualTo(SOME_TEXT + NL));
#else
Assert.That(TestResultListener.Outputs, Has.Count.EqualTo(0));
#endif
}

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

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

[TestFixture, NonParallelizable] // Non-parallelizable same as "ProgressTraceListenerTests" above.
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));
}
}
}

0 comments on commit e59e1bf

Please sign in to comment.