-
Notifications
You must be signed in to change notification settings - Fork 160
Description
Hello everyone!
The filter "tests" truncates the provided value at the first closing parenthesis, which can lead to the following:
- It breaks further use of the filter.
- It returns more results than expected.
- It returns fewer results than expected.
The bug appeared when we upgraded nunit.consolerunner.netcore
from version 3.18.3
to version 3.20.0
.
I suspect that the bug itself was introduced in version 3.19.0
as a result of this commit: 1af35ed.
The bug reproduces in the following cases:
-
If a regex with parentheses is used, the parser may truncate the regex without an explicit error.
Example
If I run the following command:
nunit "test.dll" -where "test =~ '(namespace1|namespace2)\\.test1'" --explore
The parser will truncate to
(namespace1|namespace2)
, and I will get all tests from these namespaces instead ofnamespace1.test1
andnamespace2.test1
. -
If a regex without parentheses is used but with test arguments, the parser may truncate the regex without an explicit error.
Example
If I run the following command:
nunit "test.dll" -where "test =~ 'namespace\\.test1\\(1\\)|namespace\\.test2\\(2\\)'" --explore
The parser will truncate to
namespace\\.test1\\(1\\)
, and I will get only one test instead of two. -
If a regex with parentheses is used, it may break the regex with an error.
Example
If I run the following command:
nunit "test.dll" -where "test =~ '(namespace\\.test1\\(1\\)|namespace\\.test2\\(2\\))'" --explore
The parser will truncate to
(namespace\\.test1\\(1\\)
, resulting in an invalid regex that will fail when creating Regex:Unit.Engine.NUnitEngineException : An exception occurred in the driver while exploring tests. ----> System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. ----> System.Text.RegularExpressions.RegexParseException : Invalid pattern '(namespace\.test1\(1\)' at offset 22. Not enough )'s. --NUnitEngineException An exception occurred in the driver while exploring tests. at NUnit.Engine.Runners.DirectTestRunner.Explore(TestFilter filter) in D:\a\nunit-console\nunit-console\src\NUnitEngine\nunit.engine.core\Runners\DirectTestRunner.cs:line 81 at NUnit.Engine.Runners.MasterTestRunner.Explore(TestFilter filter) in D:\a\nunit-console\nunit-console\src\NUnitEngine\nunit.engine\Runners\MasterTestRunner.cs:line 216 at NUnit.ConsoleRunner.ConsoleRunner.ExploreTests(TestPackage package, TestFilter filter) in D:\a\nunit-console\nunit-console\src\NUnitConsole\nunit3-console\ConsoleRunner.cs:line 171 at NUnit.ConsoleRunner.ConsoleRunner.Execute() in D:\a\nunit-console\nunit-console\src\NUnitConsole\nunit3-console\ConsoleRunner.cs:line 153 at NUnit.ConsoleRunner.Program.Main(String[] args) in D:\a\nunit-console\nunit-console\src\NUnitConsole\nunit3-console\Program.cs:line 117 -- TargetInvocationException Exception has been thrown by the target of an invocation. at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr) at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) at NUnit.Engine.Drivers.NUnitNetCore31Driver.ExecuteMethod(MethodInfo method, Object[] args) in D:\a\nunit-console\nunit-console\src\NUnitEngine\nunit.engine.core\Drivers\NUnitNetCore31Driver.cs:line 207 at NUnit.Engine.Drivers.NUnitNetCore31Driver.ExecuteMethod(String methodName, Object[] args) in D:\a\nunit-console\nunit-console\src\NUnitEngine\nunit.engine.core\Drivers\NUnitNetCore31Driver.cs:line 189 at NUnit.Engine.Drivers.NUnitNetCore31Driver.Explore(String filter) in D:\a\nunit-console\nunit-console\src\NUnitEngine\nunit.engine.core\Drivers\NUnitNetCore31Driver.cs:line 164 at NUnit.Engine.Runners.DirectTestRunner.Explore(TestFilter filter) in D:\a\nunit-console\nunit-console\src\NUnitEngine\nunit.engine.core\Runners\DirectTestRunner.cs:line 77 -- RegexParseException Invalid pattern '(namespace\.test1\(1\)' at offset 22. Not enough )'s. at System.Text.RegularExpressions.RegexParser.ScanRegex() at System.Text.RegularExpressions.RegexParser.Parse(String pattern, RegexOptions options, CultureInfo culture) at System.Text.RegularExpressions.Regex.Init(String pattern, RegexOptions options, TimeSpan matchTimeout, CultureInfo& culture) at System.Text.RegularExpressions.Regex..ctor(String pattern, CultureInfo culture) at System.Text.RegularExpressions.Regex..ctor(String pattern) at NUnit.Framework.Internal.Filters.ValueMatchFilter.Match(String input) at NUnit.Framework.Internal.Filters.FullNameFilter.Match(ITest test) at NUnit.Framework.Internal.TestFilter.Pass(ITest test, Boolean negated) at NUnit.Framework.Internal.TestFilter.Pass(ITest test) at NUnit.Framework.Internal.TestSuite..ctor(TestSuite suite, ITestFilter filter) at NUnit.Framework.Internal.TestAssembly..ctor(TestAssembly assembly, ITestFilter filter) at NUnit.Framework.Api.NUnitTestAssemblyRunner.ExploreTests(ITestFilter filter) at NUnit.Framework.Api.FrameworkController.ExploreTests(String filter) at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
-
If a TestFixture with constructor arguments is used, the parser will truncate the value to TestFixture.
Example
If I run the following command:
nunit "test.dll" -where "test == 'namespace.class(1).test1(1)'" --explore
The parser will truncate to
namespace.class(1)
, and I will get all tests from the class instead of a specific test.
Test cases for TestSelectionParserTests.cs
to reproduce the issue:
new TestCaseData("test == namespace.class(1).test1(1)", "<test>namespace.class(1).test1(1)</test>"),
new TestCaseData("test == \"namespace.class(1).test1(1)\"", "<test>namespace.class(1).test1(1)</test>"),
new TestCaseData("test == 'namespace.class(1).test1(1)'", "<test>namespace.class(1).test1(1)</test>"),
new TestCaseData("test =~ \"(namespace\\.test1\\(1\\)|namespace\\.test2\\(2\\))\"", "<test re='1'>(namespace.test1(1)|namespace.test2(2))</test>"),
new TestCaseData("test =~ '(namespace\\.test1\\(1\\)|namespace\\.test2\\(2\\))'", "<test re='1'>(namespace.test1(1)|namespace.test2(2))</test>"),
new TestCaseData("test =~ /(namespace\\.test1\\(1\\)|namespace\\.test2\\(2\\))/", "<test re='1'>(namespace.test1(1)|namespace.test2(2))</test>"),
new TestCaseData("test =~ \"(namespace1|namespace2)\\.test1\"", "<test re='1'>(namespace1|namespace2).test1</test>"),
new TestCaseData("test =~ '(namespace1|namespace2)\\.test1'", "<test re='1'>(namespace1|namespace2).test1</test>"),
new TestCaseData("test =~ /(namespace1|namespace2)\\.test1/", "<test re='1'>(namespace1|namespace2).test1</test>"),