From c45be72f139d79e082368fbac4da3517af5309d6 Mon Sep 17 00:00:00 2001 From: Mischa Vreeburg Date: Fri, 3 Nov 2023 15:43:40 +0100 Subject: [PATCH] Fix the problem that the test projects are not being enriched by VsTest. For the enrichment, an alternative datasource has been chosen along with some clever parsing. It now falls back for C# files to the previously scanned test source files and tries to map the test full name with the name in the file and uses that info to get the test file path, along with the method declaration. --- .../Initialisation/ProjectMutator.cs | 57 ++++++++++++++++++- .../Stryker.Core/Mutants/TestDescription.cs | 2 +- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/Stryker.Core/Stryker.Core/Initialisation/ProjectMutator.cs b/src/Stryker.Core/Stryker.Core/Initialisation/ProjectMutator.cs index df399d9793..0f7099014e 100644 --- a/src/Stryker.Core/Stryker.Core/Initialisation/ProjectMutator.cs +++ b/src/Stryker.Core/Stryker.Core/Initialisation/ProjectMutator.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -30,7 +31,7 @@ public IMutationTestProcess MutateProject(StrykerOptions options, MutationTestIn { var process = _injectedMutationTestProcess ?? new MutationTestProcess(input, options, reporters, new MutationTestExecutor(input.TestRunner)); - + // Enrich test projects info with unit tests EnrichTestProjectsWithTestInfo(input.InitialTestRun, input.TestProjectsInfo); @@ -46,7 +47,15 @@ private void EnrichTestProjectsWithTestInfo(InitialTestRun initialTestRun, TestP initialTestRun.Result.VsTestDescriptions .Select(desc => desc.Case) // F# has a different syntax tree and would throw further down the line - .Where(unitTest => Path.GetExtension(unitTest.CodeFilePath) == ".cs"); + .Where(unitTest => Path.GetExtension(unitTest.CodeFilePath) == ".cs").ToList(); + + if (!unitTests.Any()) + { + unitTests = initialTestRun.Result.VsTestDescriptions + .Select(desc => desc.Case) + // F# has a different syntax tree and would throw further down the line + .Where(unitTest => Path.GetExtension(unitTest.CodeFilePath) != ".fs").ToList(); + } foreach (var unitTest in unitTests) { @@ -60,7 +69,49 @@ private void EnrichTestProjectsWithTestInfo(InitialTestRun initialTestRun, TestP } else { - _logger.LogDebug("Could not locate unit test in any testfile. This should not happen and results in incorrect test reporting."); + //Test if you can find the file by scanning the sources for testcase name + var qualifiedNameArray = unitTest.FullyQualifiedName.Split('.'); + var methodName = qualifiedNameArray[^1]; + var className = qualifiedNameArray[^2]; + var nameSpace1 = new ArraySegment(qualifiedNameArray, 0, qualifiedNameArray.Length - 2); + var nameSpace = $"namespace {string.Join('.', nameSpace1)}"; + + testFile = testProjectsInfo.TestFiles.Where(tFile => !tFile.FilePath.EndsWith("GlobalSuppressions.cs")).SingleOrDefault(tFile => + tFile.Source.Contains(className) && tFile.Source.Contains(methodName) && tFile.Source.Contains(nameSpace)); + if (testFile is not null) + { + var testDescriptions = + initialTestRun.Result.VsTestDescriptions.Where(td => td.Description.Name == unitTest.FullyQualifiedName); + foreach (var testDescription in testDescriptions) + { + testDescription.Description.TestFilePath = testFile.FilePath; + } + + var lineNumber = unitTest.LineNumber; + if (lineNumber < 1) + { + var lines = testFile.Source.Split("\r\n"); + foreach (var line in lines) + { + if (line.Contains(methodName) && !line.Contains("class")) + { + lineNumber = Array.IndexOf(testFile.Source.Split("\r\n"), + testFile.Source.Split("\r\n").First(sourceLine => sourceLine.Contains(methodName) && !sourceLine.Contains("class"))); + break; + } + } + } + + var lineSpan = testFile.SyntaxTree.GetText().Lines[lineNumber].Span; + var nodesInSpan = testFile.SyntaxTree.GetRoot().DescendantNodes(lineSpan); + var node = nodesInSpan.First(n => n is MethodDeclarationSyntax); + testFile.AddTest(unitTest.Id, unitTest.FullyQualifiedName, node); + } + else + { + _logger.LogDebug( + "Could not locate unit test in any testfile. This should not happen and results in incorrect test reporting."); + } } } } diff --git a/src/Stryker.Core/Stryker.Core/Mutants/TestDescription.cs b/src/Stryker.Core/Stryker.Core/Mutants/TestDescription.cs index 3ab6ce0e9b..34187af987 100644 --- a/src/Stryker.Core/Stryker.Core/Mutants/TestDescription.cs +++ b/src/Stryker.Core/Stryker.Core/Mutants/TestDescription.cs @@ -15,7 +15,7 @@ public TestDescription(Guid id, string name, string testFilePath) public string Name { get; } - public string TestFilePath { get; } + public string TestFilePath { get; set; } private bool Equals(TestDescription other) {