nunit3-vs-adapter icon indicating copy to clipboard operation
nunit3-vs-adapter copied to clipboard

TestFilter does not support test cases with spaces and special characters

Open plainionist opened this issue 3 years ago • 33 comments

Running "dotnet test" with a test filter for a test case with spaces the following exception occurs:

dotnet test --settings ../../../build/.runsettings --no-build --logger "trx;LogFileName=C:\Temp\0.trx" --filter "FullyQualifiedName="BackLook.Apps.WorkInProgress.Specs.Computing work in progress Project.No Workpackages exist"" --no-build

Test run for C:\ws\BackLook\system\App.WorkInProgress\BackLook.Apps.WorkInProgress.Specs\bin\Debug\net48\BackLook.Apps.WorkInProgress.Specs.dll (.NETFramework,Version=v4.8) Microsoft (R) Test Execution Command Line Tool Version 16.10.0 Copyright (c) Microsoft Corporation. All rights reserved.

Starting test execution, please wait... A total of 1 test files matched the specified pattern. An exception occurred while invoking executor 'executor://nunit3testexecutor/': Unexpected Word 'work' at position 64 in selection expression. Stack trace: at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Expect(Token[] valid) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 252 at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Parse(String input) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 66 at NUnit.VisualStudio.TestAdapter.NUnitTestFilterBuilder.ConvertVsTestFilterToNUnitFilter(IVsTestFilter vsFilter) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\NUnitTestFilterBuilder.cs:line 72 at NUnit.VisualStudio.TestAdapter.NUnit3TestExecutor.RunTests(IEnumerable1 sources, IRunContext runContext, IFrameworkHandle frameworkHandle) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\NUnit3TestExecutor.cs:line 116 at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.RunTestsWithSources.InvokeExecutor(LazyExtension2 executor, Tuple2 executorUriExtensionTuple, RunContext runContext, IFrameworkHandle frameworkHandle) at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.<>c__DisplayClass48_0.<RunTestInternalWithExecutors>b__0() at Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.PlatformThread.<>c__DisplayClass0_0.<Run>b__0() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.PlatformThread.Run(Action action, PlatformApartmentState apartmentState, Boolean waitForCompletion) at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.TryToRunInSTAThread(Action action, Boolean waitForCompletion) at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.RunTestInternalWithExecutors(IEnumerable1 executorUriExtensionMap, Int64 totalTests)

according to https://docs.microsoft.com/de-de/dotnet/core/testing/selective-unit-tests?pivots=mstest spaces and special characters can be encoded using "url style encoding" but that causes the same exception.

example: --filter "FullyQualifiedName=BackLook.Apps.WorkInProgress.Specs.Computing%20work%20in%20progress%20Project.No%20Workpackages%20exist"

i am using

<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />

and "dotnet cli" version 5.0.301

plainionist avatar Aug 05 '21 15:08 plainionist

This is a known issue, part of the FQN issues.

OsirisTerje avatar Aug 26 '21 07:08 OsirisTerje

any plans for adding support for such characters?

plainionist avatar Aug 29 '21 18:08 plainionist

@plainionist This issue seems now to be fixed in the latest version of Visual Studio 2019, 16.11.3.
image

See repro here: https://github.com/nunit/nunit3-vs-adapter.issues/tree/master/Issue711

Note that the '.' in the name causes Test Explorer to add an extra hierarchy node. The Test Explorer uses the '.' in the testname as a node separator.

Works both with and without Real-time Test Discovery

OsirisTerje avatar Oct 06 '21 18:10 OsirisTerje

@OsirisTerje I just updated VS to 16.11.5 and the problem still exists. I also doubt that the issue is related to VS but to unit3-vs-adapter. as described above my use case is NOT running tests with spaces in VS itself but on the console using dotnet CLI. The error message clearly indicates that the filter parser is not supporting my use case:

An exception occurred while invoking executor 'executor://nunit3testexecutor/': Unexpected Word 'work' at position 64 in selection expression. Stack trace: at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Expect(Token[] valid) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 252 at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Parse(String input) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 66 at NUnit.VisualStudio.TestAdapter.NUnitTestFilterBuilder.ConvertVsTestFilterToNUnitFilter(IVsTestFilter vsFilter) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\NUnitTestFilterBuilder.cs:line 72

==> pls reopen the issue

thx

plainionist avatar Oct 14 '21 05:10 plainionist

Reopened.

@plainionist Can you confirm the repro at https://github.com/nunit/nunit3-vs-adapter.issues/tree/master/Issue711 reproduces your issue? If not, can you update it so that it does?

OsirisTerje avatar Oct 14 '21 06:10 OsirisTerje

as far as i can see in the code the repro would probably sufficient to reproduce the issue, at least i see spaces in the test cases. the question is: how do u execute it. if we call it from "dotnet" CLI with a filter like

"--filter "FullyQualifiedName=""

then we would probably get the same issue.

dotnet test --filter "FullyQualifiedName=Unit To Test Input A equals itself"

results in

An exception occurred while invoking executor 'executor://nunit3testexecutor/': Unexpected Word 'To' at position 24 in selection expression.
Stack trace:
   at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Expect(Token[] valid) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 255
   at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Parse(String input) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 66
   at NUnit.VisualStudio.TestAdapter.NUnitTestFilterBuilder.ConvertVsTestFilterToNUnitFilter(IVsTestFilter vsFilter) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\NUnitTestFilterBuilder.cs:line 73
   at NUnit.VisualStudio.TestAdapter.NUnit3TestExecutor.RunTests(IEnumerable`1 sources, IRunContext runContext, IFrameworkHandle frameworkHandle) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\NUnit3TestExecutor.cs:line 116
   at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.RunTestsWithSources.InvokeExecutor(LazyExtension`2 executor, Tuple`2 executorUriExtensionTuple, RunContext runContext, IFrameworkHandle frameworkHandle)
   at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.RunTestInternalWithExecutors(IEnumerable`1 executorUriExtensionMap, Int64 totalTests)

putting the test name in quotes gives similar issues

dotnet test --filter "FullyQualifiedName=\"Unit To Test Input A equals itself\""
dotnet test --filter "FullyQualifiedName='Unit To Test Input A equals itself'"

plainionist avatar Oct 20 '21 08:10 plainionist

Hi,

we have the same problem with version 4.1.0.

ThisFunctionalTom avatar Jan 25 '22 15:01 ThisFunctionalTom

Hello, I'm facing a similar issue where my test name is having spaces. I noticed the tokenizer is skipping these spaces here: https://github.com/nunit/nunit3-vs-adapter/blob/0b118ec63a52d351b879d51643f8ffa05a622237/src/NUnitTestAdapter/TestFilterConverter/Tokenizer.cs#L297-L301

Is there any reason for this? Perhaps, we can make it more context aware and not always skip the spaces.

nojaf avatar Mar 28 '22 19:03 nojaf

The problem with spaces in names is that the test names are very close to FQN for classes and namespaces, and as they can't have spaces, the test names can't either. The real time discovery in Visual Studio would not be able to handle them. For categories using string parameters, it can in principle have spaces, but once they are made like typed categories, they can't.
One could imagine a mode where this is allowed, but it would not work properly in Visual Studio, and it would require an increase in complexity to handle both scenarios.
An alternative is to make a difference between name and displayname (there already is, but one could use this more expressively), perhaps inventing a new kind of displayname, being a mixture of the name and the displayname. Then, it should work all the way down to the framework.
If anyone wants to contribute something here, we would be happy for that. Bear in mind that any changes have to be compatible and work with the current "way of working".

OsirisTerje avatar Mar 28 '22 20:03 OsirisTerje

Well, I'm running this from the command line, so I wonder if there could be a later point in time where the spaces could be stripped for Visual Studio.

nojaf avatar Mar 29 '22 06:03 nojaf

The adapter tries to deduct from where it is being called, there are properties being set to that effect. But you then have to bring that information all the way down through the code, or it could swap in different tokenizers based on that, so surely, it could be doable. Would you like to give it a try?

OsirisTerje avatar Mar 29 '22 06:03 OsirisTerje

I might want to give this a try, could you point me in the right direction where the call site deduction is done? I would then try to pass this information to the tokenizer. Any advice on how to write a test for this scenario would also be appreciated.

nojaf avatar Mar 29 '22 06:03 nojaf

You should not pass the information to the tokenizer, but create a new (derived) class for it, so that you change the method there. That way the existing code is not changed.
The property to check for is in the TestAdapter base class, and is IsRunningUnderIde.

OsirisTerje avatar Mar 29 '22 08:03 OsirisTerje

Hello. I have a similar issue

##[error]An exception occurred while invoking executor 'executor://nunit3testexecutor/': Unexpected Word 'test' at position 15 in selection expression. ##[debug]Processed: ##vso[task.logissue type=error;]An exception occurred while invoking executor 'executor://nunit3testexecutor/': Unexpected Word 'test' at position 15 in selection expression. ##[error]Stack trace: ##[debug]Processed: ##vso[task.logissue type=error;]Stack trace: ##[debug]Processed: ##vso[task.logissue type=error;]Stack trace: ##[error] at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Expect(Token[] valid) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 252 ##[debug]Processed: ##vso[task.logissue type=error;] at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Expect(Token[] valid) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 252 ##[error] at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Parse(String input) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 65 ##[debug]Processed: ##vso[task.logissue type=error;] at NUnit.VisualStudio.TestAdapter.TestFilterConverter.TestFilterParser.Parse(String input) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\TestFilterConverter\TestFilterParser.cs:line 65 ##[error] at NUnit.VisualStudio.TestAdapter.NUnitTestFilterBuilder.ConvertVsTestFilterToNUnitFilter(IVsTestFilter vsFilter) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\NUnitTestFilterBuilder.cs:line 72 ##[debug]Processed: ##vso[task.logissue type=error;] at NUnit.VisualStudio.TestAdapter.NUnitTestFilterBuilder.ConvertVsTestFilterToNUnitFilter(IVsTestFilter vsFilter) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\NUnitTestFilterBuilder.cs:line 72 ##[error] at NUnit.VisualStudio.TestAdapter.NUnit3TestExecutor.RunTests(IEnumerable1 sources, IRunContext runContext, IFrameworkHandle frameworkHandle) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\NUnit3TestExecutor.cs:line 116 ##[debug]Processed: ##vso[task.logissue type=error;] at NUnit.VisualStudio.TestAdapter.NUnit3TestExecutor.RunTests(IEnumerable1 sources, IRunContext runContext, IFrameworkHandle frameworkHandle) in D:\repos\NUnit\nunit3-vs-adapter\src\NUnitTestAdapter\NUnit3TestExecutor.cs:line 116 ##[error] at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.RunTestsWithSources.InvokeExecutor(LazyExtension2 executor, Tuple2 executorUriExtensionTuple, RunContext runContext, IFrameworkHandle frameworkHandle) ##[debug]Processed: ##vso[task.logissue type=error;] at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.RunTestsWithSources.InvokeExecutor(LazyExtension2 executor, Tuple2 executorUriExtensionTuple, RunContext runContext, IFrameworkHandle frameworkHandle) ##[error] at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.<>c__DisplayClass48_0.<RunTestInternalWithExecutors>b__0() ##[debug]Processed: ##vso[task.logissue type=error;] at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.<>c__DisplayClass48_0.<RunTestInternalWithExecutors>b__0() ##[error] at Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.PlatformThread.<>c__DisplayClass0_0.<Run>b__0() ##[debug]Processed: ##vso[task.logissue type=error;] at Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.PlatformThread.<>c__DisplayClass0_0.<Run>b__0() ##[error]--- End of stack trace from previous location where exception was thrown --- ##[debug]Processed: ##vso[task.logissue type=error;]--- End of stack trace from previous location where exception was thrown --- ##[error] at Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.PlatformThread.Run(Action action, PlatformApartmentState apartmentState, Boolean waitForCompletion) ##[debug]Processed: ##vso[task.logissue type=error;] at Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.PlatformThread.Run(Action action, PlatformApartmentState apartmentState, Boolean waitForCompletion) ##[error] at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.TryToRunInSTAThread(Action action, Boolean waitForCompletion) ##[debug]Processed: ##vso[task.logissue type=error;] at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.TryToRunInSTAThread(Action action, Boolean waitForCompletion) ##[error] at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.RunTestInternalWithExecutors(IEnumerable1 executorUriExtensionMap, Int64 totalTests) ##[debug]Processed: ##vso[task.logissue type=error;] at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.BaseRunTests.RunTestInternalWithExecutors(IEnumerable1 executorUriExtensionMap, Int64 totalTests)

NastassiaDzianisava avatar Apr 11 '22 11:04 NastassiaDzianisava

@AnastasiaDen16 And what is your test expression ?

OsirisTerje avatar Apr 11 '22 11:04 OsirisTerje

@OsirisTerje Visual studio 16.10.4 NUnit version="3.12.0" NUnit3TestAdapter version="4.0.0"

NastassiaDzianisava avatar Apr 11 '22 11:04 NastassiaDzianisava

@AnastasiaDen16 OK, but your test expression ? What is it ? There are known FQN issues, is yours different and what is it?

OsirisTerje avatar Apr 11 '22 12:04 OsirisTerje

@OsirisTerje I don't understand, what do you mean. I have this issue the first time.

NastassiaDzianisava avatar Apr 11 '22 12:04 NastassiaDzianisava

@AnastasiaDen16 This issue is about testfilters with spaces and special characters. Does your situation have the same? The error message says you have an unexpected word "test" in the selection expression. How does your selection expression look like? You say you run from Visual Studio, then I expect you have something in the Search part of the Test Explorer window, right? What is that? Next, Is there something special about the test code you have, can you shorten down that code and show how the method definition there look like, or even better, provide a very small repro solution. Does this help?

OsirisTerje avatar Apr 11 '22 15:04 OsirisTerje

@OsirisTerje Thank you, I understand what the problem is. Yes, I have a space in the category. As I understand, this way of describing the category is unacceptable, right?

NastassiaDzianisava avatar Apr 12 '22 06:04 NastassiaDzianisava

Yes, it will not work for now. We'll see if we can fix this over time, but the workaround is to make it into a single word.

OsirisTerje avatar Apr 12 '22 08:04 OsirisTerje

@OsirisTerje Ok, thank you for answer.

NastassiaDzianisava avatar Apr 12 '22 08:04 NastassiaDzianisava

@NastassiaDzianisava A small tip: When I create categories, I normally make them as typesafe classes, as shown in the figure below: image That way I avoid misspelling when they're being used too.

OsirisTerje avatar Apr 12 '22 09:04 OsirisTerje

Tried to use new libraries again, but it still hasn't been fixed So I'm back to good old NUnit 3.12.0 NUnit3TestAdapter 3.17.0 Whitespaces work there

jake8787 avatar Sep 02 '22 12:09 jake8787

@OsirisTerje

The problem with spaces in names is that the test names are very close to FQN for classes and namespaces, and as they can't have spaces, the test names can't either.

In F# i can use spaces in class and method names like this:

[<TestFixture>]
module ``Calculating team availabilities (Fruits)`` =

if i then use dnSpy to look into the compiled code it looks like this

[TestFixture]
[CompilationMapping(SourceConstructFlags.Module)]
public static class Calculating\u0020team\u0020availabilities\u0020(Fruits)

plainionist avatar Sep 09 '22 09:09 plainionist

@plainionist Good point! Now where that is failing, is then the question. ........

OsirisTerje avatar Sep 09 '22 11:09 OsirisTerje

@OsirisTerje i think the missing support is in the parser of the filter at least as far as i understood the callstack of the error i posted at the beginning of this thread

plainionist avatar Sep 09 '22 14:09 plainionist

@plainionist I am a bit out of available time at the moment, but if you feel you see where it is, a and how it could be fixed, a PR would be very appreciated.

OsirisTerje avatar Sep 09 '22 19:09 OsirisTerje

The problem seems to be in the NUnitTestAdapter/TestFilterConverter/Tokenizer.cs:Tokenizer.GetNextToken() method, which does not support any quoting or escape characters (eg. backslash).

Till then, a workaround is to AND together all the valid parts of the rhs value, like this:

--filter "testcase&with&spaces"

(reported also in this SO)

ankostis avatar Dec 13 '22 20:12 ankostis