diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/AcceptanceTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/AcceptanceTests.cs index 7aac1486..c8167de1 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/AcceptanceTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/AcceptanceTests.cs @@ -9,276 +9,275 @@ using NUnit.Framework.Interfaces; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public class Frameworks +{ + public const string NetCoreApp31 = "netcoreapp3.1"; + public const string Net50 = "net5.0"; + public const string Net60 = "net6.0"; + public const string Net70 = "net7.0"; + public const string Net80 = "net8.0"; +} + +[Category("Acceptance")] +public abstract class AcceptanceTests { - public class Frameworks + public static string NuGetPackageId => "NUnit3TestAdapter"; + + public static string NuGetPackageVersion => Initialization.Value.NupkgVersion; + + public const string LowestNetfxTarget = "net462"; + public const string LegacyProjectTargetFrameworkVersion = "v4.6.2"; + + protected static IEnumerable TargetFrameworks => new[] { - public const string NetCoreApp31 = "netcoreapp3.1"; - public const string Net50 = "net5.0"; - public const string Net60 = "net6.0"; - public const string Net70 = "net7.0"; - public const string Net80 = "net8.0"; - } + LowestNetfxTarget, + Frameworks.NetCoreApp31 + }; - [Category("Acceptance")] - public abstract class AcceptanceTests + protected static IEnumerable DotNetCliTargetFrameworks => new[] { - public static string NuGetPackageId => "NUnit3TestAdapter"; + Frameworks.NetCoreApp31, + Frameworks.Net50, + Frameworks.Net60, + Frameworks.Net70 + }; - public static string NuGetPackageVersion => Initialization.Value.NupkgVersion; + protected static IEnumerable ModernDotNetCliTargetFrameworks => new[] + { + Frameworks.Net60, + Frameworks.Net70, + Frameworks.Net80 + }; - public const string LowestNetfxTarget = "net462"; - public const string LegacyProjectTargetFrameworkVersion = "v4.6.2"; + protected static string NUnit3 => "3.*"; + protected static string NUnit4 => "4.*"; - protected static IEnumerable TargetFrameworks => new[] - { - LowestNetfxTarget, - Frameworks.NetCoreApp31 - }; + public class MultiFrameworkSource + { + public IEnumerable Frameworks { get; set; } = DotNetCliTargetFrameworks; + public string NUnitVersion { get; set; } = NUnit3; - protected static IEnumerable DotNetCliTargetFrameworks => new[] + public static IEnumerable LegacyDotNetFrameworks => new List { new() }; + + public static IEnumerable ModernDotNetFrameworks => new List { - Frameworks.NetCoreApp31, - Frameworks.Net50, - Frameworks.Net60, - Frameworks.Net70 + new () + { + Frameworks = ModernDotNetCliTargetFrameworks, + NUnitVersion = NUnit4 + } }; - protected static IEnumerable ModernDotNetCliTargetFrameworks => new[] + public static IEnumerable NetFxFrameworks => new List { - Frameworks.Net60, - Frameworks.Net70, - Frameworks.Net80 + new () + { + Frameworks = new List { LowestNetfxTarget }, + NUnitVersion = NUnit4 + } }; - protected static string NUnit3 => "3.*"; - protected static string NUnit4 => "4.*"; + public static IEnumerable AllFrameworks => LegacyDotNetFrameworks.Concat(ModernDotNetFrameworks).Concat(NetFxFrameworks); + } - public class MultiFrameworkSource - { - public IEnumerable Frameworks { get; set; } = DotNetCliTargetFrameworks; - public string NUnitVersion { get; set; } = NUnit3; + public class SingleFrameworkSource + { + public string Framework { get; set; } = LowestNetfxTarget; + public string NUnitVersion { get; set; } = NUnit4; - public static IEnumerable LegacyDotNetFrameworks => new List { new() }; + public static IEnumerable NetFxFramework => new List { new() }; - public static IEnumerable ModernDotNetFrameworks => new List + public static IEnumerable LegacyDotNetFramework => new List + { + new () { - new () - { - Frameworks = ModernDotNetCliTargetFrameworks, - NUnitVersion = NUnit4 - } - }; + Framework = Frameworks.NetCoreApp31, + NUnitVersion = NUnit3 + }, + new () + { + Framework = Frameworks.Net50, + NUnitVersion = NUnit3 + } + }; - public static IEnumerable NetFxFrameworks => new List + public static IEnumerable ModernDotNetFramework => new List + { + new () { - new () - { - Frameworks = new List { LowestNetfxTarget }, - NUnitVersion = NUnit4 - } - }; + Framework = Frameworks.Net60, + NUnitVersion = NUnit4 + }, + new () + { + Framework = Frameworks.Net70, + NUnitVersion = NUnit4 + }, + new () + { + Framework = Frameworks.Net80, + NUnitVersion = NUnit4 + } + }; - public static IEnumerable AllFrameworks => LegacyDotNetFrameworks.Concat(ModernDotNetFrameworks).Concat(NetFxFrameworks); - } + public static IEnumerable AllFrameworks => NetFxFramework.Concat(LegacyDotNetFramework).Concat(ModernDotNetFramework); + public static IEnumerable AllFrameworksExceptNetFx => LegacyDotNetFramework.Concat(ModernDotNetFramework); + } - public class SingleFrameworkSource + protected string NUnitVersion(string targetFramework) => + targetFramework switch { - public string Framework { get; set; } = LowestNetfxTarget; - public string NUnitVersion { get; set; } = NUnit4; - - public static IEnumerable NetFxFramework => new List { new() }; + Frameworks.NetCoreApp31 + or Frameworks.Net50 => NUnit3, + _ => NUnit4, + }; - public static IEnumerable LegacyDotNetFramework => new List - { - new () - { - Framework = Frameworks.NetCoreApp31, - NUnitVersion = NUnit3 - }, - new () - { - Framework = Frameworks.Net50, - NUnitVersion = NUnit3 - } - }; + private static readonly Lazy<(IsolatedWorkspaceManager Manager, string NupkgVersion, bool KeepWorkspaces)> Initialization = new(() => + { + var directory = TestContext.Parameters["ProjectWorkspaceDirectory"] + ?? TryAutoDetectProjectWorkspaceDirectory() + ?? throw new InvalidOperationException("The test parameter ProjectWorkspaceDirectory must be set in order to run this test."); + + var nupkgDirectory = TestContext.Parameters["TestNupkgDirectory"] + ?? TryAutoDetectTestNupkgDirectory(NuGetPackageId) + ?? throw new InvalidOperationException("The test parameter TestNupkgDirectory must be set in order to run this test."); + + var nupkgVersion = TryGetTestNupkgVersion(nupkgDirectory, packageId: NuGetPackageId) + ?? throw new InvalidOperationException($"No NuGet package with the ID {NuGetPackageId} was found in {nupkgDirectory}."); + + var keepWorkspaces = TestContext.Parameters.Get("KeepWorkspaces", defaultValue: false); + + var packageCachePath = Path.Combine(directory, ".isolatednugetcache"); + ClearCachedTestNupkgs(packageCachePath); + + var manager = new IsolatedWorkspaceManager( + reason: string.Join( + Environment.NewLine, + "Test assembly: " + typeof(AcceptanceTests).Assembly.Location, + "Runner process: " + Process.GetCurrentProcess().MainModule.FileName), + directory, + nupkgDirectory, + packageCachePath, + downloadCachePath: Path.Combine(directory, ".toolcache")); + + if (keepWorkspaces) manager.PreserveDirectory("The KeepWorkspaces test parameter was set to true."); + TestContext.WriteLine($"Directory: {directory}, NugetPackageDirectory {nupkgDirectory},NugetPackageVersion: {nupkgVersion}"); + return (manager, nupkgVersion, keepWorkspaces); + }); + + private static void ClearCachedTestNupkgs(string packageCachePath) + { + Utils.DeleteDirectoryRobust(Path.Combine(packageCachePath, NuGetPackageId)); + } - public static IEnumerable ModernDotNetFramework => new List - { - new () - { - Framework = Frameworks.Net60, - NUnitVersion = NUnit4 - }, - new () - { - Framework = Frameworks.Net70, - NUnitVersion = NUnit4 - }, - new () - { - Framework = Frameworks.Net80, - NUnitVersion = NUnit4 - } - }; + private static readonly Dictionary> WorkspacesByTestId = []; - public static IEnumerable AllFrameworks => NetFxFramework.Concat(LegacyDotNetFramework).Concat(ModernDotNetFramework); - public static IEnumerable AllFrameworksExceptNetFx => LegacyDotNetFramework.Concat(ModernDotNetFramework); - } + protected static IsolatedWorkspace CreateWorkspace() + { + var test = TestContext.CurrentContext?.Test ?? throw new InvalidOperationException("There is no current test."); + const string chars = "=()!,~-"; + string name = chars.Aggregate(test.Name, (current, ch) => current.Replace(ch, '_')); + var workspace = Initialization.Value.Manager.CreateWorkspace(name); - protected string NUnitVersion(string targetFramework) => - targetFramework switch - { - Frameworks.NetCoreApp31 - or Frameworks.Net50 => NUnit3, - _ => NUnit4, - }; - - private static readonly Lazy<(IsolatedWorkspaceManager Manager, string NupkgVersion, bool KeepWorkspaces)> Initialization = new(() => - { - var directory = TestContext.Parameters["ProjectWorkspaceDirectory"] - ?? TryAutoDetectProjectWorkspaceDirectory() - ?? throw new InvalidOperationException("The test parameter ProjectWorkspaceDirectory must be set in order to run this test."); - - var nupkgDirectory = TestContext.Parameters["TestNupkgDirectory"] - ?? TryAutoDetectTestNupkgDirectory(NuGetPackageId) - ?? throw new InvalidOperationException("The test parameter TestNupkgDirectory must be set in order to run this test."); - - var nupkgVersion = TryGetTestNupkgVersion(nupkgDirectory, packageId: NuGetPackageId) - ?? throw new InvalidOperationException($"No NuGet package with the ID {NuGetPackageId} was found in {nupkgDirectory}."); - - var keepWorkspaces = TestContext.Parameters.Get("KeepWorkspaces", defaultValue: false); - - var packageCachePath = Path.Combine(directory, ".isolatednugetcache"); - ClearCachedTestNupkgs(packageCachePath); - - var manager = new IsolatedWorkspaceManager( - reason: string.Join( - Environment.NewLine, - "Test assembly: " + typeof(AcceptanceTests).Assembly.Location, - "Runner process: " + Process.GetCurrentProcess().MainModule.FileName), - directory, - nupkgDirectory, - packageCachePath, - downloadCachePath: Path.Combine(directory, ".toolcache")); - - if (keepWorkspaces) manager.PreserveDirectory("The KeepWorkspaces test parameter was set to true."); - TestContext.WriteLine($"Directory: {directory}, NugetPackageDirectory {nupkgDirectory},NugetPackageVersion: {nupkgVersion}"); - return (manager, nupkgVersion, keepWorkspaces); - }); - - private static void ClearCachedTestNupkgs(string packageCachePath) + lock (WorkspacesByTestId) { - Utils.DeleteDirectoryRobust(Path.Combine(packageCachePath, NuGetPackageId)); + if (!WorkspacesByTestId.TryGetValue(test.ID, out var workspaces)) + WorkspacesByTestId.Add(test.ID, workspaces = []); + workspaces.Add(workspace); } + return workspace; + } - private static readonly Dictionary> WorkspacesByTestId = []; + protected static void InconclusiveOnException(Action action) + { + Assume.That(action.Invoke, Throws.Nothing); + } + + [TearDown] + public static void TearDown() + { + var test = TestContext.CurrentContext?.Test ?? throw new InvalidOperationException("There is no current test."); - protected static IsolatedWorkspace CreateWorkspace() + List workspaces; + lock (WorkspacesByTestId) { - var test = TestContext.CurrentContext?.Test ?? throw new InvalidOperationException("There is no current test."); - const string chars = "=()!,~-"; - string name = chars.Aggregate(test.Name, (current, ch) => current.Replace(ch, '_')); - var workspace = Initialization.Value.Manager.CreateWorkspace(name); + if (!WorkspacesByTestId.TryGetValue(test.ID, out workspaces)) + return; - lock (WorkspacesByTestId) - { - if (!WorkspacesByTestId.TryGetValue(test.ID, out var workspaces)) - WorkspacesByTestId.Add(test.ID, workspaces = []); - workspaces.Add(workspace); - } - return workspace; + WorkspacesByTestId.Remove(test.ID); } - protected static void InconclusiveOnException(Action action) + foreach (var workspace in workspaces) + workspace.Dispose(); + + if (TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Failed) { - Assume.That(action.Invoke, Throws.Nothing); + Initialization.Value.Manager.PreserveDirectory( + test.FullName + " failed:" + Environment.NewLine + + TestContext.CurrentContext.Result.Message.TrimEnd() + Environment.NewLine); } - - [TearDown] - public static void TearDown() + else if (!Initialization.Value.KeepWorkspaces) { - var test = TestContext.CurrentContext?.Test ?? throw new InvalidOperationException("There is no current test."); - - List workspaces; - lock (WorkspacesByTestId) - { - if (!WorkspacesByTestId.TryGetValue(test.ID, out workspaces)) - return; - - WorkspacesByTestId.Remove(test.ID); - } - foreach (var workspace in workspaces) - workspace.Dispose(); - - if (TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Failed) - { - Initialization.Value.Manager.PreserveDirectory( - test.FullName + " failed:" + Environment.NewLine - + TestContext.CurrentContext.Result.Message.TrimEnd() + Environment.NewLine); - } - else if (!Initialization.Value.KeepWorkspaces) - { - foreach (var workspace in workspaces) - Utils.DeleteDirectoryRobust(workspace.Directory); - } + Utils.DeleteDirectoryRobust(workspace.Directory); } + } - internal static void OnGlobalTeardown() - { - if (!Initialization.IsValueCreated) return; + internal static void OnGlobalTeardown() + { + if (!Initialization.IsValueCreated) return; - Initialization.Value.Manager.Dispose(); - } + Initialization.Value.Manager.Dispose(); + } - private static string TryAutoDetectProjectWorkspaceDirectory() + private static string TryAutoDetectProjectWorkspaceDirectory() + { + for (var directory = TestContext.CurrentContext.TestDirectory; directory != null; directory = Path.GetDirectoryName(directory)) { - for (var directory = TestContext.CurrentContext.TestDirectory; directory != null; directory = Path.GetDirectoryName(directory)) + if (File.Exists(Path.Combine(directory, "build.cake"))) { - if (File.Exists(Path.Combine(directory, "build.cake"))) - { - return Path.Combine(directory, ".acceptance"); - } + return Path.Combine(directory, ".acceptance"); } - - return null; } - private static string TryAutoDetectTestNupkgDirectory(string packageId) + return null; + } + + private static string TryAutoDetectTestNupkgDirectory(string packageId) + { + // Keep in sync with build.cake. + + // Search for it + for (var directory = TestContext.CurrentContext.TestDirectory; directory != null; directory = Path.GetDirectoryName(directory)) { - // Keep in sync with build.cake. + var packagePath = Path.Combine(directory, "package"); - // Search for it - for (var directory = TestContext.CurrentContext.TestDirectory; directory != null; directory = Path.GetDirectoryName(directory)) + try { - var packagePath = Path.Combine(directory, "package"); - - try - { - if (Directory.EnumerateFiles(Path.Combine(directory, "package"), packageId + ".*.nupkg").Any()) - { - return packagePath; - } - } - catch (DirectoryNotFoundException) + if (Directory.EnumerateFiles(Path.Combine(directory, "package"), packageId + ".*.nupkg").Any()) { + return packagePath; } } - - return null; + catch (DirectoryNotFoundException) + { + } } - private static string TryGetTestNupkgVersion(string directory, string packageId) - { - var dir = new DirectoryInfo(directory); - var packages = dir.EnumerateFiles(packageId + ".*.nupkg").ToList(); - var selected = packages.Count > 1 ? packages.OrderByDescending(f => f.LastWriteTime).First() : packages.SingleOrDefault(); + return null; + } + + private static string TryGetTestNupkgVersion(string directory, string packageId) + { + var dir = new DirectoryInfo(directory); + var packages = dir.EnumerateFiles(packageId + ".*.nupkg").ToList(); + var selected = packages.Count > 1 ? packages.OrderByDescending(f => f.LastWriteTime).First() : packages.SingleOrDefault(); - var path = selected?.FullName; + var path = selected?.FullName; - return path is null ? null : - Path.GetFileNameWithoutExtension(path).Substring(packageId.Length + 1); - } + return path is null ? null : + Path.GetFileNameWithoutExtension(path).Substring(packageId.Length + 1); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/AcceptanceTestsTeardownFixture.cs b/src/NUnit.TestAdapter.Tests.Acceptance/AcceptanceTestsTeardownFixture.cs index 7c97a49e..1c8dc83a 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/AcceptanceTestsTeardownFixture.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/AcceptanceTestsTeardownFixture.cs @@ -1,15 +1,14 @@ using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +// https://github.com/nunit/nunit/issues/3166 +[SetUpFixture] +public sealed class AcceptanceTestsTeardownFixture { - // https://github.com/nunit/nunit/issues/3166 - [SetUpFixture] - public sealed class AcceptanceTestsTeardownFixture + [OneTimeTearDown] + public static void OneTimeTearDown() { - [OneTimeTearDown] - public static void OneTimeTearDown() - { - AcceptanceTests.OnGlobalTeardown(); - } + AcceptanceTests.OnGlobalTeardown(); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/BundledDependencyTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/BundledDependencyTests.cs index d2b94421..968c07eb 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/BundledDependencyTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/BundledDependencyTests.cs @@ -1,15 +1,15 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public sealed class BundledDependencyTests : AcceptanceTests { - public sealed class BundledDependencyTests : AcceptanceTests + [Test, Platform("Win")] + public static void User_tests_get_the_version_of_Mono_Cecil_referenced_from_the_test_project() { - [Test, Platform("Win")] - public static void User_tests_get_the_version_of_Mono_Cecil_referenced_from_the_test_project() - { - var workspace = CreateWorkspace() - .AddProject("Test.csproj", $@" + var workspace = CreateWorkspace() + .AddProject("Test.csproj", $@" @@ -28,7 +28,7 @@ public static void User_tests_get_the_version_of_Mono_Cecil_referenced_from_the_ ") - .AddFile("BundledDependencyTests.cs", @" + .AddFile("BundledDependencyTests.cs", @" using System.Diagnostics; using System.Reflection; using NUnit.Framework; @@ -50,19 +50,19 @@ public static void User_tests_get_the_version_of_Mono_Cecil_referenced_from_the_ } }"); - workspace.MsBuild(restore: true); + workspace.MsBuild(restore: true); - foreach (var targetFramework in TargetFrameworks) - { - workspace.VSTest($@"bin\Debug\{targetFramework}\Test.dll", VsTestFilter.NoFilter); - } + foreach (var targetFramework in TargetFrameworks) + { + workspace.VSTest($@"bin\Debug\{targetFramework}\Test.dll", VsTestFilter.NoFilter); } + } - [Test, Platform("Win")] - public static void Engine_uses_its_bundled_version_of_Mono_Cecil_instead_of_the_version_referenced_by_the_test_project() - { - var workspace = CreateWorkspace() - .AddProject("Test.csproj", $@" + [Test, Platform("Win")] + public static void Engine_uses_its_bundled_version_of_Mono_Cecil_instead_of_the_version_referenced_by_the_test_project() + { + var workspace = CreateWorkspace() + .AddProject("Test.csproj", $@" @@ -89,7 +89,7 @@ public static void Engine_uses_its_bundled_version_of_Mono_Cecil_instead_of_the_ ") - .AddFile("BundledDependencyTests.cs", @" + .AddFile("BundledDependencyTests.cs", @" using System.Diagnostics; using System.Reflection; using NUnit.Framework; @@ -110,7 +110,7 @@ public void Engine_uses_its_bundled_version_of_Mono_Cecil_instead_of_the_version Assert.That(versionBlock.ProductVersion, Is.EqualTo(""0.10.0.0"")); } }") - .AddFile("TestNUnitEngineExtension.cs", @" + .AddFile("TestNUnitEngineExtension.cs", @" using NUnit.Engine; using NUnit.Engine.Extensibility; @@ -125,15 +125,14 @@ public void OnTestEvent(string report) { } }") - .AddFile("test.addins", @" + .AddFile("test.addins", @" Test.dll"); - workspace.MsBuild(restore: true); + workspace.MsBuild(restore: true); - foreach (var targetFramework in TargetFrameworks) - { - workspace.VSTest($@"bin\Debug\{targetFramework}\Test.dll", VsTestFilter.NoFilter); - } + foreach (var targetFramework in TargetFrameworks) + { + workspace.VSTest($@"bin\Debug\{targetFramework}\Test.dll", VsTestFilter.NoFilter); } } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/ConsoleOutTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/ConsoleOutTests.cs index 33090440..dcece252 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/ConsoleOutTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/ConsoleOutTests.cs @@ -1,12 +1,12 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public sealed class ConsoleOutTests : CsProjAcceptanceTests { - public sealed class ConsoleOutTests : CsProjAcceptanceTests + protected override void AddTestsCs(IsolatedWorkspace workspace) { - protected override void AddTestsCs(IsolatedWorkspace workspace) - { workspace.AddFile("Issue774.cs", @" using System; using NUnit.Framework; @@ -32,22 +32,21 @@ public void Test2() }"); } - protected override string Framework => Frameworks.NetCoreApp31; + protected override string Framework => Frameworks.NetCoreApp31; - [Test, Platform("Win")] - public void DotNetTest() - { + [Test, Platform("Win")] + public void DotNetTest() + { var workspace = Build(); var results = workspace.DotNetTest("", true, true, TestContext.WriteLine); Verify(2, 2, results); } - [Test, Platform("Win")] - public void VsTest() - { + [Test, Platform("Win")] + public void VsTest() + { var workspace = Build(); var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", VsTestFilter.NoFilter); Verify(2, 2, results); } - } } \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/CsProjAcceptanceTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/CsProjAcceptanceTests.cs index c8103052..d3c1af7b 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/CsProjAcceptanceTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/CsProjAcceptanceTests.cs @@ -1,18 +1,18 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public abstract class CsProjAcceptanceTests : AcceptanceTests { - public abstract class CsProjAcceptanceTests : AcceptanceTests - { - protected abstract void AddTestsCs(IsolatedWorkspace workspace); + protected abstract void AddTestsCs(IsolatedWorkspace workspace); - protected abstract string Framework { get; } - protected const string NoFilter = ""; - protected IsolatedWorkspace CreateTestWorkspace(string framework) - { - var workspace = CreateWorkspace() - .AddProject("Test.csproj", $@" + protected abstract string Framework { get; } + protected const string NoFilter = ""; + protected IsolatedWorkspace CreateTestWorkspace(string framework) + { + var workspace = CreateWorkspace() + .AddProject("Test.csproj", $@" @@ -26,30 +26,29 @@ protected IsolatedWorkspace CreateTestWorkspace(string framework) "); - return workspace; - } + return workspace; + } - protected IsolatedWorkspace Build() - { - var workspace = CreateTestWorkspace(Framework); - AddTestsCs(workspace); - workspace.MsBuild(restore: true); - return workspace; - } + protected IsolatedWorkspace Build() + { + var workspace = CreateTestWorkspace(Framework); + AddTestsCs(workspace); + workspace.MsBuild(restore: true); + return workspace; + } - protected void Verify(int executed, int total, VSTestResult results) + protected void Verify(int executed, int total, VSTestResult results) + { + TestContext.WriteLine(" "); + foreach (var error in results.RunErrors) + TestContext.WriteLine(error); + Assert.Multiple(() => { - TestContext.WriteLine(" "); - foreach (var error in results.RunErrors) - TestContext.WriteLine(error); - Assert.Multiple(() => - { - Assert.That(results.Counters.Total, Is.EqualTo(total), - $"Total tests counter did not match expectation\n{results.ProcessRunResult.StdOut}"); - Assert.That(results.Counters.Executed, Is.EqualTo(executed), - "Executed tests counter did not match expectation"); - Assert.That(results.Counters.Passed, Is.EqualTo(executed), "Passed tests counter did not match expectation"); - }); - } + Assert.That(results.Counters.Total, Is.EqualTo(total), + $"Total tests counter did not match expectation\n{results.ProcessRunResult.StdOut}"); + Assert.That(results.Counters.Executed, Is.EqualTo(executed), + "Executed tests counter did not match expectation"); + Assert.That(results.Counters.Passed, Is.EqualTo(executed), "Passed tests counter did not match expectation"); + }); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/DirectoryMutex.cs b/src/NUnit.TestAdapter.Tests.Acceptance/DirectoryMutex.cs index bbd87735..7fa37656 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/DirectoryMutex.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/DirectoryMutex.cs @@ -1,37 +1,36 @@ using System; using System.IO; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public sealed class DirectoryMutex : IDisposable { - public sealed class DirectoryMutex : IDisposable + private readonly FileStream mutexFile; + + public static DirectoryMutex TryAcquire(string directoryPath) { - private readonly FileStream mutexFile; + var mutexFilePath = Path.Combine(directoryPath, ".mutex"); - public static DirectoryMutex TryAcquire(string directoryPath) + FileStream stream; + try { - var mutexFilePath = Path.Combine(directoryPath, ".mutex"); - - FileStream stream; - try - { - stream = new FileStream(mutexFilePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 1, FileOptions.DeleteOnClose); - } - catch (IOException) // On Windows, (ushort)ex.HResult will be ERROR_SHARING_VIOLATION - { - return null; - } - - return new DirectoryMutex(stream, directoryPath); + stream = new FileStream(mutexFilePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 1, FileOptions.DeleteOnClose); } - - private DirectoryMutex(FileStream mutexFile, string directoryPath) + catch (IOException) // On Windows, (ushort)ex.HResult will be ERROR_SHARING_VIOLATION { - this.mutexFile = mutexFile ?? throw new ArgumentNullException(nameof(mutexFile)); - DirectoryPath = directoryPath ?? throw new ArgumentNullException(nameof(directoryPath)); + return null; } - public string DirectoryPath { get; } + return new DirectoryMutex(stream, directoryPath); + } - public void Dispose() => mutexFile.Dispose(); + private DirectoryMutex(FileStream mutexFile, string directoryPath) + { + this.mutexFile = mutexFile ?? throw new ArgumentNullException(nameof(mutexFile)); + DirectoryPath = directoryPath ?? throw new ArgumentNullException(nameof(directoryPath)); } -} + + public string DirectoryPath { get; } + + public void Dispose() => mutexFile.Dispose(); +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/FilterTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/FilterTests.cs index 7a4a1c81..b7129265 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/FilterTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/FilterTests.cs @@ -1,12 +1,12 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public sealed class FilterTests : CsProjAcceptanceTests { - public sealed class FilterTests : CsProjAcceptanceTests + protected override void AddTestsCs(IsolatedWorkspace workspace) { - protected override void AddTestsCs(IsolatedWorkspace workspace) - { workspace.AddFile("Tests.cs", @" using NUnit.Framework; @@ -36,57 +36,56 @@ public void Bar() }"); } - protected override string Framework => Frameworks.NetCoreApp31; + protected override string Framework => Frameworks.NetCoreApp31; - [Test, Platform("Win")] - [TestCase(NoFilter, 2, 3)] - [TestCase(@"TestCategory=FooGroup", 1, 2)] - [TestCase(@"TestCategory!=BarGroup", 1, 2)] - [TestCase(@"TestCategory=IsExplicit", 1, 1)] - [TestCase(@"FullyQualifiedName=Filter.Tests.Foo", 1, 1)] - [TestCase(@"FullyQualifiedName!=Filter.Tests.Foo", 1, 1)] - [TestCase(@"TestCategory!=AllGroup", 0, 0)] - // [TestCase(@"TestThatDontExistHere", 0, 0)] - // [TestCase(@"FullyQualifiedName~Filter.Tests.Foo", 1, 1)] - // [TestCase(@"FullyQualifiedName~Foo", 1, 1)] - public void Filter_DotNetTest(string filter, int executed, int total) - { + [Test, Platform("Win")] + [TestCase(NoFilter, 2, 3)] + [TestCase(@"TestCategory=FooGroup", 1, 2)] + [TestCase(@"TestCategory!=BarGroup", 1, 2)] + [TestCase(@"TestCategory=IsExplicit", 1, 1)] + [TestCase(@"FullyQualifiedName=Filter.Tests.Foo", 1, 1)] + [TestCase(@"FullyQualifiedName!=Filter.Tests.Foo", 1, 1)] + [TestCase(@"TestCategory!=AllGroup", 0, 0)] + // [TestCase(@"TestThatDontExistHere", 0, 0)] + // [TestCase(@"FullyQualifiedName~Filter.Tests.Foo", 1, 1)] + // [TestCase(@"FullyQualifiedName~Foo", 1, 1)] + public void Filter_DotNetTest(string filter, int executed, int total) + { var workspace = Build(); var results = workspace.DotNetTest(filter, true, true, TestContext.WriteLine); Verify(executed, total, results); } - [Test, Platform("Win")] - [TestCase(NoFilter, 2, 3)] - [TestCase(@"TestCategory=FooGroup", 1, 2)] - [TestCase(@"TestCategory!=BarGroup", 1, 2)] - [TestCase(@"TestCategory=IsExplicit", 1, 1)] - [TestCase(@"FullyQualifiedName=Filter.Tests.Foo", 1, 1)] - [TestCase(@"TestCategory=XXXX", 0, 0)] - public void Filter_VSTest(string filter, int executed, int total) - { + [Test, Platform("Win")] + [TestCase(NoFilter, 2, 3)] + [TestCase(@"TestCategory=FooGroup", 1, 2)] + [TestCase(@"TestCategory!=BarGroup", 1, 2)] + [TestCase(@"TestCategory=IsExplicit", 1, 1)] + [TestCase(@"FullyQualifiedName=Filter.Tests.Foo", 1, 1)] + [TestCase(@"TestCategory=XXXX", 0, 0)] + public void Filter_VSTest(string filter, int executed, int total) + { var workspace = Build(); var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", new VsTestTestCaseFilter(filter)); Verify(executed, total, results); } - [Test, Platform("Win")] - [TestCase(NoFilter, 2, 3)] - [TestCase("Category=FooGroup", 1, 1)] - [TestCase("cat==FooGroup", 1, 2)] - [TestCase("cat!=FooGroup", 1, 1)] - [TestCase("Category!=BarGroup", 1, 1)] - [TestCase("Category=IsExplicit", 1, 1)] - [TestCase("test==Filter.Tests.Foo", 1, 1)] - [TestCase("name==Foo", 1, 1)] - [TestCase("name!=Bar", 1, 1)] - // [TestCase("test=~Foo", 1, 1)] - public void Filter_DotNetTest_NUnitWhere(string filter, int executed, int total) - { + [Test, Platform("Win")] + [TestCase(NoFilter, 2, 3)] + [TestCase("Category=FooGroup", 1, 1)] + [TestCase("cat==FooGroup", 1, 2)] + [TestCase("cat!=FooGroup", 1, 1)] + [TestCase("Category!=BarGroup", 1, 1)] + [TestCase("Category=IsExplicit", 1, 1)] + [TestCase("test==Filter.Tests.Foo", 1, 1)] + [TestCase("name==Foo", 1, 1)] + [TestCase("name!=Bar", 1, 1)] + // [TestCase("test=~Foo", 1, 1)] + public void Filter_DotNetTest_NUnitWhere(string filter, int executed, int total) + { var workspace = Build(); var nunitWhere = $@"NUnit.Where={filter}"; var results = workspace.DotNetTest(nunitWhere, true, true, TestContext.WriteLine); Verify(executed, total, results); } - } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/FixtureTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/FixtureTests.cs index 0b894760..3b47ee7b 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/FixtureTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/FixtureTests.cs @@ -1,12 +1,12 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public sealed class FixtureTests : CsProjAcceptanceTests { - public sealed class FixtureTests : CsProjAcceptanceTests + protected override void AddTestsCs(IsolatedWorkspace workspace) { - protected override void AddTestsCs(IsolatedWorkspace workspace) - { workspace.AddFile("Issue918.cs", @" using System; using NUnit.Framework; @@ -107,28 +107,27 @@ public void Test() }"); } - protected override string Framework => Frameworks.NetCoreApp31; + protected override string Framework => Frameworks.NetCoreApp31; - [Test, Platform("Win")] - [TestCase("TestCategory=869", 2, 2)] - [TestCase("TestCategory=884", 3, 3)] - [TestCase("TestCategory=918", 1, 1)] - public void DotNetTest(string filter, int executed, int total) - { + [Test, Platform("Win")] + [TestCase("TestCategory=869", 2, 2)] + [TestCase("TestCategory=884", 3, 3)] + [TestCase("TestCategory=918", 1, 1)] + public void DotNetTest(string filter, int executed, int total) + { var workspace = Build(); var results = workspace.DotNetTest(filter, true, true, TestContext.WriteLine); Verify(executed, total, results); } - [Test, Platform("Win")] - [TestCase("TestCategory=869", 2, 2)] - [TestCase("TestCategory=884", 3, 3)] - [TestCase("TestCategory=918", 1, 1)] - public void VsTest(string filter, int executed, int total) - { + [Test, Platform("Win")] + [TestCase("TestCategory=869", 2, 2)] + [TestCase("TestCategory=884", 3, 3)] + [TestCase("TestCategory=918", 1, 1)] + public void VsTest(string filter, int executed, int total) + { var workspace = Build(); var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", new VsTestTestCaseFilter(filter)); Verify(executed, total, results); } - } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/ParanthesisTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/ParanthesisTests.cs index 232646b2..e16fac7d 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/ParanthesisTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/ParanthesisTests.cs @@ -1,13 +1,13 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public sealed class ParanthesisTests : CsProjAcceptanceTests { - public sealed class ParanthesisTests : CsProjAcceptanceTests + protected override void AddTestsCs(IsolatedWorkspace workspace) { - protected override void AddTestsCs(IsolatedWorkspace workspace) - { - workspace.AddFile("Issue919.cs", @" + workspace.AddFile("Issue919.cs", @" using System; using NUnit.Framework; @@ -28,59 +28,58 @@ public void Bzzt() } } }"); - } + } - protected override string Framework => Frameworks.NetCoreApp31; + protected override string Framework => Frameworks.NetCoreApp31; - [Test, Platform("Win")] - [TestCase] - public void VsTestNoFilter() - { - var workspace = Build(); - var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", VsTestFilter.NoFilter); - Verify(2, 2, results); - } + [Test, Platform("Win")] + [TestCase] + public void VsTestNoFilter() + { + var workspace = Build(); + var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", VsTestFilter.NoFilter); + Verify(2, 2, results); + } - [Test, Platform("Win")] - [TestCase(@"FullyQualifiedName=Issue919.Foo.Bzzt", 1, 1)] // Sanity check - [TestCase(@"FullyQualifiedName=Issue919.Foo.Bar\(1\)", 0, 0)] - [TestCase(@"FullyQualifiedName=Issue919.Foo.Baz\(1\)", 1, 1)] - [TestCase(@"Name=Bzzt", 1, 1)] // Sanity check - [TestCase(@"Name=Bar\(1\)", 0, 0)] - [TestCase(@"Name=Baz\(1\)", 1, 1)] - [TestCase(@"", 2, 2)] - public void VsTestTestCases(string filter, int executed, int total) - { - var workspace = Build(); - workspace.DumpTestExecution = true; - var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", new VsTestTestCaseFilter(filter)); - Verify(executed, total, results); - } + [Test, Platform("Win")] + [TestCase(@"FullyQualifiedName=Issue919.Foo.Bzzt", 1, 1)] // Sanity check + [TestCase(@"FullyQualifiedName=Issue919.Foo.Bar\(1\)", 0, 0)] + [TestCase(@"FullyQualifiedName=Issue919.Foo.Baz\(1\)", 1, 1)] + [TestCase(@"Name=Bzzt", 1, 1)] // Sanity check + [TestCase(@"Name=Bar\(1\)", 0, 0)] + [TestCase(@"Name=Baz\(1\)", 1, 1)] + [TestCase(@"", 2, 2)] + public void VsTestTestCases(string filter, int executed, int total) + { + var workspace = Build(); + workspace.DumpTestExecution = true; + var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", new VsTestTestCaseFilter(filter)); + Verify(executed, total, results); + } - [Test, Platform("Win")] - [TestCase(@"Bzzt", 1, 1)] // Sanity check - [TestCase(@"Bar\(1\)", 0, 0)] - [TestCase(@"Baz\(1\)", 1, 1)] - public void VsTestTests(string filter, int executed, int total) - { - var workspace = Build(); - var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", new VsTestTestsFilter(filter)); - Verify(executed, total, results); - } + [Test, Platform("Win")] + [TestCase(@"Bzzt", 1, 1)] // Sanity check + [TestCase(@"Bar\(1\)", 0, 0)] + [TestCase(@"Baz\(1\)", 1, 1)] + public void VsTestTests(string filter, int executed, int total) + { + var workspace = Build(); + var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", new VsTestTestsFilter(filter)); + Verify(executed, total, results); + } - [Test, Platform("Win")] - [TestCase(@"FullyQualifiedName=Issue919.Foo.Bzzt", 1, 1)] // Sanity check - [TestCase(@"FullyQualifiedName=Issue919.Foo.Bar\(1\)", 0, 0)] - [TestCase(@"FullyQualifiedName=Issue919.Foo.Baz\(1\)", 1, 1)] - [TestCase(@"Name=Bzzt", 1, 1)] // Sanity check - [TestCase(@"Name=Bar\(1\)", 0, 0)] - [TestCase(@"Name=Baz\(1\)", 1, 1)] - [TestCase(@"", 2, 2)] - public void DotnetTestCases(string filter, int executed, int total) - { - var workspace = Build(); - var results = workspace.DotNetTest(filter, true, true, TestContext.WriteLine); - Verify(executed, total, results); - } + [Test, Platform("Win")] + [TestCase(@"FullyQualifiedName=Issue919.Foo.Bzzt", 1, 1)] // Sanity check + [TestCase(@"FullyQualifiedName=Issue919.Foo.Bar\(1\)", 0, 0)] + [TestCase(@"FullyQualifiedName=Issue919.Foo.Baz\(1\)", 1, 1)] + [TestCase(@"Name=Bzzt", 1, 1)] // Sanity check + [TestCase(@"Name=Bar\(1\)", 0, 0)] + [TestCase(@"Name=Baz\(1\)", 1, 1)] + [TestCase(@"", 2, 2)] + public void DotnetTestCases(string filter, int executed, int total) + { + var workspace = Build(); + var results = workspace.DotNetTest(filter, true, true, TestContext.WriteLine); + Verify(executed, total, results); } } \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/PropertyTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/PropertyTests.cs index 95afad49..7f29363e 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/PropertyTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/PropertyTests.cs @@ -1,13 +1,13 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public sealed class PropertyTests : CsProjAcceptanceTests { - public sealed class PropertyTests : CsProjAcceptanceTests + protected override void AddTestsCs(IsolatedWorkspace workspace) { - protected override void AddTestsCs(IsolatedWorkspace workspace) - { - workspace.AddFile("Issue779.cs", @" + workspace.AddFile("Issue779.cs", @" using System; using NUnit.Framework; @@ -29,30 +29,29 @@ public void Test2() } } }"); - } + } - protected override string Framework => Frameworks.NetCoreApp31; + protected override string Framework => Frameworks.NetCoreApp31; - [Test, Platform("Win")] - [TestCase("Bug=99999", 0, 0)] - [TestCase("Bug=12345", 1, 1)] - [TestCase("Bug!=12345", 1, 1)] - public void DotNetTest(string filter, int executed, int total) - { - var workspace = Build(); - var results = workspace.DotNetTest(filter, true, true, TestContext.WriteLine); - Verify(executed, total, results); - } + [Test, Platform("Win")] + [TestCase("Bug=99999", 0, 0)] + [TestCase("Bug=12345", 1, 1)] + [TestCase("Bug!=12345", 1, 1)] + public void DotNetTest(string filter, int executed, int total) + { + var workspace = Build(); + var results = workspace.DotNetTest(filter, true, true, TestContext.WriteLine); + Verify(executed, total, results); + } - [Test, Platform("Win")] - [TestCase("Bug=99999", 0, 0)] - [TestCase("Bug=12345", 1, 1)] - [TestCase("Bug!=12345", 1, 1)] - public void VsTest(string filter, int executed, int total) - { - var workspace = Build(); - var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", new VsTestTestCaseFilter(filter)); - Verify(executed, total, results); - } + [Test, Platform("Win")] + [TestCase("Bug=99999", 0, 0)] + [TestCase("Bug=12345", 1, 1)] + [TestCase("Bug!=12345", 1, 1)] + public void VsTest(string filter, int executed, int total) + { + var workspace = Build(); + var results = workspace.VSTest($@"bin\Debug\{Framework}\Test.dll", new VsTestTestCaseFilter(filter)); + Verify(executed, total, results); } } \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/SinglePassingTestResultTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/SinglePassingTestResultTests.cs index 744021b1..6e79061d 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/SinglePassingTestResultTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/SinglePassingTestResultTests.cs @@ -1,13 +1,13 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public sealed class SinglePassingTestResultTests : AcceptanceTests { - public sealed class SinglePassingTestResultTests : AcceptanceTests + private void AddTestsCs(IsolatedWorkspace workspace) { - private void AddTestsCs(IsolatedWorkspace workspace) - { - workspace.AddFile("Tests.cs", @" + workspace.AddFile("Tests.cs", @" using NUnit.Framework; namespace Test @@ -21,11 +21,11 @@ public void PassingTest() } } }"); - } + } - private void AddTestsVb(IsolatedWorkspace workspace) - { - workspace.AddFile("Tests.vb", @" + private void AddTestsVb(IsolatedWorkspace workspace) + { + workspace.AddFile("Tests.vb", @" Imports NUnit.Framework Namespace Test @@ -38,11 +38,11 @@ End Sub End Class End Namespace"); - } + } - private IsolatedWorkspace CreateSingleTargetWorkspace(string fileName, SingleFrameworkSource source) => - CreateWorkspace() - .AddProject(fileName, $@" + private IsolatedWorkspace CreateSingleTargetWorkspace(string fileName, SingleFrameworkSource source) => + CreateWorkspace() + .AddProject(fileName, $@" @@ -58,49 +58,49 @@ End Class "); - [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworks))] - [Platform("Win")] - public void Single_target_csproj(SingleFrameworkSource source) - { - var workspace = CreateSingleTargetWorkspace("Test.csproj", source); - AddTestsCs(workspace); - workspace.MsBuild(restore: true); - workspace.VSTest($@"bin\Debug\{source.Framework}\Test.dll", VsTestFilter.NoFilter) - .AssertSinglePassingTest(); - } + [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworks))] + [Platform("Win")] + public void Single_target_csproj(SingleFrameworkSource source) + { + var workspace = CreateSingleTargetWorkspace("Test.csproj", source); + AddTestsCs(workspace); + workspace.MsBuild(restore: true); + workspace.VSTest($@"bin\Debug\{source.Framework}\Test.dll", VsTestFilter.NoFilter) + .AssertSinglePassingTest(); + } - [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworksExceptNetFx))] - [Platform("Win")] - public void Single_target_csproj_dotnet_CLI(SingleFrameworkSource source) - { - var workspace = CreateSingleTargetWorkspace("Test.csproj", source); - AddTestsCs(workspace); - workspace.DotNetTest().AssertSinglePassingTest(); - } + [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworksExceptNetFx))] + [Platform("Win")] + public void Single_target_csproj_dotnet_CLI(SingleFrameworkSource source) + { + var workspace = CreateSingleTargetWorkspace("Test.csproj", source); + AddTestsCs(workspace); + workspace.DotNetTest().AssertSinglePassingTest(); + } - [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworks))] - [Platform("Win")] - public void Single_target_vbproj(SingleFrameworkSource source) - { - var workspace = CreateSingleTargetWorkspace("Test.vbproj", source); - AddTestsVb(workspace); - workspace.MsBuild(restore: true); - workspace.VSTest($@"bin\Debug\{source.Framework}\Test.dll", VsTestFilter.NoFilter) - .AssertSinglePassingTest(); - } + [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworks))] + [Platform("Win")] + public void Single_target_vbproj(SingleFrameworkSource source) + { + var workspace = CreateSingleTargetWorkspace("Test.vbproj", source); + AddTestsVb(workspace); + workspace.MsBuild(restore: true); + workspace.VSTest($@"bin\Debug\{source.Framework}\Test.dll", VsTestFilter.NoFilter) + .AssertSinglePassingTest(); + } - [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworksExceptNetFx))] - [Platform("Win")] - public void Single_target_vbproj_dotnet_CLI(SingleFrameworkSource source) - { - var workspace = CreateSingleTargetWorkspace("Test.vbproj", source); - AddTestsVb(workspace); - workspace.DotNetTest().AssertSinglePassingTest(); - } + [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworksExceptNetFx))] + [Platform("Win")] + public void Single_target_vbproj_dotnet_CLI(SingleFrameworkSource source) + { + var workspace = CreateSingleTargetWorkspace("Test.vbproj", source); + AddTestsVb(workspace); + workspace.DotNetTest().AssertSinglePassingTest(); + } - private IsolatedWorkspace CreateMultiTargetWorkspace(string fileName, MultiFrameworkSource source) => - CreateWorkspace() - .AddProject(fileName, $@" + private IsolatedWorkspace CreateMultiTargetWorkspace(string fileName, MultiFrameworkSource source) => + CreateWorkspace() + .AddProject(fileName, $@" @@ -115,58 +115,58 @@ public void Single_target_vbproj_dotnet_CLI(SingleFrameworkSource source) "); - [TestCaseSource(typeof(MultiFrameworkSource), nameof(MultiFrameworkSource.AllFrameworks))] - [Platform("Win")] - public void Multi_target_csproj(MultiFrameworkSource source) - { - var workspace = CreateMultiTargetWorkspace("Test.csproj", source); - AddTestsCs(workspace); - workspace.MsBuild(restore: true); - - foreach (var targetFramework in source.Frameworks) - { - workspace.VSTest($@"bin\Debug\{targetFramework}\Test.dll", VsTestFilter.NoFilter) - .AssertSinglePassingTest(); - } - } + [TestCaseSource(typeof(MultiFrameworkSource), nameof(MultiFrameworkSource.AllFrameworks))] + [Platform("Win")] + public void Multi_target_csproj(MultiFrameworkSource source) + { + var workspace = CreateMultiTargetWorkspace("Test.csproj", source); + AddTestsCs(workspace); + workspace.MsBuild(restore: true); - [TestCaseSource(typeof(MultiFrameworkSource), nameof(MultiFrameworkSource.AllFrameworks))] - public void Multi_target_csproj_dotnet_CLI(MultiFrameworkSource source) + foreach (var targetFramework in source.Frameworks) { - var workspace = CreateMultiTargetWorkspace("Test.csproj", source); - AddTestsCs(workspace); - workspace.DotNetTest().AssertSinglePassingTest(); + workspace.VSTest($@"bin\Debug\{targetFramework}\Test.dll", VsTestFilter.NoFilter) + .AssertSinglePassingTest(); } + } - [TestCaseSource(typeof(MultiFrameworkSource), nameof(MultiFrameworkSource.AllFrameworks))] - [Platform("Win")] - public void Multi_target_vbproj(MultiFrameworkSource source) - { - var workspace = CreateMultiTargetWorkspace("Test.vbproj", source); - AddTestsVb(workspace); - workspace.MsBuild(restore: true); - - foreach (var targetFramework in source.Frameworks) - { - workspace.VSTest($@"bin\Debug\{targetFramework}\Test.dll", VsTestFilter.NoFilter) - .AssertSinglePassingTest(); - } - } + [TestCaseSource(typeof(MultiFrameworkSource), nameof(MultiFrameworkSource.AllFrameworks))] + public void Multi_target_csproj_dotnet_CLI(MultiFrameworkSource source) + { + var workspace = CreateMultiTargetWorkspace("Test.csproj", source); + AddTestsCs(workspace); + workspace.DotNetTest().AssertSinglePassingTest(); + } + + [TestCaseSource(typeof(MultiFrameworkSource), nameof(MultiFrameworkSource.AllFrameworks))] + [Platform("Win")] + public void Multi_target_vbproj(MultiFrameworkSource source) + { + var workspace = CreateMultiTargetWorkspace("Test.vbproj", source); + AddTestsVb(workspace); + workspace.MsBuild(restore: true); - [TestCaseSource(typeof(MultiFrameworkSource), nameof(MultiFrameworkSource.AllFrameworks))] - public void Multi_target_vbproj_dotnet_CLI(MultiFrameworkSource source) + foreach (var targetFramework in source.Frameworks) { - var workspace = CreateMultiTargetWorkspace("Test.vbproj", source); - AddTestsVb(workspace); - workspace.DotNetTest().AssertSinglePassingTest(); + workspace.VSTest($@"bin\Debug\{targetFramework}\Test.dll", VsTestFilter.NoFilter) + .AssertSinglePassingTest(); } + } - [Test, Platform("Win")] - public void Legacy_csproj_with_PackageReference() - { - var workspace = CreateWorkspace(); - var nuvers = NuGetPackageVersion; - workspace.AddProject("Test.csproj", $@" + [TestCaseSource(typeof(MultiFrameworkSource), nameof(MultiFrameworkSource.AllFrameworks))] + public void Multi_target_vbproj_dotnet_CLI(MultiFrameworkSource source) + { + var workspace = CreateMultiTargetWorkspace("Test.vbproj", source); + AddTestsVb(workspace); + workspace.DotNetTest().AssertSinglePassingTest(); + } + + [Test, Platform("Win")] + public void Legacy_csproj_with_PackageReference() + { + var workspace = CreateWorkspace(); + var nuvers = NuGetPackageVersion; + workspace.AddProject("Test.csproj", $@" @@ -224,19 +224,19 @@ public void Legacy_csproj_with_PackageReference() "); - AddTestsCs(workspace); + AddTestsCs(workspace); - workspace.MsBuild(restore: true); + workspace.MsBuild(restore: true); - var result = workspace.VSTest(@"bin\Debug\Test.dll", VsTestFilter.NoFilter); - result.AssertSinglePassingTest(); - } + var result = workspace.VSTest(@"bin\Debug\Test.dll", VsTestFilter.NoFilter); + result.AssertSinglePassingTest(); + } - [Test, Platform("Win")] - public void Legacy_vbproj_with_PackageReference() - { - var workspace = CreateWorkspace() - .AddProject("Test.vbproj", $@" + [Test, Platform("Win")] + public void Legacy_vbproj_with_PackageReference() + { + var workspace = CreateWorkspace() + .AddProject("Test.vbproj", $@" @@ -317,17 +317,17 @@ public void Legacy_vbproj_with_PackageReference() "); - AddTestsVb(workspace); + AddTestsVb(workspace); - workspace.MsBuild(restore: true); + workspace.MsBuild(restore: true); - workspace.VSTest(@"bin\Debug\Test.dll", VsTestFilter.NoFilter) - .AssertSinglePassingTest(); - } + workspace.VSTest(@"bin\Debug\Test.dll", VsTestFilter.NoFilter) + .AssertSinglePassingTest(); + } - private static void AddPackagesConfig(IsolatedWorkspace workspace) - { - workspace.AddFile("packages.config", $@" + private static void AddPackagesConfig(IsolatedWorkspace workspace) + { + workspace.AddFile("packages.config", $@" @@ -335,13 +335,13 @@ private static void AddPackagesConfig(IsolatedWorkspace workspace) "); - } + } - [Test, Platform("Win")] - public void Legacy_csproj_with_packages_config() - { - var workspace = CreateWorkspace() - .AddProject("Test.csproj", $@" + [Test, Platform("Win")] + public void Legacy_csproj_with_packages_config() + { + var workspace = CreateWorkspace() + .AddProject("Test.csproj", $@" @@ -416,22 +416,22 @@ public void Legacy_csproj_with_packages_config() "); - AddPackagesConfig(workspace); - AddTestsCs(workspace); + AddPackagesConfig(workspace); + AddTestsCs(workspace); - workspace.NuGetRestore(packagesDirectory: "packages"); + workspace.NuGetRestore(packagesDirectory: "packages"); - workspace.MsBuild(); + workspace.MsBuild(); - workspace.VSTest(@"bin\Debug\Test.dll", VsTestFilter.NoFilter) - .AssertSinglePassingTest(); - } + workspace.VSTest(@"bin\Debug\Test.dll", VsTestFilter.NoFilter) + .AssertSinglePassingTest(); + } - [Test, Platform("Win")] - public void Legacy_vbproj_with_packages_config() - { - var workspace = CreateWorkspace() - .AddProject("Test.vbproj", $@" + [Test, Platform("Win")] + public void Legacy_vbproj_with_packages_config() + { + var workspace = CreateWorkspace() + .AddProject("Test.vbproj", $@" @@ -529,13 +529,12 @@ public void Legacy_vbproj_with_packages_config() "); - AddPackagesConfig(workspace); - AddTestsVb(workspace); + AddPackagesConfig(workspace); + AddTestsVb(workspace); - workspace.NuGetRestore(packagesDirectory: "packages"); - workspace.MsBuild(); - workspace.VSTest(@"bin\Debug\Test.dll", VsTestFilter.NoFilter) - .AssertSinglePassingTest(); - } + workspace.NuGetRestore(packagesDirectory: "packages"); + workspace.MsBuild(); + workspace.VSTest(@"bin\Debug\Test.dll", VsTestFilter.NoFilter) + .AssertSinglePassingTest(); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/TestSourceWithCustomNames.cs b/src/NUnit.TestAdapter.Tests.Acceptance/TestSourceWithCustomNames.cs index 23350df8..6caf161a 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/TestSourceWithCustomNames.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/TestSourceWithCustomNames.cs @@ -1,13 +1,13 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public sealed class TestSourceWithCustomNames : AcceptanceTests { - public sealed class TestSourceWithCustomNames : AcceptanceTests + private static void AddTestsCs(IsolatedWorkspace workspace) { - private static void AddTestsCs(IsolatedWorkspace workspace) - { - workspace.AddFile("Tests.cs", @" + workspace.AddFile("Tests.cs", @" using System; using System.Collections; using System.Collections.Generic; @@ -79,19 +79,19 @@ public class Case } }"); - } + } - [Test, Platform("Win")] - [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworks))] - public static void Single_target_csproj(SingleFrameworkSource source) - { - var valuetupleItemgroup = source.Framework is "netcoreapp3.1" or "net5.0" ? @" + [Test, Platform("Win")] + [TestCaseSource(typeof(SingleFrameworkSource), nameof(SingleFrameworkSource.AllFrameworks))] + public static void Single_target_csproj(SingleFrameworkSource source) + { + var valuetupleItemgroup = source.Framework is "netcoreapp3.1" or "net5.0" ? @" " : ""; - TestContext.WriteLine($"Testing {source.Framework}"); - var workspace = CreateWorkspace() - .AddProject("Test.csproj", $@" + TestContext.WriteLine($"Testing {source.Framework}"); + var workspace = CreateWorkspace() + .AddProject("Test.csproj", $@" @@ -109,27 +109,26 @@ public static void Single_target_csproj(SingleFrameworkSource source) "); - AddTestsCs(workspace); + AddTestsCs(workspace); - workspace.MsBuild(restore: true); + workspace.MsBuild(restore: true); - var results = workspace.VSTest($@"bin\Debug\{source.Framework}\Test.dll", VsTestFilter.NoFilter); + var results = workspace.VSTest($@"bin\Debug\{source.Framework}\Test.dll", VsTestFilter.NoFilter); - // Total Tests = - // 3 from PassingTestStr/TestCaseSourceMethod - // 1 from UnitTest_TestCaseWithTuple_TestIsNotExecuted - // 1 from TestA/SourceA - // 1 from TestB/SourceB - // 1 from TestC/SourceC - // 2 from EqualsTest/EqualsData - //------------------- - // 9 Total Tests + // Total Tests = + // 3 from PassingTestStr/TestCaseSourceMethod + // 1 from UnitTest_TestCaseWithTuple_TestIsNotExecuted + // 1 from TestA/SourceA + // 1 from TestB/SourceB + // 1 from TestC/SourceC + // 2 from EqualsTest/EqualsData + //------------------- + // 9 Total Tests - Assert.That(results.Counters.Total, Is.EqualTo(9), "Total tests counter did not match expectation"); - Assert.That(results.Counters.Executed, Is.EqualTo(9), "Executed tests counter did not match expectation"); - Assert.That(results.Counters.Passed, Is.EqualTo(9), "Passed tests counter did not match expectation"); - } + Assert.That(results.Counters.Total, Is.EqualTo(9), "Total tests counter did not match expectation"); + Assert.That(results.Counters.Executed, Is.EqualTo(9), "Executed tests counter did not match expectation"); + Assert.That(results.Counters.Passed, Is.EqualTo(9), "Passed tests counter did not match expectation"); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/Utils.cs b/src/NUnit.TestAdapter.Tests.Acceptance/Utils.cs index c14b7535..ab9e1dc0 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/Utils.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/Utils.cs @@ -4,222 +4,221 @@ using System.Text; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +internal static class Utils { - internal static class Utils + private static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars() + .Concat(new[] { '"' }) // VSTest strips quotes from the test assembly path and fails to locate the .deps.json in the same directory + .Distinct().ToArray(); + + public static string GetSafeFilename(string arbitraryString, bool allowDirectorySeparators = false) { - private static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars() - .Concat(new[] { '"' }) // VSTest strips quotes from the test assembly path and fails to locate the .deps.json in the same directory - .Distinct().ToArray(); + var replaceIndex = arbitraryString.IndexOfAny(InvalidFileNameChars, 0); + if (replaceIndex == -1) return arbitraryString; - public static string GetSafeFilename(string arbitraryString, bool allowDirectorySeparators = false) - { - var replaceIndex = arbitraryString.IndexOfAny(InvalidFileNameChars, 0); - if (replaceIndex == -1) return arbitraryString; + var r = new StringBuilder(); + var i = 0; - var r = new StringBuilder(); - var i = 0; + do + { + r.Append(arbitraryString, i, replaceIndex - i); - do + switch (arbitraryString[replaceIndex]) { - r.Append(arbitraryString, i, replaceIndex - i); + case '<': + case '>': + case '|': + case ':': + case '*': + case '\\': + case '/': + r.Append(allowDirectorySeparators ? Path.DirectorySeparatorChar : '-'); + break; + case '\0': + case '\f': + case '?': + case '"': + break; + case '\t': + case '\n': + case '\r': + case '\v': + r.Append(' '); + break; + default: + r.Append('_'); + break; + } - switch (arbitraryString[replaceIndex]) - { - case '<': - case '>': - case '|': - case ':': - case '*': - case '\\': - case '/': - r.Append(allowDirectorySeparators ? Path.DirectorySeparatorChar : '-'); - break; - case '\0': - case '\f': - case '?': - case '"': - break; - case '\t': - case '\n': - case '\r': - case '\v': - r.Append(' '); - break; - default: - r.Append('_'); - break; - } + i = replaceIndex + 1; + replaceIndex = arbitraryString.IndexOfAny(InvalidFileNameChars, i); + } + while (replaceIndex != -1); - i = replaceIndex + 1; - replaceIndex = arbitraryString.IndexOfAny(InvalidFileNameChars, i); - } - while (replaceIndex != -1); + r.Append(arbitraryString, i, arbitraryString.Length - i); - r.Append(arbitraryString, i, arbitraryString.Length - i); + return r.ToString(); + } - return r.ToString(); - } + public static DirectoryMutex CreateMutexDirectory(string parentDirectory, string name = null) + { + parentDirectory = Path.GetFullPath(parentDirectory); - public static DirectoryMutex CreateMutexDirectory(string parentDirectory, string name = null) - { - parentDirectory = Path.GetFullPath(parentDirectory); + var safeName = name is null ? null : GetSafeFilename(name); - var safeName = name is null ? null : GetSafeFilename(name); + for (var id = 1; ; id++) + { + var path = Path.Combine( + parentDirectory, + safeName is null ? id.ToString() : + id == 1 ? safeName : + safeName + "_" + id); - for (var id = 1; ; id++) + if (!Directory.Exists(path)) { - var path = Path.Combine( - parentDirectory, - safeName is null ? id.ToString() : - id == 1 ? safeName : - safeName + "_" + id); - - if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + if (DirectoryMutex.TryAcquire(path) is { } mutex) { - Directory.CreateDirectory(path); - if (DirectoryMutex.TryAcquire(path) is { } mutex) - { - // Make sure that the directory is still empty (besides the mutex file) at this point so that a - // non-empty directory is not used. - if (Directory.GetFileSystemEntries(path).Length == 1) - return mutex; - } + // Make sure that the directory is still empty (besides the mutex file) at this point so that a + // non-empty directory is not used. + if (Directory.GetFileSystemEntries(path).Length == 1) + return mutex; } } } + } - public static void DeleteDirectoryRobust(string directory) + public static void DeleteDirectoryRobust(string directory) + { + for (var attempt = 1; ; attempt++) { - for (var attempt = 1; ; attempt++) + try { - try - { - Directory.Delete(directory, recursive: true); - break; - } - catch (DirectoryNotFoundException) - { - break; - } - catch (IOException ex) when (attempt < 3 && (WinErrorCode)ex.HResult == WinErrorCode.DirNotEmpty) - { - TestContext.WriteLine("Another process added files to the directory while its contents were being deleted. Retrying..."); - } + Directory.Delete(directory, recursive: true); + break; + } + catch (DirectoryNotFoundException) + { + break; + } + catch (IOException ex) when (attempt < 3 && (WinErrorCode)ex.HResult == WinErrorCode.DirNotEmpty) + { + TestContext.WriteLine("Another process added files to the directory while its contents were being deleted. Retrying..."); } } + } - private enum WinErrorCode : ushort - { - DirNotEmpty = 145 - } + private enum WinErrorCode : ushort + { + DirNotEmpty = 145 + } - /// - /// Removes any indentation that is common to all lines. If the first line has no indentation, - /// indentation common to all other lines is removed. If the first line is empty, it is removed. - /// Empty lines are not considered when calculating indentation. - /// - public static string RemoveIndent(string indented) - { - if (indented is null) return null; + /// + /// Removes any indentation that is common to all lines. If the first line has no indentation, + /// indentation common to all other lines is removed. If the first line is empty, it is removed. + /// Empty lines are not considered when calculating indentation. + /// + public static string RemoveIndent(string indented) + { + if (indented is null) return null; - var reader = new StringReader(indented); - var firstLine = reader.ReadLine(); + var reader = new StringReader(indented); + var firstLine = reader.ReadLine(); - var firstLineStartsWithoutIndent = firstLine.Length != 0 && firstLine[0] != ' '; + var firstLineStartsWithoutIndent = firstLine.Length != 0 && firstLine[0] != ' '; - var readerForCountingPass = new StringReader(indented); + var readerForCountingPass = new StringReader(indented); - // Skip the first line when determining common indentation if it has no indentation - if (firstLineStartsWithoutIndent) - _ = readerForCountingPass.ReadLine(); + // Skip the first line when determining common indentation if it has no indentation + if (firstLineStartsWithoutIndent) + _ = readerForCountingPass.ReadLine(); - var indentationCharCount = CountCommonIndentationChars(readerForCountingPass); + var indentationCharCount = CountCommonIndentationChars(readerForCountingPass); - var builder = new StringBuilder(); + var builder = new StringBuilder(); - var previousLineHasEnded = true; + var previousLineHasEnded = true; - if (firstLine.Length != 0) + if (firstLine.Length != 0) + { + if (firstLineStartsWithoutIndent) { - if (firstLineStartsWithoutIndent) - { - builder.Append(firstLine); - previousLineHasEnded = false; - } - else - { - // Start at beginning - reader = new StringReader(indented); - } + builder.Append(firstLine); + previousLineHasEnded = false; + } + else + { + // Start at beginning + reader = new StringReader(indented); } + } - var remainingIndentationChars = indentationCharCount; + var remainingIndentationChars = indentationCharCount; - while (reader.Read() is var next && next != -1) + while (reader.Read() is var next && next != -1) + { + if (next == ' ' && remainingIndentationChars > 0) { - if (next == ' ' && remainingIndentationChars > 0) - { - remainingIndentationChars--; - continue; - } + remainingIndentationChars--; + continue; + } - if (!previousLineHasEnded) builder.AppendLine(); + if (!previousLineHasEnded) builder.AppendLine(); - if (next == '\r') - { - next = reader.Read(); - if (next != '\n') throw new NotImplementedException("Carriage return without line feed"); - } - - if (next != '\n') - { - builder.Append((char)next).Append(reader.ReadLine()); - } + if (next == '\r') + { + next = reader.Read(); + if (next != '\n') throw new NotImplementedException("Carriage return without line feed"); + } - previousLineHasEnded = false; - remainingIndentationChars = indentationCharCount; + if (next != '\n') + { + builder.Append((char)next).Append(reader.ReadLine()); } - return builder.ToString(); + previousLineHasEnded = false; + remainingIndentationChars = indentationCharCount; } - private static int CountCommonIndentationChars(StringReader reader) - { - var maxCount = 0; - var currentLineCount = 0; + return builder.ToString(); + } + + private static int CountCommonIndentationChars(StringReader reader) + { + var maxCount = 0; + var currentLineCount = 0; - while (true) + while (true) + { + switch (reader.Read()) { - switch (reader.Read()) - { - case -1: - return maxCount; + case -1: + return maxCount; - case ' ': - currentLineCount++; - break; + case ' ': + currentLineCount++; + break; - case '\t': - throw new NotImplementedException("Tabs"); + case '\t': + throw new NotImplementedException("Tabs"); - case '\r': - case '\n': - currentLineCount = 0; - break; + case '\r': + case '\n': + currentLineCount = 0; + break; - default: - if (currentLineCount == 0) return 0; + default: + if (currentLineCount == 0) return 0; - if (maxCount == 0 || maxCount > currentLineCount) - maxCount = currentLineCount; + if (maxCount == 0 || maxCount > currentLineCount) + maxCount = currentLineCount; - currentLineCount = 0; + currentLineCount = 0; - _ = reader.ReadLine(); - break; - } + _ = reader.ReadLine(); + break; } } } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/UtilsTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/UtilsTests.cs index 9b462b16..74c5a6f4 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/UtilsTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/UtilsTests.cs @@ -1,67 +1,66 @@ using System; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance; + +public static class UtilsTests { - public static class UtilsTests + [Test] + public static void RemoveIndent_removes_indentation_of_line_with_least_indentation_from_all_lines() { - [Test] - public static void RemoveIndent_removes_indentation_of_line_with_least_indentation_from_all_lines() - { - var result = Utils.RemoveIndent(string.Join( - Environment.NewLine, - " First line", - " Second line", - " ")); + var result = Utils.RemoveIndent(string.Join( + Environment.NewLine, + " First line", + " Second line", + " ")); - Assert.That(result, Is.EqualTo(string.Join( - Environment.NewLine, - " First line", - "Second line", - " "))); - } + Assert.That(result, Is.EqualTo(string.Join( + Environment.NewLine, + " First line", + "Second line", + " "))); + } - [Test] - public static void RemoveIndent_ignores_whitespace_lines() - { - var result = Utils.RemoveIndent(string.Join( - Environment.NewLine, - " First line", - " ", - " Second line")); + [Test] + public static void RemoveIndent_ignores_whitespace_lines() + { + var result = Utils.RemoveIndent(string.Join( + Environment.NewLine, + " First line", + " ", + " Second line")); - Assert.That(result, Is.EqualTo(string.Join( - Environment.NewLine, - "First line", - "", - "Second line"))); - } + Assert.That(result, Is.EqualTo(string.Join( + Environment.NewLine, + "First line", + "", + "Second line"))); + } - [Test] - public static void RemoveIndent_ignores_first_line_if_it_begins_without_indent() - { - var result = Utils.RemoveIndent(string.Join( - Environment.NewLine, - "First line", - " Second line")); + [Test] + public static void RemoveIndent_ignores_first_line_if_it_begins_without_indent() + { + var result = Utils.RemoveIndent(string.Join( + Environment.NewLine, + "First line", + " Second line")); - Assert.That(result, Is.EqualTo(string.Join( - Environment.NewLine, - "First line", - "Second line"))); - } + Assert.That(result, Is.EqualTo(string.Join( + Environment.NewLine, + "First line", + "Second line"))); + } - [Test] - public static void RemoveIndent_removes_first_line_if_is_empty() - { - var result = Utils.RemoveIndent(string.Join( - Environment.NewLine, - "", - " Second line")); + [Test] + public static void RemoveIndent_removes_first_line_if_is_empty() + { + var result = Utils.RemoveIndent(string.Join( + Environment.NewLine, + "", + " Second line")); - Assert.That(result, Is.EqualTo(string.Join( - Environment.NewLine, - "Second line"))); - } + Assert.That(result, Is.EqualTo(string.Join( + Environment.NewLine, + "Second line"))); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspace.RunSettings.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspace.RunSettings.cs index f14c325b..e489bbb0 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspace.RunSettings.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspace.RunSettings.cs @@ -1,57 +1,56 @@ using System; using System.Collections.Generic; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +partial class IsolatedWorkspace { - partial class IsolatedWorkspace + private sealed class RunSettings { - private sealed class RunSettings + private List Arguments { get; } = []; + + public string WorkingDirectory { get; } + public string FileName { get; } + + public string ArgumentsAsEscapedString => ProcessUtils.EscapeProcessArguments(Arguments); + + public RunSettings(string workingDirectory, string fileName) + { + WorkingDirectory = workingDirectory; + FileName = fileName; + } + + public ProcessRunResult Run(bool throwOnError = true) + { + var result = ProcessUtils.Run(WorkingDirectory, FileName, Arguments); + if (throwOnError) result.ThrowIfError(); + return result; + } + + public RunSettings Add(string argument) + { + Arguments.Add(argument); + return this; + } + + public RunSettings AddRange(IEnumerable arguments) + { + if (arguments is null) throw new ArgumentNullException(nameof(arguments)); + Arguments.AddRange(arguments); + return this; + } + + public RunSettings AddIf(bool condition, string argument) + { + if (condition) Arguments.Add(argument); + return this; + } + + public RunSettings AddRangeIf(bool condition, IEnumerable arguments) { - private List Arguments { get; } = []; - - public string WorkingDirectory { get; } - public string FileName { get; } - - public string ArgumentsAsEscapedString => ProcessUtils.EscapeProcessArguments(Arguments); - - public RunSettings(string workingDirectory, string fileName) - { - WorkingDirectory = workingDirectory; - FileName = fileName; - } - - public ProcessRunResult Run(bool throwOnError = true) - { - var result = ProcessUtils.Run(WorkingDirectory, FileName, Arguments); - if (throwOnError) result.ThrowIfError(); - return result; - } - - public RunSettings Add(string argument) - { - Arguments.Add(argument); - return this; - } - - public RunSettings AddRange(IEnumerable arguments) - { - if (arguments is null) throw new ArgumentNullException(nameof(arguments)); - Arguments.AddRange(arguments); - return this; - } - - public RunSettings AddIf(bool condition, string argument) - { - if (condition) Arguments.Add(argument); - return this; - } - - public RunSettings AddRangeIf(bool condition, IEnumerable arguments) - { - if (arguments is null) throw new ArgumentNullException(nameof(arguments)); - if (condition) Arguments.AddRange(arguments); - return this; - } + if (arguments is null) throw new ArgumentNullException(nameof(arguments)); + if (condition) Arguments.AddRange(arguments); + return this; } } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspace.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspace.cs index 61f7214a..1722dabe 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspace.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspace.cs @@ -3,149 +3,148 @@ using System.Diagnostics; using System.IO; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +[DebuggerDisplay("{Directory,nq}")] +public sealed partial class IsolatedWorkspace(DirectoryMutex directoryMutex, ToolResolver toolResolver) + : IDisposable { - [DebuggerDisplay("{Directory,nq}")] - public sealed partial class IsolatedWorkspace(DirectoryMutex directoryMutex, ToolResolver toolResolver) - : IDisposable + private readonly List projectPaths = []; + private readonly ToolResolver toolResolver = toolResolver ?? throw new ArgumentNullException(nameof(toolResolver)); + private readonly DirectoryMutex directoryMutex = directoryMutex ?? throw new ArgumentNullException(nameof(toolResolver)); + + public bool DumpTestExecution { get; set; } = false; + + public string Directory => directoryMutex.DirectoryPath; + + public void Dispose() => directoryMutex.Dispose(); + + public IsolatedWorkspace AddProject(string path, string contents) { - private readonly List projectPaths = []; - private readonly ToolResolver toolResolver = toolResolver ?? throw new ArgumentNullException(nameof(toolResolver)); - private readonly DirectoryMutex directoryMutex = directoryMutex ?? throw new ArgumentNullException(nameof(toolResolver)); + AddFile(path, contents); + projectPaths.Add(path); + return this; + } - public bool DumpTestExecution { get; set; } = false; + public IsolatedWorkspace AddFile(string path, string contents) + { + if (string.IsNullOrWhiteSpace(path)) + throw new ArgumentException("File path must be specified.", nameof(path)); - public string Directory => directoryMutex.DirectoryPath; + if (Path.IsPathRooted(path)) + throw new ArgumentException("File path must not be rooted.", nameof(path)); - public void Dispose() => directoryMutex.Dispose(); + File.WriteAllText(Path.Combine(Directory, path), Utils.RemoveIndent(contents)); + return this; + } - public IsolatedWorkspace AddProject(string path, string contents) - { - AddFile(path, contents); - projectPaths.Add(path); - return this; - } + public void DotNetRestore() + { + ConfigureRun("dotnet") + .Add("restore") + .Run(); + } - public IsolatedWorkspace AddFile(string path, string contents) - { - if (string.IsNullOrWhiteSpace(path)) - throw new ArgumentException("File path must be specified.", nameof(path)); + public void DotNetBuild(bool noRestore = false) + { + ConfigureRun("dotnet") + .Add("build") + .AddIf(noRestore, "--no-restore") + .Run(); + } - if (Path.IsPathRooted(path)) - throw new ArgumentException("File path must not be rooted.", nameof(path)); + /// + /// Runs dotnet test. + /// + /// Possible filter statement. + /// if you run MSBuild or dotnet build first, set to false. + /// Set NUnit verbosity to 5, enables seing more info from the run in StdOut. + /// VSTestResults. + public VSTestResult DotNetTest(string filterArgument = "", bool noBuild = false, bool verbose = false, Action log = null) + { + using var tempTrxFile = new TempFile(); - File.WriteAllText(Path.Combine(Directory, path), Utils.RemoveIndent(contents)); - return this; - } + var dotnettest = ConfigureRun("dotnet") + .Add("test") + .AddIf(noBuild, "--no-build") + .Add("-v:n") + .Add("--logger").Add("trx;LogFileName=" + tempTrxFile); - public void DotNetRestore() - { - ConfigureRun("dotnet") - .Add("restore") - .Run(); - } + bool hasNUnitWhere = filterArgument.StartsWith("NUnit.Where"); - public void DotNetBuild(bool noRestore = false) + if (filterArgument.Length > 0 && !hasNUnitWhere) { - ConfigureRun("dotnet") - .Add("build") - .AddIf(noRestore, "--no-restore") - .Run(); + dotnettest.Add("--filter").Add($"{filterArgument}"); } - - /// - /// Runs dotnet test. - /// - /// Possible filter statement. - /// if you run MSBuild or dotnet build first, set to false. - /// Set NUnit verbosity to 5, enables seing more info from the run in StdOut. - /// VSTestResults. - public VSTestResult DotNetTest(string filterArgument = "", bool noBuild = false, bool verbose = false, Action log = null) + else if (hasNUnitWhere) { - using var tempTrxFile = new TempFile(); - - var dotnettest = ConfigureRun("dotnet") - .Add("test") - .AddIf(noBuild, "--no-build") - .Add("-v:n") - .Add("--logger").Add("trx;LogFileName=" + tempTrxFile); - - bool hasNUnitWhere = filterArgument.StartsWith("NUnit.Where"); - - if (filterArgument.Length > 0 && !hasNUnitWhere) - { - dotnettest.Add("--filter").Add($"{filterArgument}"); - } - else if (hasNUnitWhere) - { - dotnettest.Add("--").Add(filterArgument); - } - if (verbose) - { - if (!hasNUnitWhere) - dotnettest.Add("--"); - dotnettest.Add("NUnit.Verbosity=5"); - } - log?.Invoke($"\n{dotnettest.ArgumentsAsEscapedString}"); - var result = dotnettest.Run(throwOnError: false); - - if (new FileInfo(tempTrxFile).Length == 0) - result.ThrowIfError(); - - return VSTestResult.Load(result, tempTrxFile); + dotnettest.Add("--").Add(filterArgument); } - - public void DotNetVSTest(IEnumerable testAssemblyPaths) + if (verbose) { - ConfigureRun("dotnet") - .Add("vstest") - .AddRange(testAssemblyPaths) - .Run(); + if (!hasNUnitWhere) + dotnettest.Add("--"); + dotnettest.Add("NUnit.Verbosity=5"); } + log?.Invoke($"\n{dotnettest.ArgumentsAsEscapedString}"); + var result = dotnettest.Run(throwOnError: false); - public void NuGetRestore(string packagesDirectory = null) - { - ConfigureRun(toolResolver.NuGet) - .Add("restore") - .AddRangeIf(packagesDirectory != null, new[] { "-PackagesDirectory", packagesDirectory }) - .Run(); - } + if (new FileInfo(tempTrxFile).Length == 0) + result.ThrowIfError(); - public void MsBuild(string target = null, bool restore = false) - { - ConfigureRun(toolResolver.MSBuild) - .AddIf(target != null, "/t:" + target) - .AddIf(restore, "/restore") - .Run(); - } + return VSTestResult.Load(result, tempTrxFile); + } - public VSTestResult VSTest(string testAssemblyPath, IFilterArgument filter) - { - using var tempTrxFile = new TempFile(); + public void DotNetVSTest(IEnumerable testAssemblyPaths) + { + ConfigureRun("dotnet") + .Add("vstest") + .AddRange(testAssemblyPaths) + .Run(); + } + + public void NuGetRestore(string packagesDirectory = null) + { + ConfigureRun(toolResolver.NuGet) + .Add("restore") + .AddRangeIf(packagesDirectory != null, new[] { "-PackagesDirectory", packagesDirectory }) + .Run(); + } + + public void MsBuild(string target = null, bool restore = false) + { + ConfigureRun(toolResolver.MSBuild) + .AddIf(target != null, "/t:" + target) + .AddIf(restore, "/restore") + .Run(); + } - var vstest = ConfigureRun(toolResolver.VSTest) - .Add(testAssemblyPath) - .Add("/logger:trx;LogFileName=" + tempTrxFile); + public VSTestResult VSTest(string testAssemblyPath, IFilterArgument filter) + { + using var tempTrxFile = new TempFile(); - if (filter.HasArguments) - { - vstest.Add(filter.CompletedArgument()); - } + var vstest = ConfigureRun(toolResolver.VSTest) + .Add(testAssemblyPath) + .Add("/logger:trx;LogFileName=" + tempTrxFile); - if (DumpTestExecution) - vstest.Add("--").Add("NUnit.DumpXmlTestResults=true"); + if (filter.HasArguments) + { + vstest.Add(filter.CompletedArgument()); + } - var result = vstest.Run(throwOnError: false); + if (DumpTestExecution) + vstest.Add("--").Add("NUnit.DumpXmlTestResults=true"); - if (new FileInfo(tempTrxFile).Length == 0) - { - result.ThrowIfError(); - return new VSTestResult(result); - } + var result = vstest.Run(throwOnError: false); - return VSTestResult.Load(result, tempTrxFile); + if (new FileInfo(tempTrxFile).Length == 0) + { + result.ThrowIfError(); + return new VSTestResult(result); } - private RunSettings ConfigureRun(string filename) => new(Directory, filename); + return VSTestResult.Load(result, tempTrxFile); } -} + + private RunSettings ConfigureRun(string filename) => new(Directory, filename); +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspaceManager.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspaceManager.cs index d46fae6a..7c2263f5 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspaceManager.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/IsolatedWorkspaceManager.cs @@ -2,101 +2,100 @@ using System.IO; using System.Xml; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +public sealed class IsolatedWorkspaceManager : IDisposable { - public sealed class IsolatedWorkspaceManager : IDisposable + private readonly DirectoryMutex workspaceDirectory; + private readonly ToolResolver toolResolver; + private readonly StreamWriter reasonFile; + private bool keep; + + public IsolatedWorkspaceManager(string reason, string baseDirectory, string testNupkgDirectory, string packageCachePath, string downloadCachePath) { - private readonly DirectoryMutex workspaceDirectory; - private readonly ToolResolver toolResolver; - private readonly StreamWriter reasonFile; - private bool keep; + baseDirectory = Path.GetFullPath(baseDirectory); + testNupkgDirectory = Path.GetFullPath(testNupkgDirectory); + packageCachePath = Path.GetFullPath(packageCachePath); + downloadCachePath = Path.GetFullPath(downloadCachePath); - public IsolatedWorkspaceManager(string reason, string baseDirectory, string testNupkgDirectory, string packageCachePath, string downloadCachePath) - { - baseDirectory = Path.GetFullPath(baseDirectory); - testNupkgDirectory = Path.GetFullPath(testNupkgDirectory); - packageCachePath = Path.GetFullPath(packageCachePath); - downloadCachePath = Path.GetFullPath(downloadCachePath); + Directory.CreateDirectory(baseDirectory); - Directory.CreateDirectory(baseDirectory); + workspaceDirectory = Utils.CreateMutexDirectory(baseDirectory); - workspaceDirectory = Utils.CreateMutexDirectory(baseDirectory); + toolResolver = new ToolResolver(downloadCachePath); - toolResolver = new ToolResolver(downloadCachePath); + reasonFile = File.CreateText(Path.Combine(workspaceDirectory.DirectoryPath, "Reason.txt")); + reasonFile.WriteLine(reason); + reasonFile.WriteLine(); + reasonFile.Flush(); - reasonFile = File.CreateText(Path.Combine(workspaceDirectory.DirectoryPath, "Reason.txt")); - reasonFile.WriteLine(reason); - reasonFile.WriteLine(); - reasonFile.Flush(); + WriteNuGetConfig(baseDirectory, testNupkgDirectory, packageCachePath); - WriteNuGetConfig(baseDirectory, testNupkgDirectory, packageCachePath); + File.WriteAllText(Path.Combine(baseDirectory, "Directory.Build.props"), ""); + File.WriteAllText(Path.Combine(baseDirectory, "Directory.Build.targets"), ""); + } - File.WriteAllText(Path.Combine(baseDirectory, "Directory.Build.props"), ""); - File.WriteAllText(Path.Combine(baseDirectory, "Directory.Build.targets"), ""); - } + public void Dispose() + { + workspaceDirectory.Dispose(); + reasonFile.Dispose(); + if (!keep) Utils.DeleteDirectoryRobust(workspaceDirectory.DirectoryPath); + } - public void Dispose() - { - workspaceDirectory.Dispose(); - reasonFile.Dispose(); - if (!keep) Utils.DeleteDirectoryRobust(workspaceDirectory.DirectoryPath); - } + public IsolatedWorkspace CreateWorkspace(string name) + { + return new ( + Utils.CreateMutexDirectory(workspaceDirectory.DirectoryPath, name), + toolResolver); + } - public IsolatedWorkspace CreateWorkspace(string name) + /// + /// Prevents the workspace directory from being deleted when is called. + /// + public void PreserveDirectory(string reason) + { + if (!keep) { - return new ( - Utils.CreateMutexDirectory(workspaceDirectory.DirectoryPath, name), - toolResolver); + keep = true; + reasonFile.WriteLine("Preserving workspace after cleanup, due to:"); + reasonFile.WriteLine(); } - /// - /// Prevents the workspace directory from being deleted when is called. - /// - public void PreserveDirectory(string reason) - { - if (!keep) - { - keep = true; - reasonFile.WriteLine("Preserving workspace after cleanup, due to:"); - reasonFile.WriteLine(); - } - - reasonFile.WriteLine(reason); - reasonFile.Flush(); - } + reasonFile.WriteLine(reason); + reasonFile.Flush(); + } - private static void WriteNuGetConfig(string directory, string testNupkgDirectory, string packageCachePath) - { - using var file = File.CreateText(Path.Combine(directory, "nuget.config")); - using var writer = XmlWriter.Create(file, new XmlWriterSettings { Indent = true }); - writer.WriteComment(string.Join( - Environment.NewLine, - "", - "This file exists so that if any of the projects under this folder are opened by an IDE or restored from the CLI by acceptance tests or by hand,", - " 1. the .nupkg that is being tested can be referenced by these projects, and", - " 2. the .nupkg that is tested does not pollute the global cache in %userprofile%\\.nuget.", - "")); - - writer.WriteStartElement("configuration"); - writer.WriteStartElement("config"); - - writer.WriteComment(" Implements the second point "); - writer.WriteStartElement("add"); - writer.WriteAttributeString("key", "globalPackagesFolder"); - writer.WriteAttributeString("value", packageCachePath); - writer.WriteEndElement(); - - writer.WriteEndElement(); - writer.WriteStartElement("packageSources"); - - writer.WriteComment(" Implements the first point "); - writer.WriteStartElement("add"); - writer.WriteAttributeString("key", "Build script package output"); - writer.WriteAttributeString("value", testNupkgDirectory); - writer.WriteEndElement(); - - writer.WriteEndElement(); - writer.WriteEndElement(); - } + private static void WriteNuGetConfig(string directory, string testNupkgDirectory, string packageCachePath) + { + using var file = File.CreateText(Path.Combine(directory, "nuget.config")); + using var writer = XmlWriter.Create(file, new XmlWriterSettings { Indent = true }); + writer.WriteComment(string.Join( + Environment.NewLine, + "", + "This file exists so that if any of the projects under this folder are opened by an IDE or restored from the CLI by acceptance tests or by hand,", + " 1. the .nupkg that is being tested can be referenced by these projects, and", + " 2. the .nupkg that is tested does not pollute the global cache in %userprofile%\\.nuget.", + "")); + + writer.WriteStartElement("configuration"); + writer.WriteStartElement("config"); + + writer.WriteComment(" Implements the second point "); + writer.WriteStartElement("add"); + writer.WriteAttributeString("key", "globalPackagesFolder"); + writer.WriteAttributeString("value", packageCachePath); + writer.WriteEndElement(); + + writer.WriteEndElement(); + writer.WriteStartElement("packageSources"); + + writer.WriteComment(" Implements the first point "); + writer.WriteStartElement("add"); + writer.WriteAttributeString("key", "Build script package output"); + writer.WriteAttributeString("value", testNupkgDirectory); + writer.WriteEndElement(); + + writer.WriteEndElement(); + writer.WriteEndElement(); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessErrorException.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessErrorException.cs index 470433e1..350ed11d 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessErrorException.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessErrorException.cs @@ -1,39 +1,38 @@ using System; using System.Text; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +public sealed class ProcessErrorException : Exception { - public sealed class ProcessErrorException : Exception + public ProcessErrorException(ProcessRunResult result) + : base(BuildMessage(result)) { - public ProcessErrorException(ProcessRunResult result) - : base(BuildMessage(result)) - { - Result = result; - } - - public ProcessRunResult Result { get; } + Result = result; + } - private static string BuildMessage(ProcessRunResult result) - { - var builder = new StringBuilder(); - builder.Append("Process ‘").Append(result.ProcessName); - builder.Append("’ exited with code ").Append(result.ExitCode).Append('.'); - builder.AppendLine().Append("Executable: ").Append(result.FileName); + public ProcessRunResult Result { get; } - if (!string.IsNullOrWhiteSpace(result.Arguments)) - { - builder.AppendLine().Append("Arguments: ").Append(result.Arguments); - } + private static string BuildMessage(ProcessRunResult result) + { + var builder = new StringBuilder(); + builder.Append("Process ‘").Append(result.ProcessName); + builder.Append("’ exited with code ").Append(result.ExitCode).Append('.'); + builder.AppendLine().Append("Executable: ").Append(result.FileName); - var hasStdErr = !string.IsNullOrWhiteSpace(result.StdErr); + if (!string.IsNullOrWhiteSpace(result.Arguments)) + { + builder.AppendLine().Append("Arguments: ").Append(result.Arguments); + } - if (hasStdErr || !string.IsNullOrWhiteSpace(result.StdOut)) - { - builder.AppendLine().Append(hasStdErr ? "Stderr:" : "Stdout:"); - builder.AppendLine().Append(hasStdErr ? result.StdErr : result.StdOut); - } + var hasStdErr = !string.IsNullOrWhiteSpace(result.StdErr); - return builder.ToString(); + if (hasStdErr || !string.IsNullOrWhiteSpace(result.StdOut)) + { + builder.AppendLine().Append(hasStdErr ? "Stderr:" : "Stdout:"); + builder.AppendLine().Append(hasStdErr ? result.StdErr : result.StdOut); } + + return builder.ToString(); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessRunResult.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessRunResult.cs index 27eff28f..3abf8f91 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessRunResult.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessRunResult.cs @@ -1,26 +1,25 @@ using System; using System.IO; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +public readonly struct ProcessRunResult( + string fileName, + string arguments, + int exitCode, + string stdOut, + string stdErr) { - public readonly struct ProcessRunResult( - string fileName, - string arguments, - int exitCode, - string stdOut, - string stdErr) - { - public string FileName { get; } = fileName ?? throw new ArgumentNullException(nameof(fileName)); - public string Arguments { get; } = arguments; + public string FileName { get; } = fileName ?? throw new ArgumentNullException(nameof(fileName)); + public string Arguments { get; } = arguments; - public string ProcessName => Path.GetFileName(FileName); - public int ExitCode { get; } = exitCode; - public string StdOut { get; } = stdOut ?? string.Empty; - public string StdErr { get; } = stdErr ?? string.Empty; + public string ProcessName => Path.GetFileName(FileName); + public int ExitCode { get; } = exitCode; + public string StdOut { get; } = stdOut ?? string.Empty; + public string StdErr { get; } = stdErr ?? string.Empty; - public ProcessRunResult ThrowIfError() => - ExitCode == 0 && string.IsNullOrEmpty(StdErr) - ? this - : throw new ProcessErrorException(this); - } -} + public ProcessRunResult ThrowIfError() => + ExitCode == 0 && string.IsNullOrEmpty(StdErr) + ? this + : throw new ProcessErrorException(this); +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessUtils.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessUtils.cs index 213b6da4..ab57e217 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessUtils.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessUtils.cs @@ -4,158 +4,157 @@ using System.IO; using System.Text; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +public static class ProcessUtils { - public static class ProcessUtils + public static ProcessRunResult Run(string workingDirectory, string fileName, IEnumerable arguments = null) { - public static ProcessRunResult Run(string workingDirectory, string fileName, IEnumerable arguments = null) - { - if (!Path.IsPathRooted(workingDirectory)) - throw new ArgumentException(nameof(workingDirectory), "Working directory must not be relative."); + if (!Path.IsPathRooted(workingDirectory)) + throw new ArgumentException(nameof(workingDirectory), "Working directory must not be relative."); - if (string.IsNullOrWhiteSpace(fileName)) - throw new ArgumentException(nameof(fileName), "File name must be specified."); + if (string.IsNullOrWhiteSpace(fileName)) + throw new ArgumentException(nameof(fileName), "File name must be specified."); - var escapedArguments = arguments is null ? null : EscapeProcessArguments(arguments, alwaysQuote: false); + var escapedArguments = arguments is null ? null : EscapeProcessArguments(arguments, alwaysQuote: false); - using var process = new Process - { - StartInfo = - { - UseShellExecute = false, - WorkingDirectory = workingDirectory, - FileName = fileName, - Arguments = escapedArguments, - RedirectStandardOutput = true, - RedirectStandardError = true - } - }; - // This is inherited if the test runner was started by the Visual Studio process. - // It breaks MSBuild 15’s targets when it tries to build legacy csprojs and vbprojs. - process.StartInfo.EnvironmentVariables.Remove("VisualStudioVersion"); - - var stdout = (StringBuilder)null; - var stderr = (StringBuilder)null; - - process.OutputDataReceived += (sender, e) => + using var process = new Process + { + StartInfo = { - if (e.Data is null) return; + UseShellExecute = false, + WorkingDirectory = workingDirectory, + FileName = fileName, + Arguments = escapedArguments, + RedirectStandardOutput = true, + RedirectStandardError = true + } + }; + // This is inherited if the test runner was started by the Visual Studio process. + // It breaks MSBuild 15’s targets when it tries to build legacy csprojs and vbprojs. + process.StartInfo.EnvironmentVariables.Remove("VisualStudioVersion"); - if (stdout is null) - stdout = new StringBuilder(); - else - stdout.AppendLine(); + var stdout = (StringBuilder)null; + var stderr = (StringBuilder)null; - stdout.Append(e.Data); - }; + process.OutputDataReceived += (sender, e) => + { + if (e.Data is null) return; - process.ErrorDataReceived += (sender, e) => - { - if (e.Data is null) return; - - if (stderr is null) - stderr = new StringBuilder(); - else - stderr.AppendLine(); - - stderr.Append(e.Data); - }; - - process.Start(); - process.BeginErrorReadLine(); - process.BeginOutputReadLine(); - process.WaitForExit(); - - return new ProcessRunResult( - fileName, - escapedArguments, - process.ExitCode, - stdout?.ToString(), - stderr?.ToString()); - } + if (stdout is null) + stdout = new StringBuilder(); + else + stdout.AppendLine(); - private static readonly char[] CharsThatRequireQuoting = { ' ', '"' }; - private static readonly char[] CharsThatRequireEscaping = { '\\', '"' }; + stdout.Append(e.Data); + }; - /// - /// Escapes arbitrary values so that the process receives the exact string you intend and injection is impossible. - /// Spec: https://msdn.microsoft.com/en-us/library/bb776391.aspx. - /// - public static string EscapeProcessArguments(IEnumerable literalValues, bool alwaysQuote = false) + process.ErrorDataReceived += (sender, e) => { - if (literalValues is null) throw new ArgumentNullException(nameof(literalValues)); + if (e.Data is null) return; + + if (stderr is null) + stderr = new StringBuilder(); + else + stderr.AppendLine(); + + stderr.Append(e.Data); + }; + + process.Start(); + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + process.WaitForExit(); + + return new ProcessRunResult( + fileName, + escapedArguments, + process.ExitCode, + stdout?.ToString(), + stderr?.ToString()); + } - using var en = literalValues.GetEnumerator(); - if (!en.MoveNext()) return string.Empty; + private static readonly char[] CharsThatRequireQuoting = { ' ', '"' }; + private static readonly char[] CharsThatRequireEscaping = { '\\', '"' }; - var builder = new StringBuilder(); + /// + /// Escapes arbitrary values so that the process receives the exact string you intend and injection is impossible. + /// Spec: https://msdn.microsoft.com/en-us/library/bb776391.aspx. + /// + public static string EscapeProcessArguments(IEnumerable literalValues, bool alwaysQuote = false) + { + if (literalValues is null) throw new ArgumentNullException(nameof(literalValues)); - while (true) - { - EscapeProcessArgument(builder, en.Current, alwaysQuote); - if (!en.MoveNext()) break; - builder.Append(' '); - } + using var en = literalValues.GetEnumerator(); + if (!en.MoveNext()) return string.Empty; + + var builder = new StringBuilder(); + + while (true) + { + EscapeProcessArgument(builder, en.Current, alwaysQuote); + if (!en.MoveNext()) break; + builder.Append(' '); + } + + return builder.ToString(); + } - return builder.ToString(); + private static void EscapeProcessArgument(StringBuilder builder, string literalValue, bool alwaysQuote) + { + if (string.IsNullOrEmpty(literalValue)) + { + builder.Append("\"\""); + return; } - private static void EscapeProcessArgument(StringBuilder builder, string literalValue, bool alwaysQuote) + if (literalValue.IndexOfAny(CharsThatRequireQuoting) == -1) // Happy path { - if (string.IsNullOrEmpty(literalValue)) + if (!alwaysQuote) { - builder.Append("\"\""); + builder.Append(literalValue); return; } - - if (literalValue.IndexOfAny(CharsThatRequireQuoting) == -1) // Happy path + if (literalValue[literalValue.Length - 1] != '\\') { - if (!alwaysQuote) - { - builder.Append(literalValue); - return; - } - if (literalValue[literalValue.Length - 1] != '\\') - { - builder.Append('"').Append(literalValue).Append('"'); - return; - } + builder.Append('"').Append(literalValue).Append('"'); + return; } + } - builder.Append('"'); + builder.Append('"'); + + var nextPosition = 0; + while (true) + { + var nextEscapeChar = literalValue.IndexOfAny(CharsThatRequireEscaping, nextPosition); + if (nextEscapeChar == -1) break; - var nextPosition = 0; - while (true) + builder.Append(literalValue, nextPosition, nextEscapeChar - nextPosition); + nextPosition = nextEscapeChar + 1; + + switch (literalValue[nextEscapeChar]) { - var nextEscapeChar = literalValue.IndexOfAny(CharsThatRequireEscaping, nextPosition); - if (nextEscapeChar == -1) break; - - builder.Append(literalValue, nextPosition, nextEscapeChar - nextPosition); - nextPosition = nextEscapeChar + 1; - - switch (literalValue[nextEscapeChar]) - { - case '"': - builder.Append("\\\""); - break; - case '\\': - var numBackslashes = 1; - while (nextPosition < literalValue.Length && literalValue[nextPosition] == '\\') - { - numBackslashes++; - nextPosition++; - } - if (nextPosition == literalValue.Length || literalValue[nextPosition] == '"') - numBackslashes <<= 1; - - for (; numBackslashes != 0; numBackslashes--) - builder.Append('\\'); - break; - } + case '"': + builder.Append("\\\""); + break; + case '\\': + var numBackslashes = 1; + while (nextPosition < literalValue.Length && literalValue[nextPosition] == '\\') + { + numBackslashes++; + nextPosition++; + } + if (nextPosition == literalValue.Length || literalValue[nextPosition] == '"') + numBackslashes <<= 1; + + for (; numBackslashes != 0; numBackslashes--) + builder.Append('\\'); + break; } - - builder.Append(literalValue, nextPosition, literalValue.Length - nextPosition); - builder.Append('"'); } + + builder.Append(literalValue, nextPosition, literalValue.Length - nextPosition); + builder.Append('"'); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessUtilsTests.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessUtilsTests.cs index 5cd6e322..d5399e18 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessUtilsTests.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ProcessUtilsTests.cs @@ -1,91 +1,90 @@ using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +public static class ProcessUtilsTests { - public static class ProcessUtilsTests + [Test] + public static void EscapeProcessArguments_null() { - [Test] - public static void EscapeProcessArguments_null() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new string[] { null }), Is.EqualTo("\"\"")); - } + Assert.That(ProcessUtils.EscapeProcessArguments(new string[] { null }), Is.EqualTo("\"\"")); + } - [Test] - public static void EscapeProcessArguments_null_alwaysQuote() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new string[] { null }, true), Is.EqualTo("\"\"")); - } + [Test] + public static void EscapeProcessArguments_null_alwaysQuote() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new string[] { null }, true), Is.EqualTo("\"\"")); + } - [Test] - public static void EscapeProcessArguments_empty() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { string.Empty }), Is.EqualTo("\"\"")); - } + [Test] + public static void EscapeProcessArguments_empty() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { string.Empty }), Is.EqualTo("\"\"")); + } - [Test] - public static void EscapeProcessArguments_empty_alwaysQuote() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { string.Empty }, true), Is.EqualTo("\"\"")); - } + [Test] + public static void EscapeProcessArguments_empty_alwaysQuote() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { string.Empty }, true), Is.EqualTo("\"\"")); + } - [Test] - public static void EscapeProcessArguments_simple() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "123" }), Is.EqualTo("123")); - } + [Test] + public static void EscapeProcessArguments_simple() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "123" }), Is.EqualTo("123")); + } - [Test] - public static void EscapeProcessArguments_simple_alwaysQuote() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "123" }, true), Is.EqualTo("\"123\"")); - } + [Test] + public static void EscapeProcessArguments_simple_alwaysQuote() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "123" }, true), Is.EqualTo("\"123\"")); + } - [Test] - public static void EscapeProcessArguments_with_ending_backslash() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "123\\" }), Is.EqualTo("123\\")); - } + [Test] + public static void EscapeProcessArguments_with_ending_backslash() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "123\\" }), Is.EqualTo("123\\")); + } - [Test] - public static void EscapeProcessArguments_with_ending_backslash_alwaysQuote() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "123\\" }, true), Is.EqualTo("\"123\\\\\"")); - } + [Test] + public static void EscapeProcessArguments_with_ending_backslash_alwaysQuote() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "123\\" }, true), Is.EqualTo("\"123\\\\\"")); + } - [Test] - public static void EscapeProcessArguments_with_spaces_and_ending_backslash() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { " 1 2 3 \\" }), Is.EqualTo("\" 1 2 3 \\\\\"")); - } + [Test] + public static void EscapeProcessArguments_with_spaces_and_ending_backslash() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { " 1 2 3 \\" }), Is.EqualTo("\" 1 2 3 \\\\\"")); + } - [Test] - public static void EscapeProcessArguments_with_spaces() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { " 1 2 3 " }), Is.EqualTo("\" 1 2 3 \"")); - } + [Test] + public static void EscapeProcessArguments_with_spaces() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { " 1 2 3 " }), Is.EqualTo("\" 1 2 3 \"")); + } - [Test] - public static void EscapeProcessArguments_with_quotes() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "\"1\"2\"3\"" }), Is.EqualTo("\"\\\"1\\\"2\\\"3\\\"\"")); - } + [Test] + public static void EscapeProcessArguments_with_quotes() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "\"1\"2\"3\"" }), Is.EqualTo("\"\\\"1\\\"2\\\"3\\\"\"")); + } - [Test] - public static void EscapeProcessArguments_with_slashes() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "1\\2\\\\3\\\\\\" }), Is.EqualTo("1\\2\\\\3\\\\\\")); - } + [Test] + public static void EscapeProcessArguments_with_slashes() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "1\\2\\\\3\\\\\\" }), Is.EqualTo("1\\2\\\\3\\\\\\")); + } - [Test] - public static void EscapeProcessArguments_with_slashes_alwaysQuote() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "1\\2\\\\3\\\\\\" }, true), Is.EqualTo("\"1\\2\\\\3\\\\\\\\\\\\\"")); - } + [Test] + public static void EscapeProcessArguments_with_slashes_alwaysQuote() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "1\\2\\\\3\\\\\\" }, true), Is.EqualTo("\"1\\2\\\\3\\\\\\\\\\\\\"")); + } - [Test] - public static void EscapeProcessArguments_slashes_followed_by_quotes() - { - Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "\\\\\"" }), Is.EqualTo("\"\\\\\\\\\\\"\"")); - } + [Test] + public static void EscapeProcessArguments_slashes_followed_by_quotes() + { + Assert.That(ProcessUtils.EscapeProcessArguments(new[] { "\\\\\"" }), Is.EqualTo("\"\\\\\\\\\\\"\"")); } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/TempFile.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/TempFile.cs index 33c57456..0940693c 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/TempFile.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/TempFile.cs @@ -3,25 +3,24 @@ using System.IO; using IO = System.IO; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +[DebuggerDisplay("{ToString(),nq}")] +internal sealed class TempFile : IDisposable { - [DebuggerDisplay("{ToString(),nq}")] - internal sealed class TempFile : IDisposable - { - public string Path { get; } + public string Path { get; } - public TempFile() - { - Path = IO.Path.GetTempFileName(); - } + public TempFile() + { + Path = IO.Path.GetTempFileName(); + } - public void Dispose() - { - File.Delete(Path); - } + public void Dispose() + { + File.Delete(Path); + } - public override string ToString() => Path; + public override string ToString() => Path; - public static implicit operator string(TempFile tempDirectory) => tempDirectory.Path; - } -} + public static implicit operator string(TempFile tempDirectory) => tempDirectory.Path; +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ToolResolver.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ToolResolver.cs index 52013a30..54350e81 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ToolResolver.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/ToolResolver.cs @@ -3,101 +3,100 @@ using System.Linq; using System.Net; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +public sealed class ToolResolver { - public sealed class ToolResolver - { - private readonly string downloadCacheDirectory; + private readonly string downloadCacheDirectory; - private readonly Lazy nuGet; - public string NuGet => nuGet.Value; + private readonly Lazy nuGet; + public string NuGet => nuGet.Value; - private readonly Lazy msBuild; - public string MSBuild => msBuild.Value; + private readonly Lazy msBuild; + public string MSBuild => msBuild.Value; - private readonly Lazy vsTest; - public string VSTest => vsTest.Value; + private readonly Lazy vsTest; + public string VSTest => vsTest.Value; - private readonly Lazy vsWhere; - public string VSWhere => vsWhere.Value; + private readonly Lazy vsWhere; + public string VSWhere => vsWhere.Value; - public ToolResolver(string downloadCacheDirectory) - { - if (!Path.IsPathRooted(downloadCacheDirectory)) - throw new ArgumentException(nameof(downloadCacheDirectory), "Download cache directory path must be rooted."); - - this.downloadCacheDirectory = downloadCacheDirectory; + public ToolResolver(string downloadCacheDirectory) + { + if (!Path.IsPathRooted(downloadCacheDirectory)) + throw new ArgumentException(nameof(downloadCacheDirectory), "Download cache directory path must be rooted."); - nuGet = new Lazy(() => FindDownloadedTool("NuGet", "nuget.exe", "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe")); + this.downloadCacheDirectory = downloadCacheDirectory; - msBuild = new Lazy(() => - { - var vsInstallation = - FindVisualStudio(requiredComponent: "Microsoft.Component.MSBuild") - ?? throw new InvalidOperationException("MSBuild is not installed with Visual Studio on this machine."); + nuGet = new Lazy(() => FindDownloadedTool("NuGet", "nuget.exe", "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe")); - var path = Path.Combine(vsInstallation, @"MSBuild\Current\Bin\MSBuild.exe"); - if (File.Exists(path)) return path; + msBuild = new Lazy(() => + { + var vsInstallation = + FindVisualStudio(requiredComponent: "Microsoft.Component.MSBuild") + ?? throw new InvalidOperationException("MSBuild is not installed with Visual Studio on this machine."); - var oldPath = Path.Combine(vsInstallation, @"MSBuild\15.0\Bin\MSBuild.exe"); - if (File.Exists(oldPath)) return oldPath; + var path = Path.Combine(vsInstallation, @"MSBuild\Current\Bin\MSBuild.exe"); + if (File.Exists(path)) return path; - throw new FileNotFoundException("Cannot locate MSBuild.exe."); - }); + var oldPath = Path.Combine(vsInstallation, @"MSBuild\15.0\Bin\MSBuild.exe"); + if (File.Exists(oldPath)) return oldPath; - vsTest = new Lazy(() => - { - var vsInstallation = - FindVisualStudio(requiredComponent: "Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI") // https://github.com/Microsoft/vswhere/issues/126#issuecomment-360542783 - ?? throw new InvalidOperationException("VSTest is not installed with Visual Studio on this machine."); + throw new FileNotFoundException("Cannot locate MSBuild.exe."); + }); - return Path.Combine(vsInstallation, @"Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe"); - }); + vsTest = new Lazy(() => + { + var vsInstallation = + FindVisualStudio(requiredComponent: "Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI") // https://github.com/Microsoft/vswhere/issues/126#issuecomment-360542783 + ?? throw new InvalidOperationException("VSTest is not installed with Visual Studio on this machine."); - vsWhere = new Lazy(() => Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), - @"Microsoft Visual Studio\Installer\vswhere.exe")); - } + return Path.Combine(vsInstallation, @"Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe"); + }); - private string FindDownloadedTool(string id, string fileName, string downloadUrl) - { - var directory = Path.Combine(downloadCacheDirectory, Utils.GetSafeFilename(id)); - var toolPath = Path.Combine(directory, fileName); + vsWhere = new Lazy(() => Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), + @"Microsoft Visual Studio\Installer\vswhere.exe")); + } - if (!File.Exists(toolPath)) - { - Directory.CreateDirectory(directory); + private string FindDownloadedTool(string id, string fileName, string downloadUrl) + { + var directory = Path.Combine(downloadCacheDirectory, Utils.GetSafeFilename(id)); + var toolPath = Path.Combine(directory, fileName); - using var client = new WebClient(); - client.DownloadFile(downloadUrl, toolPath); - } + if (!File.Exists(toolPath)) + { + Directory.CreateDirectory(directory); - return toolPath; + using var client = new WebClient(); + client.DownloadFile(downloadUrl, toolPath); } - private string FindVisualStudio(string requiredComponent) - { - var arguments = new[] { "-latest", "-products", "*", "-requires", requiredComponent, "-property", "installationPath" }; + return toolPath; + } - var releaseInstallationPath = ProcessUtils.Run(Environment.CurrentDirectory, VSWhere, arguments) - .ThrowIfError() - .StdOut; + private string FindVisualStudio(string requiredComponent) + { + var arguments = new[] { "-latest", "-products", "*", "-requires", requiredComponent, "-property", "installationPath" }; - if (!string.IsNullOrEmpty(releaseInstallationPath)) - return releaseInstallationPath; + var releaseInstallationPath = ProcessUtils.Run(Environment.CurrentDirectory, VSWhere, arguments) + .ThrowIfError() + .StdOut; - var prereleaseInstallationPath = - ProcessUtils.Run( + if (!string.IsNullOrEmpty(releaseInstallationPath)) + return releaseInstallationPath; + + var prereleaseInstallationPath = + ProcessUtils.Run( Environment.CurrentDirectory, VSWhere, arguments.Concat(new[] { "-prerelease" })) .ThrowIfError() .StdOut; - if (!string.IsNullOrEmpty(prereleaseInstallationPath)) - return prereleaseInstallationPath; + if (!string.IsNullOrEmpty(prereleaseInstallationPath)) + return prereleaseInstallationPath; - return null; - } + return null; } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VSTestResult.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VSTestResult.cs index b023aaba..9ca252d6 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VSTestResult.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VSTestResult.cs @@ -6,87 +6,86 @@ using System.Xml.Linq; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +[DebuggerDisplay("{ToString(),nq}")] +public readonly struct VSTestResult { - [DebuggerDisplay("{ToString(),nq}")] - public readonly struct VSTestResult - { - public ProcessRunResult ProcessRunResult { get; } - public string Outcome { get; } - public VSTestResultCounters Counters { get; } - public IReadOnlyList RunErrors { get; } - public IReadOnlyList RunWarnings { get; } + public ProcessRunResult ProcessRunResult { get; } + public string Outcome { get; } + public VSTestResultCounters Counters { get; } + public IReadOnlyList RunErrors { get; } + public IReadOnlyList RunWarnings { get; } - public VSTestResult(ProcessRunResult processRunResult) - { - ProcessRunResult = processRunResult; - Outcome = ""; - Counters = VSTestResultCounters.CreateEmptyCounters(); - RunErrors = Array.Empty(); - RunWarnings = Array.Empty(); - } + public VSTestResult(ProcessRunResult processRunResult) + { + ProcessRunResult = processRunResult; + Outcome = ""; + Counters = VSTestResultCounters.CreateEmptyCounters(); + RunErrors = Array.Empty(); + RunWarnings = Array.Empty(); + } - public VSTestResult(ProcessRunResult processRunResult, string outcome, VSTestResultCounters counters, IReadOnlyList runErrors = null, IReadOnlyList runWarnings = null) - { - ProcessRunResult = processRunResult; - Outcome = outcome; - Counters = counters; - RunErrors = runErrors ?? Array.Empty(); - RunWarnings = runWarnings ?? Array.Empty(); - } + public VSTestResult(ProcessRunResult processRunResult, string outcome, VSTestResultCounters counters, IReadOnlyList runErrors = null, IReadOnlyList runWarnings = null) + { + ProcessRunResult = processRunResult; + Outcome = outcome; + Counters = counters; + RunErrors = runErrors ?? Array.Empty(); + RunWarnings = runWarnings ?? Array.Empty(); + } - public static VSTestResult Load(ProcessRunResult processRunResult, string trxFilePath) - { - var trx = XDocument.Load(trxFilePath); + public static VSTestResult Load(ProcessRunResult processRunResult, string trxFilePath) + { + var trx = XDocument.Load(trxFilePath); - var ns = (XNamespace)"http://microsoft.com/schemas/VisualStudio/TeamTest/2010"; + var ns = (XNamespace)"http://microsoft.com/schemas/VisualStudio/TeamTest/2010"; - var resultSummary = trx.Root.Element(ns + "ResultSummary"); - var counters = resultSummary.Element(ns + "Counters"); + var resultSummary = trx.Root.Element(ns + "ResultSummary"); + var counters = resultSummary.Element(ns + "Counters"); - var runInfos = resultSummary.Element(ns + "RunInfos")?.Elements().Select(runInfo => ( - Outcome: runInfo.Attribute("outcome")?.Value, - Text: runInfo.Element(ns + "Text")?.Value ?? string.Empty)); + var runInfos = resultSummary.Element(ns + "RunInfos")?.Elements().Select(runInfo => ( + Outcome: runInfo.Attribute("outcome")?.Value, + Text: runInfo.Element(ns + "Text")?.Value ?? string.Empty)); - return new VSTestResult( - processRunResult, - (string)resultSummary.Attribute("outcome"), - new VSTestResultCounters( - (int)counters.Attribute("total"), - (int)counters.Attribute("executed"), - (int)counters.Attribute("passed"), - (int)counters.Attribute("failed"), - (int)counters.Attribute("error"), - (int)counters.Attribute("timeout"), - (int)counters.Attribute("aborted"), - (int)counters.Attribute("inconclusive"), - (int)counters.Attribute("passedButRunAborted"), - (int)counters.Attribute("notRunnable"), - (int)counters.Attribute("notExecuted"), - (int)counters.Attribute("disconnected"), - (int)counters.Attribute("warning"), - (int)counters.Attribute("completed"), - (int)counters.Attribute("inProgress"), - (int)counters.Attribute("pending")), - runErrors: runInfos?.Where(i => i.Outcome == "Error").Select(i => i.Text).ToList(), - runWarnings: runInfos?.Where(i => i.Outcome == "Warning").Select(i => i.Text).ToList()); - } + return new VSTestResult( + processRunResult, + (string)resultSummary.Attribute("outcome"), + new VSTestResultCounters( + (int)counters.Attribute("total"), + (int)counters.Attribute("executed"), + (int)counters.Attribute("passed"), + (int)counters.Attribute("failed"), + (int)counters.Attribute("error"), + (int)counters.Attribute("timeout"), + (int)counters.Attribute("aborted"), + (int)counters.Attribute("inconclusive"), + (int)counters.Attribute("passedButRunAborted"), + (int)counters.Attribute("notRunnable"), + (int)counters.Attribute("notExecuted"), + (int)counters.Attribute("disconnected"), + (int)counters.Attribute("warning"), + (int)counters.Attribute("completed"), + (int)counters.Attribute("inProgress"), + (int)counters.Attribute("pending")), + runErrors: runInfos?.Where(i => i.Outcome == "Error").Select(i => i.Text).ToList(), + runWarnings: runInfos?.Where(i => i.Outcome == "Warning").Select(i => i.Text).ToList()); + } - public void AssertSinglePassingTest() - { - Assert.That(RunErrors, Is.Empty); + public void AssertSinglePassingTest() + { + Assert.That(RunErrors, Is.Empty); - if (RunWarnings.Any()) - Assert.Fail("Unexpected VSTest warnings. Standard output:" + Environment.NewLine + ProcessRunResult.StdOut); + if (RunWarnings.Any()) + Assert.Fail("Unexpected VSTest warnings. Standard output:" + Environment.NewLine + ProcessRunResult.StdOut); - Assert.That(Counters.Total, Is.EqualTo(1), "There should be a single test in the test results."); - Assert.That(Counters.Passed, Is.EqualTo(1), "There should be a single test passing in the test results."); - } + Assert.That(Counters.Total, Is.EqualTo(1), "There should be a single test in the test results."); + Assert.That(Counters.Passed, Is.EqualTo(1), "There should be a single test passing in the test results."); + } - public override string ToString() - { - return Outcome + ", " + Counters; - } + public override string ToString() + { + return Outcome + ", " + Counters; } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VSTestResultCounters.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VSTestResultCounters.cs index c91a6f8c..1d2f1ae4 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VSTestResultCounters.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VSTestResultCounters.cs @@ -1,68 +1,67 @@ using System.Diagnostics; -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +[DebuggerDisplay("{ToString(),nq}")] +public readonly struct VSTestResultCounters { - [DebuggerDisplay("{ToString(),nq}")] - public readonly struct VSTestResultCounters - { - public int Total { get; } - public int Executed { get; } - public int Passed { get; } - public int Failed { get; } - public int Error { get; } - public int Timeout { get; } - public int Aborted { get; } - public int Inconclusive { get; } - public int PassedButRunAborted { get; } - public int NotRunnable { get; } - public int NotExecuted { get; } - public int Disconnected { get; } - public int Warning { get; } - public int Completed { get; } - public int InProgress { get; } - public int Pending { get; } + public int Total { get; } + public int Executed { get; } + public int Passed { get; } + public int Failed { get; } + public int Error { get; } + public int Timeout { get; } + public int Aborted { get; } + public int Inconclusive { get; } + public int PassedButRunAborted { get; } + public int NotRunnable { get; } + public int NotExecuted { get; } + public int Disconnected { get; } + public int Warning { get; } + public int Completed { get; } + public int InProgress { get; } + public int Pending { get; } - public static VSTestResultCounters CreateEmptyCounters() => new (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + public static VSTestResultCounters CreateEmptyCounters() => new (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - public VSTestResultCounters( - int total, - int executed, - int passed, - int failed, - int error, - int timeout, - int aborted, - int inconclusive, - int passedButRunAborted, - int notRunnable, - int notExecuted, - int disconnected, - int warning, - int completed, - int inProgress, - int pending) - { - Total = total; - Executed = executed; - Passed = passed; - Failed = failed; - Error = error; - Timeout = timeout; - Aborted = aborted; - Inconclusive = inconclusive; - PassedButRunAborted = passedButRunAborted; - NotRunnable = notRunnable; - NotExecuted = notExecuted; - Disconnected = disconnected; - Warning = warning; - Completed = completed; - InProgress = inProgress; - Pending = pending; - } + public VSTestResultCounters( + int total, + int executed, + int passed, + int failed, + int error, + int timeout, + int aborted, + int inconclusive, + int passedButRunAborted, + int notRunnable, + int notExecuted, + int disconnected, + int warning, + int completed, + int inProgress, + int pending) + { + Total = total; + Executed = executed; + Passed = passed; + Failed = failed; + Error = error; + Timeout = timeout; + Aborted = aborted; + Inconclusive = inconclusive; + PassedButRunAborted = passedButRunAborted; + NotRunnable = notRunnable; + NotExecuted = notExecuted; + Disconnected = disconnected; + Warning = warning; + Completed = completed; + InProgress = inProgress; + Pending = pending; + } - public override string ToString() - { - return "Total: " + Total; - } + public override string ToString() + { + return "Total: " + Total; } -} +} \ No newline at end of file diff --git a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VsTestFilter.cs b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VsTestFilter.cs index 442b89ad..b9a37507 100644 --- a/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VsTestFilter.cs +++ b/src/NUnit.TestAdapter.Tests.Acceptance/WorkspaceTools/VsTestFilter.cs @@ -1,49 +1,48 @@ -namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools +namespace NUnit.VisualStudio.TestAdapter.Tests.Acceptance.WorkspaceTools; + +public interface IFilterArgument { - public interface IFilterArgument - { - string CompletedArgument(); - bool HasArguments { get; } - } + string CompletedArgument(); + bool HasArguments { get; } +} - public abstract class VsTestFilter : IFilterArgument +public abstract class VsTestFilter : IFilterArgument +{ + protected string Arguments { get; } + public bool HasArguments => Arguments.Length > 0; + protected VsTestFilter(string arguments) { - protected string Arguments { get; } - public bool HasArguments => Arguments.Length > 0; - protected VsTestFilter(string arguments) - { - Arguments = arguments; - } + Arguments = arguments; + } - public abstract string CompletedArgument(); + public abstract string CompletedArgument(); - public static IFilterArgument NoFilter => new VsTestTestCaseFilter(""); - } + public static IFilterArgument NoFilter => new VsTestTestCaseFilter(""); +} - public class VsTestTestCaseFilter : VsTestFilter +public class VsTestTestCaseFilter : VsTestFilter +{ + public VsTestTestCaseFilter(string arguments) : base(arguments) { - public VsTestTestCaseFilter(string arguments) : base(arguments) - { - } - - public override string CompletedArgument() - { - var completeFilterStatement = $"/TestCaseFilter:{Arguments}"; - return completeFilterStatement; - } } - public class VsTestTestsFilter : VsTestFilter + public override string CompletedArgument() { - public VsTestTestsFilter(string arguments) : base(arguments) - { - } - public override string CompletedArgument() - { - var completeFilterStatement = $"/Tests:{Arguments}"; - return completeFilterStatement; - } + var completeFilterStatement = $"/TestCaseFilter:{Arguments}"; + return completeFilterStatement; } } + +public class VsTestTestsFilter : VsTestFilter +{ + public VsTestTestsFilter(string arguments) : base(arguments) + { + } + public override string CompletedArgument() + { + var completeFilterStatement = $"/Tests:{Arguments}"; + return completeFilterStatement; + } +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/AdapterSettings.cs b/src/NUnitTestAdapter/AdapterSettings.cs index bf168928..f065ebb6 100644 --- a/src/NUnitTestAdapter/AdapterSettings.cs +++ b/src/NUnitTestAdapter/AdapterSettings.cs @@ -31,587 +31,586 @@ using NUnit.Engine; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public enum VsTestCategoryType { - public enum VsTestCategoryType - { - NUnit, - MsTest - } + NUnit, + MsTest +} - public enum DisplayNameOptions - { - Name, - FullName, - FullNameSep - } +public enum DisplayNameOptions +{ + Name, + FullName, + FullNameSep +} - public enum DiscoveryMethod - { - Legacy, - Current - } +public enum DiscoveryMethod +{ + Legacy, + Current +} - public class AdapterSettings(ITestLogger logger) : IAdapterSettings - { - private const string RandomSeedFile = "nunit_random_seed.tmp"; +public class AdapterSettings(ITestLogger logger) : IAdapterSettings +{ + private const string RandomSeedFile = "nunit_random_seed.tmp"; - #region Properties - General + #region Properties - General - public int MaxCpuCount { get; private set; } + public int MaxCpuCount { get; private set; } - public string ResultsDirectory { get; private set; } + public string ResultsDirectory { get; private set; } - public string TargetPlatform { get; private set; } + public string TargetPlatform { get; private set; } - public string TargetFrameworkVersion { get; private set; } + public string TargetFrameworkVersion { get; private set; } - public string TestAdapterPaths { get; private set; } + public string TestAdapterPaths { get; private set; } - /// - /// If false, an adapter need not parse symbols to provide test case file, line number. - /// - public bool CollectSourceInformation { get; private set; } + /// + /// If false, an adapter need not parse symbols to provide test case file, line number. + /// + public bool CollectSourceInformation { get; private set; } - /// - /// If true, an adapter shouldn't create appdomains to run tests. - /// - public bool DisableAppDomain { get; private set; } + /// + /// If true, an adapter shouldn't create appdomains to run tests. + /// + public bool DisableAppDomain { get; private set; } - /// - /// If true, an adapter should disable any test case parallelization. - /// - public bool DisableParallelization { get; private set; } + /// + /// If true, an adapter should disable any test case parallelization. + /// + public bool DisableParallelization { get; private set; } - public bool AllowParallelWithDebugger { get; private set; } + public bool AllowParallelWithDebugger { get; private set; } - /// - /// True if test run is triggered in an IDE/Editor context. - /// - public bool DesignMode { get; private set; } + /// + /// True if test run is triggered in an IDE/Editor context. + /// + public bool DesignMode { get; private set; } - #endregion + #endregion - #region Properties - TestRunParameters + #region Properties - TestRunParameters - public IDictionary TestProperties { get; private set; } + public IDictionary TestProperties { get; private set; } - #endregion + #endregion - #region Properties - NUnit Specific + #region Properties - NUnit Specific - public string InternalTraceLevel { get; private set; } - public InternalTraceLevel InternalTraceLevelEnum { get; private set; } + public string InternalTraceLevel { get; private set; } + public InternalTraceLevel InternalTraceLevelEnum { get; private set; } - /// - /// Is null if not set in runsettings. - /// - public string WorkDirectory { get; private set; } - public string Where { get; private set; } - public string TestOutputXml { get; private set; } - public string TestOutputXmlFileName { get; private set; } - public bool UseTestOutputXml => !string.IsNullOrEmpty(TestOutputXml) || OutputXmlFolderMode == OutputXmlFolderMode.UseResultDirectory; + /// + /// Is null if not set in runsettings. + /// + public string WorkDirectory { get; private set; } + public string Where { get; private set; } + public string TestOutputXml { get; private set; } + public string TestOutputXmlFileName { get; private set; } + public bool UseTestOutputXml => !string.IsNullOrEmpty(TestOutputXml) || OutputXmlFolderMode == OutputXmlFolderMode.UseResultDirectory; - public OutputXmlFolderMode OutputXmlFolderMode { get; private set; } = OutputXmlFolderMode.RelativeToWorkFolder; + public OutputXmlFolderMode OutputXmlFolderMode { get; private set; } = OutputXmlFolderMode.RelativeToWorkFolder; - /// - /// Calculated property. - /// - public string TestOutputFolder { get; private set; } = ""; + /// + /// Calculated property. + /// + public string TestOutputFolder { get; private set; } = ""; - public bool NewOutputXmlFileForEachRun { get; private set; } - public int DefaultTimeout { get; private set; } + public bool NewOutputXmlFileForEachRun { get; private set; } + public int DefaultTimeout { get; private set; } - public int NumberOfTestWorkers { get; private set; } + public int NumberOfTestWorkers { get; private set; } - public bool ShadowCopyFiles { get; private set; } + public bool ShadowCopyFiles { get; private set; } - public int Verbosity { get; private set; } + public int Verbosity { get; private set; } - public bool UseVsKeepEngineRunning { get; private set; } + public bool UseVsKeepEngineRunning { get; private set; } - public string BasePath { get; private set; } + public string BasePath { get; private set; } - public string PrivateBinPath { get; private set; } + public string PrivateBinPath { get; private set; } - public int? RandomSeed { get; private set; } - public bool RandomSeedSpecified { get; private set; } + public int? RandomSeed { get; private set; } + public bool RandomSeedSpecified { get; private set; } - public bool CollectDataForEachTestSeparately { get; private set; } + public bool CollectDataForEachTestSeparately { get; private set; } - public bool InProcDataCollectorsAvailable { get; private set; } + public bool InProcDataCollectorsAvailable { get; private set; } - public bool SynchronousEvents { get; private set; } + public bool SynchronousEvents { get; private set; } - public string DomainUsage { get; private set; } + public string DomainUsage { get; private set; } - public bool ShowInternalProperties { get; private set; } - public bool UseParentFQNForParametrizedTests { get; private set; } // Default is false. True can fix certain test name patterns, but may have side effects. - public bool UseNUnitIdforTestCaseId { get; private set; } // default is false. - public int ConsoleOut { get; private set; } - public bool StopOnError { get; private set; } + public bool ShowInternalProperties { get; private set; } + public bool UseParentFQNForParametrizedTests { get; private set; } // Default is false. True can fix certain test name patterns, but may have side effects. + public bool UseNUnitIdforTestCaseId { get; private set; } // default is false. + public int ConsoleOut { get; private set; } + public bool StopOnError { get; private set; } - public DiscoveryMethod DiscoveryMethod { get; private set; } = DiscoveryMethod.Current; - public bool SkipNonTestAssemblies { get; private set; } - public int AssemblySelectLimit { get; private set; } - public bool UseNUnitFilter { get; private set; } - public bool IncludeStackTraceForSuites { get; private set; } + public DiscoveryMethod DiscoveryMethod { get; private set; } = DiscoveryMethod.Current; + public bool SkipNonTestAssemblies { get; private set; } + public int AssemblySelectLimit { get; private set; } + public bool UseNUnitFilter { get; private set; } + public bool IncludeStackTraceForSuites { get; private set; } - public VsTestCategoryType VsTestCategoryType { get; private set; } = VsTestCategoryType.NUnit; + public VsTestCategoryType VsTestCategoryType { get; private set; } = VsTestCategoryType.NUnit; - /// - /// Syntax documentation . - /// - public string DefaultTestNamePattern { get; set; } + /// + /// Syntax documentation . + /// + public string DefaultTestNamePattern { get; set; } - public bool PreFilter { get; private set; } + public bool PreFilter { get; private set; } - public TestOutcome MapWarningTo { get; private set; } + public TestOutcome MapWarningTo { get; private set; } - public bool UseTestNameInConsoleOutput { get; private set; } + public bool UseTestNameInConsoleOutput { get; private set; } - public DisplayNameOptions DisplayName { get; private set; } = DisplayNameOptions.Name; + public DisplayNameOptions DisplayName { get; private set; } = DisplayNameOptions.Name; - public char FullnameSeparator { get; private set; } = ':'; + public char FullnameSeparator { get; private set; } = ':'; - public ExplicitModeEnum ExplicitMode { get; private set; } = ExplicitModeEnum.Strict; - public bool SkipExecutionWhenNoTests { get; private set; } + public ExplicitModeEnum ExplicitMode { get; private set; } = ExplicitModeEnum.Strict; + public bool SkipExecutionWhenNoTests { get; private set; } - #region NUnit Diagnostic properties - public bool DumpXmlTestDiscovery { get; private set; } + #region NUnit Diagnostic properties + public bool DumpXmlTestDiscovery { get; private set; } - public bool DumpXmlTestResults { get; private set; } + public bool DumpXmlTestResults { get; private set; } - public bool DumpVsInput { get; private set; } + public bool DumpVsInput { get; private set; } - public bool FreakMode { get; private set; } - public bool Debug { get; private set; } - public bool DebugExecution { get; private set; } - public bool DebugDiscovery { get; private set; } + public bool FreakMode { get; private set; } + public bool Debug { get; private set; } + public bool DebugExecution { get; private set; } + public bool DebugDiscovery { get; private set; } - #endregion + #endregion - #endregion + #endregion - #region Public Methods + #region Public Methods - /// - /// Initialized by the Load method. - /// - private TestLogger testLog; + /// + /// Initialized by the Load method. + /// + private TestLogger testLog; - public void Load(IDiscoveryContext context, TestLogger testLogger) - { - testLog = testLogger; - if (context == null) - throw new ArgumentNullException(nameof(context), "Load called with null context"); + public void Load(IDiscoveryContext context, TestLogger testLogger) + { + testLog = testLogger; + if (context == null) + throw new ArgumentNullException(nameof(context), "Load called with null context"); - Load(context.RunSettings?.SettingsXml); - } + Load(context.RunSettings?.SettingsXml); + } - public void Load(string settingsXml) + public void Load(string settingsXml) + { + if (string.IsNullOrEmpty(settingsXml)) + settingsXml = ""; + + // Visual Studio already gives a good error message if the .runsettings + // file is poorly formed, so we don't need to do anything more. + var doc = new XmlDocument(); + doc.LoadXml(settingsXml); + + var nunitNode = doc.SelectSingleNode("RunSettings/NUnit"); + Verbosity = GetInnerTextAsInt(nunitNode, nameof(Verbosity), 0); + logger.Verbosity = Verbosity; + + ExtractRunConfiguration(doc); + + UpdateTestProperties(doc); + + // NUnit settings + WorkDirectory = GetInnerTextWithLog(nunitNode, nameof(WorkDirectory)); + Where = GetInnerTextWithLog(nunitNode, nameof(Where)); + DefaultTimeout = GetInnerTextAsInt(nunitNode, nameof(DefaultTimeout), 0); + NumberOfTestWorkers = GetInnerTextAsInt(nunitNode, nameof(NumberOfTestWorkers), -1); + ShadowCopyFiles = GetInnerTextAsBool(nunitNode, nameof(ShadowCopyFiles), false); + UseVsKeepEngineRunning = GetInnerTextAsBool(nunitNode, nameof(UseVsKeepEngineRunning), false); + BasePath = GetInnerTextWithLog(nunitNode, nameof(BasePath)); + PrivateBinPath = GetInnerTextWithLog(nunitNode, nameof(PrivateBinPath)); + ParseOutputXml(nunitNode); + NewOutputXmlFileForEachRun = GetInnerTextAsBool(nunitNode, nameof(NewOutputXmlFileForEachRun), false); + + RandomSeed = GetInnerTextAsNullableInt(nunitNode, nameof(RandomSeed)); + RandomSeedSpecified = RandomSeed.HasValue; + if (!RandomSeedSpecified) + RandomSeed = new Random().Next(); + DefaultTestNamePattern = GetInnerTextWithLog(nunitNode, nameof(DefaultTestNamePattern)); + ShowInternalProperties = GetInnerTextAsBool(nunitNode, nameof(ShowInternalProperties), false); + UseParentFQNForParametrizedTests = GetInnerTextAsBool(nunitNode, nameof(UseParentFQNForParametrizedTests), false); + UseNUnitIdforTestCaseId = GetInnerTextAsBool(nunitNode, nameof(UseNUnitIdforTestCaseId), false); + ConsoleOut = GetInnerTextAsInt(nunitNode, nameof(ConsoleOut), 1); // 0 no output to console, 1 : output to console, 2: output to console as warnings + StopOnError = GetInnerTextAsBool(nunitNode, nameof(StopOnError), false); + UseNUnitFilter = GetInnerTextAsBool(nunitNode, nameof(UseNUnitFilter), true); + IncludeStackTraceForSuites = GetInnerTextAsBool(nunitNode, nameof(IncludeStackTraceForSuites), true); + EnsureAttachmentFileScheme = GetInnerTextAsBool(nunitNode, nameof(EnsureAttachmentFileScheme), false); + SkipExecutionWhenNoTests = GetInnerTextAsBool(nunitNode, nameof(SkipExecutionWhenNoTests), false); + + // Engine settings + DiscoveryMethod = MapEnum(GetInnerText(nunitNode, nameof(DiscoveryMethod), Verbosity > 0), DiscoveryMethod.Current); + SkipNonTestAssemblies = GetInnerTextAsBool(nunitNode, nameof(SkipNonTestAssemblies), true); + AssemblySelectLimit = GetInnerTextAsInt(nunitNode, nameof(AssemblySelectLimit), 2000); + + + ExplicitMode = MapEnum(GetInnerText(nunitNode, nameof(ExplicitMode), Verbosity > 0), ExplicitModeEnum.Strict); + + + ExtractNUnitDiagnosticSettings(nunitNode); + + // Adapter Display Options + MapDisplayName(GetInnerText(nunitNode, nameof(DisplayName), Verbosity > 0)); + FullnameSeparator = GetInnerText(nunitNode, nameof(FullnameSeparator), Verbosity > 0)?[0] ?? ':'; + + // EndDisplay + + PreFilter = GetInnerTextAsBool(nunitNode, nameof(PreFilter), false); + MapTestCategory(GetInnerText(nunitNode, nameof(VsTestCategoryType), Verbosity > 0)); + MapWarningTo = MapWarningOutcome(GetInnerText(nunitNode, nameof(MapWarningTo), Verbosity > 0)); + UseTestNameInConsoleOutput = GetInnerTextAsBool(nunitNode, nameof(UseTestNameInConsoleOutput), false); + var inProcDataCollectorNode = + doc.SelectSingleNode("RunSettings/InProcDataCollectionRunSettings/InProcDataCollectors"); + InProcDataCollectorsAvailable = inProcDataCollectorNode != null && + inProcDataCollectorNode.SelectNodes("InProcDataCollector")?.Count > 0; + + // Older versions of VS do not pass the CollectDataForEachTestSeparately configuration together with the LiveUnitTesting collector. + // However, the adapter is expected to run in CollectDataForEachTestSeparately mode. + // As a result for backwards compatibility reasons enable CollectDataForEachTestSeparately mode whenever LiveUnitTesting collector is being used. + var hasLiveUnitTestingDataCollector = + inProcDataCollectorNode?.SelectSingleNode( + "InProcDataCollector[@uri='InProcDataCollector://Microsoft/LiveUnitTesting/1.0']") != null; + + // TestPlatform can choose to opt in to run tests one at a time so that the InProcDataCollectors can collect the data for each one of them separately. + // In that case, we need to ensure that tests do not run in parallel and the test started/test ended events are sent synchronously. + if (CollectDataForEachTestSeparately || hasLiveUnitTestingDataCollector) { - if (string.IsNullOrEmpty(settingsXml)) - settingsXml = ""; - - // Visual Studio already gives a good error message if the .runsettings - // file is poorly formed, so we don't need to do anything more. - var doc = new XmlDocument(); - doc.LoadXml(settingsXml); - - var nunitNode = doc.SelectSingleNode("RunSettings/NUnit"); - Verbosity = GetInnerTextAsInt(nunitNode, nameof(Verbosity), 0); - logger.Verbosity = Verbosity; - - ExtractRunConfiguration(doc); - - UpdateTestProperties(doc); - - // NUnit settings - WorkDirectory = GetInnerTextWithLog(nunitNode, nameof(WorkDirectory)); - Where = GetInnerTextWithLog(nunitNode, nameof(Where)); - DefaultTimeout = GetInnerTextAsInt(nunitNode, nameof(DefaultTimeout), 0); - NumberOfTestWorkers = GetInnerTextAsInt(nunitNode, nameof(NumberOfTestWorkers), -1); - ShadowCopyFiles = GetInnerTextAsBool(nunitNode, nameof(ShadowCopyFiles), false); - UseVsKeepEngineRunning = GetInnerTextAsBool(nunitNode, nameof(UseVsKeepEngineRunning), false); - BasePath = GetInnerTextWithLog(nunitNode, nameof(BasePath)); - PrivateBinPath = GetInnerTextWithLog(nunitNode, nameof(PrivateBinPath)); - ParseOutputXml(nunitNode); - NewOutputXmlFileForEachRun = GetInnerTextAsBool(nunitNode, nameof(NewOutputXmlFileForEachRun), false); - - RandomSeed = GetInnerTextAsNullableInt(nunitNode, nameof(RandomSeed)); - RandomSeedSpecified = RandomSeed.HasValue; - if (!RandomSeedSpecified) - RandomSeed = new Random().Next(); - DefaultTestNamePattern = GetInnerTextWithLog(nunitNode, nameof(DefaultTestNamePattern)); - ShowInternalProperties = GetInnerTextAsBool(nunitNode, nameof(ShowInternalProperties), false); - UseParentFQNForParametrizedTests = GetInnerTextAsBool(nunitNode, nameof(UseParentFQNForParametrizedTests), false); - UseNUnitIdforTestCaseId = GetInnerTextAsBool(nunitNode, nameof(UseNUnitIdforTestCaseId), false); - ConsoleOut = GetInnerTextAsInt(nunitNode, nameof(ConsoleOut), 1); // 0 no output to console, 1 : output to console, 2: output to console as warnings - StopOnError = GetInnerTextAsBool(nunitNode, nameof(StopOnError), false); - UseNUnitFilter = GetInnerTextAsBool(nunitNode, nameof(UseNUnitFilter), true); - IncludeStackTraceForSuites = GetInnerTextAsBool(nunitNode, nameof(IncludeStackTraceForSuites), true); - EnsureAttachmentFileScheme = GetInnerTextAsBool(nunitNode, nameof(EnsureAttachmentFileScheme), false); - SkipExecutionWhenNoTests = GetInnerTextAsBool(nunitNode, nameof(SkipExecutionWhenNoTests), false); - - // Engine settings - DiscoveryMethod = MapEnum(GetInnerText(nunitNode, nameof(DiscoveryMethod), Verbosity > 0), DiscoveryMethod.Current); - SkipNonTestAssemblies = GetInnerTextAsBool(nunitNode, nameof(SkipNonTestAssemblies), true); - AssemblySelectLimit = GetInnerTextAsInt(nunitNode, nameof(AssemblySelectLimit), 2000); - - - ExplicitMode = MapEnum(GetInnerText(nunitNode, nameof(ExplicitMode), Verbosity > 0), ExplicitModeEnum.Strict); - - - ExtractNUnitDiagnosticSettings(nunitNode); - - // Adapter Display Options - MapDisplayName(GetInnerText(nunitNode, nameof(DisplayName), Verbosity > 0)); - FullnameSeparator = GetInnerText(nunitNode, nameof(FullnameSeparator), Verbosity > 0)?[0] ?? ':'; - - // EndDisplay - - PreFilter = GetInnerTextAsBool(nunitNode, nameof(PreFilter), false); - MapTestCategory(GetInnerText(nunitNode, nameof(VsTestCategoryType), Verbosity > 0)); - MapWarningTo = MapWarningOutcome(GetInnerText(nunitNode, nameof(MapWarningTo), Verbosity > 0)); - UseTestNameInConsoleOutput = GetInnerTextAsBool(nunitNode, nameof(UseTestNameInConsoleOutput), false); - var inProcDataCollectorNode = - doc.SelectSingleNode("RunSettings/InProcDataCollectionRunSettings/InProcDataCollectors"); - InProcDataCollectorsAvailable = inProcDataCollectorNode != null && - inProcDataCollectorNode.SelectNodes("InProcDataCollector")?.Count > 0; - - // Older versions of VS do not pass the CollectDataForEachTestSeparately configuration together with the LiveUnitTesting collector. - // However, the adapter is expected to run in CollectDataForEachTestSeparately mode. - // As a result for backwards compatibility reasons enable CollectDataForEachTestSeparately mode whenever LiveUnitTesting collector is being used. - var hasLiveUnitTestingDataCollector = - inProcDataCollectorNode?.SelectSingleNode( - "InProcDataCollector[@uri='InProcDataCollector://Microsoft/LiveUnitTesting/1.0']") != null; - - // TestPlatform can choose to opt in to run tests one at a time so that the InProcDataCollectors can collect the data for each one of them separately. - // In that case, we need to ensure that tests do not run in parallel and the test started/test ended events are sent synchronously. - if (CollectDataForEachTestSeparately || hasLiveUnitTestingDataCollector) + NumberOfTestWorkers = 0; + SynchronousEvents = true; + if (Verbosity >= 4) { - NumberOfTestWorkers = 0; - SynchronousEvents = true; - if (Verbosity >= 4) + if (!InProcDataCollectorsAvailable) { - if (!InProcDataCollectorsAvailable) - { - logger.Info( - "CollectDataForEachTestSeparately is set, which is used to make InProcDataCollectors collect data for each test separately. No InProcDataCollectors can be found, thus the tests will run slower unnecessarily."); - } + logger.Info( + "CollectDataForEachTestSeparately is set, which is used to make InProcDataCollectors collect data for each test separately. No InProcDataCollectors can be found, thus the tests will run slower unnecessarily."); } } - - // If DisableAppDomain settings is passed from the testplatform, set the DomainUsage to None. - if (DisableAppDomain) - { - DomainUsage = "None"; - } - - // Update NumberOfTestWorkers based on the DisableParallelization and NumberOfTestWorkers from runsettings. - UpdateNumberOfTestWorkers(); } - private void ParseOutputXml(XmlNode nunitNode) + // If DisableAppDomain settings is passed from the testplatform, set the DomainUsage to None. + if (DisableAppDomain) { - TestOutputXml = GetInnerTextWithLog(nunitNode, nameof(TestOutputXml)); - TestOutputXmlFileName = GetInnerTextWithLog(nunitNode, nameof(TestOutputXmlFileName)); - if (Path.IsPathRooted(TestOutputXml)) - { - OutputXmlFolderMode = OutputXmlFolderMode.AsSpecified; - return; - } - var outputMode = GetInnerText(nunitNode, nameof(OutputXmlFolderMode), Verbosity > 0); - - if (string.IsNullOrEmpty(WorkDirectory) && string.IsNullOrEmpty(outputMode)) - { - OutputXmlFolderMode = string.IsNullOrEmpty(TestOutputXml) ? OutputXmlFolderMode.UseResultDirectory : OutputXmlFolderMode.RelativeToResultDirectory; - } - - OutputXmlFolderMode = MapEnum(outputMode, OutputXmlFolderMode.RelativeToWorkFolder); + DomainUsage = "None"; } - public string SetTestOutputFolder(string workDirectory) + // Update NumberOfTestWorkers based on the DisableParallelization and NumberOfTestWorkers from runsettings. + UpdateNumberOfTestWorkers(); + } + + private void ParseOutputXml(XmlNode nunitNode) + { + TestOutputXml = GetInnerTextWithLog(nunitNode, nameof(TestOutputXml)); + TestOutputXmlFileName = GetInnerTextWithLog(nunitNode, nameof(TestOutputXmlFileName)); + if (Path.IsPathRooted(TestOutputXml)) { - if (!UseTestOutputXml) - return ""; - switch (OutputXmlFolderMode) - { - case OutputXmlFolderMode.UseResultDirectory: - TestOutputFolder = ResultsDirectory; - return TestOutputFolder; - case OutputXmlFolderMode.RelativeToResultDirectory: - TestOutputFolder = Path.Combine(ResultsDirectory, TestOutputXml); - return TestOutputFolder; - case OutputXmlFolderMode.RelativeToWorkFolder: - TestOutputFolder = Path.Combine(workDirectory, TestOutputXml); - return TestOutputFolder; - case OutputXmlFolderMode.AsSpecified: - TestOutputFolder = TestOutputXml; - return TestOutputFolder; - default: - return ""; - } + OutputXmlFolderMode = OutputXmlFolderMode.AsSpecified; + return; } + var outputMode = GetInnerText(nunitNode, nameof(OutputXmlFolderMode), Verbosity > 0); - private void ExtractNUnitDiagnosticSettings(XmlNode nunitNode) + if (string.IsNullOrEmpty(WorkDirectory) && string.IsNullOrEmpty(outputMode)) { - DumpXmlTestDiscovery = GetInnerTextAsBool(nunitNode, nameof(DumpXmlTestDiscovery), false); - DumpXmlTestResults = GetInnerTextAsBool(nunitNode, nameof(DumpXmlTestResults), false); - DumpVsInput = GetInnerTextAsBool(nunitNode, nameof(DumpVsInput), false); - FreakMode = GetInnerTextAsBool(nunitNode, nameof(FreakMode), false); - InternalTraceLevel = GetInnerTextWithLog(nunitNode, nameof(InternalTraceLevel), "Off", "Error", "Warning", "Info", "Verbose", "Debug"); - InternalTraceLevelEnum = ParseInternalTraceLevel(InternalTraceLevel); - Debug = GetInnerTextAsBool(nunitNode, nameof(Debug), false); - DebugExecution = Debug || GetInnerTextAsBool(nunitNode, nameof(DebugExecution), false); - DebugDiscovery = Debug || GetInnerTextAsBool(nunitNode, nameof(DebugDiscovery), false); + OutputXmlFolderMode = string.IsNullOrEmpty(TestOutputXml) ? OutputXmlFolderMode.UseResultDirectory : OutputXmlFolderMode.RelativeToResultDirectory; } - private InternalTraceLevel ParseInternalTraceLevel(string s) - { - if (s == null) - { - return Engine.InternalTraceLevel.Off; - } + OutputXmlFolderMode = MapEnum(outputMode, OutputXmlFolderMode.RelativeToWorkFolder); + } - try - { - var internalTrace = (InternalTraceLevel)Enum.Parse(typeof(InternalTraceLevel), s); - return internalTrace; - } - catch - { - testLog.Warning($"InternalTraceLevel is non-valid: {s}, see https://docs.nunit.org/articles/vs-test-adapter/Tips-And-Tricks.html"); - return Engine.InternalTraceLevel.Off; - } + public string SetTestOutputFolder(string workDirectory) + { + if (!UseTestOutputXml) + return ""; + switch (OutputXmlFolderMode) + { + case OutputXmlFolderMode.UseResultDirectory: + TestOutputFolder = ResultsDirectory; + return TestOutputFolder; + case OutputXmlFolderMode.RelativeToResultDirectory: + TestOutputFolder = Path.Combine(ResultsDirectory, TestOutputXml); + return TestOutputFolder; + case OutputXmlFolderMode.RelativeToWorkFolder: + TestOutputFolder = Path.Combine(workDirectory, TestOutputXml); + return TestOutputFolder; + case OutputXmlFolderMode.AsSpecified: + TestOutputFolder = TestOutputXml; + return TestOutputFolder; + default: + return ""; } + } + + private void ExtractNUnitDiagnosticSettings(XmlNode nunitNode) + { + DumpXmlTestDiscovery = GetInnerTextAsBool(nunitNode, nameof(DumpXmlTestDiscovery), false); + DumpXmlTestResults = GetInnerTextAsBool(nunitNode, nameof(DumpXmlTestResults), false); + DumpVsInput = GetInnerTextAsBool(nunitNode, nameof(DumpVsInput), false); + FreakMode = GetInnerTextAsBool(nunitNode, nameof(FreakMode), false); + InternalTraceLevel = GetInnerTextWithLog(nunitNode, nameof(InternalTraceLevel), "Off", "Error", "Warning", "Info", "Verbose", "Debug"); + InternalTraceLevelEnum = ParseInternalTraceLevel(InternalTraceLevel); + Debug = GetInnerTextAsBool(nunitNode, nameof(Debug), false); + DebugExecution = Debug || GetInnerTextAsBool(nunitNode, nameof(DebugExecution), false); + DebugDiscovery = Debug || GetInnerTextAsBool(nunitNode, nameof(DebugDiscovery), false); + } - private void UpdateTestProperties(XmlDocument doc) + private InternalTraceLevel ParseInternalTraceLevel(string s) + { + if (s == null) { - TestProperties = new Dictionary(); - foreach (XmlNode node in doc.SelectNodes("RunSettings/TestRunParameters/Parameter")) - { - var key = node.GetAttribute("name"); - var value = node.GetAttribute("value"); - if (key != null && value != null) - TestProperties.Add(key, value); - } + return Engine.InternalTraceLevel.Off; } - private void ExtractRunConfiguration(XmlDocument doc) + try { - var runConfiguration = doc.SelectSingleNode("RunSettings/RunConfiguration"); - MaxCpuCount = GetInnerTextAsInt(runConfiguration, nameof(MaxCpuCount), -1); - ResultsDirectory = GetInnerTextWithLog(runConfiguration, nameof(ResultsDirectory)); - TargetPlatform = GetInnerTextWithLog(runConfiguration, nameof(TargetPlatform)); - TargetFrameworkVersion = GetInnerTextWithLog(runConfiguration, nameof(TargetFrameworkVersion)); - TestAdapterPaths = GetInnerTextWithLog(runConfiguration, nameof(TestAdapterPaths)); - CollectSourceInformation = GetInnerTextAsBool(runConfiguration, nameof(CollectSourceInformation), true); - DisableAppDomain = GetInnerTextAsBool(runConfiguration, nameof(DisableAppDomain), false); - DisableParallelization = GetInnerTextAsBool(runConfiguration, nameof(DisableParallelization), false); - AllowParallelWithDebugger = GetInnerTextAsBool(runConfiguration, nameof(AllowParallelWithDebugger), false); - DesignMode = GetInnerTextAsBool(runConfiguration, nameof(DesignMode), false); - CollectDataForEachTestSeparately = - GetInnerTextAsBool(runConfiguration, nameof(CollectDataForEachTestSeparately), false); + var internalTrace = (InternalTraceLevel)Enum.Parse(typeof(InternalTraceLevel), s); + return internalTrace; } - - private void MapTestCategory(string vsTestCategoryType) + catch { - if (vsTestCategoryType == null) - return; - var ok = TryParse.EnumTryParse(vsTestCategoryType, out VsTestCategoryType result); - if (ok) - VsTestCategoryType = result; - else - logger.Warning($"Invalid value ({vsTestCategoryType}) for VsTestCategoryType, should be either NUnit or MsTest"); + testLog.Warning($"InternalTraceLevel is non-valid: {s}, see https://docs.nunit.org/articles/vs-test-adapter/Tips-And-Tricks.html"); + return Engine.InternalTraceLevel.Off; } + } - private void MapDisplayName(string displaynameoptions) + private void UpdateTestProperties(XmlDocument doc) + { + TestProperties = new Dictionary(); + foreach (XmlNode node in doc.SelectNodes("RunSettings/TestRunParameters/Parameter")) { - if (displaynameoptions == null) - return; - var ok = TryParse.EnumTryParse(displaynameoptions, out DisplayNameOptions result); - if (ok) - DisplayName = result; - else - logger.Warning($"Invalid value ({displaynameoptions}) for DisplayNameOptions, should be either Name, Fullname or FullnameSep"); + var key = node.GetAttribute("name"); + var value = node.GetAttribute("value"); + if (key != null && value != null) + TestProperties.Add(key, value); } + } + private void ExtractRunConfiguration(XmlDocument doc) + { + var runConfiguration = doc.SelectSingleNode("RunSettings/RunConfiguration"); + MaxCpuCount = GetInnerTextAsInt(runConfiguration, nameof(MaxCpuCount), -1); + ResultsDirectory = GetInnerTextWithLog(runConfiguration, nameof(ResultsDirectory)); + TargetPlatform = GetInnerTextWithLog(runConfiguration, nameof(TargetPlatform)); + TargetFrameworkVersion = GetInnerTextWithLog(runConfiguration, nameof(TargetFrameworkVersion)); + TestAdapterPaths = GetInnerTextWithLog(runConfiguration, nameof(TestAdapterPaths)); + CollectSourceInformation = GetInnerTextAsBool(runConfiguration, nameof(CollectSourceInformation), true); + DisableAppDomain = GetInnerTextAsBool(runConfiguration, nameof(DisableAppDomain), false); + DisableParallelization = GetInnerTextAsBool(runConfiguration, nameof(DisableParallelization), false); + AllowParallelWithDebugger = GetInnerTextAsBool(runConfiguration, nameof(AllowParallelWithDebugger), false); + DesignMode = GetInnerTextAsBool(runConfiguration, nameof(DesignMode), false); + CollectDataForEachTestSeparately = + GetInnerTextAsBool(runConfiguration, nameof(CollectDataForEachTestSeparately), false); + } - public void SaveRandomSeed(string dirname) + private void MapTestCategory(string vsTestCategoryType) + { + if (vsTestCategoryType == null) + return; + var ok = TryParse.EnumTryParse(vsTestCategoryType, out VsTestCategoryType result); + if (ok) + VsTestCategoryType = result; + else + logger.Warning($"Invalid value ({vsTestCategoryType}) for VsTestCategoryType, should be either NUnit or MsTest"); + } + + private void MapDisplayName(string displaynameoptions) + { + if (displaynameoptions == null) + return; + var ok = TryParse.EnumTryParse(displaynameoptions, out DisplayNameOptions result); + if (ok) + DisplayName = result; + else + logger.Warning($"Invalid value ({displaynameoptions}) for DisplayNameOptions, should be either Name, Fullname or FullnameSep"); + } + + + public void SaveRandomSeed(string dirname) + { + try { - try - { - var path = Path.Combine(dirname, RandomSeedFile); - File.WriteAllText(path, RandomSeed.Value.ToString()); - } - catch (Exception ex) - { - logger.Warning("Failed to save random seed.", ex); - } + var path = Path.Combine(dirname, RandomSeedFile); + File.WriteAllText(path, RandomSeed.Value.ToString()); } + catch (Exception ex) + { + logger.Warning("Failed to save random seed.", ex); + } + } - public void RestoreRandomSeed(string dirname) + public void RestoreRandomSeed(string dirname) + { + var fullPath = Path.Combine(dirname, RandomSeedFile); + if (!File.Exists(fullPath)) + return; + try { - var fullPath = Path.Combine(dirname, RandomSeedFile); - if (!File.Exists(fullPath)) - return; - try - { - var value = File.ReadAllText(fullPath); - RandomSeed = int.Parse(value); - } - catch (Exception ex) - { - logger.Warning("Unable to restore random seed.", ex); - } + var value = File.ReadAllText(fullPath); + RandomSeed = int.Parse(value); } + catch (Exception ex) + { + logger.Warning("Unable to restore random seed.", ex); + } + } - public bool EnsureAttachmentFileScheme { get; private set; } + public bool EnsureAttachmentFileScheme { get; private set; } - #endregion + #endregion - #region Helper Methods + #region Helper Methods - private void UpdateNumberOfTestWorkers() + private void UpdateNumberOfTestWorkers() + { + // Overriding the NumberOfTestWorkers if DisableParallelization is true. + if (DisableParallelization && NumberOfTestWorkers < 0) { - // Overriding the NumberOfTestWorkers if DisableParallelization is true. - if (DisableParallelization && NumberOfTestWorkers < 0) - { - NumberOfTestWorkers = 0; - } - else if (DisableParallelization && NumberOfTestWorkers > 0) + NumberOfTestWorkers = 0; + } + else if (DisableParallelization && NumberOfTestWorkers > 0) + { + if (logger.Verbosity > 0) { - if (logger.Verbosity > 0) - { - logger.Warning( - $"DisableParallelization:{DisableParallelization} & NumberOfTestWorkers:{NumberOfTestWorkers} are conflicting settings, hence not running in parallel"); - } - NumberOfTestWorkers = 0; + logger.Warning( + $"DisableParallelization:{DisableParallelization} & NumberOfTestWorkers:{NumberOfTestWorkers} are conflicting settings, hence not running in parallel"); } + NumberOfTestWorkers = 0; } + } - private string GetInnerTextWithLog(XmlNode startNode, string xpath, params string[] validValues) - { - return GetInnerText(startNode, xpath, true, validValues); - } + private string GetInnerTextWithLog(XmlNode startNode, string xpath, params string[] validValues) + { + return GetInnerText(startNode, xpath, true, validValues); + } - private string GetInnerText(XmlNode startNode, string xpath, bool log, params string[] validValues) + private string GetInnerText(XmlNode startNode, string xpath, bool log, params string[] validValues) + { + string val = null; + var targetNode = startNode?.SelectSingleNode(xpath); + if (targetNode != null) { - string val = null; - var targetNode = startNode?.SelectSingleNode(xpath); - if (targetNode != null) - { - val = targetNode.InnerText; + val = targetNode.InnerText; - if (validValues is { Length: > 0 }) + if (validValues is { Length: > 0 }) + { + foreach (string valid in validValues) { - foreach (string valid in validValues) - { - if (string.Compare(valid, val, StringComparison.OrdinalIgnoreCase) == 0) - return valid; - } - - throw new ArgumentException($"Invalid value {val} passed for element {xpath}."); + if (string.Compare(valid, val, StringComparison.OrdinalIgnoreCase) == 0) + return valid; } - } - if (log) - Log(xpath, val); - return val; + throw new ArgumentException($"Invalid value {val} passed for element {xpath}."); + } } + if (log) + Log(xpath, val); - private int GetInnerTextAsInt(XmlNode startNode, string xpath, int defaultValue) - { - var temp = GetInnerTextAsNullableInt(startNode, xpath, false); - int res = defaultValue; - if (temp != null) - res = temp.Value; - Log(xpath, res); - return res; - } + return val; + } - private int? GetInnerTextAsNullableInt(XmlNode startNode, string xpath, bool log = true) - { - string temp = GetInnerText(startNode, xpath, log); - int? res = null; - if (!string.IsNullOrEmpty(temp)) - res = int.Parse(temp); - Log(xpath, res); - return res; - } + private int GetInnerTextAsInt(XmlNode startNode, string xpath, int defaultValue) + { + var temp = GetInnerTextAsNullableInt(startNode, xpath, false); + int res = defaultValue; + if (temp != null) + res = temp.Value; + Log(xpath, res); + return res; + } - private bool GetInnerTextAsBool(XmlNode startNode, string xpath, bool defaultValue) - { - string temp = GetInnerText(startNode, xpath, false); - bool res = defaultValue; - if (!string.IsNullOrEmpty(temp)) - res = bool.Parse(temp); - Log(xpath, res); - return res; - } + private int? GetInnerTextAsNullableInt(XmlNode startNode, string xpath, bool log = true) + { + string temp = GetInnerText(startNode, xpath, log); + int? res = null; + if (!string.IsNullOrEmpty(temp)) + res = int.Parse(temp); + Log(xpath, res); + return res; + } - private void Log(string xpath, T res) + private bool GetInnerTextAsBool(XmlNode startNode, string xpath, bool defaultValue) + { + string temp = GetInnerText(startNode, xpath, false); + bool res = defaultValue; + if (!string.IsNullOrEmpty(temp)) + res = bool.Parse(temp); + Log(xpath, res); + return res; + } + + private void Log(string xpath, T res) + { + if (Verbosity >= 4) { - if (Verbosity >= 4) - { - logger.Info($"Setting: {xpath} = {res}"); - } + logger.Info($"Setting: {xpath} = {res}"); } + } - public TestOutcome MapWarningOutcome(string outcome) - { - if (outcome == null) - return TestOutcome.Skipped; + public TestOutcome MapWarningOutcome(string outcome) + { + if (outcome == null) + return TestOutcome.Skipped; - bool ok = TryParse.EnumTryParse(outcome, out TestOutcome testoutcome); + bool ok = TryParse.EnumTryParse(outcome, out TestOutcome testoutcome); - if (!ok) - { - logger.Warning( - $"Invalid value ({outcome}) for MapWarningTo, should be either Skipped,Failed,Passed or None"); - return TestOutcome.Skipped; - } - return testoutcome; + if (!ok) + { + logger.Warning( + $"Invalid value ({outcome}) for MapWarningTo, should be either Skipped,Failed,Passed or None"); + return TestOutcome.Skipped; } + return testoutcome; + } - public T MapEnum(string setting, T defaultValue) - where T : struct, Enum + public T MapEnum(string setting, T defaultValue) + where T : struct, Enum + { + if (setting == null) + return defaultValue; + bool ok = TryParse.EnumTryParse(setting, out T result); + if (!ok) { - if (setting == null) - return defaultValue; - bool ok = TryParse.EnumTryParse(setting, out T result); - if (!ok) - { - logger.Warning( - $"Invalid value ({setting}) for {typeof(T)}"); - return defaultValue; - } - return result; + logger.Warning( + $"Invalid value ({setting}) for {typeof(T)}"); + return defaultValue; } + return result; + } - #endregion - } + #endregion +} - public enum ExplicitModeEnum - { - Strict, - Relaxed, - None - } +public enum ExplicitModeEnum +{ + Strict, + Relaxed, + None +} - public enum OutputXmlFolderMode - { - UseResultDirectory, - RelativeToResultDirectory, - RelativeToWorkFolder, - AsSpecified - } +public enum OutputXmlFolderMode +{ + UseResultDirectory, + RelativeToResultDirectory, + RelativeToWorkFolder, + AsSpecified } \ No newline at end of file diff --git a/src/NUnitTestAdapter/CategoryList.cs b/src/NUnitTestAdapter/CategoryList.cs index 97036b5b..7e31107a 100644 --- a/src/NUnitTestAdapter/CategoryList.cs +++ b/src/NUnitTestAdapter/CategoryList.cs @@ -26,148 +26,147 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public class CategoryList { - public class CategoryList - { - private const string NUnitTestCategoryLabel = "Category"; - - internal static readonly TestProperty NUnitTestCategoryProperty = TestProperty.Register( - id: "NUnit.TestCategory", - // This label is what causes VSTest to include the values in the Test Categories column and show the - // grouping as `X` rather than `Category [X]`. (https://github.com/nunit/nunit3-vs-adapter/issues/310) - label: "TestCategory", - valueType: typeof(string[]), - TestPropertyAttributes.Hidden + private const string NUnitTestCategoryLabel = "Category"; + + internal static readonly TestProperty NUnitTestCategoryProperty = TestProperty.Register( + id: "NUnit.TestCategory", + // This label is what causes VSTest to include the values in the Test Categories column and show the + // grouping as `X` rather than `Category [X]`. (https://github.com/nunit/nunit3-vs-adapter/issues/310) + label: "TestCategory", + valueType: typeof(string[]), + TestPropertyAttributes.Hidden #pragma warning disable CS0618 // This is the only way to fix https://github.com/nunit/nunit3-vs-adapter/issues/310, and MSTest also depends on this. - | TestPropertyAttributes.Trait, + | TestPropertyAttributes.Trait, #pragma warning restore CS0618 - owner: typeof(TestCase)); + owner: typeof(TestCase)); - internal static readonly TestProperty NUnitExplicitProperty = TestProperty.Register( - "NUnit.Explicit", - "Explicit", typeof(bool), TestPropertyAttributes.Hidden, typeof(TestCase)); + internal static readonly TestProperty NUnitExplicitProperty = TestProperty.Register( + "NUnit.Explicit", + "Explicit", typeof(bool), TestPropertyAttributes.Hidden, typeof(TestCase)); - private const string ExplicitTraitName = "Explicit"; + private const string ExplicitTraitName = "Explicit"; - // The empty string causes the UI we want. - // If it's null, the explicit trait doesn't show up in Test Explorer. - // If it's not empty, it shows up as “Explicit [value]” in Test Explorer. - private const string ExplicitTraitValue = ""; + // The empty string causes the UI we want. + // If it's null, the explicit trait doesn't show up in Test Explorer. + // If it's not empty, it shows up as “Explicit [value]” in Test Explorer. + private const string ExplicitTraitValue = ""; - private readonly NUnitProperty explicitTrait = new (ExplicitTraitName, ExplicitTraitValue); + private readonly NUnitProperty explicitTrait = new (ExplicitTraitName, ExplicitTraitValue); - private readonly List categorylist = new (); - private readonly TestCase testCase; - private readonly IAdapterSettings settings; - private readonly bool showInternalProperties; + private readonly List categorylist = new (); + private readonly TestCase testCase; + private readonly IAdapterSettings settings; + private readonly bool showInternalProperties; - public CategoryList(TestCase testCase, IAdapterSettings adapterSettings) - { - settings = adapterSettings; - showInternalProperties = settings.ShowInternalProperties; - this.testCase = testCase; - // MsTestCategoryProperty = TestProperty.Register(MSTestCategoryName, VsTestCategoryLabel, typeof(string[]), TestPropertyAttributes.Hidden | TestPropertyAttributes.Trait, typeof(TestCase)); - } + public CategoryList(TestCase testCase, IAdapterSettings adapterSettings) + { + settings = adapterSettings; + showInternalProperties = settings.ShowInternalProperties; + this.testCase = testCase; + // MsTestCategoryProperty = TestProperty.Register(MSTestCategoryName, VsTestCategoryLabel, typeof(string[]), TestPropertyAttributes.Hidden | TestPropertyAttributes.Trait, typeof(TestCase)); + } - public void AddRange(IEnumerable categories) - { - categorylist.AddRange(categories); - } + public void AddRange(IEnumerable categories) + { + categorylist.AddRange(categories); + } - /// - /// Unsure about purpose of this, see https://github.com/nunit/nunit3-vs-adapter/pull/763#discussion_r446668680. - /// - public int LastNodeListCount { get; private set; } + /// + /// Unsure about purpose of this, see https://github.com/nunit/nunit3-vs-adapter/pull/763#discussion_r446668680. + /// + public int LastNodeListCount { get; private set; } - public IEnumerable ProcessTestCaseProperties(INUnitTestCasePropertyInfo testNode, bool addToCache, string key = null, - IDictionary traitsCache = null) + public IEnumerable ProcessTestCaseProperties(INUnitTestCasePropertyInfo testNode, bool addToCache, string key = null, + IDictionary traitsCache = null) + { + LastNodeListCount = testNode.Properties.Count(); + foreach (var propertyNode in testNode.Properties) { - LastNodeListCount = testNode.Properties.Count(); - foreach (var propertyNode in testNode.Properties) + if (addToCache) + AddTraitsToCache(traitsCache, key, propertyNode); + if (IsInternalProperty(propertyNode)) + continue; + if (propertyNode.Name != NUnitTestCategoryLabel) { - if (addToCache) - AddTraitsToCache(traitsCache, key, propertyNode); - if (IsInternalProperty(propertyNode)) - continue; - if (propertyNode.Name != NUnitTestCategoryLabel) - { - testCase.Traits.Add(new Trait(propertyNode.Name, propertyNode.Value)); - } - else - { - categorylist.Add(propertyNode.Value); - } + testCase.Traits.Add(new Trait(propertyNode.Name, propertyNode.Value)); } - - if (testNode.RunState != RunStateEnum.Explicit) // Attributes?["runstate"]?.Value != "Explicit") - return categorylist; - // Add UI grouping “Explicit” - if (testCase.Traits.All(trait => trait.Name != ExplicitTraitName)) - testCase.Traits.Add(new Trait(ExplicitTraitName, ExplicitTraitValue)); - - // Track whether the test is actually explicit since multiple things result in the same UI grouping - testCase.SetPropertyValue(NUnitExplicitProperty, true); - - if (addToCache) + else { - // Add UI grouping “Explicit” - AddTraitsToCache(traitsCache, key, explicitTrait); - - // Track whether the test is actually explicit since multiple things result in the same UI grouping - GetCachedInfo(traitsCache, key).Explicit = true; + categorylist.Add(propertyNode.Value); } + } + if (testNode.RunState != RunStateEnum.Explicit) // Attributes?["runstate"]?.Value != "Explicit") return categorylist; + // Add UI grouping “Explicit” + if (testCase.Traits.All(trait => trait.Name != ExplicitTraitName)) + testCase.Traits.Add(new Trait(ExplicitTraitName, ExplicitTraitValue)); + + // Track whether the test is actually explicit since multiple things result in the same UI grouping + testCase.SetPropertyValue(NUnitExplicitProperty, true); + + if (addToCache) + { + // Add UI grouping “Explicit” + AddTraitsToCache(traitsCache, key, explicitTrait); + + // Track whether the test is actually explicit since multiple things result in the same UI grouping + GetCachedInfo(traitsCache, key).Explicit = true; } - /// - /// See https://github.com/nunit/nunit/blob/master/src/NUnitFramework/framework/Internal/PropertyNames.cs. - /// - private readonly HashSet _internalProperties = new (StringComparer.OrdinalIgnoreCase) + return categorylist; + } + + /// + /// See https://github.com/nunit/nunit/blob/master/src/NUnitFramework/framework/Internal/PropertyNames.cs. + /// + private readonly HashSet _internalProperties = new (StringComparer.OrdinalIgnoreCase) { "Author", "ApartmentState", "Description", "IgnoreUntilDate", "LevelOfParallelism", "MaxTime", "Order", "ParallelScope", "Repeat", "RequiresThread", "SetCulture", "SetUICulture", "TestOf", "Timeout" }; - private bool IsInternalProperty(NUnitProperty property) + private bool IsInternalProperty(NUnitProperty property) + { + if (property.Name == ExplicitTraitName) { - if (property.Name == ExplicitTraitName) - { - // Otherwise the IsNullOrEmpty check does the wrong thing, - // but I'm not sure of the consequences of allowing all empty strings. - return false; - } + // Otherwise the IsNullOrEmpty check does the wrong thing, + // but I'm not sure of the consequences of allowing all empty strings. + return false; + } - // Property names starting with '_' are for internal use only, but over time this has changed, so we now use a list - return (!showInternalProperties && + // Property names starting with '_' are for internal use only, but over time this has changed, so we now use a list + return (!showInternalProperties && _internalProperties.Contains(property.Name)) || (string.IsNullOrEmpty(property.Name) || - property.Name[0] == '_' || - string.IsNullOrEmpty(property.Value)); - } + property.Name[0] == '_' || + string.IsNullOrEmpty(property.Value)); + } - private void AddTraitsToCache(IDictionary traitsCache, string key, NUnitProperty property) - { - if (IsInternalProperty(property)) return; + private void AddTraitsToCache(IDictionary traitsCache, string key, NUnitProperty property) + { + if (IsInternalProperty(property)) return; - var info = GetCachedInfo(traitsCache, key); - info.Traits.Add(new Trait(property.Name, property.Value)); - } + var info = GetCachedInfo(traitsCache, key); + info.Traits.Add(new Trait(property.Name, property.Value)); + } - private static TraitsFeature.CachedTestCaseInfo GetCachedInfo(IDictionary traitsCache, string key) - { - if (!traitsCache.TryGetValue(key, out var info)) - traitsCache.Add(key, info = new TraitsFeature.CachedTestCaseInfo()); - return info; - } + private static TraitsFeature.CachedTestCaseInfo GetCachedInfo(IDictionary traitsCache, string key) + { + if (!traitsCache.TryGetValue(key, out var info)) + traitsCache.Add(key, info = new TraitsFeature.CachedTestCaseInfo()); + return info; + } - public void UpdateCategoriesToVs() + public void UpdateCategoriesToVs() + { + if (categorylist.Any()) { - if (categorylist.Any()) - { - testCase.SetPropertyValue( - settings.VsTestCategoryType == VsTestCategoryType.NUnit - ? NUnitTestCategoryProperty - : null, categorylist.Distinct().ToArray()); - } + testCase.SetPropertyValue( + settings.VsTestCategoryType == VsTestCategoryType.NUnit + ? NUnitTestCategoryProperty + : null, categorylist.Distinct().ToArray()); } } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/Dump/DumpXml.cs b/src/NUnitTestAdapter/Dump/DumpXml.cs index ec4488c3..75275bb4 100644 --- a/src/NUnitTestAdapter/Dump/DumpXml.cs +++ b/src/NUnitTestAdapter/Dump/DumpXml.cs @@ -4,176 +4,177 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using NUnit.Engine; -namespace NUnit.VisualStudio.TestAdapter.Dump +namespace NUnit.VisualStudio.TestAdapter.Dump; + +public interface IFile { - public interface IFile - { - void WriteAllText(string path, string txt); - bool DirectoryExist(string path); + void WriteAllText(string path, string txt); + bool DirectoryExist(string path); - void CreateDirectory(string path); - } + void CreateDirectory(string path); +} - public class File : IFile +public class File : IFile +{ + public void WriteAllText(string path, string txt) { - public void WriteAllText(string path, string txt) - { - System.IO.File.WriteAllText(path, txt); - } + System.IO.File.WriteAllText(path, txt); + } - public bool DirectoryExist(string path) - { - return Directory.Exists(path); - } + public bool DirectoryExist(string path) + { + return Directory.Exists(path); + } - public void CreateDirectory(string path) - { - Directory.CreateDirectory(path); - } + public void CreateDirectory(string path) + { + Directory.CreateDirectory(path); } +} - public interface IDumpXml +public interface IDumpXml +{ + void AddString(string text); + void AddTestEvent(string text); + void StartDiscoveryInExecution(IGrouping testCases, TestFilter filter, TestPackage package); + void DumpForExecution(); + void DumpVSInputFilter(TestFilter filter, string info); + void StartExecution(TestFilter filter, string atExecution); +} + +public class DumpXml : IDumpXml +{ + private const string Header = "\n"; + private const string Rootstart = "\n"; + private const string Rootend = "\n"; + private readonly IFile file; + private readonly string directory; + private readonly string filename; + private StringBuilder txt; + private static string assemblyPath; + + public DumpXml(string path, IFile file = null) { - void AddString(string text); - void AddTestEvent(string text); - void StartDiscoveryInExecution(IGrouping testCases, TestFilter filter, TestPackage package); - void DumpForExecution(); - void DumpVSInputFilter(TestFilter filter, string info); - void StartExecution(TestFilter filter, string atExecution); + assemblyPath = path; + directory = Path.GetDirectoryName(path); + filename = Path.GetFileName(path); + this.file = file ?? new File(); + txt = new StringBuilder(); + txt.Append(Header); + txt.Append(Rootstart); } - public class DumpXml : IDumpXml + public void Dump2File(string path) { - private const string Header = "\n"; - private const string Rootstart = "\n"; - private const string Rootend = "\n"; - private readonly IFile file; - private readonly string directory; - private readonly string filename; - private StringBuilder txt; - private static string assemblyPath; - - public DumpXml(string path, IFile file = null) - { - assemblyPath = path; - directory = Path.GetDirectoryName(path); - filename = Path.GetFileName(path); - this.file = file ?? new File(); - txt = new StringBuilder(); - txt.Append(Header); - txt.Append(Rootstart); - } - - public void Dump2File(string path) - { - EnsurePathExist(path); - txt.Append(Rootend); - file.WriteAllText(path, txt.ToString()); - txt = new StringBuilder(); - } + EnsurePathExist(path); + txt.Append(Rootend); + file.WriteAllText(path, txt.ToString()); + txt = new StringBuilder(); + } - private void EnsurePathExist(string path) - { - var folder = Path.GetDirectoryName(path); - if (!file.DirectoryExist(folder)) - file.CreateDirectory(folder); - } + private void EnsurePathExist(string path) + { + var folder = Path.GetDirectoryName(path); + if (!file.DirectoryExist(folder)) + file.CreateDirectory(folder); + } - public void DumpForDiscovery() - { - var dumpfolder = Path.Combine(directory, "Dump"); - var path = Path.Combine(dumpfolder, $"D_{filename}.dump"); - Dump2File(path); - } + public void DumpForDiscovery() + { + var dumpfolder = Path.Combine(directory, "Dump"); + var path = Path.Combine(dumpfolder, $"D_{filename}.dump"); + Dump2File(path); + } - public void DumpForExecution() - { - var dumpfolder = Path.Combine(directory, "Dump"); - var path = Path.Combine(dumpfolder, $"E_{filename}.dump"); - Dump2File(path); - } + public void DumpForExecution() + { + var dumpfolder = Path.Combine(directory, "Dump"); + var path = Path.Combine(dumpfolder, $"E_{filename}.dump"); + Dump2File(path); + } - public string RandomName() - { - var guid = Guid.NewGuid(); - var res = Convert.ToBase64String(guid.ToByteArray()); - var res2 = Regex.Replace(res, @"[^a-zA-Z0-9]", ""); - return res2 + ".dump"; - } + public string RandomName() + { + var guid = Guid.NewGuid(); + var res = Convert.ToBase64String(guid.ToByteArray()); + var res2 = Regex.Replace(res, "[^a-zA-Z0-9]", ""); + return res2 + ".dump"; + } - public void AddTestEvent(string text) - { - txt.Append("\n"); - txt.Append(text); - txt.Append("\n\n"); - } + public void AddTestEvent(string text) + { + txt.Append("\n"); + txt.Append(text); + txt.Append("\n\n"); + } - public void AddString(string text) - { - txt.Append(text); - } + public void AddString(string text) + { + txt.Append(text); + } - public void DumpVSInputFilter(TestFilter filter, string info) - { - AddString($"\n {info} {filter.Text}\n\n\n"); - } + public void DumpVSInputFilter(TestFilter filter, string info) + { + AddString($"\n {info} {filter.Text}\n\n\n"); + } - public void DumpVSInput(IEnumerable testCases) + public void DumpVSInput(IEnumerable testCases) + { + AddString(" (DisplayName : FQN : Id)\n"); + foreach (var tc in testCases) { - AddString(" (DisplayName : FQN : Id)\n"); - foreach (var tc in testCases) - { - AddString($" {tc.DisplayName} : {tc.FullyQualifiedName} : {tc.Id}\n"); - } - AddString("\n"); + AddString($" {tc.DisplayName} : {tc.FullyQualifiedName} : {tc.Id}\n"); } + AddString("\n"); + } - public void DumpVSInput2NUnit(TestPackage package) + public void DumpVSInput2NUnit(TestPackage package) + { + AddString($"\n: {package.Name}\n\n"); + foreach (var tc in package.SubPackages) { - AddString($"\n: {package.Name}\n\n"); - foreach (var tc in package.SubPackages) - { - DumpVSInput2NUnit(tc); - } - AddString("\n\n\n"); + DumpVSInput2NUnit(tc); } + AddString("\n\n\n"); + } - private void DumpFromVSInput(IGrouping testCases, TestFilter filter, TestPackage package) - { - AddString("\n\n"); - if (testCases != null) - DumpVSInput(testCases); - DumpVSInput2NUnit(package); - DumpVSInputFilter(filter, ""); - AddString("\n\n"); - } + private void DumpFromVSInput(IGrouping testCases, TestFilter filter, TestPackage package) + { + AddString("\n\n"); + if (testCases != null) + DumpVSInput(testCases); + DumpVSInput2NUnit(package); + DumpVSInputFilter(filter, ""); + AddString("\n\n"); + } - public void StartDiscoveryInExecution(IGrouping testCases, TestFilter filter, TestPackage package) - { - DumpFromVSInput(testCases, filter, package); - AddString($"{assemblyPath}\n\n"); - } + public void StartDiscoveryInExecution(IGrouping testCases, TestFilter filter, TestPackage package) + { + DumpFromVSInput(testCases, filter, package); + AddString($"{assemblyPath}\n\n"); + } - public void StartExecution(TestFilter filter, string atExecution) - { - DumpVSInputFilter(filter, atExecution); - AddString($"\n\n{assemblyPath}\n\n"); - } + public void StartExecution(TestFilter filter, string atExecution) + { + DumpVSInputFilter(filter, atExecution); + AddString($"\n\n{assemblyPath}\n\n"); + } - public static IDumpXml CreateDump(string path, IGrouping testCases, IAdapterSettings settings) - { - if (!settings.DumpXmlTestResults) - return null; - var executionDumpXml = new DumpXml(path); - string runningBy = testCases == null - ? "Sources" - : "TestCases"; - executionDumpXml.AddString($"\n{runningBy}\n"); - return executionDumpXml; - } + public static IDumpXml CreateDump(string path, IGrouping testCases, IAdapterSettings settings) + { + if (!settings.DumpXmlTestResults) + return null; + var executionDumpXml = new DumpXml(path); + string runningBy = testCases == null + ? "Sources" + : "TestCases"; + executionDumpXml.AddString($"\n{runningBy}\n"); + return executionDumpXml; } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/Dump/XmlNodeExtension.cs b/src/NUnitTestAdapter/Dump/XmlNodeExtension.cs index 6d853706..d976eeef 100644 --- a/src/NUnitTestAdapter/Dump/XmlNodeExtension.cs +++ b/src/NUnitTestAdapter/Dump/XmlNodeExtension.cs @@ -1,22 +1,19 @@ using System.IO; -namespace NUnit.VisualStudio.TestAdapter.Dump +namespace NUnit.VisualStudio.TestAdapter.Dump; + +public static class XmlNodeExtension { - public static class XmlNodeExtension + public static string AsString(this System.Xml.XmlNode node) { - public static string AsString(this System.Xml.XmlNode node) + using var swriter = new StringWriter(); + using (var twriter = new System.Xml.XmlTextWriter(swriter)) { - using (var swriter = new StringWriter()) - { - using (var twriter = new System.Xml.XmlTextWriter(swriter)) - { - twriter.Formatting = System.Xml.Formatting.Indented; - twriter.Indentation = 3; - twriter.QuoteChar = '\''; - node.WriteTo(twriter); - } - return swriter.ToString(); - } + twriter.Formatting = System.Xml.Formatting.Indented; + twriter.Indentation = 3; + twriter.QuoteChar = '\''; + node.WriteTo(twriter); } + return swriter.ToString(); } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/Execution.cs b/src/NUnitTestAdapter/Execution.cs index 74c605cf..a2d2d396 100644 --- a/src/NUnitTestAdapter/Execution.cs +++ b/src/NUnitTestAdapter/Execution.cs @@ -4,201 +4,178 @@ using NUnit.VisualStudio.TestAdapter.Dump; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter -{ - public interface IExecutionContext - { - ITestLogger Log { get; } - INUnitEngineAdapter EngineAdapter { get; } - string TestOutputXmlFolder { get; } - IAdapterSettings Settings { get; } - IDumpXml Dump { get; } +namespace NUnit.VisualStudio.TestAdapter; - IVsTestFilter VsTestFilter { get; } - } +public interface IExecutionContext +{ + ITestLogger Log { get; } + INUnitEngineAdapter EngineAdapter { get; } + string TestOutputXmlFolder { get; } + IAdapterSettings Settings { get; } + IDumpXml Dump { get; } - public static class ExecutionFactory - { - public static Execution Create(IExecutionContext ctx) => ctx.Settings.DesignMode ? new IdeExecution(ctx) : new VsTestExecution(ctx); - } + IVsTestFilter VsTestFilter { get; } +} - public abstract class Execution - { - protected string TestOutputXmlFolder => ctx.TestOutputXmlFolder; - private readonly IExecutionContext ctx; - protected ITestLogger TestLog => ctx.Log; - protected IAdapterSettings Settings => ctx.Settings; +public static class ExecutionFactory +{ + public static Execution Create(IExecutionContext ctx) => ctx.Settings.DesignMode ? new IdeExecution(ctx) : new VsTestExecution(ctx); +} - protected IDumpXml Dump => ctx.Dump; - protected IVsTestFilter VsTestFilter => ctx.VsTestFilter; +public abstract class Execution(IExecutionContext ctx) +{ + protected string TestOutputXmlFolder => ctx.TestOutputXmlFolder; + protected ITestLogger TestLog => ctx.Log; + protected IAdapterSettings Settings => ctx.Settings; - protected INUnitEngineAdapter NUnitEngineAdapter => ctx.EngineAdapter; - protected Execution(IExecutionContext ctx) - { - this.ctx = ctx; - } + protected IDumpXml Dump => ctx.Dump; + protected IVsTestFilter VsTestFilter => ctx.VsTestFilter; + protected INUnitEngineAdapter NUnitEngineAdapter => ctx.EngineAdapter; - public virtual bool Run(TestFilter filter, DiscoveryConverter discovery, NUnit3TestExecutor nUnit3TestExecutor) + public virtual bool Run(TestFilter filter, DiscoveryConverter discovery, NUnit3TestExecutor nUnit3TestExecutor) + { + filter = CheckFilterInCurrentMode(filter, discovery); + nUnit3TestExecutor.Dump?.StartExecution(filter, "(At Execution)"); + var converter = CreateConverter(discovery); + using var listener = new NUnitEventListener(converter, nUnit3TestExecutor); + try { - filter = CheckFilterInCurrentMode(filter, discovery); - nUnit3TestExecutor.Dump?.StartExecution(filter, "(At Execution)"); - var converter = CreateConverter(discovery); - using var listener = new NUnitEventListener(converter, nUnit3TestExecutor); - try - { - var results = NUnitEngineAdapter.Run(listener, filter); - NUnitEngineAdapter.GenerateTestOutput(results, discovery.AssemblyPath, TestOutputXmlFolder); - } - catch (NullReferenceException) - { - // this happens during the run when CancelRun is called. - TestLog.Debug(" Null ref caught"); - } - - return true; + var results = NUnitEngineAdapter.Run(listener, filter); + NUnitEngineAdapter.GenerateTestOutput(results, discovery.AssemblyPath, TestOutputXmlFolder); } + catch (NullReferenceException) + { + // this happens during the run when CancelRun is called. + TestLog.Debug(" Null ref caught"); + } + + return true; + } - public abstract TestFilter CheckFilterInCurrentMode(TestFilter filter, IDiscoveryConverter discovery); + public abstract TestFilter CheckFilterInCurrentMode(TestFilter filter, IDiscoveryConverter discovery); - protected NUnitTestFilterBuilder CreateTestFilterBuilder() - => new(NUnitEngineAdapter.GetService(), Settings); - protected ITestConverterCommon CreateConverter(DiscoveryConverter discovery) => Settings.DiscoveryMethod == DiscoveryMethod.Current ? discovery.TestConverter : discovery.TestConverterForXml; + protected NUnitTestFilterBuilder CreateTestFilterBuilder() + => new(NUnitEngineAdapter.GetService(), Settings); + protected ITestConverterCommon CreateConverter(DiscoveryConverter discovery) => Settings.DiscoveryMethod == DiscoveryMethod.Current ? discovery.TestConverter : discovery.TestConverterForXml; - protected TestFilter CheckFilter(TestFilter testFilter, IDiscoveryConverter discovery) + protected TestFilter CheckFilter(TestFilter testFilter, IDiscoveryConverter discovery) + { + if (discovery.NoOfLoadedTestCasesAboveLimit && !testFilter.IsCategoryFilter()) { - if (discovery.NoOfLoadedTestCasesAboveLimit && !testFilter.IsCategoryFilter()) - { - TestLog.Debug("Setting filter to empty due to number of testcases"); - var filter = TestFilter.Empty; - return filter; - } - if (discovery.NoOfLoadedTestCases == 0) - return testFilter; - if (testFilter.IsCategoryFilter()) + TestLog.Debug("Setting filter to empty due to number of testcases"); + var filter = TestFilter.Empty; + return filter; + } + if (discovery.NoOfLoadedTestCases == 0) + return testFilter; + if (testFilter.IsCategoryFilter()) + { + if (!discovery.IsExplicitRun && discovery.HasExplicitTests && Settings.ExplicitMode == ExplicitModeEnum.Strict) { - if (!discovery.IsExplicitRun && discovery.HasExplicitTests && Settings.ExplicitMode == ExplicitModeEnum.Strict) - { - var filterExt = new TestFilter($"true"); - var combiner = new TestFilterCombiner(testFilter, filterExt); - return combiner.GetFilter(); - } - return testFilter; + var filterExt = new TestFilter($"true"); + var combiner = new TestFilterCombiner(testFilter, filterExt); + return combiner.GetFilter(); } - var filterBuilder = CreateTestFilterBuilder(); - return filterBuilder.FilterByList(discovery.LoadedTestCases); + return testFilter; } + var filterBuilder = CreateTestFilterBuilder(); + return filterBuilder.FilterByList(discovery.LoadedTestCases); } +} - public class TestFilterCombiner +public class TestFilterCombiner(TestFilter a, TestFilter b) +{ + public TestFilter GetFilter() { - private readonly TestFilter _a; - private readonly TestFilter _b; - - public TestFilterCombiner(TestFilter a, TestFilter b) - { - _a = a; - _b = b; - } - - public TestFilter GetFilter() - { - var innerA = StripFilter(_a); - var innerB = StripFilter(_b); - var inner = $"{innerA}{innerB}"; - return new TestFilter(inner); - } + var innerA = StripFilter(a); + var innerB = StripFilter(b); + var inner = $"{innerA}{innerB}"; + return new TestFilter(inner); + } - private string StripFilter(TestFilter x) - { - var s = x.Text.Replace("", ""); - var s2 = s.Replace("", ""); - return s2; - } + private string StripFilter(TestFilter x) + { + var s = x.Text.Replace("", ""); + var s2 = s.Replace("", ""); + return s2; } +} - public class IdeExecution : Execution +public class IdeExecution(IExecutionContext ctx) : Execution(ctx) +{ + public override TestFilter CheckFilterInCurrentMode(TestFilter filter, IDiscoveryConverter discovery) { - public IdeExecution(IExecutionContext ctx) : base(ctx) - { - } - public override TestFilter CheckFilterInCurrentMode(TestFilter filter, IDiscoveryConverter discovery) - { - if (!discovery.IsDiscoveryMethodCurrent) - return filter; - if (filter.IsEmpty()) - return filter; - filter = CheckFilter(filter, discovery); + if (!discovery.IsDiscoveryMethodCurrent) return filter; - } + if (filter.IsEmpty()) + return filter; + filter = CheckFilter(filter, discovery); + return filter; } +} - public class VsTestExecution : Execution +public class VsTestExecution(IExecutionContext ctx) : Execution(ctx) +{ + public override bool Run(TestFilter filter, DiscoveryConverter discovery, NUnit3TestExecutor nUnit3TestExecutor) { - public VsTestExecution(IExecutionContext ctx) : base(ctx) - { - } + filter = CheckVsTestFilter(filter, discovery, VsTestFilter); - public override bool Run(TestFilter filter, DiscoveryConverter discovery, NUnit3TestExecutor nUnit3TestExecutor) + if (filter == NUnitTestFilterBuilder.NoTestsFound) { - filter = CheckVsTestFilter(filter, discovery, VsTestFilter); - - if (filter == NUnitTestFilterBuilder.NoTestsFound) - { - TestLog.Info(" Skipping assembly - no matching test cases found"); - return false; - } - return base.Run(filter, discovery, nUnit3TestExecutor); + TestLog.Info(" Skipping assembly - no matching test cases found"); + return false; } + return base.Run(filter, discovery, nUnit3TestExecutor); + } - public TestFilter CheckVsTestFilter(TestFilter filter, IDiscoveryConverter discovery, IVsTestFilter vsTestFilter) - { - // If we have a VSTest TestFilter, convert it to an nunit filter - if (vsTestFilter == null || vsTestFilter.IsEmpty) - return filter; - TestLog.Debug($"TfsFilter used, length: {vsTestFilter.TfsTestCaseFilterExpression?.TestCaseFilterValue.Length}"); - // NOTE This overwrites filter used in call - var filterBuilder = CreateTestFilterBuilder(); - filter = Settings.DiscoveryMethod == DiscoveryMethod.Current - ? Settings.UseNUnitFilter - ? filterBuilder.ConvertVsTestFilterToNUnitFilter(vsTestFilter) - : filterBuilder.ConvertTfsFilterToNUnitFilter(vsTestFilter, discovery) - : filterBuilder.ConvertTfsFilterToNUnitFilter(vsTestFilter, discovery.LoadedTestCases); - - Dump?.AddString($"\n\nTFSFilter: {vsTestFilter.TfsTestCaseFilterExpression?.TestCaseFilterValue}\n"); - Dump?.DumpVSInputFilter(filter, "(At Execution (TfsFilter)"); - + public TestFilter CheckVsTestFilter(TestFilter filter, IDiscoveryConverter discovery, IVsTestFilter vsTestFilter) + { + // If we have a VSTest TestFilter, convert it to an nunit filter + if (vsTestFilter == null || vsTestFilter.IsEmpty) return filter; + TestLog.Debug($"TfsFilter used, length: {vsTestFilter.TfsTestCaseFilterExpression?.TestCaseFilterValue.Length}"); + // NOTE This overwrites filter used in call + var filterBuilder = CreateTestFilterBuilder(); + filter = Settings.DiscoveryMethod == DiscoveryMethod.Current + ? Settings.UseNUnitFilter + ? filterBuilder.ConvertVsTestFilterToNUnitFilter(vsTestFilter) + : filterBuilder.ConvertTfsFilterToNUnitFilter(vsTestFilter, discovery) + : filterBuilder.ConvertTfsFilterToNUnitFilter(vsTestFilter, discovery.LoadedTestCases); + + Dump?.AddString($"\n\nTFSFilter: {vsTestFilter.TfsTestCaseFilterExpression?.TestCaseFilterValue}\n"); + Dump?.DumpVSInputFilter(filter, "(At Execution (TfsFilter)"); + + return filter; + } + public override TestFilter CheckFilterInCurrentMode(TestFilter filter, IDiscoveryConverter discovery) + { + if (!discovery.IsDiscoveryMethodCurrent) + return filter; + if (filter != TestFilter.Empty) + { + filter = CheckFilter(filter, discovery); } - public override TestFilter CheckFilterInCurrentMode(TestFilter filter, IDiscoveryConverter discovery) + else if (VsTestFilter is { IsEmpty: false } && !Settings.UseNUnitFilter) { - if (!discovery.IsDiscoveryMethodCurrent) - return filter; - if (filter != TestFilter.Empty) - { - filter = CheckFilter(filter, discovery); - } - else if (VsTestFilter is { IsEmpty: false } && !Settings.UseNUnitFilter) - { - var s = VsTestFilter.TfsTestCaseFilterExpression.TestCaseFilterValue; - var scount = s.Split('|', '&').Length; - filter = CheckAssemblySelectLimit(filter, scount); - } - - return filter; + var s = VsTestFilter.TfsTestCaseFilterExpression.TestCaseFilterValue; + var scount = s.Split('|', '&').Length; + filter = CheckAssemblySelectLimit(filter, scount); } - private TestFilter CheckAssemblySelectLimit(TestFilter filter, int scount) + return filter; + } + + private TestFilter CheckAssemblySelectLimit(TestFilter filter, int scount) + { + if (scount <= Settings.AssemblySelectLimit) { - if (scount <= Settings.AssemblySelectLimit) - { - return filter; - } - TestLog.Debug("Setting filter to empty due to TfsFilter size"); - return TestFilter.Empty; + return filter; } + TestLog.Debug("Setting filter to empty due to TfsFilter size"); + return TestFilter.Empty; } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/Internal/Extensions.cs b/src/NUnitTestAdapter/Internal/Extensions.cs index a0f8fb2a..c6582ce7 100644 --- a/src/NUnitTestAdapter/Internal/Extensions.cs +++ b/src/NUnitTestAdapter/Internal/Extensions.cs @@ -1,15 +1,14 @@ using System; -namespace NUnit.VisualStudio.TestAdapter.Internal -{ +namespace NUnit.VisualStudio.TestAdapter.Internal; #if NET462DISABLED - public static class TypeExtensions - { - public static Type GetTypeInfo(this Type type) => type; - } -#endif - public static class StringExtensions - { - public static bool IsNullOrWhiteSpace(this string value) => string.IsNullOrEmpty(value) || value.Trim().Length == 0; - } +public static class TypeExtensions +{ + public static Type GetTypeInfo(this Type type) => type; } +#endif +public static class StringExtensions +{ + public static bool IsNullOrWhiteSpace(this string value) + => string.IsNullOrEmpty(value) || value.Trim().Length == 0; +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/Internal/TimingLogger.cs b/src/NUnitTestAdapter/Internal/TimingLogger.cs index e16c3735..d6a06296 100644 --- a/src/NUnitTestAdapter/Internal/TimingLogger.cs +++ b/src/NUnitTestAdapter/Internal/TimingLogger.cs @@ -1,38 +1,37 @@ using System.Diagnostics; -namespace NUnit.VisualStudio.TestAdapter.Internal +namespace NUnit.VisualStudio.TestAdapter.Internal; + +public class TimingLogger { - public class TimingLogger - { - private readonly IAdapterSettings settings; - private readonly ITestLogger logger; - public Stopwatch Stopwatch { get; } + private readonly IAdapterSettings settings; + private readonly ITestLogger logger; + public Stopwatch Stopwatch { get; } - public TimingLogger(IAdapterSettings settings, ITestLogger logger) - { - this.settings = settings; - this.logger = logger; - if (settings.Verbosity < 5) - return; - Stopwatch = Stopwatch.StartNew(); - } + public TimingLogger(IAdapterSettings settings, ITestLogger logger) + { + this.settings = settings; + this.logger = logger; + if (settings.Verbosity < 5) + return; + Stopwatch = Stopwatch.StartNew(); + } - public TimingLogger ReStart() - { - if (settings.Verbosity < 5) - return this; - Stopwatch.StartNew(); + public TimingLogger ReStart() + { + if (settings.Verbosity < 5) return this; - } + Stopwatch.StartNew(); + return this; + } - public TimingLogger LogTime(string leadText = "") - { - if (settings.Verbosity < 5 || Stopwatch == null) - return this; - var ts = Stopwatch.Elapsed; - string elapsedTime = $"{ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}.{ts.Milliseconds / 10:00}"; - logger.Info($"{leadText} :Elapsed: {elapsedTime}"); + public TimingLogger LogTime(string leadText = "") + { + if (settings.Verbosity < 5 || Stopwatch == null) return this; - } + var ts = Stopwatch.Elapsed; + string elapsedTime = $"{ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}.{ts.Milliseconds / 10:00}"; + logger.Info($"{leadText} :Elapsed: {elapsedTime}"); + return this; } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/Metadata/DirectReflectionMetadataProvider.cs b/src/NUnitTestAdapter/Metadata/DirectReflectionMetadataProvider.cs index 50d1402a..f0f6e530 100644 --- a/src/NUnitTestAdapter/Metadata/DirectReflectionMetadataProvider.cs +++ b/src/NUnitTestAdapter/Metadata/DirectReflectionMetadataProvider.cs @@ -25,84 +25,82 @@ using System.IO; using System.Linq; using System.Reflection; -using NUnit.VisualStudio.TestAdapter.Internal; #if !NET462 && !NETSTANDARD using System.Runtime.Loader; #endif -namespace NUnit.VisualStudio.TestAdapter.Metadata +namespace NUnit.VisualStudio.TestAdapter.Metadata; + +internal sealed class DirectReflectionMetadataProvider : IMetadataProvider { - internal sealed class DirectReflectionMetadataProvider : IMetadataProvider + public TypeInfo? GetDeclaringType(string assemblyPath, string reflectedTypeName, string methodName) { - public TypeInfo? GetDeclaringType(string assemblyPath, string reflectedTypeName, string methodName) - { - var type = TryGetSingleMethod(assemblyPath, reflectedTypeName, methodName)?.DeclaringType; - if (type == null) return null; + var type = TryGetSingleMethod(assemblyPath, reflectedTypeName, methodName)?.DeclaringType; + if (type == null) return null; - if (type.IsConstructedGenericType) - { - type = type.GetGenericTypeDefinition(); - } - - return new TypeInfo(type); + if (type.IsConstructedGenericType) + { + type = type.GetGenericTypeDefinition(); } - public TypeInfo? GetStateMachineType(string assemblyPath, string reflectedTypeName, string methodName) - { - var method = TryGetSingleMethod(assemblyPath, reflectedTypeName, methodName); - if (method == null) return null; + return new TypeInfo(type); + } + + public TypeInfo? GetStateMachineType(string assemblyPath, string reflectedTypeName, string methodName) + { + var method = TryGetSingleMethod(assemblyPath, reflectedTypeName, methodName); + if (method == null) return null; - var candidate = (Type)null; + var candidate = (Type)null; - foreach (var attributeData in CustomAttributeData.GetCustomAttributes(method)) + foreach (var attributeData in CustomAttributeData.GetCustomAttributes(method)) + { + for (var current = attributeData.Constructor.DeclaringType; current != null; current = current.GetTypeInfo().BaseType) { - for (var current = attributeData.Constructor.DeclaringType; current != null; current = current.GetTypeInfo().BaseType) - { - if (current.FullName != "System.Runtime.CompilerServices.StateMachineAttribute") continue; + if (current.FullName != "System.Runtime.CompilerServices.StateMachineAttribute") continue; - var parameters = attributeData.Constructor.GetParameters(); - for (var i = 0; i < parameters.Length; i++) + var parameters = attributeData.Constructor.GetParameters(); + for (var i = 0; i < parameters.Length; i++) + { + if (parameters[i].Name != "stateMachineType") continue; + if (attributeData.ConstructorArguments[i].Value is Type argument) { - if (parameters[i].Name != "stateMachineType") continue; - if (attributeData.ConstructorArguments[i].Value is Type argument) - { - if (candidate != null) - return null; - candidate = argument; - } + if (candidate != null) + return null; + candidate = argument; } } } - - if (candidate == null) - return null; - return new TypeInfo(candidate); } - private static MethodInfo TryGetSingleMethod(string assemblyPath, string reflectedTypeName, string methodName) + if (candidate == null) + return null; + return new TypeInfo(candidate); + } + + private static MethodInfo TryGetSingleMethod(string assemblyPath, string reflectedTypeName, string methodName) + { + try { - try - { #if !NET462 && !NETSTANDARD - var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); + var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); #else - var assembly = Assembly.LoadFrom(assemblyPath); + var assembly = Assembly.LoadFrom(assemblyPath); #endif - var type = assembly.GetType(reflectedTypeName, throwOnError: false); + var type = assembly.GetType(reflectedTypeName, throwOnError: false); - var methods = type?.GetMethods().Where(m => m.Name == methodName).Take(2).ToList(); - return methods?.Count == 1 ? methods[0] : null; - } - catch (FileNotFoundException) - { - return null; - } + var methods = type?.GetMethods().Where(m => m.Name == methodName).Take(2).ToList(); + return methods?.Count == 1 ? methods[0] : null; } - - void IDisposable.Dispose() + catch (FileNotFoundException) { + return null; } } -} + + void IDisposable.Dispose() + { + } +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/Metadata/IMetadataProvider.cs b/src/NUnitTestAdapter/Metadata/IMetadataProvider.cs index 9fcf5bfa..7edae21f 100644 --- a/src/NUnitTestAdapter/Metadata/IMetadataProvider.cs +++ b/src/NUnitTestAdapter/Metadata/IMetadataProvider.cs @@ -23,11 +23,10 @@ using System; -namespace NUnit.VisualStudio.TestAdapter.Metadata +namespace NUnit.VisualStudio.TestAdapter.Metadata; + +public interface IMetadataProvider : IDisposable { - public interface IMetadataProvider : IDisposable - { - TypeInfo? GetDeclaringType(string assemblyPath, string reflectedTypeName, string methodName); - TypeInfo? GetStateMachineType(string assemblyPath, string reflectedTypeName, string methodName); - } -} + TypeInfo? GetDeclaringType(string assemblyPath, string reflectedTypeName, string methodName); + TypeInfo? GetStateMachineType(string assemblyPath, string reflectedTypeName, string methodName); +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/Metadata/TypeInfo.cs b/src/NUnitTestAdapter/Metadata/TypeInfo.cs index 40e31217..f09134b1 100644 --- a/src/NUnitTestAdapter/Metadata/TypeInfo.cs +++ b/src/NUnitTestAdapter/Metadata/TypeInfo.cs @@ -23,28 +23,17 @@ using System; using System.Reflection; -using NUnit.VisualStudio.TestAdapter.Internal; -namespace NUnit.VisualStudio.TestAdapter.Metadata -{ +namespace NUnit.VisualStudio.TestAdapter.Metadata; #if NET462 - [Serializable] +[Serializable] #endif - public struct TypeInfo +public readonly struct TypeInfo(string assemblyPath, string fullName) +{ + public TypeInfo(Type type) : this(type.GetTypeInfo().Assembly.Location, type.FullName) { - public TypeInfo(Type type) - { - AssemblyPath = type.GetTypeInfo().Assembly.Location; - FullName = type.FullName; - } - - public TypeInfo(string assemblyPath, string fullName) - { - AssemblyPath = assemblyPath; - FullName = fullName; - } - - public string AssemblyPath { get; } - public string FullName { get; } } -} + + public string AssemblyPath { get; } = assemblyPath; + public string FullName { get; } = fullName; +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnit3TestDiscoverer.cs b/src/NUnitTestAdapter/NUnit3TestDiscoverer.cs index e41d4094..80b3d863 100644 --- a/src/NUnitTestAdapter/NUnit3TestDiscoverer.cs +++ b/src/NUnitTestAdapter/NUnit3TestDiscoverer.cs @@ -21,7 +21,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** - using System; using System.Collections.Generic; using System.ComponentModel; @@ -29,173 +28,173 @@ using System.IO; using System.Linq; using System.Xml; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; + using NUnit.Engine; using NUnit.VisualStudio.TestAdapter.Dump; using NUnit.VisualStudio.TestAdapter.Internal; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter -{ +namespace NUnit.VisualStudio.TestAdapter; #if !NET462 - [FileExtension(".appx")] +[FileExtension(".appx")] #endif - [FileExtension(".dll")] - [FileExtension(".exe")] - [DefaultExecutorUri(NUnit3TestExecutor.ExecutorUri)] - [Category("managed")] - public sealed class NUnit3TestDiscoverer : NUnitTestAdapter, ITestDiscoverer +[FileExtension(".dll")] +[FileExtension(".exe")] +[DefaultExecutorUri(ExecutorUri)] +[Category("managed")] +public sealed class NUnit3TestDiscoverer : NUnitTestAdapter, ITestDiscoverer +{ + private DumpXml dumpXml; + + #region ITestDiscoverer Members + + public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger messageLogger, ITestCaseDiscoverySink discoverySink) { - private DumpXml dumpXml; + Initialize(discoveryContext, messageLogger); + CheckIfDebug(); + TestLog.Info($"NUnit Adapter {AdapterVersion}: Test discovery starting"); - #region ITestDiscoverer Members + // Ensure any channels registered by other adapters are unregistered + CleanUpRegisteredChannels(); - public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger messageLogger, ITestCaseDiscoverySink discoverySink) + if (Settings.InProcDataCollectorsAvailable && sources.Count() > 1) { - Initialize(discoveryContext, messageLogger); - CheckIfDebug(); - TestLog.Info($"NUnit Adapter {AdapterVersion}: Test discovery starting"); - - // Ensure any channels registered by other adapters are unregistered - CleanUpRegisteredChannels(); + TestLog.Error("Unexpected to discover tests in multiple assemblies when InProcDataCollectors specified in run configuration."); + Unload(); + return; + } - if (Settings.InProcDataCollectorsAvailable && sources.Count() > 1) + foreach (string sourceAssembly in sources) + { + string sourceAssemblyPath = Path.IsPathRooted(sourceAssembly) ? sourceAssembly : Path.Combine(Directory.GetCurrentDirectory(), sourceAssembly); + TestLog.Debug("Processing " + sourceAssembly); + if (Settings.DumpXmlTestDiscovery) { - TestLog.Error("Unexpected to discover tests in multiple assemblies when InProcDataCollectors specified in run configuration."); - Unload(); - return; + dumpXml = new DumpXml(sourceAssemblyPath); } - foreach (string sourceAssembly in sources) + try { - string sourceAssemblyPath = Path.IsPathRooted(sourceAssembly) ? sourceAssembly : Path.Combine(Directory.GetCurrentDirectory(), sourceAssembly); - TestLog.Debug("Processing " + sourceAssembly); - if (Settings.DumpXmlTestDiscovery) - { - dumpXml = new DumpXml(sourceAssemblyPath); - } + var package = CreateTestPackage(sourceAssemblyPath, null); + NUnitEngineAdapter.CreateRunner(package); + var results = NUnitEngineAdapter.Explore(); + dumpXml?.AddString(results.AsString()); - try + if (results.IsRunnable) { - var package = CreateTestPackage(sourceAssemblyPath, null); - NUnitEngineAdapter.CreateRunner(package); - var results = NUnitEngineAdapter.Explore(); - dumpXml?.AddString(results.AsString()); - - if (results.IsRunnable) + int cases; + using (var testConverter = new TestConverterForXml(TestLog, sourceAssemblyPath, Settings)) { - int cases; - using (var testConverter = new TestConverterForXml(TestLog, sourceAssemblyPath, Settings)) - { - var timing = new TimingLogger(Settings, TestLog); - cases = ProcessTestCases(results, discoverySink, testConverter); - timing.LogTime("Discovery/Processing/Converting:"); - } - - TestLog.Debug($"Discovered {cases} test cases"); - // Only save if seed is not specified in runsettings - // This allows workaround in case there is no valid - // location in which the seed may be saved. - if (cases > 0 && !Settings.RandomSeedSpecified) - Settings.SaveRandomSeed(Path.GetDirectoryName(sourceAssemblyPath)); - } - else - { - if (results.HasNoNUnitTests) - { - if (Settings.Verbosity > 0) - TestLog.Info("Assembly contains no NUnit 3.0 tests: " + sourceAssembly); - } - else - { - TestLog.Info("NUnit failed to load " + sourceAssembly); - } + var timing = new TimingLogger(Settings, TestLog); + cases = ProcessTestCases(results, discoverySink, testConverter); + timing.LogTime("Discovery/Processing/Converting:"); } + + TestLog.Debug($"Discovered {cases} test cases"); + // Only save if seed is not specified in runsettings + // This allows workaround in case there is no valid + // location in which the seed may be saved. + if (cases > 0 && !Settings.RandomSeedSpecified) + Settings.SaveRandomSeed(Path.GetDirectoryName(sourceAssemblyPath)); } - catch (NUnitEngineException e) + else { - if (e.InnerException is BadImageFormatException) + if (results.HasNoNUnitTests) { - // we skip the native c++ binaries that we don't support. - TestLog.Warning("Assembly not supported: " + sourceAssembly); + if (Settings.Verbosity > 0) + TestLog.Info("Assembly contains no NUnit 3.0 tests: " + sourceAssembly); } else { - TestLog.Warning("Exception thrown discovering tests in " + sourceAssembly, e); + TestLog.Info("NUnit failed to load " + sourceAssembly); } } - catch (BadImageFormatException) + } + catch (NUnitEngineException e) + { + if (e.InnerException is BadImageFormatException) { // we skip the native c++ binaries that we don't support. TestLog.Warning("Assembly not supported: " + sourceAssembly); } - catch (FileNotFoundException ex) - { - // Either the NUnit framework was not referenced by the test assembly - // or some other error occurred. Not a problem if not an NUnit assembly. - TestLog.Warning("Dependent Assembly " + ex.FileName + " of " + sourceAssembly + " not found. Can be ignored if not an NUnit project."); - } - catch (FileLoadException ex) + else { - // Attempts to load an invalid assembly, or an assembly with missing dependencies - TestLog.Warning("Assembly " + ex.FileName + " loaded through " + sourceAssembly + " failed. Assembly is ignored. Correct deployment of dependencies if this is an error."); + TestLog.Warning("Exception thrown discovering tests in " + sourceAssembly, e); } - catch (TypeLoadException ex) - { - if (ex.TypeName == "NUnit.Framework.Api.FrameworkController") - TestLog.Warning(" Skipping NUnit 2.x test assembly"); - else - TestLog.Warning("Exception thrown discovering tests in " + sourceAssembly, ex); - } - catch (Exception ex) - { + } + catch (BadImageFormatException) + { + // we skip the native c++ binaries that we don't support. + TestLog.Warning("Assembly not supported: " + sourceAssembly); + } + catch (FileNotFoundException ex) + { + // Either the NUnit framework was not referenced by the test assembly + // or some other error occurred. Not a problem if not an NUnit assembly. + TestLog.Warning("Dependent Assembly " + ex.FileName + " of " + sourceAssembly + " not found. Can be ignored if not an NUnit project."); + } + catch (FileLoadException ex) + { + // Attempts to load an invalid assembly, or an assembly with missing dependencies + TestLog.Warning("Assembly " + ex.FileName + " loaded through " + sourceAssembly + " failed. Assembly is ignored. Correct deployment of dependencies if this is an error."); + } + catch (TypeLoadException ex) + { + if (ex.TypeName == "NUnit.Framework.Api.FrameworkController") + TestLog.Warning(" Skipping NUnit 2.x test assembly"); + else TestLog.Warning("Exception thrown discovering tests in " + sourceAssembly, ex); - } - finally - { - dumpXml?.DumpForDiscovery(); - NUnitEngineAdapter?.CloseRunner(); - } } + catch (Exception ex) + { + TestLog.Warning("Exception thrown discovering tests in " + sourceAssembly, ex); + } + finally + { + dumpXml?.DumpForDiscovery(); + NUnitEngineAdapter?.CloseRunner(); + } + } - TestLog.Info($"NUnit Adapter {AdapterVersion}: Test discovery complete"); + TestLog.Info($"NUnit Adapter {AdapterVersion}: Test discovery complete"); - Unload(); - } + Unload(); + } - #endregion + #endregion - #region Helper Methods + #region Helper Methods - private int ProcessTestCases(NUnitResults results, ITestCaseDiscoverySink discoverySink, TestConverterForXml testConverterForXml) + private int ProcessTestCases(NUnitResults results, ITestCaseDiscoverySink discoverySink, TestConverterForXml testConverterForXml) + { + int cases = 0; + foreach (XmlNode testNode in results.TestCases()) { - int cases = 0; - foreach (XmlNode testNode in results.TestCases()) + try { - try - { - var testCase = testConverterForXml.ConvertTestCase(new NUnitEventTestCase(testNode)); - discoverySink.SendTestCase(testCase); - cases += 1; - } - catch (Exception ex) - { - TestLog.Warning("Exception converting " + testNode.GetAttribute("fullname"), ex); - } + var testCase = testConverterForXml.ConvertTestCase(new NUnitEventTestCase(testNode)); + discoverySink.SendTestCase(testCase); + cases += 1; + } + catch (Exception ex) + { + TestLog.Warning("Exception converting " + testNode.GetAttribute("fullname"), ex); } - - return cases; } - private void CheckIfDebug() - { - if (!Settings.DebugDiscovery) - return; - if (!Debugger.IsAttached) - Debugger.Launch(); - } - #endregion + return cases; + } + + private void CheckIfDebug() + { + if (!Settings.DebugDiscovery) + return; + if (!Debugger.IsAttached) + Debugger.Launch(); } -} + #endregion +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnit3TestExecutor.cs b/src/NUnitTestAdapter/NUnit3TestExecutor.cs index fb4c3761..59756168 100644 --- a/src/NUnitTestAdapter/NUnit3TestExecutor.cs +++ b/src/NUnitTestAdapter/NUnit3TestExecutor.cs @@ -37,370 +37,369 @@ using NUnit.VisualStudio.TestAdapter.Internal; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public interface INUnit3TestExecutor { - public interface INUnit3TestExecutor - { - void StopRun(); - IDumpXml Dump { get; } - IAdapterSettings Settings { get; } - IFrameworkHandle FrameworkHandle { get; } - } + void StopRun(); + IDumpXml Dump { get; } + IAdapterSettings Settings { get; } + IFrameworkHandle FrameworkHandle { get; } +} - public enum RunType - { - Unknown, - CommandLineLegacy, - CommandLineCurrentVSTest, - CommandLineCurrentNUnit, - Ide - } +public enum RunType +{ + Unknown, + CommandLineLegacy, + CommandLineCurrentVSTest, + CommandLineCurrentNUnit, + Ide +} - [ExtensionUri(ExecutorUri)] - public sealed class NUnit3TestExecutor : NUnitTestAdapter, ITestExecutor, IDisposable, INUnit3TestExecutor, - IExecutionContext - { - #region Properties +[ExtensionUri(ExecutorUri)] +public sealed class NUnit3TestExecutor : NUnitTestAdapter, ITestExecutor, IDisposable, INUnit3TestExecutor, + IExecutionContext +{ + #region Properties - private RunType RunType { get; set; } + private RunType RunType { get; set; } - // Properties set when either of the RunTests methods is called - public IRunContext RunContext { get; private set; } - public IFrameworkHandle FrameworkHandle { get; private set; } + // Properties set when either of the RunTests methods is called + public IRunContext RunContext { get; private set; } + public IFrameworkHandle FrameworkHandle { get; private set; } - public IVsTestFilter VsTestFilter { get; private set; } + public IVsTestFilter VsTestFilter { get; private set; } - public ITestLogger Log => TestLog; + public ITestLogger Log => TestLog; - public INUnitEngineAdapter EngineAdapter => NUnitEngineAdapter; + public INUnitEngineAdapter EngineAdapter => NUnitEngineAdapter; - public string TestOutputXmlFolder { get; set; } = ""; + public string TestOutputXmlFolder { get; set; } = ""; - // NOTE: an earlier version of this code had a FilterBuilder - // property. This seemed to make sense, because we instantiate - // it in two different places. However, the existence of an - // NUnitTestFilterBuilder, containing a reference to an engine - // service caused our second-level tests of the test executor - // to throw an exception. So if you consider doing this, beware! + // NOTE: an earlier version of this code had a FilterBuilder + // property. This seemed to make sense, because we instantiate + // it in two different places. However, the existence of an + // NUnitTestFilterBuilder, containing a reference to an engine + // service caused our second-level tests of the test executor + // to throw an exception. So if you consider doing this, beware! - #endregion + #endregion - #region ITestExecutor Implementation + #region ITestExecutor Implementation - /// - /// Called by dotnet test, and TFS Build - /// to run either all or selected tests. In the latter case, a filter is provided - /// as part of the run context. - /// - /// Sources to be run. - /// Context to use when executing the tests. - /// Test log to send results and messages through. - public void RunTests(IEnumerable sources, IRunContext runContext, IFrameworkHandle frameworkHandle) - { - Initialize(runContext, frameworkHandle); - CheckIfDebug(); + /// + /// Called by dotnet test, and TFS Build + /// to run either all or selected tests. In the latter case, a filter is provided + /// as part of the run context. + /// + /// Sources to be run. + /// Context to use when executing the tests. + /// Test log to send results and messages through. + public void RunTests(IEnumerable sources, IRunContext runContext, IFrameworkHandle frameworkHandle) + { + Initialize(runContext, frameworkHandle); + CheckIfDebug(); #if REVERSEENGINEERING - var st = new StackTrace(); - var frames = st.GetFrames(); - var filenames = frames?.Select(x => x.GetMethod()?.DeclaringType?.Assembly.CodeBase).Distinct().ToList(); + var st = new StackTrace(); + var frames = st.GetFrames(); + var filenames = frames?.Select(x => x.GetMethod()?.DeclaringType?.Assembly.CodeBase).Distinct().ToList(); #endif - InitializeForExecution(runContext, frameworkHandle); - TestLog.Debug($"RunTests by IEnumerable,({sources.Count()} entries), called from {WhoIsCallingUsEntry}"); + InitializeForExecution(runContext, frameworkHandle); + TestLog.Debug($"RunTests by IEnumerable,({sources.Count()} entries), called from {WhoIsCallingUsEntry}"); - if (Settings.InProcDataCollectorsAvailable && sources.Count() > 1) - { - TestLog.Error( - "Failed to run tests for multiple assemblies when InProcDataCollectors specified in run configuration."); - Unload(); - return; - } + if (Settings.InProcDataCollectorsAvailable && sources.Count() > 1) + { + TestLog.Error( + "Failed to run tests for multiple assemblies when InProcDataCollectors specified in run configuration."); + Unload(); + return; + } - SetRunTypeByStrings(); - var builder = CreateTestFilterBuilder(); - TestFilter filter = null; - if (RunType == RunType.CommandLineCurrentNUnit) - { - var vsTestFilter = VsTestFilterFactory.CreateVsTestFilter(Settings, runContext); - filter = builder.ConvertVsTestFilterToNUnitFilter(vsTestFilter); - } + SetRunTypeByStrings(); + var builder = CreateTestFilterBuilder(); + TestFilter filter = null; + if (RunType == RunType.CommandLineCurrentNUnit) + { + var vsTestFilter = VsTestFilterFactory.CreateVsTestFilter(Settings, runContext); + filter = builder.ConvertVsTestFilterToNUnitFilter(vsTestFilter); + } - filter ??= builder.FilterByWhere(Settings.Where); + filter ??= builder.FilterByWhere(Settings.Where); - RunAssemblies(sources, filter); + RunAssemblies(sources, filter); - TestLog.Info($"NUnit Adapter {AdapterVersion}: Test execution complete"); - Unload(); - } + TestLog.Info($"NUnit Adapter {AdapterVersion}: Test execution complete"); + Unload(); + } - private void RunAssemblies(IEnumerable sources, TestFilter filter) + private void RunAssemblies(IEnumerable sources, TestFilter filter) + { + foreach (string assemblyName in sources) { - foreach (string assemblyName in sources) + try { - try - { - string assemblyPath = Path.IsPathRooted(assemblyName) - ? assemblyName - : Path.Combine(Directory.GetCurrentDirectory(), assemblyName); - RunAssembly(assemblyPath, null, filter); - } - catch (Exception ex) - { - if (ex is TargetInvocationException) { ex = ex.InnerException; } + string assemblyPath = Path.IsPathRooted(assemblyName) + ? assemblyName + : Path.Combine(Directory.GetCurrentDirectory(), assemblyName); + RunAssembly(assemblyPath, null, filter); + } + catch (Exception ex) + { + if (ex is TargetInvocationException) { ex = ex.InnerException; } - TestLog.Warning("Exception thrown executing tests", ex); - } + TestLog.Warning("Exception thrown executing tests", ex); } } + } + + private void SetRunTypeByStrings() + { + RunType = !Settings.DesignMode + ? Settings.DiscoveryMethod == DiscoveryMethod.Legacy + ? RunType.CommandLineLegacy + : Settings.UseNUnitFilter + ? RunType.CommandLineCurrentNUnit + : RunType.CommandLineCurrentVSTest + : RunType.Ide; + TestLog.Debug($"Runtype: {RunType}"); + } - private void SetRunTypeByStrings() + /// + /// Called by the VisualStudio IDE when all or selected tests are to be run. Never called from TFS Build, except (at least 2022, probably also 2019) when 'vstest.console' uses /test: then this is being used. + /// + /// The tests to be run. + /// The RunContext. + /// The FrameworkHandle. + public void RunTests(IEnumerable tests, IRunContext runContext, IFrameworkHandle frameworkHandle) + { + Initialize(runContext, frameworkHandle); + CheckIfDebug(); + InitializeForExecution(runContext, frameworkHandle); + RunType = RunType.Ide; + TestLog.Debug($"RunTests by IEnumerable. RunType = Ide, called from {WhoIsCallingUsEntry}"); + var timing = new TimingLogger(Settings, TestLog); + Debug.Assert(NUnitEngineAdapter != null, "NUnitEngineAdapter is null"); + Debug.Assert(NUnitEngineAdapter.EngineEnabled, "NUnitEngineAdapter TestEngine is null"); + var assemblyGroups = tests.GroupBy(tc => tc.Source).ToList(); + if (assemblyGroups.Count > 1) + TestLog.Debug($"Multiple ({assemblyGroups.Count}) assemblies in one test"); + if (IsInProcDataCollectorsSpecifiedWithMultipleAssemblies(assemblyGroups)) { - RunType = !Settings.DesignMode - ? Settings.DiscoveryMethod == DiscoveryMethod.Legacy - ? RunType.CommandLineLegacy - : Settings.UseNUnitFilter - ? RunType.CommandLineCurrentNUnit - : RunType.CommandLineCurrentVSTest - : RunType.Ide; - TestLog.Debug($"Runtype: {RunType}"); + TestLog.Error( + "Failed to run tests for multiple assemblies when InProcDataCollectors specified in run configuration."); + Unload(); + return; } - /// - /// Called by the VisualStudio IDE when all or selected tests are to be run. Never called from TFS Build, except (at least 2022, probably also 2019) when 'vstest.console' uses /test: then this is being used. - /// - /// The tests to be run. - /// The RunContext. - /// The FrameworkHandle. - public void RunTests(IEnumerable tests, IRunContext runContext, IFrameworkHandle frameworkHandle) + foreach (var assemblyGroup in assemblyGroups) { - Initialize(runContext, frameworkHandle); - CheckIfDebug(); - InitializeForExecution(runContext, frameworkHandle); - RunType = RunType.Ide; - TestLog.Debug($"RunTests by IEnumerable. RunType = Ide, called from {WhoIsCallingUsEntry}"); - var timing = new TimingLogger(Settings, TestLog); - Debug.Assert(NUnitEngineAdapter != null, "NUnitEngineAdapter is null"); - Debug.Assert(NUnitEngineAdapter.EngineEnabled, "NUnitEngineAdapter TestEngine is null"); - var assemblyGroups = tests.GroupBy(tc => tc.Source).ToList(); - if (assemblyGroups.Count > 1) - TestLog.Debug($"Multiple ({assemblyGroups.Count}) assemblies in one test"); - if (IsInProcDataCollectorsSpecifiedWithMultipleAssemblies(assemblyGroups)) - { - TestLog.Error( - "Failed to run tests for multiple assemblies when InProcDataCollectors specified in run configuration."); - Unload(); - return; - } - - foreach (var assemblyGroup in assemblyGroups) + var assemblytiming = new TimingLogger(Settings, TestLog); + try { - var assemblytiming = new TimingLogger(Settings, TestLog); - try - { - string assemblyName = assemblyGroup.Key; - string assemblyPath = Path.IsPathRooted(assemblyName) - ? assemblyName - : Path.Combine(Directory.GetCurrentDirectory(), assemblyName); + string assemblyName = assemblyGroup.Key; + string assemblyPath = Path.IsPathRooted(assemblyName) + ? assemblyName + : Path.Combine(Directory.GetCurrentDirectory(), assemblyName); - var filterBuilder = CreateTestFilterBuilder(); - var filter = filterBuilder.FilterByList(assemblyGroup); - - RunAssembly(assemblyPath, assemblyGroup, filter); - } - catch (Exception ex) - { - if (ex is TargetInvocationException) { ex = ex.InnerException; } + var filterBuilder = CreateTestFilterBuilder(); + var filter = filterBuilder.FilterByList(assemblyGroup); - TestLog.Warning("Exception thrown executing tests", ex); - } + RunAssembly(assemblyPath, assemblyGroup, filter); + } + catch (Exception ex) + { + if (ex is TargetInvocationException) { ex = ex.InnerException; } - assemblytiming.LogTime($"Executing {assemblyGroup.Key} time "); + TestLog.Warning("Exception thrown executing tests", ex); } - timing.LogTime("Total execution time"); - TestLog.Info($"NUnit Adapter {AdapterVersion}: Test execution complete"); - Unload(); + assemblytiming.LogTime($"Executing {assemblyGroup.Key} time "); } - private bool IsInProcDataCollectorsSpecifiedWithMultipleAssemblies( - IEnumerable> assemblyGroups) - => Settings.InProcDataCollectorsAvailable && assemblyGroups.Count() > 1; - - void ITestExecutor.Cancel() - { - StopRun(); - } + timing.LogTime("Total execution time"); + TestLog.Info($"NUnit Adapter {AdapterVersion}: Test execution complete"); + Unload(); + } -#endregion + private bool IsInProcDataCollectorsSpecifiedWithMultipleAssemblies( + IEnumerable> assemblyGroups) + => Settings.InProcDataCollectorsAvailable && assemblyGroups.Count() > 1; -#region IDisposable Implementation + void ITestExecutor.Cancel() + { + StopRun(); + } - public void Dispose() - { - // TODO: Nothing here at the moment. Check what needs disposing, if anything. Otherwise, remove. - } + #endregion -#endregion + #region IDisposable Implementation -#region Helper Methods + public void Dispose() + { + // TODO: Nothing here at the moment. Check what needs disposing, if anything. Otherwise, remove. + } - public void InitializeForExecution(IRunContext runContext, IFrameworkHandle frameworkHandle) - { - TestLog.Info($"NUnit Adapter {AdapterVersion}: Test execution started"); + #endregion - RunContext = runContext; - FrameworkHandle = frameworkHandle; - VsTestFilter = VsTestFilterFactory.CreateVsTestFilter(Settings, runContext); + #region Helper Methods - CleanUpRegisteredChannels(); + public void InitializeForExecution(IRunContext runContext, IFrameworkHandle frameworkHandle) + { + TestLog.Info($"NUnit Adapter {AdapterVersion}: Test execution started"); - TestLog.Debug("KeepAlive: " + runContext.KeepAlive); - TestLog.Debug("UseVsKeepEngineRunning: " + Settings.UseVsKeepEngineRunning); + RunContext = runContext; + FrameworkHandle = frameworkHandle; + VsTestFilter = VsTestFilterFactory.CreateVsTestFilter(Settings, runContext); - bool enableShutdown = true; - if (Settings.UseVsKeepEngineRunning) - { - enableShutdown = !runContext.KeepAlive; - } + CleanUpRegisteredChannels(); - if (VsTestFilter.IsEmpty) - { - if (!(enableShutdown && - !runContext - .KeepAlive)) // Otherwise causes exception when run as commandline, illegal to enableshutdown when Keepalive is false, might be only VS2012 - frameworkHandle.EnableShutdownAfterTestRun = enableShutdown; - } + TestLog.Debug("KeepAlive: " + runContext.KeepAlive); + TestLog.Debug("UseVsKeepEngineRunning: " + Settings.UseVsKeepEngineRunning); - TestLog.Debug("EnableShutdown: " + enableShutdown); + bool enableShutdown = true; + if (Settings.UseVsKeepEngineRunning) + { + enableShutdown = !runContext.KeepAlive; } - private void RunAssembly(string assemblyPath, IGrouping testCases, TestFilter filter) + if (VsTestFilter.IsEmpty) { - LogActionAndSelection(assemblyPath, filter); - RestoreRandomSeed(assemblyPath); - Dump = DumpXml.CreateDump(assemblyPath, testCases, Settings); + if (!(enableShutdown && + !runContext + .KeepAlive)) // Otherwise causes exception when run as commandline, illegal to enableshutdown when Keepalive is false, might be only VS2012 + frameworkHandle.EnableShutdownAfterTestRun = enableShutdown; + } - try + TestLog.Debug("EnableShutdown: " + enableShutdown); + } + + private void RunAssembly(string assemblyPath, IGrouping testCases, TestFilter filter) + { + LogActionAndSelection(assemblyPath, filter); + RestoreRandomSeed(assemblyPath); + Dump = DumpXml.CreateDump(assemblyPath, testCases, Settings); + + try + { + var package = CreateTestPackage(assemblyPath, testCases); + NUnitEngineAdapter.CreateRunner(package); + CreateTestOutputFolder(); + Dump?.StartDiscoveryInExecution(testCases, filter, package); + TestLog.DebugRunfrom(); + // var discoveryResults = RunType == RunType.CommandLineCurrentNUnit ? null : NUnitEngineAdapter.Explore(filter); + var discoveryResults = NUnitEngineAdapter.Explore(filter); + Dump?.AddString(discoveryResults?.AsString() ?? " No discovery"); + + if (discoveryResults?.IsRunnable ?? true) { - var package = CreateTestPackage(assemblyPath, testCases); - NUnitEngineAdapter.CreateRunner(package); - CreateTestOutputFolder(); - Dump?.StartDiscoveryInExecution(testCases, filter, package); - TestLog.DebugRunfrom(); - // var discoveryResults = RunType == RunType.CommandLineCurrentNUnit ? null : NUnitEngineAdapter.Explore(filter); - var discoveryResults = NUnitEngineAdapter.Explore(filter); - Dump?.AddString(discoveryResults?.AsString() ?? " No discovery"); - - if (discoveryResults?.IsRunnable ?? true) + var discovery = new DiscoveryConverter(TestLog, Settings); + discovery.Convert(discoveryResults, assemblyPath); + if (!Settings.SkipExecutionWhenNoTests || discovery.AllTestCases.Any()) { - var discovery = new DiscoveryConverter(TestLog, Settings); - discovery.Convert(discoveryResults, assemblyPath); - if (!Settings.SkipExecutionWhenNoTests || discovery.AllTestCases.Any()) - { - var ea = ExecutionFactory.Create(this); - ea.Run(filter, discovery, this); - } - else - { - TestLog.InfoNoTests(assemblyPath); - } + var ea = ExecutionFactory.Create(this); + ea.Run(filter, discovery, this); } else { - TestLog.InfoNoTests(discoveryResults.HasNoNUnitTests, assemblyPath); + TestLog.InfoNoTests(assemblyPath); } } - catch (Exception ex) when (ex is BadImageFormatException || ex.InnerException is BadImageFormatException) + else { - // we skip the native c++ binaries that we don't support. - TestLog.Warning(" Assembly not supported: " + assemblyPath); + TestLog.InfoNoTests(discoveryResults.HasNoNUnitTests, assemblyPath); } - catch (FileNotFoundException ex) + } + catch (Exception ex) when (ex is BadImageFormatException || ex.InnerException is BadImageFormatException) + { + // we skip the native c++ binaries that we don't support. + TestLog.Warning(" Assembly not supported: " + assemblyPath); + } + catch (FileNotFoundException ex) + { + // Probably from the GetExportedTypes in NUnit.core, attempting to find an assembly, not a problem if it is not NUnit here + TestLog.Warning(" Dependent Assembly " + ex.FileName + " of " + assemblyPath + + " not found. Can be ignored if not an NUnit project."); + } + catch (Exception ex) + { + if (ex is TargetInvocationException) + ex = ex.InnerException; + TestLog.Warning(" Exception thrown executing tests in " + assemblyPath, ex); + } + finally + { + Dump?.DumpForExecution(); + try { - // Probably from the GetExportedTypes in NUnit.core, attempting to find an assembly, not a problem if it is not NUnit here - TestLog.Warning(" Dependent Assembly " + ex.FileName + " of " + assemblyPath + - " not found. Can be ignored if not an NUnit project."); + NUnitEngineAdapter?.CloseRunner(); } catch (Exception ex) { - if (ex is TargetInvocationException) - ex = ex.InnerException; - TestLog.Warning(" Exception thrown executing tests in " + assemblyPath, ex); - } - finally - { - Dump?.DumpForExecution(); - try - { - NUnitEngineAdapter?.CloseRunner(); - } - catch (Exception ex) - { - // can happen if CLR throws CannotUnloadAppDomainException, for example - // due to a long-lasting operation in a protected region (catch/finally clause). - if (ex is TargetInvocationException) { ex = ex.InnerException; } + // can happen if CLR throws CannotUnloadAppDomainException, for example + // due to a long-lasting operation in a protected region (catch/finally clause). + if (ex is TargetInvocationException) { ex = ex.InnerException; } - TestLog.Warning($" Exception thrown unloading tests from {assemblyPath}", ex); - } + TestLog.Warning($" Exception thrown unloading tests from {assemblyPath}", ex); } } + } - private void LogActionAndSelection(string assemblyPath, TestFilter filter) - { - string actionText = Debugger.IsAttached ? "Debugging " : "Running "; - string selectionText = filter == null || filter == TestFilter.Empty ? "all" : "selected"; - TestLog.Info(actionText + selectionText + " tests in " + assemblyPath); - } + private void LogActionAndSelection(string assemblyPath, TestFilter filter) + { + string actionText = Debugger.IsAttached ? "Debugging " : "Running "; + string selectionText = filter == null || filter == TestFilter.Empty ? "all" : "selected"; + TestLog.Info(actionText + selectionText + " tests in " + assemblyPath); + } - private void RestoreRandomSeed(string assemblyPath) - { - // No need to restore if the seed was in runsettings file - if (!Settings.RandomSeedSpecified) - Settings.RestoreRandomSeed(Path.GetDirectoryName(assemblyPath)); - } + private void RestoreRandomSeed(string assemblyPath) + { + // No need to restore if the seed was in runsettings file + if (!Settings.RandomSeedSpecified) + Settings.RestoreRandomSeed(Path.GetDirectoryName(assemblyPath)); + } - private NUnitTestFilterBuilder CreateTestFilterBuilder() => new(NUnitEngineAdapter.GetService(), Settings); + private NUnitTestFilterBuilder CreateTestFilterBuilder() => new(NUnitEngineAdapter.GetService(), Settings); - /// - /// Must be called after WorkDir have been set. - /// - private void CreateTestOutputFolder() + /// + /// Must be called after WorkDir have been set. + /// + private void CreateTestOutputFolder() + { + if (!Settings.UseTestOutputXml) { - if (!Settings.UseTestOutputXml) - { - return; - } - string path = Settings.SetTestOutputFolder(WorkDir); - try - { - Directory.CreateDirectory(path); - TestOutputXmlFolder = path; - TestLog.Info($" Test Output folder checked/created : {path} "); - } - catch (UnauthorizedAccessException) - { - TestLog.Error($" Failed creating test output folder at {path}"); - throw; - } + return; } - -#endregion - - public void StopRun() + string path = Settings.SetTestOutputFolder(WorkDir); + try { - NUnitEngineAdapter?.StopRun(); + Directory.CreateDirectory(path); + TestOutputXmlFolder = path; + TestLog.Info($" Test Output folder checked/created : {path} "); } - - public IDumpXml Dump { get; private set; } - - private void CheckIfDebug() + catch (UnauthorizedAccessException) { - if (!Settings.DebugExecution) - return; - if (!Debugger.IsAttached) - Debugger.Launch(); + TestLog.Error($" Failed creating test output folder at {path}"); + throw; } } + + #endregion + + public void StopRun() + { + NUnitEngineAdapter?.StopRun(); + } + + public IDumpXml Dump { get; private set; } + + private void CheckIfDebug() + { + if (!Settings.DebugExecution) + return; + if (!Debugger.IsAttached) + Debugger.Launch(); + } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/DiscoveryConverter.cs b/src/NUnitTestAdapter/NUnitEngine/DiscoveryConverter.cs index a031b2f1..65ae6940 100644 --- a/src/NUnitTestAdapter/NUnitEngine/DiscoveryConverter.cs +++ b/src/NUnitTestAdapter/NUnitEngine/DiscoveryConverter.cs @@ -26,448 +26,434 @@ using System.Linq; using System.Xml; using System.Xml.Linq; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using NUnit.VisualStudio.TestAdapter.Internal; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public interface IDiscoveryConverter { - public interface IDiscoveryConverter - { - IEnumerable AllTestCases { get; } - bool IsExplicitRun { get; } - IList LoadedTestCases { get; } - int NoOfLoadedTestCases { get; } - - /// - /// Checks if we're running the latest Current DiscoveryMethod. - /// - bool IsDiscoveryMethodCurrent { get; } - - bool NoOfLoadedTestCasesAboveLimit { get; } - int NoOfExplicitTestCases { get; } - bool HasExplicitTests { get; } - IEnumerable GetExplicitTestCases(IEnumerable filteredTestCases); - } + IEnumerable AllTestCases { get; } + bool IsExplicitRun { get; } + IList LoadedTestCases { get; } + int NoOfLoadedTestCases { get; } + + /// + /// Checks if we're running the latest Current DiscoveryMethod. + /// + bool IsDiscoveryMethodCurrent { get; } + + bool NoOfLoadedTestCasesAboveLimit { get; } + int NoOfExplicitTestCases { get; } + bool HasExplicitTests { get; } + IEnumerable GetExplicitTestCases(IEnumerable filteredTestCases); +} - public class DiscoveryConverter : IDiscoveryConverter - { - private const string ParameterizedFixture = nameof(ParameterizedFixture); - private const string TestFixture = nameof(TestFixture); - private const string GenericFixture = nameof(GenericFixture); - private const string SetUpFixture = nameof(SetUpFixture); - private const string TestSuite = nameof(TestSuite); +public class DiscoveryConverter(ITestLogger logger, IAdapterSettings settings) : IDiscoveryConverter +{ + private const string ParameterizedFixture = nameof(ParameterizedFixture); + private const string TestFixture = nameof(TestFixture); + private const string GenericFixture = nameof(GenericFixture); + private const string SetUpFixture = nameof(SetUpFixture); + private const string TestSuite = nameof(TestSuite); - internal static class NUnitXmlAttributeNames - { - public const string Id = "id"; - public const string Type = "type"; - public const string Name = "name"; - public const string Fullname = "fullname"; - public const string Runstate = "runstate"; - public const string Testcasecount = "testcasecount"; - public const string Classname = "classname"; - public const string Methodname = "methodname"; - public const string Seed = "seed"; - } + internal static class NUnitXmlAttributeNames + { + public const string Id = "id"; + public const string Type = "type"; + public const string Name = "name"; + public const string Fullname = "fullname"; + public const string Runstate = "runstate"; + public const string Testcasecount = "testcasecount"; + public const string Classname = "classname"; + public const string Methodname = "methodname"; + public const string Seed = "seed"; + } - private ITestConverterXml converterForXml; - private ITestConverter converter; + private ITestConverterXml converterForXml; + private ITestConverter converter; - public ITestConverterCommon TestConverterForXml => converterForXml; + public ITestConverterCommon TestConverterForXml => converterForXml; - public ITestConverterCommon TestConverter => converter; + public ITestConverterCommon TestConverter => converter; - public NUnitDiscoveryTestRun TestRun { get; private set; } + public NUnitDiscoveryTestRun TestRun { get; private set; } - /// - /// Checks if we're running the latest Current DiscoveryMethod. - /// - public bool IsDiscoveryMethodCurrent => Settings.DiscoveryMethod == DiscoveryMethod.Current; + /// + /// Checks if we're running the latest Current DiscoveryMethod. + /// + public bool IsDiscoveryMethodCurrent => Settings.DiscoveryMethod == DiscoveryMethod.Current; - public NUnitDiscoveryTestAssembly CurrentTestAssembly => TestRun.TestAssembly; + public NUnitDiscoveryTestAssembly CurrentTestAssembly => TestRun.TestAssembly; - public NUnitDiscoveryTestSuite TopLevelTestSuite => CurrentTestAssembly.TestSuites.FirstOrDefault(); + public NUnitDiscoveryTestSuite TopLevelTestSuite => CurrentTestAssembly.TestSuites.FirstOrDefault(); - public IEnumerable AllTestCases => CurrentTestAssembly.AllTestCases; + public IEnumerable AllTestCases => CurrentTestAssembly.AllTestCases; - public bool IsExplicitRun => CurrentTestAssembly?.IsExplicit ?? false; + public bool IsExplicitRun => CurrentTestAssembly?.IsExplicit ?? false; - public int NoOfExplicitTestCases => CurrentTestAssembly.NoOfExplicitTestCases; + public int NoOfExplicitTestCases => CurrentTestAssembly.NoOfExplicitTestCases; - public bool HasExplicitTests => NoOfExplicitTestCases > 0; + public bool HasExplicitTests => NoOfExplicitTestCases > 0; - private readonly List loadedTestCases = new (); - public IList LoadedTestCases => loadedTestCases; + private readonly List loadedTestCases = new(); + public IList LoadedTestCases => loadedTestCases; - public int NoOfLoadedTestCases => loadedTestCases.Count; + public int NoOfLoadedTestCases => loadedTestCases.Count; - public string AssemblyPath { get; private set; } + public string AssemblyPath { get; private set; } - private IAdapterSettings Settings { get; } - private ITestLogger TestLog { get; } + private IAdapterSettings Settings { get; } = settings; + private ITestLogger TestLog { get; } = logger; - public bool NoOfLoadedTestCasesAboveLimit => NoOfLoadedTestCases > Settings.AssemblySelectLimit; - public IEnumerable GetExplicitTestCases(IEnumerable filteredTestCases) + public bool NoOfLoadedTestCasesAboveLimit => NoOfLoadedTestCases > Settings.AssemblySelectLimit; + public IEnumerable GetExplicitTestCases(IEnumerable filteredTestCases) + { + var explicitCases = new List(); + foreach (var tc in filteredTestCases) { - var explicitCases = new List(); - foreach (var tc in filteredTestCases) + var correspondingNUnitTestCase = AllTestCases.FirstOrDefault(o => o.FullName == tc.FullyQualifiedName); + if (correspondingNUnitTestCase == null) { - var correspondingNUnitTestCase = AllTestCases.FirstOrDefault(o => o.FullName == tc.FullyQualifiedName); - if (correspondingNUnitTestCase == null) - { - TestLog.Warning( - $"CheckExplicit: Can't locate corresponding NUnit testcase {tc.FullyQualifiedName}"); - continue; - } - - if (correspondingNUnitTestCase.IsExplicitReverse) - explicitCases.Add(tc); + TestLog.Warning( + $"CheckExplicit: Can't locate corresponding NUnit testcase {tc.FullyQualifiedName}"); + continue; } - return explicitCases; + + if (correspondingNUnitTestCase.IsExplicitReverse) + explicitCases.Add(tc); } + return explicitCases; + } - public DiscoveryConverter(ITestLogger logger, IAdapterSettings settings) + public IList Convert(NUnitResults discoveryResults, string assemblyPath) + { + if (discoveryResults == null) + return new List(); + AssemblyPath = assemblyPath; + var timing = new TimingLogger(Settings, TestLog); + if (Settings.DiscoveryMethod != DiscoveryMethod.Legacy) { - Settings = settings; - TestLog = logger; + TestRun = ConvertXml(discoveryResults); } - public IList Convert(NUnitResults discoveryResults, string assemblyPath) - { - if (discoveryResults == null) - return new List(); - AssemblyPath = assemblyPath; - var timing = new TimingLogger(Settings, TestLog); - if (Settings.DiscoveryMethod != DiscoveryMethod.Legacy) - { - TestRun = ConvertXml(discoveryResults); - } - - var nunitTestCases = discoveryResults.TestCases(); - - // As a side effect of calling TestConverter.ConvertTestCase, - // the converter's cache of all test cases is populated as well. - // All future calls to convert a test case may now use the cache. + var nunitTestCases = discoveryResults.TestCases(); - if (Settings.DiscoveryMethod == DiscoveryMethod.Legacy) - { - converterForXml = new TestConverterForXml(TestLog, AssemblyPath, Settings); - foreach (XmlNode testNode in nunitTestCases) - loadedTestCases.Add(converterForXml.ConvertTestCase(new NUnitEventTestCase(testNode))); - TestLog.Info( - $" NUnit3TestExecutor discovered {loadedTestCases.Count} of {nunitTestCases.Count} NUnit test cases using Legacy discovery mode"); - } - else - { - converter = new TestConverter(TestLog, AssemblyPath, Settings, this); - var isExplicit = TestRun.IsExplicit; - var testCases = RunnableTestCases(isExplicit); - foreach (var testNode in testCases) - loadedTestCases.Add(converter.ConvertTestCase(testNode)); - var msg = isExplicit ? "Explicit run" : "Non-Explicit run"; - TestLog.Info( - $" NUnit3TestExecutor discovered {loadedTestCases.Count} of {nunitTestCases.Count} NUnit test cases using Current Discovery mode, {msg}"); - } - - timing.LogTime("Converting test cases "); - return loadedTestCases; - - IEnumerable RunnableTestCases(bool isExplicit) => - isExplicit - ? TestRun.TestAssembly.AllTestCases - : TestRun.TestAssembly.RunnableTestCases; - } + // As a side effect of calling TestConverter.ConvertTestCase, + // the converter's cache of all test cases is populated as well. + // All future calls to convert a test case may now use the cache. - public NUnitDiscoveryTestRun ConvertXml(NUnitResults discovery) + if (Settings.DiscoveryMethod == DiscoveryMethod.Legacy) { - var doc = XDocument.Load(new XmlNodeReader(discovery.FullTopNode)); - var testrun = ExtractTestRun(doc); - var anode = doc.Root.Elements("test-suite"); - var assemblyNode = anode.Single(o => o.Attribute(NUnitXmlAttributeNames.Type).Value == "Assembly"); - var testassembly = ExtractTestAssembly(assemblyNode, testrun); - ExtractAllFixtures(testassembly, assemblyNode); - return testrun; + converterForXml = new TestConverterForXml(TestLog, AssemblyPath, Settings); + foreach (XmlNode testNode in nunitTestCases) + loadedTestCases.Add(converterForXml.ConvertTestCase(new NUnitEventTestCase(testNode))); + TestLog.Info( + $" NUnit3TestExecutor discovered {loadedTestCases.Count} of {nunitTestCases.Count} NUnit test cases using Legacy discovery mode"); } - - private static NUnitDiscoveryTestSuite ExtractTestSuite(XElement node, NUnitDiscoverySuiteBase parent) + else { - var b = ExtractSuiteBasePropertiesClass(node); - var ts = new NUnitDiscoveryTestSuite(b, parent); - return ts; + converter = new TestConverter(TestLog, AssemblyPath, Settings, this); + var isExplicit = TestRun.IsExplicit; + var testCases = RunnableTestCases(isExplicit); + foreach (var testNode in testCases) + loadedTestCases.Add(converter.ConvertTestCase(testNode)); + var msg = isExplicit ? "Explicit run" : "Non-Explicit run"; + TestLog.Info( + $" NUnit3TestExecutor discovered {loadedTestCases.Count} of {nunitTestCases.Count} NUnit test cases using Current Discovery mode, {msg}"); } - private void ExtractAllFixtures(NUnitDiscoveryCanHaveTestFixture parent, XElement node) + timing.LogTime("Converting test cases "); + return loadedTestCases; + + IEnumerable RunnableTestCases(bool isExplicit) => + isExplicit + ? TestRun.TestAssembly.AllTestCases + : TestRun.TestAssembly.RunnableTestCases; + } + + public NUnitDiscoveryTestRun ConvertXml(NUnitResults discovery) + { + var doc = XDocument.Load(new XmlNodeReader(discovery.FullTopNode)); + var testrun = ExtractTestRun(doc); + var anode = doc.Root.Elements("test-suite"); + var assemblyNode = anode.Single(o => o.Attribute(NUnitXmlAttributeNames.Type).Value == "Assembly"); + var testassembly = ExtractTestAssembly(assemblyNode, testrun); + ExtractAllFixtures(testassembly, assemblyNode); + return testrun; + } + + private static NUnitDiscoveryTestSuite ExtractTestSuite(XElement node, NUnitDiscoverySuiteBase parent) + { + var b = ExtractSuiteBasePropertiesClass(node); + var ts = new NUnitDiscoveryTestSuite(b, parent); + return ts; + } + + private void ExtractAllFixtures(NUnitDiscoveryCanHaveTestFixture parent, XElement node) + { + foreach (var child in node.Elements("test-suite")) { - foreach (var child in node.Elements("test-suite")) + var type = child.Attribute(NUnitXmlAttributeNames.Type)?.Value; + if (type == null) { - var type = child.Attribute(NUnitXmlAttributeNames.Type)?.Value; - if (type == null) - { - TestLog.Debug($"ETF1:Don't understand element: {child}"); - continue; - } - - var className = child.Attribute(NUnitXmlAttributeNames.Classname)?.Value; - switch (type) - { - case TestFixture: - var tf = ExtractTestFixture(parent, child, className); - parent.AddTestFixture(tf); - ExtractTestCases(tf, child); - ExtractParameterizedMethodsAndTheories(tf, child); - break; - case GenericFixture: - var gtf = ExtractGenericTestFixture(parent, child); - parent.AddTestGenericFixture(gtf); - ExtractTestFixtures(gtf, child); - break; - case ParameterizedFixture: - var ptf = ExtractParameterizedTestFixture(parent, child); - parent.AddParameterizedFixture(ptf); - ExtractTestFixtures(ptf, child); - break; - case SetUpFixture: - var stf = ExtractSetUpTestFixture(parent, child, className); - parent.AddSetUpFixture(stf); - ExtractTestFixtures(stf, child); - break; - case TestSuite: - var ts = ExtractTestSuite(child, parent); - parent.AddTestSuite(ts); - if (child.HasElements) - ExtractAllFixtures(ts, child); - break; - default: - throw new DiscoveryException($"Invalid type found in ExtractAllFixtures for test suite: {type}"); - } + TestLog.Debug($"ETF1:Don't understand element: {child}"); + continue; } - } - private void ExtractTestFixtures(NUnitDiscoveryCanHaveTestFixture parent, XElement node) - { - foreach (var child in node.Elements().Where(o => o.Name != "properties")) + var className = child.Attribute(NUnitXmlAttributeNames.Classname)?.Value; + switch (type) { - var type = child.Attribute(NUnitXmlAttributeNames.Type)?.Value; - if (type == null) - { - TestLog.Debug($"ETF2:Don't understand element: {child}"); - continue; - } - var className = child.Attribute(NUnitXmlAttributeNames.Classname)?.Value; - var btf = ExtractSuiteBasePropertiesClass(child); - switch (type) - { - case TestFixture: - var tf = new NUnitDiscoveryTestFixture(btf, className, parent); - parent.AddTestFixture(tf); - ExtractTestCases(tf, child); - ExtractParameterizedMethodsAndTheories(tf, child); - break; - case TestSuite: - var ts = ExtractTestSuite(child, parent); - parent.AddTestSuite(ts); - if (child.HasElements) - ExtractAllFixtures(ts, child); - break; - case SetUpFixture: - var tsf = ExtractSetUpTestFixture(parent, node, className); - parent.AddSetUpFixture(tsf); - if (child.HasElements) - { - ExtractTestFixtures(tsf, child); - } - break; - case ParameterizedFixture: - var ptf = ExtractParameterizedTestFixture(parent, node); - parent.AddParameterizedFixture(ptf); - if (child.HasElements) - { - ExtractTestFixtures(ptf, child); - } - break; - case GenericFixture: - var gf = ExtractGenericTestFixture(parent, node); - parent.AddTestGenericFixture(gf); - if (child.HasElements) - { - ExtractTestFixtures(gf, child); - } - break; - default: - throw new DiscoveryException($"Not a TestFixture, SetUpFixture, ParameterizedFixture, GenericFixture or TestSuite, but {type}"); - } + case TestFixture: + var tf = ExtractTestFixture(parent, child, className); + parent.AddTestFixture(tf); + ExtractTestCases(tf, child); + ExtractParameterizedMethodsAndTheories(tf, child); + break; + case GenericFixture: + var gtf = ExtractGenericTestFixture(parent, child); + parent.AddTestGenericFixture(gtf); + ExtractTestFixtures(gtf, child); + break; + case ParameterizedFixture: + var ptf = ExtractParameterizedTestFixture(parent, child); + parent.AddParameterizedFixture(ptf); + ExtractTestFixtures(ptf, child); + break; + case SetUpFixture: + var stf = ExtractSetUpTestFixture(parent, child, className); + parent.AddSetUpFixture(stf); + ExtractTestFixtures(stf, child); + break; + case TestSuite: + var ts = ExtractTestSuite(child, parent); + parent.AddTestSuite(ts); + if (child.HasElements) + ExtractAllFixtures(ts, child); + break; + default: + throw new DiscoveryException($"Invalid type found in ExtractAllFixtures for test suite: {type}"); } } + } - private static void ExtractParameterizedMethodsAndTheories(NUnitDiscoveryTestFixture tf, XElement node) + private void ExtractTestFixtures(NUnitDiscoveryCanHaveTestFixture parent, XElement node) + { + foreach (var child in node.Elements().Where(o => o.Name != "properties")) { - const string parameterizedMethod = "ParameterizedMethod"; - const string theory = "Theory"; - foreach (var child in node.Elements("test-suite")) + var type = child.Attribute(NUnitXmlAttributeNames.Type)?.Value; + if (type == null) { - var type = child.Attribute(NUnitXmlAttributeNames.Type)?.Value; - if (type != parameterizedMethod && type != "Theory" && type != "GenericMethod") - throw new DiscoveryException($"Expected ParameterizedMethod, Theory or GenericMethod, but was {type}"); - var className = child.Attribute(NUnitXmlAttributeNames.Classname)?.Value; - var btf = ExtractSuiteBasePropertiesClass(child); - switch (type) - { - case parameterizedMethod: - { - var tc = new NUnitDiscoveryParameterizedMethod(btf, className, tf); - ExtractTestCases(tc, child); - tf.AddParameterizedMethod(tc); - break; - } - case theory: - { - var tc = new NUnitDiscoveryTheory(btf, className, tf); - tf.AddTheory(tc); - ExtractTestCases(tc, child); - break; - } - default: - { - var tc = new NUnitDiscoveryGenericMethod(btf, className, tf); - tf.AddGenericMethod(tc); - ExtractTestCases(tc, child); - break; - } - } + TestLog.Debug($"ETF2:Don't understand element: {child}"); + continue; } - } - - public static IEnumerable ExtractTestCases(INUnitDiscoveryCanHaveTestCases tf, XElement node) - { - foreach (var child in node.Elements("test-case")) + var className = child.Attribute(NUnitXmlAttributeNames.Classname)?.Value; + var btf = ExtractSuiteBasePropertiesClass(child); + switch (type) { - var tc = ExtractTestCase(tf, child); - tf.AddTestCase(tc); + case TestFixture: + var tf = new NUnitDiscoveryTestFixture(btf, className, parent); + parent.AddTestFixture(tf); + ExtractTestCases(tf, child); + ExtractParameterizedMethodsAndTheories(tf, child); + break; + case TestSuite: + var ts = ExtractTestSuite(child, parent); + parent.AddTestSuite(ts); + if (child.HasElements) + ExtractAllFixtures(ts, child); + break; + case SetUpFixture: + var tsf = ExtractSetUpTestFixture(parent, node, className); + parent.AddSetUpFixture(tsf); + if (child.HasElements) + { + ExtractTestFixtures(tsf, child); + } + break; + case ParameterizedFixture: + var ptf = ExtractParameterizedTestFixture(parent, node); + parent.AddParameterizedFixture(ptf); + if (child.HasElements) + { + ExtractTestFixtures(ptf, child); + } + break; + case GenericFixture: + var gf = ExtractGenericTestFixture(parent, node); + parent.AddTestGenericFixture(gf); + if (child.HasElements) + { + ExtractTestFixtures(gf, child); + } + break; + default: + throw new DiscoveryException($"Not a TestFixture, SetUpFixture, ParameterizedFixture, GenericFixture or TestSuite, but {type}"); } - - return tf.TestCases; } + } - /// - /// Extracts single test case, made public for testing. - /// - public static NUnitDiscoveryTestCase ExtractTestCase(INUnitDiscoveryCanHaveTestCases tf, XElement child) + private static void ExtractParameterizedMethodsAndTheories(NUnitDiscoveryTestFixture tf, XElement node) + { + const string parameterizedMethod = "ParameterizedMethod"; + const string theory = "Theory"; + foreach (var child in node.Elements("test-suite")) { + var type = child.Attribute(NUnitXmlAttributeNames.Type)?.Value; + if (type != parameterizedMethod && type != "Theory" && type != "GenericMethod") + throw new DiscoveryException($"Expected ParameterizedMethod, Theory or GenericMethod, but was {type}"); var className = child.Attribute(NUnitXmlAttributeNames.Classname)?.Value; - var methodName = child.Attribute(NUnitXmlAttributeNames.Methodname)?.Value; - var seedAtr = child.Attribute(NUnitXmlAttributeNames.Seed)?.Value; - var seed = seedAtr != null ? long.Parse(seedAtr, CultureInfo.InvariantCulture) : 0; var btf = ExtractSuiteBasePropertiesClass(child); - var tc = new NUnitDiscoveryTestCase(btf, tf, className, methodName, seed); - return tc; - } - - - public static NUnitDiscoveryTestFixture ExtractTestFixture(INUnitDiscoveryCanHaveTestFixture parent, XElement node, - string className) - { - var b = ExtractSuiteBasePropertiesClass(node); - var ts = new NUnitDiscoveryTestFixture(b, className, parent); - return ts; + switch (type) + { + case parameterizedMethod: + { + var tc = new NUnitDiscoveryParameterizedMethod(btf, className, tf); + ExtractTestCases(tc, child); + tf.AddParameterizedMethod(tc); + break; + } + case theory: + { + var tc = new NUnitDiscoveryTheory(btf, className, tf); + tf.AddTheory(tc); + ExtractTestCases(tc, child); + break; + } + default: + { + var tc = new NUnitDiscoveryGenericMethod(btf, className, tf); + tf.AddGenericMethod(tc); + ExtractTestCases(tc, child); + break; + } + } } + } - private static NUnitDiscoveryGenericFixture ExtractGenericTestFixture( - NUnitDiscoveryCanHaveTestFixture parent, - XElement node) - { - var b = ExtractSuiteBasePropertiesClass(node); - var ts = new NUnitDiscoveryGenericFixture(b, parent); - return ts; - } - private static NUnitDiscoverySetUpFixture ExtractSetUpTestFixture( - NUnitDiscoveryCanHaveTestFixture parent, - XElement node, string className) - { - var b = ExtractSuiteBasePropertiesClass(node); - var ts = new NUnitDiscoverySetUpFixture(b, className, parent); - return ts; - } - private static NUnitDiscoveryParameterizedTestFixture ExtractParameterizedTestFixture( - NUnitDiscoveryCanHaveTestFixture parent, XElement node) + public static IEnumerable ExtractTestCases(INUnitDiscoveryCanHaveTestCases tf, XElement node) + { + foreach (var child in node.Elements("test-case")) { - var b = ExtractSuiteBasePropertiesClass(node); - var ts = new NUnitDiscoveryParameterizedTestFixture(b, parent); - return ts; + var tc = ExtractTestCase(tf, child); + tf.AddTestCase(tc); } - private NUnitDiscoveryTestAssembly ExtractTestAssembly(XElement node, NUnitDiscoveryTestRun parent) - { - string dType = node.Attribute(NUnitXmlAttributeNames.Type)?.Value; - if (dType is not "Assembly") - throw new DiscoveryException("Node is not of type assembly: " + node); - var aBase = ExtractSuiteBasePropertiesClass(node); - var assembly = new NUnitDiscoveryTestAssembly(aBase, parent); - parent.AddTestAssembly(assembly); - return assembly; - } + return tf.TestCases; + } - private static BaseProperties ExtractSuiteBasePropertiesClass(XElement node) - { - string dId = node.Attribute(NUnitXmlAttributeNames.Id).Value; - string dName = node.Attribute(NUnitXmlAttributeNames.Name).Value; - string dFullname = node.Attribute(NUnitXmlAttributeNames.Fullname).Value; - var dRunstate = ExtractRunState(node); - const char apo = '\''; - var tcs = node.Attribute(NUnitXmlAttributeNames.Testcasecount)?.Value.Trim(apo); - int dTestcasecount = int.Parse(tcs ?? "1", CultureInfo.InvariantCulture); - var bp = new BaseProperties(dId, dName, dFullname, dTestcasecount, dRunstate); - - foreach (var propnode in node.Elements("properties").Elements("property")) - { - var prop = new NUnitProperty(propnode); - bp.Properties.Add(prop); - } - return bp; - } + /// + /// Extracts single test case, made public for testing. + /// + public static NUnitDiscoveryTestCase ExtractTestCase(INUnitDiscoveryCanHaveTestCases tf, XElement child) + { + var className = child.Attribute(NUnitXmlAttributeNames.Classname)?.Value; + var methodName = child.Attribute(NUnitXmlAttributeNames.Methodname)?.Value; + var seedAtr = child.Attribute(NUnitXmlAttributeNames.Seed)?.Value; + var seed = seedAtr != null ? long.Parse(seedAtr, CultureInfo.InvariantCulture) : 0; + var btf = ExtractSuiteBasePropertiesClass(child); + var tc = new NUnitDiscoveryTestCase(btf, tf, className, methodName, seed); + return tc; + } - private NUnitDiscoveryTestRun ExtractTestRun(XDocument node) - { - var sb = ExtractSuiteBasePropertiesClass(node.Root); - var tr = new NUnitDiscoveryTestRun(sb); - return tr; - } + public static NUnitDiscoveryTestFixture ExtractTestFixture(INUnitDiscoveryCanHaveTestFixture parent, XElement node, + string className) + { + var b = ExtractSuiteBasePropertiesClass(node); + var ts = new NUnitDiscoveryTestFixture(b, className, parent); + return ts; + } + private static NUnitDiscoveryGenericFixture ExtractGenericTestFixture( + NUnitDiscoveryCanHaveTestFixture parent, + XElement node) + { + var b = ExtractSuiteBasePropertiesClass(node); + var ts = new NUnitDiscoveryGenericFixture(b, parent); + return ts; + } + private static NUnitDiscoverySetUpFixture ExtractSetUpTestFixture( + NUnitDiscoveryCanHaveTestFixture parent, + XElement node, string className) + { + var b = ExtractSuiteBasePropertiesClass(node); + var ts = new NUnitDiscoverySetUpFixture(b, className, parent); + return ts; + } + private static NUnitDiscoveryParameterizedTestFixture ExtractParameterizedTestFixture( + NUnitDiscoveryCanHaveTestFixture parent, XElement node) + { + var b = ExtractSuiteBasePropertiesClass(node); + var ts = new NUnitDiscoveryParameterizedTestFixture(b, parent); + return ts; + } - private static RunStateEnum ExtractRunState(XElement node) - { - var runState = node.Attribute(NUnitXmlAttributeNames.Runstate)?.Value switch - { - "Runnable" => RunStateEnum.Runnable, - "Explicit" => RunStateEnum.Explicit, - "NotRunnable" => RunStateEnum.NotRunnable, - _ => RunStateEnum.NA - }; - return runState; - } + private NUnitDiscoveryTestAssembly ExtractTestAssembly(XElement node, NUnitDiscoveryTestRun parent) + { + string dType = node.Attribute(NUnitXmlAttributeNames.Type)?.Value; + if (dType is not "Assembly") + throw new DiscoveryException("Node is not of type assembly: " + node); + var aBase = ExtractSuiteBasePropertiesClass(node); + var assembly = new NUnitDiscoveryTestAssembly(aBase, parent); + parent.AddTestAssembly(assembly); + return assembly; } - public class BaseProperties + private static BaseProperties ExtractSuiteBasePropertiesClass(XElement node) { - public BaseProperties(string dId, string dName, string dFullname, int dTestcasecount, RunStateEnum dRunstate) + string dId = node.Attribute(NUnitXmlAttributeNames.Id).Value; + string dName = node.Attribute(NUnitXmlAttributeNames.Name).Value; + string dFullname = node.Attribute(NUnitXmlAttributeNames.Fullname).Value; + var dRunstate = ExtractRunState(node); + const char apo = '\''; + var tcs = node.Attribute(NUnitXmlAttributeNames.Testcasecount)?.Value.Trim(apo); + int dTestcasecount = int.Parse(tcs ?? "1", CultureInfo.InvariantCulture); + var bp = new BaseProperties(dId, dName, dFullname, dTestcasecount, dRunstate); + + foreach (var propnode in node.Elements("properties").Elements("property")) { - Id = dId; - Name = dName; - Fullname = dFullname; - TestCaseCount = dTestcasecount; - RunState = dRunstate; + var prop = new NUnitProperty(propnode); + bp.Properties.Add(prop); } + return bp; + } + - public List Properties { get; } = new (); + private NUnitDiscoveryTestRun ExtractTestRun(XDocument node) + { + var sb = ExtractSuiteBasePropertiesClass(node.Root); + var tr = new NUnitDiscoveryTestRun(sb); + return tr; + } - public string Id { get; } - public string Name { get; } - public string Fullname { get; } - public RunStateEnum RunState { get; } - public int TestCaseCount { get; } + private static RunStateEnum ExtractRunState(XElement node) + { + var runState = node.Attribute(NUnitXmlAttributeNames.Runstate)?.Value switch + { + "Runnable" => RunStateEnum.Runnable, + "Explicit" => RunStateEnum.Explicit, + "NotRunnable" => RunStateEnum.NotRunnable, + _ => RunStateEnum.NA + }; + return runState; } } + +public class BaseProperties(string dId, string dName, string dFullname, int dTestcasecount, RunStateEnum dRunstate) +{ + public List Properties { get; } = []; + + public string Id { get; } = dId; + public string Name { get; } = dName; + public string Fullname { get; } = dFullname; + public RunStateEnum RunState { get; } = dRunstate; + + public int TestCaseCount { get; } = dTestcasecount; +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/DiscoveryException.cs b/src/NUnitTestAdapter/NUnitEngine/DiscoveryException.cs index b58a7ba0..4b1d0479 100644 --- a/src/NUnitTestAdapter/NUnitEngine/DiscoveryException.cs +++ b/src/NUnitTestAdapter/NUnitEngine/DiscoveryException.cs @@ -24,27 +24,26 @@ using System; using System.Runtime.Serialization; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +[Serializable] +public class DiscoveryException : Exception { - [Serializable] - public class DiscoveryException : Exception + public DiscoveryException() { - public DiscoveryException() - { - } + } - public DiscoveryException(string message) : base(message) - { - } + public DiscoveryException(string message) : base(message) + { + } - public DiscoveryException(string message, Exception inner) : base(message, inner) - { - } + public DiscoveryException(string message, Exception inner) : base(message, inner) + { + } - protected DiscoveryException( - SerializationInfo info, - StreamingContext context) : base(info, context) - { - } + protected DiscoveryException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/Extensions.cs b/src/NUnitTestAdapter/NUnitEngine/Extensions.cs index b717cced..8ad94dda 100644 --- a/src/NUnitTestAdapter/NUnitEngine/Extensions.cs +++ b/src/NUnitTestAdapter/NUnitEngine/Extensions.cs @@ -27,23 +27,22 @@ using NUnit.Engine; #pragma warning disable SA1618 // Generic type parameters should be documented -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public static class Extensions { - public static class Extensions - { - /// - /// All will return true if seq is empty. This returns false if sequence is empty. - /// - public static bool AllWithEmptyFalse(this IEnumerable list, Func pred) => - list.All(pred) && list.Any(); + /// + /// All will return true if seq is empty. This returns false if sequence is empty. + /// + public static bool AllWithEmptyFalse(this IEnumerable list, Func pred) + => list.All(pred) && list.Any(); - public static bool IsEmpty(this TestFilter filter) => filter == TestFilter.Empty; + public static bool IsEmpty(this TestFilter filter) => filter == TestFilter.Empty; - public static bool IsCategoryFilter(this TestFilter filter) => - filter != TestFilter.Empty && filter.Text.Contains(""); + public static bool IsCategoryFilter(this TestFilter filter) => + filter != TestFilter.Empty && filter.Text.Contains(""); - public static bool IsNegativeCategoryFilter(this TestFilter filter) => - filter.IsCategoryFilter() && filter.Text.Contains(""); - } -} + public static bool IsNegativeCategoryFilter(this TestFilter filter) => + filter.IsCategoryFilter() && filter.Text.Contains(""); +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitDiscoveryTestClasses.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitDiscoveryTestClasses.cs index ceea0925..ee41abb7 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitDiscoveryTestClasses.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitDiscoveryTestClasses.cs @@ -27,379 +27,349 @@ // ReSharper disable InconsistentNaming -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine -{ - public interface INUnitDiscoverySuiteBase : INUnitTestCasePropertyInfo - { - string Id { get; } - string Name { get; } - string FullName { get; } - int TestCaseCount { get; } - INUnitDiscoverySuiteBase Parent { get; } - NUnitDiscoveryProperties NUnitDiscoveryProperties { get; } - bool IsExplicit { get; } - bool IsExplicitReverse { get; } - - bool IsParameterizedMethod { get; } - void AddToAllTestCases(NUnitDiscoveryTestCase tc); - } - - public abstract class NUnitDiscoverySuiteBase : INUnitDiscoverySuiteBase - { - public string Id { get; } - public string Name { get; } - public string FullName { get; } - public int TestCaseCount { get; } - public RunStateEnum RunState { get; } - public INUnitDiscoverySuiteBase Parent { get; } - - - private NUnitDiscoverySuiteBase(string id, string name, string fullname, int count) - { - Id = id; - Name = name; - FullName = fullname; - TestCaseCount = count; - } +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; - protected NUnitDiscoverySuiteBase(BaseProperties other) - : this(other.Id, other.Name, other.Fullname, other.TestCaseCount) - { - RunState = other.RunState; - foreach (var prop in other.Properties) - { - NUnitDiscoveryProperties.Add(prop); - } - } - - protected NUnitDiscoverySuiteBase(BaseProperties other, INUnitDiscoverySuiteBase parent) : this(other) - { - Parent = parent; - } +public interface INUnitDiscoverySuiteBase : INUnitTestCasePropertyInfo +{ + string Id { get; } + string Name { get; } + string FullName { get; } + int TestCaseCount { get; } + INUnitDiscoverySuiteBase Parent { get; } + NUnitDiscoveryProperties NUnitDiscoveryProperties { get; } + bool IsExplicit { get; } + bool IsExplicitReverse { get; } + + bool IsParameterizedMethod { get; } + void AddToAllTestCases(NUnitDiscoveryTestCase tc); +} - public NUnitDiscoveryProperties NUnitDiscoveryProperties { get; } = new (); +public abstract class NUnitDiscoverySuiteBase : INUnitDiscoverySuiteBase +{ + public string Id { get; } + public string Name { get; } + public string FullName { get; } + public int TestCaseCount { get; } + public RunStateEnum RunState { get; } + public INUnitDiscoverySuiteBase Parent { get; } - public abstract bool IsExplicit { get; } - public virtual bool IsExplicitReverse => RunState == RunStateEnum.Explicit || (Parent?.IsExplicitReverse ?? RunState == RunStateEnum.Explicit); - public virtual bool IsParameterizedMethod => false; - public IEnumerable Properties => NUnitDiscoveryProperties.Properties; - public virtual void AddToAllTestCases(NUnitDiscoveryTestCase tc) - { - Parent.AddToAllTestCases(tc); - } + private NUnitDiscoverySuiteBase(string id, string name, string fullname, int count) + { + Id = id; + Name = name; + FullName = fullname; + TestCaseCount = count; } - - public class NUnitDiscoveryTestRun : NUnitDiscoverySuiteBase + protected NUnitDiscoverySuiteBase(BaseProperties other) + : this(other.Id, other.Name, other.Fullname, other.TestCaseCount) { - public NUnitDiscoveryTestRun(BaseProperties baseProps) : base(baseProps) + RunState = other.RunState; + foreach (var prop in other.Properties) { - } - - public NUnitDiscoveryTestAssembly TestAssembly { get; set; } - public override bool IsExplicit => - RunState == RunStateEnum.Explicit || TestAssembly.IsExplicit; - - public void AddTestAssembly(NUnitDiscoveryTestAssembly testAssembly) - { - TestAssembly = testAssembly; + NUnitDiscoveryProperties.Add(prop); } } - public class NUnitDiscoveryProperties + protected NUnitDiscoverySuiteBase(BaseProperties other, INUnitDiscoverySuiteBase parent) : this(other) { - private List TheProperties { get; } = new (); - public IEnumerable Properties => TheProperties; + Parent = parent; + } - public void Add(NUnitProperty p) => TheProperties.Add(p); + public NUnitDiscoveryProperties NUnitDiscoveryProperties { get; } = new(); - public bool AllInternal => TheProperties.All(o => o.IsInternal); - } + public abstract bool IsExplicit { get; } + public virtual bool IsExplicitReverse => RunState == RunStateEnum.Explicit || (Parent?.IsExplicitReverse ?? RunState == RunStateEnum.Explicit); + public virtual bool IsParameterizedMethod => false; + public IEnumerable Properties => NUnitDiscoveryProperties.Properties; - public class NUnitDiscoveryTestSuite : NUnitDiscoveryCanHaveTestFixture + public virtual void AddToAllTestCases(NUnitDiscoveryTestCase tc) { - public NUnitDiscoveryTestSuite(BaseProperties theBase, INUnitDiscoverySuiteBase parent) : base(theBase, parent) - { - } - - public NUnitDiscoveryTestAssembly ParentAssembly { get; set; } + Parent.AddToAllTestCases(tc); } +} +public class NUnitDiscoveryTestRun(BaseProperties baseProps) : NUnitDiscoverySuiteBase(baseProps) +{ + public NUnitDiscoveryTestAssembly TestAssembly { get; set; } + public override bool IsExplicit => + RunState == RunStateEnum.Explicit || TestAssembly.IsExplicit; - public sealed class NUnitDiscoveryTestAssembly : NUnitDiscoveryTestSuite + public void AddTestAssembly(NUnitDiscoveryTestAssembly testAssembly) { - public NUnitDiscoveryTestAssembly(BaseProperties theBase, NUnitDiscoveryTestRun parent) : base(theBase, parent) - { } + TestAssembly = testAssembly; + } +} - private readonly List allTestCases = new (); +public class NUnitDiscoveryProperties +{ + private List TheProperties { get; } = new(); + public IEnumerable Properties => TheProperties; - /// - /// If all testcases are Explicit, we can run this one. - /// - public IEnumerable AllTestCases => allTestCases; + public void Add(NUnitProperty p) => TheProperties.Add(p); - /// - /// If there are a mixture of explicit and non-explicit, this one will filter out the explicit ones. - /// - public IEnumerable RunnableTestCases => allTestCases.Where(c => !c.IsExplicitReverse); + public bool AllInternal => TheProperties.All(o => o.IsInternal); +} - public int NoOfExplicitTestCases => allTestCases.Count(c => c.IsExplicitReverse); +public class NUnitDiscoveryTestSuite(BaseProperties theBase, INUnitDiscoverySuiteBase parent) + : NUnitDiscoveryCanHaveTestFixture(theBase, parent) +{ + public NUnitDiscoveryTestAssembly ParentAssembly { get; set; } +} - public void AddTestSuiteToAssembly(NUnitDiscoveryTestSuite ts) - { - AddTestSuite(ts); - } - public override void AddToAllTestCases(NUnitDiscoveryTestCase tc) - { - allTestCases.Add(tc); - } - } - public sealed class NUnitDiscoveryTestFixture : NUnitDiscoveryCanHaveTestCases - { - private readonly List parameterizedMethods = new (); - public IEnumerable ParameterizedMethods => parameterizedMethods; +public sealed class NUnitDiscoveryTestAssembly(BaseProperties theBase, NUnitDiscoveryTestRun parent) + : NUnitDiscoveryTestSuite(theBase, parent) +{ + private readonly List allTestCases = new(); - private readonly List theories = new (); + /// + /// If all testcases are Explicit, we can run this one. + /// + public IEnumerable AllTestCases => allTestCases; - private readonly List genericMethods = new (); - public IEnumerable Theories => theories; + /// + /// If there are a mixture of explicit and non-explicit, this one will filter out the explicit ones. + /// + public IEnumerable RunnableTestCases => allTestCases.Where(c => !c.IsExplicitReverse); - public override int NoOfActualTestCases => - base.NoOfActualTestCases - + parameterizedMethods.Sum(o => o.NoOfActualTestCases) - + theories.Sum(o => o.NoOfActualTestCases) - + genericMethods.Sum(o => o.NoOfActualTestCases); + public int NoOfExplicitTestCases => allTestCases.Count(c => c.IsExplicitReverse); - public override bool IsExplicit - { - get - { - if (RunState == RunStateEnum.Explicit) - return true; - var all = new List(); - all.AddRange(TestCases.Cast()); - all.AddRange(parameterizedMethods.Cast()); - all.AddRange(theories.Cast()); - all.AddRange(genericMethods.Cast()); - return all.All(o => o.IsExplicit); - } - } + public void AddTestSuiteToAssembly(NUnitDiscoveryTestSuite ts) + { + AddTestSuite(ts); + } - public IEnumerable GenericMethods => genericMethods; + public override void AddToAllTestCases(NUnitDiscoveryTestCase tc) + { + allTestCases.Add(tc); + } +} - public NUnitDiscoveryTestFixture(BaseProperties theBase, string classname, INUnitDiscoverySuiteBase parent) : base(theBase, parent, classname) - { - } +public sealed class NUnitDiscoveryTestFixture(BaseProperties theBase, string classname, INUnitDiscoverySuiteBase parent) + : NUnitDiscoveryCanHaveTestCases(theBase, parent, classname) +{ + private readonly List parameterizedMethods = new(); + public IEnumerable ParameterizedMethods => parameterizedMethods; - public void AddParameterizedMethod(NUnitDiscoveryParameterizedMethod ts) - { - parameterizedMethods.Add(ts); - } + private readonly List theories = new(); + private readonly List genericMethods = new(); + public IEnumerable Theories => theories; - public void AddTheory(NUnitDiscoveryTheory tc) - { - theories.Add(tc); - } + public override int NoOfActualTestCases => + base.NoOfActualTestCases + + parameterizedMethods.Sum(o => o.NoOfActualTestCases) + + theories.Sum(o => o.NoOfActualTestCases) + + genericMethods.Sum(o => o.NoOfActualTestCases); - public void AddGenericMethod(NUnitDiscoveryGenericMethod tc) + public override bool IsExplicit + { + get { - genericMethods.Add(tc); + if (RunState == RunStateEnum.Explicit) + return true; + var all = new List(); + all.AddRange(TestCases); + all.AddRange(parameterizedMethods); + all.AddRange(theories); + all.AddRange(genericMethods); + return all.All(o => o.IsExplicit); } } - public interface INUnitDiscoveryTestCase : INUnitDiscoverySuiteBase - { - string ClassName { get; } - string MethodName { get; } - long Seed { get; set; } - } + public IEnumerable GenericMethods => genericMethods; - /// - /// Interface for common properties between event testcase and discoverytestcase. - /// - public interface INUnitCommonTestCase + public void AddParameterizedMethod(NUnitDiscoveryParameterizedMethod ts) { - string Id { get; } - string Name { get; } - string FullName { get; } - string ClassName { get; } - string MethodName { get; } - long Seed { get; } + parameterizedMethods.Add(ts); } - public sealed class NUnitDiscoveryTestCase : NUnitDiscoverySuiteBase, INUnitDiscoveryTestCase, INUnitCommonTestCase - { - public string ClassName { get; } - public string MethodName { get; set; } - public long Seed { get; set; } - - public NUnitDiscoveryTestCase(BaseProperties theBase, INUnitDiscoveryCanHaveTestCases parent, - string className, - string methodname, long seed) : base(theBase, parent) - { - ClassName = className; - MethodName = methodname; - Seed = seed; - } - public override bool IsExplicit => RunState == RunStateEnum.Explicit; - } - - public sealed class NUnitDiscoveryParameterizedMethod : NUnitDiscoveryCanHaveTestCases + public void AddTheory(NUnitDiscoveryTheory tc) { - public NUnitDiscoveryParameterizedMethod(BaseProperties theBase, string classname, INUnitDiscoverySuiteBase parent) : base(theBase, parent, classname) - { - } - - public override bool IsParameterizedMethod => true; + theories.Add(tc); } - public interface INUnitDiscoveryCanHaveTestCases : INUnitDiscoverySuiteBase + public void AddGenericMethod(NUnitDiscoveryGenericMethod tc) { - IEnumerable TestCases { get; } - int NoOfActualTestCases { get; } - void AddTestCase(NUnitDiscoveryTestCase tc); + genericMethods.Add(tc); } +} - public abstract class NUnitDiscoveryCanHaveTestCases : NUnitDiscoverySuiteBase, INUnitDiscoveryCanHaveTestCases - { - private readonly List testCases = new (); +public interface INUnitDiscoveryTestCase : INUnitDiscoverySuiteBase +{ + string ClassName { get; } + string MethodName { get; } + long Seed { get; set; } +} - public IEnumerable TestCases => testCases; - public virtual int NoOfActualTestCases => testCases.Count; +/// +/// Interface for common properties between event testcase and discoverytestcase. +/// +public interface INUnitCommonTestCase +{ + string Id { get; } + string Name { get; } + string FullName { get; } + string ClassName { get; } + string MethodName { get; } + long Seed { get; } +} - public override bool IsExplicit => - RunState == RunStateEnum.Explicit || testCases.AllWithEmptyFalse(o => o.IsExplicit); +public sealed class NUnitDiscoveryTestCase( + BaseProperties theBase, + INUnitDiscoveryCanHaveTestCases parent, + string className, + string methodname, + long seed) + : NUnitDiscoverySuiteBase(theBase, parent), INUnitDiscoveryTestCase, INUnitCommonTestCase +{ + public string ClassName { get; } = className; + public string MethodName { get; set; } = methodname; + public long Seed { get; set; } = seed; - public string ClassName { get; } + public override bool IsExplicit => RunState == RunStateEnum.Explicit; +} - public void AddTestCase(NUnitDiscoveryTestCase tc) - { - testCases.Add(tc); - Parent.AddToAllTestCases(tc); - } +public sealed class NUnitDiscoveryParameterizedMethod( + BaseProperties theBase, + string classname, + INUnitDiscoverySuiteBase parent) + : NUnitDiscoveryCanHaveTestCases(theBase, parent, classname) +{ + public override bool IsParameterizedMethod => true; +} - protected NUnitDiscoveryCanHaveTestCases(BaseProperties theBase, INUnitDiscoverySuiteBase parent, string classname) : base(theBase, parent) - { - ClassName = classname; - } - } +public interface INUnitDiscoveryCanHaveTestCases : INUnitDiscoverySuiteBase +{ + IEnumerable TestCases { get; } + int NoOfActualTestCases { get; } + void AddTestCase(NUnitDiscoveryTestCase tc); +} - public interface INUnitDiscoveryCanHaveTestFixture : INUnitDiscoverySuiteBase - { - IEnumerable TestFixtures { get; } - int NoOfActualTestCases { get; } - void AddTestFixture(NUnitDiscoveryTestFixture tf); - } +public abstract class NUnitDiscoveryCanHaveTestCases( + BaseProperties theBase, + INUnitDiscoverySuiteBase parent, + string classname) + : NUnitDiscoverySuiteBase(theBase, parent), INUnitDiscoveryCanHaveTestCases +{ + private readonly List testCases = new(); - public abstract class NUnitDiscoveryCanHaveTestFixture : NUnitDiscoverySuiteBase, INUnitDiscoveryCanHaveTestFixture - { - private readonly List testFixtures = new (); + public IEnumerable TestCases => testCases; + public virtual int NoOfActualTestCases => testCases.Count; - public IEnumerable TestFixtures => testFixtures; + public override bool IsExplicit => + RunState == RunStateEnum.Explicit || testCases.AllWithEmptyFalse(o => o.IsExplicit); - public void AddTestFixture(NUnitDiscoveryTestFixture tf) - { - testFixtures.Add(tf); - } - protected NUnitDiscoveryCanHaveTestFixture(BaseProperties theBase, INUnitDiscoverySuiteBase parent) : base(theBase, parent) - { - } + public string ClassName { get; } = classname; + + public void AddTestCase(NUnitDiscoveryTestCase tc) + { + testCases.Add(tc); + Parent.AddToAllTestCases(tc); + } +} +public interface INUnitDiscoveryCanHaveTestFixture : INUnitDiscoverySuiteBase +{ + IEnumerable TestFixtures { get; } + int NoOfActualTestCases { get; } + void AddTestFixture(NUnitDiscoveryTestFixture tf); +} - private readonly List testSuites = new (); +public abstract class NUnitDiscoveryCanHaveTestFixture(BaseProperties theBase, INUnitDiscoverySuiteBase parent) + : NUnitDiscoverySuiteBase(theBase, parent), INUnitDiscoveryCanHaveTestFixture +{ + private readonly List testFixtures = new(); - private readonly List genericFixtures = new (); - private readonly List setUpFixtures = new (); - private readonly List parameterizedFixtures = new (); + public IEnumerable TestFixtures => testFixtures; + public void AddTestFixture(NUnitDiscoveryTestFixture tf) + { + testFixtures.Add(tf); + } - public IEnumerable TestSuites => testSuites; - public IEnumerable SetUpFixtures => setUpFixtures; - public IEnumerable ParameterizedFixtures => parameterizedFixtures; - public IEnumerable GenericFixtures => genericFixtures; + private readonly List testSuites = new(); - public override bool IsExplicit - { - get - { - if (RunState == RunStateEnum.Explicit) - return true; - var fullList = new List(); - fullList.AddRange(TestFixtures.Cast()); - fullList.AddRange(TestSuites.Cast()); - fullList.AddRange(GenericFixtures.Cast()); - fullList.AddRange(SetUpFixtures.Cast()); - fullList.AddRange(ParameterizedFixtures.Cast()); - return fullList.All(o => o.IsExplicit); - } - } + private readonly List genericFixtures = new(); + private readonly List setUpFixtures = new(); + private readonly List parameterizedFixtures = new(); - public int NoOfActualTestCases => testFixtures.Sum(o => o.NoOfActualTestCases) - + testSuites.Sum(o => o.NoOfActualTestCases) - + genericFixtures.Sum(o => o.NoOfActualTestCases) - + setUpFixtures.Sum(o => o.NoOfActualTestCases) - + parameterizedFixtures.Sum(o => o.NoOfActualTestCases); - public void AddTestSuite(NUnitDiscoveryTestSuite ts) - { - testSuites.Add(ts); - } + public IEnumerable TestSuites => testSuites; + public IEnumerable SetUpFixtures => setUpFixtures; + public IEnumerable ParameterizedFixtures => parameterizedFixtures; - public void AddTestGenericFixture(NUnitDiscoveryGenericFixture ts) - { - genericFixtures.Add(ts); - } - public void AddSetUpFixture(NUnitDiscoverySetUpFixture ts) - { - setUpFixtures.Add(ts); - } - public void AddParameterizedFixture(NUnitDiscoveryParameterizedTestFixture ts) - { - parameterizedFixtures.Add(ts); - } - } + public IEnumerable GenericFixtures => genericFixtures; - public sealed class NUnitDiscoveryGenericFixture : NUnitDiscoveryCanHaveTestFixture + public override bool IsExplicit { - public NUnitDiscoveryGenericFixture(BaseProperties theBase, INUnitDiscoverySuiteBase parent) : base(theBase, parent) + get { + if (RunState == RunStateEnum.Explicit) + return true; + var fullList = new List(); + fullList.AddRange(TestFixtures); + fullList.AddRange(TestSuites); + fullList.AddRange(GenericFixtures); + fullList.AddRange(SetUpFixtures); + fullList.AddRange(ParameterizedFixtures); + return fullList.All(o => o.IsExplicit); } } - public sealed class NUnitDiscoveryParameterizedTestFixture : NUnitDiscoveryCanHaveTestFixture + public int NoOfActualTestCases => testFixtures.Sum(o => o.NoOfActualTestCases) + + testSuites.Sum(o => o.NoOfActualTestCases) + + genericFixtures.Sum(o => o.NoOfActualTestCases) + + setUpFixtures.Sum(o => o.NoOfActualTestCases) + + parameterizedFixtures.Sum(o => o.NoOfActualTestCases); + + public void AddTestSuite(NUnitDiscoveryTestSuite ts) { - public NUnitDiscoveryParameterizedTestFixture(BaseProperties theBase, NUnitDiscoveryCanHaveTestFixture parent) : base(theBase, parent) - { - } + testSuites.Add(ts); } - public sealed class NUnitDiscoverySetUpFixture : NUnitDiscoveryCanHaveTestFixture + public void AddTestGenericFixture(NUnitDiscoveryGenericFixture ts) { - public string ClassName { get; } - public NUnitDiscoverySetUpFixture(BaseProperties theBase, string classname, NUnitDiscoveryCanHaveTestFixture parent) : base(theBase, parent) - { - ClassName = classname; - } + genericFixtures.Add(ts); } - - public sealed class NUnitDiscoveryTheory : NUnitDiscoveryCanHaveTestCases + public void AddSetUpFixture(NUnitDiscoverySetUpFixture ts) { - public NUnitDiscoveryTheory(BaseProperties theBase, string classname, INUnitDiscoverySuiteBase parent) : base(theBase, parent, classname) - { - } + setUpFixtures.Add(ts); } - - public sealed class NUnitDiscoveryGenericMethod : NUnitDiscoveryCanHaveTestCases + public void AddParameterizedFixture(NUnitDiscoveryParameterizedTestFixture ts) { - public NUnitDiscoveryGenericMethod(BaseProperties theBase, string classname, INUnitDiscoverySuiteBase parent) : base(theBase, parent, classname) - { - } + parameterizedFixtures.Add(ts); } } + +public sealed class NUnitDiscoveryGenericFixture(BaseProperties theBase, INUnitDiscoverySuiteBase parent) + : NUnitDiscoveryCanHaveTestFixture(theBase, parent); + +public sealed class NUnitDiscoveryParameterizedTestFixture( + BaseProperties theBase, + NUnitDiscoveryCanHaveTestFixture parent) + : NUnitDiscoveryCanHaveTestFixture(theBase, parent); + +public sealed class NUnitDiscoverySetUpFixture( + BaseProperties theBase, + string classname, + NUnitDiscoveryCanHaveTestFixture parent) + : NUnitDiscoveryCanHaveTestFixture(theBase, parent) +{ + public string ClassName { get; } = classname; +} + +public sealed class NUnitDiscoveryTheory(BaseProperties theBase, string classname, INUnitDiscoverySuiteBase parent) + : NUnitDiscoveryCanHaveTestCases(theBase, parent, classname); + +public sealed class NUnitDiscoveryGenericMethod( + BaseProperties theBase, + string classname, + INUnitDiscoverySuiteBase parent) + : NUnitDiscoveryCanHaveTestCases(theBase, parent, classname); \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitEngineAdapter.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitEngineAdapter.cs index 3ee39a07..3c4ce429 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitEngineAdapter.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitEngineAdapter.cs @@ -22,199 +22,182 @@ // *********************************************************************** using System; -using System.Diagnostics; using System.IO; using System.Threading; using NUnit.Engine; using NUnit.VisualStudio.TestAdapter.Internal; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public interface INUnitEngineAdapter { - public interface INUnitEngineAdapter - { - NUnitResults Explore(); - void CloseRunner(); - NUnitResults Explore(TestFilter filter); - NUnitResults Run(ITestEventListener listener, TestFilter filter); - void StopRun(); + NUnitResults Explore(); + void CloseRunner(); + NUnitResults Explore(TestFilter filter); + NUnitResults Run(ITestEventListener listener, TestFilter filter); + void StopRun(); - T GetService() - where T : class; + T GetService() + where T : class; - void GenerateTestOutput(NUnitResults testResults, string assemblyPath, string testOutputXmlFolder); - string GetXmlFilePath(string folder, string defaultFileName, string extension); - } + void GenerateTestOutput(NUnitResults testResults, string assemblyPath, string testOutputXmlFolder); + string GetXmlFilePath(string folder, string defaultFileName, string extension); +} - public class NUnitEngineAdapter : INUnitEngineAdapter, IDisposable - { - private IAdapterSettings settings; - private ITestLogger logger; - private TestPackage package; - private ITestEngine TestEngine { get; set; } - private ITestRunner Runner { get; set; } +public class NUnitEngineAdapter : INUnitEngineAdapter, IDisposable +{ + private IAdapterSettings settings; + private ITestLogger logger; + private TestPackage package; + private ITestEngine TestEngine { get; set; } + private ITestRunner Runner { get; set; } - internal event Action InternalEngineCreated; + internal event Action InternalEngineCreated; - public bool EngineEnabled => TestEngine != null; + public bool EngineEnabled => TestEngine != null; - public void Initialize() - { + public void Initialize() + { #if NET462 - var engineX = new TestEngine(); + var engineX = new TestEngine(); #else - var engineX = TestEngineActivator.CreateInstance(); + var engineX = TestEngineActivator.CreateInstance() ?? new TestEngine(); #endif - if (engineX == null) - engineX = new TestEngine(); - - InternalEngineCreated?.Invoke(engineX); - TestEngine = engineX; - var tmpPath = Path.Combine(Path.GetTempPath(), "NUnit.Engine"); - if (!Directory.Exists(tmpPath)) - Directory.CreateDirectory(tmpPath); - TestEngine.WorkDirectory = tmpPath; - TestEngine.InternalTraceLevel = InternalTraceLevel.Off; - } - public void InitializeSettingsAndLogging(IAdapterSettings setting, ITestLogger testLog) - { - logger = testLog; - settings = setting; -#if EnableTraceLevelAtInitialization - -#endif - } + InternalEngineCreated?.Invoke(engineX); + TestEngine = engineX; + var tmpPath = Path.Combine(Path.GetTempPath(), "NUnit.Engine"); + if (!Directory.Exists(tmpPath)) + Directory.CreateDirectory(tmpPath); + TestEngine.WorkDirectory = tmpPath; + TestEngine.InternalTraceLevel = InternalTraceLevel.Off; + } - public void CreateRunner(TestPackage testPackage) - { - package = testPackage; - Runner = TestEngine.GetRunner(package); - } + public void InitializeSettingsAndLogging(IAdapterSettings setting, ITestLogger testLog) + { + logger = testLog; + settings = setting; + } - public NUnitResults Explore() - { - return Explore(TestFilter.Empty); - } + public void CreateRunner(TestPackage testPackage) + { + package = testPackage; + Runner = TestEngine.GetRunner(package); + } - public NUnitResults Explore(TestFilter filter) - { - var timing = new TimingLogger(settings, logger); - var results = new NUnitResults(Runner.Explore(filter)); - return LogTiming(filter, timing, results); - } + public NUnitResults Explore() + => Explore(TestFilter.Empty); - public NUnitResults Run(ITestEventListener listener, TestFilter filter) - { - var timing = new TimingLogger(settings, logger); - var results = new NUnitResults(Runner.Run(listener, filter)); - return LogTiming(filter, timing, results); - } + public NUnitResults Explore(TestFilter filter) + { + var timing = new TimingLogger(settings, logger); + var results = new NUnitResults(Runner.Explore(filter)); + return LogTiming(filter, timing, results); + } + + public NUnitResults Run(ITestEventListener listener, TestFilter filter) + { + var timing = new TimingLogger(settings, logger); + var results = new NUnitResults(Runner.Run(listener, filter)); + return LogTiming(filter, timing, results); + } + + private NUnitResults LogTiming(TestFilter filter, TimingLogger timing, NUnitResults results) + { + timing.LogTime($"Execution engine run time with filter length {filter.Text.Length}"); + if (filter.Text.Length < 300) + logger.Debug($"Filter: {filter.Text}"); + return results; + } - private NUnitResults LogTiming(TestFilter filter, TimingLogger timing, NUnitResults results) + public T GetService() + where T : class + { + var service = TestEngine.Services.GetService(); + if (service == null) { - timing.LogTime($"Execution engine run time with filter length {filter.Text.Length}"); - if (filter.Text.Length < 300) - logger.Debug($"Filter: {filter.Text}"); - return results; + logger.Warning($"Engine GetService can't create service {typeof(T)}."); } + return service; + } + + public void StopRun() + => Runner?.StopRun(true); + + public void CloseRunner() + { + if (Runner == null) + return; + if (Runner.IsTestRunning) + Runner.StopRun(true); - public T GetService() - where T : class + try { - var service = TestEngine.Services.GetService(); - if (service == null) - { - logger.Warning($"Engine GetService can't create service {typeof(T)}."); - } - return service; + Runner.Unload(); + Runner.Dispose(); } - - public void StopRun() + catch (NUnitEngineUnloadException ex) { - Runner?.StopRun(true); + logger.Warning($"Engine encountered NUnitEngineUnloadException : {ex.Message}"); } + Runner = null; + } - public void CloseRunner() - { - if (Runner == null) - return; - if (Runner.IsTestRunning) - Runner.StopRun(true); + public void Dispose() + { + CloseRunner(); + TestEngine?.Dispose(); + } - try - { - Runner.Unload(); - Runner.Dispose(); - } - catch (NUnitEngineUnloadException ex) - { - logger.Warning($"Engine encountered NUnitEngineUnloadException : {ex.Message}"); - } - Runner = null; - } + public void GenerateTestOutput(NUnitResults testResults, string assemblyPath, string testOutputXmlFolder) + { + if (!settings.UseTestOutputXml) + return; + + var resultService = GetService(); - public void Dispose() + using Mutex mutex = new Mutex(false, string.IsNullOrWhiteSpace(assemblyPath) ? nameof(GenerateTestOutput) : Path.GetFileNameWithoutExtension(assemblyPath)); + bool received = false; + try { - CloseRunner(); - TestEngine?.Dispose(); + received = mutex.WaitOne(); + string path = GetXmlFilePath(testOutputXmlFolder, GetTestOutputFileName(assemblyPath), "xml"); + + // Following null argument should work for nunit3 format. Empty array is OK as well. + // If you decide to handle other formats in the runsettings, it needs more work. + var resultWriter = resultService.GetResultWriter("nunit3", null); + resultWriter.WriteResultFile(testResults.FullTopNode, path); + logger.Info($" Test results written to {path}"); } - - public void GenerateTestOutput(NUnitResults testResults, string assemblyPath, string testOutputXmlFolder) + finally { - if (!settings.UseTestOutputXml) - return; - - var resultService = GetService(); - - using (Mutex mutex = new Mutex(false, string.IsNullOrWhiteSpace(assemblyPath) ? nameof(GenerateTestOutput) : Path.GetFileNameWithoutExtension(assemblyPath))) + if (received) { - bool received = false; - try - { - received = mutex.WaitOne(); - string path = GetXmlFilePath(testOutputXmlFolder, GetTestOutputFileName(assemblyPath), "xml"); - - // Following null argument should work for nunit3 format. Empty array is OK as well. - // If you decide to handle other formats in the runsettings, it needs more work. - var resultWriter = resultService.GetResultWriter("nunit3", null); - resultWriter.WriteResultFile(testResults.FullTopNode, path); - logger.Info($" Test results written to {path}"); - } - finally - { - if (received) - { - mutex.ReleaseMutex(); - } - } + mutex.ReleaseMutex(); } } + } - public string GetTestOutputFileName(string assemblyPath) + public string GetTestOutputFileName(string assemblyPath) + => string.IsNullOrWhiteSpace(settings.TestOutputXmlFileName) + ? Path.GetFileNameWithoutExtension(assemblyPath) + : settings.TestOutputXmlFileName; + + public string GetXmlFilePath(string folder, string defaultFileName, string extension) + { + if (!settings.NewOutputXmlFileForEachRun) { - if (string.IsNullOrWhiteSpace(settings.TestOutputXmlFileName)) - { - return Path.GetFileNameWithoutExtension(assemblyPath); - } - return settings.TestOutputXmlFileName; + // overwrite the existing file + return Path.Combine(folder, $"{defaultFileName}.{extension}"); } - - public string GetXmlFilePath(string folder, string defaultFileName, string extension) + // allways create a new file + int i = 1; + while (true) { - if (!settings.NewOutputXmlFileForEachRun) - { - // overwrite the existing file - return Path.Combine(folder, $"{defaultFileName}.{extension}"); - } - // allways create a new file - int i = 1; - while (true) - { - string path = Path.Combine(folder, $"{defaultFileName}.{i++}.{extension}"); - if (!File.Exists(path)) - return path; - } + string path = Path.Combine(folder, $"{defaultFileName}.{i++}.{extension}"); + if (!File.Exists(path)) + return path; } } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitEventTestCase.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitEventTestCase.cs index 1240c25a..76dc5490 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitEventTestCase.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitEventTestCase.cs @@ -24,67 +24,66 @@ using System.Collections.Generic; using System.Xml; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public interface INUnitTestCase : INUnitTestNode { - public interface INUnitTestCase : INUnitTestNode - { - bool IsTestCase { get; } - bool IsParameterizedMethod { get; } - string Type { get; } - string ClassName { get; } - string MethodName { get; } - RunStateEnum RunState { get; } - NUnitEventTestCase Parent { get; } - } + bool IsTestCase { get; } + bool IsParameterizedMethod { get; } + string Type { get; } + string ClassName { get; } + string MethodName { get; } + RunStateEnum RunState { get; } + NUnitEventTestCase Parent { get; } +} - public enum RunStateEnum - { - NA, - Runnable, - Explicit, - NotRunnable - } +public enum RunStateEnum +{ + NA, + Runnable, + Explicit, + NotRunnable +} - public interface INUnitTestCasePropertyInfo - { - RunStateEnum RunState { get; } - IEnumerable Properties { get; } - } +public interface INUnitTestCasePropertyInfo +{ + RunStateEnum RunState { get; } + IEnumerable Properties { get; } +} - public class NUnitEventTestCase : NUnitTestNode, INUnitTestCase, INUnitTestCasePropertyInfo - { - public bool IsTestCase => !IsNull && Node.Name == "test-case"; - public bool IsParameterizedMethod => Type == "ParameterizedMethod"; - public string Type => Node.GetAttribute("type"); - public string ClassName => Node.GetAttribute("classname"); - public string MethodName => Node.GetAttribute("methodname"); +public class NUnitEventTestCase : NUnitTestNode, INUnitTestCase, INUnitTestCasePropertyInfo +{ + public bool IsTestCase => !IsNull && Node.Name == "test-case"; + public bool IsParameterizedMethod => Type == "ParameterizedMethod"; + public string Type => Node.GetAttribute("type"); + public string ClassName => Node.GetAttribute("classname"); + public string MethodName => Node.GetAttribute("methodname"); - private RunStateEnum runState = RunStateEnum.NA; + private RunStateEnum runState = RunStateEnum.NA; - public RunStateEnum RunState + public RunStateEnum RunState + { + get { - get + if (runState == RunStateEnum.NA) { - if (runState == RunStateEnum.NA) + runState = Node.GetAttribute("runstate") switch { - runState = Node.GetAttribute("runstate") switch - { - "Runnable" => RunStateEnum.Runnable, - "Explicit" => RunStateEnum.Explicit, - "NotRunnable" => RunStateEnum.NotRunnable, - _ => runState - }; - } - return runState; + "Runnable" => RunStateEnum.Runnable, + "Explicit" => RunStateEnum.Explicit, + "NotRunnable" => RunStateEnum.NotRunnable, + _ => runState + }; } + return runState; } + } - public NUnitEventTestCase(XmlNode testCase) : base(testCase) - { - if (Node.ParentNode != null) - Parent = new NUnitEventTestCase(Node.ParentNode); - } - - public NUnitEventTestCase Parent { get; } + public NUnitEventTestCase(XmlNode testCase) : base(testCase) + { + if (Node.ParentNode != null) + Parent = new NUnitEventTestCase(Node.ParentNode); } + + public NUnitEventTestCase Parent { get; } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitResults.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitResults.cs index ba432c02..1ea5db32 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitResults.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitResults.cs @@ -25,49 +25,48 @@ using System.Xml; using NUnit.VisualStudio.TestAdapter.Dump; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public class NUnitResults { - public class NUnitResults + public enum SkipReason { - public enum SkipReason - { - NoNUnitTests, - LoadFailure - } + NoNUnitTests, + LoadFailure + } - public XmlNode TopNode { get; } + public XmlNode TopNode { get; } - public bool IsRunnable { get; } + public bool IsRunnable { get; } - public string AsString() => FullTopNode.AsString(); + public string AsString() => FullTopNode.AsString(); - public XmlNode FullTopNode { get; } - public NUnitResults(XmlNode results) - { - FullTopNode = results; - // Currently, this will always be the case but it might change - TopNode = results.Name == "test-run" ? results.FirstChild : results; - // ReSharper disable once StringLiteralTypo - IsRunnable = TopNode.GetAttribute("runstate") == "Runnable"; - } + public XmlNode FullTopNode { get; } + public NUnitResults(XmlNode results) + { + FullTopNode = results; + // Currently, this will always be the case but it might change + TopNode = results.Name == "test-run" ? results.FirstChild : results; + // ReSharper disable once StringLiteralTypo + IsRunnable = TopNode.GetAttribute("runstate") == "Runnable"; + } - public SkipReason WhatSkipReason() - { - var msgNode = TopNode.SelectSingleNode("properties/property[@name='_SKIPREASON']"); - return msgNode != null && - new[] { "contains no tests", "Has no TestFixtures" }.Any(msgNode.GetAttribute("value") - .Contains) - ? SkipReason.NoNUnitTests - : SkipReason.LoadFailure; - } + public SkipReason WhatSkipReason() + { + var msgNode = TopNode.SelectSingleNode("properties/property[@name='_SKIPREASON']"); + return msgNode != null && + new[] { "contains no tests", "Has no TestFixtures" }.Any(msgNode.GetAttribute("value") + .Contains) + ? SkipReason.NoNUnitTests + : SkipReason.LoadFailure; + } - public bool HasNoNUnitTests => WhatSkipReason() == SkipReason.NoNUnitTests; + public bool HasNoNUnitTests => WhatSkipReason() == SkipReason.NoNUnitTests; - public XmlNodeList TestCases() - { - return TopNode.SelectNodes("//test-case"); - } + public XmlNodeList TestCases() + { + return TopNode.SelectNodes("//test-case"); } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEvent.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEvent.cs index 7cbed4e0..f95da627 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEvent.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEvent.cs @@ -28,222 +28,221 @@ using System.Xml; using System.Xml.Linq; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public interface INUnitTestEventForXml { - public interface INUnitTestEventForXml - { - XmlNode Node { get; } - } + XmlNode Node { get; } +} - public interface INUnitTestEvent : INUnitTestNode - { - string Output { get; } - TimeSpan Duration { get; } - IEnumerable NUnitAttachments { get; } - NUnitTestEvent.CheckedTime StartTime(); - NUnitTestEvent.CheckedTime EndTime(); +public interface INUnitTestEvent : INUnitTestNode +{ + string Output { get; } + TimeSpan Duration { get; } + IEnumerable NUnitAttachments { get; } + NUnitTestEvent.CheckedTime StartTime(); + NUnitTestEvent.CheckedTime EndTime(); + + bool IsIgnored { get; } + NUnitTestEvent.ResultType Result(); + bool IsFailed { get; } + NUnitTestEvent.SiteType Site(); +} - bool IsIgnored { get; } - NUnitTestEvent.ResultType Result(); - bool IsFailed { get; } - NUnitTestEvent.SiteType Site(); +public abstract class NUnitTestEvent : NUnitTestNode, INUnitTestEvent +{ + public enum ResultType + { + Failed, + Success, + Skipped, + Warning, + NoIdea } - public abstract class NUnitTestEvent : NUnitTestNode, INUnitTestEvent + public enum SiteType { - public enum ResultType - { - Failed, - Success, - Skipped, - Warning, - NoIdea - } - - public enum SiteType - { - NoIdea, - Test, - Setup, - TearDown - } - public enum TestTypes - { - NoIdea, - TestFixture, - TestMethod - } + NoIdea, + Test, + Setup, + TearDown + } + public enum TestTypes + { + NoIdea, + TestFixture, + TestMethod + } - public TestTypes TestType() + public TestTypes TestType() + { + string type = Node.GetAttribute("type"); + return type switch { - string type = Node.GetAttribute("type"); - return type switch - { - "TestFixture" => TestTypes.TestFixture, - "TestMethod" => TestTypes.TestMethod, - _ => TestTypes.NoIdea - }; - } + "TestFixture" => TestTypes.TestFixture, + "TestMethod" => TestTypes.TestMethod, + _ => TestTypes.NoIdea + }; + } - public ResultType Result() - { - string res = Node.GetAttribute("result"); - return res switch - { - "Failed" => ResultType.Failed, - "Passed" => ResultType.Success, - "Skipped" => ResultType.Skipped, - "Warning" => ResultType.Warning, - _ => ResultType.NoIdea - }; - } + public ResultType Result() + { + string res = Node.GetAttribute("result"); + return res switch + { + "Failed" => ResultType.Failed, + "Passed" => ResultType.Success, + "Skipped" => ResultType.Skipped, + "Warning" => ResultType.Warning, + _ => ResultType.NoIdea + }; + } - public bool IsFailed => Result() == ResultType.Failed; + public bool IsFailed => Result() == ResultType.Failed; - public SiteType Site() + public SiteType Site() + { + string site = Node.GetAttribute("site"); + return site switch { - string site = Node.GetAttribute("site"); - return site switch - { - "SetUp" => SiteType.Setup, - "TearDown" => SiteType.TearDown, - _ => SiteType.NoIdea - }; - } + "SetUp" => SiteType.Setup, + "TearDown" => SiteType.TearDown, + _ => SiteType.NoIdea + }; + } - public string Label => Node.GetAttribute("label"); + public string Label => Node.GetAttribute("label"); - public bool IsIgnored => Label == "Ignored"; + public bool IsIgnored => Label == "Ignored"; - public TimeSpan Duration => TimeSpan.FromSeconds(Node.GetAttribute("duration", 0.0)); + public TimeSpan Duration => TimeSpan.FromSeconds(Node.GetAttribute("duration", 0.0)); - protected NUnitTestEvent(string testEvent) : this(XmlHelper.CreateXmlNode(testEvent)) - { } + protected NUnitTestEvent(string testEvent) : this(XmlHelper.CreateXmlNode(testEvent)) + { } - protected NUnitTestEvent(XmlNode node) : base(node) - { - } + protected NUnitTestEvent(XmlNode node) : base(node) + { + } - public string MethodName => Node.GetAttribute("methodname"); - public string ClassName => Node.GetAttribute("classname"); - public string Output => Node.SelectSingleNode("output")?.InnerText.UnEscapeUnicodeCharacters(); + public string MethodName => Node.GetAttribute("methodname"); + public string ClassName => Node.GetAttribute("classname"); + public string Output => Node.SelectSingleNode("output")?.InnerText.UnEscapeUnicodeCharacters(); - public CheckedTime StartTime() - { - string startTime = Node.GetAttribute("start-time"); - return startTime != null - ? new CheckedTime { Ok = true, Time = DateTimeOffset.Parse(startTime, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) } - : new CheckedTime { Ok = false, Time = DateTimeOffset.Now }; - } + public CheckedTime StartTime() + { + string startTime = Node.GetAttribute("start-time"); + return startTime != null + ? new CheckedTime { Ok = true, Time = DateTimeOffset.Parse(startTime, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) } + : new CheckedTime { Ok = false, Time = DateTimeOffset.Now }; + } - public CheckedTime EndTime() - { - string endTime = Node.GetAttribute("end-time"); - return endTime != null - ? new CheckedTime { Ok = true, Time = DateTimeOffset.Parse(endTime, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) } - : new CheckedTime { Ok = false, Time = DateTimeOffset.Now }; - } + public CheckedTime EndTime() + { + string endTime = Node.GetAttribute("end-time"); + return endTime != null + ? new CheckedTime { Ok = true, Time = DateTimeOffset.Parse(endTime, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) } + : new CheckedTime { Ok = false, Time = DateTimeOffset.Now }; + } - public struct CheckedTime - { - public bool Ok; - public DateTimeOffset Time; - } + public struct CheckedTime + { + public bool Ok; + public DateTimeOffset Time; + } - private List nUnitAttachments; + private List nUnitAttachments; - public IEnumerable NUnitAttachments + public IEnumerable NUnitAttachments + { + get { - get - { - if (nUnitAttachments != null) - return nUnitAttachments; - nUnitAttachments = new List(); - foreach (XmlNode attachment in Node.SelectNodes("attachments/attachment")) - { - var path = attachment.SelectSingleNode("filePath")?.InnerText ?? string.Empty; - var description = attachment.SelectSingleNode("description")?.InnerText.UnEscapeUnicodeCharacters(); - nUnitAttachments.Add(new NUnitAttachment(path, description)); - } + if (nUnitAttachments != null) return nUnitAttachments; + nUnitAttachments = new List(); + foreach (XmlNode attachment in Node.SelectNodes("attachments/attachment")) + { + var path = attachment.SelectSingleNode("filePath")?.InnerText ?? string.Empty; + var description = attachment.SelectSingleNode("description")?.InnerText.UnEscapeUnicodeCharacters(); + nUnitAttachments.Add(new NUnitAttachment(path, description)); } + return nUnitAttachments; } } +} - public class NUnitAttachment +public class NUnitAttachment +{ + public NUnitAttachment(string path, string description) { - public NUnitAttachment(string path, string description) - { - FilePath = path; - Description = description; - } - - public string FilePath { get; } - - public string Description { get; } + FilePath = path; + Description = description; } - public class NUnitProperty - { - public string Name { get; } - public string Value { get; } + public string FilePath { get; } - public bool IsInternal => Name.StartsWith("_", StringComparison.Ordinal); + public string Description { get; } +} - public NUnitProperty(string name, string value) - { - Name = name; - Value = value; - } +public class NUnitProperty +{ + public string Name { get; } + public string Value { get; } - public NUnitProperty(XElement node) - { - Name = node.Attribute("name").Value; - Value = node.Attribute("value").Value; - } - } + public bool IsInternal => Name.StartsWith("_", StringComparison.Ordinal); - public class NUnitFailure + public NUnitProperty(string name, string value) { - public string Message { get; } - public string Stacktrace { get; } + Name = name; + Value = value; + } - public NUnitFailure(string message, string stacktrace) - { - Message = message; - Stacktrace = stacktrace; - } + public NUnitProperty(XElement node) + { + Name = node.Attribute("name").Value; + Value = node.Attribute("value").Value; } +} +public class NUnitFailure +{ + public string Message { get; } + public string Stacktrace { get; } - [Serializable] - public class NUnitEventWrongTypeException : Exception + public NUnitFailure(string message, string stacktrace) { - // For guidelines regarding the creation of new exception types, see - // https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp - // and - // https://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp + Message = message; + Stacktrace = stacktrace; + } +} - public NUnitEventWrongTypeException() - { - } - public NUnitEventWrongTypeException(string message) : base(message) - { - } +[Serializable] +public class NUnitEventWrongTypeException : Exception +{ + // For guidelines regarding the creation of new exception types, see + // https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp + // and + // https://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp - public NUnitEventWrongTypeException(string message, Exception inner) : base(message, inner) - { - } + public NUnitEventWrongTypeException() + { + } - protected NUnitEventWrongTypeException( - SerializationInfo info, - StreamingContext context) : base(info, context) - { - } + public NUnitEventWrongTypeException(string message) : base(message) + { } -} + + public NUnitEventWrongTypeException(string message, Exception inner) : base(message, inner) + { + } + + protected NUnitEventWrongTypeException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { + } +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventHeader.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventHeader.cs index 4080b55d..335825d2 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventHeader.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventHeader.cs @@ -24,27 +24,27 @@ using System.Xml; using NUnit.VisualStudio.TestAdapter.Dump; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public class NUnitTestEventHeader : INUnitTestEventForXml { - public class NUnitTestEventHeader : INUnitTestEventForXml + public enum EventType + { + NoIdea, + StartTest, // Match: A test was started + TestCase, // Match: A test was finished + TestSuite, // Match: A suite was finished + TestOutput, // Match: Test output, not part of test results, but should be added to it + StartRun, // Currently not used + StartSuite // Currently not used + } + public XmlNode Node { get; } + public string AsString() => Node.AsString(); + public string FullName => Node.GetAttribute("fullname"); + public string Name => Node.GetAttribute("name"); + public EventType Type { get; } + public NUnitTestEventHeader(string sNode) { - public enum EventType - { - NoIdea, - StartTest, // Match: A test was started - TestCase, // Match: A test was finished - TestSuite, // Match: A suite was finished - TestOutput, // Match: Test output, not part of test results, but should be added to it - StartRun, // Currently not used - StartSuite // Currently not used - } - public XmlNode Node { get; } - public string AsString() => Node.AsString(); - public string FullName => Node.GetAttribute("fullname"); - public string Name => Node.GetAttribute("name"); - public EventType Type { get; } - public NUnitTestEventHeader(string sNode) - { Node = XmlHelper.CreateXmlNode(sNode); Type = Node.Name switch { @@ -57,5 +57,4 @@ public NUnitTestEventHeader(string sNode) _ => EventType.NoIdea }; } - } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventStartTest.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventStartTest.cs index f756302f..0a087725 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventStartTest.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventStartTest.cs @@ -1,25 +1,24 @@ using System.Xml; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public interface INUnitTestEventStartTest : INUnitTestEvent { - public interface INUnitTestEventStartTest : INUnitTestEvent - { - } +} - /// - /// Handles the NUnit 'start-test' event. - /// - public class NUnitTestEventStartTest : NUnitTestEvent, INUnitTestEventStartTest - { - public NUnitTestEventStartTest(INUnitTestEventForXml node) : this(node.Node) - { } - public NUnitTestEventStartTest(string testEvent) : this(XmlHelper.CreateXmlNode(testEvent)) - { } +/// +/// Handles the NUnit 'start-test' event. +/// +public class NUnitTestEventStartTest : NUnitTestEvent, INUnitTestEventStartTest +{ + public NUnitTestEventStartTest(INUnitTestEventForXml node) : this(node.Node) + { } + public NUnitTestEventStartTest(string testEvent) : this(XmlHelper.CreateXmlNode(testEvent)) + { } - public NUnitTestEventStartTest(XmlNode node) : base(node) - { - if (node.Name != "start-test") - throw new NUnitEventWrongTypeException($"Expected 'start-test', got {node.Name}"); - } + public NUnitTestEventStartTest(XmlNode node) : base(node) + { + if (node.Name != "start-test") + throw new NUnitEventWrongTypeException($"Expected 'start-test', got {node.Name}"); } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventSuiteFinished.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventSuiteFinished.cs index c1ecb9f2..6f0a900f 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventSuiteFinished.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventSuiteFinished.cs @@ -1,46 +1,45 @@ using System.Xml; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public interface INUnitTestEventSuiteFinished : INUnitTestEvent { - public interface INUnitTestEventSuiteFinished : INUnitTestEvent - { - string ReasonMessage { get; } - bool HasReason { get; } - string FailureMessage { get; } - bool HasFailure { get; } - string StackTrace { get; } - } + string ReasonMessage { get; } + bool HasReason { get; } + string FailureMessage { get; } + bool HasFailure { get; } + string StackTrace { get; } +} - /// - /// Handles the NUnit 'test-suite' event. - /// - public class NUnitTestEventSuiteFinished : NUnitTestEvent, INUnitTestEventSuiteFinished - { - public NUnitTestEventSuiteFinished(INUnitTestEventForXml node) : this(node.Node) - { } - public NUnitTestEventSuiteFinished(string testEvent) : this(XmlHelper.CreateXmlNode(testEvent)) - { } +/// +/// Handles the NUnit 'test-suite' event. +/// +public class NUnitTestEventSuiteFinished : NUnitTestEvent, INUnitTestEventSuiteFinished +{ + public NUnitTestEventSuiteFinished(INUnitTestEventForXml node) : this(node.Node) + { } + public NUnitTestEventSuiteFinished(string testEvent) : this(XmlHelper.CreateXmlNode(testEvent)) + { } - public NUnitTestEventSuiteFinished(XmlNode node) : base(node) + public NUnitTestEventSuiteFinished(XmlNode node) : base(node) + { + if (node.Name != "test-suite") + throw new NUnitEventWrongTypeException($"Expected 'test-suite', got {node.Name}"); + var failureNode = Node.SelectSingleNode("failure"); + if (failureNode != null) { - if (node.Name != "test-suite") - throw new NUnitEventWrongTypeException($"Expected 'test-suite', got {node.Name}"); - var failureNode = Node.SelectSingleNode("failure"); - if (failureNode != null) - { - FailureMessage = failureNode.SelectSingleNode("message")?.InnerText.UnEscapeUnicodeCharacters(); - StackTrace = failureNode.SelectSingleNode("stack-trace")?.InnerText.UnEscapeUnicodeCharacters(); - } - ReasonMessage = Node.SelectSingleNode("reason/message")?.InnerText.UnEscapeUnicodeCharacters(); + FailureMessage = failureNode.SelectSingleNode("message")?.InnerText.UnEscapeUnicodeCharacters(); + StackTrace = failureNode.SelectSingleNode("stack-trace")?.InnerText.UnEscapeUnicodeCharacters(); } + ReasonMessage = Node.SelectSingleNode("reason/message")?.InnerText.UnEscapeUnicodeCharacters(); + } - public string ReasonMessage { get; } + public string ReasonMessage { get; } - public bool HasReason => !string.IsNullOrEmpty(ReasonMessage); - public string FailureMessage { get; } = ""; + public bool HasReason => !string.IsNullOrEmpty(ReasonMessage); + public string FailureMessage { get; } = ""; - public string StackTrace { get; } = ""; + public string StackTrace { get; } = ""; - public bool HasFailure => !string.IsNullOrEmpty(FailureMessage); - } + public bool HasFailure => !string.IsNullOrEmpty(FailureMessage); } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventTestCase.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventTestCase.cs index 0b30f12d..4b079cf5 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventTestCase.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventTestCase.cs @@ -1,47 +1,47 @@ using System.Xml; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine -{ - public interface INUnitTestEventTestCase : INUnitTestEvent - { - NUnitFailure Failure { get; } - string ReasonMessage { get; } - bool HasReason { get; } - - bool HasFailure { get; } +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; - /// - /// Find stacktrace in assertion nodes if not defined. - /// - string StackTrace { get; } +public interface INUnitTestEventTestCase : INUnitTestEvent +{ + NUnitFailure Failure { get; } + string ReasonMessage { get; } + bool HasReason { get; } - /// - /// Complete formatted stacktrace - /// - string FailureStackTrace { get; } - } + bool HasFailure { get; } + /// + /// Find stacktrace in assertion nodes if not defined. + /// + string StackTrace { get; } /// - /// Handles the NUnit 'test-case' event. + /// Complete formatted stacktrace. /// - public class NUnitTestEventTestCase : NUnitTestEvent, INUnitTestEventTestCase + string FailureStackTrace { get; } +} + + +/// +/// Handles the NUnit 'test-case' event. +/// +public class NUnitTestEventTestCase : NUnitTestEvent, INUnitTestEventTestCase +{ + public NUnitTestEventTestCase(INUnitTestEventForXml node) + : this(node.Node) { - public NUnitTestEventTestCase(INUnitTestEventForXml node) - : this(node.Node) - { } - public NUnitTestEventTestCase(string testEvent) - : this(XmlHelper.CreateXmlNode(testEvent)) - { + public NUnitTestEventTestCase(string testEvent) + : this(XmlHelper.CreateXmlNode(testEvent)) + { } - public NUnitFailure Failure { get; } + public NUnitFailure Failure { get; } - public NUnitTestEventTestCase(XmlNode node) - : base(node) - { + public NUnitTestEventTestCase(XmlNode node) + : base(node) + { if (node.Name != "test-case") throw new NUnitEventWrongTypeException($"Expected 'test-case', got {node.Name}"); var failureNode = Node.SelectSingleNode("failure"); @@ -54,21 +54,21 @@ public NUnitTestEventTestCase(XmlNode node) ReasonMessage = Node.SelectSingleNode("reason/message")?.InnerText.UnEscapeUnicodeCharacters(); } - public string ReasonMessage { get; } + public string ReasonMessage { get; } - public bool HasReason => !string.IsNullOrEmpty(ReasonMessage); - public bool HasFailure => Failure != null; + public bool HasReason => !string.IsNullOrEmpty(ReasonMessage); + public bool HasFailure => Failure != null; - public string FailureStackTrace => $"{Failure?.Stacktrace ?? ""}\n{StackTrace}"; + public string FailureStackTrace => $"{Failure?.Stacktrace ?? ""}\n{StackTrace}"; - /// - /// Find stacktrace in assertion nodes if not defined. - /// - public string StackTrace + /// + /// Find stacktrace in assertion nodes if not defined. + /// + public string StackTrace + { + get { - get - { string stackTrace = string.Empty; int i = 1; foreach (XmlNode assertionStacktraceNode in Node.SelectNodes("assertions/assertion/stack-trace")) @@ -79,6 +79,5 @@ public string StackTrace return stackTrace; } - } } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventTestOutput.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventTestOutput.cs index 21a6cc7c..78b9f1bc 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventTestOutput.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitTestEventTestOutput.cs @@ -23,69 +23,65 @@ using System.Xml; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public interface INUnitTestEventTestOutput { - public interface INUnitTestEventTestOutput - { - NUnitTestEventTestOutput.Streams Stream { get; } - string TestId { get; } - string TestName { get; } + NUnitTestEventTestOutput.Streams Stream { get; } + string TestId { get; } + string TestName { get; } - /// - /// Returns the output information. - /// - string Content { get; } + /// + /// Returns the output information. + /// + string Content { get; } - bool IsProgressStream { get; } - bool IsErrorStream { get; } - bool IsNullOrEmptyStream { get; } + bool IsProgressStream { get; } + bool IsErrorStream { get; } + bool IsNullOrEmptyStream { get; } +} + +/// +/// Handles the 'test-output' event. +/// +public class NUnitTestEventTestOutput(XmlNode node) : NUnitTestEvent(node), INUnitTestEventTestOutput +{ + public enum Streams + { + NoIdea, + Error, + Progress } - /// - /// Handles the 'test-output' event. - /// - public class NUnitTestEventTestOutput : NUnitTestEvent, INUnitTestEventTestOutput + public Streams Stream { get; } = node.GetAttribute("stream") switch { - public enum Streams - { - NoIdea, - Error, - Progress - } + "Error" => Streams.Error, + "Progress" => Streams.Progress, + _ => Streams.NoIdea + }; - public Streams Stream { get; } - public string TestId => Node.GetAttribute("testid"); + public string TestId => Node.GetAttribute("testid"); - public string TestName => Node.GetAttribute("testname"); + public string TestName => Node.GetAttribute("testname"); - public NUnitTestEventTestOutput(INUnitTestEventForXml theEvent) : this(theEvent.Node) - { - if (theEvent.Node.Name != "test-output") - throw new NUnitEventWrongTypeException($"Expected 'test-output', got {theEvent.Node.Name}"); - } - public NUnitTestEventTestOutput(XmlNode node) : base(node) - { - Stream = node.GetAttribute("stream") switch - { - "Error" => Streams.Error, - "Progress" => Streams.Progress, - _ => Streams.NoIdea - }; - } + public NUnitTestEventTestOutput(INUnitTestEventForXml theEvent) : this(theEvent.Node) + { + if (theEvent.Node.Name != "test-output") + throw new NUnitEventWrongTypeException($"Expected 'test-output', got {theEvent.Node.Name}"); + } - public bool IsProgressStream => Stream == Streams.Progress; - public bool IsErrorStream => Stream == Streams.Error; + public bool IsProgressStream => Stream == Streams.Progress; + public bool IsErrorStream => Stream == Streams.Error; - public bool IsNullOrEmptyStream => Stream == Streams.NoIdea; + public bool IsNullOrEmptyStream => Stream == Streams.NoIdea; - /// - /// Returns the output information. - /// - public string Content => Node.InnerText; + /// + /// Returns the output information. + /// + public string Content => Node.InnerText; - // Notes: - // The input doesnt have any id, but used testid instead. - // Properties FullName and Name is not in use - } + // Notes: + // The input doesnt have any id, but used testid instead. + // Properties FullName and Name is not in use } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEngine/NUnitTestNode.cs b/src/NUnitTestAdapter/NUnitEngine/NUnitTestNode.cs index 9f0e07f2..a2cd0bc1 100644 --- a/src/NUnitTestAdapter/NUnitEngine/NUnitTestNode.cs +++ b/src/NUnitTestAdapter/NUnitEngine/NUnitTestNode.cs @@ -1,40 +1,39 @@ using System.Collections.Generic; using System.Xml; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +public interface INUnitTestNode { - public interface INUnitTestNode - { - string Id { get; } - string FullName { get; } - string Name { get; } - IEnumerable Properties { get; } - string Seed { get; } - } + string Id { get; } + string FullName { get; } + string Name { get; } + IEnumerable Properties { get; } + string Seed { get; } +} - public abstract class NUnitTestNode : INUnitTestNode - { - protected XmlNode Node { get; set; } // Need to be protected, but still the outputnodes are XmlNode - public virtual string Id => Node.GetAttribute("id"); - public string FullName => Node.GetAttribute("fullname"); - public string Name => Node.GetAttribute("name"); +public abstract class NUnitTestNode : INUnitTestNode +{ + protected XmlNode Node { get; set; } // Need to be protected, but still the outputnodes are XmlNode + public virtual string Id => Node.GetAttribute("id"); + public string FullName => Node.GetAttribute("fullname"); + public string Name => Node.GetAttribute("name"); - public bool IsNull => Node == null; + public bool IsNull => Node == null; - private readonly List properties = new (); - public IEnumerable Properties => properties; - public string Seed => Node.GetAttribute("seed"); + private readonly List properties = new (); + public IEnumerable Properties => properties; + public string Seed => Node.GetAttribute("seed"); - protected NUnitTestNode(XmlNode node) + protected NUnitTestNode(XmlNode node) + { + Node = node; + var propertyNodes = Node.SelectNodes("properties/property"); + if (propertyNodes != null) { - Node = node; - var propertyNodes = Node.SelectNodes("properties/property"); - if (propertyNodes != null) + foreach (XmlNode prop in propertyNodes) { - foreach (XmlNode prop in propertyNodes) - { - properties.Add(new NUnitProperty(prop.GetAttribute("name"), prop.GetAttribute("value"))); - } + properties.Add(new NUnitProperty(prop.GetAttribute("name"), prop.GetAttribute("value"))); } } } diff --git a/src/NUnitTestAdapter/NUnitEngine/UnicodeEscapeHelper.cs b/src/NUnitTestAdapter/NUnitEngine/UnicodeEscapeHelper.cs index 95a17cc4..5949e930 100644 --- a/src/NUnitTestAdapter/NUnitEngine/UnicodeEscapeHelper.cs +++ b/src/NUnitTestAdapter/NUnitEngine/UnicodeEscapeHelper.cs @@ -2,12 +2,12 @@ using System.Globalization; using System.Text; -namespace NUnit.VisualStudio.TestAdapter.NUnitEngine +namespace NUnit.VisualStudio.TestAdapter.NUnitEngine; + +internal static class UnicodeEscapeHelper { - internal static class UnicodeEscapeHelper + public static string UnEscapeUnicodeCharacters(this string text) { - public static string UnEscapeUnicodeCharacters(this string text) - { if (text == null) return null; @@ -34,8 +34,8 @@ public static string UnEscapeUnicodeCharacters(this string text) return stringBuilder.ToString(); } - private static bool TryUnEscapeOneCharacter(string text, int position, out char escapedChar, out int extraCharacterRead) - { + private static bool TryUnEscapeOneCharacter(string text, int position, out char escapedChar, out int extraCharacterRead) + { const string unicodeEscapeSample = "u0000"; extraCharacterRead = 0; @@ -52,5 +52,4 @@ private static bool TryUnEscapeOneCharacter(string text, int position, out char return true; } - } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitEventListener.cs b/src/NUnitTestAdapter/NUnitEventListener.cs index 5f729946..0e07de39 100644 --- a/src/NUnitTestAdapter/NUnitEventListener.cs +++ b/src/NUnitTestAdapter/NUnitEventListener.cs @@ -35,218 +35,217 @@ using NUnit.VisualStudio.TestAdapter.Internal; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter -{ - /// - /// NUnitEventListener implements the EventListener interface and - /// translates each event into a message for the VS test platform. - /// - public class NUnitEventListener(ITestConverterCommon testConverter, INUnit3TestExecutor executor) - : +namespace NUnit.VisualStudio.TestAdapter; + +/// +/// NUnitEventListener implements the EventListener interface and +/// translates each event into a message for the VS test platform. +/// +public class NUnitEventListener(ITestConverterCommon testConverter, INUnit3TestExecutor executor) + : #if NET462 - MarshalByRefObject, + MarshalByRefObject, #endif - ITestEventListener, IDisposable // Public for testing - { - private static readonly ICollection EmptyNodes = new List(); - private ITestExecutionRecorder Recorder { get; } = executor.FrameworkHandle; - private ITestConverterCommon TestConverter { get; } = testConverter; - private IAdapterSettings Settings { get; } = executor.Settings; - private Dictionary> OutputNodes { get; } = []; + ITestEventListener, IDisposable // Public for testing +{ + private static readonly ICollection EmptyNodes = new List(); + private ITestExecutionRecorder Recorder { get; } = executor.FrameworkHandle; + private ITestConverterCommon TestConverter { get; } = testConverter; + private IAdapterSettings Settings { get; } = executor.Settings; + private Dictionary> OutputNodes { get; } = []; #if NET462 - public override object InitializeLifetimeService() - { - // Give the listener an infinite lease lifetime by returning null - // https://msdn.microsoft.com/en-us/magazine/cc300474.aspx#edupdate - // This also means RemotingServices.Disconnect() must be called to prevent memory leaks - // https://nbevans.wordpress.com/2011/04/17/memory-leaks-with-an-infinite-lifetime-instance-of-marshalbyrefobject/ - return null; - } + public override object InitializeLifetimeService() + { + // Give the listener an infinite lease lifetime by returning null + // https://msdn.microsoft.com/en-us/magazine/cc300474.aspx#edupdate + // This also means RemotingServices.Disconnect() must be called to prevent memory leaks + // https://nbevans.wordpress.com/2011/04/17/memory-leaks-with-an-infinite-lifetime-instance-of-marshalbyrefobject/ + return null; + } #endif - private INUnit3TestExecutor Executor { get; } = executor; + private INUnit3TestExecutor Executor { get; } = executor; - #region ITestEventListener + #region ITestEventListener - public void OnTestEvent(string report) + public void OnTestEvent(string report) + { + var node = new NUnitTestEventHeader(report); + dumpXml?.AddTestEvent(node.AsString()); + try { - var node = new NUnitTestEventHeader(report); - dumpXml?.AddTestEvent(node.AsString()); - try - { - switch (node.Type) - { - case NUnitTestEventHeader.EventType.StartTest: - TestStarted(new NUnitTestEventStartTest(node)); - break; - - case NUnitTestEventHeader.EventType.TestCase: - TestFinished(new NUnitTestEventTestCase(node)); - break; - - case NUnitTestEventHeader.EventType.TestSuite: - SuiteFinished(new NUnitTestEventSuiteFinished(node)); - break; - - case NUnitTestEventHeader.EventType.TestOutput: - TestOutput(new NUnitTestEventTestOutput(node)); - break; - } - } - catch (Exception ex) + switch (node.Type) { - Recorder.SendMessage(TestMessageLevel.Warning, $"Error processing {node.Name} event for {node.FullName}"); - Recorder.SendMessage(TestMessageLevel.Warning, ex.ToString()); - } - } + case NUnitTestEventHeader.EventType.StartTest: + TestStarted(new NUnitTestEventStartTest(node)); + break; - #endregion + case NUnitTestEventHeader.EventType.TestCase: + TestFinished(new NUnitTestEventTestCase(node)); + break; - #region IDisposable - private bool disposed; + case NUnitTestEventHeader.EventType.TestSuite: + SuiteFinished(new NUnitTestEventSuiteFinished(node)); + break; - public void Dispose() + case NUnitTestEventHeader.EventType.TestOutput: + TestOutput(new NUnitTestEventTestOutput(node)); + break; + } + } + catch (Exception ex) { - Dispose(true); - GC.SuppressFinalize(this); + Recorder.SendMessage(TestMessageLevel.Warning, $"Error processing {node.Name} event for {node.FullName}"); + Recorder.SendMessage(TestMessageLevel.Warning, ex.ToString()); } + } + + #endregion + + #region IDisposable + private bool disposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected virtual void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) + { + if (!disposed) { - if (!disposed) + if (disposing) { - if (disposing) - { #if NET462 - RemotingServices.Disconnect(this); + RemotingServices.Disconnect(this); #endif - } } - disposed = true; } + disposed = true; + } - ~NUnitEventListener() - { - Dispose(false); - } - #endregion + ~NUnitEventListener() + { + Dispose(false); + } + #endregion - public void TestStarted(INUnitTestEventStartTest testNode) - { - var ourCase = TestConverter.GetCachedTestCase(testNode.Id); + public void TestStarted(INUnitTestEventStartTest testNode) + { + var ourCase = TestConverter.GetCachedTestCase(testNode.Id); + + // Simply ignore any TestCase not found in the cache + if (ourCase != null) + Recorder.RecordStart(ourCase); + } - // Simply ignore any TestCase not found in the cache - if (ourCase != null) - Recorder.RecordStart(ourCase); + /// + /// Collects up all text output messages in the current test, and outputs them here. + /// Note: Error and Progress are handled in TestOutput. + /// + /// resultNode. + public void TestFinished(INUnitTestEventTestCase resultNode) + { + var testId = resultNode.Id; + if (OutputNodes.TryGetValue(testId, out var outputNodes)) + { + OutputNodes.Remove(testId); } - /// - /// Collects up all text output messages in the current test, and outputs them here. - /// Note: Error and Progress are handled in TestOutput. - /// - /// resultNode. - public void TestFinished(INUnitTestEventTestCase resultNode) + var result = TestConverter.GetVsTestResults(resultNode, outputNodes ?? EmptyNodes); + if (Settings.ConsoleOut >= 1) { - var testId = resultNode.Id; - if (OutputNodes.TryGetValue(testId, out var outputNodes)) + if (!result.ConsoleOutput.IsNullOrWhiteSpace() && result.ConsoleOutput != Nl) { - OutputNodes.Remove(testId); + string msg = result.ConsoleOutput; + if (Settings.UseTestNameInConsoleOutput) + msg = $"{resultNode.Name}: {msg}"; + var messageLevel = Settings.ConsoleOut == 1 + ? TestMessageLevel.Informational + : TestMessageLevel.Warning; + Recorder.SendMessage(messageLevel, msg); } + if (!resultNode.ReasonMessage.IsNullOrWhiteSpace()) + { + Recorder.SendMessage(TestMessageLevel.Informational, $"{resultNode.Name}: {resultNode.ReasonMessage}"); + } + } - var result = TestConverter.GetVsTestResults(resultNode, outputNodes ?? EmptyNodes); - if (Settings.ConsoleOut >= 1) + if (result.TestCaseResult != null) + { + Recorder.RecordEnd(result.TestCaseResult.TestCase, result.TestCaseResult.Outcome); + foreach (var vsResult in result.TestResults) { - if (!result.ConsoleOutput.IsNullOrWhiteSpace() && result.ConsoleOutput != Nl) - { - string msg = result.ConsoleOutput; - if (Settings.UseTestNameInConsoleOutput) - msg = $"{resultNode.Name}: {msg}"; - var messageLevel = Settings.ConsoleOut == 1 - ? TestMessageLevel.Informational - : TestMessageLevel.Warning; - Recorder.SendMessage(messageLevel, msg); - } - if (!resultNode.ReasonMessage.IsNullOrWhiteSpace()) - { - Recorder.SendMessage(TestMessageLevel.Informational, $"{resultNode.Name}: {resultNode.ReasonMessage}"); - } + Recorder.RecordResult(vsResult); } - if (result.TestCaseResult != null) + if (result.TestCaseResult.Outcome == TestOutcome.Failed && Settings.StopOnError) { - Recorder.RecordEnd(result.TestCaseResult.TestCase, result.TestCaseResult.Outcome); - foreach (var vsResult in result.TestResults) - { - Recorder.RecordResult(vsResult); - } - - if (result.TestCaseResult.Outcome == TestOutcome.Failed && Settings.StopOnError) - { - Executor.StopRun(); - } + Executor.StopRun(); } } + } - public void SuiteFinished(INUnitTestEventSuiteFinished resultNode) + public void SuiteFinished(INUnitTestEventSuiteFinished resultNode) + { + if (!resultNode.IsFailed) + return; + var site = resultNode.Site(); + if (site != NUnitTestEvent.SiteType.Setup && site != NUnitTestEvent.SiteType.TearDown) + return; + Recorder.SendMessage(TestMessageLevel.Warning, $"{site} failed for test fixture {resultNode.FullName}"); + + if (resultNode.HasFailure) { - if (!resultNode.IsFailed) - return; - var site = resultNode.Site(); - if (site != NUnitTestEvent.SiteType.Setup && site != NUnitTestEvent.SiteType.TearDown) - return; - Recorder.SendMessage(TestMessageLevel.Warning, $"{site} failed for test fixture {resultNode.FullName}"); - - if (resultNode.HasFailure) - { - string msg = resultNode.FailureMessage; - var stackNode = resultNode.StackTrace; - if (!string.IsNullOrEmpty(stackNode) && Settings.IncludeStackTraceForSuites) - msg += $"\nStackTrace: {stackNode}"; - Recorder.SendMessage(TestMessageLevel.Warning, msg); - } + string msg = resultNode.FailureMessage; + var stackNode = resultNode.StackTrace; + if (!string.IsNullOrEmpty(stackNode) && Settings.IncludeStackTraceForSuites) + msg += $"\nStackTrace: {stackNode}"; + Recorder.SendMessage(TestMessageLevel.Warning, msg); } + } - private static readonly string Nl = Environment.NewLine; - private static readonly int NlLength = Nl.Length; - private readonly IDumpXml dumpXml = executor.Dump; + private static readonly string Nl = Environment.NewLine; + private static readonly int NlLength = Nl.Length; + private readonly IDumpXml dumpXml = executor.Dump; - /// - /// Error stream and Progress stream are both sent here. - /// - /// outputNodeEvent. - public void TestOutput(INUnitTestEventTestOutput outputNodeEvent) - { - if (Settings.ConsoleOut == 0) - return; - string text = outputNodeEvent.Content; + /// + /// Error stream and Progress stream are both sent here. + /// + /// outputNodeEvent. + public void TestOutput(INUnitTestEventTestOutput outputNodeEvent) + { + if (Settings.ConsoleOut == 0) + return; + string text = outputNodeEvent.Content; - // Remove final newline since logger will add one - if (text.EndsWith(Nl)) - text = text.Substring(0, text.Length - NlLength); + // Remove final newline since logger will add one + if (text.EndsWith(Nl)) + text = text.Substring(0, text.Length - NlLength); - if (text.IsNullOrWhiteSpace()) - { - return; - } + if (text.IsNullOrWhiteSpace()) + { + return; + } - string testId = outputNodeEvent.TestId; - if (!string.IsNullOrEmpty(testId)) + string testId = outputNodeEvent.TestId; + if (!string.IsNullOrEmpty(testId)) + { + if (!OutputNodes.TryGetValue(testId, out var outputNodes)) { - if (!OutputNodes.TryGetValue(testId, out var outputNodes)) - { - outputNodes = new List(); - OutputNodes.Add(testId, outputNodes); - } - - outputNodes.Add(outputNodeEvent); + outputNodes = new List(); + OutputNodes.Add(testId, outputNodes); } - var testMessageLevel = outputNodeEvent.IsErrorStream - ? TestMessageLevel.Warning - : TestMessageLevel.Informational; - - Recorder.SendMessage(testMessageLevel, text); + outputNodes.Add(outputNodeEvent); } + + var testMessageLevel = outputNodeEvent.IsErrorStream + ? TestMessageLevel.Warning + : TestMessageLevel.Informational; + + Recorder.SendMessage(testMessageLevel, text); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitTestAdapter.cs b/src/NUnitTestAdapter/NUnitTestAdapter.cs index 4446d108..14666e7a 100644 --- a/src/NUnitTestAdapter/NUnitTestAdapter.cs +++ b/src/NUnitTestAdapter/NUnitTestAdapter.cs @@ -39,294 +39,293 @@ using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +/// +/// NUnitTestAdapter is the common base for the +/// NUnit discoverer and executor classes. +/// +public abstract class NUnitTestAdapter { + #region Constants + /// - /// NUnitTestAdapter is the common base for the - /// NUnit discoverer and executor classes. + /// The Uri used to identify the NUnitExecutor. /// - public abstract class NUnitTestAdapter - { - #region Constants + public const string ExecutorUri = "executor://NUnit3TestExecutor"; - /// - /// The Uri used to identify the NUnitExecutor. - /// - public const string ExecutorUri = "executor://NUnit3TestExecutor"; + public const string SettingsName = "NUnitAdapterSettings"; - public const string SettingsName = "NUnitAdapterSettings"; + #endregion - #endregion + #region Constructor - #region Constructor - - protected NUnitTestAdapter() - { + protected NUnitTestAdapter() + { #if !NET462 - AdapterVersion = typeof(NUnitTestAdapter).GetTypeInfo().Assembly.GetName().Version.ToString(); + AdapterVersion = typeof(NUnitTestAdapter).GetTypeInfo().Assembly.GetName().Version.ToString(); #else - AdapterVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + AdapterVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); #endif - NUnitEngineAdapter = new NUnitEngineAdapter(); - } + NUnitEngineAdapter = new NUnitEngineAdapter(); + } - #endregion + #endregion - #region Properties + #region Properties - public IAdapterSettings Settings { get; private set; } + public IAdapterSettings Settings { get; private set; } - // The adapter version - protected string AdapterVersion { get; set; } + // The adapter version + protected string AdapterVersion { get; set; } - private NUnitEngineAdapter nUnitEngineAdapter; + private NUnitEngineAdapter nUnitEngineAdapter; - public NUnitEngineAdapter NUnitEngineAdapter - { - get => nUnitEngineAdapter ??= new NUnitEngineAdapter(); - private set => nUnitEngineAdapter = value; - } + public NUnitEngineAdapter NUnitEngineAdapter + { + get => nUnitEngineAdapter ??= new NUnitEngineAdapter(); + private set => nUnitEngineAdapter = value; + } - // Our logger used to display messages - protected TestLogger TestLog { get; private set; } + // Our logger used to display messages + protected TestLogger TestLog { get; private set; } - protected string WorkDir { get; private set; } + protected string WorkDir { get; private set; } - private static string entryExeName; + private static string entryExeName; - private static string whoIsCallingUsEntry; + private static string whoIsCallingUsEntry; - public static string WhoIsCallingUsEntry + public static string WhoIsCallingUsEntry + { + get { - get - { - if (whoIsCallingUsEntry != null) - return whoIsCallingUsEntry; - if (entryExeName == null) - { - var entryAssembly = Assembly.GetEntryAssembly(); - if (entryAssembly != null) - entryExeName = entryAssembly.Location; - } - whoIsCallingUsEntry = entryExeName; + if (whoIsCallingUsEntry != null) return whoIsCallingUsEntry; + if (entryExeName == null) + { + var entryAssembly = Assembly.GetEntryAssembly(); + if (entryAssembly != null) + entryExeName = entryAssembly.Location; } + whoIsCallingUsEntry = entryExeName; + return whoIsCallingUsEntry; } + } - public static bool IsRunningUnderIde + public static bool IsRunningUnderIde + { + get { - get - { - var exe = WhoIsCallingUsEntry; - return exe != null && ( - exe.Contains("vstest.executionengine") || - exe.Contains("vstest.discoveryengine") || - exe.Contains("TE.ProcessHost")); - } + var exe = WhoIsCallingUsEntry; + return exe != null && ( + exe.Contains("vstest.executionengine") || + exe.Contains("vstest.discoveryengine") || + exe.Contains("TE.ProcessHost")); } + } - public List ForbiddenFolders { get; private set; } + public List ForbiddenFolders { get; private set; } - #endregion + #endregion - #region Protected Helper Methods + #region Protected Helper Methods - // The Adapter is constructed using the default constructor. - // We don't have any info to initialize it until one of the - // ITestDiscovery or ITestExecutor methods is called. Each - // Discover or Execute method must call this method. - protected void Initialize(IDiscoveryContext context, IMessageLogger messageLogger) + // The Adapter is constructed using the default constructor. + // We don't have any info to initialize it until one of the + // ITestDiscovery or ITestExecutor methods is called. Each + // Discover or Execute method must call this method. + protected void Initialize(IDiscoveryContext context, IMessageLogger messageLogger) + { + NUnitEngineAdapter.Initialize(); + TestLog = new TestLogger(messageLogger); + Settings = new AdapterSettings(TestLog); + NUnitEngineAdapter.InitializeSettingsAndLogging(Settings, TestLog); + TestLog.InitSettings(Settings); + try { - NUnitEngineAdapter.Initialize(); - TestLog = new TestLogger(messageLogger); - Settings = new AdapterSettings(TestLog); - NUnitEngineAdapter.InitializeSettingsAndLogging(Settings, TestLog); - TestLog.InitSettings(Settings); - try - { - Settings.Load(context, TestLog); - TestLog.Verbosity = Settings.Verbosity; - InitializeForbiddenFolders(); - SetCurrentWorkingDirectory(); - } - catch (Exception e) - { - TestLog.Warning("Error initializing RunSettings. Default settings will be used"); - TestLog.Warning(e.ToString()); - } - finally - { - TestLog.DebugRunfrom(); - } + Settings.Load(context, TestLog); + TestLog.Verbosity = Settings.Verbosity; + InitializeForbiddenFolders(); + SetCurrentWorkingDirectory(); } - - public void InitializeForbiddenFolders() + catch (Exception e) { - ForbiddenFolders = new[] - { - Environment.GetEnvironmentVariable("ProgramW6432"), - Environment.GetEnvironmentVariable("ProgramFiles(x86)"), - Environment.GetEnvironmentVariable("windir"), - }.Where(o => !string.IsNullOrEmpty(o)).Select(o => o.ToLower() + @"\").ToList(); + TestLog.Warning("Error initializing RunSettings. Default settings will be used"); + TestLog.Warning(e.ToString()); } - - private void SetCurrentWorkingDirectory() + finally { - string dir = Directory.GetCurrentDirectory(); - bool foundForbiddenFolder = CheckDirectory(dir); - if (foundForbiddenFolder) - Directory.SetCurrentDirectory(Path.GetTempPath()); + TestLog.DebugRunfrom(); } + } + + public void InitializeForbiddenFolders() + { + ForbiddenFolders = new[] + { + Environment.GetEnvironmentVariable("ProgramW6432"), + Environment.GetEnvironmentVariable("ProgramFiles(x86)"), + Environment.GetEnvironmentVariable("windir"), + }.Where(o => !string.IsNullOrEmpty(o)).Select(o => o.ToLower() + @"\").ToList(); + } + + private void SetCurrentWorkingDirectory() + { + string dir = Directory.GetCurrentDirectory(); + bool foundForbiddenFolder = CheckDirectory(dir); + if (foundForbiddenFolder) + Directory.SetCurrentDirectory(Path.GetTempPath()); + } - /// - /// If a directory matches one of the forbidden folders, then we should reroute, so we return true in that case. - /// - public bool CheckDirectory(string dir) + /// + /// If a directory matches one of the forbidden folders, then we should reroute, so we return true in that case. + /// + public bool CheckDirectory(string dir) + { + string checkDir = (dir.EndsWith("\\") ? dir : dir + "\\"); + return ForbiddenFolders.Any(o => checkDir.StartsWith(o, StringComparison.OrdinalIgnoreCase)); + } + + protected TestPackage CreateTestPackage(string assemblyName, IGrouping testCases) + { + var package = new TestPackage(assemblyName); + + if (Settings.ShadowCopyFiles) { - string checkDir = (dir.EndsWith("\\") ? dir : dir + "\\"); - return ForbiddenFolders.Any(o => checkDir.StartsWith(o, StringComparison.OrdinalIgnoreCase)); + package.Settings[PackageSettings.ShadowCopyFiles] = true; + TestLog.Debug(" Setting ShadowCopyFiles to true"); } - protected TestPackage CreateTestPackage(string assemblyName, IGrouping testCases) + if (Debugger.IsAttached && !Settings.AllowParallelWithDebugger) { - var package = new TestPackage(assemblyName); - - if (Settings.ShadowCopyFiles) - { - package.Settings[PackageSettings.ShadowCopyFiles] = true; - TestLog.Debug(" Setting ShadowCopyFiles to true"); - } + package.Settings[PackageSettings.NumberOfTestWorkers] = 0; + TestLog.Debug(" Setting NumberOfTestWorkers to zero for Debugging"); + } + else + { + int workers = Settings.NumberOfTestWorkers; + if (workers >= 0) + package.Settings[PackageSettings.NumberOfTestWorkers] = workers; + } - if (Debugger.IsAttached && !Settings.AllowParallelWithDebugger) - { - package.Settings[PackageSettings.NumberOfTestWorkers] = 0; - TestLog.Debug(" Setting NumberOfTestWorkers to zero for Debugging"); - } - else - { - int workers = Settings.NumberOfTestWorkers; - if (workers >= 0) - package.Settings[PackageSettings.NumberOfTestWorkers] = workers; - } + if (Settings.PreFilter && testCases != null) + { + var prefilters = new List(); - if (Settings.PreFilter && testCases != null) + foreach (var testCase in testCases) { - var prefilters = new List(); - - foreach (var testCase in testCases) - { - int end = testCase.FullyQualifiedName.IndexOfAny(new[] { '(', '<' }); - prefilters.Add( - end > 0 ? testCase.FullyQualifiedName.Substring(0, end) : testCase.FullyQualifiedName); - } - - package.Settings[PackageSettings.LOAD] = prefilters; + int end = testCase.FullyQualifiedName.IndexOfAny(new[] { '(', '<' }); + prefilters.Add( + end > 0 ? testCase.FullyQualifiedName.Substring(0, end) : testCase.FullyQualifiedName); } - package.Settings[PackageSettings.SynchronousEvents] = Settings.SynchronousEvents; + package.Settings[PackageSettings.LOAD] = prefilters; + } - int timeout = Settings.DefaultTimeout; - if (timeout > 0) - package.Settings[PackageSettings.DefaultTimeout] = timeout; + package.Settings[PackageSettings.SynchronousEvents] = Settings.SynchronousEvents; - package.Settings[PackageSettings.InternalTraceLevel] = Settings.InternalTraceLevelEnum.ToString(); + int timeout = Settings.DefaultTimeout; + if (timeout > 0) + package.Settings[PackageSettings.DefaultTimeout] = timeout; - if (Settings.BasePath != null) - package.Settings[PackageSettings.BasePath] = Settings.BasePath; + package.Settings[PackageSettings.InternalTraceLevel] = Settings.InternalTraceLevelEnum.ToString(); - if (Settings.PrivateBinPath != null) - package.Settings[PackageSettings.PrivateBinPath] = Settings.PrivateBinPath; + if (Settings.BasePath != null) + package.Settings[PackageSettings.BasePath] = Settings.BasePath; - if (Settings.RandomSeed.HasValue) - package.Settings[PackageSettings.RandomSeed] = Settings.RandomSeed; + if (Settings.PrivateBinPath != null) + package.Settings[PackageSettings.PrivateBinPath] = Settings.PrivateBinPath; - if (Settings.TestProperties.Count > 0) - SetTestParameters(package.Settings, Settings.TestProperties); + if (Settings.RandomSeed.HasValue) + package.Settings[PackageSettings.RandomSeed] = Settings.RandomSeed; - if (Settings.StopOnError) - package.Settings[PackageSettings.StopOnError] = true; + if (Settings.TestProperties.Count > 0) + SetTestParameters(package.Settings, Settings.TestProperties); - if (Settings.SkipNonTestAssemblies) - package.Settings[PackageSettings.SkipNonTestAssemblies] = true; + if (Settings.StopOnError) + package.Settings[PackageSettings.StopOnError] = true; - // Always run one assembly at a time in process in its own domain - package.Settings[PackageSettings.ProcessModel] = "InProcess"; + if (Settings.SkipNonTestAssemblies) + package.Settings[PackageSettings.SkipNonTestAssemblies] = true; - package.Settings[PackageSettings.DomainUsage] = Settings.DomainUsage ?? "Single"; + // Always run one assembly at a time in process in its own domain + package.Settings[PackageSettings.ProcessModel] = "InProcess"; - if (Settings.DefaultTestNamePattern != null) - { - package.Settings[PackageSettings.DefaultTestNamePattern] = Settings.DefaultTestNamePattern; - } - else - { - // Force truncation of string arguments to test cases - package.Settings[PackageSettings.DefaultTestNamePattern] = "{m}{a}"; - } + package.Settings[PackageSettings.DomainUsage] = Settings.DomainUsage ?? "Single"; - return SetWorkDir(assemblyName, package); + if (Settings.DefaultTestNamePattern != null) + { + package.Settings[PackageSettings.DefaultTestNamePattern] = Settings.DefaultTestNamePattern; } - - private TestPackage SetWorkDir(string assemblyName, TestPackage package) + else { - // Set the work directory to the assembly location unless a setting is provided - string workDir = Settings.WorkDirectory; - if (workDir == null) - workDir = Path.GetDirectoryName(assemblyName); - else if (!Path.IsPathRooted(workDir)) - workDir = Path.Combine(Path.GetDirectoryName(assemblyName), workDir); - if (!Directory.Exists(workDir)) - Directory.CreateDirectory(workDir); - package.Settings[PackageSettings.WorkDirectory] = workDir; - WorkDir = workDir; - Directory.SetCurrentDirectory(workDir); - TestLog.Debug($"Workdir set to: {WorkDir}"); - return package; + // Force truncation of string arguments to test cases + package.Settings[PackageSettings.DefaultTestNamePattern] = "{m}{a}"; } - /// - /// Sets test parameters, handling backwards compatibility. - /// - private static void SetTestParameters( - IDictionary runSettings, - IDictionary testParameters) - { - runSettings[PackageSettings.TestParametersDictionary] = testParameters; + return SetWorkDir(assemblyName, package); + } - if (testParameters.Count == 0) - return; - // Kept for backwards compatibility with old frameworks. - // Reserializes the way old frameworks understand, even if the parsing above is changed. - // This reserialization cannot be changed without breaking compatibility with old frameworks. + private TestPackage SetWorkDir(string assemblyName, TestPackage package) + { + // Set the work directory to the assembly location unless a setting is provided + string workDir = Settings.WorkDirectory; + if (workDir == null) + workDir = Path.GetDirectoryName(assemblyName); + else if (!Path.IsPathRooted(workDir)) + workDir = Path.Combine(Path.GetDirectoryName(assemblyName), workDir); + if (!Directory.Exists(workDir)) + Directory.CreateDirectory(workDir); + package.Settings[PackageSettings.WorkDirectory] = workDir; + WorkDir = workDir; + Directory.SetCurrentDirectory(workDir); + TestLog.Debug($"Workdir set to: {WorkDir}"); + return package; + } - var oldFrameworkSerializedParameters = new StringBuilder(); - foreach (var parameter in testParameters) - oldFrameworkSerializedParameters.Append(parameter.Key).Append('=').Append(parameter.Value).Append(';'); + /// + /// Sets test parameters, handling backwards compatibility. + /// + private static void SetTestParameters( + IDictionary runSettings, + IDictionary testParameters) + { + runSettings[PackageSettings.TestParametersDictionary] = testParameters; - runSettings[PackageSettings.TestParameters] = - oldFrameworkSerializedParameters.ToString(0, oldFrameworkSerializedParameters.Length - 1); - } + if (testParameters.Count == 0) + return; + // Kept for backwards compatibility with old frameworks. + // Reserializes the way old frameworks understand, even if the parsing above is changed. + // This reserialization cannot be changed without breaking compatibility with old frameworks. - /// - /// Ensure any channels registered by other adapters are unregistered. - /// - protected static void CleanUpRegisteredChannels() - { + var oldFrameworkSerializedParameters = new StringBuilder(); + foreach (var parameter in testParameters) + oldFrameworkSerializedParameters.Append(parameter.Key).Append('=').Append(parameter.Value).Append(';'); + + runSettings[PackageSettings.TestParameters] = + oldFrameworkSerializedParameters.ToString(0, oldFrameworkSerializedParameters.Length - 1); + } + + /// + /// Ensure any channels registered by other adapters are unregistered. + /// + protected static void CleanUpRegisteredChannels() + { #if NET462 - foreach (var chan in ChannelServices.RegisteredChannels) - ChannelServices.UnregisterChannel(chan); + foreach (var chan in ChannelServices.RegisteredChannels) + ChannelServices.UnregisterChannel(chan); #endif - } - - protected void Unload() - { - if (NUnitEngineAdapter == null) - return; - NUnitEngineAdapter.Dispose(); - NUnitEngineAdapter = null; - } + } - #endregion + protected void Unload() + { + if (NUnitEngineAdapter == null) + return; + NUnitEngineAdapter.Dispose(); + NUnitEngineAdapter = null; } + + #endregion } \ No newline at end of file diff --git a/src/NUnitTestAdapter/NUnitTestFilterBuilder.cs b/src/NUnitTestAdapter/NUnitTestFilterBuilder.cs index 57c0c8d1..0cca18e5 100644 --- a/src/NUnitTestAdapter/NUnitTestFilterBuilder.cs +++ b/src/NUnitTestAdapter/NUnitTestFilterBuilder.cs @@ -28,86 +28,85 @@ using NUnit.VisualStudio.TestAdapter.NUnitEngine; using NUnit.VisualStudio.TestAdapter.TestFilterConverter; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public class NUnitTestFilterBuilder(ITestFilterService filterService, IAdapterSettings settings) { - public class NUnitTestFilterBuilder(ITestFilterService filterService, IAdapterSettings settings) + private readonly ITestFilterService _filterService = filterService ?? throw new NUnitEngineException("TestFilterService is not available. Engine in use is incorrect version."); + + // ReSharper disable once StringLiteralTypo + public static readonly TestFilter NoTestsFound = new (""); + + public TestFilter ConvertTfsFilterToNUnitFilter(IVsTestFilter vsFilter, IList loadedTestCases) { - private readonly ITestFilterService _filterService = filterService ?? throw new NUnitEngineException("TestFilterService is not available. Engine in use is incorrect version."); + var filteredTestCases = vsFilter.CheckFilter(loadedTestCases); + var testCases = filteredTestCases as TestCase[] ?? filteredTestCases.ToArray(); + // TestLog.Info(string.Format("TFS Filter detected: LoadedTestCases {0}, Filtered Test Cases {1}", loadedTestCases.Count, testCases.Count())); + return testCases.Any() ? FilterByList(testCases) : NoTestsFound; + } - // ReSharper disable once StringLiteralTypo - public static readonly TestFilter NoTestsFound = new (""); - public TestFilter ConvertTfsFilterToNUnitFilter(IVsTestFilter vsFilter, IList loadedTestCases) - { - var filteredTestCases = vsFilter.CheckFilter(loadedTestCases); - var testCases = filteredTestCases as TestCase[] ?? filteredTestCases.ToArray(); - // TestLog.Info(string.Format("TFS Filter detected: LoadedTestCases {0}, Filtered Test Cases {1}", loadedTestCases.Count, testCases.Count())); - return testCases.Any() ? FilterByList(testCases) : NoTestsFound; - } + public TestFilter ConvertVsTestFilterToNUnitFilter(IVsTestFilter vsFilter, IDiscoveryConverter discovery) + { + if (settings.DiscoveryMethod == DiscoveryMethod.Legacy) + return ConvertTfsFilterToNUnitFilter(vsFilter, discovery.LoadedTestCases); + if (!settings.UseNUnitFilter) + return ConvertTfsFilterToNUnitFilter(vsFilter, discovery); + var result = ConvertVsTestFilterToNUnitFilter(vsFilter); + return result ?? ConvertTfsFilterToNUnitFilter(vsFilter, discovery); + } + /// + /// Used when running from command line, mode Non-Ide, e.g. 'dotnet test --filter xxxxx'. Reads the TfsTestCaseFilterExpression. + /// + public TestFilter ConvertVsTestFilterToNUnitFilter(IVsTestFilter vsFilter) + { + if (string.IsNullOrEmpty(vsFilter?.TfsTestCaseFilterExpression?.TestCaseFilterValue)) + return null; + var parser = new TestFilterParser(); + var filter = parser.Parse(vsFilter.TfsTestCaseFilterExpression.TestCaseFilterValue); + var tf = new TestFilter(filter); + return tf; + } - public TestFilter ConvertVsTestFilterToNUnitFilter(IVsTestFilter vsFilter, IDiscoveryConverter discovery) - { - if (settings.DiscoveryMethod == DiscoveryMethod.Legacy) - return ConvertTfsFilterToNUnitFilter(vsFilter, discovery.LoadedTestCases); - if (!settings.UseNUnitFilter) - return ConvertTfsFilterToNUnitFilter(vsFilter, discovery); - var result = ConvertVsTestFilterToNUnitFilter(vsFilter); - return result ?? ConvertTfsFilterToNUnitFilter(vsFilter, discovery); - } - /// - /// Used when running from command line, mode Non-Ide, e.g. 'dotnet test --filter xxxxx'. Reads the TfsTestCaseFilterExpression. - /// - public TestFilter ConvertVsTestFilterToNUnitFilter(IVsTestFilter vsFilter) - { - if (string.IsNullOrEmpty(vsFilter?.TfsTestCaseFilterExpression?.TestCaseFilterValue)) - return null; - var parser = new TestFilterParser(); - var filter = parser.Parse(vsFilter.TfsTestCaseFilterExpression.TestCaseFilterValue); - var tf = new TestFilter(filter); - return tf; - } + public TestFilter ConvertTfsFilterToNUnitFilter(IVsTestFilter vsFilter, IDiscoveryConverter discovery) + { + var filteredTestCases = vsFilter.CheckFilter(discovery.LoadedTestCases).ToList(); + var explicitCases = discovery.GetExplicitTestCases(filteredTestCases).ToList(); + bool isExplicit = filteredTestCases.Count == explicitCases.Count; + var tcs = isExplicit ? filteredTestCases : filteredTestCases.Except(explicitCases); + var testCases = tcs as TestCase[] ?? tcs.ToArray(); + // TestLog.Info(string.Format("TFS Filter detected: LoadedTestCases {0}, Filtered Test Cases {1}", loadedTestCases.Count, testCases.Count())); + return testCases.Any() ? FilterByList(testCases) : NoTestsFound; + } + /// + /// Used when a Where statement is added as a runsettings parameter, either in a runsettings file or on the command line from dotnet using the '-- NUnit.Where .....' statement. + /// + public TestFilter FilterByWhere(string where) + { + if (string.IsNullOrEmpty(where)) + return TestFilter.Empty; + var filterBuilder = _filterService.GetTestFilterBuilder(); + filterBuilder.SelectWhere(where); + return filterBuilder.GetFilter(); + } - public TestFilter ConvertTfsFilterToNUnitFilter(IVsTestFilter vsFilter, IDiscoveryConverter discovery) + public TestFilter FilterByList(IEnumerable testCases) + { + if (testCases.Count() > settings.AssemblySelectLimit) { - var filteredTestCases = vsFilter.CheckFilter(discovery.LoadedTestCases).ToList(); - var explicitCases = discovery.GetExplicitTestCases(filteredTestCases).ToList(); - bool isExplicit = filteredTestCases.Count == explicitCases.Count; - var tcs = isExplicit ? filteredTestCases : filteredTestCases.Except(explicitCases); - var testCases = tcs as TestCase[] ?? tcs.ToArray(); - // TestLog.Info(string.Format("TFS Filter detected: LoadedTestCases {0}, Filtered Test Cases {1}", loadedTestCases.Count, testCases.Count())); - return testCases.Any() ? FilterByList(testCases) : NoTestsFound; + // Need to log that filter has been set to empty due to AssemblySelectLimit + return TestFilter.Empty; } - /// - /// Used when a Where statement is added as a runsettings parameter, either in a runsettings file or on the command line from dotnet using the '-- NUnit.Where .....' statement. - /// - public TestFilter FilterByWhere(string where) + var filterBuilder = _filterService.GetTestFilterBuilder(); + foreach (var testCase in testCases) { - if (string.IsNullOrEmpty(where)) - return TestFilter.Empty; - var filterBuilder = _filterService.GetTestFilterBuilder(); - filterBuilder.SelectWhere(where); - return filterBuilder.GetFilter(); + filterBuilder.AddTest(testCase.FullyQualifiedName); } - public TestFilter FilterByList(IEnumerable testCases) - { - if (testCases.Count() > settings.AssemblySelectLimit) - { - // Need to log that filter has been set to empty due to AssemblySelectLimit - return TestFilter.Empty; - } - - var filterBuilder = _filterService.GetTestFilterBuilder(); - foreach (var testCase in testCases) - { - filterBuilder.AddTest(testCase.FullyQualifiedName); - } - - return filterBuilder.GetFilter(); - } + return filterBuilder.GetFilter(); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/NavigationData.cs b/src/NUnitTestAdapter/NavigationData.cs index e18754a0..c0fe7095 100644 --- a/src/NUnitTestAdapter/NavigationData.cs +++ b/src/NUnitTestAdapter/NavigationData.cs @@ -21,22 +21,21 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public class NavigationData { - public class NavigationData - { - public static readonly NavigationData Invalid = new (null, 0); + public static readonly NavigationData Invalid = new (null, 0); - public NavigationData(string filePath, int lineNumber) - { - FilePath = filePath; - LineNumber = lineNumber; - } + public NavigationData(string filePath, int lineNumber) + { + FilePath = filePath; + LineNumber = lineNumber; + } - public string FilePath { get; } + public string FilePath { get; } - public int LineNumber { get; } + public int LineNumber { get; } - public bool IsValid => !string.IsNullOrEmpty(FilePath); - } -} + public bool IsValid => !string.IsNullOrEmpty(FilePath); +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/NavigationDataProvider.cs b/src/NUnitTestAdapter/NavigationDataProvider.cs index 284969c1..5bda27d2 100644 --- a/src/NUnitTestAdapter/NavigationDataProvider.cs +++ b/src/NUnitTestAdapter/NavigationDataProvider.cs @@ -27,103 +27,102 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using NUnit.VisualStudio.TestAdapter.Metadata; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public sealed class NavigationDataProvider : IDisposable { - public sealed class NavigationDataProvider : IDisposable - { - private readonly string _assemblyPath; - private readonly IMetadataProvider _metadataProvider; - private readonly ITestLogger _logger; - private readonly Dictionary _sessionsByAssemblyPath = new (StringComparer.OrdinalIgnoreCase); - private bool _disableMetadataLookup; + private readonly string _assemblyPath; + private readonly IMetadataProvider _metadataProvider; + private readonly ITestLogger _logger; + private readonly Dictionary _sessionsByAssemblyPath = new (StringComparer.OrdinalIgnoreCase); + private bool _disableMetadataLookup; - public NavigationDataProvider(string assemblyPath, ITestLogger logger) + public NavigationDataProvider(string assemblyPath, ITestLogger logger) #if !NET462 : this(assemblyPath, logger, new DirectReflectionMetadataProvider()) #else - : this(assemblyPath, logger, CreateMetadataProvider(assemblyPath)) + : this(assemblyPath, logger, CreateMetadataProvider(assemblyPath)) #endif - { - } + { + } #if NET462 - internal static AppDomainMetadataProvider CreateMetadataProvider(string assemblyPath) - { - return new ( - applicationBase: Path.GetDirectoryName(assemblyPath), - configurationFile: assemblyPath + ".config"); - } + internal static AppDomainMetadataProvider CreateMetadataProvider(string assemblyPath) + { + return new ( + applicationBase: Path.GetDirectoryName(assemblyPath), + configurationFile: assemblyPath + ".config"); + } #endif - internal NavigationDataProvider(string assemblyPath, ITestLogger logger, IMetadataProvider metadataProvider) - { - if (string.IsNullOrEmpty(assemblyPath)) - throw new ArgumentException("Assembly path must be specified.", nameof(assemblyPath)); + internal NavigationDataProvider(string assemblyPath, ITestLogger logger, IMetadataProvider metadataProvider) + { + if (string.IsNullOrEmpty(assemblyPath)) + throw new ArgumentException("Assembly path must be specified.", nameof(assemblyPath)); - _assemblyPath = assemblyPath; - _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + _assemblyPath = assemblyPath; + _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } - public void Dispose() - { - _metadataProvider.Dispose(); + public void Dispose() + { + _metadataProvider.Dispose(); - foreach (var session in _sessionsByAssemblyPath.Values) - session?.Dispose(); - } + foreach (var session in _sessionsByAssemblyPath.Values) + session?.Dispose(); + } - public NavigationData GetNavigationData(string className, string methodName) + public NavigationData GetNavigationData(string className, string methodName) + { + return TryGetSessionData(_assemblyPath, className, methodName) + ?? TryGetSessionData(DoWithBreaker(_metadataProvider.GetStateMachineType, className, methodName), "MoveNext") + ?? TryGetSessionData(DoWithBreaker(_metadataProvider.GetDeclaringType, className, methodName), methodName) + ?? NavigationData.Invalid; + } + + private TypeInfo? DoWithBreaker(Func method, string declaringTypeName, string methodName) + { + if (_disableMetadataLookup) + return null; + try { - return TryGetSessionData(_assemblyPath, className, methodName) - ?? TryGetSessionData(DoWithBreaker(_metadataProvider.GetStateMachineType, className, methodName), "MoveNext") - ?? TryGetSessionData(DoWithBreaker(_metadataProvider.GetDeclaringType, className, methodName), methodName) - ?? NavigationData.Invalid; + return method.Invoke(_assemblyPath, declaringTypeName, methodName); } + catch (Exception ex) + { + _disableMetadataLookup = true; + _logger.Warning($"Disabling navigation data lookup for \"{_assemblyPath}\".", ex); + } + return null; + } - private TypeInfo? DoWithBreaker(Func method, string declaringTypeName, string methodName) + private NavigationData TryGetSessionData(string assemblyPath, string declaringTypeName, string methodName) + { + if (!_sessionsByAssemblyPath.TryGetValue(assemblyPath, out var session)) { - if (_disableMetadataLookup) - return null; try { - return method.Invoke(_assemblyPath, declaringTypeName, methodName); + session = new DiaSession(assemblyPath); } - catch (Exception ex) + // DiaSession crashes for .NET Framework tests run via `dotnet test` or `dotnet vstest`. + // See https://github.com/Microsoft/vstest/issues/1432. + catch // TestPlatformException not available in net35. { - _disableMetadataLookup = true; - _logger.Warning($"Disabling navigation data lookup for \"{_assemblyPath}\".", ex); + session = null; } - return null; + _sessionsByAssemblyPath.Add(assemblyPath, session); } - private NavigationData TryGetSessionData(string assemblyPath, string declaringTypeName, string methodName) - { - if (!_sessionsByAssemblyPath.TryGetValue(assemblyPath, out var session)) - { - try - { - session = new DiaSession(assemblyPath); - } - // DiaSession crashes for .NET Framework tests run via `dotnet test` or `dotnet vstest`. - // See https://github.com/Microsoft/vstest/issues/1432. - catch // TestPlatformException not available in net35. - { - session = null; - } - _sessionsByAssemblyPath.Add(assemblyPath, session); - } + var data = session?.GetNavigationData(declaringTypeName, methodName); - var data = session?.GetNavigationData(declaringTypeName, methodName); - - return string.IsNullOrEmpty(data?.FileName) ? null : - new NavigationData(data.FileName, data.MinLineNumber); - } + return string.IsNullOrEmpty(data?.FileName) ? null : + new NavigationData(data.FileName, data.MinLineNumber); + } - private NavigationData TryGetSessionData(TypeInfo? declaringType, string methodName) - { - return declaringType == null ? null : - TryGetSessionData(declaringType.Value.AssemblyPath, declaringType.Value.FullName, methodName); - } + private NavigationData TryGetSessionData(TypeInfo? declaringType, string methodName) + { + return declaringType == null ? null : + TryGetSessionData(declaringType.Value.AssemblyPath, declaringType.Value.FullName, methodName); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/PackageSettings.cs b/src/NUnitTestAdapter/PackageSettings.cs index 6833366c..b9455433 100644 --- a/src/NUnitTestAdapter/PackageSettings.cs +++ b/src/NUnitTestAdapter/PackageSettings.cs @@ -22,223 +22,222 @@ // *********************************************************************** // ReSharper disable once CheckNamespace -namespace NUnit.Common +namespace NUnit.Common; + +/// +/// PackageSettings is a static class containing constant values that +/// are used as keys in setting up a TestPackage. These values are used in +/// the engine and framework. Setting values may be a string, int or bool. +/// +public static class PackageSettings { + #region Common Settings - Used by both the Engine and the 3.0 Framework + + /// + /// Flag (bool) indicating whether tests are being debugged. + /// + public const string DebugTests = "DebugTests"; + + /// + /// Flag (bool) indicating whether to pause execution of tests to allow + /// the user to attache a debugger. + /// + public const string PauseBeforeRun = "PauseBeforeRun"; + + /// + /// The InternalTraceLevel for this run. Values are: "Default", + /// "Off", "Error", "Warning", "Info", "Debug", "Verbose". + /// Default is "Off". "Debug" and "Verbose" are synonyms. + /// + public const string InternalTraceLevel = "InternalTraceLevel"; + + /// + /// Full path of the directory to be used for work and result files. + /// This path is provided to tests by the framework TestContext. + /// + public const string WorkDirectory = "WorkDirectory"; + + public const string SkipNonTestAssemblies = nameof(SkipNonTestAssemblies); + + #endregion + + #region Engine Settings - Used by the Engine itself + + /// + /// The name of the config to use in loading a project. + /// If not specified, the first config found is used. + /// + public const string ActiveConfig = "ActiveConfig"; + + /// + /// Bool indicating whether the engine should determine the private + /// bin path by examining the paths to all the tests. Defaults to + /// true unless PrivateBinPath is specified. + /// + public const string AutoBinPath = "AutoBinPath"; + + /// + /// The ApplicationBase to use in loading the tests. If not + /// specified, and each assembly has its own process, then the + /// location of the assembly is used. For multiple assemblies + /// in a single process, the closest common root directory is used. + /// + public const string BasePath = "BasePath"; + + /// + /// Path to the config file to use in running the tests. + /// + public const string ConfigurationFile = "ConfigurationFile"; + + /// + /// Bool flag indicating whether a debugger should be launched at agent + /// startup. Used only for debugging NUnit itself. + /// + public const string DebugAgent = "DebugAgent"; + + /// + /// Indicates how to load tests across AppDomains. Values are: + /// "Default", "None", "Single", "Multiple". Default is "Multiple" + /// if more than one assembly is loaded in a process. Otherwise, + /// it is "Single". + /// + public const string DomainUsage = "DomainUsage"; + + /// + /// The private binpath used to locate assemblies. Directory paths + /// is separated by a semicolon. It's an error to specify this and + /// also set AutoBinPath to true. + /// + public const string PrivateBinPath = "PrivateBinPath"; + + /// + /// The maximum number of test agents permitted to run simultaneously. + /// Ignored if the ProcessModel is not set or defaulted to Multiple. + /// + public const string MaxAgents = "MaxAgents"; + + /// + /// Indicates how to allocate assemblies to processes. Values are: + /// "Default", "Single", "Separate", "Multiple". Default is "Multiple" + /// for more than one assembly, "Separate" for a single assembly. + /// + public const string ProcessModel = "ProcessModel"; + + /// + /// Indicates the desired runtime to use for the tests. Values + /// are strings like "net-4.5", "mono-4.0", etc. Default is to + /// use the target framework for which an assembly was built. + /// + public const string RuntimeFramework = "RuntimeFramework"; + + /// + /// Bool flag indicating that the test should be run in a 32-bit process + /// on a 64-bit system. By default, NUNit runs in a 64-bit process on + /// a 64-bit system. Ignored if set on a 32-bit system. + /// + public const string RunAsX86 = "RunAsX86"; + + /// + /// Indicates that test runners should be disposed after the tests are executed. + /// + public const string DisposeRunners = "DisposeRunners"; + + /// + /// Bool flag indicating that the test assemblies should be shadow copied. + /// Defaults to false. + /// + public const string ShadowCopyFiles = "ShadowCopyFiles"; + + #endregion + + #region Framework Settings - Passed through and used by the 3.0 Framework + + /// + /// Integer value in milliseconds for the default timeout value + /// for test cases. If not specified, there is no timeout except + /// as specified by attributes on the tests themselves. + /// + public const string DefaultTimeout = "DefaultTimeout"; + + /// + /// A TextWriter to which the internal trace will be sent. + /// + public const string InternalTraceWriter = "InternalTraceWriter"; + + /// + /// A list of tests to be loaded. + /// + // TODO: Remove? + public const string LOAD = "LOAD"; + + /// + /// The number of test threads to run for the assembly. If set to + /// 1, a single queue is used. If set to 0, tests are executed + /// directly, without queuing. + /// + public const string NumberOfTestWorkers = "NumberOfTestWorkers"; + + /// + /// The random seed to be used for this assembly. If specified + /// as the value reported from a prior run, the framework should + /// generate identical random values for tests as were used for + /// that run, provided that no change has been made to the test + /// assembly. Default is a random value itself. + /// + public const string RandomSeed = "RandomSeed"; + + /// + /// If true, execution stops after the first error or failure. + /// + public const string StopOnError = "StopOnError"; + /// - /// PackageSettings is a static class containing constant values that - /// are used as keys in setting up a TestPackage. These values are used in - /// the engine and framework. Setting values may be a string, int or bool. - /// - public static class PackageSettings - { - #region Common Settings - Used by both the Engine and the 3.0 Framework - - /// - /// Flag (bool) indicating whether tests are being debugged. - /// - public const string DebugTests = "DebugTests"; - - /// - /// Flag (bool) indicating whether to pause execution of tests to allow - /// the user to attache a debugger. - /// - public const string PauseBeforeRun = "PauseBeforeRun"; - - /// - /// The InternalTraceLevel for this run. Values are: "Default", - /// "Off", "Error", "Warning", "Info", "Debug", "Verbose". - /// Default is "Off". "Debug" and "Verbose" are synonyms. - /// - public const string InternalTraceLevel = "InternalTraceLevel"; - - /// - /// Full path of the directory to be used for work and result files. - /// This path is provided to tests by the framework TestContext. - /// - public const string WorkDirectory = "WorkDirectory"; - - public const string SkipNonTestAssemblies = nameof(SkipNonTestAssemblies); - - #endregion - - #region Engine Settings - Used by the Engine itself - - /// - /// The name of the config to use in loading a project. - /// If not specified, the first config found is used. - /// - public const string ActiveConfig = "ActiveConfig"; - - /// - /// Bool indicating whether the engine should determine the private - /// bin path by examining the paths to all the tests. Defaults to - /// true unless PrivateBinPath is specified. - /// - public const string AutoBinPath = "AutoBinPath"; - - /// - /// The ApplicationBase to use in loading the tests. If not - /// specified, and each assembly has its own process, then the - /// location of the assembly is used. For multiple assemblies - /// in a single process, the closest common root directory is used. - /// - public const string BasePath = "BasePath"; - - /// - /// Path to the config file to use in running the tests. - /// - public const string ConfigurationFile = "ConfigurationFile"; - - /// - /// Bool flag indicating whether a debugger should be launched at agent - /// startup. Used only for debugging NUnit itself. - /// - public const string DebugAgent = "DebugAgent"; - - /// - /// Indicates how to load tests across AppDomains. Values are: - /// "Default", "None", "Single", "Multiple". Default is "Multiple" - /// if more than one assembly is loaded in a process. Otherwise, - /// it is "Single". - /// - public const string DomainUsage = "DomainUsage"; - - /// - /// The private binpath used to locate assemblies. Directory paths - /// is separated by a semicolon. It's an error to specify this and - /// also set AutoBinPath to true. - /// - public const string PrivateBinPath = "PrivateBinPath"; - - /// - /// The maximum number of test agents permitted to run simultaneously. - /// Ignored if the ProcessModel is not set or defaulted to Multiple. - /// - public const string MaxAgents = "MaxAgents"; - - /// - /// Indicates how to allocate assemblies to processes. Values are: - /// "Default", "Single", "Separate", "Multiple". Default is "Multiple" - /// for more than one assembly, "Separate" for a single assembly. - /// - public const string ProcessModel = "ProcessModel"; - - /// - /// Indicates the desired runtime to use for the tests. Values - /// are strings like "net-4.5", "mono-4.0", etc. Default is to - /// use the target framework for which an assembly was built. - /// - public const string RuntimeFramework = "RuntimeFramework"; - - /// - /// Bool flag indicating that the test should be run in a 32-bit process - /// on a 64-bit system. By default, NUNit runs in a 64-bit process on - /// a 64-bit system. Ignored if set on a 32-bit system. - /// - public const string RunAsX86 = "RunAsX86"; - - /// - /// Indicates that test runners should be disposed after the tests are executed. - /// - public const string DisposeRunners = "DisposeRunners"; - - /// - /// Bool flag indicating that the test assemblies should be shadow copied. - /// Defaults to false. - /// - public const string ShadowCopyFiles = "ShadowCopyFiles"; - - #endregion - - #region Framework Settings - Passed through and used by the 3.0 Framework - - /// - /// Integer value in milliseconds for the default timeout value - /// for test cases. If not specified, there is no timeout except - /// as specified by attributes on the tests themselves. - /// - public const string DefaultTimeout = "DefaultTimeout"; - - /// - /// A TextWriter to which the internal trace will be sent. - /// - public const string InternalTraceWriter = "InternalTraceWriter"; - - /// - /// A list of tests to be loaded. - /// - // TODO: Remove? - public const string LOAD = "LOAD"; - - /// - /// The number of test threads to run for the assembly. If set to - /// 1, a single queue is used. If set to 0, tests are executed - /// directly, without queuing. - /// - public const string NumberOfTestWorkers = "NumberOfTestWorkers"; - - /// - /// The random seed to be used for this assembly. If specified - /// as the value reported from a prior run, the framework should - /// generate identical random values for tests as were used for - /// that run, provided that no change has been made to the test - /// assembly. Default is a random value itself. - /// - public const string RandomSeed = "RandomSeed"; - - /// - /// If true, execution stops after the first error or failure. - /// - public const string StopOnError = "StopOnError"; - - /// - /// If true, use of the event queue is suppressed and test events are synchronous. - /// - public const string SynchronousEvents = "SynchronousEvents"; - - /// - /// Set default pattern used to generate test case names. - /// - public const string DefaultTestNamePattern = "DefaultTestNamePattern"; - - /// - /// Parameters to be passed on to the tests, serialized to a single string which needs parsing. Obsoleted by ; kept for backward compatibility. - /// - public const string TestParameters = "TestParameters"; - - /// - /// Parameters to be passed on to the tests, already parsed into an IDictionary<string, string>. Replaces . - /// - public const string TestParametersDictionary = "TestParametersDictionary"; - - #endregion - - #region Internal Settings - Used only within the engine - - /// - /// If the package represents an assembly, then this is the CLR version - /// stored in the assembly image. If it represents a project or other - /// group of assemblies, it is the maximum version for all the assemblies. - /// - public const string ImageRuntimeVersion = "ImageRuntimeVersion"; - - /// - /// True if any assembly in the package requires running as a 32-bit - /// process when on a 64-bit system. - /// - public const string ImageRequiresX86 = "ImageRequiresX86"; - - /// - /// True if any assembly in the package requires a special assembly resolution hook - /// in the default AppDomain in order to find dependent assemblies. - /// - public const string ImageRequiresDefaultAppDomainAssemblyResolver = "ImageRequiresDefaultAppDomainAssemblyResolver"; - - /// - /// The FrameworkName specified on a TargetFrameworkAttribute for the assembly. - /// - public const string ImageTargetFrameworkName = "ImageTargetFrameworkName"; - - #endregion - } -} + /// If true, use of the event queue is suppressed and test events are synchronous. + /// + public const string SynchronousEvents = "SynchronousEvents"; + + /// + /// Set default pattern used to generate test case names. + /// + public const string DefaultTestNamePattern = "DefaultTestNamePattern"; + + /// + /// Parameters to be passed on to the tests, serialized to a single string which needs parsing. Obsoleted by ; kept for backward compatibility. + /// + public const string TestParameters = "TestParameters"; + + /// + /// Parameters to be passed on to the tests, already parsed into an IDictionary<string, string>. Replaces . + /// + public const string TestParametersDictionary = "TestParametersDictionary"; + + #endregion + + #region Internal Settings - Used only within the engine + + /// + /// If the package represents an assembly, then this is the CLR version + /// stored in the assembly image. If it represents a project or other + /// group of assemblies, it is the maximum version for all the assemblies. + /// + public const string ImageRuntimeVersion = "ImageRuntimeVersion"; + + /// + /// True if any assembly in the package requires running as a 32-bit + /// process when on a 64-bit system. + /// + public const string ImageRequiresX86 = "ImageRequiresX86"; + + /// + /// True if any assembly in the package requires a special assembly resolution hook + /// in the default AppDomain in order to find dependent assemblies. + /// + public const string ImageRequiresDefaultAppDomainAssemblyResolver = "ImageRequiresDefaultAppDomainAssemblyResolver"; + + /// + /// The FrameworkName specified on a TargetFrameworkAttribute for the assembly. + /// + public const string ImageTargetFrameworkName = "ImageTargetFrameworkName"; + + #endregion +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/Polyfills.cs b/src/NUnitTestAdapter/Polyfills.cs index 3e70b792..5e944111 100644 --- a/src/NUnitTestAdapter/Polyfills.cs +++ b/src/NUnitTestAdapter/Polyfills.cs @@ -1,7 +1,6 @@ -namespace System.Runtime.CompilerServices +namespace System.Runtime.CompilerServices; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +internal sealed class ModuleInitializerAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method, Inherited = false)] - internal sealed class ModuleInitializerAttribute : Attribute - { - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/Seed.cs b/src/NUnitTestAdapter/Seed.cs index 01489677..ac616dcc 100644 --- a/src/NUnitTestAdapter/Seed.cs +++ b/src/NUnitTestAdapter/Seed.cs @@ -1,11 +1,10 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public class Seed { - public class Seed - { - internal static readonly TestProperty NUnitSeedProperty = TestProperty.Register( - "NUnit.Seed", - "Seed", typeof(string), TestPropertyAttributes.None, typeof(TestCase)); - } -} + internal static readonly TestProperty NUnitSeedProperty = TestProperty.Register( + "NUnit.Seed", + "Seed", typeof(string), TestPropertyAttributes.None, typeof(TestCase)); +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/TestConverter.cs b/src/NUnitTestAdapter/TestConverter.cs index e7b00492..5fa903d7 100644 --- a/src/NUnitTestAdapter/TestConverter.cs +++ b/src/NUnitTestAdapter/TestConverter.cs @@ -33,380 +33,379 @@ using VSTestResult = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResult; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public sealed class TestConverter : IDisposable, ITestConverter { - public sealed class TestConverter : IDisposable, ITestConverter + private readonly ITestLogger _logger; + private readonly Dictionary _vsTestCaseMap; + private readonly string _sourceAssembly; + private readonly NavigationDataProvider _navigationDataProvider; + private bool CollectSourceInformation => adapterSettings.CollectSourceInformation; + private readonly IAdapterSettings adapterSettings; + private static readonly string NL = Environment.NewLine; + private readonly IDiscoveryConverter discoveryConverter; + + public TestConverter(ITestLogger logger, string sourceAssembly, IAdapterSettings settings, IDiscoveryConverter discoveryConverter) { - private readonly ITestLogger _logger; - private readonly Dictionary _vsTestCaseMap; - private readonly string _sourceAssembly; - private readonly NavigationDataProvider _navigationDataProvider; - private bool CollectSourceInformation => adapterSettings.CollectSourceInformation; - private readonly IAdapterSettings adapterSettings; - private static readonly string NL = Environment.NewLine; - private readonly IDiscoveryConverter discoveryConverter; - - public TestConverter(ITestLogger logger, string sourceAssembly, IAdapterSettings settings, IDiscoveryConverter discoveryConverter) + this.discoveryConverter = discoveryConverter; + adapterSettings = settings; + _logger = logger; + _sourceAssembly = sourceAssembly; + _vsTestCaseMap = []; + TraitsCache = new Dictionary(); + + if (CollectSourceInformation) { - this.discoveryConverter = discoveryConverter; - adapterSettings = settings; - _logger = logger; - _sourceAssembly = sourceAssembly; - _vsTestCaseMap = []; - TraitsCache = new Dictionary(); - - if (CollectSourceInformation) - { - _navigationDataProvider = new NavigationDataProvider(sourceAssembly, logger); - } + _navigationDataProvider = new NavigationDataProvider(sourceAssembly, logger); } + } - public void Dispose() - { - _navigationDataProvider?.Dispose(); - } + public void Dispose() + { + _navigationDataProvider?.Dispose(); + } - public IDictionary TraitsCache { get; } + public IDictionary TraitsCache { get; } - #region Public Methods + #region Public Methods - /// - /// Converts an NUnit test into a TestCase for Visual Studio, - /// using the best method available according to the exact - /// type passed and caching results for efficiency. - /// - public TestCase ConvertTestCase(NUnitDiscoveryTestCase testNode) - { - // Return cached value if we have one - string id = testNode.Id; - if (_vsTestCaseMap.ContainsKey(id)) - return _vsTestCaseMap[id]; - - // Convert to VS TestCase and cache the result - var testCase = MakeTestCaseFromDiscoveryNode(testNode); - _vsTestCaseMap.Add(id, testCase); - return testCase; - } + /// + /// Converts an NUnit test into a TestCase for Visual Studio, + /// using the best method available according to the exact + /// type passed and caching results for efficiency. + /// + public TestCase ConvertTestCase(NUnitDiscoveryTestCase testNode) + { + // Return cached value if we have one + string id = testNode.Id; + if (_vsTestCaseMap.ContainsKey(id)) + return _vsTestCaseMap[id]; + + // Convert to VS TestCase and cache the result + var testCase = MakeTestCaseFromDiscoveryNode(testNode); + _vsTestCaseMap.Add(id, testCase); + return testCase; + } - public TestCase GetCachedTestCase(string id) - { - if (_vsTestCaseMap.ContainsKey(id)) - return _vsTestCaseMap[id]; + public TestCase GetCachedTestCase(string id) + { + if (_vsTestCaseMap.ContainsKey(id)) + return _vsTestCaseMap[id]; - _logger.Debug("Test " + id + " not found in cache"); - return null; - } + _logger.Debug("Test " + id + " not found in cache"); + return null; + } - public TestConverterForXml.TestResultSet GetVsTestResults(INUnitTestEventTestCase resultNode, ICollection outputNodes) - { - var results = new List(); + public TestConverterForXml.TestResultSet GetVsTestResults(INUnitTestEventTestCase resultNode, ICollection outputNodes) + { + var results = new List(); - var testCaseResult = GetBasicResult(resultNode, outputNodes); + var testCaseResult = GetBasicResult(resultNode, outputNodes); - if (testCaseResult != null) + if (testCaseResult != null) + { + switch (testCaseResult.Outcome) { - switch (testCaseResult.Outcome) - { - case TestOutcome.Failed: - case TestOutcome.NotFound: - { - testCaseResult.ErrorMessage = resultNode.Failure?.Message; - testCaseResult.ErrorStackTrace = resultNode.FailureStackTrace; - break; - } - case TestOutcome.Skipped: - case TestOutcome.None: - testCaseResult.ErrorMessage = resultNode.ReasonMessage; - testCaseResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, resultNode.ReasonMessage)); + case TestOutcome.Failed: + case TestOutcome.NotFound: + { + testCaseResult.ErrorMessage = resultNode.Failure?.Message; + testCaseResult.ErrorStackTrace = resultNode.FailureStackTrace; break; - default: - { - if (adapterSettings.ConsoleOut > 0 && !string.IsNullOrEmpty(resultNode.ReasonMessage)) - testCaseResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, resultNode.ReasonMessage)); - break; - } - } - - results.Add(testCaseResult); + } + case TestOutcome.Skipped: + case TestOutcome.None: + testCaseResult.ErrorMessage = resultNode.ReasonMessage; + testCaseResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, resultNode.ReasonMessage)); + break; + default: + { + if (adapterSettings.ConsoleOut > 0 && !string.IsNullOrEmpty(resultNode.ReasonMessage)) + testCaseResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, resultNode.ReasonMessage)); + break; + } } - if (results.Count == 0) - { - var result = MakeTestResultFromLegacyXmlNode(resultNode, outputNodes); - if (result != null) - results.Add(result); - } - return new TestConverterForXml.TestResultSet { TestCaseResult = testCaseResult, TestResults = results, ConsoleOutput = resultNode.Output }; + results.Add(testCaseResult); + } + + if (results.Count == 0) + { + var result = MakeTestResultFromLegacyXmlNode(resultNode, outputNodes); + if (result != null) + results.Add(result); } + return new TestConverterForXml.TestResultSet { TestCaseResult = testCaseResult, TestResults = results, ConsoleOutput = resultNode.Output }; + } - #endregion + #endregion - #region Helper Methods + #region Helper Methods - /// - /// Makes a TestCase from an NUnit test, adding - /// navigation data if it can be found. - /// - private TestCase MakeTestCaseFromDiscoveryNode(NUnitDiscoveryTestCase testNode) + /// + /// Makes a TestCase from an NUnit test, adding + /// navigation data if it can be found. + /// + private TestCase MakeTestCaseFromDiscoveryNode(NUnitDiscoveryTestCase testNode) + { + string fullyQualifiedName = testNode.FullName; + if (adapterSettings.UseParentFQNForParametrizedTests) { - string fullyQualifiedName = testNode.FullName; - if (adapterSettings.UseParentFQNForParametrizedTests) + var parent = testNode.Parent; + if (parent != null && parent.IsParameterizedMethod) { - var parent = testNode.Parent; - if (parent != null && parent.IsParameterizedMethod) - { - var parameterizedTestFullName = parent.FullName; + var parameterizedTestFullName = parent.FullName; - // VS expected FullyQualifiedName to be the actual class+type name,optionally with parameter types - // in parenthesis, but they must fit the pattern of a value returned by object.GetType(). - // It should _not_ include custom name or param values (just their types). - // However, the "fullname" from NUnit's file generation is the custom name of the test, so - // this code must convert from one to the other. - // Reference: https://github.com/microsoft/vstest-docs/blob/master/RFCs/0017-Managed-TestCase-Properties.md + // VS expected FullyQualifiedName to be the actual class+type name,optionally with parameter types + // in parenthesis, but they must fit the pattern of a value returned by object.GetType(). + // It should _not_ include custom name or param values (just their types). + // However, the "fullname" from NUnit's file generation is the custom name of the test, so + // this code must convert from one to the other. + // Reference: https://github.com/microsoft/vstest-docs/blob/master/RFCs/0017-Managed-TestCase-Properties.md - // Using the nUnit-provided "fullname" will cause failures at test execution time due to - // the FilterExpressionWrapper not being able to parse the test names passed-in as filters. + // Using the nUnit-provided "fullname" will cause failures at test execution time due to + // the FilterExpressionWrapper not being able to parse the test names passed-in as filters. - // To resolve this issue, for parameterized tests (which are the only tests that allow custom names), - // the parent node's "fullname" value is used instead. This is the name of the actual test method - // and will allow the filtering to work as expected. + // To resolve this issue, for parameterized tests (which are the only tests that allow custom names), + // the parent node's "fullname" value is used instead. This is the name of the actual test method + // and will allow the filtering to work as expected. - // Note that this also means you can no longer select a single tests of these to run. - // When you do that, all tests within the parent node will be executed + // Note that this also means you can no longer select a single tests of these to run. + // When you do that, all tests within the parent node will be executed - if (!string.IsNullOrEmpty(parameterizedTestFullName)) - { - fullyQualifiedName = parameterizedTestFullName; - } - } - } - - var testCase = new TestCase( - fullyQualifiedName, - new Uri(NUnitTestAdapter.ExecutorUri), - _sourceAssembly) - { - DisplayName = CreateDisplayName(fullyQualifiedName, testNode.Name), - CodeFilePath = null, - LineNumber = 0 - }; - if (adapterSettings.UseNUnitIdforTestCaseId) - { - testCase.Id = EqtHash.GuidFromString(testNode.Id); - } - if (CollectSourceInformation && _navigationDataProvider != null) - { - if (!CheckCodeFilePathOverride()) + if (!string.IsNullOrEmpty(parameterizedTestFullName)) { - var navData = _navigationDataProvider.GetNavigationData(testNode.ClassName, testNode.MethodName); - if (navData.IsValid) - { - testCase.CodeFilePath = navData.FilePath; - testCase.LineNumber = navData.LineNumber; - } + fullyQualifiedName = parameterizedTestFullName; } } - else - { - _ = CheckCodeFilePathOverride(); - } - - testCase.AddTraitsFromTestNode(testNode, TraitsCache, _logger, adapterSettings); - testCase.SetPropertyValue(Seed.NUnitSeedProperty, testNode.Seed.ToString()); - - return testCase; - - bool CheckCodeFilePathOverride() - { - var codeFilePath = testNode.Properties.FirstOrDefault(p => p.Name == "_CodeFilePath"); - if (codeFilePath == null) - return false; - testCase.CodeFilePath = codeFilePath.Value; - var lineNumber = testNode.Properties.FirstOrDefault(p => p.Name == "_LineNumber"); - testCase.LineNumber = lineNumber != null ? Convert.ToInt32(lineNumber.Value) : 1; - return true; - } } - private string CreateDisplayName(string fullyQualifiedName, string testNodeName) + var testCase = new TestCase( + fullyQualifiedName, + new Uri(NUnitTestAdapter.ExecutorUri), + _sourceAssembly) + { + DisplayName = CreateDisplayName(fullyQualifiedName, testNode.Name), + CodeFilePath = null, + LineNumber = 0 + }; + if (adapterSettings.UseNUnitIdforTestCaseId) + { + testCase.Id = EqtHash.GuidFromString(testNode.Id); + } + if (CollectSourceInformation && _navigationDataProvider != null) { - return adapterSettings.FreakMode - ? adapterSettings.DisplayName switch + if (!CheckCodeFilePathOverride()) + { + var navData = _navigationDataProvider.GetNavigationData(testNode.ClassName, testNode.MethodName); + if (navData.IsValid) { - DisplayNameOptions.Name => "N:Name -> MS:DisplayName (default)", - DisplayNameOptions.FullName => "N:FullyQualifiedName -> MS:DisplayName", - DisplayNameOptions.FullNameSep => $"N:FullyQualifiedName -> MS:DisplayName, with separator '.' replaced with '{adapterSettings.FullnameSeparator}'", - _ => $"Invalid setting: {adapterSettings.DisplayName}" + testCase.CodeFilePath = navData.FilePath; + testCase.LineNumber = navData.LineNumber; } - : adapterSettings.DisplayName switch - { - DisplayNameOptions.Name => testNodeName, - DisplayNameOptions.FullName => fullyQualifiedName, - DisplayNameOptions.FullNameSep => - fullyQualifiedName.Replace('.', adapterSettings.FullnameSeparator), - _ => throw new ArgumentOutOfRangeException(), - }; + } } - - private VSTestResult MakeTestResultFromLegacyXmlNode(INUnitTestEventTestCase resultNode, IEnumerable outputNodes) + else { - var ourResult = GetBasicResult(resultNode, outputNodes); - if (ourResult == null) - return null; - - string message = resultNode.HasFailure - ? resultNode.Failure.Message - : resultNode.HasReason - ? resultNode.ReasonMessage - : null; + _ = CheckCodeFilePathOverride(); + } - // If we're running in the IDE, remove any caret line from the message - // since it will be displayed using a variable font and won't make sense. - if (!string.IsNullOrEmpty(message) && NUnitTestAdapter.IsRunningUnderIde) - { - string pattern = NL + " -*\\^" + NL; - message = Regex.Replace(message, pattern, NL, RegexOptions.Multiline); - } + testCase.AddTraitsFromTestNode(testNode, TraitsCache, _logger, adapterSettings); + testCase.SetPropertyValue(Seed.NUnitSeedProperty, testNode.Seed.ToString()); - ourResult.ErrorMessage = message; - ourResult.ErrorStackTrace = resultNode.Failure?.Stacktrace; + return testCase; - return ourResult; + bool CheckCodeFilePathOverride() + { + var codeFilePath = testNode.Properties.FirstOrDefault(p => p.Name == "_CodeFilePath"); + if (codeFilePath == null) + return false; + testCase.CodeFilePath = codeFilePath.Value; + var lineNumber = testNode.Properties.FirstOrDefault(p => p.Name == "_LineNumber"); + testCase.LineNumber = lineNumber != null ? Convert.ToInt32(lineNumber.Value) : 1; + return true; } + } - private VSTestResult GetBasicResult(INUnitTestEvent resultNode, IEnumerable outputNodes) - { - var vsTest = GetCachedTestCase(resultNode.Id); - if (vsTest == null) + private string CreateDisplayName(string fullyQualifiedName, string testNodeName) + { + return adapterSettings.FreakMode + ? adapterSettings.DisplayName switch { - var discoveredTest = discoveryConverter.AllTestCases.FirstOrDefault(o => o.Id == resultNode.Id); - if (discoveredTest != null) - { - vsTest = ConvertTestCase(discoveredTest); - } - else - { - return null; - } + DisplayNameOptions.Name => "N:Name -> MS:DisplayName (default)", + DisplayNameOptions.FullName => "N:FullyQualifiedName -> MS:DisplayName", + DisplayNameOptions.FullNameSep => $"N:FullyQualifiedName -> MS:DisplayName, with separator '.' replaced with '{adapterSettings.FullnameSeparator}'", + _ => $"Invalid setting: {adapterSettings.DisplayName}" } - - var vsResult = new VSTestResult(vsTest) + : adapterSettings.DisplayName switch { - DisplayName = vsTest.DisplayName, - Outcome = GetTestOutcome(resultNode), - Duration = resultNode.Duration + DisplayNameOptions.Name => testNodeName, + DisplayNameOptions.FullName => fullyQualifiedName, + DisplayNameOptions.FullNameSep => + fullyQualifiedName.Replace('.', adapterSettings.FullnameSeparator), + _ => throw new ArgumentOutOfRangeException(), }; + } + + private VSTestResult MakeTestResultFromLegacyXmlNode(INUnitTestEventTestCase resultNode, IEnumerable outputNodes) + { + var ourResult = GetBasicResult(resultNode, outputNodes); + if (ourResult == null) + return null; - var startTime = resultNode.StartTime(); - if (startTime.Ok) - vsResult.StartTime = startTime.Time; + string message = resultNode.HasFailure + ? resultNode.Failure.Message + : resultNode.HasReason + ? resultNode.ReasonMessage + : null; - var endTime = resultNode.EndTime(); - if (endTime.Ok) - vsResult.EndTime = endTime.Time; + // If we're running in the IDE, remove any caret line from the message + // since it will be displayed using a variable font and won't make sense. + if (!string.IsNullOrEmpty(message) && NUnitTestAdapter.IsRunningUnderIde) + { + string pattern = NL + " -*\\^" + NL; + message = Regex.Replace(message, pattern, NL, RegexOptions.Multiline); + } - // TODO: Remove this when NUnit provides a better duration - if (vsResult.Duration == TimeSpan.Zero && (vsResult.Outcome == TestOutcome.Passed || vsResult.Outcome == TestOutcome.Failed)) - vsResult.Duration = TimeSpan.FromTicks(1); + ourResult.ErrorMessage = message; + ourResult.ErrorStackTrace = resultNode.Failure?.Stacktrace; - vsResult.ComputerName = Environment.MachineName; - vsResult.SetPropertyValue(Seed.NUnitSeedProperty, resultNode.Seed); - if (adapterSettings.Verbosity >= 5) + return ourResult; + } + + private VSTestResult GetBasicResult(INUnitTestEvent resultNode, IEnumerable outputNodes) + { + var vsTest = GetCachedTestCase(resultNode.Id); + if (vsTest == null) + { + var discoveredTest = discoveryConverter.AllTestCases.FirstOrDefault(o => o.Id == resultNode.Id); + if (discoveredTest != null) { - vsResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, $"seed: {resultNode.Seed}")); + vsTest = ConvertTestCase(discoveredTest); + } + else + { + return null; } + } + + var vsResult = new VSTestResult(vsTest) + { + DisplayName = vsTest.DisplayName, + Outcome = GetTestOutcome(resultNode), + Duration = resultNode.Duration + }; + + var startTime = resultNode.StartTime(); + if (startTime.Ok) + vsResult.StartTime = startTime.Time; + + var endTime = resultNode.EndTime(); + if (endTime.Ok) + vsResult.EndTime = endTime.Time; + + // TODO: Remove this when NUnit provides a better duration + if (vsResult.Duration == TimeSpan.Zero && (vsResult.Outcome == TestOutcome.Passed || vsResult.Outcome == TestOutcome.Failed)) + vsResult.Duration = TimeSpan.FromTicks(1); + + vsResult.ComputerName = Environment.MachineName; + vsResult.SetPropertyValue(Seed.NUnitSeedProperty, resultNode.Seed); + if (adapterSettings.Verbosity >= 5) + { + vsResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, $"seed: {resultNode.Seed}")); + } - FillResultFromOutputNodes(outputNodes, vsResult); + FillResultFromOutputNodes(outputNodes, vsResult); - // Add stdOut messages from TestFinished element to vstest result - var output = resultNode.Output; - if (!string.IsNullOrEmpty(output)) - vsResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, output)); + // Add stdOut messages from TestFinished element to vstest result + var output = resultNode.Output; + if (!string.IsNullOrEmpty(output)) + vsResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, output)); - var attachmentSet = ParseAttachments(resultNode); - if (attachmentSet.Attachments.Count > 0) - vsResult.Attachments.Add(attachmentSet); + var attachmentSet = ParseAttachments(resultNode); + if (attachmentSet.Attachments.Count > 0) + vsResult.Attachments.Add(attachmentSet); - return vsResult; - } + return vsResult; + } - private static void FillResultFromOutputNodes(IEnumerable outputNodes, VSTestResult vsResult) + private static void FillResultFromOutputNodes(IEnumerable outputNodes, VSTestResult vsResult) + { + foreach (var output in outputNodes) { - foreach (var output in outputNodes) + if (output.IsNullOrEmptyStream || output.IsProgressStream) // Don't add progress streams as output { - if (output.IsNullOrEmptyStream || output.IsProgressStream) // Don't add progress streams as output - { - continue; - } - - // Add stdErr/Progress messages from TestOutputXml element to vstest result - vsResult.Messages.Add(new TestResultMessage( - output.IsErrorStream - ? TestResultMessage.StandardErrorCategory - : TestResultMessage.StandardOutCategory, output.Content)); + continue; } + + // Add stdErr/Progress messages from TestOutputXml element to vstest result + vsResult.Messages.Add(new TestResultMessage( + output.IsErrorStream + ? TestResultMessage.StandardErrorCategory + : TestResultMessage.StandardOutCategory, output.Content)); } + } - /// - /// Looks for attachments in a results node and if any attachments are found they - /// are returned"/>. - /// - /// xml node for test result. - /// attachments to be added to the test, it will be empty if no attachments are found. - private AttachmentSet ParseAttachments(INUnitTestEvent resultNode) - { - const string fileUriScheme = "file://"; - var attachmentSet = new AttachmentSet(new Uri(NUnitTestAdapter.ExecutorUri), "Attachments"); + /// + /// Looks for attachments in a results node and if any attachments are found they + /// are returned"/>. + /// + /// xml node for test result. + /// attachments to be added to the test, it will be empty if no attachments are found. + private AttachmentSet ParseAttachments(INUnitTestEvent resultNode) + { + const string fileUriScheme = "file://"; + var attachmentSet = new AttachmentSet(new Uri(NUnitTestAdapter.ExecutorUri), "Attachments"); - foreach (var attachment in resultNode.NUnitAttachments) + foreach (var attachment in resultNode.NUnitAttachments) + { + var description = attachment.Description; + var path = attachment.FilePath; + if (adapterSettings.EnsureAttachmentFileScheme) { - var description = attachment.Description; - var path = attachment.FilePath; - if (adapterSettings.EnsureAttachmentFileScheme) - { - if (!(string.IsNullOrEmpty(path) || - path.StartsWith(fileUriScheme, StringComparison.OrdinalIgnoreCase))) - { - path = fileUriScheme + path; - } - } - // For Linux paths - if (!(string.IsNullOrEmpty(path) || path.StartsWith(fileUriScheme, StringComparison.OrdinalIgnoreCase)) && !path.Contains(':')) + if (!(string.IsNullOrEmpty(path) || + path.StartsWith(fileUriScheme, StringComparison.OrdinalIgnoreCase))) { path = fileUriScheme + path; } - try - { - // We only support absolute paths since we dont lookup working directory here - // any problem with path will throw an exception - var fileUri = new Uri(path, UriKind.Absolute); - attachmentSet.Attachments.Add(new UriDataAttachment(fileUri, description)); - } - catch (UriFormatException ex) - { - _logger.Warning($"Ignoring attachment with path '{path}' due to problem with path: {ex.Message}"); - } - catch (Exception ex) - { - _logger.Warning($"Ignoring attachment with path '{path}': {ex.Message}."); - } } - - return attachmentSet; + // For Linux paths + if (!(string.IsNullOrEmpty(path) || path.StartsWith(fileUriScheme, StringComparison.OrdinalIgnoreCase)) && !path.Contains(':')) + { + path = fileUriScheme + path; + } + try + { + // We only support absolute paths since we dont lookup working directory here + // any problem with path will throw an exception + var fileUri = new Uri(path, UriKind.Absolute); + attachmentSet.Attachments.Add(new UriDataAttachment(fileUri, description)); + } + catch (UriFormatException ex) + { + _logger.Warning($"Ignoring attachment with path '{path}' due to problem with path: {ex.Message}"); + } + catch (Exception ex) + { + _logger.Warning($"Ignoring attachment with path '{path}': {ex.Message}."); + } } - // Public for testing - public TestOutcome GetTestOutcome(INUnitTestEvent resultNode) + return attachmentSet; + } + + // Public for testing + public TestOutcome GetTestOutcome(INUnitTestEvent resultNode) + { + return resultNode.Result() switch { - return resultNode.Result() switch - { - NUnitTestEvent.ResultType.Success => TestOutcome.Passed, - NUnitTestEvent.ResultType.Failed => TestOutcome.Failed, - NUnitTestEvent.ResultType.Skipped => (resultNode.IsIgnored ? TestOutcome.Skipped : TestOutcome.None), - NUnitTestEvent.ResultType.Warning => adapterSettings.MapWarningTo, - _ => TestOutcome.None - }; - } - #endregion + NUnitTestEvent.ResultType.Success => TestOutcome.Passed, + NUnitTestEvent.ResultType.Failed => TestOutcome.Failed, + NUnitTestEvent.ResultType.Skipped => (resultNode.IsIgnored ? TestOutcome.Skipped : TestOutcome.None), + NUnitTestEvent.ResultType.Warning => adapterSettings.MapWarningTo, + _ => TestOutcome.None + }; } + #endregion } \ No newline at end of file diff --git a/src/NUnitTestAdapter/TestConverterForXml.cs b/src/NUnitTestAdapter/TestConverterForXml.cs index 4f836ff3..13340188 100644 --- a/src/NUnitTestAdapter/TestConverterForXml.cs +++ b/src/NUnitTestAdapter/TestConverterForXml.cs @@ -30,388 +30,387 @@ using NUnit.VisualStudio.TestAdapter.NUnitEngine; using VSTestResult = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResult; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public interface ITestConverterCommon +{ + TestCase GetCachedTestCase(string id); + TestConverterForXml.TestResultSet GetVsTestResults(INUnitTestEventTestCase resultNode, ICollection outputNodes); +} + +public interface ITestConverter : ITestConverterCommon +{ + /// + /// Converts an NUnit test into a TestCase for Visual Studio, + /// using the best method available according to the exact + /// type passed and caching results for efficiency. + /// + TestCase ConvertTestCase(NUnitDiscoveryTestCase testNode); +} + +public interface ITestConverterXml : ITestConverterCommon { - public interface ITestConverterCommon + TestCase ConvertTestCase(NUnitEventTestCase nUnitEventTestCase); +} + +public sealed class TestConverterForXml : IDisposable, ITestConverterXml +{ + private readonly ITestLogger _logger; + private readonly Dictionary _vsTestCaseMap; + private readonly string _sourceAssembly; + private readonly NavigationDataProvider _navigationDataProvider; + private bool CollectSourceInformation => adapterSettings.CollectSourceInformation; + private readonly IAdapterSettings adapterSettings; + + + public TestConverterForXml(ITestLogger logger, string sourceAssembly, IAdapterSettings settings) { - TestCase GetCachedTestCase(string id); - TestConverterForXml.TestResultSet GetVsTestResults(INUnitTestEventTestCase resultNode, ICollection outputNodes); + adapterSettings = settings; + _logger = logger; + _sourceAssembly = sourceAssembly; + _vsTestCaseMap = []; + TraitsCache = new Dictionary(); + + if (CollectSourceInformation) + { + _navigationDataProvider = new NavigationDataProvider(sourceAssembly, logger); + } } - public interface ITestConverter : ITestConverterCommon + public void Dispose() { - /// - /// Converts an NUnit test into a TestCase for Visual Studio, - /// using the best method available according to the exact - /// type passed and caching results for efficiency. - /// - TestCase ConvertTestCase(NUnitDiscoveryTestCase testNode); + _navigationDataProvider?.Dispose(); } - public interface ITestConverterXml : ITestConverterCommon + public IDictionary TraitsCache { get; } + + #region Public Methods + + /// + /// Converts an NUnit test into a TestCase for Visual Studio, + /// using the best method available according to the exact + /// type passed and caching results for efficiency. + /// + public TestCase ConvertTestCase(NUnitEventTestCase testNode) { - TestCase ConvertTestCase(NUnitEventTestCase nUnitEventTestCase); + if (!testNode.IsTestCase) + throw new ArgumentException("The argument must be a test case", nameof(testNode)); + + // Return cached value if we have one + string id = testNode.Id; + if (_vsTestCaseMap.ContainsKey(id)) + return _vsTestCaseMap[id]; + + // Convert to VS TestCase and cache the result + var testCase = MakeTestCaseFromXmlNode(testNode); + _vsTestCaseMap.Add(id, testCase); + return testCase; } - public sealed class TestConverterForXml : IDisposable, ITestConverterXml + public TestCase GetCachedTestCase(string id) { - private readonly ITestLogger _logger; - private readonly Dictionary _vsTestCaseMap; - private readonly string _sourceAssembly; - private readonly NavigationDataProvider _navigationDataProvider; - private bool CollectSourceInformation => adapterSettings.CollectSourceInformation; - private readonly IAdapterSettings adapterSettings; + if (_vsTestCaseMap.ContainsKey(id)) + return _vsTestCaseMap[id]; + + _logger.Warning("Test " + id + " not found in cache"); + return null; + } + private static readonly string NL = Environment.NewLine; - public TestConverterForXml(ITestLogger logger, string sourceAssembly, IAdapterSettings settings) - { - adapterSettings = settings; - _logger = logger; - _sourceAssembly = sourceAssembly; - _vsTestCaseMap = []; - TraitsCache = new Dictionary(); + public TestResultSet GetVsTestResults(INUnitTestEventTestCase resultNode, ICollection outputNodes) + { + var results = new List(); + + var testCaseResult = GetBasicResult(resultNode, outputNodes); - if (CollectSourceInformation) + if (testCaseResult != null) + { + switch (testCaseResult.Outcome) { - _navigationDataProvider = new NavigationDataProvider(sourceAssembly, logger); + case TestOutcome.Failed: + case TestOutcome.NotFound: + { + testCaseResult.ErrorMessage = resultNode.Failure?.Message; + testCaseResult.ErrorStackTrace = resultNode.FailureStackTrace; + + break; + } + case TestOutcome.Skipped: + case TestOutcome.None: + testCaseResult.ErrorMessage = resultNode.ReasonMessage; + testCaseResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, resultNode.ReasonMessage)); + break; + default: + { + if (adapterSettings.ConsoleOut > 0 && !string.IsNullOrEmpty(resultNode.ReasonMessage)) + testCaseResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, resultNode.ReasonMessage)); + break; + } } + + results.Add(testCaseResult); } - public void Dispose() + if (results.Count == 0) { - _navigationDataProvider?.Dispose(); + var result = MakeTestResultFromLegacyXmlNode(resultNode, outputNodes); + if (result != null) + results.Add(result); } + return new TestResultSet { TestCaseResult = testCaseResult, TestResults = results, ConsoleOutput = resultNode.Output }; + } - public IDictionary TraitsCache { get; } + public struct TestResultSet + { + public IList TestResults { get; set; } + public TestResult TestCaseResult { get; set; } - #region Public Methods + public string ConsoleOutput { get; set; } + } - /// - /// Converts an NUnit test into a TestCase for Visual Studio, - /// using the best method available according to the exact - /// type passed and caching results for efficiency. - /// - public TestCase ConvertTestCase(NUnitEventTestCase testNode) - { - if (!testNode.IsTestCase) - throw new ArgumentException("The argument must be a test case", nameof(testNode)); - - // Return cached value if we have one - string id = testNode.Id; - if (_vsTestCaseMap.ContainsKey(id)) - return _vsTestCaseMap[id]; - - // Convert to VS TestCase and cache the result - var testCase = MakeTestCaseFromXmlNode(testNode); - _vsTestCaseMap.Add(id, testCase); - return testCase; - } + #endregion - public TestCase GetCachedTestCase(string id) + #region Helper Methods + + /// + /// Makes a TestCase from an NUnit test, adding + /// navigation data if it can be found. + /// + private TestCase MakeTestCaseFromXmlNode(NUnitEventTestCase testNode) + { + string fullyQualifiedName = testNode.FullName; + if (adapterSettings.UseParentFQNForParametrizedTests) { - if (_vsTestCaseMap.ContainsKey(id)) - return _vsTestCaseMap[id]; + var parent = testNode.Parent; + if (parent != null && parent.IsParameterizedMethod) + { + var parameterizedTestFullName = parent.FullName; - _logger.Warning("Test " + id + " not found in cache"); - return null; - } + // VS expected FullyQualifiedName to be the actual class+type name,optionally with parameter types + // in parenthesis, but they must fit the pattern of a value returned by object.GetType(). + // It should _not_ include custom name or param values (just their types). + // However, the "fullname" from NUnit's file generation is the custom name of the test, so + // this code must convert from one to the other. + // Reference: https://github.com/microsoft/vstest-docs/blob/master/RFCs/0017-Managed-TestCase-Properties.md - private static readonly string NL = Environment.NewLine; + // Using the nUnit-provided "fullname" will cause failures at test execution time due to + // the FilterExpressionWrapper not being able to parse the test names passed-in as filters. - public TestResultSet GetVsTestResults(INUnitTestEventTestCase resultNode, ICollection outputNodes) - { - var results = new List(); + // To resolve this issue, for parameterized tests (which are the only tests that allow custom names), + // the parent node's "fullname" value is used instead. This is the name of the actual test method + // and will allow the filtering to work as expected. - var testCaseResult = GetBasicResult(resultNode, outputNodes); + // Note that this also means you can no longer select a single tests of these to run. + // When you do that, all tests within the parent node will be executed - if (testCaseResult != null) - { - switch (testCaseResult.Outcome) + if (!string.IsNullOrEmpty(parameterizedTestFullName)) { - case TestOutcome.Failed: - case TestOutcome.NotFound: - { - testCaseResult.ErrorMessage = resultNode.Failure?.Message; - testCaseResult.ErrorStackTrace = resultNode.FailureStackTrace; - - break; - } - case TestOutcome.Skipped: - case TestOutcome.None: - testCaseResult.ErrorMessage = resultNode.ReasonMessage; - testCaseResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, resultNode.ReasonMessage)); - break; - default: - { - if (adapterSettings.ConsoleOut > 0 && !string.IsNullOrEmpty(resultNode.ReasonMessage)) - testCaseResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, resultNode.ReasonMessage)); - break; - } + fullyQualifiedName = parameterizedTestFullName; } - - results.Add(testCaseResult); - } - - if (results.Count == 0) - { - var result = MakeTestResultFromLegacyXmlNode(resultNode, outputNodes); - if (result != null) - results.Add(result); } - return new TestResultSet { TestCaseResult = testCaseResult, TestResults = results, ConsoleOutput = resultNode.Output }; } - public struct TestResultSet + var testCase = new TestCase( + fullyQualifiedName, + new Uri(NUnitTestAdapter.ExecutorUri), + _sourceAssembly) { - public IList TestResults { get; set; } - public TestResult TestCaseResult { get; set; } - - public string ConsoleOutput { get; set; } + DisplayName = CreateDisplayName(fullyQualifiedName, testNode.Name), + CodeFilePath = null, + LineNumber = 0, + }; + if (adapterSettings.UseNUnitIdforTestCaseId) + { + var id = testNode.Id; + testCase.Id = EqtHash.GuidFromString(id); } - - #endregion - - #region Helper Methods - - /// - /// Makes a TestCase from an NUnit test, adding - /// navigation data if it can be found. - /// - private TestCase MakeTestCaseFromXmlNode(NUnitEventTestCase testNode) + if (CollectSourceInformation && _navigationDataProvider != null) { - string fullyQualifiedName = testNode.FullName; - if (adapterSettings.UseParentFQNForParametrizedTests) + if (!CheckCodeFilePathOverride()) { - var parent = testNode.Parent; - if (parent != null && parent.IsParameterizedMethod) - { - var parameterizedTestFullName = parent.FullName; + var className = testNode.ClassName; + var methodName = testNode.MethodName; - // VS expected FullyQualifiedName to be the actual class+type name,optionally with parameter types - // in parenthesis, but they must fit the pattern of a value returned by object.GetType(). - // It should _not_ include custom name or param values (just their types). - // However, the "fullname" from NUnit's file generation is the custom name of the test, so - // this code must convert from one to the other. - // Reference: https://github.com/microsoft/vstest-docs/blob/master/RFCs/0017-Managed-TestCase-Properties.md - - // Using the nUnit-provided "fullname" will cause failures at test execution time due to - // the FilterExpressionWrapper not being able to parse the test names passed-in as filters. + var navData = _navigationDataProvider.GetNavigationData(className, methodName); + if (navData.IsValid) + { + testCase.CodeFilePath = navData.FilePath; + testCase.LineNumber = navData.LineNumber; + } + } + } + else + { + _ = CheckCodeFilePathOverride(); + } - // To resolve this issue, for parameterized tests (which are the only tests that allow custom names), - // the parent node's "fullname" value is used instead. This is the name of the actual test method - // and will allow the filtering to work as expected. + testCase.AddTraitsFromXmlTestNode(testNode, TraitsCache, _logger, adapterSettings); - // Note that this also means you can no longer select a single tests of these to run. - // When you do that, all tests within the parent node will be executed + return testCase; - if (!string.IsNullOrEmpty(parameterizedTestFullName)) - { - fullyQualifiedName = parameterizedTestFullName; - } - } - } + bool CheckCodeFilePathOverride() + { + var codeFilePath = testNode.Properties.FirstOrDefault(p => p.Name == "_CodeFilePath"); + if (codeFilePath == null) + return false; + testCase.CodeFilePath = codeFilePath.Value; + var lineNumber = testNode.Properties.FirstOrDefault(p => p.Name == "_LineNumber"); + testCase.LineNumber = lineNumber != null ? Convert.ToInt32(lineNumber.Value) : 1; + return true; + } + } - var testCase = new TestCase( - fullyQualifiedName, - new Uri(NUnitTestAdapter.ExecutorUri), - _sourceAssembly) + private string CreateDisplayName(string fullyQualifiedName, string testNodeName) + { + return adapterSettings.FreakMode + ? "N:Name -> MS:DisplayName (default)" + : adapterSettings.DisplayName switch { - DisplayName = CreateDisplayName(fullyQualifiedName, testNode.Name), - CodeFilePath = null, - LineNumber = 0, + DisplayNameOptions.Name => testNodeName, + DisplayNameOptions.FullName => fullyQualifiedName, + DisplayNameOptions.FullNameSep => + fullyQualifiedName.Replace('.', adapterSettings.FullnameSeparator), + _ => throw new ArgumentOutOfRangeException(), }; - if (adapterSettings.UseNUnitIdforTestCaseId) - { - var id = testNode.Id; - testCase.Id = EqtHash.GuidFromString(id); - } - if (CollectSourceInformation && _navigationDataProvider != null) - { - if (!CheckCodeFilePathOverride()) - { - var className = testNode.ClassName; - var methodName = testNode.MethodName; - - var navData = _navigationDataProvider.GetNavigationData(className, methodName); - if (navData.IsValid) - { - testCase.CodeFilePath = navData.FilePath; - testCase.LineNumber = navData.LineNumber; - } - } - } - else - { - _ = CheckCodeFilePathOverride(); - } - - testCase.AddTraitsFromXmlTestNode(testNode, TraitsCache, _logger, adapterSettings); + } - return testCase; + private VSTestResult MakeTestResultFromLegacyXmlNode(INUnitTestEventTestCase resultNode, IEnumerable outputNodes) + { + var ourResult = GetBasicResult(resultNode, outputNodes); + if (ourResult == null) + return null; - bool CheckCodeFilePathOverride() - { - var codeFilePath = testNode.Properties.FirstOrDefault(p => p.Name == "_CodeFilePath"); - if (codeFilePath == null) - return false; - testCase.CodeFilePath = codeFilePath.Value; - var lineNumber = testNode.Properties.FirstOrDefault(p => p.Name == "_LineNumber"); - testCase.LineNumber = lineNumber != null ? Convert.ToInt32(lineNumber.Value) : 1; - return true; - } - } + string message = resultNode.HasFailure + ? resultNode.Failure.Message + : resultNode.HasReason + ? resultNode.ReasonMessage + : null; - private string CreateDisplayName(string fullyQualifiedName, string testNodeName) + // If we're running in the IDE, remove any caret line from the message + // since it will be displayed using a variable font and won't make sense. + if (!string.IsNullOrEmpty(message) && NUnitTestAdapter.IsRunningUnderIde) { - return adapterSettings.FreakMode - ? "N:Name -> MS:DisplayName (default)" - : adapterSettings.DisplayName switch - { - DisplayNameOptions.Name => testNodeName, - DisplayNameOptions.FullName => fullyQualifiedName, - DisplayNameOptions.FullNameSep => - fullyQualifiedName.Replace('.', adapterSettings.FullnameSeparator), - _ => throw new ArgumentOutOfRangeException(), - }; + string pattern = NL + " -*\\^" + NL; + message = Regex.Replace(message, pattern, NL, RegexOptions.Multiline); } - private VSTestResult MakeTestResultFromLegacyXmlNode(INUnitTestEventTestCase resultNode, IEnumerable outputNodes) - { - var ourResult = GetBasicResult(resultNode, outputNodes); - if (ourResult == null) - return null; - - string message = resultNode.HasFailure - ? resultNode.Failure.Message - : resultNode.HasReason - ? resultNode.ReasonMessage - : null; - - // If we're running in the IDE, remove any caret line from the message - // since it will be displayed using a variable font and won't make sense. - if (!string.IsNullOrEmpty(message) && NUnitTestAdapter.IsRunningUnderIde) - { - string pattern = NL + " -*\\^" + NL; - message = Regex.Replace(message, pattern, NL, RegexOptions.Multiline); - } + ourResult.ErrorMessage = message; + ourResult.ErrorStackTrace = resultNode.Failure?.Stacktrace; - ourResult.ErrorMessage = message; - ourResult.ErrorStackTrace = resultNode.Failure?.Stacktrace; + return ourResult; + } - return ourResult; - } + private VSTestResult GetBasicResult(INUnitTestEvent resultNode, IEnumerable outputNodes) + { + var vsTest = GetCachedTestCase(resultNode.Id); + if (vsTest == null) + return null; - private VSTestResult GetBasicResult(INUnitTestEvent resultNode, IEnumerable outputNodes) + var vsResult = new VSTestResult(vsTest) { - var vsTest = GetCachedTestCase(resultNode.Id); - if (vsTest == null) - return null; + DisplayName = vsTest.DisplayName, + Outcome = GetTestOutcome(resultNode), + Duration = resultNode.Duration + }; - var vsResult = new VSTestResult(vsTest) - { - DisplayName = vsTest.DisplayName, - Outcome = GetTestOutcome(resultNode), - Duration = resultNode.Duration - }; + var startTime = resultNode.StartTime(); + if (startTime.Ok) + vsResult.StartTime = startTime.Time; - var startTime = resultNode.StartTime(); - if (startTime.Ok) - vsResult.StartTime = startTime.Time; + var endTime = resultNode.EndTime(); + if (endTime.Ok) + vsResult.EndTime = endTime.Time; - var endTime = resultNode.EndTime(); - if (endTime.Ok) - vsResult.EndTime = endTime.Time; + // TODO: Remove this when NUnit provides a better duration + if (vsResult.Duration == TimeSpan.Zero && (vsResult.Outcome == TestOutcome.Passed || vsResult.Outcome == TestOutcome.Failed)) + vsResult.Duration = TimeSpan.FromTicks(1); - // TODO: Remove this when NUnit provides a better duration - if (vsResult.Duration == TimeSpan.Zero && (vsResult.Outcome == TestOutcome.Passed || vsResult.Outcome == TestOutcome.Failed)) - vsResult.Duration = TimeSpan.FromTicks(1); + vsResult.ComputerName = Environment.MachineName; - vsResult.ComputerName = Environment.MachineName; + FillResultFromOutputNodes(outputNodes, vsResult); - FillResultFromOutputNodes(outputNodes, vsResult); + // Add stdOut messages from TestFinished element to vstest result + var output = resultNode.Output; + if (!string.IsNullOrEmpty(output)) + vsResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, output)); - // Add stdOut messages from TestFinished element to vstest result - var output = resultNode.Output; - if (!string.IsNullOrEmpty(output)) - vsResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, output)); + var attachmentSet = ParseAttachments(resultNode); + if (attachmentSet.Attachments.Count > 0) + vsResult.Attachments.Add(attachmentSet); - var attachmentSet = ParseAttachments(resultNode); - if (attachmentSet.Attachments.Count > 0) - vsResult.Attachments.Add(attachmentSet); - - return vsResult; - } + return vsResult; + } - private static void FillResultFromOutputNodes(IEnumerable outputNodes, VSTestResult vsResult) + private static void FillResultFromOutputNodes(IEnumerable outputNodes, VSTestResult vsResult) + { + foreach (var output in outputNodes) { - foreach (var output in outputNodes) + if (output.IsNullOrEmptyStream || output.IsProgressStream) // Don't add progress streams as output { - if (output.IsNullOrEmptyStream || output.IsProgressStream) // Don't add progress streams as output - { - continue; - } - - // Add stdErr/Progress messages from TestOutputXml element to vstest result - vsResult.Messages.Add(new TestResultMessage( - output.IsErrorStream - ? TestResultMessage.StandardErrorCategory - : TestResultMessage.StandardOutCategory, output.Content)); + continue; } + + // Add stdErr/Progress messages from TestOutputXml element to vstest result + vsResult.Messages.Add(new TestResultMessage( + output.IsErrorStream + ? TestResultMessage.StandardErrorCategory + : TestResultMessage.StandardOutCategory, output.Content)); } + } + + /// + /// Looks for attachments in a results node and if any attachments are found they + /// are returned"/>. + /// + /// xml node for test result. + /// attachments to be added to the test, it will be empty if no attachments are found. + private AttachmentSet ParseAttachments(INUnitTestEvent resultNode) + { + const string fileUriScheme = "file://"; + var attachmentSet = new AttachmentSet(new Uri(NUnitTestAdapter.ExecutorUri), "Attachments"); - /// - /// Looks for attachments in a results node and if any attachments are found they - /// are returned"/>. - /// - /// xml node for test result. - /// attachments to be added to the test, it will be empty if no attachments are found. - private AttachmentSet ParseAttachments(INUnitTestEvent resultNode) + foreach (var attachment in resultNode.NUnitAttachments) // AttSelectNodes("attachments/attachment")) { - const string fileUriScheme = "file://"; - var attachmentSet = new AttachmentSet(new Uri(NUnitTestAdapter.ExecutorUri), "Attachments"); + var path = attachment.FilePath; // SelectSingleNode("filePath")?.InnerText ?? string.Empty; + var description = attachment.Description; // SelectSingleNode("description")?.InnerText; - foreach (var attachment in resultNode.NUnitAttachments) // AttSelectNodes("attachments/attachment")) + if (!(string.IsNullOrEmpty(path) || path.StartsWith(fileUriScheme, StringComparison.OrdinalIgnoreCase))) { - var path = attachment.FilePath; // SelectSingleNode("filePath")?.InnerText ?? string.Empty; - var description = attachment.Description; // SelectSingleNode("description")?.InnerText; - - if (!(string.IsNullOrEmpty(path) || path.StartsWith(fileUriScheme, StringComparison.OrdinalIgnoreCase))) - { - path = fileUriScheme + path; - } - - try - { - // We only support absolute paths since we dont lookup working directory here - // any problem with path will throw an exception - var fileUri = new Uri(path, UriKind.Absolute); - attachmentSet.Attachments.Add(new UriDataAttachment(fileUri, description)); - } - catch (UriFormatException ex) - { - _logger.Warning($"Ignoring attachment with path '{path}' due to problem with path: {ex.Message}"); - } - catch (Exception ex) - { - _logger.Warning($"Ignoring attachment with path '{path}': {ex.Message}."); - } + path = fileUriScheme + path; } - return attachmentSet; + try + { + // We only support absolute paths since we dont lookup working directory here + // any problem with path will throw an exception + var fileUri = new Uri(path, UriKind.Absolute); + attachmentSet.Attachments.Add(new UriDataAttachment(fileUri, description)); + } + catch (UriFormatException ex) + { + _logger.Warning($"Ignoring attachment with path '{path}' due to problem with path: {ex.Message}"); + } + catch (Exception ex) + { + _logger.Warning($"Ignoring attachment with path '{path}': {ex.Message}."); + } } - // Public for testing - public TestOutcome GetTestOutcome(INUnitTestEvent resultNode) + return attachmentSet; + } + + // Public for testing + public TestOutcome GetTestOutcome(INUnitTestEvent resultNode) + { + return resultNode.Result() switch { - return resultNode.Result() switch - { - NUnitTestEvent.ResultType.Success => TestOutcome.Passed, - NUnitTestEvent.ResultType.Failed => TestOutcome.Failed, - NUnitTestEvent.ResultType.Skipped => (resultNode.IsIgnored ? TestOutcome.Skipped : TestOutcome.None), - NUnitTestEvent.ResultType.Warning => adapterSettings.MapWarningTo, - _ => TestOutcome.None - }; - } - #endregion + NUnitTestEvent.ResultType.Success => TestOutcome.Passed, + NUnitTestEvent.ResultType.Failed => TestOutcome.Failed, + NUnitTestEvent.ResultType.Skipped => (resultNode.IsIgnored ? TestOutcome.Skipped : TestOutcome.None), + NUnitTestEvent.ResultType.Warning => adapterSettings.MapWarningTo, + _ => TestOutcome.None + }; } + #endregion } \ No newline at end of file diff --git a/src/NUnitTestAdapter/TestFilterConverter/TestFilterParser.cs b/src/NUnitTestAdapter/TestFilterConverter/TestFilterParser.cs index 94470833..10c70216 100644 --- a/src/NUnitTestAdapter/TestFilterConverter/TestFilterParser.cs +++ b/src/NUnitTestAdapter/TestFilterConverter/TestFilterParser.cs @@ -29,32 +29,32 @@ // Missing XML Docs #pragma warning disable 1591 -namespace NUnit.VisualStudio.TestAdapter.TestFilterConverter +namespace NUnit.VisualStudio.TestAdapter.TestFilterConverter; + +public class TestFilterParser { - public class TestFilterParser - { - private Tokenizer _tokenizer; + private Tokenizer _tokenizer; - private static readonly Token LPAREN = new(TokenKind.Symbol, "("); - private static readonly Token RPAREN = new(TokenKind.Symbol, ")"); - private static readonly Token AND_OP = new(TokenKind.Symbol, "&"); - private static readonly Token OR_OP = new(TokenKind.Symbol, "|"); - private static readonly Token NOT_OP = new(TokenKind.Symbol, "!"); + private static readonly Token LPAREN = new(TokenKind.Symbol, "("); + private static readonly Token RPAREN = new(TokenKind.Symbol, ")"); + private static readonly Token AND_OP = new(TokenKind.Symbol, "&"); + private static readonly Token OR_OP = new(TokenKind.Symbol, "|"); + private static readonly Token NOT_OP = new(TokenKind.Symbol, "!"); - private static readonly Token EQ_OP = new(TokenKind.Symbol, "="); - private static readonly Token NE_OP = new(TokenKind.Symbol, "!="); - private static readonly Token CONTAINS_OP = new(TokenKind.Symbol, "~"); - private static readonly Token NOTCONTAINS_OP = new(TokenKind.Symbol, "!~"); + private static readonly Token EQ_OP = new(TokenKind.Symbol, "="); + private static readonly Token NE_OP = new(TokenKind.Symbol, "!="); + private static readonly Token CONTAINS_OP = new(TokenKind.Symbol, "~"); + private static readonly Token NOTCONTAINS_OP = new(TokenKind.Symbol, "!~"); - private static readonly Token[] AND_OPS = { AND_OP }; - private static readonly Token[] OR_OPS = { OR_OP }; - private static readonly Token[] EQ_OPS = { EQ_OP }; - private static readonly Token[] REL_OPS = { EQ_OP, NE_OP, CONTAINS_OP, NOTCONTAINS_OP }; + private static readonly Token[] AND_OPS = { AND_OP }; + private static readonly Token[] OR_OPS = { OR_OP }; + private static readonly Token[] EQ_OPS = { EQ_OP }; + private static readonly Token[] REL_OPS = { EQ_OP, NE_OP, CONTAINS_OP, NOTCONTAINS_OP }; - private static readonly Token EOF = new(TokenKind.Eof); + private static readonly Token EOF = new(TokenKind.Eof); - public string Parse(string input) - { + public string Parse(string input) + { _tokenizer = new Tokenizer(input); if (_tokenizer.LookAhead == EOF) @@ -67,11 +67,11 @@ public string Parse(string input) return result; } - /// - /// Parse a single term or an or expression, returning the xml. - /// - public string ParseFilterExpression() - { + /// + /// Parse a single term or an or expression, returning the xml. + /// + public string ParseFilterExpression() + { var terms = new List { ParseFilterTerm() }; while (LookingAt(OR_OPS)) @@ -93,11 +93,11 @@ public string ParseFilterExpression() return sb.ToString(); } - /// - /// Parse a single element or an and expression and return the xml. - /// - public string ParseFilterTerm() - { + /// + /// Parse a single element or an and expression and return the xml. + /// + public string ParseFilterTerm() + { var elements = new List { ParseFilterCondition() }; while (LookingAt(AND_OPS)) @@ -119,12 +119,12 @@ public string ParseFilterTerm() return sb.ToString(); } - /// - /// Parse a single filter element such as a category expression - /// and return the xml representation of the filter. - /// - public string ParseFilterCondition() - { + /// + /// Parse a single filter element such as a category expression + /// and return the xml representation of the filter. + /// + public string ParseFilterCondition() + { if (LookingAt(LPAREN, NOT_OP)) return ParseExpressionInParentheses(); @@ -158,28 +158,28 @@ public string ParseFilterCondition() } } - private string UnEscape(string rhs) - { + private string UnEscape(string rhs) + { return rhs.Replace(@"\(", "(").Replace(@"\)", ")"); } - private static string EmitFullNameFilter(Token op, string value) - { + private static string EmitFullNameFilter(Token op, string value) + { return EmitFilter("test", op, value); } - private static string EmitCategoryFilter(Token op, string value) - { + private static string EmitCategoryFilter(Token op, string value) + { return EmitFilter("cat", op, value); } - private static string EmitNameFilter(Token op, string value) - { + private static string EmitNameFilter(Token op, string value) + { return EmitFilter("name", op, value); } - private static string EmitFilter(string lhs, Token op, string rhs) - { + private static string EmitFilter(string lhs, Token op, string rhs) + { rhs = EscapeRhsValue(op, rhs); if (op == EQ_OP) @@ -194,8 +194,8 @@ private static string EmitFilter(string lhs, Token op, string rhs) throw new TestFilterParserException($"Invalid operator {op.Text} at position {op.Pos}"); } - private static string EmitPropertyFilter(Token op, string name, string value) - { + private static string EmitPropertyFilter(Token op, string name, string value) + { value = EscapeRhsValue(op, value); if (op == EQ_OP) @@ -210,16 +210,16 @@ private static string EmitPropertyFilter(Token op, string name, string value) throw new TestFilterParserException($"Invalid operator {op.Text} at position {op.Pos}"); } - private static string EscapeRhsValue(Token op, string rhs) - { + private static string EscapeRhsValue(Token op, string rhs) + { if (op == CONTAINS_OP || op == NOTCONTAINS_OP) rhs = EscapeRegexChars(rhs); return XmlEscape(rhs); } - private string ParseExpressionInParentheses() - { + private string ParseExpressionInParentheses() + { var op = Expect(LPAREN, NOT_OP); if (op == NOT_OP) Expect(LPAREN); @@ -234,9 +234,9 @@ private string ParseExpressionInParentheses() return result; } - // Require a token of one or more kinds - private Token Expect(params TokenKind[] kinds) - { + // Require a token of one or more kinds + private Token Expect(params TokenKind[] kinds) + { var token = NextToken(); if (kinds.Any(kind => token.Kind == kind)) @@ -247,9 +247,9 @@ private Token Expect(params TokenKind[] kinds) throw InvalidTokenError(token); } - // Require a token from a list of tokens - private Token Expect(params Token[] valid) - { + // Require a token from a list of tokens + private Token Expect(params Token[] valid) + { var token = NextToken(); if (valid.Any(item => token == item)) @@ -260,31 +260,31 @@ private Token Expect(params Token[] valid) throw InvalidTokenError(token); } - private Exception InvalidTokenError(Token token) - { + private Exception InvalidTokenError(Token token) + { return new TestFilterParserException(string.Format( $"Unexpected {token.Kind} '{token.Text}' at position {token.Pos} in selection expression.")); } - private Token LookAhead => _tokenizer.LookAhead; + private Token LookAhead => _tokenizer.LookAhead; - private bool LookingAt(params Token[] tokens) - { + private bool LookingAt(params Token[] tokens) + { return tokens.Any(token => LookAhead == token); } - private Token NextToken() - { + private Token NextToken() + { return _tokenizer.NextToken(); } - // Since we use a regular expression to implement - // the contains operator, we must escape all chars - // that have a special meaning in a regex. - private const string REGEX_CHARS = @".[]{}()*+?|^$\"; + // Since we use a regular expression to implement + // the contains operator, we must escape all chars + // that have a special meaning in a regex. + private const string REGEX_CHARS = @".[]{}()*+?|^$\"; - private static string EscapeRegexChars(string input) - { + private static string EscapeRegexChars(string input) + { var sb = new StringBuilder(); foreach (var c in input) @@ -297,10 +297,10 @@ private static string EscapeRegexChars(string input) return sb.ToString(); } - // Since the NUnit filter is represented in XML - // contents of each element must be escaped. - private static string XmlEscape(string text) - { + // Since the NUnit filter is represented in XML + // contents of each element must be escaped. + private static string XmlEscape(string text) + { return text .Replace("&", "&") .Replace("\"", """) @@ -308,5 +308,4 @@ private static string XmlEscape(string text) .Replace(">", ">") .Replace("'", "'"); } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/TestFilterConverter/TestFilterParserException.cs b/src/NUnitTestAdapter/TestFilterConverter/TestFilterParserException.cs index 81004f23..f5915df5 100644 --- a/src/NUnitTestAdapter/TestFilterConverter/TestFilterParserException.cs +++ b/src/NUnitTestAdapter/TestFilterConverter/TestFilterParserException.cs @@ -27,35 +27,34 @@ using System.Runtime.Serialization; #endif -namespace NUnit.VisualStudio.TestAdapter.TestFilterConverter +namespace NUnit.VisualStudio.TestAdapter.TestFilterConverter; + +/// +/// TestSelectionParserException is thrown when an error +/// is found while parsing the selection expression. +/// +#if !NETSTANDARD1_6 +[Serializable] +#endif +public class TestFilterParserException : Exception { /// - /// TestSelectionParserException is thrown when an error - /// is found while parsing the selection expression. + /// Initializes a new instance of the class. + /// Construct with a message. /// -#if !NETSTANDARD1_6 - [Serializable] -#endif - public class TestFilterParserException : Exception - { - /// - /// Initializes a new instance of the class. - /// Construct with a message. - /// - public TestFilterParserException(string message) : base(message) { } + public TestFilterParserException(string message) : base(message) { } - /// - /// Initializes a new instance of the class. - /// Construct with a message and inner exception. - /// - public TestFilterParserException(string message, Exception innerException) : base(message, innerException) { } + /// + /// Initializes a new instance of the class. + /// Construct with a message and inner exception. + /// + public TestFilterParserException(string message, Exception innerException) : base(message, innerException) { } #if !NETSTANDARD1_6 - /// - /// Initializes a new instance of the class. - /// Serialization constructor. - /// - public TestFilterParserException(SerializationInfo info, StreamingContext context) : base(info, context) { } + /// + /// Initializes a new instance of the class. + /// Serialization constructor. + /// + public TestFilterParserException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endif - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/TestFilterConverter/Tokenizer.cs b/src/NUnitTestAdapter/TestFilterConverter/Tokenizer.cs index be969b30..34d664b0 100644 --- a/src/NUnitTestAdapter/TestFilterConverter/Tokenizer.cs +++ b/src/NUnitTestAdapter/TestFilterConverter/Tokenizer.cs @@ -24,139 +24,139 @@ using System; using System.Text; -namespace NUnit.VisualStudio.TestAdapter.TestFilterConverter +namespace NUnit.VisualStudio.TestAdapter.TestFilterConverter; + +public enum TokenKind { - public enum TokenKind - { - Eof, - Word, - FQN, - String, // Unused - Symbol - } + Eof, + Word, + FQN, + String, // Unused + Symbol +} - public class Token - { - public Token(TokenKind kind) : this(kind, string.Empty) { } +public class Token +{ + public Token(TokenKind kind) : this(kind, string.Empty) { } - public Token(TokenKind kind, char ch) : this(kind, ch.ToString()) { } + public Token(TokenKind kind, char ch) : this(kind, ch.ToString()) { } - public Token(TokenKind kind, string text) - { - Kind = kind; - Text = text; - } + public Token(TokenKind kind, string text) + { + Kind = kind; + Text = text; + } - public TokenKind Kind { get; } + public TokenKind Kind { get; } - public string Text { get; } + public string Text { get; } - public int Pos { get; set; } + public int Pos { get; set; } - #region Equality Overrides + #region Equality Overrides - public override bool Equals(object obj) => obj is Token token && this == token; + public override bool Equals(object obj) => obj is Token token && this == token; - public override int GetHashCode() - { - return Text.GetHashCode(); - } - - public override string ToString() - { - return Text != null - ? Kind + ":" + Text - : Kind.ToString(); - } - - public static bool operator ==(Token t1, Token t2) - { - bool t1Null = ReferenceEquals(t1, null); - bool t2Null = ReferenceEquals(t2, null); + public override int GetHashCode() + { + return Text.GetHashCode(); + } - return (t1Null && t2Null) || (!t1Null && !t2Null && (t1.Kind == t2.Kind && t1.Text == t2.Text)); - } + public override string ToString() + { + return Text != null + ? Kind + ":" + Text + : Kind.ToString(); + } - public static bool operator !=(Token t1, Token t2) => !(t1 == t2); + public static bool operator ==(Token t1, Token t2) + { + bool t1Null = ReferenceEquals(t1, null); + bool t2Null = ReferenceEquals(t2, null); - #endregion + return (t1Null && t2Null) || (!t1Null && !t2Null && (t1.Kind == t2.Kind && t1.Text == t2.Text)); } - /// - /// Tokenizer class performs lexical analysis for the TestSelectionParser. - /// It recognizes a very limited set of tokens: words, symbols and - /// quoted strings. This is sufficient for the simple DSL we use to - /// select which tests to run. - /// - public class Tokenizer - { - private readonly string input; - private int index; + public static bool operator !=(Token t1, Token t2) => !(t1 == t2); - private const char EOF_CHAR = '\0'; - private const string WORD_BREAK_CHARS = "=~!()&|"; - private readonly string[] dOubleCharSymbols = { "!=", "!~" }; + #endregion +} - private Token lookahead; +/// +/// Tokenizer class performs lexical analysis for the TestSelectionParser. +/// It recognizes a very limited set of tokens: words, symbols and +/// quoted strings. This is sufficient for the simple DSL we use to +/// select which tests to run. +/// +public class Tokenizer +{ + private readonly string input; + private int index; - public Tokenizer(string input) - { - this.input = input ?? throw new ArgumentNullException(nameof(input)); - index = 0; - } + private const char EOF_CHAR = '\0'; + private const string WORD_BREAK_CHARS = "=~!()&|"; + private readonly string[] dOubleCharSymbols = { "!=", "!~" }; - public Token LookAhead - { - get - { - if (lookahead == null) - lookahead = GetNextToken(); + private Token lookahead; - return lookahead; - } - } + public Tokenizer(string input) + { + this.input = input ?? throw new ArgumentNullException(nameof(input)); + index = 0; + } - public Token NextToken() + public Token LookAhead + { + get { - Token result = lookahead ?? GetNextToken(); - lookahead = null; - return result; + if (lookahead == null) + lookahead = GetNextToken(); + + return lookahead; } + } - private Token GetNextToken() - { - SkipBlanks(); + public Token NextToken() + { + Token result = lookahead ?? GetNextToken(); + lookahead = null; + return result; + } - var ch = NextChar; - int pos = index; + private Token GetNextToken() + { + SkipBlanks(); - switch (ch) - { - case EOF_CHAR: - return new Token(TokenKind.Eof) { Pos = pos }; - - // Single char symbols - case '(': - case ')': - case '~': - case '&': - case '|': - case '=': - GetChar(); - return new Token(TokenKind.Symbol, ch) { Pos = pos }; + var ch = NextChar; + int pos = index; - // Could be alone or start of a double char symbol - case '!': + switch (ch) + { + case EOF_CHAR: + return new Token(TokenKind.Eof) { Pos = pos }; + + // Single char symbols + case '(': + case ')': + case '~': + case '&': + case '|': + case '=': + GetChar(); + return new Token(TokenKind.Symbol, ch) { Pos = pos }; + + // Could be alone or start of a double char symbol + case '!': + GetChar(); + foreach (string dbl in dOubleCharSymbols) + { + if (ch != dbl[0] || NextChar != dbl[1]) + continue; GetChar(); - foreach (string dbl in dOubleCharSymbols) - { - if (ch != dbl[0] || NextChar != dbl[1]) - continue; - GetChar(); - return new Token(TokenKind.Symbol, dbl) { Pos = pos }; - } + return new Token(TokenKind.Symbol, dbl) { Pos = pos }; + } - return new Token(TokenKind.Symbol, ch); + return new Token(TokenKind.Symbol, ch); #if UNUSED case '"': @@ -165,25 +165,25 @@ private Token GetNextToken() return GetString(); #endif - default: - // This is the only place in the tokenizer where - // we don't know what we are getting at the start - // of the input string. To avoid modifying the - // overall design of the parser, the tokenizer - // will return either a Word or an FQN and the - // parser grammar has been changed to accept either - // one of them in certain places. - return GetWordOrFqn(); - } + default: + // This is the only place in the tokenizer where + // we don't know what we are getting at the start + // of the input string. To avoid modifying the + // overall design of the parser, the tokenizer + // will return either a Word or an FQN and the + // parser grammar has been changed to accept either + // one of them in certain places. + return GetWordOrFqn(); } + } - private bool IsWordChar(char c) - { - if (char.IsWhiteSpace(c) || c == EOF_CHAR) - return false; + private bool IsWordChar(char c) + { + if (char.IsWhiteSpace(c) || c == EOF_CHAR) + return false; - return WORD_BREAK_CHARS.IndexOf(c) < 0; - } + return WORD_BREAK_CHARS.IndexOf(c) < 0; + } #if UNUSED private Token GetWord() @@ -218,86 +218,85 @@ private Token GetString() } #endif - private Token GetWordOrFqn() - { - var sb = new StringBuilder(); - int pos = index; - - CollectWordChars(sb); + private Token GetWordOrFqn() + { + var sb = new StringBuilder(); + int pos = index; - if (NextChar != '(') - return new Token(TokenKind.Word, sb.ToString()) { Pos = pos }; + CollectWordChars(sb); - CollectBalancedParentheticalExpression(sb); + if (NextChar != '(') + return new Token(TokenKind.Word, sb.ToString()) { Pos = pos }; - while (NextChar == '+' || NextChar == '.') - { - sb.Append(GetChar()); - CollectWordChars(sb); - if (NextChar == '(') - CollectBalancedParentheticalExpression(sb); - } + CollectBalancedParentheticalExpression(sb); - return new Token(TokenKind.FQN, sb.ToString()) { Pos = pos }; - } - - private void CollectWordChars(StringBuilder sb) + while (NextChar == '+' || NextChar == '.') { - while (IsWordChar(NextChar)) - sb.Append(GetChar()); + sb.Append(GetChar()); + CollectWordChars(sb); + if (NextChar == '(') + CollectBalancedParentheticalExpression(sb); } - private void CollectBalancedParentheticalExpression(StringBuilder sb) + return new Token(TokenKind.FQN, sb.ToString()) { Pos = pos }; + } + + private void CollectWordChars(StringBuilder sb) + { + while (IsWordChar(NextChar)) + sb.Append(GetChar()); + } + + private void CollectBalancedParentheticalExpression(StringBuilder sb) + { + int depth = 0; + if (NextChar == '(') { - int depth = 0; - if (NextChar == '(') + do { - do - { - var c = GetChar(); - sb.Append(c); - if (c == '(') - ++depth; - else if (c == ')') - --depth; - else if (c == '"') - CollectQuotedString(sb); - } - while (depth > 0); + var c = GetChar(); + sb.Append(c); + if (c == '(') + ++depth; + else if (c == ')') + --depth; + else if (c == '"') + CollectQuotedString(sb); } + while (depth > 0); } + } - private void CollectQuotedString(StringBuilder sb) + private void CollectQuotedString(StringBuilder sb) + { + while (NextChar != EOF_CHAR) { - while (NextChar != EOF_CHAR) - { - var ch = GetChar(); + var ch = GetChar(); - if (ch == '\\') - ch = GetChar(); - else if (ch == '"') - break; - sb.Append(ch); - } - - sb.Append('"'); + if (ch == '\\') + ch = GetChar(); + else if (ch == '"') + break; + sb.Append(ch); } - /// - /// Get the next character in the input, consuming it. - /// - /// The next char. - private char GetChar() => index < input.Length ? input[index++] : EOF_CHAR; + sb.Append('"'); + } - /// - /// Peek ahead at the next character in input. - /// - private char NextChar => index < input.Length ? input[index] : EOF_CHAR; + /// + /// Get the next character in the input, consuming it. + /// + /// The next char. + private char GetChar() => index < input.Length ? input[index++] : EOF_CHAR; - private void SkipBlanks() - { - while (char.IsWhiteSpace(NextChar)) - index++; - } + /// + /// Peek ahead at the next character in input. + /// + private char NextChar => index < input.Length ? input[index] : EOF_CHAR; + + private void SkipBlanks() + { + while (char.IsWhiteSpace(NextChar)) + index++; } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/TestLogger.cs b/src/NUnitTestAdapter/TestLogger.cs index 79fd3915..cc10e33b 100644 --- a/src/NUnitTestAdapter/TestLogger.cs +++ b/src/NUnitTestAdapter/TestLogger.cs @@ -26,152 +26,136 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; -namespace NUnit.VisualStudio.TestAdapter -{ - public interface ITestLogger - { - void Error(string message); - void Error(string message, Exception ex); - void Warning(string message); - void Warning(string message, Exception ex); - void Info(string message); - int Verbosity { get; set; } - void Debug(string message); - } +namespace NUnit.VisualStudio.TestAdapter; - /// - /// TestLogger wraps an IMessageLogger and adds various - /// utility methods for sending messages. Since the - /// IMessageLogger is only provided when the discovery - /// and execution objects are called, we use two-phase - /// construction. Until Initialize is called, the logger - /// simply swallows all messages without sending them - /// anywhere. - /// - public class TestLogger : IMessageLogger, ITestLogger - { - private IAdapterSettings adapterSettings; - private const string EXCEPTION_FORMAT = "Exception {0}, {1}"; +public interface ITestLogger +{ + void Error(string message); + void Error(string message, Exception ex); + void Warning(string message); + void Warning(string message, Exception ex); + void Info(string message); + int Verbosity { get; set; } + void Debug(string message); +} - private IMessageLogger MessageLogger { get; } +/// +/// TestLogger wraps an IMessageLogger and adds various +/// utility methods for sending messages. Since the +/// IMessageLogger is only provided when the discovery +/// and execution objects are called, we use two-phase +/// construction. Until Initialize is called, the logger +/// simply swallows all messages without sending them +/// anywhere. +/// +public class TestLogger(IMessageLogger messageLogger) : IMessageLogger, ITestLogger +{ + private IAdapterSettings adapterSettings; + private const string ExceptionFormat = "Exception {0}, {1}"; - public int Verbosity { get; set; } + private IMessageLogger MessageLogger { get; } = messageLogger; - public TestLogger(IMessageLogger messageLogger) - { - MessageLogger = messageLogger; - } + public int Verbosity { get; set; } - public TestLogger InitSettings(IAdapterSettings settings) - { - adapterSettings = settings; - Verbosity = adapterSettings.Verbosity; - return this; - } + public TestLogger InitSettings(IAdapterSettings settings) + { + adapterSettings = settings; + Verbosity = adapterSettings.Verbosity; + return this; + } - #region Error Messages + #region Error Messages - public void Error(string message) - { - SendMessage(TestMessageLevel.Error, message); - } + public void Error(string message) + => SendMessage(TestMessageLevel.Error, message); - public void Error(string message, Exception ex) - { - SendMessage(TestMessageLevel.Error, message, ex); - } + public void Error(string message, Exception ex) + => SendMessage(TestMessageLevel.Error, message, ex); - #endregion + #endregion - #region Warning Messages + #region Warning Messages - public void Warning(string message) - { - SendMessage(TestMessageLevel.Warning, message); - } + public void Warning(string message) + => SendMessage(TestMessageLevel.Warning, message); - public void Warning(string message, Exception ex) - { - SendMessage(TestMessageLevel.Warning, message, ex); - } + public void Warning(string message, Exception ex) + => SendMessage(TestMessageLevel.Warning, message, ex); - #endregion + #endregion - #region Information Messages + #region Information Messages - public void Info(string message) - { - if (adapterSettings?.Verbosity >= 0) - SendMessage(TestMessageLevel.Informational, message); - } + public void Info(string message) + { + if (adapterSettings?.Verbosity >= 0) + SendMessage(TestMessageLevel.Informational, message); + } - #endregion + #endregion - #region Debug Messages + #region Debug Messages - public void Debug(string message) - { - if (adapterSettings?.Verbosity >= 5) - SendMessage(TestMessageLevel.Informational, message); - } + public void Debug(string message) + { + if (adapterSettings?.Verbosity >= 5) + SendMessage(TestMessageLevel.Informational, message); + } - #endregion + #endregion - #region SendMessage + #region SendMessage - public void SendMessage(TestMessageLevel testMessageLevel, string message) - { - MessageLogger?.SendMessage(testMessageLevel, message); - } + public void SendMessage(TestMessageLevel testMessageLevel, string message) + => MessageLogger?.SendMessage(testMessageLevel, message); - public void SendMessage(TestMessageLevel testMessageLevel, string message, Exception ex) + public void SendMessage(TestMessageLevel testMessageLevel, string message, Exception ex) + { + switch (Verbosity) { - switch (Verbosity) - { - case 0: - var type = ex.GetType(); - SendMessage(testMessageLevel, string.Format(EXCEPTION_FORMAT, type, message)); - SendMessage(testMessageLevel, ex.Message); - SendMessage(testMessageLevel, ex.StackTrace); - if (ex.InnerException != null) - { - SendMessage(testMessageLevel, $"InnerException: {ex.InnerException}"); - } - break; - - default: - SendMessage(testMessageLevel, message); - SendMessage(testMessageLevel, ex.ToString()); - SendMessage(testMessageLevel, ex.StackTrace); - break; - } + case 0: + var type = ex.GetType(); + SendMessage(testMessageLevel, string.Format(ExceptionFormat, type, message)); + SendMessage(testMessageLevel, ex.Message); + SendMessage(testMessageLevel, ex.StackTrace); + if (ex.InnerException != null) + { + SendMessage(testMessageLevel, $"InnerException: {ex.InnerException}"); + } + break; + + default: + SendMessage(testMessageLevel, message); + SendMessage(testMessageLevel, ex.ToString()); + SendMessage(testMessageLevel, ex.StackTrace); + break; } - #endregion + } + #endregion - #region SpecializedMessages - public void DebugRunfrom() - { + #region SpecializedMessages + public void DebugRunfrom() + { #if NET462 - string fw = ".Net Framework"; + string fw = ".Net Framework"; #else - string fw = ".Net/ .Net Core"; + string fw = ".Net/ .Net Core"; #endif - var assLoc = Assembly.GetExecutingAssembly().Location; - Debug($"{fw} adapter running from {assLoc}"); - Debug($"Current directory: {Environment.CurrentDirectory}"); - } + var assLoc = Assembly.GetExecutingAssembly().Location; + Debug($"{fw} adapter running from {assLoc}"); + Debug($"Current directory: {Environment.CurrentDirectory}"); + } - public void InfoNoTests(bool discoveryResultsHasNoNUnitTests, string assemblyPath) - { - Info(discoveryResultsHasNoNUnitTests - ? " NUnit couldn't find any tests in " + assemblyPath - : " NUnit failed to load " + assemblyPath); - } + public void InfoNoTests(bool discoveryResultsHasNoNUnitTests, string assemblyPath) + { + Info(discoveryResultsHasNoNUnitTests + ? " NUnit couldn't find any tests in " + assemblyPath + : " NUnit failed to load " + assemblyPath); + } - public void InfoNoTests(string assemblyPath) - { - Info($" NUnit couldn't find any tests in {assemblyPath}"); - } - #endregion + public void InfoNoTests(string assemblyPath) + { + Info($" NUnit couldn't find any tests in {assemblyPath}"); } -} + #endregion +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/TraitsFeature.cs b/src/NUnitTestAdapter/TraitsFeature.cs index 56d1cb02..bcfb4e87 100644 --- a/src/NUnitTestAdapter/TraitsFeature.cs +++ b/src/NUnitTestAdapter/TraitsFeature.cs @@ -27,130 +27,129 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +public static class TraitsFeature { - public static class TraitsFeature + public static void AddTrait(this TestCase testCase, string name, string value) { - public static void AddTrait(this TestCase testCase, string name, string value) - { - testCase?.Traits.Add(new Trait(name, value)); - } - private const string NUnitTestCategoryLabel = "Category"; + testCase?.Traits.Add(new Trait(name, value)); + } + private const string NUnitTestCategoryLabel = "Category"; + /// + /// Stores the information needed to initialize a + /// which can be inherited from an ancestor node during the conversion of test cases. + /// + public sealed class CachedTestCaseInfo + { /// - /// Stores the information needed to initialize a - /// which can be inherited from an ancestor node during the conversion of test cases. + /// Used to populate a test case’s collection. + /// Currently, the only effect this has is to add a Test Explorer grouping header + /// for each trait with the name “Name [Value]”, or for an empty value, “Name”. /// - public sealed class CachedTestCaseInfo - { - /// - /// Used to populate a test case’s collection. - /// Currently, the only effect this has is to add a Test Explorer grouping header - /// for each trait with the name “Name [Value]”, or for an empty value, “Name”. - /// - public List Traits { get; } = new (); - - /// - /// Used by ; does not affect the Test Explorer UI. - /// - public bool Explicit { get; set; } - - // Eventually, we might split out the Categories collection and make this - // an immutable struct. (https://github.com/nunit/nunit3-vs-adapter/pull/457) - } + public List Traits { get; } = new (); - public static void AddTraitsFromTestNode(this TestCase testCase, NUnitDiscoveryTestCase testNCase, - IDictionary traitsCache, ITestLogger logger, IAdapterSettings adapterSettings) - { - var ancestor = testNCase.Parent; - var key = ancestor?.Id; - var categoryList = new CategoryList(testCase, adapterSettings); - // Reading ancestor properties of a test-case node. And adding to the cache. - while (ancestor != null && !string.IsNullOrEmpty(key)) - { - AddingToCache(testCase, traitsCache, key, categoryList, ancestor, categoryList.ProcessTestCaseProperties); - ancestor = ancestor.Parent; - key = ancestor?.Id; - } + /// + /// Used by ; does not affect the Test Explorer UI. + /// + public bool Explicit { get; set; } - // No Need to store test-case properties in cache. - categoryList.ProcessTestCaseProperties(testNCase, false); - categoryList.UpdateCategoriesToVs(); - } + // Eventually, we might split out the Categories collection and make this + // an immutable struct. (https://github.com/nunit/nunit3-vs-adapter/pull/457) + } - private static void AddingToCache(TestCase testCase, IDictionary traitsCache, string key, CategoryList categoryList, T ancestor, Func, IEnumerable> processTestCaseProperties) + public static void AddTraitsFromTestNode(this TestCase testCase, NUnitDiscoveryTestCase testNCase, + IDictionary traitsCache, ITestLogger logger, IAdapterSettings adapterSettings) + { + var ancestor = testNCase.Parent; + var key = ancestor?.Id; + var categoryList = new CategoryList(testCase, adapterSettings); + // Reading ancestor properties of a test-case node. And adding to the cache. + while (ancestor != null && !string.IsNullOrEmpty(key)) { - if (traitsCache.ContainsKey(key)) - { - categoryList.AddRange(traitsCache[key].Traits.Where(o => o.Name == NUnitTestCategoryLabel) - .Select(prop => prop.Value).ToList()); - - if (traitsCache[key].Explicit) - testCase.SetPropertyValue(CategoryList.NUnitExplicitProperty, true); - - var traitsList = traitsCache[key].Traits.Where(o => o.Name != NUnitTestCategoryLabel).ToList(); - if (traitsList.Count > 0) - testCase.Traits.AddRange(traitsList); - } - else - { - processTestCaseProperties(ancestor, true, key, traitsCache); - // Adding entry to dictionary, so that we will not make SelectNodes call again. - if (categoryList.LastNodeListCount == 0 && !traitsCache.ContainsKey(key)) - { - traitsCache[key] = new CachedTestCaseInfo(); - } - } + AddingToCache(testCase, traitsCache, key, categoryList, ancestor, categoryList.ProcessTestCaseProperties); + ancestor = ancestor.Parent; + key = ancestor?.Id; } - public static void AddTraitsFromXmlTestNode(this TestCase testCase, NUnitEventTestCase testNCase, - IDictionary traitsCache, ITestLogger logger, IAdapterSettings adapterSettings) - { - var ancestor = testNCase.Parent; - var key = ancestor?.Id; - var categoryList = new CategoryList(testCase, adapterSettings); - // Reading ancestor properties of a test-case node. And adding to the cache. - while (ancestor != null && key != null) - { - AddingToCache(testCase, traitsCache, key, categoryList, ancestor, categoryList.ProcessTestCaseProperties); - ancestor = ancestor.Parent; - key = ancestor?.Id; - } + // No Need to store test-case properties in cache. + categoryList.ProcessTestCaseProperties(testNCase, false); + categoryList.UpdateCategoriesToVs(); + } - // No Need to store test-case properties in cache. - categoryList.ProcessTestCaseProperties(testNCase, false); - categoryList.UpdateCategoriesToVs(); - } + private static void AddingToCache(TestCase testCase, IDictionary traitsCache, string key, CategoryList categoryList, T ancestor, Func, IEnumerable> processTestCaseProperties) + { + if (traitsCache.ContainsKey(key)) + { + categoryList.AddRange(traitsCache[key].Traits.Where(o => o.Name == NUnitTestCategoryLabel) + .Select(prop => prop.Value).ToList()); + if (traitsCache[key].Explicit) + testCase.SetPropertyValue(CategoryList.NUnitExplicitProperty, true); - public static IEnumerable GetTraits(this TestCase testCase) + var traitsList = traitsCache[key].Traits.Where(o => o.Name != NUnitTestCategoryLabel).ToList(); + if (traitsList.Count > 0) + testCase.Traits.AddRange(traitsList); + } + else { - var traits = new List(); - - if (testCase?.Traits != null) + processTestCaseProperties(ancestor, true, key, traitsCache); + // Adding entry to dictionary, so that we will not make SelectNodes call again. + if (categoryList.LastNodeListCount == 0 && !traitsCache.ContainsKey(key)) { - traits.AddRange(from trait in testCase.Traits let name = trait.Name let value = trait.Value select new NTrait(name, value)); + traitsCache[key] = new CachedTestCaseInfo(); } - return traits; } + } - public static IEnumerable GetCategories(this TestCase testCase) + public static void AddTraitsFromXmlTestNode(this TestCase testCase, NUnitEventTestCase testNCase, + IDictionary traitsCache, ITestLogger logger, IAdapterSettings adapterSettings) + { + var ancestor = testNCase.Parent; + var key = ancestor?.Id; + var categoryList = new CategoryList(testCase, adapterSettings); + // Reading ancestor properties of a test-case node. And adding to the cache. + while (ancestor != null && key != null) { - var categories = testCase.GetPropertyValue(CategoryList.NUnitTestCategoryProperty) as string[]; - return categories; + AddingToCache(testCase, traitsCache, key, categoryList, ancestor, categoryList.ProcessTestCaseProperties); + ancestor = ancestor.Parent; + key = ancestor?.Id; } + + // No Need to store test-case properties in cache. + categoryList.ProcessTestCaseProperties(testNCase, false); + categoryList.UpdateCategoriesToVs(); } - public class NTrait + + public static IEnumerable GetTraits(this TestCase testCase) { - public string Name { get; } - public string Value { get; } + var traits = new List(); - public NTrait(string name, string value) + if (testCase?.Traits != null) { - Name = name; - Value = value; + traits.AddRange(from trait in testCase.Traits let name = trait.Name let value = trait.Value select new NTrait(name, value)); } + return traits; + } + + public static IEnumerable GetCategories(this TestCase testCase) + { + var categories = testCase.GetPropertyValue(CategoryList.NUnitTestCategoryProperty) as string[]; + return categories; } } + +public class NTrait +{ + public string Name { get; } + public string Value { get; } + + public NTrait(string name, string value) + { + Name = name; + Value = value; + } +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/TryParse.cs b/src/NUnitTestAdapter/TryParse.cs index 31ac7a14..358a8d87 100644 --- a/src/NUnitTestAdapter/TryParse.cs +++ b/src/NUnitTestAdapter/TryParse.cs @@ -1,15 +1,15 @@ using System; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +/// +/// Need this just because we're still on .net 3.5 and it don't have TryParse :-(. +/// +public static class TryParse { - /// - /// Need this just because we're still on .net 3.5 and it don't have TryParse :-(. - /// - public static class TryParse + public static bool EnumTryParse(string input, out T result) + where T : Enum { - public static bool EnumTryParse(string input, out T result) - where T : Enum - { result = default; if (string.IsNullOrEmpty(input)) return false; @@ -23,5 +23,4 @@ public static bool EnumTryParse(string input, out T result) return false; } } - } } \ No newline at end of file diff --git a/src/NUnitTestAdapter/VsTestFilter.cs b/src/NUnitTestAdapter/VsTestFilter.cs index 9d3d61d9..0439b408 100644 --- a/src/NUnitTestAdapter/VsTestFilter.cs +++ b/src/NUnitTestAdapter/VsTestFilter.cs @@ -27,203 +27,202 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; -namespace NUnit.VisualStudio.TestAdapter -{ - using System.Collections; - // ReSharper disable once RedundantUsingDirective - using System.Reflection; // Needed for .net core 2.1 +namespace NUnit.VisualStudio.TestAdapter; - public interface IVsTestFilter - { - ITestCaseFilterExpression TfsTestCaseFilterExpression { get; } +using System.Collections; +// ReSharper disable once RedundantUsingDirective +using System.Reflection; // Needed for .net core 2.1 - bool IsEmpty { get; } +public interface IVsTestFilter +{ + ITestCaseFilterExpression TfsTestCaseFilterExpression { get; } - IEnumerable CheckFilter(IEnumerable tests); - } + bool IsEmpty { get; } - public abstract class VsTestFilter(IRunContext runContext) : IVsTestFilter + IEnumerable CheckFilter(IEnumerable tests); +} + +public abstract class VsTestFilter(IRunContext runContext) : IVsTestFilter +{ + /// + /// Supported properties for filtering. + /// + private static readonly Dictionary SupportedPropertiesCache; + private static readonly Dictionary SupportedTraitCache; + private static readonly Dictionary TraitPropertyMap; + private static readonly List SupportedProperties; + + static VsTestFilter() { - /// - /// Supported properties for filtering. - /// - private static readonly Dictionary SupportedPropertiesCache; - private static readonly Dictionary SupportedTraitCache; - private static readonly Dictionary TraitPropertyMap; - private static readonly List SupportedProperties; - - static VsTestFilter() + // Initialize the property cache + SupportedPropertiesCache = new Dictionary(StringComparer.OrdinalIgnoreCase) { - // Initialize the property cache - SupportedPropertiesCache = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["FullyQualifiedName"] = TestCaseProperties.FullyQualifiedName, - ["Name"] = TestCaseProperties.DisplayName, - ["TestCategory"] = CategoryList.NUnitTestCategoryProperty, - ["Category"] = CategoryList.NUnitTestCategoryProperty, - }; - // Initialize the trait cache - var priorityTrait = new NTrait("Priority", ""); - var categoryTrait = new NTrait("Category", ""); - SupportedTraitCache = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["Priority"] = priorityTrait, - ["TestCategory"] = categoryTrait, - ["Category"] = categoryTrait - }; - // Initialize the trait property map, since TFS doesn't know about traits - TraitPropertyMap = new Dictionary(new NTraitNameComparer()); - var priorityProperty = TestProperty.Find("Priority") ?? - TestProperty.Register("Priority", "Priority", typeof(string), typeof(TestCase)); - TraitPropertyMap[priorityTrait] = priorityProperty; - var categoryProperty = TestProperty.Find("TestCategory") ?? - TestProperty.Register("TestCategory", "TestCategory", typeof(string), typeof(TestCase)); - TraitPropertyMap[categoryTrait] = categoryProperty; - // Initialize a merged list of properties and traits to fool TFS Build to think traits is properties - SupportedProperties = [.. SupportedPropertiesCache.Keys, .. SupportedTraitCache.Keys]; - } + ["FullyQualifiedName"] = TestCaseProperties.FullyQualifiedName, + ["Name"] = TestCaseProperties.DisplayName, + ["TestCategory"] = CategoryList.NUnitTestCategoryProperty, + ["Category"] = CategoryList.NUnitTestCategoryProperty, + }; + // Initialize the trait cache + var priorityTrait = new NTrait("Priority", ""); + var categoryTrait = new NTrait("Category", ""); + SupportedTraitCache = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["Priority"] = priorityTrait, + ["TestCategory"] = categoryTrait, + ["Category"] = categoryTrait + }; + // Initialize the trait property map, since TFS doesn't know about traits + TraitPropertyMap = new Dictionary(new NTraitNameComparer()); + var priorityProperty = TestProperty.Find("Priority") ?? + TestProperty.Register("Priority", "Priority", typeof(string), typeof(TestCase)); + TraitPropertyMap[priorityTrait] = priorityProperty; + var categoryProperty = TestProperty.Find("TestCategory") ?? + TestProperty.Register("TestCategory", "TestCategory", typeof(string), typeof(TestCase)); + TraitPropertyMap[categoryTrait] = categoryProperty; + // Initialize a merged list of properties and traits to fool TFS Build to think traits is properties + SupportedProperties = [.. SupportedPropertiesCache.Keys, .. SupportedTraitCache.Keys]; + } - private ITestCaseFilterExpression testCaseFilterExpression; - public ITestCaseFilterExpression TfsTestCaseFilterExpression => - testCaseFilterExpression ??= runContext.GetTestCaseFilter(SupportedProperties, PropertyProvider); + private ITestCaseFilterExpression testCaseFilterExpression; + public ITestCaseFilterExpression TfsTestCaseFilterExpression => + testCaseFilterExpression ??= runContext.GetTestCaseFilter(SupportedProperties, PropertyProvider); - public bool IsEmpty => TfsTestCaseFilterExpression == null || TfsTestCaseFilterExpression.TestCaseFilterValue == string.Empty; + public bool IsEmpty => TfsTestCaseFilterExpression == null || TfsTestCaseFilterExpression.TestCaseFilterValue == string.Empty; - public IEnumerable CheckFilter(IEnumerable tests) - { - return tests.Where(CheckFilter).ToList(); - } + public IEnumerable CheckFilter(IEnumerable tests) + { + return tests.Where(CheckFilter).ToList(); + } - protected abstract bool CheckFilter(TestCase testCase); + protected abstract bool CheckFilter(TestCase testCase); - /// - /// Provides value of TestProperty corresponding to property name 'propertyName' as used in filter. - /// Return value should be a string for single valued property or array of strings for multivalued property (e.g. TestCategory). - /// - public static object PropertyValueProvider(TestCase currentTest, string propertyName) + /// + /// Provides value of TestProperty corresponding to property name 'propertyName' as used in filter. + /// Return value should be a string for single valued property or array of strings for multivalued property (e.g. TestCategory). + /// + public static object PropertyValueProvider(TestCase currentTest, string propertyName) + { + var testProperty = LocalPropertyProvider(propertyName); + if (testProperty != null) { - var testProperty = LocalPropertyProvider(propertyName); - if (testProperty != null) - { - // Test case might not have defined this property. In that case GetPropertyValue() - // would return default value. For filtering, if property is not defined return null. - if (currentTest.Properties.Contains(testProperty)) - { - return currentTest.GetPropertyValue(testProperty); - } - } - // Now it may be a trait, so we check the trait collection as well - var testTrait = TraitProvider(propertyName); - if (testTrait != null) + // Test case might not have defined this property. In that case GetPropertyValue() + // would return default value. For filtering, if property is not defined return null. + if (currentTest.Properties.Contains(testProperty)) { - var val = CachedTraitContainsDelegate(currentTest, testTrait.Name); - if (val.Length == 0) return null; - if (val.Length == 1) // Contains a single string - return val[0]; // return that string - return val; // otherwise return the whole array + return currentTest.GetPropertyValue(testProperty); } - return null; } - - static readonly Func CachedTraitContainsDelegate = TraitContains(); - - /// - /// TestCase: To be checked - /// traitName: Name of trait to be checked against. - /// - /// Value of trait. - private static Func TraitContains() + // Now it may be a trait, so we check the trait collection as well + var testTrait = TraitProvider(propertyName); + if (testTrait != null) { - return (testCase, traitName) => - { - var testCaseType = typeof(TestCase); - var property = testCaseType.GetTypeInfo().GetProperty("Traits"); - if (property == null) - return null; - var traits = property.GetValue(testCase, null) as IEnumerable; - return (from object t in traits let name = t.GetType().GetTypeInfo().GetProperty("Name").GetValue(t, null) as string where name == traitName select t.GetType().GetProperty("Value").GetValue(t, null) as string).ToArray(); - }; + var val = CachedTraitContainsDelegate(currentTest, testTrait.Name); + if (val.Length == 0) return null; + if (val.Length == 1) // Contains a single string + return val[0]; // return that string + return val; // otherwise return the whole array } + return null; + } - /// - /// Provides TestProperty for property name 'propertyName' as used in filter. - /// - public static TestProperty LocalPropertyProvider(string propertyName) - { - SupportedPropertiesCache.TryGetValue(propertyName, out var testProperty); - return testProperty; - } + static readonly Func CachedTraitContainsDelegate = TraitContains(); - public static TestProperty PropertyProvider(string propertyName) + /// + /// TestCase: To be checked + /// traitName: Name of trait to be checked against. + /// + /// Value of trait. + private static Func TraitContains() + { + return (testCase, traitName) => { - var testProperty = LocalPropertyProvider(propertyName); - if (testProperty != null) - { - return testProperty; - } - var testTrait = TraitProvider(propertyName); - return testTrait == null ? null : TraitPropertyMap.TryGetValue(testTrait, out var tp) ? tp : null; - } + var testCaseType = typeof(TestCase); + var property = testCaseType.GetTypeInfo().GetProperty("Traits"); + if (property == null) + return null; + var traits = property.GetValue(testCase, null) as IEnumerable; + return (from object t in traits let name = t.GetType().GetTypeInfo().GetProperty("Name").GetValue(t, null) as string where name == traitName select t.GetType().GetProperty("Value").GetValue(t, null) as string).ToArray(); + }; + } + + /// + /// Provides TestProperty for property name 'propertyName' as used in filter. + /// + public static TestProperty LocalPropertyProvider(string propertyName) + { + SupportedPropertiesCache.TryGetValue(propertyName, out var testProperty); + return testProperty; + } - public static NTrait TraitProvider(string traitName) + public static TestProperty PropertyProvider(string propertyName) + { + var testProperty = LocalPropertyProvider(propertyName); + if (testProperty != null) { - SupportedTraitCache.TryGetValue(traitName, out var testTrait); - return testTrait; + return testProperty; } + var testTrait = TraitProvider(propertyName); + return testTrait == null ? null : TraitPropertyMap.TryGetValue(testTrait, out var tp) ? tp : null; } - public static class VsTestFilterFactory + public static NTrait TraitProvider(string traitName) { - public static VsTestFilter CreateVsTestFilter(IAdapterSettings settings, IRunContext context) => - settings.DiscoveryMethod == DiscoveryMethod.Legacy - ? new VsTestFilterLegacy(context) : - settings.DesignMode - ? new VsTestFilterIde(context) - : new VsTestFilterNonIde(context); + SupportedTraitCache.TryGetValue(traitName, out var testTrait); + return testTrait; } +} - public class VsTestFilterLegacy(IRunContext runContext) : VsTestFilter(runContext) +public static class VsTestFilterFactory +{ + public static VsTestFilter CreateVsTestFilter(IAdapterSettings settings, IRunContext context) => + settings.DiscoveryMethod == DiscoveryMethod.Legacy + ? new VsTestFilterLegacy(context) : + settings.DesignMode + ? new VsTestFilterIde(context) + : new VsTestFilterNonIde(context); +} + +public class VsTestFilterLegacy(IRunContext runContext) : VsTestFilter(runContext) +{ + protected override bool CheckFilter(TestCase testCase) { - protected override bool CheckFilter(TestCase testCase) - { - var isExplicit = testCase.GetPropertyValue(CategoryList.NUnitExplicitProperty, false); + var isExplicit = testCase.GetPropertyValue(CategoryList.NUnitExplicitProperty, false); - return !isExplicit && TfsTestCaseFilterExpression?.MatchTestCase(testCase, p => PropertyValueProvider(testCase, p)) != false; - } + return !isExplicit && TfsTestCaseFilterExpression?.MatchTestCase(testCase, p => PropertyValueProvider(testCase, p)) != false; } +} - public class VsTestFilterIde(IRunContext runContext) : VsTestFilter(runContext) +public class VsTestFilterIde(IRunContext runContext) : VsTestFilter(runContext) +{ + protected override bool CheckFilter(TestCase testCase) { - protected override bool CheckFilter(TestCase testCase) - { - var isExplicit = testCase.GetPropertyValue(CategoryList.NUnitExplicitProperty, false); + var isExplicit = testCase.GetPropertyValue(CategoryList.NUnitExplicitProperty, false); - return !isExplicit && TfsTestCaseFilterExpression?.MatchTestCase(testCase, p => PropertyValueProvider(testCase, p)) != false; - } + return !isExplicit && TfsTestCaseFilterExpression?.MatchTestCase(testCase, p => PropertyValueProvider(testCase, p)) != false; } +} - public class VsTestFilterNonIde(IRunContext runContext) : VsTestFilter(runContext) +public class VsTestFilterNonIde(IRunContext runContext) : VsTestFilter(runContext) +{ + protected override bool CheckFilter(TestCase testCase) { - protected override bool CheckFilter(TestCase testCase) - { - return TfsTestCaseFilterExpression?.MatchTestCase(testCase, p => PropertyValueProvider(testCase, p)) != false; - } + return TfsTestCaseFilterExpression?.MatchTestCase(testCase, p => PropertyValueProvider(testCase, p)) != false; } +} - public class NTraitNameComparer : IEqualityComparer +public class NTraitNameComparer : IEqualityComparer +{ + public bool Equals(NTrait n, NTrait y) { - public bool Equals(NTrait n, NTrait y) - { - return n.Name == y.Name; - } + return n.Name == y.Name; + } - public int GetHashCode(NTrait obj) - { - return obj.Name.GetHashCode(); - } + public int GetHashCode(NTrait obj) + { + return obj.Name.GetHashCode(); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapter/XmlHelper.cs b/src/NUnitTestAdapter/XmlHelper.cs index ee3da2cd..10fa8337 100644 --- a/src/NUnitTestAdapter/XmlHelper.cs +++ b/src/NUnitTestAdapter/XmlHelper.cs @@ -25,34 +25,34 @@ using System.Globalization; using System.Xml; -namespace NUnit.VisualStudio.TestAdapter +namespace NUnit.VisualStudio.TestAdapter; + +/// +/// XmlHelper provides static methods for basic XML operations. +/// +public static class XmlHelper { /// - /// XmlHelper provides static methods for basic XML operations. + /// Creates a new top level element node. /// - public static class XmlHelper + /// The element name. + /// A new XmlNode. + public static XmlNode CreateTopLevelElement(string name) { - /// - /// Creates a new top level element node. - /// - /// The element name. - /// A new XmlNode. - public static XmlNode CreateTopLevelElement(string name) - { var doc = new XmlDocument(); doc.LoadXml("<" + name + "/>"); return doc.FirstChild; } - public static XmlNode CreateXmlNode(string xml) - { + public static XmlNode CreateXmlNode(string xml) + { var doc = new XmlDocument(); doc.LoadXml(xml); return doc.FirstChild; } - public static XmlNode ToXml(this string xml) - { + public static XmlNode ToXml(this string xml) + { var doc = new XmlDocument(); var fragment = doc.CreateDocumentFragment(); fragment.InnerXml = xml; @@ -60,68 +60,68 @@ public static XmlNode ToXml(this string xml) return doc.FirstChild; } - /// - /// Adds an attribute with a specified name and value to an existing XmlNode. - /// - /// The node to which the attribute should be added. - /// The name of the attribute. - /// The value of the attribute. - public static void AddAttribute(this XmlNode node, string name, string value) - { + /// + /// Adds an attribute with a specified name and value to an existing XmlNode. + /// + /// The node to which the attribute should be added. + /// The name of the attribute. + /// The value of the attribute. + public static void AddAttribute(this XmlNode node, string name, string value) + { var attr = node.OwnerDocument.CreateAttribute(name); attr.Value = value; node.Attributes.Append(attr); } - /// - /// Adds a new element as a child of an existing XmlNode and returns it. - /// - /// The node to which the element should be added. - /// The element name. - /// The newly created child element. - public static XmlNode AddElement(this XmlNode node, string name) - { + /// + /// Adds a new element as a child of an existing XmlNode and returns it. + /// + /// The node to which the element should be added. + /// The element name. + /// The newly created child element. + public static XmlNode AddElement(this XmlNode node, string name) + { XmlNode childNode = node.OwnerDocument.CreateElement(name); node.AppendChild(childNode); return childNode; } - /// - /// Adds the a new element as a child of an existing node and returns it. - /// A CDataSection is added to the new element using the data provided. - /// - /// The node to which the element should be added. - /// The element name. - /// The data for the CDataSection. - public static XmlNode AddElementWithCDataSection(this XmlNode node, string name, string data) - { + /// + /// Adds the a new element as a child of an existing node and returns it. + /// A CDataSection is added to the new element using the data provided. + /// + /// The node to which the element should be added. + /// The element name. + /// The data for the CDataSection. + public static XmlNode AddElementWithCDataSection(this XmlNode node, string name, string data) + { var childNode = node.AddElement(name); childNode.AppendChild(node.OwnerDocument.CreateCDataSection(data)); return childNode; } - #region Safe Attribute Access + #region Safe Attribute Access - /// - /// Gets the value of the given attribute. - /// - /// The result. - /// The name. - public static string GetAttribute(this XmlNode result, string name) - { + /// + /// Gets the value of the given attribute. + /// + /// The result. + /// The name. + public static string GetAttribute(this XmlNode result, string name) + { var attr = result.Attributes?[name]; return attr?.Value; } - /// - /// Gets the value of the given attribute as an int. - /// - /// The result. - /// The name. - /// The default value. - public static int GetAttribute(this XmlNode result, string name, int defaultValue) - { + /// + /// Gets the value of the given attribute as an int. + /// + /// The result. + /// The name. + /// The default value. + public static int GetAttribute(this XmlNode result, string name, int defaultValue) + { var attr = result.Attributes[name]; return attr == null @@ -129,14 +129,14 @@ public static int GetAttribute(this XmlNode result, string name, int defaultValu : int.Parse(attr.Value, CultureInfo.InvariantCulture); } - /// - /// Gets the value of the given attribute as a double. - /// - /// The result. - /// The name. - /// The default value. - public static double GetAttribute(this XmlNode result, string name, double defaultValue) - { + /// + /// Gets the value of the given attribute as a double. + /// + /// The result. + /// The name. + /// The default value. + public static double GetAttribute(this XmlNode result, string name, double defaultValue) + { var attr = result.Attributes[name]; return attr == null @@ -144,14 +144,14 @@ public static double GetAttribute(this XmlNode result, string name, double defau : double.Parse(attr.Value, CultureInfo.InvariantCulture); } - /// - /// Gets the value of the given attribute as a DateTime. - /// - /// The result. - /// The name. - /// The default value. - public static DateTime GetAttribute(this XmlNode result, string name, DateTime defaultValue) - { + /// + /// Gets the value of the given attribute as a DateTime. + /// + /// The result. + /// The name. + /// The default value. + public static DateTime GetAttribute(this XmlNode result, string name, DateTime defaultValue) + { string dateStr = GetAttribute(result, name); if (dateStr == null) return defaultValue; @@ -161,6 +161,5 @@ public static DateTime GetAttribute(this XmlNode result, string name, DateTime d : date; } - #endregion - } -} + #endregion +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/AdapterSettingsTests.cs b/src/NUnitTestAdapterTests/AdapterSettingsTests.cs index 118a4bb0..1d6c095b 100644 --- a/src/NUnitTestAdapterTests/AdapterSettingsTests.cs +++ b/src/NUnitTestAdapterTests/AdapterSettingsTests.cs @@ -32,343 +32,343 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Fakes; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +public class AdapterSettingsTests { - public class AdapterSettingsTests + private IAdapterSettings _settings; + + [SetUp] + public void SetUp() { - private IAdapterSettings _settings; + var testLogger = new TestLogger(new MessageLoggerStub()); + _settings = new AdapterSettings(testLogger); + testLogger.InitSettings(_settings); + } - [SetUp] - public void SetUp() - { - var testLogger = new TestLogger(new MessageLoggerStub()); - _settings = new AdapterSettings(testLogger); - testLogger.InitSettings(_settings); - } + [Test] + public void NullContextThrowsException() + { + Assert.That(() => _settings.Load((IDiscoveryContext)null), Throws.ArgumentNullException); + } - [Test] - public void NullContextThrowsException() - { - Assert.That(() => _settings.Load((IDiscoveryContext)null), Throws.ArgumentNullException); - } + [TestCase(null)] + [TestCase("")] + [TestCase("")] + public void DefaultSettings(string xml) + { + _settings.Load(xml); + Assert.Multiple(() => + { + Assert.That(_settings.MaxCpuCount, Is.EqualTo(-1)); + Assert.That(_settings.ResultsDirectory, Is.Null); + Assert.That(_settings.TargetFrameworkVersion, Is.Null); + Assert.That(_settings.TargetPlatform, Is.Null); + Assert.That(_settings.TestAdapterPaths, Is.Null); + Assert.That(_settings.CollectSourceInformation, Is.True); + Assert.That(_settings.TestProperties, Is.Empty); + Assert.That(_settings.InternalTraceLevelEnum, Is.EqualTo(Engine.InternalTraceLevel.Off)); + Assert.That(_settings.WorkDirectory, Is.Null); + Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(-1)); + Assert.That(_settings.DefaultTimeout, Is.EqualTo(0)); + Assert.That(_settings.Verbosity, Is.EqualTo(0)); + Assert.That(_settings.ShadowCopyFiles, Is.False); + Assert.That(_settings.UseVsKeepEngineRunning, Is.False); + Assert.That(_settings.BasePath, Is.Null); + Assert.That(_settings.PrivateBinPath, Is.Null); + Assert.That(_settings.RandomSeed, Is.Not.Null); + Assert.That(_settings.SynchronousEvents, Is.False); + Assert.That(_settings.DomainUsage, Is.Null); + Assert.That(_settings.InProcDataCollectorsAvailable, Is.False); + Assert.That(_settings.DisableAppDomain, Is.False); + Assert.That(_settings.DisableParallelization, Is.False); + Assert.That(_settings.DesignMode, Is.False); + Assert.That(_settings.UseTestOutputXml, Is.False); + Assert.That(_settings.NewOutputXmlFileForEachRun, Is.False); + }); + } - [TestCase(null)] - [TestCase("")] - [TestCase("")] - public void DefaultSettings(string xml) - { - _settings.Load(xml); - Assert.Multiple(() => - { - Assert.That(_settings.MaxCpuCount, Is.EqualTo(-1)); - Assert.That(_settings.ResultsDirectory, Is.Null); - Assert.That(_settings.TargetFrameworkVersion, Is.Null); - Assert.That(_settings.TargetPlatform, Is.Null); - Assert.That(_settings.TestAdapterPaths, Is.Null); - Assert.That(_settings.CollectSourceInformation, Is.True); - Assert.That(_settings.TestProperties, Is.Empty); - Assert.That(_settings.InternalTraceLevelEnum, Is.EqualTo(Engine.InternalTraceLevel.Off)); - Assert.That(_settings.WorkDirectory, Is.Null); - Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(-1)); - Assert.That(_settings.DefaultTimeout, Is.EqualTo(0)); - Assert.That(_settings.Verbosity, Is.EqualTo(0)); - Assert.That(_settings.ShadowCopyFiles, Is.False); - Assert.That(_settings.UseVsKeepEngineRunning, Is.False); - Assert.That(_settings.BasePath, Is.Null); - Assert.That(_settings.PrivateBinPath, Is.Null); - Assert.That(_settings.RandomSeed, Is.Not.Null); - Assert.That(_settings.SynchronousEvents, Is.False); - Assert.That(_settings.DomainUsage, Is.Null); - Assert.That(_settings.InProcDataCollectorsAvailable, Is.False); - Assert.That(_settings.DisableAppDomain, Is.False); - Assert.That(_settings.DisableParallelization, Is.False); - Assert.That(_settings.DesignMode, Is.False); - Assert.That(_settings.UseTestOutputXml, Is.False); - Assert.That(_settings.NewOutputXmlFileForEachRun, Is.False); - }); - } - - [Test] - public void ResultsDirectorySetting() - { - _settings.Load("./myresults"); - Assert.That(_settings.ResultsDirectory, Is.EqualTo("./myresults")); - } + [Test] + public void ResultsDirectorySetting() + { + _settings.Load("./myresults"); + Assert.That(_settings.ResultsDirectory, Is.EqualTo("./myresults")); + } - [Test] - public void MaxCpuCountSetting() - { - _settings.Load("42"); - Assert.That(_settings.MaxCpuCount, Is.EqualTo(42)); - } + [Test] + public void MaxCpuCountSetting() + { + _settings.Load("42"); + Assert.That(_settings.MaxCpuCount, Is.EqualTo(42)); + } - [Test] - public void TargetFrameworkVersionSetting() - { - _settings.Load("Framework45"); - Assert.That(_settings.TargetFrameworkVersion, Is.EqualTo("Framework45")); - } + [Test] + public void TargetFrameworkVersionSetting() + { + _settings.Load("Framework45"); + Assert.That(_settings.TargetFrameworkVersion, Is.EqualTo("Framework45")); + } - [Test] - public void TargetPlatformSetting() - { - _settings.Load("x86"); - Assert.That(_settings.TargetPlatform, Is.EqualTo("x86")); - } + [Test] + public void TargetPlatformSetting() + { + _settings.Load("x86"); + Assert.That(_settings.TargetPlatform, Is.EqualTo("x86")); + } - [Test] - public void TestAdapterPathsSetting() - { - _settings.Load("/first/path;/second/path"); - Assert.That(_settings.TestAdapterPaths, Is.EqualTo("/first/path;/second/path")); - } + [Test] + public void TestAdapterPathsSetting() + { + _settings.Load("/first/path;/second/path"); + Assert.That(_settings.TestAdapterPaths, Is.EqualTo("/first/path;/second/path")); + } - [Test] - public void CollectSourceInformationSetting() - { - _settings.Load("False"); - Assert.That(_settings.CollectSourceInformation, Is.EqualTo(false)); - } + [Test] + public void CollectSourceInformationSetting() + { + _settings.Load("False"); + Assert.That(_settings.CollectSourceInformation, Is.EqualTo(false)); + } - [Test] - public void DisableAppDomainSetting() - { - _settings.Load("true"); - Assert.That(_settings.DisableAppDomain, Is.EqualTo(true)); - } + [Test] + public void DisableAppDomainSetting() + { + _settings.Load("true"); + Assert.That(_settings.DisableAppDomain, Is.EqualTo(true)); + } - [Test] - public void DisableParallelizationSetting() - { - _settings.Load("true"); - Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(0)); - } + [Test] + public void DisableParallelizationSetting() + { + _settings.Load("true"); + Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(0)); + } - [Test] - public void UpdateNumberOfTestWorkersWhenConflictingSettings() - { - _settings.Load("true12"); + [Test] + public void UpdateNumberOfTestWorkersWhenConflictingSettings() + { + _settings.Load("true12"); - // When there's a conflicting values in DisableParallelization and NumberOfTestWorkers. Override the NumberOfTestWorkers. - Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(0)); + // When there's a conflicting values in DisableParallelization and NumberOfTestWorkers. Override the NumberOfTestWorkers. + Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(0)); - // Do not override the NumberOfTestWorkers when DisableParallelization is False - _settings.Load("false0"); - Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(0)); + // Do not override the NumberOfTestWorkers when DisableParallelization is False + _settings.Load("false0"); + Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(0)); - // Do not override the NumberOfTestWorkers when DisableParallelization is not defined - _settings.Load("12"); - Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(12)); - } + // Do not override the NumberOfTestWorkers when DisableParallelization is not defined + _settings.Load("12"); + Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(12)); + } - [Test] - public void DesignModeSetting() - { - _settings.Load("true"); - Assert.That(_settings.DesignMode, Is.EqualTo(true)); - } + [Test] + public void DesignModeSetting() + { + _settings.Load("true"); + Assert.That(_settings.DesignMode, Is.EqualTo(true)); + } - [Test] - public void TestRunParameterSettings() - { - _settings.Load(""); - Assert.That(_settings.TestProperties.Count, Is.EqualTo(2)); - Assert.That(_settings.TestProperties["Answer"], Is.EqualTo("42")); - Assert.That(_settings.TestProperties["Question"], Is.EqualTo("Why?")); - } - - [Test] - public void InternalTraceLevel() - { - _settings.Load("Debug"); - Assert.That(_settings.InternalTraceLevelEnum, Is.EqualTo(Engine.InternalTraceLevel.Debug)); - } + [Test] + public void TestRunParameterSettings() + { + _settings.Load(""); + Assert.That(_settings.TestProperties.Count, Is.EqualTo(2)); + Assert.That(_settings.TestProperties["Answer"], Is.EqualTo("42")); + Assert.That(_settings.TestProperties["Question"], Is.EqualTo("Why?")); + } - [Test] - public void InternalTraceLevelEmpty() - { - _settings.Load(""); - Assert.That(_settings.InternalTraceLevelEnum, Is.EqualTo(Engine.InternalTraceLevel.Off)); - Assert.That(_settings.InternalTraceLevelEnum.ToString(), Is.EqualTo("Off")); - } + [Test] + public void InternalTraceLevel() + { + _settings.Load("Debug"); + Assert.That(_settings.InternalTraceLevelEnum, Is.EqualTo(Engine.InternalTraceLevel.Debug)); + } + [Test] + public void InternalTraceLevelEmpty() + { + _settings.Load(""); + Assert.That(_settings.InternalTraceLevelEnum, Is.EqualTo(Engine.InternalTraceLevel.Off)); + Assert.That(_settings.InternalTraceLevelEnum.ToString(), Is.EqualTo("Off")); + } - [Test] - public void WorkDirectorySetting() - { - _settings.Load("/my/work/dir"); - Assert.That(_settings.WorkDirectory, Is.EqualTo("/my/work/dir")); - } - - /// - /// Workdir not set, TestOutput is relative. - /// - [Test] - public void TestOutputSetting() - { - _settings.Load(@"C:\Whatever/my/work/dir"); - Assert.That(_settings.UseTestOutputXml); - _settings.SetTestOutputFolder(_settings.WorkDirectory); - Assert.That(_settings.TestOutputFolder, Does.Contain(@"/my/work/dir")); - } - - /// - /// NewOutputXmlFileForEachRun setting. - /// - [Test] - public void TestNewOutputXmlFileForEachRunSetting() - { - _settings.Load("true"); - Assert.That(_settings.NewOutputXmlFileForEachRun, Is.True); - } - [Test] - public void TestOutputSettingWithWorkDir() - { - _settings.Load(@"C:\Whatevermy/testoutput/dirRelativeToWorkFolder"); - Assert.That(_settings.UseTestOutputXml, "Settings not loaded properly"); - _settings.SetTestOutputFolder(_settings.WorkDirectory); - Assert.Multiple(() => - { - Assert.That(_settings.TestOutputFolder, Does.Contain(@"\my/testoutput/dir"), "Content not correct"); - Assert.That(_settings.TestOutputFolder, Does.StartWith(@"C:\"), "Not correct start drive"); - Assert.That(Path.IsPathRooted(_settings.TestOutputFolder), Is.True, "Path not properly rooted"); - }); - } - - /// - /// Test should set output folder to same as resultdirectory, and ignore workdirectory and testoutputxml. - /// - [Test] - public void TestOutputSettingWithUseResultDirectory() - { - _settings.Load(@"c:\whatever\resultsC:\AnotherWhatevermy/testoutput/dirUseResultDirectory"); - Assert.That(_settings.UseTestOutputXml, "Settings not loaded properly"); - _settings.SetTestOutputFolder(_settings.WorkDirectory); - Assert.That(_settings.TestOutputFolder, Is.EqualTo(@"c:\whatever\results"), "Content not correct"); - } - - /// - /// Test should set output folder to same as resultdirectory, and ignore workdirectory and testoutputxml. - /// - [Test] - public void TestOutputSettingAsSpecified() - { - _settings.Load(@"c:\whatever"); - Assert.That(_settings.UseTestOutputXml, "Settings not loaded properly"); - _settings.SetTestOutputFolder(_settings.WorkDirectory); - Assert.Multiple(() => - { - Assert.That(_settings.TestOutputFolder, Is.EqualTo(@"c:\whatever"), "Content not correct"); - Assert.That(_settings.OutputXmlFolderMode, Is.EqualTo(OutputXmlFolderMode.AsSpecified), "Should be set default AsSpecified with absolute path in"); - }); - } - - [Test] - public void NumberOfTestWorkersSetting() - { - _settings.Load("12"); - Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(12)); - } + [Test] + public void WorkDirectorySetting() + { + _settings.Load("/my/work/dir"); + Assert.That(_settings.WorkDirectory, Is.EqualTo("/my/work/dir")); + } - [Test] - public void DefaultTimeoutSetting() - { - _settings.Load("5000"); - Assert.That(_settings.DefaultTimeout, Is.EqualTo(5000)); - } + /// + /// Workdir not set, TestOutput is relative. + /// + [Test] + public void TestOutputSetting() + { + _settings.Load(@"C:\Whatever/my/work/dir"); + Assert.That(_settings.UseTestOutputXml); + _settings.SetTestOutputFolder(_settings.WorkDirectory); + Assert.That(_settings.TestOutputFolder, Does.Contain(@"/my/work/dir")); + } - [Test] - public void ShadowCopySetting() - { - _settings.Load("true"); - Assert.That(_settings.ShadowCopyFiles, Is.True); - } + /// + /// NewOutputXmlFileForEachRun setting. + /// + [Test] + public void TestNewOutputXmlFileForEachRunSetting() + { + _settings.Load("true"); + Assert.That(_settings.NewOutputXmlFileForEachRun, Is.True); + } + [Test] + public void TestOutputSettingWithWorkDir() + { + _settings.Load(@"C:\Whatevermy/testoutput/dirRelativeToWorkFolder"); + Assert.That(_settings.UseTestOutputXml, "Settings not loaded properly"); + _settings.SetTestOutputFolder(_settings.WorkDirectory); + Assert.Multiple(() => + { + Assert.That(_settings.TestOutputFolder, Does.Contain(@"\my/testoutput/dir"), "Content not correct"); + Assert.That(_settings.TestOutputFolder, Does.StartWith(@"C:\"), "Not correct start drive"); + Assert.That(Path.IsPathRooted(_settings.TestOutputFolder), Is.True, "Path not properly rooted"); + }); + } - [Test] - public void ShadowCopySettingDefault() - { - _settings.Load(""); - Assert.That(_settings.ShadowCopyFiles, Is.False); - } + /// + /// Test should set output folder to same as resultdirectory, and ignore workdirectory and testoutputxml. + /// + [Test] + public void TestOutputSettingWithUseResultDirectory() + { + _settings.Load(@"c:\whatever\resultsC:\AnotherWhatevermy/testoutput/dirUseResultDirectory"); + Assert.That(_settings.UseTestOutputXml, "Settings not loaded properly"); + _settings.SetTestOutputFolder(_settings.WorkDirectory); + Assert.That(_settings.TestOutputFolder, Is.EqualTo(@"c:\whatever\results"), "Content not correct"); + } - [Test] - public void VerbositySetting() - { - _settings.Load("1"); - Assert.That(_settings.Verbosity, Is.EqualTo(1)); - } + /// + /// Test should set output folder to same as resultdirectory, and ignore workdirectory and testoutputxml. + /// + [Test] + public void TestOutputSettingAsSpecified() + { + _settings.Load(@"c:\whatever"); + Assert.That(_settings.UseTestOutputXml, "Settings not loaded properly"); + _settings.SetTestOutputFolder(_settings.WorkDirectory); + Assert.Multiple(() => + { + Assert.That(_settings.TestOutputFolder, Is.EqualTo(@"c:\whatever"), "Content not correct"); + Assert.That(_settings.OutputXmlFolderMode, Is.EqualTo(OutputXmlFolderMode.AsSpecified), "Should be set default AsSpecified with absolute path in"); + }); + } - [Test] - public void UseVsKeepEngineRunningSetting() - { - _settings.Load("true"); - Assert.That(_settings.UseVsKeepEngineRunning, Is.True); - } + [Test] + public void NumberOfTestWorkersSetting() + { + _settings.Load("12"); + Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(12)); + } - [Test] - public void PreFilterIsDefaultOff() - { - Assert.That(_settings.PreFilter, Is.False); - } + [Test] + public void DefaultTimeoutSetting() + { + _settings.Load("5000"); + Assert.That(_settings.DefaultTimeout, Is.EqualTo(5000)); + } - [Test] - public void PreFilterCanBeSet() - { - _settings.Load("true"); - Assert.That(_settings.PreFilter); - } + [Test] + public void ShadowCopySetting() + { + _settings.Load("true"); + Assert.That(_settings.ShadowCopyFiles, Is.True); + } - [Test] - public void BasePathSetting() - { - _settings.Load(".."); - Assert.That(_settings.BasePath, Is.EqualTo("..")); - } + [Test] + public void ShadowCopySettingDefault() + { + _settings.Load(""); + Assert.That(_settings.ShadowCopyFiles, Is.False); + } + [Test] + public void VerbositySetting() + { + _settings.Load("1"); + Assert.That(_settings.Verbosity, Is.EqualTo(1)); + } - [Test] - public void VsTestCategoryTypeSetting() - { - _settings.Load("mstest"); - Assert.That(_settings.VsTestCategoryType, Is.EqualTo(VsTestCategoryType.MsTest)); - } + [Test] + public void UseVsKeepEngineRunningSetting() + { + _settings.Load("true"); + Assert.That(_settings.UseVsKeepEngineRunning, Is.True); + } - [Test] - public void VsTestCategoryTypeSettingWithGarbage() - { - _settings.Load("garbage"); - Assert.That(_settings.VsTestCategoryType, Is.EqualTo(VsTestCategoryType.NUnit)); - } + [Test] + public void PreFilterIsDefaultOff() + { + Assert.That(_settings.PreFilter, Is.False); + } + [Test] + public void PreFilterCanBeSet() + { + _settings.Load("true"); + Assert.That(_settings.PreFilter); + } - [Test] - public void PrivateBinPathSetting() - { - _settings.Load("dir1;dir2"); - Assert.That(_settings.PrivateBinPath, Is.EqualTo("dir1;dir2")); - } - [Test] - public void RandomSeedSetting() - { - _settings.Load("12345"); - Assert.That(_settings.RandomSeed, Is.EqualTo(12345)); - } + [Test] + public void BasePathSetting() + { + _settings.Load(".."); + Assert.That(_settings.BasePath, Is.EqualTo("..")); + } - [Test] - public void DefaultTestNamePattern() - { - _settings.Load("{m}{a:1000}"); - Assert.That(_settings.DefaultTestNamePattern, Is.EqualTo("{m}{a:1000}")); - } - [Test] - public void CollectDataForEachTestSeparately() - { - _settings.Load(@" + [Test] + public void VsTestCategoryTypeSetting() + { + _settings.Load("mstest"); + Assert.That(_settings.VsTestCategoryType, Is.EqualTo(VsTestCategoryType.MsTest)); + } + + [Test] + public void VsTestCategoryTypeSettingWithGarbage() + { + _settings.Load("garbage"); + Assert.That(_settings.VsTestCategoryType, Is.EqualTo(VsTestCategoryType.NUnit)); + } + + + [Test] + public void PrivateBinPathSetting() + { + _settings.Load("dir1;dir2"); + Assert.That(_settings.PrivateBinPath, Is.EqualTo("dir1;dir2")); + } + + [Test] + public void RandomSeedSetting() + { + _settings.Load("12345"); + Assert.That(_settings.RandomSeed, Is.EqualTo(12345)); + } + + [Test] + public void DefaultTestNamePattern() + { + _settings.Load("{m}{a:1000}"); + Assert.That(_settings.DefaultTestNamePattern, Is.EqualTo("{m}{a:1000}")); + } + + [Test] + public void CollectDataForEachTestSeparately() + { + _settings.Load(@" true @@ -380,16 +380,16 @@ public void CollectDataForEachTestSeparately() "); - Assert.That(_settings.DomainUsage, Is.Null); - Assert.That(_settings.SynchronousEvents); - Assert.That(_settings.NumberOfTestWorkers, Is.Zero); - Assert.That(_settings.InProcDataCollectorsAvailable); - } + Assert.That(_settings.DomainUsage, Is.Null); + Assert.That(_settings.SynchronousEvents); + Assert.That(_settings.NumberOfTestWorkers, Is.Zero); + Assert.That(_settings.InProcDataCollectorsAvailable); + } - [Test] - public void InProcDataCollector() - { - _settings.Load(@" + [Test] + public void InProcDataCollector() + { + _settings.Load(@" @@ -398,16 +398,16 @@ public void InProcDataCollector() "); - Assert.That(_settings.DomainUsage, Is.Null); - Assert.That(_settings.SynchronousEvents, Is.False); - Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(-1)); - Assert.That(_settings.InProcDataCollectorsAvailable, Is.True); - } + Assert.That(_settings.DomainUsage, Is.Null); + Assert.That(_settings.SynchronousEvents, Is.False); + Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(-1)); + Assert.That(_settings.InProcDataCollectorsAvailable, Is.True); + } - [Test] - public void LiveUnitTestingDataCollector() - { - _settings.Load(@" + [Test] + public void LiveUnitTestingDataCollector() + { + _settings.Load(@" @@ -416,88 +416,87 @@ public void LiveUnitTestingDataCollector() "); - Assert.That(_settings.DomainUsage, Is.Null); - Assert.That(_settings.SynchronousEvents, Is.True); - Assert.That(_settings.NumberOfTestWorkers, Is.Zero); - Assert.That(_settings.InProcDataCollectorsAvailable, Is.True); - } + Assert.That(_settings.DomainUsage, Is.Null); + Assert.That(_settings.SynchronousEvents, Is.True); + Assert.That(_settings.NumberOfTestWorkers, Is.Zero); + Assert.That(_settings.InProcDataCollectorsAvailable, Is.True); + } - [Test] - public void WhereCanBeSet() - { - _settings.Load("cat == SomeCategory and namespace == SomeNamespace or cat != SomeOtherCategory"); - Assert.That(_settings.Where, Is.EqualTo("cat == SomeCategory and namespace == SomeNamespace or cat != SomeOtherCategory")); - } - - [TestCase("None", TestOutcome.None)] - [TestCase("Passed", TestOutcome.Passed)] - [TestCase("Failed", TestOutcome.Failed)] - [TestCase("Skipped", TestOutcome.Skipped)] - public void MapWarningToTests(string setting, TestOutcome outcome) - { - var runsettings = $"{setting}"; - _settings.Load(runsettings); - Assert.That(_settings.MapWarningTo, Is.EqualTo(outcome)); - } + [Test] + public void WhereCanBeSet() + { + _settings.Load("cat == SomeCategory and namespace == SomeNamespace or cat != SomeOtherCategory"); + Assert.That(_settings.Where, Is.EqualTo("cat == SomeCategory and namespace == SomeNamespace or cat != SomeOtherCategory")); + } + + [TestCase("None", TestOutcome.None)] + [TestCase("Passed", TestOutcome.Passed)] + [TestCase("Failed", TestOutcome.Failed)] + [TestCase("Skipped", TestOutcome.Skipped)] + public void MapWarningToTests(string setting, TestOutcome outcome) + { + var runsettings = $"{setting}"; + _settings.Load(runsettings); + Assert.That(_settings.MapWarningTo, Is.EqualTo(outcome)); + } - [TestCase("garbage")] - public void MapWarningToTestsFailing(string setting) + [TestCase("garbage")] + public void MapWarningToTestsFailing(string setting) + { + var runsettings = $"{setting}"; + _settings.Load(runsettings); + Assert.That(_settings.MapWarningTo, Is.EqualTo(TestOutcome.Skipped)); + } + + [Test] + public void MapWarningToTestsDefault() + { + _settings.Load(""); + } + + [TestCase("Name", DisplayNameOptions.Name)] + [TestCase("Fullname", DisplayNameOptions.FullName)] + [TestCase("FullnameSep", DisplayNameOptions.FullNameSep)] + [TestCase("invalid", DisplayNameOptions.Name)] + public void MapDisplayNameTests(string setting, DisplayNameOptions outcome) + { + var runsettings = $"{setting}"; + _settings.Load(runsettings); + Assert.That(_settings.DisplayName, Is.EqualTo(outcome)); + } + + [TestCase(":")] + [TestCase("-")] + [TestCase(".")] + public void FullNameSeparatorTest(string setting) + { + var expected = setting[0]; + var runsettings = $"{setting}"; + _settings.Load(runsettings); + Assert.That(_settings.FullnameSeparator, Is.EqualTo(expected)); + } + + [Test] + public void TestDefaults() + { + _settings.Load(""); + Assert.Multiple(() => { - var runsettings = $"{setting}"; - _settings.Load(runsettings); + Assert.That(_settings.FullnameSeparator, Is.EqualTo(':')); + Assert.That(_settings.DisplayName, Is.EqualTo(DisplayNameOptions.Name)); Assert.That(_settings.MapWarningTo, Is.EqualTo(TestOutcome.Skipped)); - } + }); + } - [Test] - public void MapWarningToTestsDefault() - { - _settings.Load(""); - } - - [TestCase("Name", DisplayNameOptions.Name)] - [TestCase("Fullname", DisplayNameOptions.FullName)] - [TestCase("FullnameSep", DisplayNameOptions.FullNameSep)] - [TestCase("invalid", DisplayNameOptions.Name)] - public void MapDisplayNameTests(string setting, DisplayNameOptions outcome) - { - var runsettings = $"{setting}"; - _settings.Load(runsettings); - Assert.That(_settings.DisplayName, Is.EqualTo(outcome)); - } - - [TestCase(":")] - [TestCase("-")] - [TestCase(".")] - public void FullNameSeparatorTest(string setting) - { - var expected = setting[0]; - var runsettings = $"{setting}"; - _settings.Load(runsettings); - Assert.That(_settings.FullnameSeparator, Is.EqualTo(expected)); - } - - [Test] - public void TestDefaults() - { - _settings.Load(""); - Assert.Multiple(() => - { - Assert.That(_settings.FullnameSeparator, Is.EqualTo(':')); - Assert.That(_settings.DisplayName, Is.EqualTo(DisplayNameOptions.Name)); - Assert.That(_settings.MapWarningTo, Is.EqualTo(TestOutcome.Skipped)); - }); - } - - [TestCase("garbage", DiscoveryMethod.Current, DiscoveryMethod.Current)] - [TestCase("Legacy", DiscoveryMethod.Legacy, DiscoveryMethod.Legacy)] - [TestCase("Current", DiscoveryMethod.Legacy, DiscoveryMethod.Current)] - public void TestMapEnum(string setting, T defaultValue, T expected) + [TestCase("garbage", DiscoveryMethod.Current, DiscoveryMethod.Current)] + [TestCase("Legacy", DiscoveryMethod.Legacy, DiscoveryMethod.Legacy)] + [TestCase("Current", DiscoveryMethod.Legacy, DiscoveryMethod.Current)] + public void TestMapEnum(string setting, T defaultValue, T expected) where T : struct, Enum - { - var logger = Substitute.For(); - var sut = new AdapterSettings(logger); - var result = sut.MapEnum(setting, defaultValue); - Assert.That(result, Is.EqualTo(expected), $"Failed for {setting}"); - } + { + var logger = Substitute.For(); + var sut = new AdapterSettings(logger); + var result = sut.MapEnum(setting, defaultValue); + Assert.That(result, Is.EqualTo(expected), $"Failed for {setting}"); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/AssemblyRunnerTests.cs b/src/NUnitTestAdapterTests/AssemblyRunnerTests.cs index fd797b06..2c93b0dc 100644 --- a/src/NUnitTestAdapterTests/AssemblyRunnerTests.cs +++ b/src/NUnitTestAdapterTests/AssemblyRunnerTests.cs @@ -24,16 +24,16 @@ using System; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +// TODO: Convert tests of the old AssemblyRunner as needed +// to tests of NUnit3TestExecutor. +[TestFixture] +public class AssemblyRunnerTests { - // TODO: Convert tests of the old AssemblyRunner as needed - // to tests of NUnit3TestExecutor. - [TestFixture] - public class AssemblyRunnerTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() - { // MethodInfo fakeTestMethod1 = GetType() // .GetMethod("FakeTestMethod1", BindingFlags.Instance | BindingFlags.NonPublic); // fakeTest1 = new NUnitTestMethod(fakeTestMethod1); @@ -42,88 +42,87 @@ public void SetUp() // fakeTest2 = new NUnitTestMethod(fakeTestMethod2); } - private static readonly Uri ExecutorUri = new (NUnit3TestExecutor.ExecutorUri); + private static readonly Uri ExecutorUri = new (NUnit3TestExecutor.ExecutorUri); // ReSharper disable once UnusedMember.Local - private void FakeTestMethod1() - { + private void FakeTestMethod1() + { } // ReSharper disable once UnusedMember.Local - private void FakeTestMethod2() - { + private void FakeTestMethod2() + { } - // [Test] - // public void AddsFilteredCorrectly() - // { - // var t1 = new TestCase(fakeTest1.TestName.FullName, ExecutorUri, "test"); - // var t2 = new TestCase(fakeTest2.TestName.FullName, ExecutorUri, "test"); - // var list = new List {t1, t2}; - // var runner = new AssemblyRunner(new TestLogger(), "test", list); - // runner.AddTestCases(fakeTest1); - // runner.AddTestCases(fakeTest2); - // Assert.That(runner.NUnitFilter.IsEmpty, Is.False, "NUnitfilter should not be empty, we have added testcases"); - // Assert.That(runner.LoadedTestCases.Count, Is.EqualTo(2), "We should have had 2 converted MS test cases here"); - // } - - // [Test] - // public void AddsNonFilteredCorrectly() - // { - // var runner = new AssemblyRunner(new TestLogger(), "test"); - // runner.AddTestCases(fakeTest1); - // runner.AddTestCases(fakeTest2); - // Assert.That(runner.NUnitFilter.IsEmpty, Is.True, "NUnitfilter has been touched"); - // Assert.That(runner.LoadedTestCases.Count, Is.EqualTo(2), "We should have had 2 test cases here"); - // } - - - // [Test] - // public void VerifyConstruction1() - // { - // var runner = new AssemblyRunner(new TestLogger(), "test"); - // Assert.That(runner.NUnitFilter.Xml.ChildNodes.Count, Is.EqualTo(0)); - // } - - // [Test] - // public void VerifyConstruction2() - // { - // var t1 = new TestCase("Test1", ExecutorUri, "test"); - // var t2 = new TestCase("Test2", ExecutorUri, "test"); - // var cases = new List { t1, t2 }; - // var runner = new AssemblyRunner(new TestLogger(), "test", cases); - // var tests = runner.NUnitFilter.Xml.SelectNodes("tests/test"); - - // var names = new List(); - // foreach (XmlNode testNode in tests) - // names.Add(testNode.InnerText); - - // Assert.That(names, Is.EquivalentTo(new string[] { "Test1", "Test2" })); - // } - - // TODO: Instead of using AddTestCases, we should be loading an actual assembly - - // [Test] - // public void HandleTfsFilterCorrectlyWhenFilterIsEmpty() - // { - // var tfsfilter = new Mock(); - // tfsfilter.Setup(f => f.HasTfsFilterValue).Returns(false); - // var runner = new AssemblyRunner(new TestLogger(), "test", tfsfilter.Object); - // runner.AddTestCases(fakeTest1); - // runner.AddTestCases(fakeTest2); - - // Assert.That(runner.NUnitFilter.IsEmpty, Is.False, "NUnitfilter should not be empty, we have added testcases"); - // Assert.That(runner.LoadedTestCases.Count, Is.EqualTo(2), "We should have had 2 converted MS test cases here"); - // } - // [Test] - // public void HandleTfsFilterCorrectlyWhenNoFilter() - // { - // var runner = new AssemblyRunner(new TestLogger(), "test", (TFSTestFilter)null); - // runner.AddTestCases(fakeTest1); - // runner.AddTestCases(fakeTest2); - - // Assert.That(runner.NUnitFilter.IsEmpty, Is.False, "NUnitfilter should not be empty, we have added testcases"); - // Assert.That(runner.LoadedTestCases.Count, Is.EqualTo(2), "We should have had 2 converted MS test cases here"); - // } - } + // [Test] + // public void AddsFilteredCorrectly() + // { + // var t1 = new TestCase(fakeTest1.TestName.FullName, ExecutorUri, "test"); + // var t2 = new TestCase(fakeTest2.TestName.FullName, ExecutorUri, "test"); + // var list = new List {t1, t2}; + // var runner = new AssemblyRunner(new TestLogger(), "test", list); + // runner.AddTestCases(fakeTest1); + // runner.AddTestCases(fakeTest2); + // Assert.That(runner.NUnitFilter.IsEmpty, Is.False, "NUnitfilter should not be empty, we have added testcases"); + // Assert.That(runner.LoadedTestCases.Count, Is.EqualTo(2), "We should have had 2 converted MS test cases here"); + // } + + // [Test] + // public void AddsNonFilteredCorrectly() + // { + // var runner = new AssemblyRunner(new TestLogger(), "test"); + // runner.AddTestCases(fakeTest1); + // runner.AddTestCases(fakeTest2); + // Assert.That(runner.NUnitFilter.IsEmpty, Is.True, "NUnitfilter has been touched"); + // Assert.That(runner.LoadedTestCases.Count, Is.EqualTo(2), "We should have had 2 test cases here"); + // } + + + // [Test] + // public void VerifyConstruction1() + // { + // var runner = new AssemblyRunner(new TestLogger(), "test"); + // Assert.That(runner.NUnitFilter.Xml.ChildNodes.Count, Is.EqualTo(0)); + // } + + // [Test] + // public void VerifyConstruction2() + // { + // var t1 = new TestCase("Test1", ExecutorUri, "test"); + // var t2 = new TestCase("Test2", ExecutorUri, "test"); + // var cases = new List { t1, t2 }; + // var runner = new AssemblyRunner(new TestLogger(), "test", cases); + // var tests = runner.NUnitFilter.Xml.SelectNodes("tests/test"); + + // var names = new List(); + // foreach (XmlNode testNode in tests) + // names.Add(testNode.InnerText); + + // Assert.That(names, Is.EquivalentTo(new string[] { "Test1", "Test2" })); + // } + + // TODO: Instead of using AddTestCases, we should be loading an actual assembly + + // [Test] + // public void HandleTfsFilterCorrectlyWhenFilterIsEmpty() + // { + // var tfsfilter = new Mock(); + // tfsfilter.Setup(f => f.HasTfsFilterValue).Returns(false); + // var runner = new AssemblyRunner(new TestLogger(), "test", tfsfilter.Object); + // runner.AddTestCases(fakeTest1); + // runner.AddTestCases(fakeTest2); + + // Assert.That(runner.NUnitFilter.IsEmpty, Is.False, "NUnitfilter should not be empty, we have added testcases"); + // Assert.That(runner.LoadedTestCases.Count, Is.EqualTo(2), "We should have had 2 converted MS test cases here"); + // } + // [Test] + // public void HandleTfsFilterCorrectlyWhenNoFilter() + // { + // var runner = new AssemblyRunner(new TestLogger(), "test", (TFSTestFilter)null); + // runner.AddTestCases(fakeTest1); + // runner.AddTestCases(fakeTest2); + + // Assert.That(runner.NUnitFilter.IsEmpty, Is.False, "NUnitfilter should not be empty, we have added testcases"); + // Assert.That(runner.LoadedTestCases.Count, Is.EqualTo(2), "We should have had 2 converted MS test cases here"); + // } } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/AsyncTests.cs b/src/NUnitTestAdapterTests/AsyncTests.cs index 0b06691a..4f767e93 100644 --- a/src/NUnitTestAdapterTests/AsyncTests.cs +++ b/src/NUnitTestAdapterTests/AsyncTests.cs @@ -24,35 +24,34 @@ using System.Threading.Tasks; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +public class AsyncTests { - public class AsyncTests + [Test] + public async Task TaskTestSuccess() { - [Test] - public async Task TaskTestSuccess() - { var result = await ReturnOne(); Assert.That(result, Is.EqualTo(1)); } - [TestCase(ExpectedResult = 1)] - public async Task TaskTTestCaseWithResultCheckSuccess() - { + [TestCase(ExpectedResult = 1)] + public async Task TaskTTestCaseWithResultCheckSuccess() + { return await ReturnOne(); } - private static Task ReturnOne() - { + private static Task ReturnOne() + { return Task.Run(() => 1); } - private static Task ThrowException() - { + private static Task ThrowException() + { return Task.Run(() => { throw new InvalidOperationException(); }); } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/CurrentDirectoryTests.cs b/src/NUnitTestAdapterTests/CurrentDirectoryTests.cs index ebbb1381..a9933fab 100644 --- a/src/NUnitTestAdapterTests/CurrentDirectoryTests.cs +++ b/src/NUnitTestAdapterTests/CurrentDirectoryTests.cs @@ -24,39 +24,38 @@ using System.Linq; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +public class CurrentDirectoryTests { - public class CurrentDirectoryTests + [TestCase(@"C:\Windows")] + [TestCase(@"C:\Windows\Whatever")] + [TestCase(@"C:\Program Files\Something")] + [TestCase(@"C:\Program Files (x86)\Something")] + [Platform("Win")] + public void ThatWeFindForbiddenFolders(string folder) { - [TestCase(@"C:\Windows")] - [TestCase(@"C:\Windows\Whatever")] - [TestCase(@"C:\Program Files\Something")] - [TestCase(@"C:\Program Files (x86)\Something")] - [Platform("Win")] - public void ThatWeFindForbiddenFolders(string folder) - { var sut = new NUnit3TestExecutor(); sut.InitializeForbiddenFolders(); Assert.That(sut.CheckDirectory(folder)); } - [TestCase(@"C:\Whatever")] - [TestCase(@"C:\WindowsWhatever")] - [TestCase(@"C:\Program Files Whatever\Something")] - public void ThatWeAcceptNonForbiddenFolders(string folder) - { + [TestCase(@"C:\Whatever")] + [TestCase(@"C:\WindowsWhatever")] + [TestCase(@"C:\Program Files Whatever\Something")] + public void ThatWeAcceptNonForbiddenFolders(string folder) + { var sut = new NUnit3TestExecutor(); sut.InitializeForbiddenFolders(); Assert.That(sut.CheckDirectory(folder), Is.False); } - [Test] - public void ThatForbiddenFoldersAreUnique() - { + [Test] + public void ThatForbiddenFoldersAreUnique() + { var sut = new NUnit3TestExecutor(); sut.InitializeForbiddenFolders(); var sutunique = sut.ForbiddenFolders.Distinct(); Assert.That(sutunique.Count(), Is.EqualTo(sut.ForbiddenFolders.Count), "There are duplicate entries in ForbiddenFolders"); } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/DumpXmlTests.cs b/src/NUnitTestAdapterTests/DumpXmlTests.cs index 6712595e..d007e7e9 100644 --- a/src/NUnitTestAdapterTests/DumpXmlTests.cs +++ b/src/NUnitTestAdapterTests/DumpXmlTests.cs @@ -26,14 +26,14 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Dump; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +[Category(nameof(DumpXml))] +public class DumpXmlTests { - [Category(nameof(DumpXml))] - public class DumpXmlTests + [Test] + public void ThatWritingClearsBuffer() { - [Test] - public void ThatWritingClearsBuffer() - { string res = ""; var file = Substitute.For(); file.WriteAllText(Arg.Any(), Arg.Do(o => res = o)); @@ -49,9 +49,9 @@ public void ThatWritingClearsBuffer() Assert.That(res, Does.Not.Contain(string1)); } - [Test] - public void ThatRandomNameContainsValidCharacters() - { + [Test] + public void ThatRandomNameContainsValidCharacters() + { var sut = new DumpXml("whatever"); var res = sut.RandomName(); Assert.That(res, Does.EndWith(".dump")); @@ -62,12 +62,12 @@ public void ThatRandomNameContainsValidCharacters() Assert.That(rg.IsMatch(part1)); } - [TestCase(@"C:\MyFolder\Whatever.dll", @"C:\MyFolder\Dump\D_Whatever.dll.dump")] - [TestCase(@"C:\MyFolder\Whatever.dll", @"C:\MyFolder\Dump")] - [TestCase(@"C:\MyFolder\Whatever.dll", @"C:\MyFolder")] - [Platform("Win")] - public void ThatPathIsCorrectlyParsedInDiscoveryPhase(string path, string expected) - { + [TestCase(@"C:\MyFolder\Whatever.dll", @"C:\MyFolder\Dump\D_Whatever.dll.dump")] + [TestCase(@"C:\MyFolder\Whatever.dll", @"C:\MyFolder\Dump")] + [TestCase(@"C:\MyFolder\Whatever.dll", @"C:\MyFolder")] + [Platform("Win")] + public void ThatPathIsCorrectlyParsedInDiscoveryPhase(string path, string expected) + { var file = Substitute.For(); var sut = new DumpXml(path, file); sut.AddString("whatever"); @@ -75,12 +75,12 @@ public void ThatPathIsCorrectlyParsedInDiscoveryPhase(string path, string expect file.Received().WriteAllText(Arg.Is(o => o.StartsWith(expected, StringComparison.OrdinalIgnoreCase)), Arg.Any()); } - [TestCase(@"/some/Folder/Whatever.dll", @"/some/Folder/Dump/D_Whatever.dll.dump")] - [TestCase(@"/some/Folder/Whatever.dll", @"/some/Folder/Dump")] - [TestCase(@"/some/Folder/Whatever.dll", @"/some/Folder")] - [Platform("Unix")] - public void ThatPathIsCorrectlyParsedInDiscoveryPhaseOnUnix(string path, string expected) - { + [TestCase(@"/some/Folder/Whatever.dll", @"/some/Folder/Dump/D_Whatever.dll.dump")] + [TestCase(@"/some/Folder/Whatever.dll", @"/some/Folder/Dump")] + [TestCase(@"/some/Folder/Whatever.dll", @"/some/Folder")] + [Platform("Unix")] + public void ThatPathIsCorrectlyParsedInDiscoveryPhaseOnUnix(string path, string expected) + { var file = Substitute.For(); var sut = new DumpXml(path, file); sut.AddString("whatever"); @@ -89,9 +89,9 @@ public void ThatPathIsCorrectlyParsedInDiscoveryPhaseOnUnix(string path, string } - [Test] - public void ThatEmptyContainsHeaders() - { + [Test] + public void ThatEmptyContainsHeaders() + { string res = ""; var file = Substitute.For(); file.WriteAllText(Arg.Any(), Arg.Do(o => res = o)); @@ -101,5 +101,4 @@ public void ThatEmptyContainsHeaders() var sarray = res.Split('\n'); Assert.That(sarray.Length, Is.GreaterThanOrEqualTo(3)); } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/ExecutionTests.cs b/src/NUnitTestAdapterTests/ExecutionTests.cs index 5171c8c1..b6f84d40 100644 --- a/src/NUnitTestAdapterTests/ExecutionTests.cs +++ b/src/NUnitTestAdapterTests/ExecutionTests.cs @@ -9,51 +9,50 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +public class ExecutionTests { - public class ExecutionTests + IExecutionContext ctx; + TestFilter filter; + IDiscoveryConverter discovery; + + [SetUp] + public void Setup() { - IExecutionContext ctx; - TestFilter filter; - IDiscoveryConverter discovery; + ctx = Substitute.For(); + var settings = Substitute.For(); + settings.AssemblySelectLimit.Returns(10); + ctx.Settings.Returns(settings); + var engineAdapter = new NUnitEngineAdapter(); + engineAdapter.Initialize(); + ctx.EngineAdapter.Returns(engineAdapter); + settings.DiscoveryMethod.Returns(DiscoveryMethod.Current); + discovery = Substitute.For(); + discovery.NoOfLoadedTestCases.Returns(1); + discovery.IsDiscoveryMethodCurrent.Returns(true); - [SetUp] - public void Setup() + discovery.LoadedTestCases.Returns(new List { - ctx = Substitute.For(); - var settings = Substitute.For(); - settings.AssemblySelectLimit.Returns(10); - ctx.Settings.Returns(settings); - var engineAdapter = new NUnitEngineAdapter(); - engineAdapter.Initialize(); - ctx.EngineAdapter.Returns(engineAdapter); - settings.DiscoveryMethod.Returns(DiscoveryMethod.Current); - discovery = Substitute.For(); - discovery.NoOfLoadedTestCases.Returns(1); - discovery.IsDiscoveryMethodCurrent.Returns(true); - - discovery.LoadedTestCases.Returns(new List - { - new ("A", new Uri(NUnitTestAdapter.ExecutorUri), "line 23") - }); - filter = new TestFilter("AB"); - } + new ("A", new Uri(NUnitTestAdapter.ExecutorUri), "line 23") + }); + filter = new TestFilter("AB"); + } - [Explicit("Need to mock out the engine, it crashes on [command line] build due to multiple instances that can't be handled")] - [Test] - public void ThatCheckFilterInCurrentModeWorks() - { - var sut = new IdeExecution(ctx); - var result = sut.CheckFilterInCurrentMode(filter, discovery); - Assert.That(result.IsEmpty, Is.False); - Assert.That(result.Text, Is.Not.EqualTo(filter.Text)); - Assert.That(result.Text, Is.EqualTo("A")); - } + [Explicit("Need to mock out the engine, it crashes on [command line] build due to multiple instances that can't be handled")] + [Test] + public void ThatCheckFilterInCurrentModeWorks() + { + var sut = new IdeExecution(ctx); + var result = sut.CheckFilterInCurrentMode(filter, discovery); + Assert.That(result.IsEmpty, Is.False); + Assert.That(result.Text, Is.Not.EqualTo(filter.Text)); + Assert.That(result.Text, Is.EqualTo("A")); + } - [TearDown] - public void TearDown() - { - ctx.EngineAdapter.CloseRunner(); - } + [TearDown] + public void TearDown() + { + ctx.EngineAdapter.CloseRunner(); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/ExperimentalTests.cs b/src/NUnitTestAdapterTests/ExperimentalTests.cs index c57546ed..d56506b1 100644 --- a/src/NUnitTestAdapterTests/ExperimentalTests.cs +++ b/src/NUnitTestAdapterTests/ExperimentalTests.cs @@ -1,15 +1,14 @@ using System.Reflection; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +[TestFixture] +public class ExperimentalTests { - [TestFixture] - public class ExperimentalTests + [Test] + public void LocationTest() { - [Test] - public void LocationTest() - { var location = typeof(ExperimentalTests).GetTypeInfo().Assembly.Location; } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/ExtensionsTests.cs b/src/NUnitTestAdapterTests/ExtensionsTests.cs index 58c0a3e5..c0df4910 100644 --- a/src/NUnitTestAdapterTests/ExtensionsTests.cs +++ b/src/NUnitTestAdapterTests/ExtensionsTests.cs @@ -24,29 +24,28 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Internal; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +public class ExtensionsTests { - public class ExtensionsTests + [TestCase("\t\t\t")] + [TestCase(" \t")] + [TestCase(" ")] + [TestCase("")] + [TestCase(null)] + [TestCase("\r\n")] + public void ThatIsNullOrWhiteSpaceHandlesTabs(string value) { - [TestCase("\t\t\t")] - [TestCase(" \t")] - [TestCase(" ")] - [TestCase("")] - [TestCase(null)] - [TestCase("\r\n")] - public void ThatIsNullOrWhiteSpaceHandlesTabs(string value) - { var res = StringExtensions.IsNullOrWhiteSpace(value); Assert.That(res); } - [TestCase("\t42")] - [TestCase(" 42")] - [TestCase("42\n\r")] - public void ThatIsNullOrWhiteSpaceHandlesNonWhiteSpace(string value) - { + [TestCase("\t42")] + [TestCase(" 42")] + [TestCase("42\n\r")] + public void ThatIsNullOrWhiteSpaceHandlesNonWhiteSpace(string value) + { var res = StringExtensions.IsNullOrWhiteSpace(value); Assert.That(res, Is.False); } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Fakes/FakeDiscoveryContext.cs b/src/NUnitTestAdapterTests/Fakes/FakeDiscoveryContext.cs index 4bfbcd36..0cbf946e 100644 --- a/src/NUnitTestAdapterTests/Fakes/FakeDiscoveryContext.cs +++ b/src/NUnitTestAdapterTests/Fakes/FakeDiscoveryContext.cs @@ -23,19 +23,18 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; -namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes +namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes; + +class FakeDiscoveryContext : IDiscoveryContext { - class FakeDiscoveryContext : IDiscoveryContext + public FakeDiscoveryContext(IRunSettings runSettings) { - public FakeDiscoveryContext(IRunSettings runSettings) - { RunSettings = runSettings; } - #region IDiscoveryContextMembers + #region IDiscoveryContextMembers - public IRunSettings RunSettings { get; } + public IRunSettings RunSettings { get; } - #endregion - } -} + #endregion +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Fakes/FakeFrameworkHandle.cs b/src/NUnitTestAdapterTests/Fakes/FakeFrameworkHandle.cs index 8ea3423b..07608dff 100644 --- a/src/NUnitTestAdapterTests/Fakes/FakeFrameworkHandle.cs +++ b/src/NUnitTestAdapterTests/Fakes/FakeFrameworkHandle.cs @@ -4,74 +4,74 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; -namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes +namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes; + +/// +/// FakeFrameworkHandle is used in all tests that require an +/// IFrameworkHandle, ITestExecutionRecorder or IMessageLogger. +/// +class FakeFrameworkHandle : IFrameworkHandle { - /// - /// FakeFrameworkHandle is used in all tests that require an - /// IFrameworkHandle, ITestExecutionRecorder or IMessageLogger. - /// - class FakeFrameworkHandle : IFrameworkHandle - { - #region Constructor + #region Constructor - public FakeFrameworkHandle() - { + public FakeFrameworkHandle() + { Events = new List(); } - #endregion + #endregion - #region Nested Types + #region Nested Types - public enum EventType - { - RecordStart, - RecordEnd, - RecordResult, - SendMessage - } + public enum EventType + { + RecordStart, + RecordEnd, + RecordResult, + SendMessage + } - public struct TextMessage - { - public TestMessageLevel Level { get; set; } - public string Text { get; set; } - } + public struct TextMessage + { + public TestMessageLevel Level { get; set; } + public string Text { get; set; } + } - public struct Event - { - public EventType EventType { get; set; } - public TestCase TestCase { get; set; } - public TestResult TestResult { get; set; } - public TestOutcome TestOutcome { get; set; } - public TextMessage Message { get; set; } - } + public struct Event + { + public EventType EventType { get; set; } + public TestCase TestCase { get; set; } + public TestResult TestResult { get; set; } + public TestOutcome TestOutcome { get; set; } + public TextMessage Message { get; set; } + } - #endregion + #endregion - #region Properties + #region Properties - public List Events { get; private set; } + public List Events { get; private set; } - #endregion + #endregion - #region IFrameworkHandle Members + #region IFrameworkHandle Members - bool IFrameworkHandle.EnableShutdownAfterTestRun - { - get; set; - } + bool IFrameworkHandle.EnableShutdownAfterTestRun + { + get; set; + } - int IFrameworkHandle.LaunchProcessWithDebuggerAttached(string filePath, string workingDirectory, string arguments, IDictionary environmentVariables) - { + int IFrameworkHandle.LaunchProcessWithDebuggerAttached(string filePath, string workingDirectory, string arguments, IDictionary environmentVariables) + { throw new NotImplementedException(); } - #endregion + #endregion - #region ITestExecutionRecorder Members + #region ITestExecutionRecorder Members - void ITestExecutionRecorder.RecordStart(TestCase testCase) - { + void ITestExecutionRecorder.RecordStart(TestCase testCase) + { Events.Add(new Event { EventType = EventType.RecordStart, @@ -79,8 +79,8 @@ void ITestExecutionRecorder.RecordStart(TestCase testCase) }); } - void ITestExecutionRecorder.RecordResult(TestResult testResult) - { + void ITestExecutionRecorder.RecordResult(TestResult testResult) + { Events.Add(new Event { EventType = EventType.RecordResult, @@ -88,8 +88,8 @@ void ITestExecutionRecorder.RecordResult(TestResult testResult) }); } - void ITestExecutionRecorder.RecordEnd(TestCase testCase, TestOutcome outcome) - { + void ITestExecutionRecorder.RecordEnd(TestCase testCase, TestOutcome outcome) + { Events.Add(new Event { EventType = EventType.RecordEnd, @@ -98,17 +98,17 @@ void ITestExecutionRecorder.RecordEnd(TestCase testCase, TestOutcome outcome) }); } - void ITestExecutionRecorder.RecordAttachments(IList attachmentSets) - { + void ITestExecutionRecorder.RecordAttachments(IList attachmentSets) + { throw new NotImplementedException(); } - #endregion + #endregion - #region IMessageLogger + #region IMessageLogger - void IMessageLogger.SendMessage(TestMessageLevel testMessageLevel, string message) - { + void IMessageLogger.SendMessage(TestMessageLevel testMessageLevel, string message) + { var textMessage = new TextMessage { Level = testMessageLevel, @@ -122,6 +122,5 @@ void IMessageLogger.SendMessage(TestMessageLevel testMessageLevel, string messag }); } - #endregion - } -} + #endregion +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Fakes/FakeRunContext.cs b/src/NUnitTestAdapterTests/Fakes/FakeRunContext.cs index d2e07462..95b8f379 100644 --- a/src/NUnitTestAdapterTests/Fakes/FakeRunContext.cs +++ b/src/NUnitTestAdapterTests/Fakes/FakeRunContext.cs @@ -26,38 +26,37 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; -namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes +namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes; + +class FakeRunContext : FakeDiscoveryContext, IRunContext { - class FakeRunContext : FakeDiscoveryContext, IRunContext + public FakeRunContext() : base(new FakeRunSettings()) { - public FakeRunContext() : base(new FakeRunSettings()) - { - } + } - public FakeRunContext(FakeRunSettings fakeRunSettings) : base(fakeRunSettings) - { - } + public FakeRunContext(FakeRunSettings fakeRunSettings) : base(fakeRunSettings) + { + } - #region IRunContext Members + #region IRunContext Members - bool IRunContext.InIsolation => throw new NotImplementedException(); + bool IRunContext.InIsolation => throw new NotImplementedException(); - bool IRunContext.IsBeingDebugged => throw new NotImplementedException(); + bool IRunContext.IsBeingDebugged => throw new NotImplementedException(); - bool IRunContext.IsDataCollectionEnabled => throw new NotImplementedException(); + bool IRunContext.IsDataCollectionEnabled => throw new NotImplementedException(); - bool IRunContext.KeepAlive => true; + bool IRunContext.KeepAlive => true; - string IRunContext.TestRunDirectory => throw new NotImplementedException(); + string IRunContext.TestRunDirectory => throw new NotImplementedException(); - ITestCaseFilterExpression IRunContext.GetTestCaseFilter(IEnumerable supportedProperties, Func propertyProvider) - { - return null; // as if we don't have a TFS Build, equal to testing from VS - } + ITestCaseFilterExpression IRunContext.GetTestCaseFilter(IEnumerable supportedProperties, Func propertyProvider) + { + return null; // as if we don't have a TFS Build, equal to testing from VS + } - #endregion + #endregion - public string SolutionDirectory => throw new NotImplementedException(); - } -} + public string SolutionDirectory => throw new NotImplementedException(); +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Fakes/FakeRunSettings.cs b/src/NUnitTestAdapterTests/Fakes/FakeRunSettings.cs index 8d991394..7b24f26f 100644 --- a/src/NUnitTestAdapterTests/Fakes/FakeRunSettings.cs +++ b/src/NUnitTestAdapterTests/Fakes/FakeRunSettings.cs @@ -24,44 +24,43 @@ using System; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; -namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes +namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes; + +class FakeRunSettings : IRunSettings { - class FakeRunSettings : IRunSettings + ISettingsProvider IRunSettings.GetSettings(string settingsName) { - ISettingsProvider IRunSettings.GetSettings(string settingsName) - { - throw new NotImplementedException(); - } - - public virtual string SettingsXml => "false5"; + throw new NotImplementedException(); } - class FakeRunSettingsForTestOutput : FakeRunSettings - { - public override string SettingsXml => "TestResultsfalse"; - } + public virtual string SettingsXml => "false5"; +} - class FakeRunSettingsForTestOutputAndWorkDir : FakeRunSettings - { - private readonly string _testOutput; - private readonly string _workDir; +class FakeRunSettingsForTestOutput : FakeRunSettings +{ + public override string SettingsXml => "TestResultsfalse"; +} - public FakeRunSettingsForTestOutputAndWorkDir(string testOutput, string workDir) - { - _workDir = workDir; - _testOutput = testOutput; - } - public override string SettingsXml => $"{_workDir}{_testOutput}false"; - } +class FakeRunSettingsForTestOutputAndWorkDir : FakeRunSettings +{ + private readonly string _testOutput; + private readonly string _workDir; - class FakeRunSettingsForWhere : FakeRunSettings + public FakeRunSettingsForTestOutputAndWorkDir(string testOutput, string workDir) { - private readonly string _where; - - public FakeRunSettingsForWhere(string where) - { - _where = where; - } - public override string SettingsXml => $"{_where}false"; + _workDir = workDir; + _testOutput = testOutput; } + public override string SettingsXml => $"{_workDir}{_testOutput}false"; } + +class FakeRunSettingsForWhere : FakeRunSettings +{ + private readonly string _where; + + public FakeRunSettingsForWhere(string where) + { + _where = where; + } + public override string SettingsXml => $"{_where}false"; +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Fakes/FakeTestData.cs b/src/NUnitTestAdapterTests/Fakes/FakeTestData.cs index 7b4f8ed0..5ab17bf1 100644 --- a/src/NUnitTestAdapterTests/Fakes/FakeTestData.cs +++ b/src/NUnitTestAdapterTests/Fakes/FakeTestData.cs @@ -25,19 +25,19 @@ using System.Reflection; using System.Xml; -namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes +namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes; + +/// +/// FakeTestData provides xml data representing a test. +/// +public static class FakeTestData { - /// - /// FakeTestData provides xml data representing a test. - /// - public static class FakeTestData - { - // ReSharper disable once UnusedMember.Local - private static void FakeTestCase() { } // LineNumber should be this line + // ReSharper disable once UnusedMember.Local + private static void FakeTestCase() { } // LineNumber should be this line - #region TestXmls - public const string TestXml = - @" "; - public const string HierarchyTestXml = @" + public const string HierarchyTestXml = @" @@ -115,10 +115,10 @@ public static class FakeTestData "; - #endregion + #endregion - public const string ResultXml = - @" "; - public const string DisplayName = "FakeTestCase"; + public const string DisplayName = "FakeTestCase"; - public const string FullyQualifiedName = "NUnit.VisualStudio.TestAdapter.Tests.Fakes.FakeTestData.FakeTestCase"; + public const string FullyQualifiedName = "NUnit.VisualStudio.TestAdapter.Tests.Fakes.FakeTestData.FakeTestCase"; - public static readonly string AssemblyPath = - typeof(FakeTestData).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName; + public static readonly string AssemblyPath = + typeof(FakeTestData).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName; - public static readonly string CodeFile = Path.Combine(Path.GetDirectoryName(AssemblyPath), @"..\..\..\Fakes\FakeTestData.cs"); + public static readonly string CodeFile = Path.Combine(Path.GetDirectoryName(AssemblyPath), @"..\..\..\Fakes\FakeTestData.cs"); - // NOTE: If the location of the FakeTestCase method defined - // above changes, update the value of LineNumber. - public const int LineNumber = 36; + // NOTE: If the location of the FakeTestCase method defined + // above changes, update the value of LineNumber. + public const int LineNumber = 36; - public static XmlNode GetTestNode() - { - return XmlHelper.CreateXmlNode(TestXml).SelectSingleNode("test-case"); - } + public static XmlNode GetTestNode() + { + return XmlHelper.CreateXmlNode(TestXml).SelectSingleNode("test-case"); + } - public static XmlNodeList GetTestNodes() - { - return XmlHelper.CreateXmlNode(HierarchyTestXml).SelectNodes("//test-case"); - } + public static XmlNodeList GetTestNodes() + { + return XmlHelper.CreateXmlNode(HierarchyTestXml).SelectNodes("//test-case"); + } - public static XmlNode GetResultNode() - { - return XmlHelper.CreateXmlNode(ResultXml).SelectSingleNode("test-case"); - } + public static XmlNode GetResultNode() + { + return XmlHelper.CreateXmlNode(ResultXml).SelectSingleNode("test-case"); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Fakes/MessageLoggerStub.cs b/src/NUnitTestAdapterTests/Fakes/MessageLoggerStub.cs index db5e8566..391aa7ac 100644 --- a/src/NUnitTestAdapterTests/Fakes/MessageLoggerStub.cs +++ b/src/NUnitTestAdapterTests/Fakes/MessageLoggerStub.cs @@ -26,23 +26,22 @@ using System.Linq; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; -namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes +namespace NUnit.VisualStudio.TestAdapter.Tests.Fakes; + +public class MessageLoggerStub : IMessageLogger { - public class MessageLoggerStub : IMessageLogger + private readonly List> messages = new (); + public void SendMessage(TestMessageLevel testMessageLevel, string message) { - private readonly List> messages = new (); - public void SendMessage(TestMessageLevel testMessageLevel, string message) - { messages.Add(new Tuple(testMessageLevel, message)); } - public TestMessageLevel LatestTestMessageLevel => messages.Last().Item1; - public string LatestMessage => messages.Last().Item2; + public TestMessageLevel LatestTestMessageLevel => messages.Last().Item1; + public string LatestMessage => messages.Last().Item2; - public int Count => messages.Count; + public int Count => messages.Count; - public IEnumerable> Messages => messages; - public IEnumerable> WarningMessages => messages.Where(o => o.Item1 == TestMessageLevel.Warning); - public IEnumerable> ErrorMessages => messages.Where(o => o.Item1 == TestMessageLevel.Error); - } -} + public IEnumerable> Messages => messages; + public IEnumerable> WarningMessages => messages.Where(o => o.Item1 == TestMessageLevel.Warning); + public IEnumerable> ErrorMessages => messages.Where(o => o.Item1 == TestMessageLevel.Error); +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Filtering/FilteringTestUtils.cs b/src/NUnitTestAdapterTests/Filtering/FilteringTestUtils.cs index ef7d9fab..7dcb965f 100644 --- a/src/NUnitTestAdapterTests/Filtering/FilteringTestUtils.cs +++ b/src/NUnitTestAdapterTests/Filtering/FilteringTestUtils.cs @@ -30,38 +30,37 @@ using NSubstitute; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering +namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering; + +public static class FilteringTestUtils { - public static class FilteringTestUtils + public static ITestCaseFilterExpression CreateVSTestFilterExpression(string filter) { - public static ITestCaseFilterExpression CreateVSTestFilterExpression(string filter) - { - var filterExpressionWrapperType = Type.GetType("Microsoft.VisualStudio.TestPlatform.Common.Filtering.FilterExpressionWrapper, Microsoft.VisualStudio.TestPlatform.Common", throwOnError: true); + var filterExpressionWrapperType = Type.GetType("Microsoft.VisualStudio.TestPlatform.Common.Filtering.FilterExpressionWrapper, Microsoft.VisualStudio.TestPlatform.Common", throwOnError: true); - var filterExpressionWrapper = - filterExpressionWrapperType.GetTypeInfo() + var filterExpressionWrapper = + filterExpressionWrapperType.GetTypeInfo() .GetConstructor(new[] { typeof(string) }) .Invoke(new object[] { filter }); - return (ITestCaseFilterExpression)Type.GetType("Microsoft.VisualStudio.TestPlatform.Common.Filtering.TestCaseFilterExpression, Microsoft.VisualStudio.TestPlatform.Common", throwOnError: true).GetTypeInfo() - .GetConstructor(new[] { filterExpressionWrapperType }) - .Invoke(new[] { filterExpressionWrapper }); - } + return (ITestCaseFilterExpression)Type.GetType("Microsoft.VisualStudio.TestPlatform.Common.Filtering.TestCaseFilterExpression, Microsoft.VisualStudio.TestPlatform.Common", throwOnError: true).GetTypeInfo() + .GetConstructor(new[] { filterExpressionWrapperType }) + .Invoke(new[] { filterExpressionWrapper }); + } - public static VsTestFilter CreateTestFilter(ITestCaseFilterExpression filterExpression) - { - var context = Substitute.For(); - context.GetTestCaseFilter(null, null).ReturnsForAnyArgs(filterExpression); - var settings = Substitute.For(); - settings.DiscoveryMethod.Returns(DiscoveryMethod.Legacy); - return VsTestFilterFactory.CreateVsTestFilter(settings, context); - } + public static VsTestFilter CreateTestFilter(ITestCaseFilterExpression filterExpression) + { + var context = Substitute.For(); + context.GetTestCaseFilter(null, null).ReturnsForAnyArgs(filterExpression); + var settings = Substitute.For(); + settings.DiscoveryMethod.Returns(DiscoveryMethod.Legacy); + return VsTestFilterFactory.CreateVsTestFilter(settings, context); + } - public static void AssertExpectedResult(ITestCaseFilterExpression filterExpression, IReadOnlyCollection testCases, IReadOnlyCollection expectedMatchingTestNames) - { - var matchingTestCases = CreateTestFilter(filterExpression).CheckFilter(testCases); + public static void AssertExpectedResult(ITestCaseFilterExpression filterExpression, IReadOnlyCollection testCases, IReadOnlyCollection expectedMatchingTestNames) + { + var matchingTestCases = CreateTestFilter(filterExpression).CheckFilter(testCases); - Assert.That(matchingTestCases.Select(t => t.FullyQualifiedName), Is.EquivalentTo(expectedMatchingTestNames)); - } + Assert.That(matchingTestCases.Select(t => t.FullyQualifiedName), Is.EquivalentTo(expectedMatchingTestNames)); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Filtering/NUnitTestFilterBuilderTests.cs b/src/NUnitTestAdapterTests/Filtering/NUnitTestFilterBuilderTests.cs index 6d9cdef4..92ada449 100644 --- a/src/NUnitTestAdapterTests/Filtering/NUnitTestFilterBuilderTests.cs +++ b/src/NUnitTestAdapterTests/Filtering/NUnitTestFilterBuilderTests.cs @@ -27,13 +27,13 @@ using NUnit.Engine; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering +namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering; + +public class NUnitTestFilterBuilderTests { - public class NUnitTestFilterBuilderTests + [Test] + public void ThatConvertTfsFilterToNUnitFilterHandlesNoTests() { - [Test] - public void ThatConvertTfsFilterToNUnitFilterHandlesNoTests() - { var filterService = Substitute.For(); var settings = Substitute.For(); settings.AssemblySelectLimit.Returns(2000); @@ -44,9 +44,9 @@ public void ThatConvertTfsFilterToNUnitFilterHandlesNoTests() Assert.That(results, Is.EqualTo(NUnitTestFilterBuilder.NoTestsFound)); } - [Test] - public void ThatWhereFilterIsAdded() - { + [Test] + public void ThatWhereFilterIsAdded() + { var filterService = Substitute.For(); var settings = Substitute.For(); settings.AssemblySelectLimit.Returns(2000); @@ -57,5 +57,4 @@ public void ThatWhereFilterIsAdded() sut.FilterByWhere(where); testFilterBuilder.Received().SelectWhere(Arg.Is(x => x == where)); } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Filtering/TestDoubleFilterExpression.cs b/src/NUnitTestAdapterTests/Filtering/TestDoubleFilterExpression.cs index 99931473..c4cda25c 100644 --- a/src/NUnitTestAdapterTests/Filtering/TestDoubleFilterExpression.cs +++ b/src/NUnitTestAdapterTests/Filtering/TestDoubleFilterExpression.cs @@ -27,28 +27,27 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; -namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering +namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering; + +public sealed class TestDoubleFilterExpression : ITestCaseFilterExpression { - public sealed class TestDoubleFilterExpression : ITestCaseFilterExpression - { - private readonly Func, bool> predicate; + private readonly Func, bool> predicate; - public TestDoubleFilterExpression(string testCaseFilterValue, Func, bool> predicate) - { + public TestDoubleFilterExpression(string testCaseFilterValue, Func, bool> predicate) + { TestCaseFilterValue = testCaseFilterValue; this.predicate = predicate; } - public string TestCaseFilterValue { get; } + public string TestCaseFilterValue { get; } - public bool MatchTestCase(TestCase testCase, Func propertyValueProvider) - { + public bool MatchTestCase(TestCase testCase, Func propertyValueProvider) + { return predicate.Invoke(propertyValueProvider); } - public static TestDoubleFilterExpression AnyIsEqualTo(string propertyName, object value) - { + public static TestDoubleFilterExpression AnyIsEqualTo(string propertyName, object value) + { return new ($"{propertyName}={value}", propertyValueProvider => propertyValueProvider.Invoke(propertyName) is IEnumerable list && list.Cast().Contains(value)); } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Filtering/TestFilterTests.cs b/src/NUnitTestAdapterTests/Filtering/TestFilterTests.cs index 214d1baf..313875f9 100644 --- a/src/NUnitTestAdapterTests/Filtering/TestFilterTests.cs +++ b/src/NUnitTestAdapterTests/Filtering/TestFilterTests.cs @@ -31,160 +31,159 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Tests.Fakes; -namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering +namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering; + +[TestFixture, Category("TFS")] +public class TestFilterTests { - [TestFixture, Category("TFS")] - public class TestFilterTests + private IAdapterSettings settings; + + [OneTimeSetUp] + public void Setup() + { + settings = Substitute.For(); + settings.DiscoveryMethod.Returns(DiscoveryMethod.Legacy); + } + + + [Test] + public void PropertyProvider() + { + var prop = VsTestFilter.PropertyProvider("Priority"); + Assert.That(prop, Is.Not.Null); + prop = VsTestFilter.PropertyProvider("TestCategory"); + Assert.That(prop, Is.Not.Null); + prop = VsTestFilter.PropertyProvider("Category"); + Assert.That(prop, Is.Not.Null); + } + + [Test] + public void TraitProvider() + { + var trait = VsTestFilter.TraitProvider("TestCategory"); + Assert.That(trait, Is.Not.Null); + trait = VsTestFilter.TraitProvider("Category"); + Assert.That(trait, Is.Not.Null); + } + + [Test] + public void TraitProviderWithNoCategory() + { + var trait = VsTestFilter.TraitProvider("JustKidding"); + Assert.That(trait, Is.Null); + } + + [Test] + public void PropertyValueProviderFqn() + { + var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); + var obj = VsTestFilter.PropertyValueProvider(tc, "FullyQualifiedName"); + Assert.That(obj, Is.SameAs("Test1")); + } + + [Test] + public void PropertyValueProviderWithOneCategoryAndTestCategoryAsFilter() + { + var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); + tc.AddTrait("Category", "CI"); + var obj = VsTestFilter.PropertyValueProvider(tc, "TestCategory"); + Assert.That(obj, Is.SameAs("CI")); + } + + [Test] + public void PropertyValueProviderWithOneCategoryAndCategoryAsFilter() + { + var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); + tc.AddTrait("Category", "CI"); + var obj = VsTestFilter.PropertyValueProvider(tc, "Category"); + Assert.That(obj, Is.SameAs("CI")); + } + + [Test] + public void PropertyValueProviderWithNoTraitsAndTestCategoryAsFilter() + { + var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); + var obj = VsTestFilter.PropertyValueProvider(tc, "TestCategory"); + Assert.That(obj, Is.Null); + } + + [Test] + public void PropertyValueProviderWithNoTraitsAndCategoryAsFilter() + { + var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); + var obj = VsTestFilter.PropertyValueProvider(tc, "Category"); + Assert.That(obj, Is.Null); + } + + [Test] + public void PropertyValueProviderWithMultipleCategoriesAndTestCategoryAsFilter() + { + var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); + tc.AddTrait("Category", "CI"); + tc.AddTrait("Category", "MyOwn"); + var obj = VsTestFilter.PropertyValueProvider(tc, "TestCategory") as string[]; + Assert.That(obj, Is.Not.Null); + Assert.That(obj.Length, Is.EqualTo(2)); + Assert.That(obj[0], Is.SameAs("CI")); + Assert.That(obj[1], Is.SameAs("MyOwn")); + } + + [Test] + public void PropertyValueProviderWithMultipleCategoriesAndCategoryAsFilter() + { + var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); + tc.AddTrait("Category", "CI"); + tc.AddTrait("Category", "MyOwn"); + var obj = VsTestFilter.PropertyValueProvider(tc, "Category") as string[]; + Assert.That(obj, Is.Not.Null); + Assert.That(obj.Length, Is.EqualTo(2)); + Assert.That(obj[0], Is.SameAs("CI")); + Assert.That(obj[1], Is.SameAs("MyOwn")); + } + + [Test] + public void PropertyValueProviderCategoryFail() + { + var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); + tc.AddTrait("Category", "CI"); + var obj = VsTestFilter.PropertyValueProvider(tc, "Garbage"); + Assert.That(obj, Is.Null); + } + + + [TestCase("CategoryThatMatchesNothing", new string[0])] + [TestCase("AsmCat", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest", "nUnitClassLibrary.NestedClasses.NC11", "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] + [TestCase("BaseClass", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] + [TestCase("Base", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] + [TestCase("DerivedClass", new[] { "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] + [TestCase("Derived", new[] { "nUnitClassLibrary.ClassD.dNUnitTest" })] + [TestCase("NS1", new[] { "nUnitClassLibrary.NestedClasses.NC11" })] + [TestCase("NS11", new[] { "nUnitClassLibrary.NestedClasses.NC11" })] + [TestCase("NS2", new[] { "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] + [TestCase("NS21", new[] { "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] + public void CanFilterConvertedTestsByCategoryWithTestCategoryAsFilter(string category, IReadOnlyCollection expectedMatchingTestNames) + { + FilteringTestUtils.AssertExpectedResult( + TestDoubleFilterExpression.AnyIsEqualTo("TestCategory", category), + TestCaseUtils.ConvertTestCases(FakeTestData.HierarchyTestXml), + expectedMatchingTestNames); + } + + [TestCase("CategoryThatMatchesNothing", new string[0])] + [TestCase("AsmCat", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest", "nUnitClassLibrary.NestedClasses.NC11", "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] + [TestCase("BaseClass", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] + [TestCase("Base", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] + [TestCase("DerivedClass", new[] { "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] + [TestCase("Derived", new[] { "nUnitClassLibrary.ClassD.dNUnitTest" })] + [TestCase("NS1", new[] { "nUnitClassLibrary.NestedClasses.NC11" })] + [TestCase("NS11", new[] { "nUnitClassLibrary.NestedClasses.NC11" })] + [TestCase("NS2", new[] { "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] + [TestCase("NS21", new[] { "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] + public void CanFilterConvertedTestsByCategoryWithCategoryAsFilter(string category, IReadOnlyCollection expectedMatchingTestNames) { - private IAdapterSettings settings; - - [OneTimeSetUp] - public void Setup() - { - settings = Substitute.For(); - settings.DiscoveryMethod.Returns(DiscoveryMethod.Legacy); - } - - - [Test] - public void PropertyProvider() - { - var prop = VsTestFilter.PropertyProvider("Priority"); - Assert.That(prop, Is.Not.Null); - prop = VsTestFilter.PropertyProvider("TestCategory"); - Assert.That(prop, Is.Not.Null); - prop = VsTestFilter.PropertyProvider("Category"); - Assert.That(prop, Is.Not.Null); - } - - [Test] - public void TraitProvider() - { - var trait = VsTestFilter.TraitProvider("TestCategory"); - Assert.That(trait, Is.Not.Null); - trait = VsTestFilter.TraitProvider("Category"); - Assert.That(trait, Is.Not.Null); - } - - [Test] - public void TraitProviderWithNoCategory() - { - var trait = VsTestFilter.TraitProvider("JustKidding"); - Assert.That(trait, Is.Null); - } - - [Test] - public void PropertyValueProviderFqn() - { - var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); - var obj = VsTestFilter.PropertyValueProvider(tc, "FullyQualifiedName"); - Assert.That(obj, Is.SameAs("Test1")); - } - - [Test] - public void PropertyValueProviderWithOneCategoryAndTestCategoryAsFilter() - { - var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); - tc.AddTrait("Category", "CI"); - var obj = VsTestFilter.PropertyValueProvider(tc, "TestCategory"); - Assert.That(obj, Is.SameAs("CI")); - } - - [Test] - public void PropertyValueProviderWithOneCategoryAndCategoryAsFilter() - { - var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); - tc.AddTrait("Category", "CI"); - var obj = VsTestFilter.PropertyValueProvider(tc, "Category"); - Assert.That(obj, Is.SameAs("CI")); - } - - [Test] - public void PropertyValueProviderWithNoTraitsAndTestCategoryAsFilter() - { - var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); - var obj = VsTestFilter.PropertyValueProvider(tc, "TestCategory"); - Assert.That(obj, Is.Null); - } - - [Test] - public void PropertyValueProviderWithNoTraitsAndCategoryAsFilter() - { - var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); - var obj = VsTestFilter.PropertyValueProvider(tc, "Category"); - Assert.That(obj, Is.Null); - } - - [Test] - public void PropertyValueProviderWithMultipleCategoriesAndTestCategoryAsFilter() - { - var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); - tc.AddTrait("Category", "CI"); - tc.AddTrait("Category", "MyOwn"); - var obj = VsTestFilter.PropertyValueProvider(tc, "TestCategory") as string[]; - Assert.That(obj, Is.Not.Null); - Assert.That(obj.Length, Is.EqualTo(2)); - Assert.That(obj[0], Is.SameAs("CI")); - Assert.That(obj[1], Is.SameAs("MyOwn")); - } - - [Test] - public void PropertyValueProviderWithMultipleCategoriesAndCategoryAsFilter() - { - var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); - tc.AddTrait("Category", "CI"); - tc.AddTrait("Category", "MyOwn"); - var obj = VsTestFilter.PropertyValueProvider(tc, "Category") as string[]; - Assert.That(obj, Is.Not.Null); - Assert.That(obj.Length, Is.EqualTo(2)); - Assert.That(obj[0], Is.SameAs("CI")); - Assert.That(obj[1], Is.SameAs("MyOwn")); - } - - [Test] - public void PropertyValueProviderCategoryFail() - { - var tc = new TestCase("Test1", new Uri("executor://NUnitTestExecutor"), "NUnit.VSIX"); - tc.AddTrait("Category", "CI"); - var obj = VsTestFilter.PropertyValueProvider(tc, "Garbage"); - Assert.That(obj, Is.Null); - } - - - [TestCase("CategoryThatMatchesNothing", new string[0])] - [TestCase("AsmCat", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest", "nUnitClassLibrary.NestedClasses.NC11", "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] - [TestCase("BaseClass", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] - [TestCase("Base", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] - [TestCase("DerivedClass", new[] { "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] - [TestCase("Derived", new[] { "nUnitClassLibrary.ClassD.dNUnitTest" })] - [TestCase("NS1", new[] { "nUnitClassLibrary.NestedClasses.NC11" })] - [TestCase("NS11", new[] { "nUnitClassLibrary.NestedClasses.NC11" })] - [TestCase("NS2", new[] { "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] - [TestCase("NS21", new[] { "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] - public void CanFilterConvertedTestsByCategoryWithTestCategoryAsFilter(string category, IReadOnlyCollection expectedMatchingTestNames) - { - FilteringTestUtils.AssertExpectedResult( - TestDoubleFilterExpression.AnyIsEqualTo("TestCategory", category), - TestCaseUtils.ConvertTestCases(FakeTestData.HierarchyTestXml), - expectedMatchingTestNames); - } - - [TestCase("CategoryThatMatchesNothing", new string[0])] - [TestCase("AsmCat", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest", "nUnitClassLibrary.NestedClasses.NC11", "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] - [TestCase("BaseClass", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] - [TestCase("Base", new[] { "nUnitClassLibrary.Class1.nUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] - [TestCase("DerivedClass", new[] { "nUnitClassLibrary.ClassD.dNUnitTest", "nUnitClassLibrary.ClassD.nUnitTest" })] - [TestCase("Derived", new[] { "nUnitClassLibrary.ClassD.dNUnitTest" })] - [TestCase("NS1", new[] { "nUnitClassLibrary.NestedClasses.NC11" })] - [TestCase("NS11", new[] { "nUnitClassLibrary.NestedClasses.NC11" })] - [TestCase("NS2", new[] { "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] - [TestCase("NS21", new[] { "nUnitClassLibrary.NestedClasses+NestedClass2.NC21" })] - public void CanFilterConvertedTestsByCategoryWithCategoryAsFilter(string category, IReadOnlyCollection expectedMatchingTestNames) - { - FilteringTestUtils.AssertExpectedResult( - TestDoubleFilterExpression.AnyIsEqualTo("Category", category), - TestCaseUtils.ConvertTestCases(FakeTestData.HierarchyTestXml), - expectedMatchingTestNames); - } + FilteringTestUtils.AssertExpectedResult( + TestDoubleFilterExpression.AnyIsEqualTo("Category", category), + TestCaseUtils.ConvertTestCases(FakeTestData.HierarchyTestXml), + expectedMatchingTestNames); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Filtering/VSTestFilterStringTestsLegacy.cs b/src/NUnitTestAdapterTests/Filtering/VSTestFilterStringTestsLegacy.cs index 6e5d479e..4d208f30 100644 --- a/src/NUnitTestAdapterTests/Filtering/VSTestFilterStringTestsLegacy.cs +++ b/src/NUnitTestAdapterTests/Filtering/VSTestFilterStringTestsLegacy.cs @@ -26,20 +26,20 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering +namespace NUnit.VisualStudio.TestAdapter.Tests.Filtering; + +public static class VSTestFilterStringTestsLegacy { - public static class VSTestFilterStringTestsLegacy + [TestCase(null, new[] { "NonExplicitParent.NonExplicitTest" })] + [TestCase("", new[] { "NonExplicitParent.NonExplicitTest" })] + [TestCase("TestCategory = CategoryThatMatchesNothing", new string[0])] + [TestCase("MeaninglessName", new string[0])] + [TestCase("TestCategory != CategoryThatMatchesNothing", new[] { "NonExplicitParent.NonExplicitTest" })] + [TestCase("TestCategory = SomeCat", new[] { "NonExplicitParent.NonExplicitTest" })] + [TestCase("TestCategory != SomeCat", new string[0])] + public static void NoFiltersIncludeExplicitTests(string vsTestFilterString, IReadOnlyCollection nonExplicitTestIds) { - [TestCase(null, new[] { "NonExplicitParent.NonExplicitTest" })] - [TestCase("", new[] { "NonExplicitParent.NonExplicitTest" })] - [TestCase("TestCategory = CategoryThatMatchesNothing", new string[0])] - [TestCase("MeaninglessName", new string[0])] - [TestCase("TestCategory != CategoryThatMatchesNothing", new[] { "NonExplicitParent.NonExplicitTest" })] - [TestCase("TestCategory = SomeCat", new[] { "NonExplicitParent.NonExplicitTest" })] - [TestCase("TestCategory != SomeCat", new string[0])] - public static void NoFiltersIncludeExplicitTests(string vsTestFilterString, IReadOnlyCollection nonExplicitTestIds) - { - var result = ApplyFilter(vsTestFilterString, @" + var result = ApplyFilter(vsTestFilterString, @" @@ -60,15 +60,14 @@ public static void NoFiltersIncludeExplicitTests(string vsTestFilterString, IRea "); - Assert.That(from test in result select test.FullyQualifiedName, Is.EquivalentTo(nonExplicitTestIds)); - } + Assert.That(from test in result select test.FullyQualifiedName, Is.EquivalentTo(nonExplicitTestIds)); + } - private static IEnumerable ApplyFilter(string vsTestFilterString, string testCasesXml) - { - var filter = FilteringTestUtils.CreateTestFilter(string.IsNullOrEmpty(vsTestFilterString) ? null : - FilteringTestUtils.CreateVSTestFilterExpression(vsTestFilterString)); + private static IEnumerable ApplyFilter(string vsTestFilterString, string testCasesXml) + { + var filter = FilteringTestUtils.CreateTestFilter(string.IsNullOrEmpty(vsTestFilterString) ? null : + FilteringTestUtils.CreateVSTestFilterExpression(vsTestFilterString)); - return filter.CheckFilter(TestCaseUtils.ConvertTestCases(testCasesXml)); - } + return filter.CheckFilter(TestCaseUtils.ConvertTestCases(testCasesXml)); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/IssueNo24Tests.cs b/src/NUnitTestAdapterTests/IssueNo24Tests.cs index 7b68f7d5..9009eec9 100644 --- a/src/NUnitTestAdapterTests/IssueNo24Tests.cs +++ b/src/NUnitTestAdapterTests/IssueNo24Tests.cs @@ -1,36 +1,35 @@ using System.Threading; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +[Explicit] +[TestFixture] +[Category("LongRunning")] +class IssueNo24Tests { [Explicit] - [TestFixture] - [Category("LongRunning")] - class IssueNo24Tests + [Test] + public void Quick() + { + Thread.Sleep(1); + } + [Explicit] + [Test] + public void Slow() + { + Thread.Sleep(150000); + } + [Explicit] + [Test] + public void Slower() + { + Thread.Sleep(250000); + } + [Explicit] + [Test] + public void TooLateButFast() { - [Explicit] - [Test] - public void Quick() - { - Thread.Sleep(1); - } - [Explicit] - [Test] - public void Slow() - { - Thread.Sleep(150000); - } - [Explicit] - [Test] - public void Slower() - { - Thread.Sleep(250000); - } - [Explicit] - [Test] - public void TooLateButFast() - { - Thread.Sleep(1); - } + Thread.Sleep(1); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NUnit3TestDiscovererTests.cs b/src/NUnitTestAdapterTests/NUnit3TestDiscovererTests.cs index 04459bbc..dcc67002 100644 --- a/src/NUnitTestAdapterTests/NUnit3TestDiscovererTests.cs +++ b/src/NUnitTestAdapterTests/NUnit3TestDiscovererTests.cs @@ -30,27 +30,26 @@ using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +[TestFixture] +public class NUnit3TestDiscovererTests { - [TestFixture] - public class NUnit3TestDiscovererTests + [Test] + public void VerifyNUnit3TestDiscovererHasCategoryAttribute() { - [Test] - public void VerifyNUnit3TestDiscovererHasCategoryAttribute() - { - var attribute = typeof(NUnit3TestDiscoverer).GetTypeInfo().GetCustomAttribute(typeof(System.ComponentModel.CategoryAttribute)); - Assert.That(attribute, Is.Not.Null); - Assert.That((attribute as System.ComponentModel.CategoryAttribute)?.Category, Is.EqualTo("managed")); - } + var attribute = typeof(NUnit3TestDiscoverer).GetTypeInfo().GetCustomAttribute(typeof(System.ComponentModel.CategoryAttribute)); + Assert.That(attribute, Is.Not.Null); + Assert.That((attribute as System.ComponentModel.CategoryAttribute)?.Category, Is.EqualTo("managed")); + } - [Test] - public void ThatDiscovererNUnitEngineAdapterIsInitialized() - { - var sut = new NUnit3TestDiscoverer(); - Assert.That(sut.NUnitEngineAdapter, Is.Not.Null); - var dc = Substitute.For(); - sut.DiscoverTests(new List(), dc, null, null); - Assert.That(sut.NUnitEngineAdapter, Is.Not.Null); - } + [Test] + public void ThatDiscovererNUnitEngineAdapterIsInitialized() + { + var sut = new NUnit3TestDiscoverer(); + Assert.That(sut.NUnitEngineAdapter, Is.Not.Null); + var dc = Substitute.For(); + sut.DiscoverTests(new List(), dc, null, null); + Assert.That(sut.NUnitEngineAdapter, Is.Not.Null); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitDiscoveryTests.cs b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitDiscoveryTests.cs index 5db9b5fb..5229d7fe 100644 --- a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitDiscoveryTests.cs +++ b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitDiscoveryTests.cs @@ -7,15 +7,15 @@ using NUnit.VisualStudio.TestAdapter.NUnitEngine; // ReSharper disable StringLiteralTypo -namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests +namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests; + +public class NUnitDiscoveryTests { - public class NUnitDiscoveryTests - { - private ITestLogger logger; - private IAdapterSettings settings; + private ITestLogger logger; + private IAdapterSettings settings; - private const string FullDiscoveryXml = - @" + private const string FullDiscoveryXml = + @" @@ -454,44 +454,44 @@ public class NUnitDiscoveryTests "; - [SetUp] - public void SetUp() - { - logger = Substitute.For(); - settings = Substitute.For(); - settings.DiscoveryMethod.Returns(DiscoveryMethod.Legacy); - } + [SetUp] + public void SetUp() + { + logger = Substitute.For(); + settings = Substitute.For(); + settings.DiscoveryMethod.Returns(DiscoveryMethod.Legacy); + } - [Test] - public void ThatWeCanParseDiscoveryXml() + [Test] + public void ThatWeCanParseDiscoveryXml() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(FullDiscoveryXml))); + + Assert.That(ndr.Id, Is.EqualTo("2")); + Assert.That(ndr.TestAssembly, Is.Not.Null, "Missing test assembly"); + Assert.That(ndr.TestAssembly.NUnitDiscoveryProperties.Properties.Count(), Is.EqualTo(2)); + Assert.That(ndr.TestAssembly.NUnitDiscoveryProperties.AllInternal); + var suite = ndr.TestAssembly.TestSuites.SingleOrDefault(); + Assert.That(suite, Is.Not.Null, "No top level suite"); + var fixturesCount = suite.TestFixtures.Count(); + var genericFixturesCount = suite.GenericFixtures.Count(); + var parameterizedFicturesCount = suite.ParameterizedFixtures.Count(); + var setupFixturesCount = suite.SetUpFixtures.Count(); + Assert.Multiple(() => { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(FullDiscoveryXml))); - - Assert.That(ndr.Id, Is.EqualTo("2")); - Assert.That(ndr.TestAssembly, Is.Not.Null, "Missing test assembly"); - Assert.That(ndr.TestAssembly.NUnitDiscoveryProperties.Properties.Count(), Is.EqualTo(2)); - Assert.That(ndr.TestAssembly.NUnitDiscoveryProperties.AllInternal); - var suite = ndr.TestAssembly.TestSuites.SingleOrDefault(); - Assert.That(suite, Is.Not.Null, "No top level suite"); - var fixturesCount = suite.TestFixtures.Count(); - var genericFixturesCount = suite.GenericFixtures.Count(); - var parameterizedFicturesCount = suite.ParameterizedFixtures.Count(); - var setupFixturesCount = suite.SetUpFixtures.Count(); - Assert.Multiple(() => - { - Assert.That(fixturesCount, Is.EqualTo(12), nameof(fixturesCount)); - Assert.That(genericFixturesCount, Is.EqualTo(2), nameof(genericFixturesCount)); - Assert.That(parameterizedFicturesCount, Is.EqualTo(1), nameof(parameterizedFicturesCount)); - Assert.That(setupFixturesCount, Is.EqualTo(1), nameof(setupFixturesCount)); - }); - } + Assert.That(fixturesCount, Is.EqualTo(12), nameof(fixturesCount)); + Assert.That(genericFixturesCount, Is.EqualTo(2), nameof(genericFixturesCount)); + Assert.That(parameterizedFicturesCount, Is.EqualTo(1), nameof(parameterizedFicturesCount)); + Assert.That(setupFixturesCount, Is.EqualTo(1), nameof(setupFixturesCount)); + }); + } - private const string SimpleTestXml = - @" + private const string SimpleTestXml = + @" @@ -506,115 +506,115 @@ public void ThatWeCanParseDiscoveryXml() "; - [Test] - public void ThatTestCaseHasAllData() + [Test] + public void ThatTestCaseHasAllData() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(SimpleTestXml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + var testCase = topLevelSuite.TestFixtures.First().TestCases.First(); + Assert.Multiple(() => { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(SimpleTestXml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - var testCase = topLevelSuite.TestFixtures.First().TestCases.First(); - Assert.Multiple(() => - { - Assert.That(testCase.Id, Is.EqualTo("0-1074"), "Id fails"); - Assert.That(testCase.Name, Is.EqualTo("TestSucceeds"), "Name fails"); - Assert.That(testCase.FullName, Is.EqualTo("NUnitTestDemo.SimpleTests.TestSucceeds"), "Fullname fails"); - Assert.That(testCase.MethodName, Is.EqualTo("TestSucceeds"), "Methodname fails"); - Assert.That(testCase.ClassName, Is.EqualTo("NUnitTestDemo.SimpleTests"), "Classname fails"); - Assert.That(testCase.RunState, Is.EqualTo(RunStateEnum.Runnable), "Runstate fails"); - Assert.That(testCase.Seed, Is.EqualTo(296066266), "Seed fails"); - Assert.That( - testCase.NUnitDiscoveryProperties.Properties.Single(o => o.Name == "Category").Value, - Is.EqualTo("Whatever")); - Assert.That(testCase.Parent, Is.Not.Null, "Parent missing"); - }); - } + Assert.That(testCase.Id, Is.EqualTo("0-1074"), "Id fails"); + Assert.That(testCase.Name, Is.EqualTo("TestSucceeds"), "Name fails"); + Assert.That(testCase.FullName, Is.EqualTo("NUnitTestDemo.SimpleTests.TestSucceeds"), "Fullname fails"); + Assert.That(testCase.MethodName, Is.EqualTo("TestSucceeds"), "Methodname fails"); + Assert.That(testCase.ClassName, Is.EqualTo("NUnitTestDemo.SimpleTests"), "Classname fails"); + Assert.That(testCase.RunState, Is.EqualTo(RunStateEnum.Runnable), "Runstate fails"); + Assert.That(testCase.Seed, Is.EqualTo(296066266), "Seed fails"); + Assert.That( + testCase.NUnitDiscoveryProperties.Properties.Single(o => o.Name == "Category").Value, + Is.EqualTo("Whatever")); + Assert.That(testCase.Parent, Is.Not.Null, "Parent missing"); + }); + } - [Test] - public void ThatNumberOfTestCasesAreCorrect() + [Test] + public void ThatNumberOfTestCasesAreCorrect() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(FullDiscoveryXml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + var count = topLevelSuite.TestCaseCount; + Assert.That(count, Is.EqualTo(108)); + var actualCount = topLevelSuite.NoOfActualTestCases; + + Assert.Multiple(() => { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(FullDiscoveryXml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - var count = topLevelSuite.TestCaseCount; - Assert.That(count, Is.EqualTo(108)); - var actualCount = topLevelSuite.NoOfActualTestCases; - - Assert.Multiple(() => - { - // Special count checks for some - Assert.That(topLevelSuite.GenericFixtures.Sum(o => o.NoOfActualTestCases), Is.EqualTo(3), - "Generic fixtures counts fails in itself"); - - // Test Case count checks - Assert.That(actualCount, Is.EqualTo(count), "Actual count doesn't match given count"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "AsyncTests").Sum(o => o.NoOfActualTestCases), - Is.EqualTo(7), "Asynctests wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "ConfigFileTests").Sum(o => o.NoOfActualTestCases), - Is.EqualTo(2), "ConfigFileTests wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "ExplicitClass").Sum(o => o.NoOfActualTestCases), - Is.EqualTo(1), "ExplicitClass wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "FixtureWithApartmentAttributeOnClass") - .Sum(o => o.NoOfActualTestCases), - Is.EqualTo(1), "FixtureWithApartmentAttributeOnClass wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "FixtureWithApartmentAttributeOnMethod") - .Sum(o => o.NoOfActualTestCases), - Is.EqualTo(1), "FixtureWithApartmentAttributeOnMethod wrong"); - Assert.That( - topLevelSuite.GenericFixtures.Where(o => o.Name == "GenericTests_IList") - .Sum(o => o.NoOfActualTestCases), - Is.EqualTo(2), "GenericTests_IList<TList> wrong"); - Assert.That( - topLevelSuite.GenericFixtures.Where(o => o.Name == "GenericTests") - .Sum(o => o.NoOfActualTestCases), - Is.EqualTo(1), "GenericTests<T> wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "InheritedTestDerivedClass") - .Sum(o => o.NoOfActualTestCases), - Is.EqualTo(1), "InheritedTestDerivedClass wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "OneTimeSetUpTests") - .Sum(o => o.NoOfActualTestCases), - Is.EqualTo(2), "OneTimeSetUpTests wrong"); - Assert.That( - topLevelSuite.ParameterizedFixtures.Where(o => o.Name == "ParameterizedTestFixture") - .Sum(o => o.NoOfActualTestCases), - Is.EqualTo(6), "ParameterizedTestFixture wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "ParameterizedTests") - .Sum(o => o.NoOfActualTestCases), - Is.EqualTo(23), "ParameterizedTests wrong"); - Assert.That( - topLevelSuite.SetUpFixtures.Where(o => o.Name == "SetUpFixture").Sum(o => o.NoOfActualTestCases), - Is.EqualTo(2), "SetUpFixture wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "SimpleTests").Sum(o => o.NoOfActualTestCases), - Is.EqualTo(20), "SimpleTests wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "TestCaseSourceTests") - .Sum(o => o.NoOfActualTestCases), - Is.EqualTo(3), "TestCaseSourceTests wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "TextOutputTests").Sum(o => o.NoOfActualTestCases), - Is.EqualTo(9), "TextOutputTests wrong"); - Assert.That( - topLevelSuite.TestFixtures.Where(o => o.Name == "Theories").Sum(o => o.NoOfActualTestCases), - Is.EqualTo(27), "Theories wrong"); - }); - Assert.That(ndr.TestAssembly.AllTestCases.Count, Is.EqualTo(108)); - } + // Special count checks for some + Assert.That(topLevelSuite.GenericFixtures.Sum(o => o.NoOfActualTestCases), Is.EqualTo(3), + "Generic fixtures counts fails in itself"); + + // Test Case count checks + Assert.That(actualCount, Is.EqualTo(count), "Actual count doesn't match given count"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "AsyncTests").Sum(o => o.NoOfActualTestCases), + Is.EqualTo(7), "Asynctests wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "ConfigFileTests").Sum(o => o.NoOfActualTestCases), + Is.EqualTo(2), "ConfigFileTests wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "ExplicitClass").Sum(o => o.NoOfActualTestCases), + Is.EqualTo(1), "ExplicitClass wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "FixtureWithApartmentAttributeOnClass") + .Sum(o => o.NoOfActualTestCases), + Is.EqualTo(1), "FixtureWithApartmentAttributeOnClass wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "FixtureWithApartmentAttributeOnMethod") + .Sum(o => o.NoOfActualTestCases), + Is.EqualTo(1), "FixtureWithApartmentAttributeOnMethod wrong"); + Assert.That( + topLevelSuite.GenericFixtures.Where(o => o.Name == "GenericTests_IList") + .Sum(o => o.NoOfActualTestCases), + Is.EqualTo(2), "GenericTests_IList<TList> wrong"); + Assert.That( + topLevelSuite.GenericFixtures.Where(o => o.Name == "GenericTests") + .Sum(o => o.NoOfActualTestCases), + Is.EqualTo(1), "GenericTests<T> wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "InheritedTestDerivedClass") + .Sum(o => o.NoOfActualTestCases), + Is.EqualTo(1), "InheritedTestDerivedClass wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "OneTimeSetUpTests") + .Sum(o => o.NoOfActualTestCases), + Is.EqualTo(2), "OneTimeSetUpTests wrong"); + Assert.That( + topLevelSuite.ParameterizedFixtures.Where(o => o.Name == "ParameterizedTestFixture") + .Sum(o => o.NoOfActualTestCases), + Is.EqualTo(6), "ParameterizedTestFixture wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "ParameterizedTests") + .Sum(o => o.NoOfActualTestCases), + Is.EqualTo(23), "ParameterizedTests wrong"); + Assert.That( + topLevelSuite.SetUpFixtures.Where(o => o.Name == "SetUpFixture").Sum(o => o.NoOfActualTestCases), + Is.EqualTo(2), "SetUpFixture wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "SimpleTests").Sum(o => o.NoOfActualTestCases), + Is.EqualTo(20), "SimpleTests wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "TestCaseSourceTests") + .Sum(o => o.NoOfActualTestCases), + Is.EqualTo(3), "TestCaseSourceTests wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "TextOutputTests").Sum(o => o.NoOfActualTestCases), + Is.EqualTo(9), "TextOutputTests wrong"); + Assert.That( + topLevelSuite.TestFixtures.Where(o => o.Name == "Theories").Sum(o => o.NoOfActualTestCases), + Is.EqualTo(27), "Theories wrong"); + }); + Assert.That(ndr.TestAssembly.AllTestCases.Count, Is.EqualTo(108)); + } - private const string SetupFixtureXml = - @" + private const string SetupFixtureXml = + @" @@ -629,45 +629,45 @@ public void ThatNumberOfTestCasesAreCorrect() "; - [Test] - public void ThatSetUpFixtureWorks() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(SetupFixtureXml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + [Test] + public void ThatSetUpFixtureWorks() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(SetupFixtureXml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - Assert.That(topLevelSuite.SetUpFixtures.Count, Is.EqualTo(1), "Setupfixture count"); - foreach (var setupFixture in topLevelSuite.SetUpFixtures) + Assert.That(topLevelSuite.SetUpFixtures.Count, Is.EqualTo(1), "Setupfixture count"); + foreach (var setupFixture in topLevelSuite.SetUpFixtures) + { + Assert.That(setupFixture.TestFixtures.Count, Is.EqualTo(2), "Test fixtures count"); + Assert.That(setupFixture.RunState, Is.EqualTo(RunStateEnum.Runnable), + "Runstate fails for setupfixture"); + foreach (var testFixture in setupFixture.TestFixtures) { - Assert.That(setupFixture.TestFixtures.Count, Is.EqualTo(2), "Test fixtures count"); - Assert.That(setupFixture.RunState, Is.EqualTo(RunStateEnum.Runnable), - "Runstate fails for setupfixture"); - foreach (var testFixture in setupFixture.TestFixtures) + Assert.That(testFixture.RunState, Is.EqualTo(RunStateEnum.Runnable), + "Runstate fails for testFixture"); + Assert.That(testFixture.TestCases.Count, Is.EqualTo(1), "Testcase count per fixture"); + foreach (var testCase in testFixture.TestCases) { - Assert.That(testFixture.RunState, Is.EqualTo(RunStateEnum.Runnable), - "Runstate fails for testFixture"); - Assert.That(testFixture.TestCases.Count, Is.EqualTo(1), "Testcase count per fixture"); - foreach (var testCase in testFixture.TestCases) + Assert.Multiple(() => { - Assert.Multiple(() => - { - Assert.That(testCase.Name, Does.StartWith("Test"), "Name is wrong"); - Assert.That(testCase.FullName, Does.StartWith("NUnitTestDemo.SetUpFixture.TestFixture")); - Assert.That(testCase.MethodName, Does.StartWith("Test"), "MethodName is wrong"); - Assert.That(testCase.ClassName, Does.StartWith("NUnitTestDemo.SetUpFixture.TestFixture"), - "Name is wrong"); - Assert.That(testCase.RunState, Is.EqualTo(RunStateEnum.Runnable), - "Runstate fails for testCase"); - Assert.That(testCase.Seed, Is.GreaterThan(0), "Seed missing"); - }); - } + Assert.That(testCase.Name, Does.StartWith("Test"), "Name is wrong"); + Assert.That(testCase.FullName, Does.StartWith("NUnitTestDemo.SetUpFixture.TestFixture")); + Assert.That(testCase.MethodName, Does.StartWith("Test"), "MethodName is wrong"); + Assert.That(testCase.ClassName, Does.StartWith("NUnitTestDemo.SetUpFixture.TestFixture"), + "Name is wrong"); + Assert.That(testCase.RunState, Is.EqualTo(RunStateEnum.Runnable), + "Runstate fails for testCase"); + Assert.That(testCase.Seed, Is.GreaterThan(0), "Seed missing"); + }); } } } + } - private const string ParameterizedMethodXml = - @" + private const string ParameterizedMethodXml = + @" @@ -682,36 +682,36 @@ public void ThatSetUpFixtureWorks() "; - [Test] - public void ThatParameterizedMethodsWorks() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(ParameterizedMethodXml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - Assert.That(topLevelSuite.TestCaseCount, Is.EqualTo(3), "Count number from NUnit is wrong"); - Assert.That(topLevelSuite.TestFixtures.Count, Is.EqualTo(1), "Missing text fixture"); - Assert.That(topLevelSuite.TestFixtures.Single().ParameterizedMethods.Count(), Is.EqualTo(1), - "Missing parameterizedMethod"); - Assert.That( - topLevelSuite.TestFixtures.Single().ParameterizedMethods.Single().TestCases.Count, - Is.EqualTo(3)); - } + [Test] + public void ThatParameterizedMethodsWorks() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(ParameterizedMethodXml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + Assert.That(topLevelSuite.TestCaseCount, Is.EqualTo(3), "Count number from NUnit is wrong"); + Assert.That(topLevelSuite.TestFixtures.Count, Is.EqualTo(1), "Missing text fixture"); + Assert.That(topLevelSuite.TestFixtures.Single().ParameterizedMethods.Count(), Is.EqualTo(1), + "Missing parameterizedMethod"); + Assert.That( + topLevelSuite.TestFixtures.Single().ParameterizedMethods.Single().TestCases.Count, + Is.EqualTo(3)); + } - [Test] - public void ThatTheoryWorks() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(FullDiscoveryXml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - var theoryFixture = topLevelSuite.TestFixtures.FirstOrDefault(o => o.Name == "Theories"); - Assert.That(theoryFixture, Is.Not.Null); - } + [Test] + public void ThatTheoryWorks() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(FullDiscoveryXml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + var theoryFixture = topLevelSuite.TestFixtures.FirstOrDefault(o => o.Name == "Theories"); + Assert.That(theoryFixture, Is.Not.Null); + } - private const string ExplicitXml = - @" + private const string ExplicitXml = + @" @@ -733,8 +733,8 @@ public void ThatTheoryWorks() "; - private const string ExplicitQuickTestXml = - @" + private const string ExplicitQuickTestXml = + @" @@ -751,64 +751,64 @@ public void ThatTheoryWorks() "; - [TestCase(ExplicitXml, 3, TestName = nameof(ThatExplicitWorks) + "." + nameof(ExplicitXml))] - public void ThatExplicitWorks(string xml, int count) + [TestCase(ExplicitXml, 3, TestName = nameof(ThatExplicitWorks) + "." + nameof(ExplicitXml))] + public void ThatExplicitWorks(string xml, int count) + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(xml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + Assert.Multiple(() => { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(xml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - Assert.Multiple(() => - { - var first = topLevelSuite.TestFixtures.First(); - Assert.That(first.IsExplicit, $"First {first.Id} failed"); - var second = topLevelSuite.TestFixtures.Skip(1).First(); - Assert.That(second.IsExplicit, $"Second {first.Id} failed"); - var third = topLevelSuite.TestFixtures.Skip(2).First(); - Assert.That(third.IsExplicit, $"Third {first.Id} failed"); - }); - Assert.That(topLevelSuite.IsExplicit, "TopLevelsuite failed"); - Assert.That(ndr.TestAssembly.AllTestCases.Count(), Is.EqualTo(count), "Count failed"); - Assert.Multiple(() => + var first = topLevelSuite.TestFixtures.First(); + Assert.That(first.IsExplicit, $"First {first.Id} failed"); + var second = topLevelSuite.TestFixtures.Skip(1).First(); + Assert.That(second.IsExplicit, $"Second {first.Id} failed"); + var third = topLevelSuite.TestFixtures.Skip(2).First(); + Assert.That(third.IsExplicit, $"Third {first.Id} failed"); + }); + Assert.That(topLevelSuite.IsExplicit, "TopLevelsuite failed"); + Assert.That(ndr.TestAssembly.AllTestCases.Count(), Is.EqualTo(count), "Count failed"); + Assert.Multiple(() => + { + foreach (var testCase in ndr.TestAssembly.AllTestCases) { - foreach (var testCase in ndr.TestAssembly.AllTestCases) - { - Assert.That(testCase.IsExplicitReverse, $"Failed for {testCase.Id}"); - } - }); - } + Assert.That(testCase.IsExplicitReverse, $"Failed for {testCase.Id}"); + } + }); + } - [TestCase(ExplicitQuickTestXml, 1, TestName = nameof(ThatExplicitWorks2) + "." + nameof(ExplicitQuickTestXml))] - public void ThatExplicitWorks2(string xml, int count) + [TestCase(ExplicitQuickTestXml, 1, TestName = nameof(ThatExplicitWorks2) + "." + nameof(ExplicitQuickTestXml))] + public void ThatExplicitWorks2(string xml, int count) + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(xml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + Assert.Multiple(() => { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(xml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - Assert.Multiple(() => - { - Assert.That(topLevelSuite.IsExplicit, "TopLevelsuite failed"); - var first = topLevelSuite.TestSuites.First(); - Assert.That(first.IsExplicit, $"First {first.Id} failed"); - }); + Assert.That(topLevelSuite.IsExplicit, "TopLevelsuite failed"); + var first = topLevelSuite.TestSuites.First(); + Assert.That(first.IsExplicit, $"First {first.Id} failed"); + }); - Assert.That(ndr.TestAssembly.AllTestCases.Count(), Is.EqualTo(count), "Count failed"); - Assert.Multiple(() => + Assert.That(ndr.TestAssembly.AllTestCases.Count(), Is.EqualTo(count), "Count failed"); + Assert.Multiple(() => + { + foreach (var testCase in ndr.TestAssembly.AllTestCases) { - foreach (var testCase in ndr.TestAssembly.AllTestCases) - { - Assert.That(testCase.IsExplicitReverse, $"Failed for {testCase.Id}"); - } - }); - } + Assert.That(testCase.IsExplicitReverse, $"Failed for {testCase.Id}"); + } + }); + } - private const string NotExplicitXml = - @" + private const string NotExplicitXml = + @" @@ -836,18 +836,18 @@ public void ThatExplicitWorks2(string xml, int count) "; - [Test] - public void ThatExplicitWorksWhenOneTestIsNotExplicit() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(NotExplicitXml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - Assert.That(topLevelSuite.IsExplicit, Is.False); - } + [Test] + public void ThatExplicitWorksWhenOneTestIsNotExplicit() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(NotExplicitXml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + Assert.That(topLevelSuite.IsExplicit, Is.False); + } - private const string AsyncTestsXml = - @" + private const string AsyncTestsXml = + @" @@ -888,18 +888,18 @@ public void ThatExplicitWorksWhenOneTestIsNotExplicit() - [Test] - public void ThatAsyncTestsHasSevenTests() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(AsyncTestsXml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - Assert.That(topLevelSuite.NoOfActualTestCases, Is.EqualTo(7)); - } + [Test] + public void ThatAsyncTestsHasSevenTests() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(AsyncTestsXml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + Assert.That(topLevelSuite.NoOfActualTestCases, Is.EqualTo(7)); + } - private const string ParameterizedTestFixtureXml = - @" + private const string ParameterizedTestFixtureXml = + @" @@ -921,19 +921,19 @@ public void ThatAsyncTestsHasSevenTests() "; - [Test] - public void ThatParameterizedTestFixtureHasSixTests() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(ParameterizedTestFixtureXml))); - var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); - Assert.That(topLevelSuite.NoOfActualTestCases, Is.EqualTo(6)); - } + [Test] + public void ThatParameterizedTestFixtureHasSixTests() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(ParameterizedTestFixtureXml))); + var topLevelSuite = ndr.TestAssembly.TestSuites.Single(); + Assert.That(topLevelSuite.NoOfActualTestCases, Is.EqualTo(6)); + } - private const string DotnetXml = - @" + private const string DotnetXml = + @" @@ -971,31 +971,31 @@ public void ThatParameterizedTestFixtureHasSixTests() "; - /// - /// The dotnetxml has no top level suite, but fixtures directly under assembly. - /// - [Test] - public void ThatDotNetTestWorks() + /// + /// The dotnetxml has no top level suite, but fixtures directly under assembly. + /// + [Test] + public void ThatDotNetTestWorks() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(DotnetXml))); + var fixtures = ndr.TestAssembly.TestFixtures; + Assert.That(fixtures.Count(), Is.EqualTo(3), "Didnt find all fixtures"); + foreach (var fixture in fixtures) { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(DotnetXml))); - var fixtures = ndr.TestAssembly.TestFixtures; - Assert.That(fixtures.Count(), Is.EqualTo(3), "Didnt find all fixtures"); - foreach (var fixture in fixtures) - { - Assert.That(fixture.TestCases.Count, Is.EqualTo(3), - "Didnt find all testcases for fixture"); - } - - Assert.That(ndr.TestAssembly.TestSuites.Count, Is.EqualTo(1)); - var suite = ndr.TestAssembly.TestSuites.Single(); - Assert.That(suite.TestFixtures.Count, Is.EqualTo(1)); - Assert.That(suite.TestCaseCount, Is.EqualTo(2)); + Assert.That(fixture.TestCases.Count, Is.EqualTo(3), + "Didnt find all testcases for fixture"); } - private const string MixedExplicitTestSourceXmlForNUnit312 = - @" + Assert.That(ndr.TestAssembly.TestSuites.Count, Is.EqualTo(1)); + var suite = ndr.TestAssembly.TestSuites.Single(); + Assert.That(suite.TestFixtures.Count, Is.EqualTo(1)); + Assert.That(suite.TestCaseCount, Is.EqualTo(2)); + } + + private const string MixedExplicitTestSourceXmlForNUnit312 = + @" @@ -1009,11 +1009,11 @@ public void ThatDotNetTestWorks() "; - /// - /// See issue 1041 at https://github.com/nunit/nunit3-vs-adapter/issues/1044 - /// - private const string MixedExplicitTestSourceXmlForIssue1041 = - @" + /// + /// See issue 1041 at https://github.com/nunit/nunit3-vs-adapter/issues/1044 + /// + private const string MixedExplicitTestSourceXmlForIssue1041 = + @" @@ -1045,23 +1045,23 @@ public void ThatDotNetTestWorks() "; - [TestCase(MixedExplicitTestSourceXmlForIssue1041, 2, 4)] - [TestCase(MixedExplicitTestSourceXmlForNUnit312, 1, 3)] - public void ThatMixedExplicitTestSourceWorks(string xml, int expectedRunnable, int expectedAll) + [TestCase(MixedExplicitTestSourceXmlForIssue1041, 2, 4)] + [TestCase(MixedExplicitTestSourceXmlForNUnit312, 1, 3)] + public void ThatMixedExplicitTestSourceWorks(string xml, int expectedRunnable, int expectedAll) + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(xml))); + Assert.Multiple(() => { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(xml))); - Assert.Multiple(() => - { - Assert.That(ndr.IsExplicit, Is.False, "Explicit check fails"); - Assert.That(ndr.TestAssembly.RunnableTestCases.Count, Is.EqualTo(expectedRunnable), "Runnable number fails"); - Assert.That(ndr.TestAssembly.AllTestCases.Count, Is.EqualTo(expectedAll), "Can't find all testcases"); - }); - } + Assert.That(ndr.IsExplicit, Is.False, "Explicit check fails"); + Assert.That(ndr.TestAssembly.RunnableTestCases.Count, Is.EqualTo(expectedRunnable), "Runnable number fails"); + Assert.That(ndr.TestAssembly.AllTestCases.Count, Is.EqualTo(expectedAll), "Can't find all testcases"); + }); + } - private const string ExplicitRun = - @" + private const string ExplicitRun = + @" @@ -1074,33 +1074,33 @@ public void ThatMixedExplicitTestSourceWorks(string xml, int expectedRunnable, i "; - [Test] - public void ThatExplicitRunWorks() + [Test] + public void ThatExplicitRunWorks() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(ExplicitRun))); + Assert.Multiple(() => { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(ExplicitRun))); - Assert.Multiple(() => - { - Assert.That(ndr.IsExplicit, "Explicit check fails"); - Assert.That(ndr.TestAssembly.AllTestCases.Count, Is.EqualTo(2), "All testcases number fails"); - Assert.That(ndr.TestAssembly.AllTestCases.Count, Is.EqualTo(2), "Can't find all testcases"); - Assert.That(ndr.TestAssembly.TestSuites.First().IsExplicit, "Test suite don't match explicit"); - Assert.That( - ndr.TestAssembly.TestSuites.First().TestFixtures.First().IsExplicit, - "Test fixture don't match explicit"); - Assert.That( - ndr.TestAssembly.TestSuites.First().TestFixtures.First().ParameterizedMethods.First().IsExplicit, - "Parameterized method don't match explicit"); - Assert.That( - ndr.TestAssembly.TestSuites.First().TestFixtures.First().ParameterizedMethods.First().RunState, - Is.EqualTo(RunStateEnum.Explicit), "Runstate fails for parameterizedfixture"); - }); - } + Assert.That(ndr.IsExplicit, "Explicit check fails"); + Assert.That(ndr.TestAssembly.AllTestCases.Count, Is.EqualTo(2), "All testcases number fails"); + Assert.That(ndr.TestAssembly.AllTestCases.Count, Is.EqualTo(2), "Can't find all testcases"); + Assert.That(ndr.TestAssembly.TestSuites.First().IsExplicit, "Test suite don't match explicit"); + Assert.That( + ndr.TestAssembly.TestSuites.First().TestFixtures.First().IsExplicit, + "Test fixture don't match explicit"); + Assert.That( + ndr.TestAssembly.TestSuites.First().TestFixtures.First().ParameterizedMethods.First().IsExplicit, + "Parameterized method don't match explicit"); + Assert.That( + ndr.TestAssembly.TestSuites.First().TestFixtures.First().ParameterizedMethods.First().RunState, + Is.EqualTo(RunStateEnum.Explicit), "Runstate fails for parameterizedfixture"); + }); + } - private const string SetupFixtureIssue770 = - @" + private const string SetupFixtureIssue770 = + @" @@ -1113,17 +1113,17 @@ public void ThatExplicitRunWorks() "; - [Test] - public void ThatSetUpFixtureWorksIssue770() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(SetupFixtureIssue770))); - Assert.That(ndr, Is.Not.Null); - } + [Test] + public void ThatSetUpFixtureWorksIssue770() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(SetupFixtureIssue770))); + Assert.That(ndr, Is.Not.Null); + } - private const string SetupFixtureIssue824 = - @" + private const string SetupFixtureIssue824 = + @" @@ -1146,17 +1146,17 @@ public void ThatSetUpFixtureWorksIssue770() "; - [Test] - public void ThatSetUpFixtureWorksIssue824() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(SetupFixtureIssue824))); - Assert.That(ndr, Is.Not.Null); - } + [Test] + public void ThatSetUpFixtureWorksIssue824() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(SetupFixtureIssue824))); + Assert.That(ndr, Is.Not.Null); + } - private const string SetupFixtureIssue884 = - @" + private const string SetupFixtureIssue884 = + @" @@ -1179,16 +1179,16 @@ public void ThatSetUpFixtureWorksIssue824() "; - [Test] - public void ThatSetUpFixtureWorksIssue884() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(SetupFixtureIssue884))); - Assert.That(ndr, Is.Not.Null); - } + [Test] + public void ThatSetUpFixtureWorksIssue884() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(SetupFixtureIssue884))); + Assert.That(ndr, Is.Not.Null); + } - private const string GenericIssue918 = @" + private const string GenericIssue918 = @" @@ -1207,18 +1207,18 @@ public void ThatSetUpFixtureWorksIssue884() "; - [Test] - public void ThatGenericFixturesWorksIssue918() - { - var sut = new DiscoveryConverter(logger, settings); - var ndr = sut.ConvertXml( - new NUnitResults(XmlHelper.CreateXmlNode(GenericIssue918))); - Assert.That(ndr, Is.Not.Null); - } + [Test] + public void ThatGenericFixturesWorksIssue918() + { + var sut = new DiscoveryConverter(logger, settings); + var ndr = sut.ConvertXml( + new NUnitResults(XmlHelper.CreateXmlNode(GenericIssue918))); + Assert.That(ndr, Is.Not.Null); + } - private const string ExtractFixturesHandlesProperties = - @" + private const string ExtractFixturesHandlesProperties = + @" @@ -1237,15 +1237,14 @@ public void ThatGenericFixturesWorksIssue918() "; - [Test] - public void ThatExtractFixturesHandlesProperties() - { - var sut = new DiscoveryConverter(logger, settings); - XmlNode node = null; - Assert.DoesNotThrow(() => node = XmlHelper.CreateXmlNode(ExtractFixturesHandlesProperties)); - var ndr = sut.ConvertXml( - new NUnitResults(node)); - Assert.That(ndr, Is.Not.Null); - } + [Test] + public void ThatExtractFixturesHandlesProperties() + { + var sut = new DiscoveryConverter(logger, settings); + XmlNode node = null; + Assert.DoesNotThrow(() => node = XmlHelper.CreateXmlNode(ExtractFixturesHandlesProperties)); + var ndr = sut.ConvertXml( + new NUnitResults(node)); + Assert.That(ndr, Is.Not.Null); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitEngineAdapterTests.cs b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitEngineAdapterTests.cs index 0b28c6bd..86ffb9d2 100644 --- a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitEngineAdapterTests.cs +++ b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitEngineAdapterTests.cs @@ -2,14 +2,14 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests +namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests; + +[TestFixture] +public class NUnitEngineAdapterTests { - [TestFixture] - public class NUnitEngineAdapterTests + [Test] + public void TestXmlFileNameGeneration() { - [Test] - public void TestXmlFileNameGeneration() - { var logger = Substitute.For(); var settings = new AdapterSettings(logger); settings.Load(@"c:\whatever/my/work/dir"); @@ -19,10 +19,10 @@ public void TestXmlFileNameGeneration() Assert.That(path, Is.EqualTo("c:/assembly.xml")); } - [TestCase("", "myAssemblyFilename")] - [TestCase("whateverFileName", "whateverFileName")] - public void When_setting_up_defined_result_GetTestOutputFileName_returns_defined_filename(string testOutputXmlFileNameWithoutExtensionXmlNode, string expectedFileName) - { + [TestCase("", "myAssemblyFilename")] + [TestCase("whateverFileName", "whateverFileName")] + public void When_setting_up_defined_result_GetTestOutputFileName_returns_defined_filename(string testOutputXmlFileNameWithoutExtensionXmlNode, string expectedFileName) + { var logger = Substitute.For(); var settings = new AdapterSettings(logger); settings.Load($@"c:\whatever/my/work/dir{testOutputXmlFileNameWithoutExtensionXmlNode}"); @@ -32,9 +32,9 @@ public void When_setting_up_defined_result_GetTestOutputFileName_returns_defined Assert.That(filename, Is.EqualTo(expectedFileName)); } - [Test] - public void TestXmlFileNameGenerationNewOutputXmlFileForEachRun() - { + [Test] + public void TestXmlFileNameGenerationNewOutputXmlFileForEachRun() + { var logger = Substitute.For(); var settings = new AdapterSettings(logger); settings.Load(@"c:\whatever/my/work/dirtrue"); @@ -43,5 +43,4 @@ public void TestXmlFileNameGenerationNewOutputXmlFileForEachRun() string path = sut.GetXmlFilePath("c:/", "assembly", "xml"); Assert.That(path, Is.EqualTo("c:/assembly.1.xml")); } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitResultsTests.cs b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitResultsTests.cs index 5e8e8e6e..b126e4a0 100644 --- a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitResultsTests.cs +++ b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitResultsTests.cs @@ -27,8 +27,7 @@ using System.Text; using System.Threading.Tasks; -namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests -{ - public class NUnitResultsTests - { } -} +namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests; + +public class NUnitResultsTests +{ } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestCaseTests.cs b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestCaseTests.cs index b04acfc5..b8d30669 100644 --- a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestCaseTests.cs +++ b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestCaseTests.cs @@ -24,35 +24,34 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests +namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests; + +public class NUnitTestCaseTests { - public class NUnitTestCaseTests - { - private const string XmlRunnable = @""; + private const string XmlRunnable = @""; - private const string XmlExplicit = @""; + private const string XmlExplicit = @""; - private const string XmlNone = @""; + private const string XmlNone = @""; - [Test] - public void ThatRunStateIsHandledForRunnable() - { + [Test] + public void ThatRunStateIsHandledForRunnable() + { var sut = new NUnitEventTestCase(XmlHelper.CreateXmlNode(XmlRunnable)); Assert.That(sut.RunState, Is.EqualTo(RunStateEnum.Runnable)); } - [Test] - public void ThatRunStateIsHandledForExplicit() - { + [Test] + public void ThatRunStateIsHandledForExplicit() + { var sut = new NUnitEventTestCase(XmlHelper.CreateXmlNode(XmlExplicit)); Assert.That(sut.RunState, Is.EqualTo(RunStateEnum.Explicit)); } - [Test] - public void ThatRunStateIsHandledForNone() - { + [Test] + public void ThatRunStateIsHandledForNone() + { var sut = new NUnitEventTestCase(XmlHelper.CreateXmlNode(XmlNone)); Assert.That(sut.RunState, Is.EqualTo(RunStateEnum.NA)); } - } } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestEventTestOutputTests.cs b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestEventTestOutputTests.cs index 5354d12a..2b6f19ba 100644 --- a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestEventTestOutputTests.cs +++ b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestEventTestOutputTests.cs @@ -1,70 +1,69 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests +namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests; + +public class NUnitTestEventTestOutputTests { - public class NUnitTestEventTestOutputTests - { - private const string OutputProgress = - @""; + private const string OutputProgress = + @""; - private const string OutputOut = - @""; + private const string OutputOut = + @""; - private const string OutputError = - @""; + private const string OutputError = + @""; - private const string BlankTestOutput = - @""; + private const string BlankTestOutput = + @""; - [Test] - public void NUnitTestEventTestOutputTestWithProgress() + [Test] + public void NUnitTestEventTestOutputTestWithProgress() + { + var sut = new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(OutputProgress)); + Assert.Multiple(() => { - var sut = new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(OutputProgress)); - Assert.Multiple(() => - { - Assert.That(sut.IsProgressStream); - Assert.That(sut.IsErrorStream, Is.False); - Assert.That(sut.IsNullOrEmptyStream, Is.False); - Assert.That(sut.Stream, Is.EqualTo(NUnitTestEventTestOutput.Streams.Progress)); - Assert.That(sut.TestId, Is.EqualTo("0-1001")); - Assert.That(sut.Content, Is.EqualTo("Whatever")); - Assert.That(sut.TestName, Is.EqualTo("Something.TestClass.Whatever")); - }); - } + Assert.That(sut.IsProgressStream); + Assert.That(sut.IsErrorStream, Is.False); + Assert.That(sut.IsNullOrEmptyStream, Is.False); + Assert.That(sut.Stream, Is.EqualTo(NUnitTestEventTestOutput.Streams.Progress)); + Assert.That(sut.TestId, Is.EqualTo("0-1001")); + Assert.That(sut.Content, Is.EqualTo("Whatever")); + Assert.That(sut.TestName, Is.EqualTo("Something.TestClass.Whatever")); + }); + } - [Test] - public void NUnitTestEventTestOutputTestWithError() + [Test] + public void NUnitTestEventTestOutputTestWithError() + { + var sut = new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(OutputError)); + Assert.Multiple(() => { - var sut = new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(OutputError)); - Assert.Multiple(() => - { - Assert.That(sut.IsProgressStream, Is.False, "Progress stream failed"); - Assert.That(sut.IsErrorStream, Is.True, "Error stream failed"); - Assert.That(sut.IsNullOrEmptyStream, Is.False, "NullOrEmpty stream failed"); - Assert.That(sut.Stream, Is.EqualTo(NUnitTestEventTestOutput.Streams.Error), "Stream failed"); - Assert.That(sut.TestId, Is.EqualTo("0-1001"), "Id failed"); - Assert.That(sut.Content, Is.EqualTo("Whatever"), "Content failed"); - Assert.That(sut.TestName, Is.EqualTo("Something.TestClass.Whatever"), "Fullname failed"); - }); - } + Assert.That(sut.IsProgressStream, Is.False, "Progress stream failed"); + Assert.That(sut.IsErrorStream, Is.True, "Error stream failed"); + Assert.That(sut.IsNullOrEmptyStream, Is.False, "NullOrEmpty stream failed"); + Assert.That(sut.Stream, Is.EqualTo(NUnitTestEventTestOutput.Streams.Error), "Stream failed"); + Assert.That(sut.TestId, Is.EqualTo("0-1001"), "Id failed"); + Assert.That(sut.Content, Is.EqualTo("Whatever"), "Content failed"); + Assert.That(sut.TestName, Is.EqualTo("Something.TestClass.Whatever"), "Fullname failed"); + }); + } - [Test] - public void NUnitTestEventTestOutputTestWithBlank() + [Test] + public void NUnitTestEventTestOutputTestWithBlank() + { + var sut = new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(BlankTestOutput)); + Assert.Multiple(() => { - var sut = new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(BlankTestOutput)); - Assert.Multiple(() => - { - Assert.That(sut.IsProgressStream, Is.True); - Assert.That(sut.IsErrorStream, Is.False); - Assert.That(sut.IsNullOrEmptyStream, Is.False); - Assert.That(sut.Stream, Is.EqualTo(NUnitTestEventTestOutput.Streams.Progress)); - Assert.That(sut.TestId, Is.EqualTo("0-1001")); - Assert.That(sut.Content.Length, Is.EqualTo(3)); - Assert.That(sut.TestName, Is.EqualTo("Something.TestClass.Whatever")); - }); - } + Assert.That(sut.IsProgressStream, Is.True); + Assert.That(sut.IsErrorStream, Is.False); + Assert.That(sut.IsNullOrEmptyStream, Is.False); + Assert.That(sut.Stream, Is.EqualTo(NUnitTestEventTestOutput.Streams.Progress)); + Assert.That(sut.TestId, Is.EqualTo("0-1001")); + Assert.That(sut.Content.Length, Is.EqualTo(3)); + Assert.That(sut.TestName, Is.EqualTo("Something.TestClass.Whatever")); + }); } } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestEventsTests.cs b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestEventsTests.cs index 77311458..2b4a9f00 100644 --- a/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestEventsTests.cs +++ b/src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestEventsTests.cs @@ -26,20 +26,20 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests +namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests; + +public class NUnitTestEventsTests { - public class NUnitTestEventsTests - { - private const string StartSuite = @""; - private readonly string testSuite = @" + private const string StartSuite = @""; + private readonly string testSuite = @" "; - [Test] - public void ThatTestEventIsParsedForTestSuite() - { + [Test] + public void ThatTestEventIsParsedForTestSuite() + { var sut = new NUnitTestEventSuiteFinished(testSuite); Assert.Multiple(() => { @@ -53,11 +53,11 @@ public void ThatTestEventIsParsedForTestSuite() Assert.That(sut.FailureMessage, Is.EqualTo("One or more child tests had errors")); } - private readonly string startTest = @""; + private readonly string startTest = @""; - [Test] - public void ThatTestEventIsParsedForStartTest() - { + [Test] + public void ThatTestEventIsParsedForStartTest() + { var sut = new NUnitTestEventStartTest(startTest); Assert.Multiple(() => { @@ -69,8 +69,8 @@ public void ThatTestEventIsParsedForStartTest() }); } - private readonly string testCaseFailing = - @" + private readonly string testCaseFailing = + @" @@ -91,9 +91,9 @@ public void ThatTestEventIsParsedForStartTest() "; - [Test] - public void ThatTestEventIsParsedForFailingTestCase() - { + [Test] + public void ThatTestEventIsParsedForFailingTestCase() + { var sut = new NUnitTestEventTestCase(testCaseFailing); Assert.Multiple(() => { @@ -108,9 +108,9 @@ public void ThatTestEventIsParsedForFailingTestCase() }); } - [Test] - public void ThatTestCasePropertiesAreParsedWhenFailing() - { + [Test] + public void ThatTestCasePropertiesAreParsedWhenFailing() + { var sut = new NUnitTestEventTestCase(testCaseFailing); Assert.That(sut.Properties, Is.Not.Null); Assert.That(sut.Properties.Count, Is.EqualTo(1)); @@ -120,9 +120,9 @@ public void ThatTestCasePropertiesAreParsedWhenFailing() Assert.That(property.Value, Is.EqualTo("Failure")); } - [Test] - public void ThatTestCaseFailureIsParsedWhenFailing() - { + [Test] + public void ThatTestCaseFailureIsParsedWhenFailing() + { var sut = new NUnitTestEventTestCase(testCaseFailing); var failure = sut.Failure; Assert.That(failure, Is.Not.Null); @@ -134,14 +134,14 @@ public void ThatTestCaseFailureIsParsedWhenFailing() } - private readonly string testCaseSucceeds = @" + private readonly string testCaseSucceeds = @" "; - [Test] - public void ThatTestEventIsParsedForSuccessTestCase() - { + [Test] + public void ThatTestEventIsParsedForSuccessTestCase() + { var sut = new NUnitTestEventTestCase(testCaseSucceeds); Assert.Multiple(() => { @@ -153,14 +153,14 @@ public void ThatTestEventIsParsedForSuccessTestCase() }); } - private readonly string testSuiteFinished = @" + private readonly string testSuiteFinished = @" "; - [Test] - public void ThatTestEventIsParsedForFinishSuite() - { + [Test] + public void ThatTestEventIsParsedForFinishSuite() + { var sut = new NUnitTestEventSuiteFinished(testSuiteFinished); Assert.Multiple(() => { @@ -172,8 +172,8 @@ public void ThatTestEventIsParsedForFinishSuite() }); } - private readonly string testSuiteFinishedWithReason = - @" + private readonly string testSuiteFinishedWithReason = + @" @@ -182,15 +182,15 @@ public void ThatTestEventIsParsedForFinishSuite() "; - [Test] - public void ThatTestEventIsParsedForFinishSuiteWithReason() - { + [Test] + public void ThatTestEventIsParsedForFinishSuiteWithReason() + { var sut = new NUnitTestEventSuiteFinished(testSuiteFinishedWithReason); Assert.That(sut.HasReason); Assert.That(sut.ReasonMessage, Is.EqualTo("One or more child tests had warnings")); Assert.That(sut.HasFailure, Is.False); } - private readonly string testCaseSucceedsWithOutputAndReason = @" + private readonly string testCaseSucceedsWithOutputAndReason = @" @@ -201,32 +201,32 @@ public void ThatTestEventIsParsedForFinishSuiteWithReason() ]]> "; - [Test] - public void ThatTestEventIsParsedForTestCaseWithReason() - { + [Test] + public void ThatTestEventIsParsedForTestCaseWithReason() + { var sut = new NUnitTestEventTestCase(testCaseSucceedsWithOutputAndReason); Assert.That(sut.HasReason); Assert.That(sut.ReasonMessage, Is.EqualTo("One or more child tests had warnings")); } - private readonly string testSuiteFinishedWithFailure = @" + private readonly string testSuiteFinishedWithFailure = @" "; - [Test] - public void ThatTestEventIsParsedForFinishSuiteWithFailure() - { + [Test] + public void ThatTestEventIsParsedForFinishSuiteWithFailure() + { var sut = new NUnitTestEventSuiteFinished(testSuiteFinishedWithFailure); Assert.That(sut.HasFailure); Assert.That(sut.FailureMessage, Is.EqualTo("One or more child tests had errors")); } - /// - /// Exception in OneTimeSetUp - /// - private readonly string testSuiteFinishedWithFailureAndStackTrace = @" + /// + /// Exception in OneTimeSetUp + /// + private readonly string testSuiteFinishedWithFailureAndStackTrace = @" "; - [Test] - public void ThatTestEventIsParsedForFinishSuiteWithExceptionInOneTimeSetUp() - { + [Test] + public void ThatTestEventIsParsedForFinishSuiteWithExceptionInOneTimeSetUp() + { var sut = new NUnitTestEventSuiteFinished(testSuiteFinishedWithFailureAndStackTrace); Assert.That(sut.HasFailure); Assert.That(sut.FailureMessage.Length, Is.GreaterThan(0)); @@ -255,16 +255,16 @@ public void ThatTestEventIsParsedForFinishSuiteWithExceptionInOneTimeSetUp() - private readonly string testCaseSucceedsWithOutput = @" + private readonly string testCaseSucceedsWithOutput = @" "; - [Test] - public void ThatTestEventIsParsedForSuccessTestCaseWithOutput() - { + [Test] + public void ThatTestEventIsParsedForSuccessTestCaseWithOutput() + { var sut = new NUnitTestEventTestCase(testCaseSucceedsWithOutput); Assert.Multiple(() => { @@ -278,7 +278,7 @@ public void ThatTestEventIsParsedForSuccessTestCaseWithOutput() }); } - private readonly string testCaseFails = @" + private readonly string testCaseFails = @" @@ -300,9 +300,9 @@ public void ThatTestEventIsParsedForSuccessTestCaseWithOutput() "; - [Test] - public void ThatTestCaseFailsCanBeParsed() - { + [Test] + public void ThatTestCaseFailsCanBeParsed() + { var sut = new NUnitTestEventTestCase(testCaseFails); Assert.That(sut.Properties.Count, Is.EqualTo(1)); Assert.That(sut.HasFailure); @@ -313,7 +313,7 @@ public void ThatTestCaseFailsCanBeParsed() }); } - private readonly string testCaseFailsWithReason = @" + private readonly string testCaseFailsWithReason = @" @@ -322,24 +322,23 @@ public void ThatTestCaseFailsCanBeParsed() "; - [Test] - public void ThatTestCaseFailsCanBeParsedWithReason() - { + [Test] + public void ThatTestCaseFailsCanBeParsedWithReason() + { var sut = new NUnitTestEventTestCase(testCaseFailsWithReason); Assert.That(sut.ReasonMessage, Is.EqualTo("Ignoring this test deliberately")); } - private readonly string testCaseExplicitFixtureTime = - @""; + private readonly string testCaseExplicitFixtureTime = + @""; - /// - /// Issue 811. - /// - [Test] - public void ThatExplicitTestFixtureWorksWithZeroStartTime() - { + /// + /// Issue 811. + /// + [Test] + public void ThatExplicitTestFixtureWorksWithZeroStartTime() + { var sut = new NUnitTestEventTestCase(testEvent: testCaseExplicitFixtureTime); Assert.DoesNotThrow(code: () => sut.StartTime()); } - } } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NUnitEngineTests/UnicodeEscapeHelperTests.cs b/src/NUnitTestAdapterTests/NUnitEngineTests/UnicodeEscapeHelperTests.cs index 4203eead..e13ea6b6 100644 --- a/src/NUnitTestAdapterTests/NUnitEngineTests/UnicodeEscapeHelperTests.cs +++ b/src/NUnitTestAdapterTests/NUnitEngineTests/UnicodeEscapeHelperTests.cs @@ -1,19 +1,18 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests +namespace NUnit.VisualStudio.TestAdapter.Tests.NUnitEngineTests; + +public class UnicodeEscapeHelperTests { - public class UnicodeEscapeHelperTests + [TestCase("\\u001b", "\u001b")] + [TestCase("\\u001", "\\u001")] + [TestCase("\\u01", "\\u01")] + [TestCase("\\u1", "\\u1")] + [TestCase("\\u001b6", "\u001b6")] + [TestCase("some-text", "some-text")] + public void UnEscapeUnicodeCharacters_ShouldReplaceBackslashU(string value, string expected) { - [TestCase("\\u001b", "\u001b")] - [TestCase("\\u001", "\\u001")] - [TestCase("\\u01", "\\u01")] - [TestCase("\\u1", "\\u1")] - [TestCase("\\u001b6", "\u001b6")] - [TestCase("some-text", "some-text")] - public void UnEscapeUnicodeCharacters_ShouldReplaceBackslashU(string value, string expected) - { - Assert.That(value.UnEscapeUnicodeCharacters(), Is.EqualTo(expected)); - } + Assert.That(value.UnEscapeUnicodeCharacters(), Is.EqualTo(expected)); } } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NUnitEventListenerOutputTests.cs b/src/NUnitTestAdapterTests/NUnitEventListenerOutputTests.cs index ee8809e6..d179c7a0 100644 --- a/src/NUnitTestAdapterTests/NUnitEventListenerOutputTests.cs +++ b/src/NUnitTestAdapterTests/NUnitEventListenerOutputTests.cs @@ -6,119 +6,118 @@ using NUnit.VisualStudio.TestAdapter.Dump; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +/// +/// These tests ensure correct console output, which is what we send to the "recorder". +/// +public class NUnitEventListenerOutputTests { - /// - /// These tests ensure correct console output, which is what we send to the "recorder". - /// - public class NUnitEventListenerOutputTests - { - private ITestExecutionRecorder recorder; - private ITestConverterCommon converter; - private IAdapterSettings settings; - private INUnit3TestExecutor executor; + private ITestExecutionRecorder recorder; + private ITestConverterCommon converter; + private IAdapterSettings settings; + private INUnit3TestExecutor executor; - private const string TestOutputProgress = - @""; - private const string TestOutputOut = - @""; - private const string TestOutputError = - @""; - private const string BlankTestOutput = - @""; - - private const string TestFinish = - @""; - - /// - /// For Issue 811. - /// - private const string TestFinishWithExplicitFixture = - @""; - - [SetUp] - public void Setup() - { - recorder = Substitute.For(); - converter = Substitute.For(); - settings = Substitute.For(); - settings.ConsoleOut.Returns(1); - executor = Substitute.For(); - executor.Settings.Returns(settings); - executor.FrameworkHandle.Returns(recorder); - } - - [Test] - public void ThatNormalTestOutputIsOutput() - { - var sut = new NUnitEventListener(converter, executor); - sut.OnTestEvent(TestOutputOut); - sut.OnTestEvent(TestFinish); - - recorder.Received().SendMessage(Arg.Any(), Arg.Is(x => x.StartsWith("Whatever"))); - converter.Received().GetVsTestResults(Arg.Any(), Arg.Is>(x => x.Count == 1)); - } - - [Test] - public void ThatProgressTestOutputIsOutput() - { - var sut = new NUnitEventListener(converter, executor); - sut.OnTestEvent(TestOutputProgress); - sut.OnTestEvent(TestFinish); - - recorder.Received().SendMessage(Arg.Any(), Arg.Is(x => x.StartsWith("Whatever"))); - converter.Received().GetVsTestResults(Arg.Any(), Arg.Is>(x => x.Count == 1)); - } - - [Test] - public void ThatNormalTestOutputIsError() - { - var sut = new NUnitEventListener(converter, executor); - sut.OnTestEvent(TestOutputError); - sut.OnTestEvent(TestFinish); - - recorder.Received().SendMessage(Arg.Any(), Arg.Is(x => x.StartsWith("Whatever"))); - converter.Received().GetVsTestResults(Arg.Any(), Arg.Is>(x => x.Count == 1)); - } - - [Test] - public void ThatConsoleOutCanStopAllTestOutput() - { - settings.ConsoleOut.Returns(0); - var sut = new NUnitEventListener(converter, executor); - sut.OnTestEvent(TestOutputOut); - sut.OnTestEvent(TestOutputProgress); - sut.OnTestEvent(TestOutputError); - sut.OnTestEvent(TestFinish); - - recorder.DidNotReceive().SendMessage(Arg.Any(), Arg.Any()); - } - - [Test] - public void ThatTestOutputWithOnlyWhiteSpaceIsNotOutput() - { - var sut = new NUnitEventListener(converter, executor); - - sut.OnTestEvent(BlankTestOutput); - - recorder.DidNotReceive().SendMessage(Arg.Any(), Arg.Any()); - } - - /// - /// Issue 811 System.FormatException: The UTC representation of the date falls outside the year range 1-9999" from skipped test in Eastern European time zone. - /// - [Test] - public void ThatExplicitTestFixtureWorksWithZeroStartTime() - { - var sut = new NUnitEventListener(converter, executor); - Assert.DoesNotThrow(() => sut.OnTestEvent(TestFinishWithExplicitFixture)); - } + private const string BlankTestOutput = + @""; + + private const string TestFinish = + @""; + + /// + /// For Issue 811. + /// + private const string TestFinishWithExplicitFixture = + @""; + + [SetUp] + public void Setup() + { + recorder = Substitute.For(); + converter = Substitute.For(); + settings = Substitute.For(); + settings.ConsoleOut.Returns(1); + executor = Substitute.For(); + executor.Settings.Returns(settings); + executor.FrameworkHandle.Returns(recorder); + } + + [Test] + public void ThatNormalTestOutputIsOutput() + { + var sut = new NUnitEventListener(converter, executor); + sut.OnTestEvent(TestOutputOut); + sut.OnTestEvent(TestFinish); + + recorder.Received().SendMessage(Arg.Any(), Arg.Is(x => x.StartsWith("Whatever"))); + converter.Received().GetVsTestResults(Arg.Any(), Arg.Is>(x => x.Count == 1)); + } + + [Test] + public void ThatProgressTestOutputIsOutput() + { + var sut = new NUnitEventListener(converter, executor); + sut.OnTestEvent(TestOutputProgress); + sut.OnTestEvent(TestFinish); + + recorder.Received().SendMessage(Arg.Any(), Arg.Is(x => x.StartsWith("Whatever"))); + converter.Received().GetVsTestResults(Arg.Any(), Arg.Is>(x => x.Count == 1)); + } + + [Test] + public void ThatNormalTestOutputIsError() + { + var sut = new NUnitEventListener(converter, executor); + sut.OnTestEvent(TestOutputError); + sut.OnTestEvent(TestFinish); + + recorder.Received().SendMessage(Arg.Any(), Arg.Is(x => x.StartsWith("Whatever"))); + converter.Received().GetVsTestResults(Arg.Any(), Arg.Is>(x => x.Count == 1)); + } + + [Test] + public void ThatConsoleOutCanStopAllTestOutput() + { + settings.ConsoleOut.Returns(0); + var sut = new NUnitEventListener(converter, executor); + sut.OnTestEvent(TestOutputOut); + sut.OnTestEvent(TestOutputProgress); + sut.OnTestEvent(TestOutputError); + sut.OnTestEvent(TestFinish); + + recorder.DidNotReceive().SendMessage(Arg.Any(), Arg.Any()); + } + + [Test] + public void ThatTestOutputWithOnlyWhiteSpaceIsNotOutput() + { + var sut = new NUnitEventListener(converter, executor); + + sut.OnTestEvent(BlankTestOutput); + + recorder.DidNotReceive().SendMessage(Arg.Any(), Arg.Any()); + } + + /// + /// Issue 811 System.FormatException: The UTC representation of the date falls outside the year range 1-9999" from skipped test in Eastern European time zone. + /// + [Test] + public void ThatExplicitTestFixtureWorksWithZeroStartTime() + { + var sut = new NUnitEventListener(converter, executor); + Assert.DoesNotThrow(() => sut.OnTestEvent(TestFinishWithExplicitFixture)); } } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NavigationDataProviderTests.cs b/src/NUnitTestAdapterTests/NavigationDataProviderTests.cs index 5a59ad15..8e8b3aa6 100644 --- a/src/NUnitTestAdapterTests/NavigationDataProviderTests.cs +++ b/src/NUnitTestAdapterTests/NavigationDataProviderTests.cs @@ -24,91 +24,84 @@ using System; using System.IO; using System.Reflection; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; + using NSubstitute; + using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.Metadata; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +public static class NavigationDataProviderTests { - public static class NavigationDataProviderTests - { #if NET462 - [Ignore("Joseph: This doesn't really work!")] - [Description( - "This simulates what happens when the adapter is deployed: " + - "nunit.framework.dll is no longer beside the adapter assembly " + - "and we need to make sure the reflection AppDomain wouldn’t fail " + - "to load it.")] - [TestCase(false, TestName = "AsyncMethodWithAttributeDefinedOutsideAdapterDirectory()")] - [TestCase(true, TestName = "AsyncMethodWithAttributeDefinedOutsideAdapterDirectory(with binding redirect)")] - public static void AsyncMethodWithAttributeDefinedOutsideAdapterDirectory(bool withBindingRedirect) + [Ignore("Joseph: This doesn't really work!")] + [Description( + "This simulates what happens when the adapter is deployed: " + + "nunit.framework.dll is no longer beside the adapter assembly " + + "and we need to make sure the reflection AppDomain wouldn’t fail " + + "to load it.")] + [TestCase(false, TestName = "AsyncMethodWithAttributeDefinedOutsideAdapterDirectory()")] + [TestCase(true, TestName = "AsyncMethodWithAttributeDefinedOutsideAdapterDirectory(with binding redirect)")] + public static void AsyncMethodWithAttributeDefinedOutsideAdapterDirectory(bool withBindingRedirect) + { + using var dir = new TempDirectory(); + // The tests must run in the same AppDomain as VSTest for DiaSession to work, + // but that VSTest has already loaded an old version of S.C.Immutable in this AppDomain. + // To avoid MissingMethodException, it’s necessary to only deal with Roslyn in a separate AppDomain. + using (var compileInvoker = new AppDomainInvoker()) { - using (var dir = new TempDirectory()) - { - // The tests must run in the same AppDomain as VSTest for DiaSession to work, - // but that VSTest has already loaded an old version of S.C.Immutable in this AppDomain. - // To avoid MissingMethodException, it’s necessary to only deal with Roslyn in a separate AppDomain. - using (var compileInvoker = new AppDomainInvoker()) + compileInvoker.Invoke( + marshalled => { - compileInvoker.Invoke( - marshalled => + var baseCompilation = CSharpCompilation.Create(null) + .AddReferences(MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location)) + .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + var dependencyAssemblyPath = Path.Combine(marshalled.outputDir, "AssemblyOutsideAdapterDir.dll"); + var dependencyBaseCompilation = baseCompilation + .WithAssemblyName("AssemblyOutsideAdapterDir") + .AddSyntaxTrees(CSharpSyntaxTree.ParseText("public sealed class AttributeDefinedOutsideAdapterDir : System.Attribute { }")); + + if (marshalled.withBindingRedirect) { - var baseCompilation = CSharpCompilation.Create(null) - .AddReferences(MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location)) - .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - - var dependencyAssemblyPath = Path.Combine(marshalled.outputDir, "AssemblyOutsideAdapterDir.dll"); - var dependencyBaseCompilation = baseCompilation - .WithAssemblyName("AssemblyOutsideAdapterDir") - .AddSyntaxTrees(CSharpSyntaxTree.ParseText("public sealed class AttributeDefinedOutsideAdapterDir : System.Attribute { }")); - - if (marshalled.withBindingRedirect) - { - dependencyBaseCompilation = dependencyBaseCompilation - .WithOptions(baseCompilation.Options - .WithPublicSign(true) - .WithCryptoKeyFile(Path.Combine(Path.GetDirectoryName(typeof(NavigationDataProviderTests).Assembly.Location), "temp.snk"))); - } - - var dependencyAssembly = dependencyBaseCompilation - .AddSyntaxTrees(CSharpSyntaxTree.ParseText("[assembly: System.Reflection.AssemblyVersion(\"1.0.1.0\")]")) - .Emit(Path.Combine(marshalled.outputDir, "AssemblyOutsideAdapterDir.dll")); - if (!dependencyAssembly.Success) Assert.Fail("Broken test"); - - MetadataReference reference; - if (marshalled.withBindingRedirect) - { - reference = dependencyBaseCompilation - .AddSyntaxTrees(CSharpSyntaxTree.ParseText("[assembly: System.Reflection.AssemblyVersion(\"1.0.0.0\")]")) - .ToMetadataReference(); - } - else - { - reference = MetadataReference.CreateFromFile(dependencyAssemblyPath); - } - - using (var outputDll = File.Create(Path.Combine(marshalled.outputDir, "DependentAssembly.dll"))) - using (var outputPdb = File.Create(Path.Combine(marshalled.outputDir, "DependentAssembly.pdb"))) - { - var dependentAssembly = baseCompilation - .WithAssemblyName("DependentAssembly") - .AddReferences(reference) - .AddSyntaxTrees(CSharpSyntaxTree.ParseText("public class TestClass { [AttributeDefinedOutsideAdapterDir] public async System.Threading.Tasks.Task AsyncMethod() { } }")) - .Emit(outputDll, outputPdb, options: new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb)); - if (!dependentAssembly.Success) Assert.Fail("Broken test"); - } - }, (outputDir: dir.Path, withBindingRedirect)); - } - - var assemblyPath = Path.Combine(dir, "DependentAssembly.dll"); - if (withBindingRedirect) - { - File.WriteAllText( - assemblyPath + ".config", - @" + dependencyBaseCompilation = dependencyBaseCompilation + .WithOptions(baseCompilation.Options + .WithPublicSign(true) + .WithCryptoKeyFile(Path.Combine(Path.GetDirectoryName(typeof(NavigationDataProviderTests).Assembly.Location), "temp.snk"))); + } + + var dependencyAssembly = dependencyBaseCompilation + .AddSyntaxTrees(CSharpSyntaxTree.ParseText("[assembly: System.Reflection.AssemblyVersion(\"1.0.1.0\")]")) + .Emit(Path.Combine(marshalled.outputDir, "AssemblyOutsideAdapterDir.dll")); + if (!dependencyAssembly.Success) Assert.Fail("Broken test"); + + var reference = marshalled.withBindingRedirect + ? dependencyBaseCompilation + .AddSyntaxTrees(CSharpSyntaxTree.ParseText("[assembly: System.Reflection.AssemblyVersion(\"1.0.0.0\")]")) + .ToMetadataReference() + : (MetadataReference)MetadataReference.CreateFromFile(dependencyAssemblyPath); + using var outputDll = File.Create(Path.Combine(marshalled.outputDir, "DependentAssembly.dll")); + using var outputPdb = File.Create(Path.Combine(marshalled.outputDir, "DependentAssembly.pdb")); + var dependentAssembly = baseCompilation + .WithAssemblyName("DependentAssembly") + .AddReferences(reference) + .AddSyntaxTrees(CSharpSyntaxTree.ParseText("public class TestClass { [AttributeDefinedOutsideAdapterDir] public async System.Threading.Tasks.Task AsyncMethod() { } }")) + .Emit(outputDll, outputPdb, options: new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb)); + if (!dependentAssembly.Success) Assert.Fail("Broken test"); + }, (outputDir: dir.Path, withBindingRedirect)); + } + + var assemblyPath = Path.Combine(dir, "DependentAssembly.dll"); + if (withBindingRedirect) + { + File.WriteAllText( + assemblyPath + ".config", + @" @@ -119,58 +112,54 @@ public static void AsyncMethodWithAttributeDefinedOutsideAdapterDirectory(bool w "); - } - - using (var metadataProvider = NavigationDataProvider.CreateMetadataProvider(assemblyPath)) - { - var result = metadataProvider.GetStateMachineType(assemblyPath, "TestClass", "AsyncMethod"); - Assert.That(result, Is.Not.Null); - } - } } + + using var metadataProvider = NavigationDataProvider.CreateMetadataProvider(assemblyPath); + var result = metadataProvider.GetStateMachineType(assemblyPath, "TestClass", "AsyncMethod"); + Assert.That(result, Is.Not.Null); + } #endif - [Test] - public static void ExceptionShouldDisableGetStateMachineTypeAndLogErrorForAssembly() - { - var fixture = new Fixture(); - fixture.MetadataProvider.GetStateMachineType(null, null, null).ReturnsForAnyArgs(_ => throw new Exception()); + [Test] + public static void ExceptionShouldDisableGetStateMachineTypeAndLogErrorForAssembly() + { + var fixture = new Fixture(); + fixture.MetadataProvider.GetStateMachineType(null, null, null).ReturnsForAnyArgs(_ => throw new Exception()); - fixture.CauseLookupFailure(); + fixture.CauseLookupFailure(); - fixture.MetadataProvider.ReceivedWithAnyArgs(requiredNumberOfCalls: 1).GetStateMachineType(null, null, null); - fixture.AssertLoggerReceivedErrorForAssemblyPath(); - } + fixture.MetadataProvider.ReceivedWithAnyArgs(requiredNumberOfCalls: 1).GetStateMachineType(null, null, null); + fixture.AssertLoggerReceivedErrorForAssemblyPath(); + } - [Test] - public static void ExceptionShouldDisableGetDeclaringTypeAndLogErrorForAssembly() - { - var fixture = new Fixture(); - fixture.MetadataProvider.GetDeclaringType(null, null, null).ReturnsForAnyArgs(_ => throw new Exception()); + [Test] + public static void ExceptionShouldDisableGetDeclaringTypeAndLogErrorForAssembly() + { + var fixture = new Fixture(); + fixture.MetadataProvider.GetDeclaringType(null, null, null).ReturnsForAnyArgs(_ => throw new Exception()); + + fixture.CauseLookupFailure(); + + fixture.MetadataProvider.ReceivedWithAnyArgs(requiredNumberOfCalls: 1).GetDeclaringType(null, null, null); + fixture.AssertLoggerReceivedErrorForAssemblyPath(); + } - fixture.CauseLookupFailure(); + private sealed class Fixture + { + private ITestLogger Logger { get; } = Substitute.For(); + public IMetadataProvider MetadataProvider { get; } = Substitute.For(); + private readonly string existingAssemblyPath = typeof(NavigationDataProviderTests).GetTypeInfo().Assembly.Location; - fixture.MetadataProvider.ReceivedWithAnyArgs(requiredNumberOfCalls: 1).GetDeclaringType(null, null, null); - fixture.AssertLoggerReceivedErrorForAssemblyPath(); + public void CauseLookupFailure() + { + using var navigationProvider = new NavigationDataProvider(existingAssemblyPath, Logger, MetadataProvider); + navigationProvider.GetNavigationData("NonExistentFixture", "SomeTest"); + navigationProvider.GetNavigationData("NonExistentFixture", "SomeTest"); } - private sealed class Fixture + public void AssertLoggerReceivedErrorForAssemblyPath() { - private ITestLogger Logger { get; } = Substitute.For(); - public IMetadataProvider MetadataProvider { get; } = Substitute.For(); - private readonly string existingAssemblyPath = typeof(NavigationDataProviderTests).GetTypeInfo().Assembly.Location; - - public void CauseLookupFailure() - { - using var navigationProvider = new NavigationDataProvider(existingAssemblyPath, Logger, MetadataProvider); - navigationProvider.GetNavigationData("NonExistentFixture", "SomeTest"); - navigationProvider.GetNavigationData("NonExistentFixture", "SomeTest"); - } - - public void AssertLoggerReceivedErrorForAssemblyPath() - { - Logger.Received().Warning(Arg.Is(message => message.Contains(existingAssemblyPath)), Arg.Any()); - } + Logger.Received().Warning(Arg.Is(message => message.Contains(existingAssemblyPath)), Arg.Any()); } } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/NavigationDataTests.cs b/src/NUnitTestAdapterTests/NavigationDataTests.cs index 41747b10..5fa83b6c 100644 --- a/src/NUnitTestAdapterTests/NavigationDataTests.cs +++ b/src/NUnitTestAdapterTests/NavigationDataTests.cs @@ -1,94 +1,95 @@ using System.IO; using System.Reflection; + using NSubstitute; + using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +[Category("Navigation")] +public class NavigationDataTests { - [Category("Navigation")] - public class NavigationDataTests - { - NavigationDataProvider _provider; + NavigationDataProvider _provider; - const string Prefix = "NUnit.VisualStudio.TestAdapter.Tests.NavigationTestData"; + const string Prefix = "NUnit.VisualStudio.TestAdapter.Tests.NavigationTestData"; - [SetUp] - public void SetUp() - { - _provider = new NavigationDataProvider( - typeof(NavigationDataTests).GetTypeInfo().Assembly.Location, - Substitute.For()); - } + [SetUp] + public void SetUp() + { + _provider = new NavigationDataProvider( + typeof(NavigationDataTests).GetTypeInfo().Assembly.Location, + Substitute.For()); + } - [TearDown] - public void TearDown() - { - _provider.Dispose(); - } + [TearDown] + public void TearDown() + { + _provider.Dispose(); + } - [TestCase("", "EmptyMethod_OneLine", 11, 11)] - [TestCase("", "EmptyMethod_TwoLines", 14, 15)] - [TestCase("", "EmptyMethod_ThreeLines", 18, 19)] - [TestCase("", "EmptyMethod_LotsOfLines", 22, 23)] - [TestCase("", "SimpleMethod_Void_NoArgs", 26, 28)] - [TestCase("", "SimpleMethod_Void_OneArg", 32, 33)] - [TestCase("", "SimpleMethod_Void_TwoArgs", 38, 39)] - [TestCase("", "SimpleMethod_ReturnsInt_NoArgs", 44, 46)] - [TestCase("", "SimpleMethod_ReturnsString_OneArg", 50, 51)] - // Generic method uses simple name - [TestCase("", "GenericMethod_ReturnsString_OneArg", 55, 56)] - [TestCase("", "AsyncMethod_Void", 60, 62)] - [TestCase("", "AsyncMethod_Task", 67, 69)] - [TestCase("", "AsyncMethod_ReturnsInt", 74, 76)] - [TestCase("", "IteratorMethod_ReturnsEnumerable", 81, 83)] - [TestCase("", "IteratorMethod_ReturnsEnumerator", 87, 89)] - // Nested classes use Type.FullName format - [TestCase("+NestedClass", "SimpleMethod_Void_NoArgs", 95, 97)] - [TestCase("+ParameterizedFixture", "SimpleMethod_ReturnsString_OneArg", 113, 114)] - // Generic Fixture requires ` plus type arg count - [TestCase("+GenericFixture`2", "Matches", 128, 129)] - [TestCase("+GenericFixture`2+DoublyNested", "WriteBoth", 144, 145)] - [TestCase("+GenericFixture`2+DoublyNested`1", "WriteAllThree", 163, 164)] - [TestCase("+DerivedClass", "EmptyMethod_ThreeLines", 172, 173)] - [TestCase("+DerivedClass", "AsyncMethod_Task", 176, 178)] - [TestCase("+DerivedFromGenericClass", "EmptyMethod_ThreeLines", 198, 199)] - public void VerifyNavigationData_WithinAssembly(string suffix, string methodName, int expectedLineDebug, int expectedLineRelease) - { - VerifyNavigationData(suffix, methodName, "NUnitTestAdapterTests", expectedLineDebug, expectedLineRelease); - } + [TestCase("", "EmptyMethod_OneLine", 11, 11)] + [TestCase("", "EmptyMethod_TwoLines", 14, 15)] + [TestCase("", "EmptyMethod_ThreeLines", 18, 19)] + [TestCase("", "EmptyMethod_LotsOfLines", 22, 23)] + [TestCase("", "SimpleMethod_Void_NoArgs", 26, 28)] + [TestCase("", "SimpleMethod_Void_OneArg", 32, 33)] + [TestCase("", "SimpleMethod_Void_TwoArgs", 38, 39)] + [TestCase("", "SimpleMethod_ReturnsInt_NoArgs", 44, 46)] + [TestCase("", "SimpleMethod_ReturnsString_OneArg", 50, 51)] + // Generic method uses simple name + [TestCase("", "GenericMethod_ReturnsString_OneArg", 55, 56)] + [TestCase("", "AsyncMethod_Void", 60, 62)] + [TestCase("", "AsyncMethod_Task", 67, 69)] + [TestCase("", "AsyncMethod_ReturnsInt", 74, 76)] + [TestCase("", "IteratorMethod_ReturnsEnumerable", 81, 83)] + [TestCase("", "IteratorMethod_ReturnsEnumerator", 87, 89)] + // Nested classes use Type.FullName format + [TestCase("+NestedClass", "SimpleMethod_Void_NoArgs", 95, 97)] + [TestCase("+ParameterizedFixture", "SimpleMethod_ReturnsString_OneArg", 113, 114)] + // Generic Fixture requires ` plus type arg count + [TestCase("+GenericFixture`2", "Matches", 128, 129)] + [TestCase("+GenericFixture`2+DoublyNested", "WriteBoth", 144, 145)] + [TestCase("+GenericFixture`2+DoublyNested`1", "WriteAllThree", 163, 164)] + [TestCase("+DerivedClass", "EmptyMethod_ThreeLines", 172, 173)] + [TestCase("+DerivedClass", "AsyncMethod_Task", 176, 178)] + [TestCase("+DerivedFromGenericClass", "EmptyMethod_ThreeLines", 198, 199)] + public void VerifyNavigationData_WithinAssembly(string suffix, string methodName, int expectedLineDebug, int expectedLineRelease) + { + VerifyNavigationData(suffix, methodName, "NUnitTestAdapterTests", expectedLineDebug, expectedLineRelease); + } - [TestCase("+DerivedFromExternalAbstractClass", "EmptyMethod_ThreeLines", 6, 7)] - [TestCase("+DerivedFromExternalConcreteClass", "EmptyMethod_ThreeLines", 13, 14)] - public void VerifyNavigationData_WithExternalAssembly(string suffix, string methodName, int expectedLineDebug, int expectedLineRelease) - { - VerifyNavigationData(suffix, methodName, "NUnit3AdapterExternalTests", expectedLineDebug, expectedLineRelease); - } + [TestCase("+DerivedFromExternalAbstractClass", "EmptyMethod_ThreeLines", 6, 7)] + [TestCase("+DerivedFromExternalConcreteClass", "EmptyMethod_ThreeLines", 13, 14)] + public void VerifyNavigationData_WithExternalAssembly(string suffix, string methodName, int expectedLineDebug, int expectedLineRelease) + { + VerifyNavigationData(suffix, methodName, "NUnit3AdapterExternalTests", expectedLineDebug, expectedLineRelease); + } - private void VerifyNavigationData(string suffix, string methodName, string expectedDirectory, int expectedLineDebug, int expectedLineRelease) - { - // Get the navigation data - ensure names are spelled correctly! - var className = Prefix + suffix; - var data = _provider.GetNavigationData(className, methodName); - Assert.That(data.IsValid, "Unable to retrieve navigation data"); + private void VerifyNavigationData(string suffix, string methodName, string expectedDirectory, int expectedLineDebug, int expectedLineRelease) + { + // Get the navigation data - ensure names are spelled correctly! + var className = Prefix + suffix; + var data = _provider.GetNavigationData(className, methodName); + Assert.That(data.IsValid, "Unable to retrieve navigation data"); - // Verify the navigation data - // Note that different line numbers are returned for our - // debug and release builds, as follows: - // - // DEBUG - // Opening curly brace. - // - // RELEASE - // First non-comment code line or closing - // curly brace if the method is empty. + // Verify the navigation data + // Note that different line numbers are returned for our + // debug and release builds, as follows: + // + // DEBUG + // Opening curly brace. + // + // RELEASE + // First non-comment code line or closing + // curly brace if the method is empty. - Assert.That(data.FilePath, Does.EndWith("NavigationTestData.cs")); - Assert.That(Path.GetDirectoryName(data.FilePath), Does.EndWith(expectedDirectory)); + Assert.That(data.FilePath, Does.EndWith("NavigationTestData.cs")); + Assert.That(Path.GetDirectoryName(data.FilePath), Does.EndWith(expectedDirectory)); #if DEBUG - Assert.That(data.LineNumber, Is.EqualTo(expectedLineDebug)); + Assert.That(data.LineNumber, Is.EqualTo(expectedLineDebug)); #else - Assert.That(data.LineNumber, Is.EqualTo(expectedLineRelease)); + Assert.That(data.LineNumber, Is.EqualTo(expectedLineRelease)); #endif - } } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/ProjectTests.cs b/src/NUnitTestAdapterTests/ProjectTests.cs index bc45d8c3..a0fb29dc 100644 --- a/src/NUnitTestAdapterTests/ProjectTests.cs +++ b/src/NUnitTestAdapterTests/ProjectTests.cs @@ -28,47 +28,46 @@ using NUnit.Framework.Legacy; #endif -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +[TestFixture] +public class ProjectTests { - [TestFixture] - public class ProjectTests - { #if NET462 - [Test] - public void ThatTheReferenceToMicrosoftTestObjectModelPointsToVS2012Version() - { - var dir = TestContext.CurrentContext.TestDirectory; - var assembly = Assembly.LoadFrom(dir + "/NUnit3.TestAdapter.dll"); - var refNames = assembly.GetReferencedAssemblies().Where(ass => ass.Name == "Microsoft.VisualStudio.TestPlatform.ObjectModel").ToList(); - ClassicAssert.IsTrue(refNames.Count == 1, "No reference to Microsoft.VisualStudio.TestPlatform.ObjectModel found"); - ClassicAssert.IsTrue(refNames[0].Version.Major == 11, "Microsoft.VisualStudio.TestPlatform.ObjectModel must point to the 2012 version (11)"); - } + [Test] + public void ThatTheReferenceToMicrosoftTestObjectModelPointsToVS2012Version() + { + var dir = TestContext.CurrentContext.TestDirectory; + var assembly = Assembly.LoadFrom(dir + "/NUnit3.TestAdapter.dll"); + var refNames = assembly.GetReferencedAssemblies().Where(ass => ass.Name == "Microsoft.VisualStudio.TestPlatform.ObjectModel").ToList(); + ClassicAssert.IsTrue(refNames.Count == 1, "No reference to Microsoft.VisualStudio.TestPlatform.ObjectModel found"); + ClassicAssert.IsTrue(refNames[0].Version.Major == 11, "Microsoft.VisualStudio.TestPlatform.ObjectModel must point to the 2012 version (11)"); + } #endif - [Test] - public void ThatTheTestAdapterEndsWithTestAdapterDll() - { - var adapter = typeof(NUnitTestAdapter).GetTypeInfo().Assembly.Location; - Assert.That(adapter, Does.EndWith(".TestAdapter.dll"), $"Ensure the Testadapter {Path.GetFileName(adapter)} ends with '.TestAdapter.dll'"); - } + [Test] + public void ThatTheTestAdapterEndsWithTestAdapterDll() + { + var adapter = typeof(NUnitTestAdapter).GetTypeInfo().Assembly.Location; + Assert.That(adapter, Does.EndWith(".TestAdapter.dll"), $"Ensure the Testadapter {Path.GetFileName(adapter)} ends with '.TestAdapter.dll'"); + } - [Test] - public void ThatNoMSTestDLLIsCopiedToOutput() - { - var dir = TestContext.CurrentContext.TestDirectory; - var filesNotToExist = Directory.EnumerateFiles(dir, "Microsoft", SearchOption.TopDirectoryOnly); - Assert.That(!filesNotToExist.Any(), Is.True, "The reference of NUnitTestAdapter - Microsoft.VisualStudio.TestPlatform.ObjectModel must be set Copy Local to false"); - } + [Test] + public void ThatNoMSTestDLLIsCopiedToOutput() + { + var dir = TestContext.CurrentContext.TestDirectory; + var filesNotToExist = Directory.EnumerateFiles(dir, "Microsoft", SearchOption.TopDirectoryOnly); + Assert.That(!filesNotToExist.Any(), Is.True, "The reference of NUnitTestAdapter - Microsoft.VisualStudio.TestPlatform.ObjectModel must be set Copy Local to false"); } +} - public static class DirectoryInfoExtensions +public static class DirectoryInfoExtensions +{ + public static DirectoryInfo MoveUp(this DirectoryInfo di, int noOfLevels) { - public static DirectoryInfo MoveUp(this DirectoryInfo di, int noOfLevels) - { - var grandParent = di; - for (int i = 0; i < noOfLevels; i++) - grandParent = grandParent?.Parent; - return grandParent; - } + var grandParent = di; + for (int i = 0; i < noOfLevels; i++) + grandParent = grandParent?.Parent; + return grandParent; } } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TempDirectory.cs b/src/NUnitTestAdapterTests/TempDirectory.cs index 0199290c..ea22ac50 100644 --- a/src/NUnitTestAdapterTests/TempDirectory.cs +++ b/src/NUnitTestAdapterTests/TempDirectory.cs @@ -25,23 +25,22 @@ using System.IO; using IO = System.IO; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +internal sealed class TempDirectory : IDisposable { - internal sealed class TempDirectory : IDisposable - { - public string Path { get; } + public string Path { get; } - public TempDirectory() - { + public TempDirectory() + { Path = IO.Path.Combine(IO.Path.GetTempPath(), IO.Path.GetRandomFileName()); Directory.CreateDirectory(Path); } - public void Dispose() - { + public void Dispose() + { Utils.DeleteDirectoryRobust(Path); } - public static implicit operator string(TempDirectory tempDirectory) => tempDirectory.Path; - } + public static implicit operator string(TempDirectory tempDirectory) => tempDirectory.Path; } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestAdapterUtils.cs b/src/NUnitTestAdapterTests/TestAdapterUtils.cs index 99a51dc2..db0fbda1 100644 --- a/src/NUnitTestAdapterTests/TestAdapterUtils.cs +++ b/src/NUnitTestAdapterTests/TestAdapterUtils.cs @@ -27,26 +27,26 @@ using NUnit.Engine.Services; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +internal static class TestAdapterUtils { - internal static class TestAdapterUtils + public static ITestDiscoverer CreateDiscoverer() { - public static ITestDiscoverer CreateDiscoverer() - { - var discoverer = new NUnit3TestDiscoverer(); - InitializeForTesting(discoverer); - return discoverer; - } + var discoverer = new NUnit3TestDiscoverer(); + InitializeForTesting(discoverer); + return discoverer; + } - public static ITestExecutor CreateExecutor() - { - var executor = new NUnit3TestExecutor(); - InitializeForTesting(executor); - return executor; - } + public static ITestExecutor CreateExecutor() + { + var executor = new NUnit3TestExecutor(); + InitializeForTesting(executor); + return executor; + } - private static void InitializeForTesting(NUnitTestAdapter adapter) - { + private static void InitializeForTesting(NUnitTestAdapter adapter) + { #if NET462 adapter.NUnitEngineAdapter.InternalEngineCreated += engine => { @@ -63,6 +63,5 @@ private static void InitializeForTesting(NUnitTestAdapter adapter) concreteEngineType.Services.Add(new TestFilterService()); }; #endif - } } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestCaseUtils.cs b/src/NUnitTestAdapterTests/TestCaseUtils.cs index 5504ec44..d26713bd 100644 --- a/src/NUnitTestAdapterTests/TestCaseUtils.cs +++ b/src/NUnitTestAdapterTests/TestCaseUtils.cs @@ -29,18 +29,18 @@ using NUnit.VisualStudio.TestAdapter.NUnitEngine; using NUnit.VisualStudio.TestAdapter.Tests.Fakes; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +/// +/// Helper methods for testing against test cases. +/// +internal static class TestCaseUtils { /// - /// Helper methods for testing against test cases. + /// Knows how to convert an entire XML fragment. /// - internal static class TestCaseUtils + public static IReadOnlyList ConvertTestCases(this TestConverterForXml testConverterForXml, string xml) { - /// - /// Knows how to convert an entire XML fragment. - /// - public static IReadOnlyList ConvertTestCases(this TestConverterForXml testConverterForXml, string xml) - { if (testConverterForXml == null) throw new ArgumentNullException(nameof(testConverterForXml)); var fragment = new XmlDocument().CreateDocumentFragment(); @@ -55,8 +55,8 @@ public static IReadOnlyList ConvertTestCases(this TestConverterForXml return testCases; } - public static IReadOnlyCollection ConvertTestCases(string xml) - { + public static IReadOnlyCollection ConvertTestCases(string xml) + { var settings = Substitute.For(); settings.CollectSourceInformation.Returns(false); using (var testConverter = new TestConverterForXml( @@ -67,5 +67,4 @@ public static IReadOnlyCollection ConvertTestCases(string xml) return testConverter.ConvertTestCases(xml); } } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestConverterForXmlTests.cs b/src/NUnitTestAdapterTests/TestConverterForXmlTests.cs index 99a188e6..f84abc24 100644 --- a/src/NUnitTestAdapterTests/TestConverterForXmlTests.cs +++ b/src/NUnitTestAdapterTests/TestConverterForXmlTests.cs @@ -31,273 +31,271 @@ using NUnit.VisualStudio.TestAdapter.Dump; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +using Fakes; + +[Category("TestConverter")] +public class TestConverterForXmlTests { - using Fakes; + private NUnitEventTestCase fakeTestNode; + private TestConverterForXml testConverterForXml; - [Category("TestConverter")] - public class TestConverterForXmlTests + [SetUp] + public void SetUp() { - private NUnitEventTestCase fakeTestNode; - private TestConverterForXml testConverterForXml; + fakeTestNode = new NUnitEventTestCase(FakeTestData.GetTestNode()); + var settings = Substitute.For(); + settings.ConsoleOut.Returns(0); + settings.UseTestNameInConsoleOutput.Returns(false); + settings.CollectSourceInformation.Returns(true); + testConverterForXml = new TestConverterForXml(new TestLogger(new MessageLoggerStub()), FakeTestData.AssemblyPath, settings); + } - [SetUp] - public void SetUp() - { - fakeTestNode = new NUnitEventTestCase(FakeTestData.GetTestNode()); - var settings = Substitute.For(); - settings.ConsoleOut.Returns(0); - settings.UseTestNameInConsoleOutput.Returns(false); - settings.CollectSourceInformation.Returns(true); - testConverterForXml = new TestConverterForXml(new TestLogger(new MessageLoggerStub()), FakeTestData.AssemblyPath, settings); - } + [TearDown] + public void TearDown() + { + testConverterForXml.Dispose(); + } - [TearDown] - public void TearDown() - { - testConverterForXml.Dispose(); - } + [Test] + public void CanMakeTestCaseFromTest() + { + var testCase = testConverterForXml.ConvertTestCase(fakeTestNode); + CheckTestCase(testCase); + } - [Test] - public void CanMakeTestCaseFromTest() - { - var testCase = testConverterForXml.ConvertTestCase(fakeTestNode); - CheckTestCase(testCase); - } + [Test] + public void CanMakeTestCaseFromTestWithCache() + { + var testCase = testConverterForXml.ConvertTestCase(fakeTestNode); - [Test] - public void CanMakeTestCaseFromTestWithCache() - { - var testCase = testConverterForXml.ConvertTestCase(fakeTestNode); + CheckTestCase(testCase); - CheckTestCase(testCase); + Assert.That(testConverterForXml.TraitsCache.Keys.Count, Is.EqualTo(1)); + Assert.That(testConverterForXml.TraitsCache["121"].Traits.Count, Is.EqualTo(1)); + var parentTrait = testConverterForXml.TraitsCache["121"].Traits; + Assert.That(parentTrait[0].Name, Is.EqualTo("Category")); + Assert.That(parentTrait[0].Value, Is.EqualTo("super")); + } - Assert.That(testConverterForXml.TraitsCache.Keys.Count, Is.EqualTo(1)); - Assert.That(testConverterForXml.TraitsCache["121"].Traits.Count, Is.EqualTo(1)); - var parentTrait = testConverterForXml.TraitsCache["121"].Traits; - Assert.That(parentTrait[0].Name, Is.EqualTo("Category")); - Assert.That(parentTrait[0].Value, Is.EqualTo("super")); - } + [Test] + public void CanMakeTestCaseShouldBuildTraitsCache() + { + var xmlNodeList = FakeTestData.GetTestNodes(); - [Test] - public void CanMakeTestCaseShouldBuildTraitsCache() + foreach (XmlNode node in xmlNodeList) { - var xmlNodeList = FakeTestData.GetTestNodes(); - - foreach (XmlNode node in xmlNodeList) - { - testConverterForXml.ConvertTestCase(new NUnitEventTestCase(node)); - } - - var traitsCache = testConverterForXml.TraitsCache; + testConverterForXml.ConvertTestCase(new NUnitEventTestCase(node)); + } - // There are 12 ids in the TestXml2, but will be storing only ancestor properties. - // Not the leaf node test-case properties. - Assert.That(traitsCache.Keys.Count, Is.EqualTo(7)); + var traitsCache = testConverterForXml.TraitsCache; - // Even though ancestor doesn't have any properties. Will be storing their ids. - // So that we will not make call SelectNodes call again. - CheckNodesWithNoProperties(traitsCache); + // There are 12 ids in the TestXml2, but will be storing only ancestor properties. + // Not the leaf node test-case properties. + Assert.That(traitsCache.Keys.Count, Is.EqualTo(7)); - // Will not be storing leaf nodes test-case nodes in the cache. - CheckNoTestCaseNodesExist(traitsCache); + // Even though ancestor doesn't have any properties. Will be storing their ids. + // So that we will not make call SelectNodes call again. + CheckNodesWithNoProperties(traitsCache); - // Checking assembly level attribute. -#pragma warning disable SA1010 // Opening square brackets should be spaced correctly - CheckNodeProperties(traitsCache, "0-1009", [new KeyValuePair("Category", "AsmCat")]); + // Will not be storing leaf nodes test-case nodes in the cache. + CheckNoTestCaseNodesExist(traitsCache); + // Checking assembly level attribute. - // Checking Class level attributes base class & dervied class - CheckNodeProperties(traitsCache, "0-1000", [new KeyValuePair("Category", "BaseClass")]); - CheckNodeProperties(traitsCache, "0-1002", [new KeyValuePair("Category", "DerivedClass"), new KeyValuePair("Category", "BaseClass") - ]); + CheckNodeProperties(traitsCache, "0-1009", [new KeyValuePair("Category", "AsmCat")]); - // Checking Nested class attributes. - CheckNodeProperties(traitsCache, "0-1005", [new KeyValuePair("Category", "NS1")]); - CheckNodeProperties(traitsCache, "0-1007", [new KeyValuePair("Category", "NS2")]); -#pragma warning restore SA1010 // Opening square brackets should be spaced correctly - } + // Checking Class level attributes base class & dervied class + CheckNodeProperties(traitsCache, "0-1000", [new KeyValuePair("Category", "BaseClass")]); + CheckNodeProperties(traitsCache, "0-1002", [new KeyValuePair("Category", "DerivedClass"), new KeyValuePair("Category", "BaseClass") + ]); - [Test] - public void ConvertedTestCaseIsCached() - { - testConverterForXml.ConvertTestCase(fakeTestNode); - var testCase = testConverterForXml.GetCachedTestCase("123"); + // Checking Nested class attributes. + CheckNodeProperties(traitsCache, "0-1005", [new KeyValuePair("Category", "NS1")]); + CheckNodeProperties(traitsCache, "0-1007", [new KeyValuePair("Category", "NS2")]); + } - CheckTestCase(testCase); - } + [Test] + public void ConvertedTestCaseIsCached() + { + testConverterForXml.ConvertTestCase(fakeTestNode); + var testCase = testConverterForXml.GetCachedTestCase("123"); - [Test] - public void CannotMakeTestResultWhenTestCaseIsNotInCache() - { - var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); - var results = testConverterForXml.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); - Assert.That(results.TestResults.Count, Is.EqualTo(0)); - } + CheckTestCase(testCase); + } - [Test] - public void CanMakeTestResultFromNUnitTestResult() - { - // This should put the TestCase in the cache - var cachedTestCase = testConverterForXml.ConvertTestCase(fakeTestNode); - var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); + [Test] + public void CannotMakeTestResultWhenTestCaseIsNotInCache() + { + var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); + var results = testConverterForXml.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); + Assert.That(results.TestResults.Count, Is.EqualTo(0)); + } - var testResults = testConverterForXml.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); - var testResult = testResults.TestResults[0]; - var testCase = testResult.TestCase; + [Test] + public void CanMakeTestResultFromNUnitTestResult() + { + // This should put the TestCase in the cache + var cachedTestCase = testConverterForXml.ConvertTestCase(fakeTestNode); + var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); - Assert.That(testCase, Is.SameAs(cachedTestCase)); + var testResults = testConverterForXml.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); + var testResult = testResults.TestResults[0]; + var testCase = testResult.TestCase; - CheckTestCase(testCase); + Assert.That(testCase, Is.SameAs(cachedTestCase)); - Assert.That(testResult.Outcome, Is.EqualTo(TestOutcome.Passed)); - Assert.That(testResult.ErrorMessage, Is.EqualTo(null)); - Assert.That(testResult.Duration, Is.EqualTo(TimeSpan.FromSeconds(1.234))); - } + CheckTestCase(testCase); - [TestCase( - "", - "StdErrMsgs:some stdErr")] + Assert.That(testResult.Outcome, Is.EqualTo(TestOutcome.Passed)); + Assert.That(testResult.ErrorMessage, Is.EqualTo(null)); + Assert.That(testResult.Duration, Is.EqualTo(TimeSpan.FromSeconds(1.234))); + } - [TestCase( - "", - "")] + [TestCase( + "", + "StdErrMsgs:some stdErr")] - [TestCase( - "" - + ";", - "StdErrMsgs:some stdErr")] - public void CanMakeTestResultFromNUnitTestResult2(string output, string expectedMessages) - { - testConverterForXml.ConvertTestCase(fakeTestNode); - var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); - var outputNodes = output.Split(';').Select(i => new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(i.Trim()))).ToList(); - var outputNodesCollection = new List(outputNodes); - var testResults = testConverterForXml.GetVsTestResults(fakeResultNode, outputNodesCollection); - var testResult = testResults.TestResults[0]; - var actualMessages = string.Join(";", testResult.Messages.Select(i => i.Category + ":" + i.Text)); - - Assert.That(actualMessages, Is.EqualTo(expectedMessages)); - } + [TestCase( + "", + "")] - #region Attachment tests + [TestCase( + "" + + ";", + "StdErrMsgs:some stdErr")] + public void CanMakeTestResultFromNUnitTestResult2(string output, string expectedMessages) + { + testConverterForXml.ConvertTestCase(fakeTestNode); + var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); + var outputNodes = output.Split(';').Select(i => new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(i.Trim()))).ToList(); + var outputNodesCollection = new List(outputNodes); + var testResults = testConverterForXml.GetVsTestResults(fakeResultNode, outputNodesCollection); + var testResult = testResults.TestResults[0]; + var actualMessages = string.Join(";", testResult.Messages.Select(i => i.Category + ":" + i.Text)); + + Assert.That(actualMessages, Is.EqualTo(expectedMessages)); + } - [Test] - public void Attachments_CorrectAmountOfConvertedAttachments() - { - testConverterForXml.ConvertTestCase(fakeTestNode); - var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); + #region Attachment tests - var testResults = testConverterForXml.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); + [Test] + public void Attachments_CorrectAmountOfConvertedAttachments() + { + testConverterForXml.ConvertTestCase(fakeTestNode); + var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); - var fakeAttachments = fakeResultNode.NUnitAttachments - .Where(n => !string.IsNullOrEmpty(n.FilePath)) - .ToArray(); + var testResults = testConverterForXml.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); - var convertedAttachments = testResults.TestResults - .SelectMany(tr => tr.Attachments.SelectMany(ats => ats.Attachments)) - .ToArray(); + var fakeAttachments = fakeResultNode.NUnitAttachments + .Where(n => !string.IsNullOrEmpty(n.FilePath)) + .ToArray(); - Assert.Multiple(() => - { - Assert.That(convertedAttachments.Length, Is.GreaterThan(0), "Some converted attachments were expected"); - Assert.That(convertedAttachments.Length, Is.EqualTo(fakeAttachments.Length), "Attachments are not converted"); - }); - } + var convertedAttachments = testResults.TestResults + .SelectMany(tr => tr.Attachments.SelectMany(ats => ats.Attachments)) + .ToArray(); - [Test] - public void Attachments_AllFilePathesStartWithFileScheme() + Assert.Multiple(() => { - const string fileUriScheme = "file://"; - const string errorMessage = "Path must start with file:// uri scheme"; - - testConverterForXml.ConvertTestCase(fakeTestNode); - var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode().AsString()); + Assert.That(convertedAttachments.Length, Is.GreaterThan(0), "Some converted attachments were expected"); + Assert.That(convertedAttachments.Length, Is.EqualTo(fakeAttachments.Length), "Attachments are not converted"); + }); + } - var testResults = testConverterForXml.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); + [Test] + public void Attachments_AllFilePathesStartWithFileScheme() + { + const string fileUriScheme = "file://"; + const string errorMessage = "Path must start with file:// uri scheme"; - var convertedAttachments = testResults.TestResults - .SelectMany(tr => tr.Attachments.SelectMany(ats => ats.Attachments)) - .ToArray(); + testConverterForXml.ConvertTestCase(fakeTestNode); + var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode().AsString()); - foreach (var attachment in convertedAttachments) - { - var originalPath = attachment.Uri.OriginalString; - Assert.That(originalPath.LastIndexOf(fileUriScheme), Is.EqualTo(0), errorMessage); - } - } + var testResults = testConverterForXml.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); - #endregion Attachment tests + var convertedAttachments = testResults.TestResults + .SelectMany(tr => tr.Attachments.SelectMany(ats => ats.Attachments)) + .ToArray(); - private void CheckTestCase(TestCase testCase) + foreach (var attachment in convertedAttachments) { - Assert.That(testCase.FullyQualifiedName, Is.EqualTo(FakeTestData.FullyQualifiedName)); - Assert.That(testCase.DisplayName, Is.EqualTo(FakeTestData.DisplayName)); - Assert.That(testCase.Source, Is.SamePath(FakeTestData.AssemblyPath)); - - if (testCase.CodeFilePath != null) // Unavailable if not running under VS - { - Assert.That(testCase.CodeFilePath, Is.SamePath(FakeTestData.CodeFile)); - Assert.That(testCase.LineNumber, Is.EqualTo(FakeTestData.LineNumber)); - } - - var traitList = testCase.GetTraits().Select(trait => trait.Name + ":" + trait.Value).ToList(); - Assert.That(traitList, Is.EquivalentTo(new[] { "Priority:medium" })); - Assert.That(testCase.GetCategories(), Is.EquivalentTo(new[] { "super", "cat1", })); + var originalPath = attachment.Uri.OriginalString; + Assert.That(originalPath.LastIndexOf(fileUriScheme), Is.EqualTo(0), errorMessage); } + } - private void CheckNodesWithNoProperties(IDictionary cache) - { - Assert.That(cache["2"].Traits.Count, Is.EqualTo(0)); - Assert.That(cache["0-1010"].Traits.Count, Is.EqualTo(0)); - } + #endregion Attachment tests + + private void CheckTestCase(TestCase testCase) + { + Assert.That(testCase.FullyQualifiedName, Is.EqualTo(FakeTestData.FullyQualifiedName)); + Assert.That(testCase.DisplayName, Is.EqualTo(FakeTestData.DisplayName)); + Assert.That(testCase.Source, Is.SamePath(FakeTestData.AssemblyPath)); - private void CheckNoTestCaseNodesExist(IDictionary cache) + if (testCase.CodeFilePath != null) // Unavailable if not running under VS { - Assert.That(!cache.ContainsKey("0-1008")); - Assert.That(!cache.ContainsKey("0-1006")); - Assert.That(!cache.ContainsKey("0-1004")); - Assert.That(!cache.ContainsKey("0-1003")); - Assert.That(!cache.ContainsKey("0-1001")); + Assert.That(testCase.CodeFilePath, Is.SamePath(FakeTestData.CodeFile)); + Assert.That(testCase.LineNumber, Is.EqualTo(FakeTestData.LineNumber)); } - private void CheckNodeProperties(IDictionary cache, string id, KeyValuePair[] kps) + var traitList = testCase.GetTraits().Select(trait => trait.Name + ":" + trait.Value).ToList(); + Assert.That(traitList, Is.EquivalentTo(new[] { "Priority:medium" })); + Assert.That(testCase.GetCategories(), Is.EquivalentTo(new[] { "super", "cat1", })); + } + + private void CheckNodesWithNoProperties(IDictionary cache) + { + Assert.That(cache["2"].Traits.Count, Is.EqualTo(0)); + Assert.That(cache["0-1010"].Traits.Count, Is.EqualTo(0)); + } + + private void CheckNoTestCaseNodesExist(IDictionary cache) + { + Assert.That(!cache.ContainsKey("0-1008")); + Assert.That(!cache.ContainsKey("0-1006")); + Assert.That(!cache.ContainsKey("0-1004")); + Assert.That(!cache.ContainsKey("0-1003")); + Assert.That(!cache.ContainsKey("0-1001")); + } + + private void CheckNodeProperties(IDictionary cache, string id, KeyValuePair[] kps) + { + Assert.That(cache.ContainsKey(id)); + Assert.That(cache[id].Traits.Count, Is.EqualTo(kps.Length)); + var info = cache[id]; + + foreach (var kp in kps) { - Assert.That(cache.ContainsKey(id)); - Assert.That(cache[id].Traits.Count, Is.EqualTo(kps.Length)); - var info = cache[id]; - - foreach (var kp in kps) - { - Assert.That(info.Traits.Any(t => t.Name == kp.Key && t.Value == kp.Value)); - } + Assert.That(info.Traits.Any(t => t.Name == kp.Key && t.Value == kp.Value)); } + } - [Description("Third-party runners may opt to depend on this. https://github.com/nunit/nunit3-vs-adapter/issues/487#issuecomment-389222879")] - [TestCase("NonExplicitParent.ExplicitTest")] - [TestCase("ExplicitParent.NonExplicitTest")] - public static void NUnitExplicitBoolPropertyIsProvidedForThirdPartyRunnersInExplicitTestCases(string testName) - { - var testCase = GetSampleTestCase(testName); + [Description("Third-party runners may opt to depend on this. https://github.com/nunit/nunit3-vs-adapter/issues/487#issuecomment-389222879")] + [TestCase("NonExplicitParent.ExplicitTest")] + [TestCase("ExplicitParent.NonExplicitTest")] + public static void NUnitExplicitBoolPropertyIsProvidedForThirdPartyRunnersInExplicitTestCases(string testName) + { + var testCase = GetSampleTestCase(testName); - var property = testCase.Properties.Single(p => - p.Id == "NUnit.Explicit" - && p.GetValueType() == typeof(bool)); + var property = testCase.Properties.Single(p => + p.Id == "NUnit.Explicit" + && p.GetValueType() == typeof(bool)); - Assert.That(testCase.GetPropertyValue(property), Is.True); - } + Assert.That(testCase.GetPropertyValue(property), Is.True); + } - [TestCase("NonExplicitParent.NonExplicitTestWithExplicitCategory")] - public static void NUnitExplicitBoolPropertyIsNotProvidedForThirdPartyRunnersInNonExplicitTestCases(string testName) - { - var testCase = GetSampleTestCase(testName); + [TestCase("NonExplicitParent.NonExplicitTestWithExplicitCategory")] + public static void NUnitExplicitBoolPropertyIsNotProvidedForThirdPartyRunnersInNonExplicitTestCases(string testName) + { + var testCase = GetSampleTestCase(testName); - Assert.That(testCase, Has.Property("Properties").With.None.With.Property("Id").EqualTo("NUnit.Explicit")); - } + Assert.That(testCase, Has.Property("Properties").With.None.With.Property("Id").EqualTo("NUnit.Explicit")); + } - private static TestCase GetSampleTestCase(string fullyQualifiedName) - { - return TestCaseUtils.ConvertTestCases(@" + private static TestCase GetSampleTestCase(string fullyQualifiedName) + { + return TestCaseUtils.ConvertTestCases(@" @@ -309,6 +307,5 @@ private static TestCase GetSampleTestCase(string fullyQualifiedName) ").Single(t => t.FullyQualifiedName == fullyQualifiedName); - } } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestConverterTests.cs b/src/NUnitTestAdapterTests/TestConverterTests.cs index 24cbffd2..cadc06bd 100644 --- a/src/NUnitTestAdapterTests/TestConverterTests.cs +++ b/src/NUnitTestAdapterTests/TestConverterTests.cs @@ -32,276 +32,276 @@ using NUnit.VisualStudio.TestAdapter.Dump; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +using Fakes; + +[Category("TestConverter")] +public class TestConverterTests { - using Fakes; + private NUnitDiscoveryTestCase fakeTestNode; + private TestConverter testConverter; - [Category("TestConverter")] - public class TestConverterTests + [SetUp] + public void SetUp() { - private NUnitDiscoveryTestCase fakeTestNode; - private TestConverter testConverter; - - [SetUp] - public void SetUp() - { - var xDoc = XDocument.Parse(FakeTestData.TestXml); - var parent = Substitute.For(); - parent.Parent.Returns(null as INUnitDiscoverySuiteBase); - var className = xDoc.Root.Attribute("classname").Value; - var tf = DiscoveryConverter.ExtractTestFixture(parent, xDoc.Root, className); - var tcs = DiscoveryConverter.ExtractTestCases(tf, xDoc.Root); - Assert.That(tcs.Count(), Is.EqualTo(1), "Setup: More than one test case in fake data"); - fakeTestNode = tcs.Single(); - var settings = Substitute.For(); - settings.ConsoleOut.Returns(0); - settings.UseTestNameInConsoleOutput.Returns(false); - settings.CollectSourceInformation.Returns(true); - var discoveryConverter = Substitute.For(); - testConverter = new TestConverter(new TestLogger(new MessageLoggerStub()), FakeTestData.AssemblyPath, settings, discoveryConverter); - } + var xDoc = XDocument.Parse(FakeTestData.TestXml); + var parent = Substitute.For(); + parent.Parent.Returns(null as INUnitDiscoverySuiteBase); + var className = xDoc.Root.Attribute("classname").Value; + var tf = DiscoveryConverter.ExtractTestFixture(parent, xDoc.Root, className); + var tcs = DiscoveryConverter.ExtractTestCases(tf, xDoc.Root); + Assert.That(tcs.Count(), Is.EqualTo(1), "Setup: More than one test case in fake data"); + fakeTestNode = tcs.Single(); + var settings = Substitute.For(); + settings.ConsoleOut.Returns(0); + settings.UseTestNameInConsoleOutput.Returns(false); + settings.CollectSourceInformation.Returns(true); + var discoveryConverter = Substitute.For(); + testConverter = new TestConverter(new TestLogger(new MessageLoggerStub()), FakeTestData.AssemblyPath, settings, discoveryConverter); + } - [TearDown] - public void TearDown() - { - testConverter?.Dispose(); - } + [TearDown] + public void TearDown() + { + testConverter?.Dispose(); + } - [Test] - public void CanMakeTestCaseFromTest() - { - var testCase = testConverter.ConvertTestCase(fakeTestNode); - CheckTestCase(testCase); - } + [Test] + public void CanMakeTestCaseFromTest() + { + var testCase = testConverter.ConvertTestCase(fakeTestNode); + CheckTestCase(testCase); + } - [Test] - public void CanMakeTestCaseFromTestWithCache() - { - var testCase = testConverter.ConvertTestCase(fakeTestNode); + [Test] + public void CanMakeTestCaseFromTestWithCache() + { + var testCase = testConverter.ConvertTestCase(fakeTestNode); - CheckTestCase(testCase); + CheckTestCase(testCase); - Assert.That(testConverter.TraitsCache.Keys.Count, Is.EqualTo(1)); - Assert.That(testConverter.TraitsCache["121"].Traits.Count, Is.EqualTo(1)); - var parentTrait = testConverter.TraitsCache["121"].Traits; - Assert.That(parentTrait[0].Name, Is.EqualTo("Category")); - Assert.That(parentTrait[0].Value, Is.EqualTo("super")); - } + Assert.That(testConverter.TraitsCache.Keys.Count, Is.EqualTo(1)); + Assert.That(testConverter.TraitsCache["121"].Traits.Count, Is.EqualTo(1)); + var parentTrait = testConverter.TraitsCache["121"].Traits; + Assert.That(parentTrait[0].Name, Is.EqualTo("Category")); + Assert.That(parentTrait[0].Value, Is.EqualTo("super")); + } - [Ignore("To do")] - [Test] - public void CanMakeTestCaseShouldBuildTraitsCache() + [Ignore("To do")] + [Test] + public void CanMakeTestCaseShouldBuildTraitsCache() + { + var xmlNodeList = FakeTestData.GetTestNodes(); + var tf = Substitute.For(); + foreach (XmlNode node in xmlNodeList) { - var xmlNodeList = FakeTestData.GetTestNodes(); - var tf = Substitute.For(); - foreach (XmlNode node in xmlNodeList) - { - var xElem = XElement.Load(node.CreateNavigator().ReadSubtree()); - var tc = DiscoveryConverter.ExtractTestCase(tf, xElem); - var testCase = testConverter.ConvertTestCase(tc); - } - - var traitsCache = testConverter.TraitsCache; - Assert.Multiple(() => - { - // There are 12 ids in the TestXml2, but will be storing only ancestor properties. - // Not the leaf node test-case properties. - Assert.That(traitsCache.Keys.Count, Is.EqualTo(7)); - - // Even though ancestor doesn't have any properties. Will be storing their ids. - // So that we will not make call SelectNodes call again. - CheckNodesWithNoProperties(traitsCache); - - // Will not be storing leaf nodes test-case nodes in the cache. - CheckNoTestCaseNodesExist(traitsCache); - - // Checking assembly level attribute. - CheckNodeProperties(traitsCache, "0-1009", - new[] { new KeyValuePair("Category", "AsmCat") }); - - // Checking Class level attributes base class & dervied class - CheckNodeProperties(traitsCache, "0-1000", - new[] { new KeyValuePair("Category", "BaseClass") }); - CheckNodeProperties(traitsCache, "0-1002", - new[] - { - new KeyValuePair("Category", "DerivedClass"), - new KeyValuePair("Category", "BaseClass") - }); - - // Checking Nested class attributes. - CheckNodeProperties(traitsCache, "0-1005", new[] { new KeyValuePair("Category", "NS1") }); - CheckNodeProperties(traitsCache, "0-1007", new[] { new KeyValuePair("Category", "NS2") }); - }); + var xElem = XElement.Load(node.CreateNavigator().ReadSubtree()); + var tc = DiscoveryConverter.ExtractTestCase(tf, xElem); + var testCase = testConverter.ConvertTestCase(tc); } - [Test] - public void ConvertedTestCaseIsCached() + var traitsCache = testConverter.TraitsCache; + Assert.Multiple(() => { - testConverter.ConvertTestCase(fakeTestNode); - var testCase = testConverter.GetCachedTestCase("123"); + // There are 12 ids in the TestXml2, but will be storing only ancestor properties. + // Not the leaf node test-case properties. + Assert.That(traitsCache.Keys.Count, Is.EqualTo(7)); + + // Even though ancestor doesn't have any properties. Will be storing their ids. + // So that we will not make call SelectNodes call again. + CheckNodesWithNoProperties(traitsCache); + + // Will not be storing leaf nodes test-case nodes in the cache. + CheckNoTestCaseNodesExist(traitsCache); + + // Checking assembly level attribute. + CheckNodeProperties(traitsCache, "0-1009", + new[] { new KeyValuePair("Category", "AsmCat") }); + + // Checking Class level attributes base class & dervied class + CheckNodeProperties(traitsCache, "0-1000", + new[] { new KeyValuePair("Category", "BaseClass") }); + CheckNodeProperties(traitsCache, "0-1002", + new[] + { + new KeyValuePair("Category", "DerivedClass"), + new KeyValuePair("Category", "BaseClass") + }); + + // Checking Nested class attributes. + CheckNodeProperties(traitsCache, "0-1005", new[] { new KeyValuePair("Category", "NS1") }); + CheckNodeProperties(traitsCache, "0-1007", new[] { new KeyValuePair("Category", "NS2") }); + }); + } - CheckTestCase(testCase); - } + [Test] + public void ConvertedTestCaseIsCached() + { + testConverter.ConvertTestCase(fakeTestNode); + var testCase = testConverter.GetCachedTestCase("123"); - [Test] - public void CannotMakeTestResultWhenTestCaseIsNotInCache() - { - var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); - var results = testConverter.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); - Assert.That(results.TestResults.Count, Is.EqualTo(0)); - } + CheckTestCase(testCase); + } - [Test] - public void CanMakeTestResultFromNUnitTestResult() - { - // This should put the TestCase in the cache - var cachedTestCase = testConverter.ConvertTestCase(fakeTestNode); - var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); + [Test] + public void CannotMakeTestResultWhenTestCaseIsNotInCache() + { + var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); + var results = testConverter.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); + Assert.That(results.TestResults.Count, Is.EqualTo(0)); + } - var testResults = testConverter.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); - var testResult = testResults.TestResults[0]; - var testCase = testResult.TestCase; + [Test] + public void CanMakeTestResultFromNUnitTestResult() + { + // This should put the TestCase in the cache + var cachedTestCase = testConverter.ConvertTestCase(fakeTestNode); + var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); - Assert.That(testCase, Is.SameAs(cachedTestCase)); + var testResults = testConverter.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); + var testResult = testResults.TestResults[0]; + var testCase = testResult.TestCase; - CheckTestCase(testCase); + Assert.That(testCase, Is.SameAs(cachedTestCase)); - Assert.That(testResult.Outcome, Is.EqualTo(TestOutcome.Passed)); - Assert.That(testResult.ErrorMessage, Is.EqualTo(null)); - Assert.That(testResult.Duration, Is.EqualTo(TimeSpan.FromSeconds(1.234))); - } + CheckTestCase(testCase); - [TestCase( - "", - "StdErrMsgs:some stdErr")] + Assert.That(testResult.Outcome, Is.EqualTo(TestOutcome.Passed)); + Assert.That(testResult.ErrorMessage, Is.EqualTo(null)); + Assert.That(testResult.Duration, Is.EqualTo(TimeSpan.FromSeconds(1.234))); + } - [TestCase( - "", - "")] + [TestCase( + "", + "StdErrMsgs:some stdErr")] - [TestCase( - "" - + ";", - "StdErrMsgs:some stdErr")] - public void CanMakeTestResultFromNUnitTestResult2(string output, string expectedMessages) - { - var cachedTestCase = testConverter.ConvertTestCase(fakeTestNode); - var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); - var outputNodes = output.Split(';').Select(i => new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(i.Trim()))).ToList(); - var outputNodesCollection = new List(outputNodes); - var testResults = testConverter.GetVsTestResults(fakeResultNode, outputNodesCollection); - var testResult = testResults.TestResults[0]; - var actualMessages = string.Join(";", testResult.Messages.Select(i => i.Category + ":" + i.Text)); - - Assert.That(actualMessages, Is.EqualTo(expectedMessages)); - } + [TestCase( + "", + "")] - #region Attachment tests + [TestCase( + "" + + ";", + "StdErrMsgs:some stdErr")] + public void CanMakeTestResultFromNUnitTestResult2(string output, string expectedMessages) + { + var cachedTestCase = testConverter.ConvertTestCase(fakeTestNode); + var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); + var outputNodes = output.Split(';').Select(i => new NUnitTestEventTestOutput(XmlHelper.CreateXmlNode(i.Trim()))).ToList(); + var outputNodesCollection = new List(outputNodes); + var testResults = testConverter.GetVsTestResults(fakeResultNode, outputNodesCollection); + var testResult = testResults.TestResults[0]; + var actualMessages = string.Join(";", testResult.Messages.Select(i => i.Category + ":" + i.Text)); + + Assert.That(actualMessages, Is.EqualTo(expectedMessages)); + } - [Test] - public void Attachments_CorrectAmountOfConvertedAttachments() - { - var cachedTestCase = testConverter.ConvertTestCase(fakeTestNode); - var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); - - var testResults = testConverter.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); - - var fakeAttachments = fakeResultNode.NUnitAttachments - .Where(n => !string.IsNullOrEmpty(n.FilePath)) - .ToArray(); - TestContext.Out.WriteLine("Incoming attachments"); - foreach (var attachment in fakeAttachments) - { - TestContext.Out.WriteLine($"{attachment.FilePath}"); - } - var convertedAttachments = testResults.TestResults - .SelectMany(tr => tr.Attachments.SelectMany(ats => ats.Attachments)) - .ToArray(); - TestContext.Out.WriteLine("\nConverted attachments (Uri, path)"); - foreach (var attachment in convertedAttachments) - { - TestContext.Out.WriteLine($"{attachment.Uri.AbsoluteUri} : {attachment.Uri.LocalPath}"); - } - Assert.Multiple(() => - { - Assert.That(convertedAttachments.Length, Is.GreaterThan(0), "Some converted attachments were expected"); - Assert.That(convertedAttachments.Length, Is.EqualTo(fakeAttachments.Length), "Attachments are not converted"); - }); - } + #region Attachment tests + + [Test] + public void Attachments_CorrectAmountOfConvertedAttachments() + { + var cachedTestCase = testConverter.ConvertTestCase(fakeTestNode); + var fakeResultNode = new NUnitTestEventTestCase(FakeTestData.GetResultNode()); - #endregion Attachment tests + var testResults = testConverter.GetVsTestResults(fakeResultNode, Enumerable.Empty().ToList()); - private void CheckTestCase(TestCase testCase) + var fakeAttachments = fakeResultNode.NUnitAttachments + .Where(n => !string.IsNullOrEmpty(n.FilePath)) + .ToArray(); + TestContext.Out.WriteLine("Incoming attachments"); + foreach (var attachment in fakeAttachments) { - Assert.That(testCase.FullyQualifiedName, Is.EqualTo(FakeTestData.FullyQualifiedName)); - Assert.That(testCase.DisplayName, Is.EqualTo(FakeTestData.DisplayName)); - Assert.That(testCase.Source, Is.SamePath(FakeTestData.AssemblyPath)); - - if (testCase.CodeFilePath != null) // Unavailable if not running under VS - { - Assert.That(testCase.CodeFilePath, Is.SamePath(FakeTestData.CodeFile)); - Assert.That(testCase.LineNumber, Is.EqualTo(FakeTestData.LineNumber)); - } - - var traitList = testCase.GetTraits().Select(trait => trait.Name + ":" + trait.Value).ToList(); - Assert.That(traitList, Is.EquivalentTo(new[] { "Priority:medium" })); - Assert.That(testCase.GetCategories(), Is.EquivalentTo(new[] { "super", "cat1", })); + TestContext.Out.WriteLine($"{attachment.FilePath}"); } - - private void CheckNodesWithNoProperties(IDictionary cache) + var convertedAttachments = testResults.TestResults + .SelectMany(tr => tr.Attachments.SelectMany(ats => ats.Attachments)) + .ToArray(); + TestContext.Out.WriteLine("\nConverted attachments (Uri, path)"); + foreach (var attachment in convertedAttachments) { - Assert.That(cache["2"].Traits.Count, Is.EqualTo(0)); - Assert.That(cache["0-1010"].Traits.Count, Is.EqualTo(0)); + TestContext.Out.WriteLine($"{attachment.Uri.AbsoluteUri} : {attachment.Uri.LocalPath}"); } + Assert.Multiple(() => + { + Assert.That(convertedAttachments.Length, Is.GreaterThan(0), "Some converted attachments were expected"); + Assert.That(convertedAttachments.Length, Is.EqualTo(fakeAttachments.Length), "Attachments are not converted"); + }); + } + + #endregion Attachment tests - private void CheckNoTestCaseNodesExist(IDictionary cache) + private void CheckTestCase(TestCase testCase) + { + Assert.That(testCase.FullyQualifiedName, Is.EqualTo(FakeTestData.FullyQualifiedName)); + Assert.That(testCase.DisplayName, Is.EqualTo(FakeTestData.DisplayName)); + Assert.That(testCase.Source, Is.SamePath(FakeTestData.AssemblyPath)); + + if (testCase.CodeFilePath != null) // Unavailable if not running under VS { - Assert.That(!cache.ContainsKey("0-1008")); - Assert.That(!cache.ContainsKey("0-1006")); - Assert.That(!cache.ContainsKey("0-1004")); - Assert.That(!cache.ContainsKey("0-1003")); - Assert.That(!cache.ContainsKey("0-1001")); + Assert.That(testCase.CodeFilePath, Is.SamePath(FakeTestData.CodeFile)); + Assert.That(testCase.LineNumber, Is.EqualTo(FakeTestData.LineNumber)); } - private void CheckNodeProperties(IDictionary cache, string id, KeyValuePair[] kps) + var traitList = testCase.GetTraits().Select(trait => trait.Name + ":" + trait.Value).ToList(); + Assert.That(traitList, Is.EquivalentTo(new[] { "Priority:medium" })); + Assert.That(testCase.GetCategories(), Is.EquivalentTo(new[] { "super", "cat1", })); + } + + private void CheckNodesWithNoProperties(IDictionary cache) + { + Assert.That(cache["2"].Traits.Count, Is.EqualTo(0)); + Assert.That(cache["0-1010"].Traits.Count, Is.EqualTo(0)); + } + + private void CheckNoTestCaseNodesExist(IDictionary cache) + { + Assert.That(!cache.ContainsKey("0-1008")); + Assert.That(!cache.ContainsKey("0-1006")); + Assert.That(!cache.ContainsKey("0-1004")); + Assert.That(!cache.ContainsKey("0-1003")); + Assert.That(!cache.ContainsKey("0-1001")); + } + + private void CheckNodeProperties(IDictionary cache, string id, KeyValuePair[] kps) + { + Assert.That(cache.ContainsKey(id)); + Assert.That(cache[id].Traits.Count, Is.EqualTo(kps.Count())); + var info = cache[id]; + + foreach (var kp in kps) { - Assert.That(cache.ContainsKey(id)); - Assert.That(cache[id].Traits.Count, Is.EqualTo(kps.Count())); - var info = cache[id]; - - foreach (var kp in kps) - { - Assert.That(info.Traits.Any(t => t.Name == kp.Key && t.Value == kp.Value)); - } + Assert.That(info.Traits.Any(t => t.Name == kp.Key && t.Value == kp.Value)); } + } - [Description("Third-party runners may opt to depend on this. https://github.com/nunit/nunit3-vs-adapter/issues/487#issuecomment-389222879")] - [TestCase("NonExplicitParent.ExplicitTest")] - [TestCase("ExplicitParent.NonExplicitTest")] - public static void NUnitExplicitBoolPropertyIsProvidedForThirdPartyRunnersInExplicitTestCases(string testName) - { - var testCase = GetSampleTestCase(testName); + [Description("Third-party runners may opt to depend on this. https://github.com/nunit/nunit3-vs-adapter/issues/487#issuecomment-389222879")] + [TestCase("NonExplicitParent.ExplicitTest")] + [TestCase("ExplicitParent.NonExplicitTest")] + public static void NUnitExplicitBoolPropertyIsProvidedForThirdPartyRunnersInExplicitTestCases(string testName) + { + var testCase = GetSampleTestCase(testName); - var property = testCase.Properties.Single(p => - p.Id == "NUnit.Explicit" - && p.GetValueType() == typeof(bool)); + var property = testCase.Properties.Single(p => + p.Id == "NUnit.Explicit" + && p.GetValueType() == typeof(bool)); - Assert.That(testCase.GetPropertyValue(property), Is.True); - } + Assert.That(testCase.GetPropertyValue(property), Is.True); + } - [TestCase("NonExplicitParent.NonExplicitTestWithExplicitCategory")] - public static void NUnitExplicitBoolPropertyIsNotProvidedForThirdPartyRunnersInNonExplicitTestCases(string testName) - { - var testCase = GetSampleTestCase(testName); + [TestCase("NonExplicitParent.NonExplicitTestWithExplicitCategory")] + public static void NUnitExplicitBoolPropertyIsNotProvidedForThirdPartyRunnersInNonExplicitTestCases(string testName) + { + var testCase = GetSampleTestCase(testName); - Assert.That(testCase, Has.Property("Properties").With.None.With.Property("Id").EqualTo("NUnit.Explicit")); - } + Assert.That(testCase, Has.Property("Properties").With.None.With.Property("Id").EqualTo("NUnit.Explicit")); + } - private static TestCase GetSampleTestCase(string fullyQualifiedName) - { - return TestCaseUtils.ConvertTestCases(@" + private static TestCase GetSampleTestCase(string fullyQualifiedName) + { + return TestCaseUtils.ConvertTestCases(@" @@ -313,6 +313,5 @@ private static TestCase GetSampleTestCase(string fullyQualifiedName) ").Single(t => t.FullyQualifiedName == fullyQualifiedName); - } } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestConverterTests_StaticHelpers.cs b/src/NUnitTestAdapterTests/TestConverterTests_StaticHelpers.cs index 4722169a..5b4cb5ee 100644 --- a/src/NUnitTestAdapterTests/TestConverterTests_StaticHelpers.cs +++ b/src/NUnitTestAdapterTests/TestConverterTests_StaticHelpers.cs @@ -28,22 +28,22 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.NUnitEngine; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +[Category("TestConverter")] +public class TestConverterTestsGetTestOutcome { - [Category("TestConverter")] - public class TestConverterTestsGetTestOutcome + [TestCase("", TestOutcome.Failed)] + [TestCase("", TestOutcome.Failed)] + [TestCase("", TestOutcome.Failed)] + [TestCase("", TestOutcome.Skipped)] + [TestCase("", TestOutcome.None)] + [TestCase("", TestOutcome.Failed)] + [TestCase("", TestOutcome.None)] + [TestCase("", TestOutcome.Passed)] + [TestCase("", TestOutcome.Skipped)] + public void ResultStateToTestOutcome(string result, TestOutcome expected) { - [TestCase("", TestOutcome.Failed)] - [TestCase("", TestOutcome.Failed)] - [TestCase("", TestOutcome.Failed)] - [TestCase("", TestOutcome.Skipped)] - [TestCase("", TestOutcome.None)] - [TestCase("", TestOutcome.Failed)] - [TestCase("", TestOutcome.None)] - [TestCase("", TestOutcome.Passed)] - [TestCase("", TestOutcome.Skipped)] - public void ResultStateToTestOutcome(string result, TestOutcome expected) - { var resultNode = new NUnitTestEventTestCase(XmlHelper.CreateXmlNode(result)); var logger = Substitute.For(); var settings = Substitute.For(); @@ -55,5 +55,4 @@ public void ResultStateToTestOutcome(string result, TestOutcome expected) Assert.That(res, Is.EqualTo(expected), $"In: {result}, out: {res.ToString()} expected: {expected.ToString()} "); } - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestDiscoveryTests.cs b/src/NUnitTestAdapterTests/TestDiscoveryTests.cs index 73e337d8..fb20d1c8 100644 --- a/src/NUnitTestAdapterTests/TestDiscoveryTests.cs +++ b/src/NUnitTestAdapterTests/TestDiscoveryTests.cs @@ -33,182 +33,181 @@ using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +using Fakes; + +internal static class TestDiscoveryDataProvider +{ + public static IEnumerable TestDiscoveryData() + { + // yield return new FakeDiscoveryContext(null); + yield return new FakeDiscoveryContext(new FakeRunSettings()); + } +} + +[Ignore("These tests needs to rewritten as isolated tests")] +[Category("TestDiscovery")] +public class TestDiscoveryTests : ITestCaseDiscoverySink { - using Fakes; + static readonly string MockAssemblyPath = + Path.Combine(TestContext.CurrentContext.TestDirectory, "mock-assembly.dll"); - internal static class TestDiscoveryDataProvider + private readonly List testCases = new(); + + private readonly IDiscoveryContext _context; + + public TestDiscoveryTests() { - public static IEnumerable TestDiscoveryData() - { - // yield return new FakeDiscoveryContext(null); - yield return new FakeDiscoveryContext(new FakeRunSettings()); - } + _context = Substitute.For(); } - [Ignore("These tests needs to rewritten as isolated tests")] - [Category("TestDiscovery")] - public class TestDiscoveryTests : ITestCaseDiscoverySink + [OneTimeSetUp] + public void LoadMockassembly() { - static readonly string MockAssemblyPath = - Path.Combine(TestContext.CurrentContext.TestDirectory, "mock-assembly.dll"); + // Sanity check to be sure we have the correct version of mock-assembly.dll. + Assert.That(NUnit.Tests.Assemblies.MockAssembly.TestsAtRuntime, Is.EqualTo(NUnit.Tests.Assemblies.MockAssembly.Tests), + "The reference to mock-assembly.dll appears to be the wrong version"); + Assert.That(File.Exists(MockAssemblyPath), $"Can't locate mock-assembly.dll at {MockAssemblyPath}"); + var runsettings = "TruefalseLegacy"; + var rs = Substitute.For(); + rs.SettingsXml.Returns(runsettings); + _context.RunSettings.Returns(rs); + // Load the NUnit mock-assembly.dll once for this test, saving + // the list of test cases sent to the discovery sink. + var discoverer = TestAdapterUtils.CreateDiscoverer(); + discoverer.DiscoverTests( + new[] { MockAssemblyPath }, + _context, + new MessageLoggerStub(), + this); + } - private readonly List testCases = new(); + [Test] + public void VerifyTestCaseCount() + { + Assert.That(testCases.Count, Is.EqualTo(NUnit.Tests.Assemblies.MockAssembly.Tests)); + } - private readonly IDiscoveryContext _context; + [TestCase("MockTest3", "NUnit.Tests.Assemblies.MockTestFixture.MockTest3")] + [TestCase("MockTest4", "NUnit.Tests.Assemblies.MockTestFixture.MockTest4")] + [TestCase("ExplicitlyRunTest", "NUnit.Tests.Assemblies.MockTestFixture.ExplicitlyRunTest")] + [TestCase("MethodWithParameters(9,11)", "NUnit.Tests.FixtureWithTestCases.MethodWithParameters", true)] + public void VerifyTestCaseIsFound(string name, string fullName, bool parentFQN = false) + { + var testCase = testCases.Find(tc => tc.DisplayName == name); + Assert.That(testCase.FullyQualifiedName, Is.EqualTo(fullName)); + } - public TestDiscoveryTests() - { - _context = Substitute.For(); - } + [Category("Navigation")] + [TestCase("NestedClassTest1")] // parent + [TestCase("NestedClassTest2")] // child + [TestCase("NestedClassTest3")] // grandchild + public void VerifyNestedTestCaseSourceIsAvailable(string name) + { + var testCase = testCases.Find(tc => tc.DisplayName == name); - [OneTimeSetUp] - public void LoadMockassembly() - { - // Sanity check to be sure we have the correct version of mock-assembly.dll. - Assert.That(NUnit.Tests.Assemblies.MockAssembly.TestsAtRuntime, Is.EqualTo(NUnit.Tests.Assemblies.MockAssembly.Tests), - "The reference to mock-assembly.dll appears to be the wrong version"); - Assert.That(File.Exists(MockAssemblyPath), $"Can't locate mock-assembly.dll at {MockAssemblyPath}"); - var runsettings = "TruefalseLegacy"; - var rs = Substitute.For(); - rs.SettingsXml.Returns(runsettings); - _context.RunSettings.Returns(rs); - // Load the NUnit mock-assembly.dll once for this test, saving - // the list of test cases sent to the discovery sink. - var discoverer = TestAdapterUtils.CreateDiscoverer(); - discoverer.DiscoverTests( - new[] { MockAssemblyPath }, - _context, - new MessageLoggerStub(), - this); - } + Assert.That(!string.IsNullOrEmpty(testCase.Source)); + Assert.That(testCase.LineNumber, Is.GreaterThan(0)); + } - [Test] - public void VerifyTestCaseCount() - { - Assert.That(testCases.Count, Is.EqualTo(NUnit.Tests.Assemblies.MockAssembly.Tests)); - } - - [TestCase("MockTest3", "NUnit.Tests.Assemblies.MockTestFixture.MockTest3")] - [TestCase("MockTest4", "NUnit.Tests.Assemblies.MockTestFixture.MockTest4")] - [TestCase("ExplicitlyRunTest", "NUnit.Tests.Assemblies.MockTestFixture.ExplicitlyRunTest")] - [TestCase("MethodWithParameters(9,11)", "NUnit.Tests.FixtureWithTestCases.MethodWithParameters", true)] - public void VerifyTestCaseIsFound(string name, string fullName, bool parentFQN = false) - { - var testCase = testCases.Find(tc => tc.DisplayName == name); - Assert.That(testCase.FullyQualifiedName, Is.EqualTo(fullName)); - } - - [Category("Navigation")] - [TestCase("NestedClassTest1")] // parent - [TestCase("NestedClassTest2")] // child - [TestCase("NestedClassTest3")] // grandchild - public void VerifyNestedTestCaseSourceIsAvailable(string name) - { - var testCase = testCases.Find(tc => tc.DisplayName == name); + #region ITestCaseDiscoverySink Methods - Assert.That(!string.IsNullOrEmpty(testCase.Source)); - Assert.That(testCase.LineNumber, Is.GreaterThan(0)); - } + void ITestCaseDiscoverySink.SendTestCase(TestCase discoveredTest) + { + testCases.Add(discoveredTest); + } - #region ITestCaseDiscoverySink Methods + #endregion +} - void ITestCaseDiscoverySink.SendTestCase(TestCase discoveredTest) - { - testCases.Add(discoveredTest); - } +[Category("TestDiscovery")] +public class EmptyAssemblyDiscoveryTests : ITestCaseDiscoverySink +{ + static readonly string EmptyAssemblyPath = + Path.Combine(TestContext.CurrentContext.TestDirectory, "empty-assembly.dll"); - #endregion + [TestCaseSource(typeof(TestDiscoveryDataProvider), nameof(TestDiscoveryDataProvider.TestDiscoveryData))] + public void VerifyLoading(IDiscoveryContext context) + { + // Load the NUnit empty-assembly.dll once for this test + TestAdapterUtils.CreateDiscoverer().DiscoverTests( + new[] { EmptyAssemblyPath }, + context, + new MessageLoggerStub(), + this); } - [Category("TestDiscovery")] - public class EmptyAssemblyDiscoveryTests : ITestCaseDiscoverySink + #region ITestCaseDiscoverySink Methods + + void ITestCaseDiscoverySink.SendTestCase(TestCase discoveredTest) { - static readonly string EmptyAssemblyPath = - Path.Combine(TestContext.CurrentContext.TestDirectory, "empty-assembly.dll"); + } - [TestCaseSource(typeof(TestDiscoveryDataProvider), nameof(TestDiscoveryDataProvider.TestDiscoveryData))] - public void VerifyLoading(IDiscoveryContext context) - { - // Load the NUnit empty-assembly.dll once for this test - TestAdapterUtils.CreateDiscoverer().DiscoverTests( - new[] { EmptyAssemblyPath }, - context, - new MessageLoggerStub(), - this); - } + #endregion +} - #region ITestCaseDiscoverySink Methods +[Category("TestDiscovery")] +public class FailuresInDiscovery : ITestCaseDiscoverySink +{ + bool testcaseWasSent; - void ITestCaseDiscoverySink.SendTestCase(TestCase discoveredTest) - { - } - #endregion + [SetUp] + public void Setup() + { + testcaseWasSent = false; } - [Category("TestDiscovery")] - public class FailuresInDiscovery : ITestCaseDiscoverySink + [Test] + public void WhenAssemblyDontExist() { - bool testcaseWasSent; - - - [SetUp] - public void Setup() - { - testcaseWasSent = false; - } - - [Test] - public void WhenAssemblyDontExist() + int noOfMessagesFound = 3; // Start + end, + info + var context = new FakeDiscoveryContext(null); + var messageLoggerStub = new MessageLoggerStub(); + TestAdapterUtils.CreateDiscoverer().DiscoverTests( + new[] { "FileThatDoesntExist.dll" }, + context, + messageLoggerStub, + this); + Assert.Multiple(() => { - int noOfMessagesFound = 3; // Start + end, + info - var context = new FakeDiscoveryContext(null); - var messageLoggerStub = new MessageLoggerStub(); - TestAdapterUtils.CreateDiscoverer().DiscoverTests( - new[] { "FileThatDoesntExist.dll" }, - context, - messageLoggerStub, - this); - Assert.Multiple(() => - { - Assert.That(messageLoggerStub.Count, Is.EqualTo(noOfMessagesFound)); - Assert.That(messageLoggerStub.LatestTestMessageLevel, Is.EqualTo(TestMessageLevel.Informational)); - Assert.That(testcaseWasSent, Is.False); - Assert.That(!messageLoggerStub.ErrorMessages.Any()); - Assert.That(!messageLoggerStub.WarningMessages.Any()); - }); - } + Assert.That(messageLoggerStub.Count, Is.EqualTo(noOfMessagesFound)); + Assert.That(messageLoggerStub.LatestTestMessageLevel, Is.EqualTo(TestMessageLevel.Informational)); + Assert.That(testcaseWasSent, Is.False); + Assert.That(!messageLoggerStub.ErrorMessages.Any()); + Assert.That(!messageLoggerStub.WarningMessages.Any()); + }); + } #if NET462 - [Test] - public void WhenAssemblyIsNative() + [Test] + public void WhenAssemblyIsNative() + { + var context = new FakeDiscoveryContext(null); + var messageLoggerStub = new MessageLoggerStub(); + var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "NativeTests.dll"); + Assert.That(File.Exists(path)); + TestAdapterUtils.CreateDiscoverer().DiscoverTests( + new[] { path }, + context, + messageLoggerStub, + this); + Assert.Multiple(() => { - var context = new FakeDiscoveryContext(null); - var messageLoggerStub = new MessageLoggerStub(); - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "NativeTests.dll"); - Assert.That(File.Exists(path)); - TestAdapterUtils.CreateDiscoverer().DiscoverTests( - new[] { path }, - context, - messageLoggerStub, - this); - Assert.Multiple(() => - { - Assert.That(testcaseWasSent, Is.False); - Assert.That(messageLoggerStub.WarningMessages.Count(), Is.EqualTo(1)); - Assert.That(!messageLoggerStub.ErrorMessages.Any()); - string warningmsg = messageLoggerStub.WarningMessages.Select(o => o.Item2).FirstOrDefault(); - Assert.That(warningmsg, Is.Not.Null); - if (!string.IsNullOrEmpty(warningmsg)) - Assert.That(warningmsg, Does.Contain("Assembly not supported")); - }); - } + Assert.That(testcaseWasSent, Is.False); + Assert.That(messageLoggerStub.WarningMessages.Count(), Is.EqualTo(1)); + Assert.That(!messageLoggerStub.ErrorMessages.Any()); + string warningmsg = messageLoggerStub.WarningMessages.Select(o => o.Item2).FirstOrDefault(); + Assert.That(warningmsg, Is.Not.Null); + if (!string.IsNullOrEmpty(warningmsg)) + Assert.That(warningmsg, Does.Contain("Assembly not supported")); + }); + } #endif - public void SendTestCase(TestCase discoveredTest) - { - testcaseWasSent = true; - } + public void SendTestCase(TestCase discoveredTest) + { + testcaseWasSent = true; } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestExecutionTests.cs b/src/NUnitTestAdapterTests/TestExecutionTests.cs index 9a2fccc6..552eeea0 100644 --- a/src/NUnitTestAdapterTests/TestExecutionTests.cs +++ b/src/NUnitTestAdapterTests/TestExecutionTests.cs @@ -34,17 +34,17 @@ using NUnit.Tests.Assemblies; using NUnit.VisualStudio.TestAdapter.Tests.Fakes; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +/// +/// ResultSummary Helper Class. +/// +public class ResultSummary { - /// - /// ResultSummary Helper Class. - /// - public class ResultSummary - { - private readonly Dictionary summary; + private readonly Dictionary summary; - public ResultSummary(IEnumerable results) - { + public ResultSummary(IEnumerable results) + { summary = new Dictionary(); foreach (TestResult result in results) @@ -54,22 +54,22 @@ public ResultSummary(IEnumerable results) } } - private int GetCount(TestOutcome outcome) - { + private int GetCount(TestOutcome outcome) + { return summary.ContainsKey(outcome) ? summary[outcome] : 0; } - } +} - [Ignore("These tests needs to rewritten as isolated tests")] - [Category("TestExecution")] - public class TestFilteringTests +[Ignore("These tests needs to rewritten as isolated tests")] +[Category("TestExecution")] +public class TestFilteringTests +{ + private string mockAssemblyPath; + [OneTimeSetUp] + public void LoadMockassembly() { - private string mockAssemblyPath; - [OneTimeSetUp] - public void LoadMockassembly() - { mockAssemblyPath = Path.Combine(TestContext.CurrentContext.TestDirectory, "mock-assembly.dll"); // Sanity check to be sure we have the correct version of mock-assembly.dll @@ -77,24 +77,24 @@ public void LoadMockassembly() "The reference to mock-assembly.dll appears to be the wrong version"); } - [TestCase("", 38, 5, 5)] - [TestCase(null, 38, 5, 5)] - [TestCase("cat == Special", 1)] - [TestCase("cat == MockCategory", 2)] - [TestCase("method =~ MockTest?", 5, 1)] - [TestCase("method =~ MockTest? and cat != MockCategory", 3, 1)] - [TestCase("namespace == ThisNamespaceDoesNotExist", 0)] - [TestCase("test==NUnit.Tests.Assemblies.MockTestFixture", MockTestFixture.Tests - MockTestFixture.Explicit, 1, 1, TestName = "{m}_MockTestFixture")] - [TestCase("test==NUnit.Tests.IgnoredFixture and method == Test2", 1, 1, TestName = "{m}_IgnoredFixture")] - [TestCase("class==NUnit.Tests.Assemblies.MockTestFixture", MockTestFixture.Tests - MockTestFixture.Explicit, 1, 1)] - [TestCase("name==MockTestFixture", MockTestFixture.Tests + NUnit.Tests.TestAssembly.MockTestFixture.Tests - MockTestFixture.Explicit, 1, 1)] - [TestCase("cat==FixtureCategory", MockTestFixture.Tests, 1, 2)] - [TestCase("cat!=Special", 38 - 1, 5, 4)] - [TestCase("class==NUnit.Tests.Assemblies.MockTestFixture", MockTestFixture.Tests - MockTestFixture.Explicit, MockTestFixture.Ignored, 1)] - [TestCase("class==NUnit.Tests.OneOfEach", 2, 1, 0)] - [TestCase("cat==OneOfEachCat", 3, 1, 1)] - public void TestsWhereShouldFilter(string filter, int expectedCount, int noOfSkipped = 0, int noOfNone = 0) - { + [TestCase("", 38, 5, 5)] + [TestCase(null, 38, 5, 5)] + [TestCase("cat == Special", 1)] + [TestCase("cat == MockCategory", 2)] + [TestCase("method =~ MockTest?", 5, 1)] + [TestCase("method =~ MockTest? and cat != MockCategory", 3, 1)] + [TestCase("namespace == ThisNamespaceDoesNotExist", 0)] + [TestCase("test==NUnit.Tests.Assemblies.MockTestFixture", MockTestFixture.Tests - MockTestFixture.Explicit, 1, 1, TestName = "{m}_MockTestFixture")] + [TestCase("test==NUnit.Tests.IgnoredFixture and method == Test2", 1, 1, TestName = "{m}_IgnoredFixture")] + [TestCase("class==NUnit.Tests.Assemblies.MockTestFixture", MockTestFixture.Tests - MockTestFixture.Explicit, 1, 1)] + [TestCase("name==MockTestFixture", MockTestFixture.Tests + NUnit.Tests.TestAssembly.MockTestFixture.Tests - MockTestFixture.Explicit, 1, 1)] + [TestCase("cat==FixtureCategory", MockTestFixture.Tests, 1, 2)] + [TestCase("cat!=Special", 38 - 1, 5, 4)] + [TestCase("class==NUnit.Tests.Assemblies.MockTestFixture", MockTestFixture.Tests - MockTestFixture.Explicit, MockTestFixture.Ignored, 1)] + [TestCase("class==NUnit.Tests.OneOfEach", 2, 1, 0)] + [TestCase("cat==OneOfEachCat", 3, 1, 1)] + public void TestsWhereShouldFilter(string filter, int expectedCount, int noOfSkipped = 0, int noOfNone = 0) + { // Create a fake environment. var context = new FakeRunContext(new FakeRunSettingsForWhere(filter)); var fakeFramework = new FakeFrameworkHandle(); @@ -116,22 +116,22 @@ public void TestsWhereShouldFilter(string filter, int expectedCount, int noOfSki Assert.That(completedRuns.Count(o => o.TestOutcome == TestOutcome.None), Is.EqualTo(noOfNone), "Explicit and inconclusive number wrong"); }); } - } +} - [Ignore("These tests needs to rewritten as isolated tests")] - [Category("TestExecution")] - public class TestExecutionTests - { - private string mockAssemblyPath; - static readonly IRunContext Context = new FakeRunContext(); +[Ignore("These tests needs to rewritten as isolated tests")] +[Category("TestExecution")] +public class TestExecutionTests +{ + private string mockAssemblyPath; + static readonly IRunContext Context = new FakeRunContext(); - private FakeFrameworkHandle testLog; - ResultSummary Summary { get; set; } + private FakeFrameworkHandle testLog; + ResultSummary Summary { get; set; } - [OneTimeSetUp] - public void LoadMockassembly() - { + [OneTimeSetUp] + public void LoadMockassembly() + { mockAssemblyPath = Path.Combine(TestContext.CurrentContext.TestDirectory, "mock-assembly.dll"); // Sanity check to be sure we have the correct version of mock-assembly.dll @@ -150,9 +150,9 @@ public void LoadMockassembly() this.Summary = new ResultSummary(testResults); } - [Test] - public void DumpEvents() - { + [Test] + public void DumpEvents() + { foreach (var ev in testLog.Events) { TestContext.Write(ev.EventType + ": "); @@ -167,9 +167,9 @@ public void DumpEvents() } } - [Test] - public void CorrectNumberOfTestCasesWereStarted() - { + [Test] + public void CorrectNumberOfTestCasesWereStarted() + { const FakeFrameworkHandle.EventType eventType = FakeFrameworkHandle.EventType.RecordStart; Console.WriteLine(" "); foreach (var ev in testLog.Events.FindAll(e => e.EventType == eventType)) @@ -179,25 +179,25 @@ public void CorrectNumberOfTestCasesWereStarted() Is.EqualTo(MockAssembly.ResultCount - BadFixture.Tests - IgnoredFixture.Tests - ExplicitFixture.Tests - MockTestFixture.Explicit - OneOfEach.ExplicitTests)); } - [Test] - public void CorrectNumberOfTestCasesWereEnded() - { + [Test] + public void CorrectNumberOfTestCasesWereEnded() + { const FakeFrameworkHandle.EventType eventType = FakeFrameworkHandle.EventType.RecordEnd; Assert.That( testLog.Events.FindAll(e => e.EventType == eventType).Count, Is.EqualTo(MockAssembly.ResultCount)); } - [Test] - public void CorrectNumberOfResultsWereReceived() - { + [Test] + public void CorrectNumberOfResultsWereReceived() + { const FakeFrameworkHandle.EventType eventType = FakeFrameworkHandle.EventType.RecordResult; Assert.That( testLog.Events.FindAll(e => e.EventType == eventType).Count, Is.EqualTo(MockAssembly.ResultCount)); } - static readonly TestCaseData[] Outcomes = + static readonly TestCaseData[] Outcomes = { // NOTE: One inconclusive test is reported as None new TestCaseData(TestOutcome.Passed).Returns(MockAssembly.Success), @@ -207,26 +207,26 @@ public void CorrectNumberOfResultsWereReceived() new TestCaseData(TestOutcome.NotFound).Returns(0) }; - [TestCaseSource(nameof(Outcomes))] - public int TestOutcomeTotalsAreCorrect(TestOutcome outcome) - { + [TestCaseSource(nameof(Outcomes))] + public int TestOutcomeTotalsAreCorrect(TestOutcome outcome) + { TestContext.WriteLine(" "); TestContext.WriteLine($"Looking for outcome: {outcome}"); return testLog.Events .Count(e => e.EventType == FakeFrameworkHandle.EventType.RecordResult && e.TestResult.Outcome == outcome); } - [TestCase("MockTest3", TestOutcome.Passed, null, false)] - [TestCase("FailingTest", TestOutcome.Failed, "Intentional failure", true)] - [TestCase("TestWithException", TestOutcome.Failed, "System.Exception : Intentional Exception", true)] - // NOTE: Should Inconclusive be reported as TestOutcome.None? - [TestCase("ExplicitlyRunTest", TestOutcome.None, null, false)] - [TestCase("InconclusiveTest", TestOutcome.None, "No valid data", false)] - [TestCase("MockTest4", TestOutcome.Skipped, "ignoring this test method for now", false)] - // NOTE: Should this be failed? - [TestCase("NotRunnableTest", TestOutcome.Failed, "No arguments were provided", false)] - public void TestResultIsReportedCorrectly(string name, TestOutcome outcome, string message, bool hasStackTrace) - { + [TestCase("MockTest3", TestOutcome.Passed, null, false)] + [TestCase("FailingTest", TestOutcome.Failed, "Intentional failure", true)] + [TestCase("TestWithException", TestOutcome.Failed, "System.Exception : Intentional Exception", true)] + // NOTE: Should Inconclusive be reported as TestOutcome.None? + [TestCase("ExplicitlyRunTest", TestOutcome.None, null, false)] + [TestCase("InconclusiveTest", TestOutcome.None, "No valid data", false)] + [TestCase("MockTest4", TestOutcome.Skipped, "ignoring this test method for now", false)] + // NOTE: Should this be failed? + [TestCase("NotRunnableTest", TestOutcome.Failed, "No arguments were provided", false)] + public void TestResultIsReportedCorrectly(string name, TestOutcome outcome, string message, bool hasStackTrace) + { var testResult = GetTestResult(name); Assert.That(testResult, Is.Not.Null, "Unable to find result for method: " + name); @@ -236,9 +236,9 @@ public void TestResultIsReportedCorrectly(string name, TestOutcome outcome, stri Assert.That(testResult.ErrorStackTrace, Is.Not.Null, "Unable to find error stacktrace"); } - [Test] - public void AttachmentsShowSupportMultipleFiles() - { + [Test] + public void AttachmentsShowSupportMultipleFiles() + { var test = GetTestResult(nameof(FixtureWithAttachment.AttachmentTest)); Assert.That(test, Is.Not.Null, "Could not find test result"); @@ -253,9 +253,9 @@ public void AttachmentsShowSupportMultipleFiles() } #if NET462 - [Test] - public void NativeAssemblyProducesWarning() - { + [Test] + public void NativeAssemblyProducesWarning() + { // Create a fake environment. var context = new FakeRunContext(); var fakeFramework = new FakeFrameworkHandle(); @@ -288,8 +288,8 @@ public void NativeAssemblyProducesWarning() } #endif - private static void VerifyAttachment(UriDataAttachment attachment, string expectedName, string expectedDescription) - { + private static void VerifyAttachment(UriDataAttachment attachment, string expectedName, string expectedDescription) + { Assert.Multiple(() => { Assert.That(attachment.Uri.OriginalString, Does.EndWith(expectedName)); @@ -297,33 +297,33 @@ private static void VerifyAttachment(UriDataAttachment attachment, string expect }); } - /// - /// Tries to get the with the specified DisplayName. - /// - /// DisplayName to search for. - /// The first testresult with the specified DisplayName, or null if none where found. - private TestResult GetTestResult(string displayName) - { + /// + /// Tries to get the with the specified DisplayName. + /// + /// DisplayName to search for. + /// The first testresult with the specified DisplayName, or null if none where found. + private TestResult GetTestResult(string displayName) + { return testLog.Events .Where(e => e.EventType == FakeFrameworkHandle.EventType.RecordResult && e.TestResult.TestCase.DisplayName == displayName) .Select(e => e.TestResult) .FirstOrDefault(); } - } +} - [Category("TestExecution")] - public class TestExecutionTestsForTestOutput - { - private string _mockAssemblyPath; - private string _mockAssemblyFolder; +[Category("TestExecution")] +public class TestExecutionTestsForTestOutput +{ + private string _mockAssemblyPath; + private string _mockAssemblyFolder; - private FakeFrameworkHandle testLog; - ResultSummary Summary { get; set; } + private FakeFrameworkHandle testLog; + ResultSummary Summary { get; set; } - [OneTimeSetUp] - public void LoadMockAssembly() - { + [OneTimeSetUp] + public void LoadMockAssembly() + { _mockAssemblyPath = Path.Combine(TestContext.CurrentContext.TestDirectory, "mock-assembly.dll"); _mockAssemblyFolder = Path.GetDirectoryName(_mockAssemblyPath); // Sanity check to be sure we have the correct version of mock-assembly.dll @@ -341,9 +341,9 @@ public void LoadMockAssembly() Summary = new ResultSummary(testResults); } #if NET462 - [Test] - public void ThatTestOutputXmlHasBeenCreatedBelowAssemblyFolder() - { + [Test] + public void ThatTestOutputXmlHasBeenCreatedBelowAssemblyFolder() + { var context = new FakeRunContext(new FakeRunSettingsForTestOutput()); TestAdapterUtils.CreateExecutor().RunTests(new[] { _mockAssemblyPath }, context, testLog); @@ -355,9 +355,9 @@ public void ThatTestOutputXmlHasBeenCreatedBelowAssemblyFolder() } - [Test] - public void ThatTestOutputXmlHasBeenAtWorkDirLocation() - { + [Test] + public void ThatTestOutputXmlHasBeenAtWorkDirLocation() + { var temp = Path.GetTempPath(); var context = new FakeRunContext(new FakeRunSettingsForTestOutputAndWorkDir("TestResult", Path.Combine(temp, "NUnit"))); @@ -370,5 +370,4 @@ public void ThatTestOutputXmlHasBeenAtWorkDirLocation() } #endif - } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestFilterConverterTests/TestFilterCombinerTests.cs b/src/NUnitTestAdapterTests/TestFilterConverterTests/TestFilterCombinerTests.cs index b9da0856..64f4d023 100644 --- a/src/NUnitTestAdapterTests/TestFilterConverterTests/TestFilterCombinerTests.cs +++ b/src/NUnitTestAdapterTests/TestFilterConverterTests/TestFilterCombinerTests.cs @@ -1,34 +1,33 @@ using NUnit.Engine; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests.TestFilterConverterTests +namespace NUnit.VisualStudio.TestAdapter.Tests.TestFilterConverterTests; + +public class TestFilterCombinerTests { - public class TestFilterCombinerTests + [Test] + public void TestCombiningCategories() { - [Test] - public void TestCombiningCategories() - { - var builder = new TestFilterBuilder(); - builder.SelectWhere("cat==FOO"); + var builder = new TestFilterBuilder(); + builder.SelectWhere("cat==FOO"); - var t1 = builder.GetFilter(); - builder = new TestFilterBuilder(); - builder.SelectWhere("cat!=BOO"); - var t2 = builder.GetFilter(); - var combiner = new TestFilterCombiner(t1, t2); - var tRes = combiner.GetFilter(); - Assert.Multiple(() => - { - Assert.That(t1.Text, Does.StartWith("")); - Assert.That(t1.Text, Is.EqualTo("FOO")); - Assert.That(t2.Text, Does.StartWith("")); - Assert.That(t2.Text, Is.EqualTo("BOO")); - Assert.That(tRes.Text, Does.StartWith("")); - Assert.That(tRes.Text, Does.Not.StartWith("")); - Assert.That(tRes.Text, Is.EqualTo("FOOBOO")); - }); - TestContext.Out.WriteLine(" "); - TestContext.Out.WriteLine(tRes.Text); - } + var t1 = builder.GetFilter(); + builder = new TestFilterBuilder(); + builder.SelectWhere("cat!=BOO"); + var t2 = builder.GetFilter(); + var combiner = new TestFilterCombiner(t1, t2); + var tRes = combiner.GetFilter(); + Assert.Multiple(() => + { + Assert.That(t1.Text, Does.StartWith("")); + Assert.That(t1.Text, Is.EqualTo("FOO")); + Assert.That(t2.Text, Does.StartWith("")); + Assert.That(t2.Text, Is.EqualTo("BOO")); + Assert.That(tRes.Text, Does.StartWith("")); + Assert.That(tRes.Text, Does.Not.StartWith("")); + Assert.That(tRes.Text, Is.EqualTo("FOOBOO")); + }); + TestContext.Out.WriteLine(" "); + TestContext.Out.WriteLine(tRes.Text); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestFilterConverterTests/TestFilterParserTests.cs b/src/NUnitTestAdapterTests/TestFilterConverterTests/TestFilterParserTests.cs index b00d16dd..dd0faa20 100644 --- a/src/NUnitTestAdapterTests/TestFilterConverterTests/TestFilterParserTests.cs +++ b/src/NUnitTestAdapterTests/TestFilterConverterTests/TestFilterParserTests.cs @@ -26,164 +26,163 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.TestFilterConverter; -namespace NUnit.VisualStudio.TestAdapter.Tests.TestFilterConverterTests +namespace NUnit.VisualStudio.TestAdapter.Tests.TestFilterConverterTests; + +public class TestFilterParserTests { - public class TestFilterParserTests + private TestFilterParser _parser; + + [SetUp] + public void CreateParser() + { + _parser = new TestFilterParser(); + } + + // Default + [TestCase( + "Method", + "Method")] + + // Test Category + [TestCase("TestCategory=Urgent", "Urgent")] + [TestCase("TestCategory!=Urgent", "Urgent")] + [TestCase("TestCategory ~ Urgent", "Urgent")] + [TestCase("TestCategory !~ Urgent", "Urgent")] + + // Priority + [TestCase("Priority = High", "High")] + [TestCase("Priority != Urgent", "Urgent")] + [TestCase("Priority ~ Normal", "Normal")] + [TestCase("Priority !~ Low", "Low")] + + // Name + [TestCase("Name=SomeTest", "SomeTest")] + [TestCase("Name!=SomeTest", "SomeTest")] + [TestCase("Name~SomeTest", "SomeTest")] + [TestCase("Name!~SomeTest", "SomeTest")] + + // FQN - No arguments + [TestCase( + "FullyQualifiedName=My.Test.Fixture.Method", + "My.Test.Fixture.Method")] + [TestCase( + "FullyQualifiedName!=My.Test.Fixture.Method", + "My.Test.Fixture.Method")] + [TestCase( + "FullyQualifiedName~My.Test.Fixture.Method", + @"My\.Test\.Fixture\.Method")] + [TestCase( + "FullyQualifiedName!~My.Test.Fixture.Method", + @"My\.Test\.Fixture\.Method")] + + // FQN - Method arguments + [TestCase( + "FullyQualifiedName=My.Test.Fixture.Method(42)", + "My.Test.Fixture.Method(42)")] + [TestCase( + "FullyQualifiedName!=My.Test.Fixture.Method(42)", + "My.Test.Fixture.Method(42)")] + [TestCase( + "FullyQualifiedName~My.Test.Fixture.Method(42)", + @"My\.Test\.Fixture\.Method\(42\)")] + [TestCase( + "FullyQualifiedName!~My.Test.Fixture.Method(42)", + @"My\.Test\.Fixture\.Method\(42\)")] + + // FQN - String argument escaping + [TestCase( + "FullyQualifiedName=My.Test.Fixture.Method(\"xyz\")", + "My.Test.Fixture.Method("xyz")")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture.Method(\"abc's\")", + "My.Test.Fixture.Method("abc's")")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture.Method(\"x&y&z\")", + "My.Test.Fixture.Method("x&y&z")")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture.Method(\"\")", + "My.Test.Fixture.Method("<xyz>")")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture.Method(\"x(y(z\")", + "My.Test.Fixture.Method("x(y(z")")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture.Method(\"x)y)z\")", + "My.Test.Fixture.Method("x)y)z")")] + [TestCase( + "FullyQualifiedName~My.Test.Fixture.Method(\"xyz\")", + @"My\.Test\.Fixture\.Method\("xyz"\)")] + [TestCase( + "FullyQualifiedName~My.Test.Fixture.Method(\"abc's\")", + @"My\.Test\.Fixture\.Method\("abc's"\)")] + [TestCase( + "FullyQualifiedName~My.Test.Fixture.Method(\"x&y&z\")", + @"My\.Test\.Fixture\.Method\("x&y&z"\)")] + [TestCase( + "FullyQualifiedName~My.Test.Fixture.Method(\"\")", + @"My\.Test\.Fixture\.Method\("<xyz>"\)")] + + // FQN - Fixture Arguments + [TestCase( + "FullyQualifiedName=My.Test.Fixture(99).Method", + "My.Test.Fixture(99).Method")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture(99).Method(42)", + "My.Test.Fixture(99).Method(42)")] + + // FQN - Nested Fixture + [TestCase( + "FullyQualifiedName=My.Test.Fixture+NestedFixture.Method", + "My.Test.Fixture+NestedFixture.Method")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture+NestedFixture.Method(1,2,3)", + "My.Test.Fixture+NestedFixture.Method(1,2,3)")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture(1,2,3)+NestedFixture.Method(\"fred\")", + "My.Test.Fixture(1,2,3)+NestedFixture.Method("fred")")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture+NestedFixture(1,2,3).Method(4,5,6)", + "My.Test.Fixture+NestedFixture(1,2,3).Method(4,5,6)")] + [TestCase( + "FullyQualifiedName=My.Test.Fixture(1,2,3)+NestedFixture(4,5,6).Method(7,8,9)", + "My.Test.Fixture(1,2,3)+NestedFixture(4,5,6).Method(7,8,9)")] + + // Logical expressions + [TestCase( + "TestCategory = Urgent | TestCategory = High", + "UrgentHigh")] + [TestCase( + "TestCategory=Urgent & FullyQualifiedName=My.Tests", + "UrgentMy.Tests")] + [TestCase( + "TestCategory=Urgent | FullyQualifiedName=My.Tests", + "UrgentMy.Tests")] + [TestCase( + "TestCategory=Urgent | FullyQualifiedName=My.Tests & TestCategory = high", + "UrgentMy.Testshigh")] + [TestCase( + "TestCategory=Urgent & FullyQualifiedName=My.Tests | TestCategory = high", + "UrgentMy.Testshigh")] + [TestCase( + "TestCategory=Urgent & (FullyQualifiedName=My.Tests | TestCategory = high)", + "UrgentMy.Testshigh")] + [TestCase( + "TestCategory=Urgent & !(FullyQualifiedName=My.Tests | TestCategory = high)", + "UrgentMy.Testshigh")] + [TestCase("Bug = 12345", "12345")] + public void TestParser(string input, string output) + { + Assert.That(_parser.Parse(input), Is.EqualTo($"{output}")); + + XmlDocument doc = new (); + Assert.DoesNotThrow(() => doc.LoadXml(output)); + } + + [TestCase(null, typeof(ArgumentNullException))] + [TestCase("", typeof(TestFilterParserException))] + [TestCase(" ", typeof(TestFilterParserException))] + [TestCase(" \t\t ", typeof(TestFilterParserException))] + public void TestParser_InvalidInput(string input, Type type) { - private TestFilterParser _parser; - - [SetUp] - public void CreateParser() - { - _parser = new TestFilterParser(); - } - - // Default - [TestCase( - "Method", - "Method")] - - // Test Category - [TestCase("TestCategory=Urgent", "Urgent")] - [TestCase("TestCategory!=Urgent", "Urgent")] - [TestCase("TestCategory ~ Urgent", "Urgent")] - [TestCase("TestCategory !~ Urgent", "Urgent")] - - // Priority - [TestCase("Priority = High", "High")] - [TestCase("Priority != Urgent", "Urgent")] - [TestCase("Priority ~ Normal", "Normal")] - [TestCase("Priority !~ Low", "Low")] - - // Name - [TestCase("Name=SomeTest", "SomeTest")] - [TestCase("Name!=SomeTest", "SomeTest")] - [TestCase("Name~SomeTest", "SomeTest")] - [TestCase("Name!~SomeTest", "SomeTest")] - - // FQN - No arguments - [TestCase( - "FullyQualifiedName=My.Test.Fixture.Method", - "My.Test.Fixture.Method")] - [TestCase( - "FullyQualifiedName!=My.Test.Fixture.Method", - "My.Test.Fixture.Method")] - [TestCase( - "FullyQualifiedName~My.Test.Fixture.Method", - @"My\.Test\.Fixture\.Method")] - [TestCase( - "FullyQualifiedName!~My.Test.Fixture.Method", - @"My\.Test\.Fixture\.Method")] - - // FQN - Method arguments - [TestCase( - "FullyQualifiedName=My.Test.Fixture.Method(42)", - "My.Test.Fixture.Method(42)")] - [TestCase( - "FullyQualifiedName!=My.Test.Fixture.Method(42)", - "My.Test.Fixture.Method(42)")] - [TestCase( - "FullyQualifiedName~My.Test.Fixture.Method(42)", - @"My\.Test\.Fixture\.Method\(42\)")] - [TestCase( - "FullyQualifiedName!~My.Test.Fixture.Method(42)", - @"My\.Test\.Fixture\.Method\(42\)")] - - // FQN - String argument escaping - [TestCase( - "FullyQualifiedName=My.Test.Fixture.Method(\"xyz\")", - "My.Test.Fixture.Method("xyz")")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture.Method(\"abc's\")", - "My.Test.Fixture.Method("abc's")")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture.Method(\"x&y&z\")", - "My.Test.Fixture.Method("x&y&z")")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture.Method(\"\")", - "My.Test.Fixture.Method("<xyz>")")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture.Method(\"x(y(z\")", - "My.Test.Fixture.Method("x(y(z")")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture.Method(\"x)y)z\")", - "My.Test.Fixture.Method("x)y)z")")] - [TestCase( - "FullyQualifiedName~My.Test.Fixture.Method(\"xyz\")", - @"My\.Test\.Fixture\.Method\("xyz"\)")] - [TestCase( - "FullyQualifiedName~My.Test.Fixture.Method(\"abc's\")", - @"My\.Test\.Fixture\.Method\("abc's"\)")] - [TestCase( - "FullyQualifiedName~My.Test.Fixture.Method(\"x&y&z\")", - @"My\.Test\.Fixture\.Method\("x&y&z"\)")] - [TestCase( - "FullyQualifiedName~My.Test.Fixture.Method(\"\")", - @"My\.Test\.Fixture\.Method\("<xyz>"\)")] - - // FQN - Fixture Arguments - [TestCase( - "FullyQualifiedName=My.Test.Fixture(99).Method", - "My.Test.Fixture(99).Method")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture(99).Method(42)", - "My.Test.Fixture(99).Method(42)")] - - // FQN - Nested Fixture - [TestCase( - "FullyQualifiedName=My.Test.Fixture+NestedFixture.Method", - "My.Test.Fixture+NestedFixture.Method")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture+NestedFixture.Method(1,2,3)", - "My.Test.Fixture+NestedFixture.Method(1,2,3)")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture(1,2,3)+NestedFixture.Method(\"fred\")", - "My.Test.Fixture(1,2,3)+NestedFixture.Method("fred")")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture+NestedFixture(1,2,3).Method(4,5,6)", - "My.Test.Fixture+NestedFixture(1,2,3).Method(4,5,6)")] - [TestCase( - "FullyQualifiedName=My.Test.Fixture(1,2,3)+NestedFixture(4,5,6).Method(7,8,9)", - "My.Test.Fixture(1,2,3)+NestedFixture(4,5,6).Method(7,8,9)")] - - // Logical expressions - [TestCase( - "TestCategory = Urgent | TestCategory = High", - "UrgentHigh")] - [TestCase( - "TestCategory=Urgent & FullyQualifiedName=My.Tests", - "UrgentMy.Tests")] - [TestCase( - "TestCategory=Urgent | FullyQualifiedName=My.Tests", - "UrgentMy.Tests")] - [TestCase( - "TestCategory=Urgent | FullyQualifiedName=My.Tests & TestCategory = high", - "UrgentMy.Testshigh")] - [TestCase( - "TestCategory=Urgent & FullyQualifiedName=My.Tests | TestCategory = high", - "UrgentMy.Testshigh")] - [TestCase( - "TestCategory=Urgent & (FullyQualifiedName=My.Tests | TestCategory = high)", - "UrgentMy.Testshigh")] - [TestCase( - "TestCategory=Urgent & !(FullyQualifiedName=My.Tests | TestCategory = high)", - "UrgentMy.Testshigh")] - [TestCase("Bug = 12345", "12345")] - public void TestParser(string input, string output) - { - Assert.That(_parser.Parse(input), Is.EqualTo($"{output}")); - - XmlDocument doc = new (); - Assert.DoesNotThrow(() => doc.LoadXml(output)); - } - - [TestCase(null, typeof(ArgumentNullException))] - [TestCase("", typeof(TestFilterParserException))] - [TestCase(" ", typeof(TestFilterParserException))] - [TestCase(" \t\t ", typeof(TestFilterParserException))] - public void TestParser_InvalidInput(string input, Type type) - { - Assert.That(() => _parser.Parse(input), Throws.TypeOf(type)); - } + Assert.That(() => _parser.Parse(input), Throws.TypeOf(type)); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TestFilterConverterTests/TokenizerTests.cs b/src/NUnitTestAdapterTests/TestFilterConverterTests/TokenizerTests.cs index 99da2001..c6091741 100644 --- a/src/NUnitTestAdapterTests/TestFilterConverterTests/TokenizerTests.cs +++ b/src/NUnitTestAdapterTests/TestFilterConverterTests/TokenizerTests.cs @@ -24,45 +24,45 @@ using NUnit.Framework; using NUnit.VisualStudio.TestAdapter.TestFilterConverter; -namespace NUnit.VisualStudio.TestAdapter.Tests.TestFilterConverterTests +namespace NUnit.VisualStudio.TestAdapter.Tests.TestFilterConverterTests; + +public class TokenizerTests { - public class TokenizerTests + [Test] + public void NullInputThrowsException() { - [Test] - public void NullInputThrowsException() - { - Assert.That(() => new Tokenizer(null), Throws.ArgumentNullException); - } + Assert.That(() => new Tokenizer(null), Throws.ArgumentNullException); + } - [Test] - public void BlankStringReturnsEof() - { - var tokenizer = new Tokenizer(" "); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof)), "First Call"); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof)), "Second Call"); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof)), "Third Call"); - } + [Test] + public void BlankStringReturnsEof() + { + var tokenizer = new Tokenizer(" "); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof)), "First Call"); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof)), "Second Call"); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof)), "Third Call"); + } - [Test] - public void IdentifierTokens() - { - var tokenizer = new Tokenizer(" Identifiers x abc123 a1x "); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "Identifiers"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "x"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "abc123"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "a1x"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); - } + [Test] + public void IdentifierTokens() + { + var tokenizer = new Tokenizer(" Identifiers x abc123 a1x "); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "Identifiers"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "x"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "abc123"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "a1x"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); + } - [Test] - public void WordsInUnicode() - { - var tokenizer = new Tokenizer("method = Здравствуйте"); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "method"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "Здравствуйте"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); - } + [Test] + public void WordsInUnicode() + { + var tokenizer = new Tokenizer("method = Здравствуйте"); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "method"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "Здравствуйте"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); + } #if UNUSED [Test] @@ -106,56 +106,55 @@ public void StringsMayContainEscapedQuoteChar() } #endif - [Test] - public void SymbolTokens_SingleChar() - { - var tokenizer = new Tokenizer("=!&|()"); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "!"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "&"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "|"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "("))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, ")"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); - } + [Test] + public void SymbolTokens_SingleChar() + { + var tokenizer = new Tokenizer("=!&|()"); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "!"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "&"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "|"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "("))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, ")"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); + } - [Test] - public void SymbolTokens_DoubleChar() - { - var tokenizer = new Tokenizer("!=!~"); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "!="))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "!~"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); - } + [Test] + public void SymbolTokens_DoubleChar() + { + var tokenizer = new Tokenizer("!=!~"); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "!="))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "!~"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); + } - [Test] - public void MixedTokens_Simple() - { - var tokenizer = new Tokenizer("id=123"); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "id"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "123"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); - } + [Test] + public void MixedTokens_Simple() + { + var tokenizer = new Tokenizer("id=123"); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "id"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "123"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); + } - [Test] - public void MixedTokens_Complex() - { - var tokenizer = new Tokenizer("name ~ DataBase & (category = Urgent | Priority = High)"); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "name"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "~"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "DataBase"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "&"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "("))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "category"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "Urgent"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "|"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "Priority"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "High"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, ")"))); - Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); - } + [Test] + public void MixedTokens_Complex() + { + var tokenizer = new Tokenizer("name ~ DataBase & (category = Urgent | Priority = High)"); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "name"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "~"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "DataBase"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "&"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "("))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "category"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "Urgent"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "|"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "Priority"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, "="))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Word, "High"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Symbol, ")"))); + Assert.That(tokenizer.NextToken(), Is.EqualTo(new Token(TokenKind.Eof))); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TraitsTests.cs b/src/NUnitTestAdapterTests/TraitsTests.cs index 23fe1116..63ea129c 100644 --- a/src/NUnitTestAdapterTests/TraitsTests.cs +++ b/src/NUnitTestAdapterTests/TraitsTests.cs @@ -9,13 +9,13 @@ using NUnit.VisualStudio.TestAdapter.Tests.Fakes; // ReSharper disable StringLiteralTypo -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +public class TestDataForTraits { - public class TestDataForTraits - { - #region TestXml Data - const string TestXml = - @" "; - /// - /// [Category("BaseClass")] - /// public class Class1 - /// { - /// [Category("Base")] - /// [Test] - /// public void nUnitTest() - /// { - /// - /// } - /// } - /// - /// [Category("DerivedClass")] - /// public class ClassD : Class1 - /// { - /// [Category("Derived")] - /// [Test] - /// public void dNUnitTest() - /// { } - /// }. - /// - const string XmlHierarchyOfClasses = @" + /// + /// [Category("BaseClass")] + /// public class Class1 + /// { + /// [Category("Base")] + /// [Test] + /// public void nUnitTest() + /// { + /// + /// } + /// } + /// + /// [Category("DerivedClass")] + /// public class ClassD : Class1 + /// { + /// [Category("Derived")] + /// [Test] + /// public void dNUnitTest() + /// { } + /// }. + /// + const string XmlHierarchyOfClasses = @" @@ -94,28 +94,28 @@ public class TestDataForTraits "; - /// - /// [Category("NS1")] - /// public class NestedClasses - /// { - /// [Category("NS11")] - /// [Test] - /// public void NC11() - /// { - /// } - /// - /// [Category("NS2")] - /// public class NestedClass2 - /// { - /// [Category("NS21")] - /// [Test] - /// public void NC21() - /// { - /// } - /// } - /// }. - /// - const string XmlNestedClasses = @" + /// + /// [Category("NS1")] + /// public class NestedClasses + /// { + /// [Category("NS11")] + /// [Test] + /// public void NC11() + /// { + /// } + /// + /// [Category("NS2")] + /// public class NestedClass2 + /// { + /// [Category("NS21")] + /// [Test] + /// public void NC21() + /// { + /// } + /// } + /// }. + /// + const string XmlNestedClasses = @" @@ -146,21 +146,21 @@ public class TestDataForTraits "; - /// - /// [Category("ClassLevel")] - /// public class ManyTests - /// { - /// [TestCase(1), Category("TestCase level")] - /// [TestCase(2)] - /// [Category("MethodLevel")] - /// public void ThatWeExist(int n) - /// { - /// Assert.IsTrue(true); - /// } - /// }. - /// - const string TestXmlParameterizedData = - @" + /// + /// [Category("ClassLevel")] + /// public class ManyTests + /// { + /// [TestCase(1), Category("TestCase level")] + /// [TestCase(2)] + /// [Category("MethodLevel")] + /// public void ThatWeExist(int n) + /// { + /// Assert.IsTrue(true); + /// } + /// }. + /// + const string TestXmlParameterizedData = + @" @@ -182,20 +182,20 @@ public class TestDataForTraits "; - /// - /// [Category("ClassLevel")] - /// public class StandardClass - /// { - /// [Category("MethodLevel")] - /// [Test] - /// public void ThatWeExist() - /// { - /// Assert.IsTrue(true); - /// } - /// }. - /// - private const string TestXmlStandardClass = - @" + /// + /// [Category("ClassLevel")] + /// public class StandardClass + /// { + /// [Category("MethodLevel")] + /// [Test] + /// public void ThatWeExist() + /// { + /// Assert.IsTrue(true); + /// } + /// }. + /// + private const string TestXmlStandardClass = + @" @@ -218,19 +218,19 @@ public class TestDataForTraits - /// - /// [TestCase(1, 2, ExpectedResult = 3, Category="Single")] - /// [TestCase(4, 5, ExpectedResult = 9)] - /// [TestCase(27, 30, ExpectedResult = 57)] - /// public int SumTests(int a, int b) - /// { - /// var sut = new Calculator(); - /// - /// return sut.Sum(a, b); - /// }. - /// - private const string TestCaseWithCategory = - @" + /// + /// [TestCase(1, 2, ExpectedResult = 3, Category="Single")] + /// [TestCase(4, 5, ExpectedResult = 9)] + /// [TestCase(27, 30, ExpectedResult = 57)] + /// public int SumTests(int a, int b) + /// { + /// var sut = new Calculator(); + /// + /// return sut.Sum(a, b); + /// }. + /// + private const string TestCaseWithCategory = + @" @@ -250,28 +250,28 @@ public class TestDataForTraits "; - // [Category("BaseClass")] - // public class TestBase - // { - // [Category("BaseMethod")] - // [Test] - // public void TestItBase() - // { - // Assert.That(true); - // } - // } - // [Category("DerivedClass")] - // public class Derived : TestBase - // { - // [Category("DerivedMethod")] - // [Test] - // public void TestItDerived() - // { - // Assert.That(true); - // } - // } - private const string TestCaseWithInheritedTestsInSameAssembly = - @" + // [Category("BaseClass")] + // public class TestBase + // { + // [Category("BaseMethod")] + // [Test] + // public void TestItBase() + // { + // Assert.That(true); + // } + // } + // [Category("DerivedClass")] + // public class Derived : TestBase + // { + // [Category("DerivedMethod")] + // [Test] + // public void TestItDerived() + // { + // Assert.That(true); + // } + // } + private const string TestCaseWithInheritedTestsInSameAssembly = + @" @@ -306,28 +306,28 @@ public class TestDataForTraits "; - // [Category("BaseClass")] - // public abstract class TestBase - // { - // [Category("BaseMethod")] - // [Test] - // public void TestItBase() - // { - // Assert.That(true); - // } - // } - // [Category("DerivedClass")] - // public class Derived : TestBase - // { - // [Category("DerivedMethod")] - // [Test] - // public void TestItDerived() - // { - // Assert.That(true); - // } - // } - private const string TestCaseWithAbstractInheritedTestsInSameAssembly = - @" + // [Category("BaseClass")] + // public abstract class TestBase + // { + // [Category("BaseMethod")] + // [Test] + // public void TestItBase() + // { + // Assert.That(true); + // } + // } + // [Category("DerivedClass")] + // public class Derived : TestBase + // { + // [Category("DerivedMethod")] + // [Test] + // public void TestItDerived() + // { + // Assert.That(true); + // } + // } + private const string TestCaseWithAbstractInheritedTestsInSameAssembly = + @" @@ -353,242 +353,241 @@ public class TestDataForTraits "; - #endregion + #endregion - public XmlNode XmlForNestedClasses => XmlHelper.CreateXmlNode(XmlNestedClasses); - public XmlNode XmlForHierarchyOfClasses => XmlHelper.CreateXmlNode(XmlHierarchyOfClasses); - public XmlNode XmlForParameterizedTests => XmlHelper.CreateXmlNode(TestXmlParameterizedData); - public XmlNode XmlForStandardTest => XmlHelper.CreateXmlNode(TestXmlStandardClass); + public XmlNode XmlForNestedClasses => XmlHelper.CreateXmlNode(XmlNestedClasses); + public XmlNode XmlForHierarchyOfClasses => XmlHelper.CreateXmlNode(XmlHierarchyOfClasses); + public XmlNode XmlForParameterizedTests => XmlHelper.CreateXmlNode(TestXmlParameterizedData); + public XmlNode XmlForStandardTest => XmlHelper.CreateXmlNode(TestXmlStandardClass); - public XmlNode XmlForTestCaseWithCategory => XmlHelper.CreateXmlNode(TestCaseWithCategory); + public XmlNode XmlForTestCaseWithCategory => XmlHelper.CreateXmlNode(TestCaseWithCategory); - public XmlNode XmlForTestCaseWithInheritedTestsInSameAssembly => XmlHelper.CreateXmlNode(TestCaseWithInheritedTestsInSameAssembly); - public XmlNode XmlForTestCaseWithAbstractInheritedTestsInSameAssembly => XmlHelper.CreateXmlNode(TestCaseWithAbstractInheritedTestsInSameAssembly); - } + public XmlNode XmlForTestCaseWithInheritedTestsInSameAssembly => XmlHelper.CreateXmlNode(TestCaseWithInheritedTestsInSameAssembly); + public XmlNode XmlForTestCaseWithAbstractInheritedTestsInSameAssembly => XmlHelper.CreateXmlNode(TestCaseWithAbstractInheritedTestsInSameAssembly); +} - [Category(nameof(TestTraits))] - public class TestTraits - { - private TestConverterForXml testconverter; - private List testcaselist; - private TestDataForTraits testDataForTraits; +[Category(nameof(TestTraits))] +public class TestTraits +{ + private TestConverterForXml testconverter; + private List testcaselist; + private TestDataForTraits testDataForTraits; - [SetUp] - public void SetUp() - { - testDataForTraits = new TestDataForTraits(); - var messagelogger = Substitute.For(); - var adaptersettings = Substitute.For(); - adaptersettings.Verbosity.Returns(5); - var testlogger = new TestLogger(messagelogger); - testlogger.InitSettings(adaptersettings); - var settings = Substitute.For(); - settings.CollectSourceInformation.Returns(false); - testconverter = new TestConverterForXml(testlogger, "whatever", settings); - testcaselist = new List(); - } + [SetUp] + public void SetUp() + { + testDataForTraits = new TestDataForTraits(); + var messagelogger = Substitute.For(); + var adaptersettings = Substitute.For(); + adaptersettings.Verbosity.Returns(5); + var testlogger = new TestLogger(messagelogger); + testlogger.InitSettings(adaptersettings); + var settings = Substitute.For(); + settings.CollectSourceInformation.Returns(false); + testconverter = new TestConverterForXml(testlogger, "whatever", settings); + testcaselist = new List(); + } - [TearDown] - public void TearDown() - { - testconverter.Dispose(); - } + [TearDown] + public void TearDown() + { + testconverter.Dispose(); + } - [Test] - public void ThatParameterizedTestsHaveTraits() - { - var xml = testDataForTraits.XmlForParameterizedTests; + [Test] + public void ThatParameterizedTestsHaveTraits() + { + var xml = testDataForTraits.XmlForParameterizedTests; - ProcessXml2TestCase(xml); + ProcessXml2TestCase(xml); - Assert.That(testcaselist.Count, Is.EqualTo(2), "Wrong number of testcases found"); - var testcase1 = testcaselist.FirstOrDefault(o => o.DisplayName == "ThatWeExist(1)"); - Assert.That(testcase1, Is.Not.Null, "Didn't find the first testcase"); - Assert.That(testcase1.GetCategories().Count(), Is.EqualTo(3), "Wrong number of categories for first test case"); + Assert.That(testcaselist.Count, Is.EqualTo(2), "Wrong number of testcases found"); + var testcase1 = testcaselist.FirstOrDefault(o => o.DisplayName == "ThatWeExist(1)"); + Assert.That(testcase1, Is.Not.Null, "Didn't find the first testcase"); + Assert.That(testcase1.GetCategories().Count(), Is.EqualTo(3), "Wrong number of categories for first test case"); - var testcase2 = testcaselist.FirstOrDefault(o => o.DisplayName == "ThatWeExist(2)"); - Assert.That(testcase2, Is.Not.Null, "Didn't find the second testcase"); - Assert.That(testcase2.GetCategories().Count(), Is.EqualTo(3), "Wrong number of categories for second test case"); - } + var testcase2 = testcaselist.FirstOrDefault(o => o.DisplayName == "ThatWeExist(2)"); + Assert.That(testcase2, Is.Not.Null, "Didn't find the second testcase"); + Assert.That(testcase2.GetCategories().Count(), Is.EqualTo(3), "Wrong number of categories for second test case"); + } - [Test] - public void ThatDerivedClassesHaveTraits() - { - var xml = testDataForTraits.XmlForHierarchyOfClasses; + [Test] + public void ThatDerivedClassesHaveTraits() + { + var xml = testDataForTraits.XmlForHierarchyOfClasses; - ProcessXml2TestCase(xml); + ProcessXml2TestCase(xml); - Assert.That(testcaselist.Count, Is.EqualTo(3), "Wrong number of testcases found"); - var testcase1 = testcaselist.FirstOrDefault(o => o.DisplayName == "dNUnitTest"); - Assert.That(testcase1, Is.Not.Null, "Didn't find the testcase"); - VerifyCategoriesOnly(testcase1, 3, "derived"); - } + Assert.That(testcaselist.Count, Is.EqualTo(3), "Wrong number of testcases found"); + var testcase1 = testcaselist.FirstOrDefault(o => o.DisplayName == "dNUnitTest"); + Assert.That(testcase1, Is.Not.Null, "Didn't find the testcase"); + VerifyCategoriesOnly(testcase1, 3, "derived"); + } - [Test] - public void ThatNestedClassesHaveTraits() - { - var xml = testDataForTraits.XmlForNestedClasses; + [Test] + public void ThatNestedClassesHaveTraits() + { + var xml = testDataForTraits.XmlForNestedClasses; - ProcessXml2TestCase(xml); + ProcessXml2TestCase(xml); - Assert.That(testcaselist.Count, Is.EqualTo(2), "Wrong number of testcases found"); - var testcase1 = testcaselist.FirstOrDefault(o => o.DisplayName == "NC21"); - Assert.That(testcase1, Is.Not.Null, "Didn't find the testcase"); - VerifyCategoriesOnly(testcase1, 2, "nested"); - } + Assert.That(testcaselist.Count, Is.EqualTo(2), "Wrong number of testcases found"); + var testcase1 = testcaselist.FirstOrDefault(o => o.DisplayName == "NC21"); + Assert.That(testcase1, Is.Not.Null, "Didn't find the testcase"); + VerifyCategoriesOnly(testcase1, 2, "nested"); + } - [Test] - public void ThatInheritedConcreteClassesHaveTraits() - { - var xml = testDataForTraits.XmlForTestCaseWithInheritedTestsInSameAssembly; - ProcessXml2TestCase(xml); - Assert.That(testcaselist.Count, Is.EqualTo(3), "Wrong number of testcases found"); - var uniqueTraits = UniqueCategories(); - Assert.That(uniqueTraits.Count(), Is.EqualTo(4), "Wrong number of traits"); - string searchTrait = "BaseClass"; - var tcWithTrait = TcWithTrait(searchTrait); - Assert.That(tcWithTrait.Count(), Is.EqualTo(3), $"Wrong number of testcases found for trait={searchTrait}"); - } + [Test] + public void ThatInheritedConcreteClassesHaveTraits() + { + var xml = testDataForTraits.XmlForTestCaseWithInheritedTestsInSameAssembly; + ProcessXml2TestCase(xml); + Assert.That(testcaselist.Count, Is.EqualTo(3), "Wrong number of testcases found"); + var uniqueTraits = UniqueCategories(); + Assert.That(uniqueTraits.Count(), Is.EqualTo(4), "Wrong number of traits"); + string searchTrait = "BaseClass"; + var tcWithTrait = TcWithTrait(searchTrait); + Assert.That(tcWithTrait.Count(), Is.EqualTo(3), $"Wrong number of testcases found for trait={searchTrait}"); + } - private IEnumerable TcWithTrait(string searchTrait) - { - return testcaselist.Where(o => o.GetCategories().Contains(searchTrait)); - } + private IEnumerable TcWithTrait(string searchTrait) + { + return testcaselist.Where(o => o.GetCategories().Contains(searchTrait)); + } - private IEnumerable UniqueCategories() + private IEnumerable UniqueCategories() + { + var traits = new List(); + foreach (var tc in testcaselist) { - var traits = new List(); - foreach (var tc in testcaselist) - { - traits.AddRange(tc.GetCategories()); - } - var uniqueTraits = traits.Distinct(); - return uniqueTraits; + traits.AddRange(tc.GetCategories()); } + var uniqueTraits = traits.Distinct(); + return uniqueTraits; + } - [Test] - public void ThatInheritedAbstractClassesHaveTraits() - { - var xml = testDataForTraits.XmlForTestCaseWithAbstractInheritedTestsInSameAssembly; - ProcessXml2TestCase(xml); - Assert.That(testcaselist.Count, Is.EqualTo(2), "Wrong number of testcases found"); - var uniqueTraits = UniqueCategories(); - Assert.That(uniqueTraits.Count(), Is.EqualTo(4), "Wrong number of traits"); - string searchTrait = "BaseClass"; - var tcWithTrait = TcWithTrait(searchTrait); - Assert.That(tcWithTrait.Count(), Is.EqualTo(2), $"Wrong number of testcases found for trait={searchTrait}"); - } + [Test] + public void ThatInheritedAbstractClassesHaveTraits() + { + var xml = testDataForTraits.XmlForTestCaseWithAbstractInheritedTestsInSameAssembly; + ProcessXml2TestCase(xml); + Assert.That(testcaselist.Count, Is.EqualTo(2), "Wrong number of testcases found"); + var uniqueTraits = UniqueCategories(); + Assert.That(uniqueTraits.Count(), Is.EqualTo(4), "Wrong number of traits"); + string searchTrait = "BaseClass"; + var tcWithTrait = TcWithTrait(searchTrait); + Assert.That(tcWithTrait.Count(), Is.EqualTo(2), $"Wrong number of testcases found for trait={searchTrait}"); + } - private void ProcessXml2TestCase(XmlNode xml) + private void ProcessXml2TestCase(XmlNode xml) + { + foreach (XmlNode node in xml.SelectNodes("//test-case")) { - foreach (XmlNode node in xml.SelectNodes("//test-case")) - { - var testcase = testconverter.ConvertTestCase(new NUnitEventTestCase(node)); - testcaselist.Add(testcase); - } + var testcase = testconverter.ConvertTestCase(new NUnitEventTestCase(node)); + testcaselist.Add(testcase); } + } - [Test] - public void ThatStandardClassHasTraits() - { - var xml = testDataForTraits.XmlForStandardTest; + [Test] + public void ThatStandardClassHasTraits() + { + var xml = testDataForTraits.XmlForStandardTest; - ProcessXml2TestCase(xml); + ProcessXml2TestCase(xml); - Assert.That(testcaselist.Count, Is.EqualTo(1), "Wrong number of testcases found"); - var testcase1 = testcaselist.FirstOrDefault(o => o.DisplayName == "ThatWeExist"); - Assert.That(testcase1, Is.Not.Null, "Didn't find the testcase"); + Assert.That(testcaselist.Count, Is.EqualTo(1), "Wrong number of testcases found"); + var testcase1 = testcaselist.FirstOrDefault(o => o.DisplayName == "ThatWeExist"); + Assert.That(testcase1, Is.Not.Null, "Didn't find the testcase"); - VerifyCategoriesOnly(testcase1, 2, "first"); - } + VerifyCategoriesOnly(testcase1, 2, "first"); + } - [Test] - public void ThatTestCaseHasTraits() - { - var xml = testDataForTraits.XmlForTestCaseWithCategory; + [Test] + public void ThatTestCaseHasTraits() + { + var xml = testDataForTraits.XmlForTestCaseWithCategory; - ProcessXml2TestCase(xml); + ProcessXml2TestCase(xml); - Assert.That(testcaselist.Count, Is.EqualTo(3), "Wrong number of testcases found"); - var testcasesWithCategories = testcaselist.Where(o => o.GetCategories()?.FirstOrDefault() != null).ToList(); - Assert.That(testcasesWithCategories, Is.Not.Null, "Didn't find the testcases"); - Assert.That(testcasesWithCategories.Count, Is.EqualTo(1), "Wrong number of testcases with categories, should be only 1"); - var tc = testcasesWithCategories.FirstOrDefault(); - VerifyCategoriesOnly(tc, 1, "simple"); - Assert.That(tc.GetCategories().First(), Is.EqualTo("Single")); - } + Assert.That(testcaselist.Count, Is.EqualTo(3), "Wrong number of testcases found"); + var testcasesWithCategories = testcaselist.Where(o => o.GetCategories()?.FirstOrDefault() != null).ToList(); + Assert.That(testcasesWithCategories, Is.Not.Null, "Didn't find the testcases"); + Assert.That(testcasesWithCategories.Count, Is.EqualTo(1), "Wrong number of testcases with categories, should be only 1"); + var tc = testcasesWithCategories.FirstOrDefault(); + VerifyCategoriesOnly(tc, 1, "simple"); + Assert.That(tc.GetCategories().First(), Is.EqualTo("Single")); + } - private void VerifyCategoriesOnly(TestCase testcase, int expectedCategories, string forTest) + private void VerifyCategoriesOnly(TestCase testcase, int expectedCategories, string forTest) + { + var categories = testcase.GetCategories(); + Assert.Multiple(() => { - var categories = testcase.GetCategories(); - Assert.Multiple(() => - { - Assert.That(categories.Count(), Is.EqualTo(expectedCategories), $"Wrong number of categories for {forTest} testcase"); - Assert.That(testcase.Traits.Any(), Is.False, "There should be no traits"); - }); - } + Assert.That(categories.Count(), Is.EqualTo(expectedCategories), $"Wrong number of categories for {forTest} testcase"); + Assert.That(testcase.Traits.Any(), Is.False, "There should be no traits"); + }); + } - private static IReadOnlyList GetTestCases(string xml) - { - var settings = Substitute.For(); - settings.CollectSourceInformation.Returns(false); - using var converter = new TestConverterForXml( - new TestLogger(new MessageLoggerStub()), - "unused", - settings); - return converter.ConvertTestCases(xml); - } + private static IReadOnlyList GetTestCases(string xml) + { + var settings = Substitute.For(); + settings.CollectSourceInformation.Returns(false); + using var converter = new TestConverterForXml( + new TestLogger(new MessageLoggerStub()), + "unused", + settings); + return converter.ConvertTestCases(xml); + } - [Test] - public static void ThatExplicitTestCaseHasExplicitTrait() - { - var testCase = GetTestCases( - @" + [Test] + public static void ThatExplicitTestCaseHasExplicitTrait() + { + var testCase = GetTestCases( + @" ").Single(); - Assert.That(testCase.Traits, Has.One.With.Property("Name").EqualTo("Explicit")); - } + Assert.That(testCase.Traits, Has.One.With.Property("Name").EqualTo("Explicit")); + } - [Test] - public static void ThatTestCaseWithExplicitParentHasExplicitTrait() - { - var testCase = GetTestCases( - @" + [Test] + public static void ThatTestCaseWithExplicitParentHasExplicitTrait() + { + var testCase = GetTestCases( + @" ").Single(); - Assert.That(testCase.Traits, Has.One.With.Property("Name").EqualTo("Explicit")); - } + Assert.That(testCase.Traits, Has.One.With.Property("Name").EqualTo("Explicit")); + } - [Test] - public static void ThatMultipleChildTestCasesWithExplicitParentHaveExplicitTraits() - { - var testCases = GetTestCases( - @" + [Test] + public static void ThatMultipleChildTestCasesWithExplicitParentHaveExplicitTraits() + { + var testCases = GetTestCases( + @" "); - foreach (var testCase in testCases) - Assert.That(testCase.Traits, Has.One.With.Property("Name").EqualTo("Explicit")); - } + foreach (var testCase in testCases) + Assert.That(testCase.Traits, Has.One.With.Property("Name").EqualTo("Explicit")); + } - [Test] - public static void ThatExplicitTraitValueIsEmptyString() - { - var testCase = GetTestCases( - @" + [Test] + public static void ThatExplicitTraitValueIsEmptyString() + { + var testCase = GetTestCases( + @" ").Single(); - Assert.That(testCase.Traits, Has.One.With.Property("Name").EqualTo("Explicit").And.Property("Value").SameAs(string.Empty)); - } + Assert.That(testCase.Traits, Has.One.With.Property("Name").EqualTo("Explicit").And.Property("Value").SameAs(string.Empty)); } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/TryParseTests.cs b/src/NUnitTestAdapterTests/TryParseTests.cs index c9f1f277..019c3a49 100644 --- a/src/NUnitTestAdapterTests/TryParseTests.cs +++ b/src/NUnitTestAdapterTests/TryParseTests.cs @@ -1,34 +1,33 @@ using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +public class TryParseTests { - public class TryParseTests + public enum Whatever { - public enum Whatever - { - Something, - Nothing - } + Something, + Nothing + } - [TestCase("1", true, Whatever.Nothing)] - [TestCase("Nothing", true, Whatever.Nothing)] - [TestCase("something", true, Whatever.Something)] - [TestCase("0", true, Whatever.Something)] - public void EnumTryParseTestOk(string input, bool expected, Whatever expectedResult) - { + [TestCase("1", true, Whatever.Nothing)] + [TestCase("Nothing", true, Whatever.Nothing)] + [TestCase("something", true, Whatever.Something)] + [TestCase("0", true, Whatever.Something)] + public void EnumTryParseTestOk(string input, bool expected, Whatever expectedResult) + { var ok = TryParse.EnumTryParse(input, out Whatever whatever); Assert.That(ok, Is.EqualTo(expected)); Assert.That(whatever, Is.EqualTo(expectedResult)); } - [TestCase("10")] - [TestCase("svada")] - [TestCase("")] - [TestCase(null)] - public void EnumTryParseTestNotOk(string input) - { + [TestCase("10")] + [TestCase("svada")] + [TestCase("")] + [TestCase(null)] + public void EnumTryParseTestNotOk(string input) + { var ok = TryParse.EnumTryParse(input, out Whatever whatever); Assert.That(ok, Is.EqualTo(false)); } - } } \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/Utils.cs b/src/NUnitTestAdapterTests/Utils.cs index 38a7d054..34f4b313 100644 --- a/src/NUnitTestAdapterTests/Utils.cs +++ b/src/NUnitTestAdapterTests/Utils.cs @@ -1,33 +1,32 @@ using System.IO; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +internal static class Utils { - internal static class Utils + public static void DeleteDirectoryRobust(string directory) { - public static void DeleteDirectoryRobust(string directory) + for (var attempt = 1; ; attempt++) { - for (var attempt = 1; ; attempt++) + try + { + Directory.Delete(directory, recursive: true); + break; + } + catch (DirectoryNotFoundException) + { + break; + } + catch (IOException ex) when (attempt < 3 && (WinErrorCode)ex.HResult == WinErrorCode.DirNotEmpty) { - try - { - Directory.Delete(directory, recursive: true); - break; - } - catch (DirectoryNotFoundException) - { - break; - } - catch (IOException ex) when (attempt < 3 && (WinErrorCode)ex.HResult == WinErrorCode.DirNotEmpty) - { - TestContext.WriteLine("Another process added files to the directory while its contents were being deleted. Retrying..."); - } + TestContext.WriteLine("Another process added files to the directory while its contents were being deleted. Retrying..."); } } + } - private enum WinErrorCode : ushort - { - DirNotEmpty = 145 - } + private enum WinErrorCode : ushort + { + DirNotEmpty = 145 } -} +} \ No newline at end of file diff --git a/src/NUnitTestAdapterTests/VsExperimentalTests.cs b/src/NUnitTestAdapterTests/VsExperimentalTests.cs index 042f9799..d21ed0c0 100644 --- a/src/NUnitTestAdapterTests/VsExperimentalTests.cs +++ b/src/NUnitTestAdapterTests/VsExperimentalTests.cs @@ -28,16 +28,16 @@ using NSubstitute; using NUnit.Framework; -namespace NUnit.VisualStudio.TestAdapter.Tests +namespace NUnit.VisualStudio.TestAdapter.Tests; + +/// +/// Experimental tests used to deduce functionality of VSTest. +/// +public class VsExperimentalTests { - /// - /// Experimental tests used to deduce functionality of VSTest. - /// - public class VsExperimentalTests + [Test] + public void ThatCategoriesAreDistinct() { - [Test] - public void ThatCategoriesAreDistinct() - { var testCase = new TestCase( "whatever", new Uri(NUnitTestAdapter.ExecutorUri), @@ -56,5 +56,4 @@ public void ThatCategoriesAreDistinct() var returnedCategoryList = testCase.GetCategories(); Assert.That(returnedCategoryList.Count(), Is.EqualTo(2), $"Found {testCase.GetCategories().Count()} category entries"); } - } -} +} \ No newline at end of file