From 359e19c2431b9a1d8f6fffc11f67dfd4645db2da Mon Sep 17 00:00:00 2001 From: Charlie Poole Date: Sat, 14 Sep 2024 15:38:28 -0700 Subject: [PATCH] Handle invalid chars sent from the framework --- NUnitConsole.sln | 7 ++++ package-tests.cake | 40 ++++++++++++++++++- .../TestEventHandlerTests.cs | 6 +++ .../nunit3-console.tests.csproj | 8 ++-- .../Extensibility/IDriverFactory.cs | 2 +- .../nunit.engine.api/TestEngineActivator.cs | 2 +- .../Runners/TestEventDispatcher.cs | 5 +++ .../InvalidTestNames/InvalidTestNames.cs | 22 ++++++++++ .../InvalidTestNames/InvalidTestNames.csproj | 12 ++++++ 9 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 src/TestData/InvalidTestNames/InvalidTestNames.cs create mode 100644 src/TestData/InvalidTestNames/InvalidTestNames.csproj diff --git a/NUnitConsole.sln b/NUnitConsole.sln index acd529631..c197b9a6a 100644 --- a/NUnitConsole.sln +++ b/NUnitConsole.sln @@ -142,6 +142,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "notest-assembly", "src\Test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApp", "src\TestData\WpfApp\WpfApp.csproj", "{6B550F25-1CA5-4F3E-B631-1ECCD4CB94E4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InvalidTestNames", "src\TestData\InvalidTestNames\InvalidTestNames.csproj", "{58E18ACC-1F7E-4395-817E-E7EF943E0C77}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -212,6 +214,10 @@ Global {6B550F25-1CA5-4F3E-B631-1ECCD4CB94E4}.Debug|Any CPU.Build.0 = Debug|Any CPU {6B550F25-1CA5-4F3E-B631-1ECCD4CB94E4}.Release|Any CPU.ActiveCfg = Release|Any CPU {6B550F25-1CA5-4F3E-B631-1ECCD4CB94E4}.Release|Any CPU.Build.0 = Release|Any CPU + {58E18ACC-1F7E-4395-817E-E7EF943E0C77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {58E18ACC-1F7E-4395-817E-E7EF943E0C77}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58E18ACC-1F7E-4395-817E-E7EF943E0C77}.Release|Any CPU.ActiveCfg = Release|Any CPU + {58E18ACC-1F7E-4395-817E-E7EF943E0C77}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -244,6 +250,7 @@ Global {8FE8378E-5A8B-4708-8F86-35BE0DE121F7} = {2ECE1CFB-9436-4149-B7E4-1FB1786FDE9F} {81E63A90-3191-4E99-92FF-01F9B1D3E3C5} = {2ECE1CFB-9436-4149-B7E4-1FB1786FDE9F} {6B550F25-1CA5-4F3E-B631-1ECCD4CB94E4} = {2ECE1CFB-9436-4149-B7E4-1FB1786FDE9F} + {58E18ACC-1F7E-4395-817E-E7EF943E0C77} = {2ECE1CFB-9436-4149-B7E4-1FB1786FDE9F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D8E4FC26-5422-4C51-8BBC-D1AC0A578711} diff --git a/package-tests.cake b/package-tests.cake index bd1faf66e..ea7fd4bb4 100644 --- a/package-tests.cake +++ b/package-tests.cake @@ -202,7 +202,7 @@ StandardRunnerTests.Add(new PackageTest( StandardRunnerTests.Add(new PackageTest( 1, "NUnitProjectTest", - "Run project with both copies of mock-assembly", + "Run NUnit project with mock-assembly.dll built for .NET 4.6.2 and 6.0", "../../NetFXTests.nunit --config=Release --trace=Debug", new MockAssemblyExpectedResult("net-4.6.2", "netcore-6.0"), KnownExtensions.NUnitProjectLoader.SetVersion("3.8.0"))); @@ -249,3 +249,41 @@ StandardRunnerTests.Add(new PackageTest( "../../src/TestData/TestData.sln --config=Release --trace=Debug", MockAssemblySolutionResult, KnownExtensions.VSProjectLoader.SetVersion("3.9.0"))); + +// Special Cases + +StandardRunnerTests.Add(new PackageTest( + 1, "InvalidTestNameTest_Net462", + "Ensure we handle invalid test names correctly under .NET 4.6.2", + "net462/InvalidTestNames.dll --trace:Debug", + new ExpectedResult("Passed") + { + Assemblies = new ExpectedAssemblyResult[] + { + new ExpectedAssemblyResult("InvalidTestNames.dll", "net-4.6.2") + } + })); + +AddToBothLists(new PackageTest( + 1, "InvalidTestNameTest_Net60", + "Ensure we handle invalid test names correctly under .NET 6.0", + "net6.0/InvalidTestNames.dll --trace:Debug", + new ExpectedResult("Passed") + { + Assemblies = new ExpectedAssemblyResult[] + { + new ExpectedAssemblyResult("InvalidTestNames.dll", "netcore-6.0") + } + })); + +AddToBothLists(new PackageTest( + 1, "InvalidTestNameTest_Net80", + "Ensure we handle invalid test names correctly under .NET 8.0", + "net8.0/InvalidTestNames.dll --trace:Debug", + new ExpectedResult("Passed") + { + Assemblies = new ExpectedAssemblyResult[] + { + new ExpectedAssemblyResult("InvalidTestNames.dll", "netcore-8.0") + } + })); diff --git a/src/NUnitConsole/nunit3-console.tests/TestEventHandlerTests.cs b/src/NUnitConsole/nunit3-console.tests/TestEventHandlerTests.cs index 48981fe5d..d00f47f7f 100644 --- a/src/NUnitConsole/nunit3-console.tests/TestEventHandlerTests.cs +++ b/src/NUnitConsole/nunit3-console.tests/TestEventHandlerTests.cs @@ -21,6 +21,12 @@ public void CreateWriter() _writer = new ExtendedTextWrapper(new StringWriter(_output)); } + [TestCase(char.MaxValue)] + public void TestNameContainsInvalidChar(char c) + { + Console.WriteLine($"Test for char {c}"); + } + [TestCaseSource("SingleEventData")] public void SingleEventsWriteExpectedOutput(string report, string labels, string expected) { diff --git a/src/NUnitConsole/nunit3-console.tests/nunit3-console.tests.csproj b/src/NUnitConsole/nunit3-console.tests/nunit3-console.tests.csproj index a9f1aec4d..a668e6134 100644 --- a/src/NUnitConsole/nunit3-console.tests/nunit3-console.tests.csproj +++ b/src/NUnitConsole/nunit3-console.tests/nunit3-console.tests.csproj @@ -23,8 +23,8 @@ - - + @@ -45,9 +45,7 @@ - - - + diff --git a/src/NUnitEngine/nunit.engine.api/Extensibility/IDriverFactory.cs b/src/NUnitEngine/nunit.engine.api/Extensibility/IDriverFactory.cs index 9aadc8bfa..c8eb3c7e3 100644 --- a/src/NUnitEngine/nunit.engine.api/Extensibility/IDriverFactory.cs +++ b/src/NUnitEngine/nunit.engine.api/Extensibility/IDriverFactory.cs @@ -19,7 +19,7 @@ public interface IDriverFactory /// An AssemblyName referring to the possible test framework. bool IsSupportedTestFramework(AssemblyName reference); -#if NETSTANDARD2_0 +#if NETSTANDARD || NETCOREAPP /// /// Gets a driver for a given test assembly and a framework /// which the assembly is already known to reference. diff --git a/src/NUnitEngine/nunit.engine.api/TestEngineActivator.cs b/src/NUnitEngine/nunit.engine.api/TestEngineActivator.cs index 14f596cd8..d69ec5f50 100644 --- a/src/NUnitEngine/nunit.engine.api/TestEngineActivator.cs +++ b/src/NUnitEngine/nunit.engine.api/TestEngineActivator.cs @@ -17,7 +17,7 @@ public static class TestEngineActivator private const string DefaultAssemblyName = "nunit.engine.dll"; internal const string DefaultTypeName = "NUnit.Engine.TestEngine"; -#if NETSTANDARD2_0 +#if NETSTANDARD || NETCOREAPP /// /// Create an instance of the test engine. /// diff --git a/src/NUnitEngine/nunit.engine/Runners/TestEventDispatcher.cs b/src/NUnitEngine/nunit.engine/Runners/TestEventDispatcher.cs index 5bd7f6830..316d98381 100644 --- a/src/NUnitEngine/nunit.engine/Runners/TestEventDispatcher.cs +++ b/src/NUnitEngine/nunit.engine/Runners/TestEventDispatcher.cs @@ -21,8 +21,13 @@ public TestEventDispatcher() public void OnTestEvent(string report) { + const string badChar = "\xffff"; + lock (_eventLock) { + // TODO: Review whether we need more checks + report = report.Replace(badChar, "?"); + foreach (var listener in Listeners) listener.OnTestEvent(report); } diff --git a/src/TestData/InvalidTestNames/InvalidTestNames.cs b/src/TestData/InvalidTestNames/InvalidTestNames.cs new file mode 100644 index 000000000..07d585dd5 --- /dev/null +++ b/src/TestData/InvalidTestNames/InvalidTestNames.cs @@ -0,0 +1,22 @@ +// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt + +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace InvalidTestNames +{ + // Issue 1469 showed that the NUnit framework sometimes sends char + // '\uffff' in test names, if the user provides it as an argument. + // Therefore, the runner has to protect itself. If additional bad + // characters are detected, we can add more tests here. + public class InvalidTestNames + { + // Generates test name TestContainsInvalidCharacter("\uffff"); + [TestCase(char.MaxValue)] + public void TestNameContainsInvalidChar(char c) + { + Console.WriteLine($"Test for char {c}"); + } + } +} diff --git a/src/TestData/InvalidTestNames/InvalidTestNames.csproj b/src/TestData/InvalidTestNames/InvalidTestNames.csproj new file mode 100644 index 000000000..d08f867db --- /dev/null +++ b/src/TestData/InvalidTestNames/InvalidTestNames.csproj @@ -0,0 +1,12 @@ + + + + net462;net6.0;net8.0 + Library + + + + + + +