diff --git a/.editorconfig b/.editorconfig index 3513ec6283..76c9203e22 100644 --- a/.editorconfig +++ b/.editorconfig @@ -35,7 +35,11 @@ charset = utf-8 indent_size = 2 # Xml files -[*.{xml}] +[*.xml] +indent_size = 2 + +# Xlf files +[*.xlf] indent_size = 2 # YAML files @@ -428,6 +432,9 @@ dotnet_diagnostic.CA1854.severity = warning # CA1863: Use 'CompositeFormat' dotnet_diagnostic.CA1863.severity = none +# CA2007: Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.CA2007.severity = warning + # CA2016: Forward the 'CancellationToken' parameter to methods dotnet_diagnostic.CA2016.severity = warning @@ -683,11 +690,14 @@ csharp_style_unused_value_expression_statement_preference = discard_variable:sil # IDE0290: Use primary constructor csharp_style_prefer_primary_constructors = false +# Empty constructor +resharper_empty_constructor_highlighting = warning + # Redundant empty argument list on object creation expression resharper_redundant_empty_object_creation_argument_list_highlighting = warning -# IDE0300: Simplify collection initialization -dotnet_style_prefer_collection_expression = false +# IDE0300-IDE0306: Simplify collection initialization +dotnet_style_prefer_collection_expression = true # IDE0065: using directive placement csharp_using_directive_placement = outside_namespace:warning @@ -826,4 +836,4 @@ resharper_replace_with_single_call_to_first_or_default_highlighting = warning resharper_replace_conditional_expression_with_null_coalescing_highlighting = warning # Redundant cast -resharper_redundant_cast_highlighting = warning \ No newline at end of file +resharper_redundant_cast_highlighting = warning diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000000..0ca019af93 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,36 @@ +This is a .NET based repository that contains the MSTest testing framework and Microsoft.Testing.Platform (aka MTP) testing platform. Please follow these guidelines when contributing: + +## Code Standards + +You MUST follow all code-formatting and naming conventions defined in [`.editorconfig`](../.editorconfig). + +In addition to the rules enforced by `.editorconfig`, you SHOULD: + +- Favor style and conventions that are consistent with the existing codebase. +- Prefer file-scoped namespace declarations and single-line using directives. +- Ensure that the final return statement of a method is on its own line. +- Use pattern matching and switch expressions wherever possible. +- Use `nameof` instead of string literals when referring to member names. +- Always use `is null` or `is not null` instead of `== null` or `!= null`. +- Trust the C# null annotations and don't add null checks when the type system says a value cannot be null. +- Prefer `?.` if applicable (e.g. `scope?.Dispose()`). +- Use `ObjectDisposedException.ThrowIf` where applicable. +- Respect StyleCop.Analyzers rules, in particular: + - SA1028: Code must not contain trailing whitespace + - SA1316: Tuple element names should use correct casing + - SA1518: File is required to end with a single newline character + +You MUST minimize adding public API surface area but any newly added public API MUST be declared in the related `PublicAPI.Unshipped.txt` file. + +## Localization Guidelines + +Anytime you add a new localization resource, you MUST: +- Add a corresponding entry in the localization resource file. +- Add an entry in all `*.xlf` files related to the modified `.resx` file. +- Do not modify existing entries in '*.xlf' files unless you are also modifying the corresponding `.resx` file. + +## Testing Guidelines + +- Tests for MTP and MSTest analyzers MUST use MSTest. +- Unit tests for MSTest MUST use the internal test framework defined in [`TestFramework.ForTestingMSTest`](../test/Utilities/TestFramework.ForTestingMSTest). +- All assertions must be written using FluentAssertions style of assertion. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 07e9451eef..25bc4f05d6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,4 +10,14 @@ updates: - dependency-name: "Microsoft.DotNet.Arcade.Sdk" - dependency-name: Moq commit-message: - prefix: '[main] ' \ No newline at end of file + prefix: '[main] ' + - package-ecosystem: dotnet-sdk + directory: / + schedule: + interval: weekly + day: wednesday + ignore: + - dependency-name: '*' + update-types: + - version-update:semver-major + - version-update:semver-minor diff --git a/.github/workflows/backport-base.yml b/.github/workflows/backport-base.yml index 5941ec39fb..f53a7c1cec 100644 --- a/.github/workflows/backport-base.yml +++ b/.github/workflows/backport-base.yml @@ -2,10 +2,10 @@ on: workflow_call: inputs: pr_title_template: - description: 'The template used for the PR title. Special placeholder tokens that will be replaced with a value: %target_branch%, %source_pr_title%, %source_pr_number%, %cc_users%.' + description: 'The template used for the PR title. Special placeholder tokens that will be replaced with a value: %target_branch%, %source_pr_title%, %source_pr_number%, %source_pr_author%, %cc_users%.' required: false type: string - default: '[%target_branch%] %source_pr_title%' + default: '%source_pr_title% by @%source_pr_author% in #%source_pr_number% (backport to %target_branch%)' pr_description_template: description: 'The template used for the PR description. Special placeholder tokens that will be replaced with a value: %target_branch%, %source_pr_title%, %source_pr_number%, %cc_users%.' required: false @@ -116,6 +116,7 @@ jobs: .replace(/%target_branch%/g, target_branch) .replace(/%source_pr_title%/g, context.payload.issue.title) .replace(/%source_pr_number%/g, context.payload.issue.number) + .replace(/%source_pr_author%/g, context.payload.issue.user.login) return backport_pr_title; diff --git a/Directory.Build.props b/Directory.Build.props index 81e8489fd4..2f31b2c195 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,6 +14,7 @@ enable true enable + true @@ -36,6 +37,9 @@ embedded 0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7 + + + $(NoWarn);TPEXP @@ -62,12 +66,13 @@ - TestingPlatformRunner + Microsoft.Testing.Platform true + true diff --git a/Directory.Packages.props b/Directory.Packages.props index b276b09c02..7c8ac71080 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -23,14 +23,12 @@ 17.13.0 1.50.0 - 17.14.0-beta.25202.4 + 17.14.1 1.5.0-preview.24577.4 4.5.4 1.1.3-beta1.24423.1 - 3.9.0-preview.25229.4 - 1.7.0-preview.25226.1 @@ -54,7 +52,7 @@ - + diff --git a/MSTest.slnf b/MSTest.slnf index 111ef185e0..5b52bd185f 100644 --- a/MSTest.slnf +++ b/MSTest.slnf @@ -1,6 +1,6 @@ { "solution": { - "path": "TestFx.sln", + "path": "TestFx.slnx", "projects": [ "samples\\FxExtensibility\\FxExtensibility.csproj", "samples\\Playground\\Playground.csproj", @@ -40,6 +40,7 @@ "test\\IntegrationTests\\TestAssets\\SampleFrameworkExtensions\\SampleFrameworkExtensions.csproj", "test\\IntegrationTests\\TestAssets\\SampleProjectForAssemblyResolution\\SampleProjectForAssemblyResolution.csproj", "test\\IntegrationTests\\TestAssets\\SuiteLifeCycleTestProject\\SuiteLifeCycleTestProject.csproj", + "test\\IntegrationTests\\TestAssets\\TestCategoriesFromTestDataRowProject\\TestCategoriesFromTestDataRowProject.csproj", "test\\IntegrationTests\\TestAssets\\TestIdProject.DefaultStrategy\\TestIdProject.DefaultStrategy.csproj", "test\\IntegrationTests\\TestAssets\\TestIdProject.DisplayNameStrategy\\TestIdProject.DisplayNameStrategy.csproj", "test\\IntegrationTests\\TestAssets\\TestIdProject.FullyQualifiedTestStrategy\\TestIdProject.FullyQualifiedStrategy.csproj", @@ -50,6 +51,7 @@ "test\\UnitTests\\MSTest.Analyzers.UnitTests\\MSTest.Analyzers.UnitTests.csproj", "test\\UnitTests\\MSTestAdapter.PlatformServices.UnitTests\\MSTestAdapter.PlatformServices.UnitTests.csproj", "test\\UnitTests\\MSTestAdapter.UnitTests\\MSTestAdapter.UnitTests.csproj", + "test\\UnitTests\\MSTest.SelfRealExamples.UnitTests\\MSTest.SelfRealExamples.UnitTests.csproj", "test\\UnitTests\\TestFramework.UnitTests\\TestFramework.UnitTests.csproj", "test\\Utilities\\Automation.CLI\\Automation.CLI.csproj", "test\\Utilities\\Microsoft.Testing.TestInfrastructure\\Microsoft.Testing.TestInfrastructure.csproj", diff --git a/Microsoft.Testing.Platform.slnf b/Microsoft.Testing.Platform.slnf index 1595904e3a..d32084741e 100644 --- a/Microsoft.Testing.Platform.slnf +++ b/Microsoft.Testing.Platform.slnf @@ -1,6 +1,6 @@ { "solution": { - "path": "TestFx.sln", + "path": "TestFx.slnx", "projects": [ "samples\\Playground\\Playground.csproj", "src\\Platform\\Microsoft.Testing.Extensions.CrashDump\\Microsoft.Testing.Extensions.CrashDump.csproj", diff --git a/NonWindowsTests.slnf b/NonWindowsTests.slnf index e965c3ed7e..a69cbb51e1 100644 --- a/NonWindowsTests.slnf +++ b/NonWindowsTests.slnf @@ -1,14 +1,40 @@ { "solution": { - "path": "TestFx.sln", + "path": "TestFx.slnx", "projects": [ - "test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests.csproj", - "test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MSTest.Acceptance.IntegrationTests.csproj", - "test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Microsoft.Testing.Extensions.UnitTests.csproj", - "test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests.csproj", - "test/UnitTests/Microsoft.Testing.Platform.UnitTests/Microsoft.Testing.Platform.UnitTests.csproj", - "test/UnitTests/Microsoft.Testing.Platform.MSBuild.UnitTests/Microsoft.Testing.Platform.MSBuild.UnitTests.csproj", - "test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj" + "src\\Adapter\\MSTest.Engine\\MSTest.Engine.csproj", + "src\\Adapter\\MSTest.TestAdapter\\MSTest.TestAdapter.csproj", + "src\\Adapter\\MSTestAdapter.PlatformServices\\MSTestAdapter.PlatformServices.csproj", + "src\\Analyzers\\MSTest.Analyzers.CodeFixes\\MSTest.Analyzers.CodeFixes.csproj", + "src\\Analyzers\\MSTest.Analyzers.Package\\MSTest.Analyzers.Package.csproj", + "src\\Analyzers\\MSTest.Analyzers\\MSTest.Analyzers.csproj", + "src\\Analyzers\\MSTest.GlobalConfigsGenerator\\MSTest.GlobalConfigsGenerator.csproj", + "src\\Analyzers\\MSTest.Internal.Analyzers\\MSTest.Internal.Analyzers.csproj", + "src\\Analyzers\\MSTest.SourceGeneration\\MSTest.SourceGeneration.csproj", + "src\\Package\\MSTest.Sdk\\MSTest.Sdk.csproj", + "src\\Package\\MSTest\\MSTest.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.AzureDevOpsReport\\Microsoft.Testing.Extensions.AzureDevOpsReport.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.CrashDump\\Microsoft.Testing.Extensions.CrashDump.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.HangDump\\Microsoft.Testing.Extensions.HangDump.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.HotReload\\Microsoft.Testing.Extensions.HotReload.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.MSBuild\\Microsoft.Testing.Extensions.MSBuild.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.Retry\\Microsoft.Testing.Extensions.Retry.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.Telemetry\\Microsoft.Testing.Extensions.Telemetry.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.TrxReport.Abstractions\\Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.TrxReport\\Microsoft.Testing.Extensions.TrxReport.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.VSTestBridge\\Microsoft.Testing.Extensions.VSTestBridge.csproj", + "src\\Platform\\Microsoft.Testing.Platform.MSBuild\\Microsoft.Testing.Platform.MSBuild.csproj", + "src\\Platform\\Microsoft.Testing.Platform\\Microsoft.Testing.Platform.csproj", + "src\\TestFramework\\TestFramework.Extensions\\TestFramework.Extensions.csproj", + "src\\TestFramework\\TestFramework\\TestFramework.csproj", + "test\\IntegrationTests\\MSTest.Acceptance.IntegrationTests\\MSTest.Acceptance.IntegrationTests.csproj", + "test\\IntegrationTests\\Microsoft.Testing.Platform.Acceptance.IntegrationTests\\Microsoft.Testing.Platform.Acceptance.IntegrationTests.csproj", + "test\\UnitTests\\MSTest.Analyzers.UnitTests\\MSTest.Analyzers.UnitTests.csproj", + "test\\UnitTests\\Microsoft.Testing.Extensions.UnitTests\\Microsoft.Testing.Extensions.UnitTests.csproj", + "test\\UnitTests\\Microsoft.Testing.Extensions.VSTestBridge.UnitTests\\Microsoft.Testing.Extensions.VSTestBridge.UnitTests.csproj", + "test\\UnitTests\\Microsoft.Testing.Platform.MSBuild.UnitTests\\Microsoft.Testing.Platform.MSBuild.UnitTests.csproj", + "test\\UnitTests\\Microsoft.Testing.Platform.UnitTests\\Microsoft.Testing.Platform.UnitTests.csproj", + "test\\Utilities\\Microsoft.Testing.TestInfrastructure\\Microsoft.Testing.TestInfrastructure.csproj" ] } } \ No newline at end of file diff --git a/TestFx.sln b/TestFx.sln deleted file mode 100644 index ef5738fbb2..0000000000 --- a/TestFx.sln +++ /dev/null @@ -1,629 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.1.31910.343 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{FF8B1B72-55A1-4FFE-809E-7B79323ED8D0}" - ProjectSection(SolutionItems) = preProject - src\.editorconfig = src\.editorconfig - src\Directory.Build.props = src\Directory.Build.props - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2 - Adapter", "2 - Adapter", "{24088844-2107-4DB2-8F3F-CBCA94FC4B28}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.TestAdapter", "src\Adapter\MSTest.TestAdapter\MSTest.TestAdapter.csproj", "{98BA6D2C-1F3D-4636-8E1D-D4932B7A253D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTestAdapter.PlatformServices", "src\Adapter\MSTestAdapter.PlatformServices\MSTestAdapter.PlatformServices.csproj", "{5D153CAA-80C2-4551-9549-6C406FCEEFB1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3 - TestFramework", "3 - TestFramework", "{E48AC786-E150-4F41-9A16-32F02E4493D8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework", "src\TestFramework\TestFramework\TestFramework.csproj", "{7252D9E3-267D-442C-96BC-C73AEF3241D6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A9596292-7E67-4566-9096-143DDAA4E8D8}" - ProjectSection(SolutionItems) = preProject - test\.editorconfig = test\.editorconfig - test\Directory.Build.props = test\Directory.Build.props - test\Directory.Build.targets = test\Directory.Build.targets - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework.Extensions", "src\TestFramework\TestFramework.Extensions\TestFramework.Extensions.csproj", "{DF131865-84EE-4540-8112-E88ACEBDEA09}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestUtilities", "TestUtilities", "{33D3029D-E653-4929-BB31-C714178C4BEE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{929A3EDE-893B-4801-82BA-01FD947291CB}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - .gitignore = .gitignore - Directory.Build.props = Directory.Build.props - Directory.Build.targets = Directory.Build.targets - Directory.Packages.props = Directory.Packages.props - global.json = global.json - Nuget.config = Nuget.config - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "5 - Package", "5 - Package", "{E374A3A6-C364-4890-B315-D60F5C682B6E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTestAdapter.UnitTests", "test\UnitTests\MSTestAdapter.UnitTests\MSTestAdapter.UnitTests.csproj", "{1CEB5743-70BF-475E-91BC-0AEBD63835B7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTestAdapter.PlatformServices.UnitTests", "test\UnitTests\MSTestAdapter.PlatformServices.UnitTests\MSTestAdapter.PlatformServices.UnitTests.csproj", "{599833DC-EC5A-40CA-B5CF-DEF719548EEF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework.UnitTests", "test\UnitTests\TestFramework.UnitTests\TestFramework.UnitTests.csproj", "{0A4A76DD-FEE1-4D04-926B-38E1A24A7ED2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "eng", "eng", "{FE0DF239-0D81-46CA-9277-3342009E83F9}" - ProjectSection(SolutionItems) = preProject - eng\AfterSolutionBuild.targets = eng\AfterSolutionBuild.targets - eng\Analyzers.props = eng\Analyzers.props - eng\Build.props = eng\Build.props - eng\coverage.config = eng\coverage.config - eng\install-windows-sdk.ps1 = eng\install-windows-sdk.ps1 - eng\verify-nupkgs.ps1 = eng\verify-nupkgs.ps1 - eng\Version.Details.xml = eng\Version.Details.xml - eng\Versions.props = eng\Versions.props - eng\write-release-notes.ps1 = eng\write-release-notes.ps1 - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{92F8E9A2-903E-4025-99BC-7DC478D5466D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FxExtensibility", "samples\FxExtensibility\FxExtensibility.csproj", "{A82770C0-1FF5-43C7-8790-471D5E4F8D6E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{BB874DF1-44FE-415A-B634-A6B829107890}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegrationTests", "IntegrationTests", "{FF69998C-C661-4EF0-804B-845675B3602E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestAssets", "TestAssets", "{C9F82701-0E0F-4E61-B05B-AE387E7631F6}" - ProjectSection(SolutionItems) = preProject - test\IntegrationTests\TestAssets\Directory.Build.targets = test\IntegrationTests\TestAssets\Directory.Build.targets - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.IntegrationTests", "test\IntegrationTests\MSTest.IntegrationTests\MSTest.IntegrationTests.csproj", "{6359B7FD-5C63-487A-9467-99323C17AA10}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.VstestConsoleWrapper.IntegrationTests", "test\IntegrationTests\MSTest.VstestConsoleWrapper.IntegrationTests\MSTest.VstestConsoleWrapper.IntegrationTests.csproj", "{FE2A0AE6-835E-4603-9CE9-C8E25D14C4A0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformServices.Desktop.IntegrationTests", "test\IntegrationTests\PlatformServices.Desktop.IntegrationTests\PlatformServices.Desktop.IntegrationTests.csproj", "{93D3B3B5-6850-461C-9A08-A78D2921F86F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataRowTestProject", "test\IntegrationTests\TestAssets\DataRowTestProject\DataRowTestProject.csproj", "{2833FDA8-ECA0-439C-97E4-620AB9EC45AA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataSourceTestProject", "test\IntegrationTests\TestAssets\DataSourceTestProject\DataSourceTestProject.csproj", "{60116E14-11A3-47DF-B730-8A28ABD9B7AF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeploymentTestProject.Never", "test\IntegrationTests\TestAssets\DeploymentTestProject.Never\DeploymentTestProject.Never.csproj", "{CA6A4A5A-CFDE-440B-898E-FF6FBA405540}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeploymentTestProject.PreserveNewest", "test\IntegrationTests\TestAssets\DeploymentTestProject.PreserveNewest\DeploymentTestProject.PreserveNewest.csproj", "{9C81E66B-5DFE-4130-982E-64EF8D7F6A60}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesktopTestProjectx64Debug", "test\IntegrationTests\TestAssets\DesktopTestProjectx64Debug\DesktopTestProjectx64Debug.csproj", "{BE21907B-A4C1-41D7-A2EF-5C73A33090A0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesktopTestProjectx64Release", "test\IntegrationTests\TestAssets\DesktopTestProjectx64Release\DesktopTestProjectx64Release.csproj", "{F6AD3FE2-3C82-44E8-A694-C4C447EB2F10}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesktopTestProjectx86Debug", "test\IntegrationTests\TestAssets\DesktopTestProjectx86Debug\DesktopTestProjectx86Debug.csproj", "{41DD903C-CA88-4761-831B-978EC793508F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesktopTestProjectx86Release", "test\IntegrationTests\TestAssets\DesktopTestProjectx86Release\DesktopTestProjectx86Release.csproj", "{93B2E07F-A41D-42DC-AF5D-47048761DFA9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscoverInternalsProject", "test\IntegrationTests\TestAssets\DiscoverInternalsProject\DiscoverInternalsProject.csproj", "{48A0431B-9EFA-46DA-9AA9-D6552A7DA109}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DoNotParallelizeTestProject", "test\IntegrationTests\TestAssets\DoNotParallelizeTestProject\DoNotParallelizeTestProject.csproj", "{A2C5B6FE-A5B4-4419-A1FC-3F977DE24D2B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamicDataTestProject", "test\IntegrationTests\TestAssets\DynamicDataTestProject\DynamicDataTestProject.csproj", "{D11D17B0-74DB-43B2-B5AC-7F86E0ACEFCD}" -EndProject -Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpTestProject", "test\IntegrationTests\TestAssets\FSharpTestProject\FSharpTestProject.fsproj", "{C37026D9-6525-4128-A4A1-9E3E2C195737}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FxExtensibilityTestProject", "test\IntegrationTests\TestAssets\FxExtensibilityTestProject\FxExtensibilityTestProject.csproj", "{2F4DFABA-B031-4164-A178-25F0753C9971}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HierarchyProject", "test\IntegrationTests\TestAssets\HierarchyProject\HierarchyProject.csproj", "{77CDBBF7-895B-44E1-8C86-05D81286BC3A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibProjectReferencedByDataSourceTest", "test\IntegrationTests\TestAssets\LibProjectReferencedByDataSourceTest\LibProjectReferencedByDataSourceTest.csproj", "{DBE6C4AF-4D79-44BB-94B5-C57FEC8B4E69}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OutputTestProject", "test\IntegrationTests\TestAssets\OutputTestProject\OutputTestProject.csproj", "{2607F3CC-3AFE-4968-B028-4F502B9F6A28}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParallelClassesTestProject", "test\IntegrationTests\TestAssets\ParallelTestClass\ParallelClassesTestProject.csproj", "{60AE14C4-C54C-419D-AFF8-D7E49901D42B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleFrameworkExtensions", "test\IntegrationTests\TestAssets\SampleFrameworkExtensions\SampleFrameworkExtensions.csproj", "{17025461-E4B9-4D4A-AD74-AF1C355E61BC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleProjectForAssemblyResolution", "test\IntegrationTests\TestAssets\SampleProjectForAssemblyResolution\SampleProjectForAssemblyResolution.csproj", "{279E5DCA-3CD6-4C66-9D5F-475FDE96F3B8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SuiteLifeCycleTestProject", "test\IntegrationTests\TestAssets\SuiteLifeCycleTestProject\SuiteLifeCycleTestProject.csproj", "{CAA66039-6747-4516-ADBA-F3D4C349E9EA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestIdProject.DefaultStrategy", "test\IntegrationTests\TestAssets\TestIdProject.DefaultStrategy\TestIdProject.DefaultStrategy.csproj", "{8BCC6F49-CF4F-40DA-8EFC-D232C7984ABC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestIdProject.DisplayNameStrategy", "test\IntegrationTests\TestAssets\TestIdProject.DisplayNameStrategy\TestIdProject.DisplayNameStrategy.csproj", "{34714FAD-A226-432E-9083-6BCF79D71873}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestIdProject.FullyQualifiedStrategy", "test\IntegrationTests\TestAssets\TestIdProject.FullyQualifiedTestStrategy\TestIdProject.FullyQualifiedStrategy.csproj", "{27CFE39F-3F60-47E0-9281-12CB13C7B91E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestIdProject.LegacyStrategy", "test\IntegrationTests\TestAssets\TestIdProject.LegacyStrategy\TestIdProject.LegacyStrategy.csproj", "{DBA74878-65BF-4EE7-925A-67AF395F7D11}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestProjectForDiscovery", "test\IntegrationTests\TestAssets\TestProject\TestProjectForDiscovery.csproj", "{B3419F35-A31F-4CAA-A606-034D5DB669A2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimeoutTestProject", "test\IntegrationTests\TestAssets\TimeoutTestProject\TimeoutTestProject.csproj", "{4A184EC4-8BAB-498F-ABC6-300C70BF8240}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParallelMethodsTestProject", "test\IntegrationTests\TestAssets\ParallelTestMethods\ParallelMethodsTestProject.csproj", "{CA5D66E2-7244-4E72-AFB6-58A826A30B74}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Automation.CLI", "test\Utilities\Automation.CLI\Automation.CLI.csproj", "{35E90097-976B-4FF5-B55F-2F51561D7A33}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework.ForTestingMSTest", "test\Utilities\TestFramework.ForTestingMSTest\TestFramework.ForTestingMSTest.csproj", "{17CE999F-F3D1-48B4-A18F-8BA050C3A4AD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest", "src\Package\MSTest\MSTest.csproj", "{ED8534D1-3136-4915-8071-5547E8D84DC3}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestingPlatformRunner", "TestingPlatformRunner", "{A9F9C49E-3CDA-4207-AA53-CC80AF1798FE}" - ProjectSection(SolutionItems) = preProject - eng\TestingPlatformRunner\TestingPlatform.Runner.targets = eng\TestingPlatformRunner\TestingPlatform.Runner.targets - eng\TestingPlatformRunner\TestingPlatformRunner.targets = eng\TestingPlatformRunner\TestingPlatformRunner.targets - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1 - Platform and Extensions", "1 - Platform and Extensions", "{6AEE1440-FDF0-4729-8196-B24D0E333550}" - ProjectSection(SolutionItems) = preProject - src\Platform\Directory.Build.props = src\Platform\Directory.Build.props - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Platform", "src\Platform\Microsoft.Testing.Platform\Microsoft.Testing.Platform.csproj", "{48FAB979-8DA5-492E-8B3F-5DBBE82F659A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Platform.UnitTests", "test\UnitTests\Microsoft.Testing.Platform.UnitTests\Microsoft.Testing.Platform.UnitTests.csproj", "{0F1BB08E-BB6C-43E0-A7DF-1D6A03DA5DC7}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4 - Analyzers", "4 - Analyzers", "{E7F15C9C-3928-47AD-8462-64FD29FFCA54}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.Analyzers", "src\Analyzers\MSTest.Analyzers\MSTest.Analyzers.csproj", "{72C4FA49-E553-4B39-825A-8C4EA6CE93E2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.Analyzers.CodeFixes", "src\Analyzers\MSTest.Analyzers.CodeFixes\MSTest.Analyzers.CodeFixes.csproj", "{462B0201-1C26-4951-97C9-722C2A58EF8C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.Analyzers.Package", "src\Analyzers\MSTest.Analyzers.Package\MSTest.Analyzers.Package.csproj", "{DC068986-7549-4B75-8EFC-A9958FD5CF88}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.Analyzers.UnitTests", "test\UnitTests\MSTest.Analyzers.UnitTests\MSTest.Analyzers.UnitTests.csproj", "{1FF35C23-C128-4C95-B3F8-67B1B4C51E4D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.Sdk", "src\Package\MSTest.Sdk\MSTest.Sdk.csproj", "{10930CFD-EDF9-4486-B0A3-49230B5A6798}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClsTestProject", "test\IntegrationTests\TestAssets\ClsTestProject\ClsTestProject.csproj", "{100CF515-8291-45FF-9FFD-2A9064FECC72}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.TestInfrastructure", "test\Utilities\Microsoft.Testing.TestInfrastructure\Microsoft.Testing.TestInfrastructure.csproj", "{9DCE14DA-3DFB-48DE-A3CC-A02C3465973C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Platform.Acceptance.IntegrationTests", "test\IntegrationTests\Microsoft.Testing.Platform.Acceptance.IntegrationTests\Microsoft.Testing.Platform.Acceptance.IntegrationTests.csproj", "{3CF3861E-EB1B-4FA6-9355-372A9816DF6B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Performance", "Performance", "{CB0CC552-2017-40C0-934A-C8A3B00EF650}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.Performance.Runner", "test\Performance\MSTest.Performance.Runner\MSTest.Performance.Runner.csproj", "{7E9D98E7-733C-4D6B-A5AC-087D588A40ED}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Playground", "samples\Playground\Playground.csproj", "{8A41B37E-0732-4F28-B214-A44233B447FE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest.Acceptance.IntegrationTests", "test\IntegrationTests\MSTest.Acceptance.IntegrationTests\MSTest.Acceptance.IntegrationTests.csproj", "{BCB42780-C559-40B6-8C4A-85EBC464AAA8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FixturesTestProject", "test\IntegrationTests\TestAssets\FixturesTestProject\FixturesTestProject.csproj", "{A7D0995D-0516-4975-ABBD-EB93E1B79292}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Extensions.TrxReport.Abstractions", "src\Platform\Microsoft.Testing.Extensions.TrxReport.Abstractions\Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj", "{9164E0BA-0846-4839-BA0F-C25F5FBE056C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Extensions.TrxReport", "src\Platform\Microsoft.Testing.Extensions.TrxReport\Microsoft.Testing.Extensions.TrxReport.csproj", "{29B9F157-3733-471E-A11E-A5FF3C6D1348}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Extensions.VSTestBridge", "src\Platform\Microsoft.Testing.Extensions.VSTestBridge\Microsoft.Testing.Extensions.VSTestBridge.csproj", "{60763BAA-C963-4858-8DA1-78DB92428865}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Platform.MSBuild", "src\Platform\Microsoft.Testing.Platform.MSBuild\Microsoft.Testing.Platform.MSBuild.csproj", "{1B30B69C-A4E3-4660-9CA8-140D0C34B4A5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Extensions.Telemetry", "src\Platform\Microsoft.Testing.Extensions.Telemetry\Microsoft.Testing.Extensions.Telemetry.csproj", "{BCA498E6-22C7-4E3F-8862-A7FAA06652D1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Extensions.CrashDump", "src\Platform\Microsoft.Testing.Extensions.CrashDump\Microsoft.Testing.Extensions.CrashDump.csproj", "{DFC9B46A-BFA7-407D-B872-7104C78A0787}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Extensions.HangDump", "src\Platform\Microsoft.Testing.Extensions.HangDump\Microsoft.Testing.Extensions.HangDump.csproj", "{8C743361-B796-4A92-BD69-3B5DD734BA6F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Extensions.UnitTests", "test\UnitTests\Microsoft.Testing.Extensions.UnitTests\Microsoft.Testing.Extensions.UnitTests.csproj", "{16FEFD31-B0D6-4291-B620-F902A16F39DC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Extensions.VSTestBridge.UnitTests", "test\UnitTests\Microsoft.Testing.Extensions.VSTestBridge.UnitTests\Microsoft.Testing.Extensions.VSTestBridge.UnitTests.csproj", "{573C617F-6BB2-403A-AD87-E00A7FD537F0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Testing.Platform.MSBuild.UnitTests", "test\UnitTests\Microsoft.Testing.Platform.MSBuild.UnitTests\Microsoft.Testing.Platform.MSBuild.UnitTests.csproj", "{F422398C-72CD-43EA-AC8E-E0DBD08E5563}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Testing.Extensions.MSBuild", "src\Platform\Microsoft.Testing.Extensions.MSBuild\Microsoft.Testing.Extensions.MSBuild.csproj", "{8CE782A2-7374-4916-9C69-1F87E51A64A9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSTest.Internal.Analyzers", "src\Analyzers\MSTest.Internal.Analyzers\MSTest.Internal.Analyzers.csproj", "{4A93E1A2-B61E-31B2-33F2-478156A9B5E7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Testing.Extensions.HotReload", "src\Platform\Microsoft.Testing.Extensions.HotReload\Microsoft.Testing.Extensions.HotReload.csproj", "{53EBA540-F6CF-0715-1F62-241A53F537EC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Testing.Extensions.Retry", "src\Platform\Microsoft.Testing.Extensions.Retry\Microsoft.Testing.Extensions.Retry.csproj", "{FB4ED3AA-A12E-4192-861F-4B025876AA0F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSTest.GlobalConfigsGenerator", "src\Analyzers\MSTest.GlobalConfigsGenerator\MSTest.GlobalConfigsGenerator.csproj", "{A85AA656-6DB6-4A0B-AA80-CBB4058B3DDB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSTest.Engine", "src\Adapter\MSTest.Engine\MSTest.Engine.csproj", "{82881535-7E40-80D9-F086-A3847775F2E7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSTest.SourceGeneration", "src\Analyzers\MSTest.SourceGeneration\MSTest.SourceGeneration.csproj", "{7BA0E74E-798E-4399-2EDE-A23BD5DA78CA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSTest.Engine.UnitTests", "test\UnitTests\MSTest.Engine.UnitTests\MSTest.Engine.UnitTests.csproj", "{2C0DFAC0-5D58-D172-ECE4-CBB78AD03435}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSTest.SourceGeneration.UnitTests", "test\UnitTests\MSTest.SourceGeneration.UnitTests\MSTest.SourceGeneration.UnitTests.csproj", "{E6C0466E-BE8D-C04F-149A-FD98438F1413}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Testing.Extensions.AzureDevOpsReport", "src\Platform\Microsoft.Testing.Extensions.AzureDevOpsReport\Microsoft.Testing.Extensions.AzureDevOpsReport.csproj", "{F608D3A3-125B-CD88-1D51-8714ED142029}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {98BA6D2C-1F3D-4636-8E1D-D4932B7A253D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {98BA6D2C-1F3D-4636-8E1D-D4932B7A253D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {98BA6D2C-1F3D-4636-8E1D-D4932B7A253D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {98BA6D2C-1F3D-4636-8E1D-D4932B7A253D}.Release|Any CPU.Build.0 = Release|Any CPU - {5D153CAA-80C2-4551-9549-6C406FCEEFB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5D153CAA-80C2-4551-9549-6C406FCEEFB1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5D153CAA-80C2-4551-9549-6C406FCEEFB1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5D153CAA-80C2-4551-9549-6C406FCEEFB1}.Release|Any CPU.Build.0 = Release|Any CPU - {7252D9E3-267D-442C-96BC-C73AEF3241D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7252D9E3-267D-442C-96BC-C73AEF3241D6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7252D9E3-267D-442C-96BC-C73AEF3241D6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7252D9E3-267D-442C-96BC-C73AEF3241D6}.Release|Any CPU.Build.0 = Release|Any CPU - {DF131865-84EE-4540-8112-E88ACEBDEA09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DF131865-84EE-4540-8112-E88ACEBDEA09}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DF131865-84EE-4540-8112-E88ACEBDEA09}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DF131865-84EE-4540-8112-E88ACEBDEA09}.Release|Any CPU.Build.0 = Release|Any CPU - {1CEB5743-70BF-475E-91BC-0AEBD63835B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1CEB5743-70BF-475E-91BC-0AEBD63835B7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1CEB5743-70BF-475E-91BC-0AEBD63835B7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1CEB5743-70BF-475E-91BC-0AEBD63835B7}.Release|Any CPU.Build.0 = Release|Any CPU - {599833DC-EC5A-40CA-B5CF-DEF719548EEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {599833DC-EC5A-40CA-B5CF-DEF719548EEF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {599833DC-EC5A-40CA-B5CF-DEF719548EEF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {599833DC-EC5A-40CA-B5CF-DEF719548EEF}.Release|Any CPU.Build.0 = Release|Any CPU - {0A4A76DD-FEE1-4D04-926B-38E1A24A7ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0A4A76DD-FEE1-4D04-926B-38E1A24A7ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0A4A76DD-FEE1-4D04-926B-38E1A24A7ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0A4A76DD-FEE1-4D04-926B-38E1A24A7ED2}.Release|Any CPU.Build.0 = Release|Any CPU - {A82770C0-1FF5-43C7-8790-471D5E4F8D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A82770C0-1FF5-43C7-8790-471D5E4F8D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A82770C0-1FF5-43C7-8790-471D5E4F8D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A82770C0-1FF5-43C7-8790-471D5E4F8D6E}.Release|Any CPU.Build.0 = Release|Any CPU - {6359B7FD-5C63-487A-9467-99323C17AA10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6359B7FD-5C63-487A-9467-99323C17AA10}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6359B7FD-5C63-487A-9467-99323C17AA10}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6359B7FD-5C63-487A-9467-99323C17AA10}.Release|Any CPU.Build.0 = Release|Any CPU - {FE2A0AE6-835E-4603-9CE9-C8E25D14C4A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FE2A0AE6-835E-4603-9CE9-C8E25D14C4A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FE2A0AE6-835E-4603-9CE9-C8E25D14C4A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FE2A0AE6-835E-4603-9CE9-C8E25D14C4A0}.Release|Any CPU.Build.0 = Release|Any CPU - {93D3B3B5-6850-461C-9A08-A78D2921F86F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {93D3B3B5-6850-461C-9A08-A78D2921F86F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {93D3B3B5-6850-461C-9A08-A78D2921F86F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {93D3B3B5-6850-461C-9A08-A78D2921F86F}.Release|Any CPU.Build.0 = Release|Any CPU - {2833FDA8-ECA0-439C-97E4-620AB9EC45AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2833FDA8-ECA0-439C-97E4-620AB9EC45AA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2833FDA8-ECA0-439C-97E4-620AB9EC45AA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2833FDA8-ECA0-439C-97E4-620AB9EC45AA}.Release|Any CPU.Build.0 = Release|Any CPU - {60116E14-11A3-47DF-B730-8A28ABD9B7AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {60116E14-11A3-47DF-B730-8A28ABD9B7AF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {60116E14-11A3-47DF-B730-8A28ABD9B7AF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {60116E14-11A3-47DF-B730-8A28ABD9B7AF}.Release|Any CPU.Build.0 = Release|Any CPU - {CA6A4A5A-CFDE-440B-898E-FF6FBA405540}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CA6A4A5A-CFDE-440B-898E-FF6FBA405540}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CA6A4A5A-CFDE-440B-898E-FF6FBA405540}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CA6A4A5A-CFDE-440B-898E-FF6FBA405540}.Release|Any CPU.Build.0 = Release|Any CPU - {9C81E66B-5DFE-4130-982E-64EF8D7F6A60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C81E66B-5DFE-4130-982E-64EF8D7F6A60}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C81E66B-5DFE-4130-982E-64EF8D7F6A60}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C81E66B-5DFE-4130-982E-64EF8D7F6A60}.Release|Any CPU.Build.0 = Release|Any CPU - {BE21907B-A4C1-41D7-A2EF-5C73A33090A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BE21907B-A4C1-41D7-A2EF-5C73A33090A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE21907B-A4C1-41D7-A2EF-5C73A33090A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BE21907B-A4C1-41D7-A2EF-5C73A33090A0}.Release|Any CPU.Build.0 = Release|Any CPU - {F6AD3FE2-3C82-44E8-A694-C4C447EB2F10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F6AD3FE2-3C82-44E8-A694-C4C447EB2F10}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F6AD3FE2-3C82-44E8-A694-C4C447EB2F10}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F6AD3FE2-3C82-44E8-A694-C4C447EB2F10}.Release|Any CPU.Build.0 = Release|Any CPU - {41DD903C-CA88-4761-831B-978EC793508F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {41DD903C-CA88-4761-831B-978EC793508F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {41DD903C-CA88-4761-831B-978EC793508F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {41DD903C-CA88-4761-831B-978EC793508F}.Release|Any CPU.Build.0 = Release|Any CPU - {93B2E07F-A41D-42DC-AF5D-47048761DFA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {93B2E07F-A41D-42DC-AF5D-47048761DFA9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {93B2E07F-A41D-42DC-AF5D-47048761DFA9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {93B2E07F-A41D-42DC-AF5D-47048761DFA9}.Release|Any CPU.Build.0 = Release|Any CPU - {48A0431B-9EFA-46DA-9AA9-D6552A7DA109}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {48A0431B-9EFA-46DA-9AA9-D6552A7DA109}.Debug|Any CPU.Build.0 = Debug|Any CPU - {48A0431B-9EFA-46DA-9AA9-D6552A7DA109}.Release|Any CPU.ActiveCfg = Release|Any CPU - {48A0431B-9EFA-46DA-9AA9-D6552A7DA109}.Release|Any CPU.Build.0 = Release|Any CPU - {A2C5B6FE-A5B4-4419-A1FC-3F977DE24D2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A2C5B6FE-A5B4-4419-A1FC-3F977DE24D2B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A2C5B6FE-A5B4-4419-A1FC-3F977DE24D2B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A2C5B6FE-A5B4-4419-A1FC-3F977DE24D2B}.Release|Any CPU.Build.0 = Release|Any CPU - {D11D17B0-74DB-43B2-B5AC-7F86E0ACEFCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D11D17B0-74DB-43B2-B5AC-7F86E0ACEFCD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D11D17B0-74DB-43B2-B5AC-7F86E0ACEFCD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D11D17B0-74DB-43B2-B5AC-7F86E0ACEFCD}.Release|Any CPU.Build.0 = Release|Any CPU - {C37026D9-6525-4128-A4A1-9E3E2C195737}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C37026D9-6525-4128-A4A1-9E3E2C195737}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C37026D9-6525-4128-A4A1-9E3E2C195737}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C37026D9-6525-4128-A4A1-9E3E2C195737}.Release|Any CPU.Build.0 = Release|Any CPU - {2F4DFABA-B031-4164-A178-25F0753C9971}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2F4DFABA-B031-4164-A178-25F0753C9971}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2F4DFABA-B031-4164-A178-25F0753C9971}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2F4DFABA-B031-4164-A178-25F0753C9971}.Release|Any CPU.Build.0 = Release|Any CPU - {77CDBBF7-895B-44E1-8C86-05D81286BC3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77CDBBF7-895B-44E1-8C86-05D81286BC3A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77CDBBF7-895B-44E1-8C86-05D81286BC3A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77CDBBF7-895B-44E1-8C86-05D81286BC3A}.Release|Any CPU.Build.0 = Release|Any CPU - {DBE6C4AF-4D79-44BB-94B5-C57FEC8B4E69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DBE6C4AF-4D79-44BB-94B5-C57FEC8B4E69}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DBE6C4AF-4D79-44BB-94B5-C57FEC8B4E69}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DBE6C4AF-4D79-44BB-94B5-C57FEC8B4E69}.Release|Any CPU.Build.0 = Release|Any CPU - {2607F3CC-3AFE-4968-B028-4F502B9F6A28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2607F3CC-3AFE-4968-B028-4F502B9F6A28}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2607F3CC-3AFE-4968-B028-4F502B9F6A28}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2607F3CC-3AFE-4968-B028-4F502B9F6A28}.Release|Any CPU.Build.0 = Release|Any CPU - {60AE14C4-C54C-419D-AFF8-D7E49901D42B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {60AE14C4-C54C-419D-AFF8-D7E49901D42B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {60AE14C4-C54C-419D-AFF8-D7E49901D42B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {60AE14C4-C54C-419D-AFF8-D7E49901D42B}.Release|Any CPU.Build.0 = Release|Any CPU - {17025461-E4B9-4D4A-AD74-AF1C355E61BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {17025461-E4B9-4D4A-AD74-AF1C355E61BC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {17025461-E4B9-4D4A-AD74-AF1C355E61BC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {17025461-E4B9-4D4A-AD74-AF1C355E61BC}.Release|Any CPU.Build.0 = Release|Any CPU - {279E5DCA-3CD6-4C66-9D5F-475FDE96F3B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {279E5DCA-3CD6-4C66-9D5F-475FDE96F3B8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {279E5DCA-3CD6-4C66-9D5F-475FDE96F3B8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {279E5DCA-3CD6-4C66-9D5F-475FDE96F3B8}.Release|Any CPU.Build.0 = Release|Any CPU - {CAA66039-6747-4516-ADBA-F3D4C349E9EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CAA66039-6747-4516-ADBA-F3D4C349E9EA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CAA66039-6747-4516-ADBA-F3D4C349E9EA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CAA66039-6747-4516-ADBA-F3D4C349E9EA}.Release|Any CPU.Build.0 = Release|Any CPU - {8BCC6F49-CF4F-40DA-8EFC-D232C7984ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8BCC6F49-CF4F-40DA-8EFC-D232C7984ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8BCC6F49-CF4F-40DA-8EFC-D232C7984ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8BCC6F49-CF4F-40DA-8EFC-D232C7984ABC}.Release|Any CPU.Build.0 = Release|Any CPU - {34714FAD-A226-432E-9083-6BCF79D71873}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {34714FAD-A226-432E-9083-6BCF79D71873}.Debug|Any CPU.Build.0 = Debug|Any CPU - {34714FAD-A226-432E-9083-6BCF79D71873}.Release|Any CPU.ActiveCfg = Release|Any CPU - {34714FAD-A226-432E-9083-6BCF79D71873}.Release|Any CPU.Build.0 = Release|Any CPU - {27CFE39F-3F60-47E0-9281-12CB13C7B91E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {27CFE39F-3F60-47E0-9281-12CB13C7B91E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {27CFE39F-3F60-47E0-9281-12CB13C7B91E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {27CFE39F-3F60-47E0-9281-12CB13C7B91E}.Release|Any CPU.Build.0 = Release|Any CPU - {DBA74878-65BF-4EE7-925A-67AF395F7D11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DBA74878-65BF-4EE7-925A-67AF395F7D11}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DBA74878-65BF-4EE7-925A-67AF395F7D11}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DBA74878-65BF-4EE7-925A-67AF395F7D11}.Release|Any CPU.Build.0 = Release|Any CPU - {B3419F35-A31F-4CAA-A606-034D5DB669A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B3419F35-A31F-4CAA-A606-034D5DB669A2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B3419F35-A31F-4CAA-A606-034D5DB669A2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B3419F35-A31F-4CAA-A606-034D5DB669A2}.Release|Any CPU.Build.0 = Release|Any CPU - {4A184EC4-8BAB-498F-ABC6-300C70BF8240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A184EC4-8BAB-498F-ABC6-300C70BF8240}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A184EC4-8BAB-498F-ABC6-300C70BF8240}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A184EC4-8BAB-498F-ABC6-300C70BF8240}.Release|Any CPU.Build.0 = Release|Any CPU - {CA5D66E2-7244-4E72-AFB6-58A826A30B74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CA5D66E2-7244-4E72-AFB6-58A826A30B74}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CA5D66E2-7244-4E72-AFB6-58A826A30B74}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CA5D66E2-7244-4E72-AFB6-58A826A30B74}.Release|Any CPU.Build.0 = Release|Any CPU - {35E90097-976B-4FF5-B55F-2F51561D7A33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {35E90097-976B-4FF5-B55F-2F51561D7A33}.Debug|Any CPU.Build.0 = Debug|Any CPU - {35E90097-976B-4FF5-B55F-2F51561D7A33}.Release|Any CPU.ActiveCfg = Release|Any CPU - {35E90097-976B-4FF5-B55F-2F51561D7A33}.Release|Any CPU.Build.0 = Release|Any CPU - {17CE999F-F3D1-48B4-A18F-8BA050C3A4AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {17CE999F-F3D1-48B4-A18F-8BA050C3A4AD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {17CE999F-F3D1-48B4-A18F-8BA050C3A4AD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {17CE999F-F3D1-48B4-A18F-8BA050C3A4AD}.Release|Any CPU.Build.0 = Release|Any CPU - {ED8534D1-3136-4915-8071-5547E8D84DC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ED8534D1-3136-4915-8071-5547E8D84DC3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ED8534D1-3136-4915-8071-5547E8D84DC3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ED8534D1-3136-4915-8071-5547E8D84DC3}.Release|Any CPU.Build.0 = Release|Any CPU - {48FAB979-8DA5-492E-8B3F-5DBBE82F659A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {48FAB979-8DA5-492E-8B3F-5DBBE82F659A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {48FAB979-8DA5-492E-8B3F-5DBBE82F659A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {48FAB979-8DA5-492E-8B3F-5DBBE82F659A}.Release|Any CPU.Build.0 = Release|Any CPU - {0F1BB08E-BB6C-43E0-A7DF-1D6A03DA5DC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0F1BB08E-BB6C-43E0-A7DF-1D6A03DA5DC7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0F1BB08E-BB6C-43E0-A7DF-1D6A03DA5DC7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0F1BB08E-BB6C-43E0-A7DF-1D6A03DA5DC7}.Release|Any CPU.Build.0 = Release|Any CPU - {72C4FA49-E553-4B39-825A-8C4EA6CE93E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {72C4FA49-E553-4B39-825A-8C4EA6CE93E2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {72C4FA49-E553-4B39-825A-8C4EA6CE93E2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {72C4FA49-E553-4B39-825A-8C4EA6CE93E2}.Release|Any CPU.Build.0 = Release|Any CPU - {462B0201-1C26-4951-97C9-722C2A58EF8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {462B0201-1C26-4951-97C9-722C2A58EF8C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {462B0201-1C26-4951-97C9-722C2A58EF8C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {462B0201-1C26-4951-97C9-722C2A58EF8C}.Release|Any CPU.Build.0 = Release|Any CPU - {DC068986-7549-4B75-8EFC-A9958FD5CF88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DC068986-7549-4B75-8EFC-A9958FD5CF88}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DC068986-7549-4B75-8EFC-A9958FD5CF88}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DC068986-7549-4B75-8EFC-A9958FD5CF88}.Release|Any CPU.Build.0 = Release|Any CPU - {1FF35C23-C128-4C95-B3F8-67B1B4C51E4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1FF35C23-C128-4C95-B3F8-67B1B4C51E4D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1FF35C23-C128-4C95-B3F8-67B1B4C51E4D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1FF35C23-C128-4C95-B3F8-67B1B4C51E4D}.Release|Any CPU.Build.0 = Release|Any CPU - {10930CFD-EDF9-4486-B0A3-49230B5A6798}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {10930CFD-EDF9-4486-B0A3-49230B5A6798}.Debug|Any CPU.Build.0 = Debug|Any CPU - {10930CFD-EDF9-4486-B0A3-49230B5A6798}.Release|Any CPU.ActiveCfg = Release|Any CPU - {10930CFD-EDF9-4486-B0A3-49230B5A6798}.Release|Any CPU.Build.0 = Release|Any CPU - {100CF515-8291-45FF-9FFD-2A9064FECC72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {100CF515-8291-45FF-9FFD-2A9064FECC72}.Debug|Any CPU.Build.0 = Debug|Any CPU - {100CF515-8291-45FF-9FFD-2A9064FECC72}.Release|Any CPU.ActiveCfg = Release|Any CPU - {100CF515-8291-45FF-9FFD-2A9064FECC72}.Release|Any CPU.Build.0 = Release|Any CPU - {9DCE14DA-3DFB-48DE-A3CC-A02C3465973C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9DCE14DA-3DFB-48DE-A3CC-A02C3465973C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9DCE14DA-3DFB-48DE-A3CC-A02C3465973C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9DCE14DA-3DFB-48DE-A3CC-A02C3465973C}.Release|Any CPU.Build.0 = Release|Any CPU - {3CF3861E-EB1B-4FA6-9355-372A9816DF6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3CF3861E-EB1B-4FA6-9355-372A9816DF6B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3CF3861E-EB1B-4FA6-9355-372A9816DF6B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3CF3861E-EB1B-4FA6-9355-372A9816DF6B}.Release|Any CPU.Build.0 = Release|Any CPU - {7E9D98E7-733C-4D6B-A5AC-087D588A40ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7E9D98E7-733C-4D6B-A5AC-087D588A40ED}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7E9D98E7-733C-4D6B-A5AC-087D588A40ED}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7E9D98E7-733C-4D6B-A5AC-087D588A40ED}.Release|Any CPU.Build.0 = Release|Any CPU - {8A41B37E-0732-4F28-B214-A44233B447FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A41B37E-0732-4F28-B214-A44233B447FE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A41B37E-0732-4F28-B214-A44233B447FE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A41B37E-0732-4F28-B214-A44233B447FE}.Release|Any CPU.Build.0 = Release|Any CPU - {BCB42780-C559-40B6-8C4A-85EBC464AAA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BCB42780-C559-40B6-8C4A-85EBC464AAA8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BCB42780-C559-40B6-8C4A-85EBC464AAA8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BCB42780-C559-40B6-8C4A-85EBC464AAA8}.Release|Any CPU.Build.0 = Release|Any CPU - {A7D0995D-0516-4975-ABBD-EB93E1B79292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A7D0995D-0516-4975-ABBD-EB93E1B79292}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A7D0995D-0516-4975-ABBD-EB93E1B79292}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A7D0995D-0516-4975-ABBD-EB93E1B79292}.Release|Any CPU.Build.0 = Release|Any CPU - {9164E0BA-0846-4839-BA0F-C25F5FBE056C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9164E0BA-0846-4839-BA0F-C25F5FBE056C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9164E0BA-0846-4839-BA0F-C25F5FBE056C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9164E0BA-0846-4839-BA0F-C25F5FBE056C}.Release|Any CPU.Build.0 = Release|Any CPU - {29B9F157-3733-471E-A11E-A5FF3C6D1348}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {29B9F157-3733-471E-A11E-A5FF3C6D1348}.Debug|Any CPU.Build.0 = Debug|Any CPU - {29B9F157-3733-471E-A11E-A5FF3C6D1348}.Release|Any CPU.ActiveCfg = Release|Any CPU - {29B9F157-3733-471E-A11E-A5FF3C6D1348}.Release|Any CPU.Build.0 = Release|Any CPU - {60763BAA-C963-4858-8DA1-78DB92428865}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {60763BAA-C963-4858-8DA1-78DB92428865}.Debug|Any CPU.Build.0 = Debug|Any CPU - {60763BAA-C963-4858-8DA1-78DB92428865}.Release|Any CPU.ActiveCfg = Release|Any CPU - {60763BAA-C963-4858-8DA1-78DB92428865}.Release|Any CPU.Build.0 = Release|Any CPU - {1B30B69C-A4E3-4660-9CA8-140D0C34B4A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B30B69C-A4E3-4660-9CA8-140D0C34B4A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B30B69C-A4E3-4660-9CA8-140D0C34B4A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B30B69C-A4E3-4660-9CA8-140D0C34B4A5}.Release|Any CPU.Build.0 = Release|Any CPU - {BCA498E6-22C7-4E3F-8862-A7FAA06652D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BCA498E6-22C7-4E3F-8862-A7FAA06652D1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BCA498E6-22C7-4E3F-8862-A7FAA06652D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BCA498E6-22C7-4E3F-8862-A7FAA06652D1}.Release|Any CPU.Build.0 = Release|Any CPU - {DFC9B46A-BFA7-407D-B872-7104C78A0787}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DFC9B46A-BFA7-407D-B872-7104C78A0787}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DFC9B46A-BFA7-407D-B872-7104C78A0787}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DFC9B46A-BFA7-407D-B872-7104C78A0787}.Release|Any CPU.Build.0 = Release|Any CPU - {8C743361-B796-4A92-BD69-3B5DD734BA6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8C743361-B796-4A92-BD69-3B5DD734BA6F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8C743361-B796-4A92-BD69-3B5DD734BA6F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8C743361-B796-4A92-BD69-3B5DD734BA6F}.Release|Any CPU.Build.0 = Release|Any CPU - {16FEFD31-B0D6-4291-B620-F902A16F39DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {16FEFD31-B0D6-4291-B620-F902A16F39DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {16FEFD31-B0D6-4291-B620-F902A16F39DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {16FEFD31-B0D6-4291-B620-F902A16F39DC}.Release|Any CPU.Build.0 = Release|Any CPU - {573C617F-6BB2-403A-AD87-E00A7FD537F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {573C617F-6BB2-403A-AD87-E00A7FD537F0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {573C617F-6BB2-403A-AD87-E00A7FD537F0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {573C617F-6BB2-403A-AD87-E00A7FD537F0}.Release|Any CPU.Build.0 = Release|Any CPU - {F422398C-72CD-43EA-AC8E-E0DBD08E5563}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F422398C-72CD-43EA-AC8E-E0DBD08E5563}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F422398C-72CD-43EA-AC8E-E0DBD08E5563}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F422398C-72CD-43EA-AC8E-E0DBD08E5563}.Release|Any CPU.Build.0 = Release|Any CPU - {8CE782A2-7374-4916-9C69-1F87E51A64A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8CE782A2-7374-4916-9C69-1F87E51A64A9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8CE782A2-7374-4916-9C69-1F87E51A64A9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8CE782A2-7374-4916-9C69-1F87E51A64A9}.Release|Any CPU.Build.0 = Release|Any CPU - {4A93E1A2-B61E-31B2-33F2-478156A9B5E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A93E1A2-B61E-31B2-33F2-478156A9B5E7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A93E1A2-B61E-31B2-33F2-478156A9B5E7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A93E1A2-B61E-31B2-33F2-478156A9B5E7}.Release|Any CPU.Build.0 = Release|Any CPU - {53EBA540-F6CF-0715-1F62-241A53F537EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {53EBA540-F6CF-0715-1F62-241A53F537EC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {53EBA540-F6CF-0715-1F62-241A53F537EC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {53EBA540-F6CF-0715-1F62-241A53F537EC}.Release|Any CPU.Build.0 = Release|Any CPU - {FB4ED3AA-A12E-4192-861F-4B025876AA0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FB4ED3AA-A12E-4192-861F-4B025876AA0F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FB4ED3AA-A12E-4192-861F-4B025876AA0F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FB4ED3AA-A12E-4192-861F-4B025876AA0F}.Release|Any CPU.Build.0 = Release|Any CPU - {A85AA656-6DB6-4A0B-AA80-CBB4058B3DDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A85AA656-6DB6-4A0B-AA80-CBB4058B3DDB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A85AA656-6DB6-4A0B-AA80-CBB4058B3DDB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A85AA656-6DB6-4A0B-AA80-CBB4058B3DDB}.Release|Any CPU.Build.0 = Release|Any CPU - {82881535-7E40-80D9-F086-A3847775F2E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {82881535-7E40-80D9-F086-A3847775F2E7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {82881535-7E40-80D9-F086-A3847775F2E7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {82881535-7E40-80D9-F086-A3847775F2E7}.Release|Any CPU.Build.0 = Release|Any CPU - {7BA0E74E-798E-4399-2EDE-A23BD5DA78CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7BA0E74E-798E-4399-2EDE-A23BD5DA78CA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7BA0E74E-798E-4399-2EDE-A23BD5DA78CA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7BA0E74E-798E-4399-2EDE-A23BD5DA78CA}.Release|Any CPU.Build.0 = Release|Any CPU - {2C0DFAC0-5D58-D172-ECE4-CBB78AD03435}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2C0DFAC0-5D58-D172-ECE4-CBB78AD03435}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2C0DFAC0-5D58-D172-ECE4-CBB78AD03435}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2C0DFAC0-5D58-D172-ECE4-CBB78AD03435}.Release|Any CPU.Build.0 = Release|Any CPU - {E6C0466E-BE8D-C04F-149A-FD98438F1413}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E6C0466E-BE8D-C04F-149A-FD98438F1413}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E6C0466E-BE8D-C04F-149A-FD98438F1413}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E6C0466E-BE8D-C04F-149A-FD98438F1413}.Release|Any CPU.Build.0 = Release|Any CPU - {F608D3A3-125B-CD88-1D51-8714ED142029}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F608D3A3-125B-CD88-1D51-8714ED142029}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F608D3A3-125B-CD88-1D51-8714ED142029}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F608D3A3-125B-CD88-1D51-8714ED142029}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {24088844-2107-4DB2-8F3F-CBCA94FC4B28} = {FF8B1B72-55A1-4FFE-809E-7B79323ED8D0} - {98BA6D2C-1F3D-4636-8E1D-D4932B7A253D} = {24088844-2107-4DB2-8F3F-CBCA94FC4B28} - {5D153CAA-80C2-4551-9549-6C406FCEEFB1} = {24088844-2107-4DB2-8F3F-CBCA94FC4B28} - {E48AC786-E150-4F41-9A16-32F02E4493D8} = {FF8B1B72-55A1-4FFE-809E-7B79323ED8D0} - {7252D9E3-267D-442C-96BC-C73AEF3241D6} = {E48AC786-E150-4F41-9A16-32F02E4493D8} - {DF131865-84EE-4540-8112-E88ACEBDEA09} = {E48AC786-E150-4F41-9A16-32F02E4493D8} - {33D3029D-E653-4929-BB31-C714178C4BEE} = {A9596292-7E67-4566-9096-143DDAA4E8D8} - {E374A3A6-C364-4890-B315-D60F5C682B6E} = {FF8B1B72-55A1-4FFE-809E-7B79323ED8D0} - {1CEB5743-70BF-475E-91BC-0AEBD63835B7} = {BB874DF1-44FE-415A-B634-A6B829107890} - {599833DC-EC5A-40CA-B5CF-DEF719548EEF} = {BB874DF1-44FE-415A-B634-A6B829107890} - {0A4A76DD-FEE1-4D04-926B-38E1A24A7ED2} = {BB874DF1-44FE-415A-B634-A6B829107890} - {FE0DF239-0D81-46CA-9277-3342009E83F9} = {929A3EDE-893B-4801-82BA-01FD947291CB} - {A82770C0-1FF5-43C7-8790-471D5E4F8D6E} = {92F8E9A2-903E-4025-99BC-7DC478D5466D} - {BB874DF1-44FE-415A-B634-A6B829107890} = {A9596292-7E67-4566-9096-143DDAA4E8D8} - {FF69998C-C661-4EF0-804B-845675B3602E} = {A9596292-7E67-4566-9096-143DDAA4E8D8} - {C9F82701-0E0F-4E61-B05B-AE387E7631F6} = {FF69998C-C661-4EF0-804B-845675B3602E} - {6359B7FD-5C63-487A-9467-99323C17AA10} = {FF69998C-C661-4EF0-804B-845675B3602E} - {FE2A0AE6-835E-4603-9CE9-C8E25D14C4A0} = {FF69998C-C661-4EF0-804B-845675B3602E} - {93D3B3B5-6850-461C-9A08-A78D2921F86F} = {FF69998C-C661-4EF0-804B-845675B3602E} - {2833FDA8-ECA0-439C-97E4-620AB9EC45AA} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {60116E14-11A3-47DF-B730-8A28ABD9B7AF} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {CA6A4A5A-CFDE-440B-898E-FF6FBA405540} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {9C81E66B-5DFE-4130-982E-64EF8D7F6A60} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {BE21907B-A4C1-41D7-A2EF-5C73A33090A0} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {F6AD3FE2-3C82-44E8-A694-C4C447EB2F10} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {41DD903C-CA88-4761-831B-978EC793508F} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {93B2E07F-A41D-42DC-AF5D-47048761DFA9} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {48A0431B-9EFA-46DA-9AA9-D6552A7DA109} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {A2C5B6FE-A5B4-4419-A1FC-3F977DE24D2B} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {D11D17B0-74DB-43B2-B5AC-7F86E0ACEFCD} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {C37026D9-6525-4128-A4A1-9E3E2C195737} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {2F4DFABA-B031-4164-A178-25F0753C9971} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {77CDBBF7-895B-44E1-8C86-05D81286BC3A} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {DBE6C4AF-4D79-44BB-94B5-C57FEC8B4E69} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {2607F3CC-3AFE-4968-B028-4F502B9F6A28} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {60AE14C4-C54C-419D-AFF8-D7E49901D42B} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {17025461-E4B9-4D4A-AD74-AF1C355E61BC} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {279E5DCA-3CD6-4C66-9D5F-475FDE96F3B8} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {CAA66039-6747-4516-ADBA-F3D4C349E9EA} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {8BCC6F49-CF4F-40DA-8EFC-D232C7984ABC} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {34714FAD-A226-432E-9083-6BCF79D71873} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {27CFE39F-3F60-47E0-9281-12CB13C7B91E} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {DBA74878-65BF-4EE7-925A-67AF395F7D11} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {B3419F35-A31F-4CAA-A606-034D5DB669A2} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {4A184EC4-8BAB-498F-ABC6-300C70BF8240} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {CA5D66E2-7244-4E72-AFB6-58A826A30B74} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {35E90097-976B-4FF5-B55F-2F51561D7A33} = {33D3029D-E653-4929-BB31-C714178C4BEE} - {17CE999F-F3D1-48B4-A18F-8BA050C3A4AD} = {33D3029D-E653-4929-BB31-C714178C4BEE} - {ED8534D1-3136-4915-8071-5547E8D84DC3} = {E374A3A6-C364-4890-B315-D60F5C682B6E} - {A9F9C49E-3CDA-4207-AA53-CC80AF1798FE} = {FE0DF239-0D81-46CA-9277-3342009E83F9} - {6AEE1440-FDF0-4729-8196-B24D0E333550} = {FF8B1B72-55A1-4FFE-809E-7B79323ED8D0} - {48FAB979-8DA5-492E-8B3F-5DBBE82F659A} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {0F1BB08E-BB6C-43E0-A7DF-1D6A03DA5DC7} = {BB874DF1-44FE-415A-B634-A6B829107890} - {E7F15C9C-3928-47AD-8462-64FD29FFCA54} = {FF8B1B72-55A1-4FFE-809E-7B79323ED8D0} - {72C4FA49-E553-4B39-825A-8C4EA6CE93E2} = {E7F15C9C-3928-47AD-8462-64FD29FFCA54} - {462B0201-1C26-4951-97C9-722C2A58EF8C} = {E7F15C9C-3928-47AD-8462-64FD29FFCA54} - {DC068986-7549-4B75-8EFC-A9958FD5CF88} = {E7F15C9C-3928-47AD-8462-64FD29FFCA54} - {1FF35C23-C128-4C95-B3F8-67B1B4C51E4D} = {BB874DF1-44FE-415A-B634-A6B829107890} - {10930CFD-EDF9-4486-B0A3-49230B5A6798} = {E374A3A6-C364-4890-B315-D60F5C682B6E} - {100CF515-8291-45FF-9FFD-2A9064FECC72} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {9DCE14DA-3DFB-48DE-A3CC-A02C3465973C} = {33D3029D-E653-4929-BB31-C714178C4BEE} - {3CF3861E-EB1B-4FA6-9355-372A9816DF6B} = {FF69998C-C661-4EF0-804B-845675B3602E} - {CB0CC552-2017-40C0-934A-C8A3B00EF650} = {A9596292-7E67-4566-9096-143DDAA4E8D8} - {7E9D98E7-733C-4D6B-A5AC-087D588A40ED} = {CB0CC552-2017-40C0-934A-C8A3B00EF650} - {8A41B37E-0732-4F28-B214-A44233B447FE} = {92F8E9A2-903E-4025-99BC-7DC478D5466D} - {BCB42780-C559-40B6-8C4A-85EBC464AAA8} = {FF69998C-C661-4EF0-804B-845675B3602E} - {A7D0995D-0516-4975-ABBD-EB93E1B79292} = {C9F82701-0E0F-4E61-B05B-AE387E7631F6} - {9164E0BA-0846-4839-BA0F-C25F5FBE056C} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {29B9F157-3733-471E-A11E-A5FF3C6D1348} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {60763BAA-C963-4858-8DA1-78DB92428865} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {1B30B69C-A4E3-4660-9CA8-140D0C34B4A5} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {BCA498E6-22C7-4E3F-8862-A7FAA06652D1} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {DFC9B46A-BFA7-407D-B872-7104C78A0787} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {8C743361-B796-4A92-BD69-3B5DD734BA6F} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {16FEFD31-B0D6-4291-B620-F902A16F39DC} = {BB874DF1-44FE-415A-B634-A6B829107890} - {573C617F-6BB2-403A-AD87-E00A7FD537F0} = {BB874DF1-44FE-415A-B634-A6B829107890} - {F422398C-72CD-43EA-AC8E-E0DBD08E5563} = {BB874DF1-44FE-415A-B634-A6B829107890} - {8CE782A2-7374-4916-9C69-1F87E51A64A9} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {4A93E1A2-B61E-31B2-33F2-478156A9B5E7} = {E7F15C9C-3928-47AD-8462-64FD29FFCA54} - {53EBA540-F6CF-0715-1F62-241A53F537EC} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {FB4ED3AA-A12E-4192-861F-4B025876AA0F} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - {A85AA656-6DB6-4A0B-AA80-CBB4058B3DDB} = {E7F15C9C-3928-47AD-8462-64FD29FFCA54} - {82881535-7E40-80D9-F086-A3847775F2E7} = {24088844-2107-4DB2-8F3F-CBCA94FC4B28} - {7BA0E74E-798E-4399-2EDE-A23BD5DA78CA} = {E7F15C9C-3928-47AD-8462-64FD29FFCA54} - {2C0DFAC0-5D58-D172-ECE4-CBB78AD03435} = {BB874DF1-44FE-415A-B634-A6B829107890} - {E6C0466E-BE8D-C04F-149A-FD98438F1413} = {BB874DF1-44FE-415A-B634-A6B829107890} - {F608D3A3-125B-CD88-1D51-8714ED142029} = {6AEE1440-FDF0-4729-8196-B24D0E333550} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {31E0F4D5-975A-41CC-933E-545B2201FAF9} - EndGlobalSection -EndGlobal diff --git a/TestFx.slnx b/TestFx.slnx new file mode 100644 index 0000000000..d1a4ea3a97 --- /dev/null +++ b/TestFx.slnx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/azure-pipelines-official.yml b/azure-pipelines-official.yml index 2ead4ae47b..353e76967e 100644 --- a/azure-pipelines-official.yml +++ b/azure-pipelines-official.yml @@ -4,6 +4,7 @@ trigger: include: - main - rel/* + - dev/v4 exclude: - rel/2.* - rel/3.0.* @@ -90,7 +91,8 @@ extends: enablePublishTestResults: true testResultsFormat: 'vstest' enablePublishBuildAssets: true - enablePublishUsingPipelines: true + # For final version build, don't publish to internal feeds. + isAssetlessBuild: ${{ parameters.isRTM }} enableTelemetry: true jobs: - job: Windows @@ -140,13 +142,16 @@ extends: - ${{ if eq(parameters.SkipTests, False) }}: # -ci is allowing to import some environment variables and some required configurations - # -nobl avoids overwriting build binlog with binlog from tests - script: Test.cmd -configuration $(_BuildConfig) -ci -nobl + /bl:$(BUILD.SOURCESDIRECTORY)\artifacts\TestResults\$(_BuildConfig)\TestStep.binlog name: Test displayName: Test + env: + TESTINGPLATFORM_DEFAULT_HANG_TIMEOUT: 5m + DOTNET_ROOT: $(Build.SourcesDirectory)/.dotnet - task: CopyFiles@2 displayName: 'Copy binlogs' @@ -169,25 +174,27 @@ extends: Remove-Item -Path $(Build.SourcesDirectory)/artifacts/tmp -Recurse -Force displayName: Remove artifacts/tmp - # This step is only helpful for diagnosing some issues with vstest/test host that would not appear - # through the console or trx - task: 1ES.PublishBuildArtifacts@1 displayName: 'Publish Test Results folders' inputs: PathtoPublish: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - ArtifactName: TestResults_Windows - condition: failed() + ArtifactName: TestResults_Windows_Attempt$(System.JobAttempt) + condition: always() - task: NuGetAuthenticate@1 displayName: 'NuGet Authenticate to test-tools feed' - - task: 1ES.PublishNuget@1 - displayName: 'Publish NuGet packages to test-tools feed' - inputs: - # Do not push symbol packages nor Microsoft.Testing.Platform package - packageParentPath: '$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)' - packagesToPush: '$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)/**/*.nupkg;!$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)/**/*.symbols.nupkg;!$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)/NonShipping/Microsoft.Testing.Platform.*.nupkg' - publishVstsFeed: 'public/test-tools' + # Final builds should not go into test-tools package feed, so we can keep re-building them until we are ready to ship to nuget.org. + # This has to depend on the parameter and not on variable, variables are not defined early enough to be used in templating condition. + # We still need the final builds on test-tools so that internal repos can consume it, so we will publish it manually. + - ${{ if eq(parameters.isRTM, False) }}: + - task: 1ES.PublishNuget@1 + displayName: 'Publish NuGet packages to test-tools feed' + inputs: + # Do not push symbol packages nor Microsoft.Testing.Platform package + packageParentPath: '$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)' + packagesToPush: '$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)/**/*.nupkg;!$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)/**/*.symbols.nupkg;!$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)/NonShipping/Microsoft.Testing.Platform.*.nupkg' + publishVstsFeed: 'public/test-tools' - job: Linux timeoutInMinutes: 90 @@ -208,21 +215,21 @@ extends: - ${{ if eq(parameters.SkipTests, False) }}: # -ci is allowing to import some environment variables and some required configurations - # --nobl avoids overwriting build binlog with binlog from tests - script: | chmod +x ./test.sh - ./test.sh --configuration $(_BuildConfig) --ci --test --integrationTest --nobl + ./test.sh --configuration $(_BuildConfig) --ci --test --integrationTest --nobl /bl:$(BUILD.SOURCESDIRECTORY)/artifacts/TestResults/$(_BuildConfig)/TestStep.binlog name: Test displayName: Tests + env: + TESTINGPLATFORM_DEFAULT_HANG_TIMEOUT: 5m + DOTNET_ROOT: $(Build.SourcesDirectory)/.dotnet - # This step is only helpful for diagnosing some issues with vstest/test host that would not appear - # through the console or trx - task: 1ES.PublishBuildArtifacts@1 displayName: 'Publish Test Results folders' inputs: PathtoPublish: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - ArtifactName: TestResults_Linux - condition: failed() + ArtifactName: TestResults_Linux_Attempt$(System.JobAttempt) + condition: always() - ${{ if eq(variables['Build.SourceBranchName'], 'main') }}: - template: /eng/common/templates-official/job/onelocbuild.yml@self @@ -232,4 +239,6 @@ extends: LclSource: lclFilesfromPackage LclPackageId: 'LCL-JUNO-PROD-TESTFX' - - template: eng\common\templates-official\post-build\post-build.yml@self + # For stable versions avoid publishing them to internal feeds. + - ${{ if eq(parameters.isRTM, False) }}: + - template: eng\common\templates-official\post-build\post-build.yml@self diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1a37097e89..52908637ec 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,9 +1,16 @@ +trigger: + branches: + include: + - main + - rel/* + # Branch(es) that trigger(s) build(s) on PR pr: branches: include: - main - rel/* + - dev/v4 paths: exclude: - .github/* @@ -76,7 +83,15 @@ stages: filePath: ./eng/install-procdump.ps1 failOnStderr: true showWarnings: true - + - task: PowerShell@2 + displayName: 'Enable local dumps' + inputs: + targetType: 'inline' + script: | + New-Item -Path $(Build.SourcesDirectory)\artifacts\CrashDumps -ItemType Directory -Force + Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" + New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" -Name "DumpFolder" -Value "$(Build.SourcesDirectory)\artifacts\CrashDumps" -PropertyType ExpandString -Force + New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" -Name "DumpCount" -Value 10 -PropertyType DWord -Force - task: PowerShell@2 displayName: 'Install Access Database Engine' inputs: @@ -88,31 +103,38 @@ stages: - script: eng\common\CIBuild.cmd -configuration $(_BuildConfig) -prepareMachine + /p:Publish=false /p:Test=false /p:FastAcceptanceTest=true name: Build displayName: Build + - task: PublishBuildArtifacts@1 + displayName: 'Publish NuGet packages' + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)/Shipping' + ArtifactName: '$(Agent.Os)_$(Agent.JobName)_Attempt$(System.JobAttempt)' + condition: always() + - ${{ if eq(parameters.SkipTests, False) }}: # Because the build step is using -ci flag, restore is done in a local .packages directory. # We need to pass NUGET_PACKAGES so that when dotnet test is doing evaluation phase on the projects, it can resolve .props/.targets from packages and import them. # Otherwise, props/targets are not imported. It's important that they are imported so that IsTestingPlatformApplication ends up being set. - - script: $(Build.SourcesDirectory)/.dotnet/dotnet test -c $(_BuildConfig) --no-build -bl:$(BUILD.SOURCESDIRECTORY)\artifacts\log\$(_BuildConfig)\TestStep.binlog + - script: dotnet test -c $(_BuildConfig) --no-build -bl:$(BUILD.SOURCESDIRECTORY)\artifacts\TestResults\$(_BuildConfig)\TestStep.binlog --no-progress -p:UsingDotNetTest=true name: Test displayName: Test env: DOTNET_ROOT: $(Build.SourcesDirectory)/.dotnet NUGET_PACKAGES: $(Build.SourcesDirectory)/.packages + DOTNET_CLI_CONTEXT_VERBOSE: 1 - # This step is only helpful for diagnosing some issues with vstest/test host that would not appear - # through the console or trx - task: PublishBuildArtifacts@1 displayName: 'Publish Test Results folders' inputs: PathtoPublish: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - ArtifactName: TestResults_Windows_$(_BuildConfig) - condition: failed() + ArtifactName: TestResults_Windows_$(_BuildConfig)_Attempt$(System.JobAttempt) + condition: always() - task: CopyFiles@2 displayName: 'Copy binlogs' @@ -131,13 +153,20 @@ stages: condition: always() # Upload code coverage to codecov.io - - script: $(Build.SourcesDirectory)/.dotnet/dotnet msbuild -restore + - script: dotnet msbuild -restore eng/CodeCoverage.proj /p:Configuration=$(_BuildConfig) /bl:$(BUILD.SOURCESDIRECTORY)\artifacts\log\$(_BuildConfig)\CodeCoverage.binlog displayName: Upload coverage to codecov.io condition: and(succeeded(), eq(variables._BuildConfig, 'Debug')) + - task: PublishBuildArtifacts@1 + displayName: 'Publish local dumps' + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/artifacts/CrashDumps' + ArtifactName: TestResults_Windows_$(_BuildConfig) + condition: failed() + - job: Linux timeoutInMinutes: 90 pool: @@ -154,29 +183,36 @@ stages: -configuration $(_BuildConfig) -prepareMachine /p:Test=false + /p:Publish=false /p:NonWindowsBuild=true /p:FastAcceptanceTest=true displayName: Build + - task: PublishBuildArtifacts@1 + displayName: 'Publish NuGet packages' + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)/Shipping' + ArtifactName: '$(Agent.Os)_$(Agent.JobName)_Attempt$(System.JobAttempt)' + condition: always() + - ${{ if eq(parameters.SkipTests, False) }}: # Because the build step is using -ci flag, restore is done in a local .packages directory. # We need to pass NUGET_PACKAGES so that when dotnet test is doing evaluation phase on the projects, it can resolve .props/.targets from packages and import them. # Otherwise, props/targets are not imported. It's important that they are imported so that IsTestingPlatformApplication ends up being set. - - script: $(Build.SourcesDirectory)/.dotnet/dotnet test --solution NonWindowsTests.slnf -c $(_BuildConfig) --no-build -bl:$(BUILD.SOURCESDIRECTORY)\artifacts\log\$(_BuildConfig)\TestStep.binlog + - script: dotnet test --solution NonWindowsTests.slnf -c $(_BuildConfig) --no-build -bl:$(BUILD.SOURCESDIRECTORY)/artifacts/TestResults/$(_BuildConfig)/TestStep.binlog --no-progress -p:UsingDotNetTest=true name: Test displayName: Test env: DOTNET_ROOT: $(Build.SourcesDirectory)/.dotnet NUGET_PACKAGES: $(Build.SourcesDirectory)/.packages + DOTNET_CLI_CONTEXT_VERBOSE: 1 - # This step is only helpful for diagnosing some issues with vstest/test host that would not appear - # through the console or trx - task: PublishBuildArtifacts@1 displayName: 'Publish Test Results folders' inputs: PathtoPublish: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - ArtifactName: TestResults_Linux_$(_BuildConfig) - condition: failed() + ArtifactName: TestResults_Linux_$(_BuildConfig)_Attempt$(System.JobAttempt) + condition: always() - task: CopyFiles@2 displayName: 'Copy binlogs' @@ -211,29 +247,36 @@ stages: -configuration $(_BuildConfig) -prepareMachine /p:Test=false + /p:Publish=false /p:NonWindowsBuild=true /p:FastAcceptanceTest=true displayName: Build + - task: PublishBuildArtifacts@1 + displayName: 'Publish NuGet packages' + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/artifacts/packages/$(_BuildConfig)/Shipping' + ArtifactName: '$(Agent.Os)_$(Agent.JobName)_Attempt$(System.JobAttempt)' + condition: always() + - ${{ if eq(parameters.SkipTests, False) }}: # Because the build step is using -ci flag, restore is done in a local .packages directory. # We need to pass NUGET_PACKAGES so that when dotnet test is doing evaluation phase on the projects, it can resolve .props/.targets from packages and import them. # Otherwise, props/targets are not imported. It's important that they are imported so that IsTestingPlatformApplication ends up being set. - - script: $(Build.SourcesDirectory)/.dotnet/dotnet test --solution NonWindowsTests.slnf -c $(_BuildConfig) --no-build -bl:$(BUILD.SOURCESDIRECTORY)\artifacts\log\$(_BuildConfig)\TestStep.binlog + - script: dotnet test --solution NonWindowsTests.slnf -c $(_BuildConfig) --no-build -bl:$(BUILD.SOURCESDIRECTORY)/artifacts/TestResults/$(_BuildConfig)/TestStep.binlog --no-progress -p:UsingDotNetTest=true name: Test displayName: Test env: DOTNET_ROOT: $(Build.SourcesDirectory)/.dotnet NUGET_PACKAGES: $(Build.SourcesDirectory)/.packages + DOTNET_CLI_CONTEXT_VERBOSE: 1 - # This step is only helpful for diagnosing some issues with vstest/test host that would not appear - # through the console or trx - task: PublishBuildArtifacts@1 displayName: 'Publish Test Results folders' inputs: PathtoPublish: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - ArtifactName: TestResults_MacOs_$(_BuildConfig) - condition: failed() + ArtifactName: TestResults_MacOs_$(_BuildConfig)_Attempt$(System.JobAttempt) + condition: always() - task: CopyFiles@2 displayName: 'Copy binlogs' diff --git a/docs/Changelog-Platform.md b/docs/Changelog-Platform.md index 766d06c90e..13fda7dd6c 100644 --- a/docs/Changelog-Platform.md +++ b/docs/Changelog-Platform.md @@ -4,9 +4,151 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) +## [1.7.3] - 2025-06-17 + +See full log [of v3.9.2...v3.9.3](https://github.com/microsoft/testfx/compare/v3.9.2...v3.9.3) + +### Fixed + +* Simpler fix for dotnet test when using retry by @Youssef1313 in [#5731](https://github.com/microsoft/testfx/pull/5684) + +### Artifacts + +* Microsoft.Testing.Extensions.CrashDump: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.7.3) +* Microsoft.Testing.Extensions.HangDump: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.7.3) +* Microsoft.Testing.Extensions.HotReload: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.7.3) +* Microsoft.Testing.Extensions.Retry: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.7.3) +* Microsoft.Testing.Extensions.TrxReport: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.7.3) +* Microsoft.Testing.Extensions.AzureDevOpsReport [1.0.0-alpha.25317.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.AzureDevOpsReport/1.0.0-alpha.25317.1) + +## [1.7.2] - 2025-06-10 + +See full log [of v3.9.1...v3.9.2](https://github.com/microsoft/testfx/compare/v3.9.1...v3.9.2) + +### Fixed + +* Allow framework authors to use TestCase.FullyQualifiedName as the TestNodeUid by @Youssef1313 in [#5658](https://github.com/microsoft/testfx/pull/5658) + +### Artifacts + +* Microsoft.Testing.Extensions.CrashDump: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.7.2) +* Microsoft.Testing.Extensions.HangDump: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.7.2) +* Microsoft.Testing.Extensions.HotReload: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.7.2) +* Microsoft.Testing.Extensions.Retry: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.7.2) +* Microsoft.Testing.Extensions.TrxReport: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.7.2) +* Microsoft.Testing.Extensions.AzureDevOpsReport [1.0.0-alpha.25310.6](https://www.nuget.org/packages/Microsoft.Testing.Extensions.AzureDevOpsReport/1.0.0-alpha.25310.6) + +## [1.7.1] - 2025-05-27 + +See full log [of v3.9.0...v3.9.1](https://github.com/microsoft/testfx/compare/v3.9.0...v3.9.1) + +### Fixed + +* VSTestBridge: Handle TestPropertyAttributes.Trait instead of special casing specific properties by @Youssef1313 in [#5644](https://github.com/microsoft/testfx/pull/5644) + +### Artifacts + +* MSTest: [3.9.1](https://www.nuget.org/packages/MSTest/3.9.1) +* MSTest.TestFramework: [3.9.1](https://www.nuget.org/packages/MSTest.TestFramework/3.9.1) +* MSTest.TestAdapter: [3.9.1](https://www.nuget.org/packages/MSTest.TestAdapter/3.9.1) +* MSTest.Analyzers: [3.9.1](https://www.nuget.org/packages/MSTest.Analyzers/3.9.1) +* MSTest.Sdk: [3.9.1](https://www.nuget.org/packages/MSTest.Sdk/3.9.1) +* Microsoft.Testing.Extensions.CrashDump: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.7.1) +* Microsoft.Testing.Extensions.HangDump: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.7.1) +* Microsoft.Testing.Extensions.HotReload: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.7.1) +* Microsoft.Testing.Extensions.Retry: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.7.1) +* Microsoft.Testing.Extensions.TrxReport: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.7.1) +* Microsoft.Testing.Extensions.AzureDevOpsReport [1.0.0-alpha.25277.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.AzureDevOpsReport/1.0.0-alpha.25277.3) +* MSTest.SourceGeneration: [1.0.0-alpha.25277.3](https://www.nuget.org/packages/MSTest.SourceGeneration/1.0.0-alpha.25277.3) +* MSTest.Engine: [1.0.0-alpha.25277.3](https://www.nuget.org/packages/MSTest.Engine/1.0.0-alpha.25277.3) + +## [1.7.0] - 2025-05-20 + +See full log [of v3.8.3...v3.9.0](https://github.com/microsoft/testfx/compare/v3.8.3...v3.9.0) + +### Added + +* [Source Breaking (only for framework authors)]: Support test artifacts in VS by @Youssef1313 in [#5323](https://github.com/microsoft/testfx/pull/5323) +* Add (alpha) Azure DevOps extension to report errors by @nohwnd in [#5260](https://github.com/microsoft/testfx/pull/5260) +* Add banner for MSTest.Engine by @Youssef1313 in [#5051](https://github.com/microsoft/testfx/pull/5051) +* Use terminal logger for discovery by @nohwnd in [#4907](https://github.com/microsoft/testfx/pull/4907) +* Add RetryContext.FirstRunResults by @Youssef1313 in [#5314](https://github.com/microsoft/testfx/pull/5314) +* VSTestBridge: Add traits as TestMetadataProperty by @Youssef1313 in [#5316](https://github.com/microsoft/testfx/pull/5316) +* Mark APIs not supported in wasi by @Youssef1313 in [#5367](https://github.com/microsoft/testfx/pull/5367) +* Show disk info when hang dump fails by @Youssef1313 in [#5404](https://github.com/microsoft/testfx/pull/5404) +* Implement analyzer for RetryAttribute to be present on test methods by @Youssef1313 in [#5437](https://github.com/microsoft/testfx/pull/5437) +* Add TestMethodIdentifierProperty constructor with arity parameter by @Youssef1313 in [#5528](https://github.com/microsoft/testfx/pull/5528) + +### Fixed + +* Kill testhost if writing hang dump fails by @Youssef1313 in [#5538](https://github.com/microsoft/testfx/pull/5538) +* Simplify generated file name by using DefaultLanguageSourceExtension by @Youssef1313 in [#5026](https://github.com/microsoft/testfx/pull/5026) +* Fix handling of unsupported platforms of CancelKeyPress by @Youssef1313 in [#5038](https://github.com/microsoft/testfx/pull/5038) +* Refactor logic around GetCurrentTestApplicationFullPath by @Youssef1313 in [#5037](https://github.com/microsoft/testfx/pull/5037) +* Enable platform compatibility warnings for android, ios, tvos, and browser by @Youssef1313 in [#5046](https://github.com/microsoft/testfx/pull/5046) +* Improve MSTest.SourceGeneration incrementality by @Youssef1313 in [#5053](https://github.com/microsoft/testfx/pull/5053) +* remove redundant IPlatformOutputDeviceManager by @SimonCropp in [#4848](https://github.com/microsoft/testfx/pull/4848) +* Avoid using unsupported APIs by @Youssef1313 in [#5057](https://github.com/microsoft/testfx/pull/5057) +* Fix binlog base name for .NET Framework tests by @Youssef1313 in [#5102](https://github.com/microsoft/testfx/pull/5102) +* Improve ExecutionContext propagation by @Youssef1313 in [#5156](https://github.com/microsoft/testfx/pull/5156) +* use StringBuilder AppendJoin by @SimonCropp in [#5167](https://github.com/microsoft/testfx/pull/5167) +* Update README.md with MSTest.Sdk information by @stan-sz in [#5214](https://github.com/microsoft/testfx/pull/5214) +* Add assembly name by @nohwnd in [#5235](https://github.com/microsoft/testfx/pull/5235) +* Correct branding as Microsoft.Testing.Platform by @Youssef1313 in [#5240](https://github.com/microsoft/testfx/pull/5240) +* Remove extra space by @nohwnd in [#5238](https://github.com/microsoft/testfx/pull/5238) +* Fix Retry for dotnet test by @Youssef1313 in [#5261](https://github.com/microsoft/testfx/pull/5261) +* Onboard to new dotnet test experience by @Evangelink in [#5111](https://github.com/microsoft/testfx/pull/5111) +* Add InstanceId to communication with dotnet test by @mariam-abdulla in [#5279](https://github.com/microsoft/testfx/pull/5279) +* Add instance id to dotnet test protocol by @mariam-abdulla in [#5287](https://github.com/microsoft/testfx/pull/5287) +* Use FileAccess.Read when reading testconfig.json file by @Youssef1313 in [#5264](https://github.com/microsoft/testfx/pull/5264) +* Fix double empty line by @nohwnd in [#5317](https://github.com/microsoft/testfx/pull/5317) +* Remove SessionUid from FileArtifactProperty by @Youssef1313 in [#5347](https://github.com/microsoft/testfx/pull/5347) +* Fix typo in DotnetTestDataConsumer causes only first artifact to be sent by @Youssef1313 in [#5349](https://github.com/microsoft/testfx/pull/5349) +* fix nullability in GetRepoRoot by @SimonCropp in [#5392](https://github.com/microsoft/testfx/pull/5392) +* remove redundant null check in FormatInnerExceptions by @SimonCropp in [#5397](https://github.com/microsoft/testfx/pull/5397) +* fix nullability of CreateBindCtx by @SimonCropp in [#5385](https://github.com/microsoft/testfx/pull/5385) +* remove redundant control flow statements by @SimonCropp in [#5403](https://github.com/microsoft/testfx/pull/5403) +* fix nullability of InvokeTestingPlatformTask _outputFileName by @SimonCropp in [#5394](https://github.com/microsoft/testfx/pull/5394) +* fix nullability of argument in GetProcessExitCodeAsync_IgnoreExitCodes by @SimonCropp in [#5386](https://github.com/microsoft/testfx/pull/5386) +* remove redundant null check for OpenBaseKey return by @SimonCropp in [#5395](https://github.com/microsoft/testfx/pull/5395) +* remove redundant null check in GetStringFromIndexOrDefault by @SimonCropp in [#5396](https://github.com/microsoft/testfx/pull/5396) +* fix nullability in FileLoggerProvider by @SimonCropp in [#5398](https://github.com/microsoft/testfx/pull/5398) +* remove un-used TestNodeProcessor by @SimonCropp in [#5430](https://github.com/microsoft/testfx/pull/5430) +* Rename MTP entrypoint to MicrosoftTestingPlatformEntryPoint by @Youssef1313 in [#5423](https://github.com/microsoft/testfx/pull/5423) +* use null propagation and mark as warning in editorconfig by @SimonCropp in [#5383](https://github.com/microsoft/testfx/pull/5383) +* FindNode cant return null by @SimonCropp in [#5448](https://github.com/microsoft/testfx/pull/5448) +* remove un-used methods in UnicodeCharacterUtilities by @SimonCropp in [#5444](https://github.com/microsoft/testfx/pull/5444) +* remove ServerLogMessageInMemoryStore by @SimonCropp in [#5456](https://github.com/microsoft/testfx/pull/5456) +* Remove some redundant casts and mark as a warning for rider and R# by @SimonCropp in [#5459](https://github.com/microsoft/testfx/pull/5459) +* Use GetFileNameWithoutExtension for crashdump file name to be consistent with hangdump by @Youssef1313 in [#5454](https://github.com/microsoft/testfx/pull/5454) +* Remove dead --internal-vstest-adapter by @Youssef1313 in [#5450](https://github.com/microsoft/testfx/pull/5450) +* Consistent command-line options provider properties by @Youssef1313 in [#5452](https://github.com/microsoft/testfx/pull/5452) +* Update Fakes dependency by @stan-sz in [#5482](https://github.com/microsoft/testfx/pull/5482) +* Use PlatformVersion.Version as the server version by @Youssef1313 in [#5486](https://github.com/microsoft/testfx/pull/5486) +* Handle DebugOrTraceTrxMessage in TrxReportEngine by @Youssef1313 in [#5510](https://github.com/microsoft/testfx/pull/5510) +* Few improvements to AzDO extension by @Youssef1313 in [#5513](https://github.com/microsoft/testfx/pull/5513) +* VSTestBridge+MSTest: Use TestMethodIdentifierProperty and stop sending VSTest-specifics by @Youssef1313 in [#5409](https://github.com/microsoft/testfx/pull/5409) +* Add vstest.TestCase.CodeFilePath and vstest.TestCase.LineNumber by @Youssef1313 in [#5539](https://github.com/microsoft/testfx/pull/5539) + +### Artifacts + +* MSTest: [3.9.0](https://www.nuget.org/packages/MSTest/3.9.0) +* MSTest.TestFramework: [3.9.0](https://www.nuget.org/packages/MSTest.TestFramework/3.9.0) +* MSTest.TestAdapter: [3.9.0](https://www.nuget.org/packages/MSTest.TestAdapter/3.9.0) +* MSTest.Analyzers: [3.9.0](https://www.nuget.org/packages/MSTest.Analyzers/3.9.0) +* MSTest.Sdk: [3.9.0](https://www.nuget.org/packages/MSTest.Sdk/3.9.0) +* Microsoft.Testing.Extensions.CrashDump: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.7.0) +* Microsoft.Testing.Extensions.HangDump: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.7.0) +* Microsoft.Testing.Extensions.HotReload: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.7.0) +* Microsoft.Testing.Extensions.Retry: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.7.0) +* Microsoft.Testing.Extensions.TrxReport: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.7.0) +* Microsoft.Testing.Extensions.AzureDevOpsReport [1.0.0-alpha.25256.6](https://www.nuget.org/packages/Microsoft.Testing.Extensions.AzureDevOpsReport/1.0.0-alpha.25256.6) +* MSTest.SourceGeneration: [1.0.0-alpha.25256.6](https://www.nuget.org/packages/MSTest.SourceGeneration/1.0.0-alpha.25256.6) +* MSTest.Engine: [1.0.0-alpha.25256.6](https://www.nuget.org/packages/MSTest.Engine/1.0.0-alpha.25256.6) + ## [1.6.3] - 2025-03-17 -See full log [here](https://github.com/microsoft/testfx/compare/v3.8.2...v3.8.3) +See full log [of v3.8.2...v3.8.3](https://github.com/microsoft/testfx/compare/v3.8.2...v3.8.3) ### Fixed @@ -35,7 +177,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.8.2...v3.8.3) ## [1.6.2] - 2025-02-19 -See full log [here](https://github.com/microsoft/testfx/compare/v3.8.1...v3.8.2) +See full log [of v3.8.1...v3.8.2](https://github.com/microsoft/testfx/compare/v3.8.1...v3.8.2) ### Fixed @@ -56,7 +198,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.8.1...v3.8.2) ## [1.6.1] - 2025-02-18 -See full log [here](https://github.com/microsoft/testfx/compare/v3.8.0...v3.8.1) +See full log [of v3.8.0...v3.8.1](https://github.com/microsoft/testfx/compare/v3.8.0...v3.8.1) ### Fixed @@ -79,7 +221,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.8.0...v3.8.1) ## [1.6.0] - 2025-02-12 -See full log [here](https://github.com/microsoft/testfx/compare/v3.7.3...v3.8.0) +See full log [of v3.7.3...v3.8.0](https://github.com/microsoft/testfx/compare/v3.7.3...v3.8.0) ### Added @@ -117,7 +259,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.7.3...v3.8.0) ## [1.5.3] - 2025-01-27 -See full log [here](https://github.com/microsoft/testfx/compare/v3.7.2...v3.7.3) +See full log [of v3.7.2...v3.7.3](https://github.com/microsoft/testfx/compare/v3.7.2...v3.7.3) ### Fixed @@ -138,7 +280,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.7.2...v3.7.3) ## [1.5.2] - 2025-01-21 -See full log [here](https://github.com/microsoft/testfx/compare/v3.7.1...v3.7.2) +See full log [of v3.7.1...v3.7.2](https://github.com/microsoft/testfx/compare/v3.7.1...v3.7.2) ### Fixed @@ -159,7 +301,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.7.1...v3.7.2) ## [1.5.1] - 2025-01-13 -See full log [here](https://github.com/microsoft/testfx/compare/v3.7.0...v3.7.1) +See full log [of v3.7.0...v3.7.1](https://github.com/microsoft/testfx/compare/v3.7.0...v3.7.1) ### Fixed @@ -181,7 +323,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.7.0...v3.7.1) ## [1.5.0] - 2024-12-20 -See full log [here](https://github.com/microsoft/testfx/compare/v1.4.3...v1.5.0) +See full log [of v1.4.3...v1.5.0](https://github.com/microsoft/testfx/compare/v1.4.3...v1.5.0) ### Added @@ -236,7 +378,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v1.4.3...v1.5.0) ## [1.4.3] - 2024-11-12 -See full log [here](https://github.com/microsoft/testanywhere/compare/v1.4.2...v1.4.3) +See full log [of v1.4.2...v1.4.3](https://github.com/microsoft/testanywhere/compare/v1.4.2...v1.4.3) ### Fixed @@ -259,7 +401,7 @@ See full log [here](https://github.com/microsoft/testanywhere/compare/v1.4.2...v ## [1.4.2] - 2024-10-31 -See full log [here](https://github.com/microsoft/testanywhere/compare/v1.4.1...v1.4.2) +See full log [of v1.4.1...v1.4.2](https://github.com/microsoft/testanywhere/compare/v1.4.1...v1.4.2) ### Fixed @@ -282,7 +424,7 @@ See full log [here](https://github.com/microsoft/testanywhere/compare/v1.4.1...v ## [1.4.1] - 2024-10-03 -See full log [here](https://github.com/microsoft/testanywhere/compare/v1.4.0...v1.4.1) +See full log [of v1.4.0...v1.4.1](https://github.com/microsoft/testanywhere/compare/v1.4.0...v1.4.1) ### Fixed @@ -305,7 +447,7 @@ See full log [here](https://github.com/microsoft/testanywhere/compare/v1.4.0...v ## [1.4.0] - 2024-09-11 -See full log [here](https://github.com/microsoft/testanywhere/compare/v1.3.2...v1.4.0) +See full log [of v1.3.2...v1.4.0](https://github.com/microsoft/testanywhere/compare/v1.3.2...v1.4.0) ### Added @@ -377,7 +519,7 @@ See full log [here](https://github.com/microsoft/testanywhere/compare/v1.3.2...v ## [1.3.2] - 2024-08-05 -See full log [here](https://github.com/microsoft/testanywhere/compare/v1.3.1...v1.3.2) +See full log [of v1.3.1...v1.3.2](https://github.com/microsoft/testanywhere/compare/v1.3.1...v1.3.2) ### Fixed @@ -401,7 +543,7 @@ See full log [here](https://github.com/microsoft/testanywhere/compare/v1.3.1...v ## [1.3.1] - 2024-07-15 -See full log [here](https://github.com/microsoft/testanywhere/compare/v1.2.1...v1.3.1) +See full log [of v1.2.1...v1.3.1](https://github.com/microsoft/testanywhere/compare/v1.2.1...v1.3.1) ### Added diff --git a/docs/Changelog.md b/docs/Changelog.md index 24e4e4da1b..350f80b081 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -4,9 +4,162 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) +## [3.9.3] - 2025-06-17 + +See full log [of v3.9.2...v3.9.3](https://github.com/microsoft/testfx/compare/v3.9.2...v3.9.3) + +### Fixed + +* No change, released to keep version aligned with Microsoft.Testing.Platform. + +### Artifacts + +* MSTest: [3.9.3](https://www.nuget.org/packages/MSTest/3.9.3) +* MSTest.TestFramework: [3.9.3](https://www.nuget.org/packages/MSTest.TestFramework/3.9.3) +* MSTest.TestAdapter: [3.9.3](https://www.nuget.org/packages/MSTest.TestAdapter/3.9.3) +* MSTest.Analyzers: [3.9.3](https://www.nuget.org/packages/MSTest.Analyzers/3.9.3) +* MSTest.Sdk: [3.9.3](https://www.nuget.org/packages/MSTest.Sdk/3.9.3) +* Microsoft.Testing.Extensions.CrashDump: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.7.3) +* Microsoft.Testing.Extensions.HangDump: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.7.3) +* Microsoft.Testing.Extensions.HotReload: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.7.3) +* Microsoft.Testing.Extensions.Retry: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.7.3) +* Microsoft.Testing.Extensions.TrxReport: [1.7.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.7.3) +* Microsoft.Testing.Extensions.AzureDevOpsReport [1.0.0-alpha.25317.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.AzureDevOpsReport/1.0.0-alpha.25317.1) +* MSTest.SourceGeneration: [1.0.0-alpha.25317.1](https://www.nuget.org/packages/MSTest.SourceGeneration/1.0.0-alpha.25317.1) +* MSTest.Engine: [1.0.0-alpha.25317.1](https://www.nuget.org/packages/MSTest.Engine/1.0.0-alpha.25317.1) + +## [3.9.2] - 2025-06-10 + +See full log [of v3.9.1...v3.9.2](https://github.com/microsoft/testfx/compare/v3.9.1...v3.9.2) + +### Fixed + +* Fix MSTEST0042 (duplicate data row) false positive with Zero/NegativeZero by @Youssef1313 in [#5684](https://github.com/microsoft/testfx/pull/5684) +* Ensure TestMethodAttribute.Execute is run on the correct execution context by @Youssef1313 in [#5688](https://github.com/microsoft/testfx/pull/5688) +* Avoid loading System.Threading.Tasks.Extensions when not needed by @Youssef1313 in [#5694](https://github.com/microsoft/testfx/pull/5694) +* Fix UseAsync property in TestMethodAttribute derived classes to use type checks by @Youssef1313 and @Copilot in [#5708](https://github.com/microsoft/testfx/pull/5708) +* Fix UnitTestRunner leaking some test class instances by @Youssef1313 in [#5715](https://github.com/microsoft/testfx/pull/5715) + +### Artifacts + +* MSTest: [3.9.2](https://www.nuget.org/packages/MSTest/3.9.2) +* MSTest.TestFramework: [3.9.2](https://www.nuget.org/packages/MSTest.TestFramework/3.9.2) +* MSTest.TestAdapter: [3.9.2](https://www.nuget.org/packages/MSTest.TestAdapter/3.9.2) +* MSTest.Analyzers: [3.9.2](https://www.nuget.org/packages/MSTest.Analyzers/3.9.2) +* MSTest.Sdk: [3.9.2](https://www.nuget.org/packages/MSTest.Sdk/3.9.2) +* Microsoft.Testing.Extensions.CrashDump: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.7.2) +* Microsoft.Testing.Extensions.HangDump: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.7.2) +* Microsoft.Testing.Extensions.HotReload: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.7.2) +* Microsoft.Testing.Extensions.Retry: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.7.2) +* Microsoft.Testing.Extensions.TrxReport: [1.7.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.7.2) +* Microsoft.Testing.Extensions.AzureDevOpsReport [1.0.0-alpha.25310.6](https://www.nuget.org/packages/Microsoft.Testing.Extensions.AzureDevOpsReport/1.0.0-alpha.25310.6) +* MSTest.SourceGeneration: [1.0.0-alpha.25310.6](https://www.nuget.org/packages/MSTest.SourceGeneration/1.0.0-alpha.25310.6) +* MSTest.Engine: [1.0.0-alpha.25310.6](https://www.nuget.org/packages/MSTest.Engine/1.0.0-alpha.25310.6) + +## [3.9.1] - 2025-05-27 + +See full log [of v3.9.0...v3.9.1](https://github.com/microsoft/testfx/compare/v3.9.0...v3.9.1) + +### Fixed + +* Make ConditionBaseAttribute.Mode public by @Youssef1313 in [#5581](https://github.com/microsoft/testfx/pull/5581) +* Add missing overload for Assert.Throws by @Youssef1313 in [#5619](https://github.com/microsoft/testfx/pull/5619) +* Fix System.MissingMethodException for KeyValuePair Deconstruction by @Youssef1313 in [#5633](https://github.com/microsoft/testfx/pull/5633) +* Run the whole ExecuteInternal logic under the right execution context by @Youssef1313 in [#5636](https://github.com/microsoft/testfx/pull/5636) + +### Artifacts + +* MSTest: [3.9.1](https://www.nuget.org/packages/MSTest/3.9.1) +* MSTest.TestFramework: [3.9.1](https://www.nuget.org/packages/MSTest.TestFramework/3.9.1) +* MSTest.TestAdapter: [3.9.1](https://www.nuget.org/packages/MSTest.TestAdapter/3.9.1) +* MSTest.Analyzers: [3.9.1](https://www.nuget.org/packages/MSTest.Analyzers/3.9.1) +* MSTest.Sdk: [3.9.1](https://www.nuget.org/packages/MSTest.Sdk/3.9.1) +* Microsoft.Testing.Extensions.CrashDump: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.7.1) +* Microsoft.Testing.Extensions.HangDump: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.7.1) +* Microsoft.Testing.Extensions.HotReload: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.7.1) +* Microsoft.Testing.Extensions.Retry: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.7.1) +* Microsoft.Testing.Extensions.TrxReport: [1.7.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.7.1) +* Microsoft.Testing.Extensions.AzureDevOpsReport [1.0.0-alpha.25277.3](https://www.nuget.org/packages/Microsoft.Testing.Extensions.AzureDevOpsReport/1.0.0-alpha.25277.3) +* MSTest.SourceGeneration: [1.0.0-alpha.25277.3](https://www.nuget.org/packages/MSTest.SourceGeneration/1.0.0-alpha.25277.3) +* MSTest.Engine: [1.0.0-alpha.25277.3](https://www.nuget.org/packages/MSTest.Engine/1.0.0-alpha.25277.3) + +## [3.9.0] - 2025-05-20 + +See full log [of v3.8.3...v3.9.0](https://github.com/microsoft/testfx/compare/v3.8.3...v3.9.0) + +### Added + +* Allow async test methods for UITestMethod on UWP and WinUI by @Youssef1313 in [#5297](https://github.com/microsoft/testfx/pull/5297) +* Add analyzer for duplicate data row by @Youssef1313 in [#5144](https://github.com/microsoft/testfx/pull/5144) +* Add `Func` overloads for Assert.Throws[Exactly] by @Youssef1313 in [#5313](https://github.com/microsoft/testfx/pull/5313) +* Add TestRunCount to TestContext by @Youssef1313 in [#5425](https://github.com/microsoft/testfx/pull/5425) + +### Fixed + +* Fix ClassCleanup not called when the first test in class is ignored by @Youssef1313 in [#5070](https://github.com/microsoft/testfx/pull/5070) +* Write warnings outside of appdomain by @nohwnd in [#5371](https://github.com/microsoft/testfx/pull/5371) +* Fix MSTEST0038 message by @Youssef1313 in [#5008](https://github.com/microsoft/testfx/pull/5008) +* Fix parameterized test treated as ignored when using VSTest in Test Explorer by @Youssef1313 in [#5020](https://github.com/microsoft/testfx/pull/5020) +* Avoid handling tuples for test methods with only object[] parameter by @Youssef1313 in [#5013](https://github.com/microsoft/testfx/pull/5013) +* Follow-up to ignore fix by @Youssef1313 in [#5042](https://github.com/microsoft/testfx/pull/5042) +* Fix discard handling for newer Assert.Throws codefix by @Youssef1313 in [#5117](https://github.com/microsoft/testfx/pull/5117) +* Ship props/targets of MSTest.TestFramework and MSTest.TestAdapter in both build and buildTransitive by @Youssef1313 in [#5220](https://github.com/microsoft/testfx/pull/5220) +* Fix TestFailedException outcome not propagating to TestResult outcome by @Youssef1313 in [#5236](https://github.com/microsoft/testfx/pull/5236) +* Fix stackoverflow in Assert.DoesNotContain by @Youssef1313 in [#5275](https://github.com/microsoft/testfx/pull/5275) +* Fix typo in docs for StringAssert.That by @YoshiRulz in [#5281](https://github.com/microsoft/testfx/pull/5281) +* Fix TypeCache re-calculating info when running in parallel by @Youssef1313 in [#5291](https://github.com/microsoft/testfx/pull/5291) +* Fix test property not considering the test class correctly by @Youssef1313 in [#5293](https://github.com/microsoft/testfx/pull/5293) +* Fix typo in TestMethodAttribute documentation by @bjornhellander in [#5300](https://github.com/microsoft/testfx/pull/5300) +* Fix parameterized UI tests for WinUI by @Youssef1313 in [#5305](https://github.com/microsoft/testfx/pull/5305) +* Fix MSTEST0032 false positive with nullability analysis by @Youssef1313 in [#5315](https://github.com/microsoft/testfx/pull/5315) +* Move System.Threading.Tasks.Extensions to TestFramework by @Youssef1313 in [#5330](https://github.com/microsoft/testfx/pull/5330) +* remove redundant null check in WriteExceptionAsync by @SimonCropp in [#5393](https://github.com/microsoft/testfx/pull/5393) +* remove redundant null checks in DeploymentItemUtility by @SimonCropp in [#5399](https://github.com/microsoft/testfx/pull/5399) +* add disable CS0618 to MSTestSettingsTests by @SimonCropp in [#5389](https://github.com/microsoft/testfx/pull/5389) +* remove redundant catch by @SimonCropp in [#5376](https://github.com/microsoft/testfx/pull/5376) +* remove redundant ReflectHelper constructor by @SimonCropp in [#5379](https://github.com/microsoft/testfx/pull/5379) +* remove redundant braces and mark as error in rider and R# by @SimonCropp in [#5380](https://github.com/microsoft/testfx/pull/5380) +* avoid redundant where and mark as an error for rider and r# by @SimonCropp in [#5384](https://github.com/microsoft/testfx/pull/5384) +* Update MSTestSettingsTests.cs by @SimonCropp in [#5388](https://github.com/microsoft/testfx/pull/5388) +* remove redundant null checks in UnitTestRunnerTests by @SimonCropp in [#5390](https://github.com/microsoft/testfx/pull/5390) +* remove redundant null checks in AssemblyEnumeratorTests by @SimonCropp in [#5391](https://github.com/microsoft/testfx/pull/5391) +* remove redundant null check in UnitTestElement by @SimonCropp in [#5400](https://github.com/microsoft/testfx/pull/5400) +* fix nullability in TestableMSTestAdapterSettings by @SimonCropp in [#5387](https://github.com/microsoft/testfx/pull/5387) +* Downgrade error entries in .editorconfig to warning by @Youssef1313 in [#5416](https://github.com/microsoft/testfx/pull/5416) +* Conditional expression can be rewritten as null-coalescing and mark as warning by @SimonCropp in [#5429](https://github.com/microsoft/testfx/pull/5429) +* remove un-used IParameterInfo by @SimonCropp in [#5431](https://github.com/microsoft/testfx/pull/5431) +* remove Trimming, AOT, and SingleFile config from MSTest.SourceGeneration by @SimonCropp in [#5433](https://github.com/microsoft/testfx/pull/5433) +* Add test for TestContext.TestRunCount by @Youssef1313 in [#5440](https://github.com/microsoft/testfx/pull/5440) +* Add test for TestProperty attribute by @Youssef1313 in [#5439](https://github.com/microsoft/testfx/pull/5439) +* remove dead code from SourceGeneration by @SimonCropp in [#5446](https://github.com/microsoft/testfx/pull/5446) +* use-char-based-replace-in-string by @SimonCropp in [#5447](https://github.com/microsoft/testfx/pull/5447) +* remove un-used static class EquatableArray by @SimonCropp in [#5445](https://github.com/microsoft/testfx/pull/5445) +* Fix exception in assembly initialize shown as aggregate exception by @Youssef1313 in [#5498](https://github.com/microsoft/testfx/pull/5498) +* Skip analyzing TestContext fields that are generated via primary constructor parameters by @Youssef1313 in [#5501](https://github.com/microsoft/testfx/pull/5501) +* Fix MSTEST0017 (actual/expected order) false negative for conversions by @Youssef1313 in [#5502](https://github.com/microsoft/testfx/pull/5502) +* Avoid overwriting TestFailureException by @Youssef1313 in [#5505](https://github.com/microsoft/testfx/pull/5505) +* Add some unit tests for Assert.Contains/DoesNotContain by @Evangelink in [#5541](https://github.com/microsoft/testfx/pull/5541) +* Fix false positive of Assert.IsTrue(x == null) when x is a pointer type by @Youssef1313 in [#5548](https://github.com/microsoft/testfx/pull/5548) + +### Artifacts + +* MSTest: [3.9.0](https://www.nuget.org/packages/MSTest/3.9.0) +* MSTest.TestFramework: [3.9.0](https://www.nuget.org/packages/MSTest.TestFramework/3.9.0) +* MSTest.TestAdapter: [3.9.0](https://www.nuget.org/packages/MSTest.TestAdapter/3.9.0) +* MSTest.Analyzers: [3.9.0](https://www.nuget.org/packages/MSTest.Analyzers/3.9.0) +* MSTest.Sdk: [3.9.0](https://www.nuget.org/packages/MSTest.Sdk/3.9.0) +* Microsoft.Testing.Extensions.CrashDump: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.7.0) +* Microsoft.Testing.Extensions.HangDump: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.7.0) +* Microsoft.Testing.Extensions.HotReload: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.7.0) +* Microsoft.Testing.Extensions.Retry: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.7.0) +* Microsoft.Testing.Extensions.TrxReport: [1.7.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.7.0) +* Microsoft.Testing.Extensions.AzureDevOpsReport [1.0.0-alpha.25256.6](https://www.nuget.org/packages/Microsoft.Testing.Extensions.AzureDevOpsReport/1.0.0-alpha.25256.6) +* MSTest.SourceGeneration: [1.0.0-alpha.25256.6](https://www.nuget.org/packages/MSTest.SourceGeneration/1.0.0-alpha.25256.6) +* MSTest.Engine: [1.0.0-alpha.25256.6](https://www.nuget.org/packages/MSTest.Engine/1.0.0-alpha.25256.6) + ## [3.8.3] - 2025-03-17 -See full log [here](https://github.com/microsoft/testfx/compare/v3.8.2...v3.8.3) +See full log [of v3.8.2...v3.8.3](https://github.com/microsoft/testfx/compare/v3.8.2...v3.8.3) ### Fixed @@ -33,7 +186,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.8.2...v3.8.3) ## [3.8.2] - 2025-02-19 -See full log [here](https://github.com/microsoft/testfx/compare/v3.8.1...v3.8.2) +See full log [of v3.8.1...v3.8.2](https://github.com/microsoft/testfx/compare/v3.8.1...v3.8.2) ### Fixed @@ -56,7 +209,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.8.1...v3.8.2) ## [3.8.1] - 2025-02-18 -See full log [here](https://github.com/microsoft/testfx/compare/v3.8.0...v3.8.1) +See full log [of v3.8.0...v3.8.1](https://github.com/microsoft/testfx/compare/v3.8.0...v3.8.1) ### Fixed @@ -83,7 +236,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.8.0...v3.8.1) ## [3.8.0] - 2025-02-12 -See full log [here](https://github.com/microsoft/testfx/compare/v3.7.3...v3.8.0) +See full log [of v3.7.3...v3.8.0](https://github.com/microsoft/testfx/compare/v3.7.3...v3.8.0) ### Added @@ -194,7 +347,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.7.3...v3.8.0) ## [3.7.3] - 2025-01-27 -See full log [here](https://github.com/microsoft/testfx/compare/v3.7.2...v3.7.3) +See full log [of v3.7.2...v3.7.3](https://github.com/microsoft/testfx/compare/v3.7.2...v3.7.3) ### Fixed @@ -215,7 +368,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.7.2...v3.7.3) ## [3.7.2] - 2025-01-21 -See full log [here](https://github.com/microsoft/testfx/compare/v3.7.1...v3.7.2) +See full log [of v3.7.1...v3.7.2](https://github.com/microsoft/testfx/compare/v3.7.1...v3.7.2) ### Fixed @@ -237,7 +390,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.7.1...v3.7.2) ## [3.7.1] - 2024-01-13 -See full log [here](https://github.com/microsoft/testfx/compare/v3.7.0...v3.7.1) +See full log [of v3.7.0...v3.7.1](https://github.com/microsoft/testfx/compare/v3.7.0...v3.7.1) ### Fixed @@ -266,7 +419,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.7.0...v3.7.1) ## [3.7.0] - 2024-12-20 -See full log [here](https://github.com/microsoft/testfx/compare/v3.6.4...v3.7.0) +See full log [of v3.6.4...v3.7.0](https://github.com/microsoft/testfx/compare/v3.6.4...v3.7.0) ### Added @@ -396,7 +549,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.6.4...v3.7.0) ## [3.6.4] - 2024-12-03 -See full log [here](https://github.com/microsoft/testfx/compare/v3.6.3...v3.6.4) +See full log [of v3.6.3...v3.6.4](https://github.com/microsoft/testfx/compare/v3.6.3...v3.6.4) ### Fixed @@ -418,7 +571,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.6.3...v3.6.4) ## [3.6.3] - 2024-11-12 -See full log [here](https://github.com/microsoft/testfx/compare/v3.6.2...v3.6.3) +See full log [of v3.6.2...v3.6.3](https://github.com/microsoft/testfx/compare/v3.6.2...v3.6.3) ### Fixed @@ -439,7 +592,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.6.2...v3.6.3) ## [3.6.2] - 2024-10-31 -See full log [here](https://github.com/microsoft/testfx/compare/v3.6.1...v3.6.2) +See full log [of v3.6.1...v3.6.2](https://github.com/microsoft/testfx/compare/v3.6.1...v3.6.2) ### Fixed @@ -465,7 +618,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.6.1...v3.6.2) ## [3.6.1] - 2024-10-03 -See full log [here](https://github.com/microsoft/testfx/compare/v3.6.0...v3.6.1) +See full log [of v3.6.0...v3.6.1](https://github.com/microsoft/testfx/compare/v3.6.0...v3.6.1) ### Fixed @@ -492,7 +645,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.6.0...v3.6.1) ## [3.6.0] - 2024-09-11 -See full log [here](https://github.com/microsoft/testfx/compare/v3.5.2...v3.6.0) +See full log [of v3.5.2...v3.6.0](https://github.com/microsoft/testfx/compare/v3.5.2...v3.6.0) ### Added @@ -576,7 +729,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.5.2...v3.6.0) ## [3.5.2] - 2024-08-13 -See full log [here](https://github.com/microsoft/testfx/compare/v3.5.1...v3.5.2) +See full log [of v3.5.1...v3.5.2](https://github.com/microsoft/testfx/compare/v3.5.1...v3.5.2) ### Fixed @@ -597,7 +750,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.5.1...v3.5.2) ## [3.5.1] - 2024-08-05 -See full log [here](https://github.com/microsoft/testfx/compare/v3.5.0...v3.5.1) +See full log [of v3.5.0...v3.5.1](https://github.com/microsoft/testfx/compare/v3.5.0...v3.5.1) ### Fixed @@ -620,7 +773,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.5.0...v3.5.1) ## [3.5.0] - 2024-07-15 -See full log [here](https://github.com/microsoft/testfx/compare/v3.4.3...v3.5.0) +See full log [of v3.4.3...v3.5.0](https://github.com/microsoft/testfx/compare/v3.4.3...v3.5.0) ### Added @@ -724,7 +877,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.4.3...v3.5.0) ## [3.4.3] - 2024-05-30 -See full log [here](https://github.com/microsoft/testfx/compare/v3.4.2...v3.4.3) +See full log [of v3.4.2...v3.4.3](https://github.com/microsoft/testfx/compare/v3.4.2...v3.4.3) ### Fixed @@ -745,7 +898,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.4.2...v3.4.3) ## [3.4.2] - 2024-05-30 -See full log [here](https://github.com/microsoft/testfx/compare/v3.4.1...v3.4.2) +See full log [of v3.4.1...v3.4.2](https://github.com/microsoft/testfx/compare/v3.4.1...v3.4.2) ### Fixed @@ -768,7 +921,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.4.1...v3.4.2) ## [3.4.1] - 2024-05-27 -See full log [here](https://github.com/microsoft/testfx/compare/v3.4.0...v3.4.1) +See full log [of v3.4.0...v3.4.1](https://github.com/microsoft/testfx/compare/v3.4.0...v3.4.1) ### Fixed @@ -789,7 +942,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.4.0...v3.4.1) ## [3.4.0] - 2024-05-23 -See full log [here](https://github.com/microsoft/testfx/compare/v3.3.1...v3.4.0) +See full log [of v3.3.1...v3.4.0](https://github.com/microsoft/testfx/compare/v3.3.1...v3.4.0) ### Added @@ -884,7 +1037,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.3.1...v3.4.0) ## [3.3.1] - 2024-04-04 -See full log [here](https://github.com/microsoft/testfx/compare/v3.3.0...v3.3.1) +See full log [of v3.3.0...v3.3.1](https://github.com/microsoft/testfx/compare/v3.3.0...v3.3.1) ### Fixed @@ -905,7 +1058,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.3.0...v3.3.1) ## [3.3.0] - 2024-04-03 -See full log [here](https://github.com/microsoft/testfx/compare/v3.2.2...v3.3.0) +See full log [of v3.2.2...v3.3.0](https://github.com/microsoft/testfx/compare/v3.2.2...v3.3.0) ### Added @@ -978,7 +1131,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.2.2...v3.3.0) ## [3.2.2] - 2024-02-22 -See full log [here](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2) +See full log [of v3.2.1...v3.2.2](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2) ### Fixed @@ -1002,7 +1155,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2) ## [3.2.1] - 2024-02-13 -See full log [here](https://github.com/microsoft/testfx/compare/v3.2.0...v.3.2.1) +See full log [of v3.2.0...v.3.2.1](https://github.com/microsoft/testfx/compare/v3.2.0...v.3.2.1) ### Fixed @@ -1032,7 +1185,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.2.0...v.3.2.1 ## [3.2.0] - 2024-01-24 -See full log [here](https://github.com/microsoft/testfx/compare/v3.1.1...v.3.2.0) +See full log [of v3.1.1...v.3.2.0](https://github.com/microsoft/testfx/compare/v3.1.1...v.3.2.0) ### Added @@ -1113,7 +1266,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.1.1...v.3.2.0 ## [3.2.0-preview.24069.3] - 2024-01-19 -See full log [here](https://github.com/microsoft/testfx/compare/v3.2.0-preview.23623.1...v3.2.0-preview.24069.3) +See full log [of v3.2.0-preview.23623.1...v3.2.0-preview.24069.3](https://github.com/microsoft/testfx/compare/v3.2.0-preview.23623.1...v3.2.0-preview.24069.3) ### Added @@ -1166,7 +1319,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.2.0-preview.2 ## [3.2.0-preview.23623.1] - 2023-12-23 -See full log [here](https://github.com/Microsoft/testfx/compare/v3.2.0-preview.23622.1...3.2.0-preview.23623.1) +See full log [of v3.2.0-preview.23622.1...3.2.0-preview.23623.1](https://github.com/microsoft/testfx/compare/v3.2.0-preview.23622.1...3.2.0-preview.23623.1) ### Fixed @@ -1181,7 +1334,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.2.0-preview.2 ## [3.2.0-preview.23622.1] - 2023-12-22 -See full log [here](https://github.com/Microsoft/testfx/compare/v3.1.1...v3.2.0-preview.23622.1) +See full log [of v3.1.1...v3.2.0-preview.23622.1](https://github.com/microsoft/testfx/compare/v3.1.1...v3.2.0-preview.23622.1) ### Added @@ -1233,7 +1386,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.1.1...v3.2.0- * Artifact `3.1.0` was corrupted during pipeline and for security reasons we cannot regenerate it. -See full log [here](https://github.com/Microsoft/testfx/compare/v3.1.0...v3.1.1) +See full log [of v3.1.0...v3.1.1](https://github.com/microsoft/testfx/compare/v3.1.0...v3.1.1) ### Artifacts @@ -1243,7 +1396,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.1.0...v3.1.1) ## [3.1.0] - 2023-07-14 -See full log [here](https://github.com/Microsoft/testfx/compare/v3.0.4...v3.1.0) +See full log [of v3.0.4...v3.1.0](https://github.com/microsoft/testfx/compare/v3.0.4...v3.1.0) ### Added @@ -1289,7 +1442,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.0.4...v3.1.0) ## [3.0.4] - 2023-06-01 -See full log [here](https://github.com/microsoft/testfx/compare/v3.0.3...v3.0.4) +See full log [of v3.0.3...v3.0.4](https://github.com/microsoft/testfx/compare/v3.0.3...v3.0.4) ### Fixed @@ -1304,7 +1457,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.0.3...v3.0.4) ## [3.0.3] - 2023-05-24 -See full log [here](https://github.com/Microsoft/testfx/compare/v3.0.2...v3.0.3) +See full log [of v3.0.2...v3.0.3](https://github.com/microsoft/testfx/compare/v3.0.2...v3.0.3) ### Changed @@ -1325,7 +1478,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.0.2...v3.0.3) ## [3.0.2] - 2022-12-27 -See full log [here](https://github.com/microsoft/testfx/compare/v3.0.1...v3.0.2) +See full log [of v3.0.1...v3.0.2](https://github.com/microsoft/testfx/compare/v3.0.1...v3.0.2) ### Fixed @@ -1339,7 +1492,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.0.1...v3.0.2) ## [3.0.1] - 2022-12-20 -See full log [here](https://github.com/microsoft/testfx/compare/v3.0.0...v3.0.1) +See full log [of v3.0.0...v3.0.1](https://github.com/microsoft/testfx/compare/v3.0.0...v3.0.1) ### Fixed @@ -1362,7 +1515,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.0.0...v3.0.1) ## [3.0.0] - 2022-12-06 -See full log [here](https://github.com/microsoft/testfx/compare/v2.2.10...v3.0.0) +See full log [of v2.2.10...v3.0.0](https://github.com/microsoft/testfx/compare/v2.2.10...v3.0.0) Breaking changes announcements [#1274](https://github.com/microsoft/testfx/issues/1274) @@ -1419,7 +1572,7 @@ Breaking changes announcements [#1274](https://github.com/microsoft/testfx/issue ## [3.0.0-preview-20221122-01] - 2022-11-23 -See full log [here](https://github.com/microsoft/testfx/compare/v3.0.0-preview-20221110-04...v3.0.0-preview-20221122-01) +See full log [of v3.0.0-preview-20221110-04...v3.0.0-preview-20221122-01](https://github.com/microsoft/testfx/compare/v3.0.0-preview-20221110-04...v3.0.0-preview-20221122-01) ### Added @@ -1463,7 +1616,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.0.0-preview-2 ## [3.0.0-preview-20221110-04] - 2022-11-11 -See full log [here](https://github.com/microsoft/testfx/compare/v2.3.0-preview-20220810-02...v3.0.0-preview-20221110-04) +See full log [of v2.3.0-preview-20220810-02...v3.0.0-preview-20221110-04](https://github.com/microsoft/testfx/compare/v2.3.0-preview-20220810-02...v3.0.0-preview-20221110-04) ### Added @@ -1596,7 +1749,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v2.3.0-preview-2 ## [2.3.0-preview-20220810-02] 2022-08-10 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.10...v2.3.0-preview-20220810-02) +A list of changes since last release are available [of v2.2.10...v2.3.0-preview-20220810-02](https://github.com/microsoft/testfx/compare/v2.2.10...v2.3.0-preview-20220810-02) ### Added @@ -1629,7 +1782,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.10] - 2022-04-26 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.10-preview-20220414-01...v2.2.10) +A list of changes since last release are available [of v2.2.10-preview-20220414-01...v2.2.10](https://github.com/microsoft/testfx/compare/v2.2.10-preview-20220414-01...v2.2.10) ### Added @@ -1669,7 +1822,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.9] 2022-04-08 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.8...v2.2.9) +A list of changes since last release are available [of v2.2.8...v2.2.9](https://github.com/microsoft/testfx/compare/v2.2.8...v2.2.9) ### Parallel output @@ -1703,7 +1856,7 @@ Due to the way that class and assembly initialize, and cleanup are invoked, thei ## [2.2.8] - 2021-11-23 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.7...v2.2.8) +A list of changes since last release are available [of v2.2.7...v2.2.8](https://github.com/microsoft/testfx/compare/v2.2.7...v2.2.8) ### Added @@ -1735,7 +1888,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.7] - 2021-09-03 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.6...v2.2.7) +A list of changes since last release are available [of v2.2.6...v2.2.7](https://github.com/microsoft/testfx/compare/v2.2.6...v2.2.7) ### Changed @@ -1752,7 +1905,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.6] - 2021-08-25 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.5...v2.2.6) +A list of changes since last release are available [of v2.2.5...v2.2.6](https://github.com/microsoft/testfx/compare/v2.2.5...v2.2.6) ### Changed @@ -1770,7 +1923,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.5] - 2021-06-28 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.4...v2.2.5) +A list of changes since last release are available [of v2.2.4...v2.2.5](https://github.com/microsoft/testfx/compare/v2.2.4...v2.2.5) ### Added @@ -1795,7 +1948,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.4] - 2021-05-25 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/0b95a26282eae17f896d732381e5c77b9a603382...v2.2.4) +A list of changes since last release are available [of 0b95a26282eae17f896d732381e5c77b9a603382...v2.2.4](https://github.com/microsoft/testfx/compare/0b95a26282eae17f896d732381e5c77b9a603382...v2.2.4) ### Artifacts @@ -1804,7 +1957,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.4-preview-20210331-02] - 2021-04-02 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.3...v2.2.4-preview-20210331-02) +A list of changes since last release are available [of v2.2.3...v2.2.4-preview-20210331-02](https://github.com/microsoft/testfx/compare/v2.2.3...v2.2.4-preview-20210331-02) ### Added @@ -1826,7 +1979,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.3] - 2021-03-16 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.2...v2.2.3) +A list of changes since last release are available [of v2.2.2...v2.2.3](https://github.com/microsoft/testfx/compare/v2.2.2...v2.2.3) ### Added @@ -1839,7 +1992,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.2] - 2021-03-15 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.1...v2.2.2) +A list of changes since last release are available [of v2.2.1...v2.2.2](https://github.com/microsoft/testfx/compare/v2.2.1...v2.2.2) ### Added @@ -1858,7 +2011,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.1] - 2021-03-01 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.0-preview-20210115-03...v2.2.1) +A list of changes since last release are available [of v2.2.0-preview-20210115-03...v2.2.1](https://github.com/microsoft/testfx/compare/v2.2.0-preview-20210115-03...v2.2.1) ### Added @@ -1887,7 +2040,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.0-preview-20210115-03] - 2021-01-20 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.2.0-preview-20201126-03...v2.2.0-preview-20210115-03) +A list of changes since last release are available [of v2.2.0-preview-20201126-03...v2.2.0-preview-20210115-03](https://github.com/microsoft/testfx/compare/v2.2.0-preview-20201126-03...v2.2.0-preview-20210115-03) ### Changed @@ -1914,7 +2067,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.2.0-preview-20201126-03] - 2020-11-26 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.1.2...v2.2.0-preview-20201126-03) +A list of changes since last release are available [of v2.1.2...v2.2.0-preview-20201126-03](https://github.com/microsoft/testfx/compare/v2.1.2...v2.2.0-preview-20201126-03) ### Added @@ -1944,7 +2097,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.1.2] - 2020-06-08 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.1.1...v2.1.2) +A list of changes since last release are available [of v2.1.1...v2.1.2](https://github.com/microsoft/testfx/compare/v2.1.1...v2.1.2) ### Changed @@ -1965,7 +2118,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.1.1] - 2020-04-01 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.1.0...v2.1.1) +A list of changes since last release are available [of v2.1.0...v2.1.1](https://github.com/microsoft/testfx/compare/v2.1.0...v2.1.1) ### Added @@ -1992,7 +2145,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.1.0] - 2020-02-03 -A list of changes since last release are available [here](https://github.com/microsoft/testfx/compare/v2.1.0-beta2...v2.1.0) +A list of changes since last release are available [of v2.1.0-beta2...v2.1.0](https://github.com/microsoft/testfx/compare/v2.1.0-beta2...v2.1.0) ### Changed @@ -2010,7 +2163,7 @@ A list of changes since last release are available [here](https://github.com/mic ## [2.1.0-beta2] - 2019-12-18 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v2.1.0-beta...v2.1.0-beta2) +A list of changes since last release are available [of v2.1.0-beta...v2.1.0-beta2](https://github.com/microsoft/testfx/compare/v2.1.0-beta...v2.1.0-beta2) ### Changed @@ -2023,7 +2176,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [2.1.0-beta] - 2019-11-28 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v2.0.0...v2.1.0-beta) +A list of changes since last release are available [of v2.0.0...v2.1.0-beta](https://github.com/microsoft/testfx/compare/v2.0.0...v2.1.0-beta) ### Fixed @@ -2037,7 +2190,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [2.0.0] 2019-09-03 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v2.0.0-beta4...v2.0.0) +A list of changes since last release are available [of v2.0.0-beta4...v2.0.0](https://github.com/microsoft/testfx/compare/v2.0.0-beta4...v2.0.0) ### Added @@ -2061,7 +2214,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [2.0.0-beta4] - 2019-04-10 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/2.0.0-beta2...v2.0.0-beta4) +A list of changes since last release are available [of 2.0.0-beta2...v2.0.0-beta4](https://github.com/microsoft/testfx/compare/2.0.0-beta2...v2.0.0-beta4) ### Changed @@ -2076,7 +2229,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [2.0.0-beta2] - 2019-02-15 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/1.4.0...2.0.0-beta2) +A list of changes since last release are available [of 1.4.0...2.0.0-beta2](https://github.com/microsoft/testfx/compare/1.4.0...2.0.0-beta2) ### Changed @@ -2091,7 +2244,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.4.0] - 2018-11-26 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/1.4.0-beta...1.4.0) +A list of changes since last release are available [of 1.4.0-beta...1.4.0](https://github.com/microsoft/testfx/compare/1.4.0-beta...1.4.0) ### Added @@ -2113,7 +2266,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.4.0-beta] 2018-10-17 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/1.3.2...1.4.0-beta) +A list of changes since last release are available [of 1.3.2...1.4.0-beta](https://github.com/microsoft/testfx/compare/1.3.2...1.4.0-beta) ### Added @@ -2131,7 +2284,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.3.2] - 2018-06-06 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.3.1...v1.3.2) +A list of changes since last release are available [of v1.3.1...v1.3.2](https://github.com/microsoft/testfx/compare/v1.3.1...v1.3.2) ### Changed @@ -2144,7 +2297,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.3.1] - 2018-05-25 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.3.0...v1.3.1) +A list of changes since last release are available [of v1.3.0...v1.3.1](https://github.com/microsoft/testfx/compare/v1.3.0...v1.3.1) ### Changed @@ -2158,7 +2311,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.3.0] - 2018-05-11 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.2.1...v1.3.0) +A list of changes since last release are available [of v1.2.1...v1.3.0](https://github.com/microsoft/testfx/compare/v1.2.1...v1.3.0) ### Changed @@ -2180,7 +2333,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.3.0-beta2] - 2018-01-15 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.2.0...v1.3.0-beta2) +A list of changes since last release are available [of v1.2.0...v1.3.0-beta2](https://github.com/microsoft/testfx/compare/v1.2.0...v1.3.0-beta2) ### Added @@ -2223,7 +2376,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.2.0] - 2017-10-11 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.2.0-beta3...v1.2.0) +A list of changes since last release are available [of v1.2.0-beta3...v1.2.0](https://github.com/microsoft/testfx/compare/v1.2.0-beta3...v1.2.0) ### Added @@ -2243,7 +2396,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.2.0-beta3] - 2017-08-09 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.2.0-beta...v1.2.0-beta3) +A list of changes since last release are available [of v1.2.0-beta...v1.2.0-beta3](https://github.com/microsoft/testfx/compare/v1.2.0-beta...v1.2.0-beta3) ### Added @@ -2263,7 +2416,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.2.0-beta] - 2017-06-29 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.1.18...v1.2.0-beta) +A list of changes since last release are available [of v1.1.18...v1.2.0-beta](https://github.com/microsoft/testfx/compare/v1.1.18...v1.2.0-beta) ### Changed @@ -2278,7 +2431,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.1.18] - 2017-06-01 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.1.17...v1.1.18) +A list of changes since last release are available [of v1.1.17...v1.1.18](https://github.com/microsoft/testfx/compare/v1.1.17...v1.1.18) ### Changed @@ -2296,7 +2449,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.1.17] - 2017-04-21 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.1.14...v1.1.17) +A list of changes since last release are available [of v1.1.14...v1.1.17](https://github.com/microsoft/testfx/compare/v1.1.14...v1.1.17) ### Changed @@ -2314,7 +2467,7 @@ A list of changes since last release are available [here](https://github.com/Mic ## [1.1.14] - 2017-03-31 -A list of changes since last release are available [here](https://github.com/Microsoft/testfx/compare/v1.1.13...v1.1.14) +A list of changes since last release are available [of v1.1.13...v1.1.14](https://github.com/microsoft/testfx/compare/v1.1.13...v1.1.14) ### Changed diff --git a/docs/README.md b/docs/README.md index 5096491634..f476da5c8e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,7 @@ The following official [learn.microsoft.com website](https://learn.microsoft.com This [blog post](https://devblogs.microsoft.com/devops/mstest-v2-now-and-ahead/) announces the vision for MSTest V2. -For API documentation refer [here](https://docs.microsoft.com/dotnet/api/microsoft.visualstudio.testtools.unittesting). +For API documentation refer [to Microsoft Documentation](https://docs.microsoft.com/dotnet/api/microsoft.visualstudio.testtools.unittesting). ## Contributing diff --git a/docs/RFCs/007-DataSource-Attribute-VS-ITestDataSource.md b/docs/RFCs/007-DataSource-Attribute-VS-ITestDataSource.md index c5e08d9f65..e40cc02454 100644 --- a/docs/RFCs/007-DataSource-Attribute-VS-ITestDataSource.md +++ b/docs/RFCs/007-DataSource-Attribute-VS-ITestDataSource.md @@ -7,7 +7,7 @@ ## Summary -This details the MSTest V2 framework attribute "DataSource" for data driven tests where test data can be present in an excel file, xml file, sql database or OleDb. You can refer documentation [here](https://docs.microsoft.com/dotnet/api/microsoft.visualstudio.testtools.unittesting.datasourceattribute) for more details. +This details the MSTest V2 framework attribute "DataSource" for data driven tests where test data can be present in an excel file, xml file, sql database or OleDb. You can refer to documentation [of datasourceattribute here](https://docs.microsoft.com/dotnet/api/microsoft.visualstudio.testtools.unittesting.datasourceattribute) for more details. ## Motivation diff --git a/eng/Build.props b/eng/Build.props index 57aac3a459..559d7f3749 100644 --- a/eng/Build.props +++ b/eng/Build.props @@ -6,16 +6,12 @@ - + - - - - - + diff --git a/eng/TestingPlatformRunner/TestingPlatform.Runner.targets b/eng/TestingPlatformRunner/TestingPlatform.Runner.targets deleted file mode 100644 index 6088a84863..0000000000 --- a/eng/TestingPlatformRunner/TestingPlatform.Runner.targets +++ /dev/null @@ -1,91 +0,0 @@ - - - - <_TestEnvironment>%(TestToRun.EnvironmentDisplay) - <_TestAssembly>%(TestToRun.Identity) - <_TestRuntime>%(TestToRun.TestRuntime) - <_TestTimeout>%(TestToRun.TestTimeout) - <_TestRunnerAdditionalArguments>%(TestToRun.TestRunnerAdditionalArguments) - - - - <_TestResultDirectory>$([System.IO.Path]::GetDirectoryName('%(TestToRun.ResultsTrxPath)')) - <_TestResultTrxFileName>$([System.IO.Path]::GetFileName('%(TestToRun.ResultsTrxPath)')) - - - - <_TargetFileNameNoExt>$([System.IO.Path]::GetFileNameWithoutExtension('$(_TestAssembly)')) - <_TargetDir>$([System.IO.Path]::GetDirectoryName('$(_TestAssembly)'))\ - <_CoreRuntimeConfigPath>$(_TargetDir)$(_TargetFileNameNoExt).runtimeconfig.json - <_CoreDepsPath>$(_TargetDir)$(_TargetFileNameNoExt).deps.json - - <_TestRunner Condition="'%(TestToRun.Architecture)'=='x86' And Exists('$(DotNetRoot)x86\dotnet.exe')">$(DotNetRoot)x86\dotnet.exe - <_TestRunner Condition="'$(_TestRunner)'==''">$(DotNetTool) - - <_TestRunnerArgs>exec --depsfile "$(_CoreDepsPath)" --runtimeconfig "$(_CoreRuntimeConfigPath)" $(TestRuntimeAdditionalArguments) "$(_TestAssembly)" --report-trx --report-trx-filename "$(_TestResultTrxFileName)" --results-directory "$(_TestResultDirectory)" --report-azdo $(_TestRunnerAdditionalArguments) - - - - <_TestRunner Condition="'$(_TestRunner)'==''">$(_TestAssembly) - <_TestRunnerArgs>--results-directory "$(_TestResultDirectory)" $(_TestRunnerAdditionalArguments) - - - - <_TestRunnerCommand>"$(_TestRunner)" $(_TestRunnerArgs) - - - <_TestRunnerCommand Condition="'$(TestCaptureOutput)' != 'false'">$(_TestRunnerCommand) > "%(TestToRun.ResultsStdOutPath)" 2>&1 - - - - <_OutputFiles Include="%(TestToRun.ResultsTrxPath)" /> - <_OutputFiles Include="%(TestToRun.ResultsHtmlPath)" /> - <_OutputFiles Include="%(TestToRun.ResultsStdOutPath)" /> - - - - - - - - - - - - - - - - - - <_ResultsFileToDisplay>%(TestToRun.ResultsHtmlPath) - <_ResultsFileToDisplay Condition="!Exists('$(_ResultsFileToDisplay)')">%(TestToRun.ResultsStdOutPath) - - - - - - - - - - diff --git a/eng/TestingPlatformRunner/TestingPlatformRunner.targets b/eng/TestingPlatformRunner/TestingPlatformRunner.targets deleted file mode 100644 index 1814b7ea47..0000000000 --- a/eng/TestingPlatformRunner/TestingPlatformRunner.targets +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9372be8c7c..10799facb8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,21 +1,29 @@ - + https://github.com/dotnet/arcade - e46d1266547513110e67a3e4709fe8ecdfb20849 + e2fed65f9c524d12c64876194ae4ce177b935bb3 - + https://github.com/dotnet/arcade - e46d1266547513110e67a3e4709fe8ecdfb20849 + e2fed65f9c524d12c64876194ae4ce177b935bb3 - + https://github.com/dotnet/arcade - e46d1266547513110e67a3e4709fe8ecdfb20849 + e2fed65f9c524d12c64876194ae4ce177b935bb3 - + https://dev.azure.com/devdiv/DevDiv/_git/vs-code-coverage - 22fe23c5579dfe54e9ab651eb4d3b002d9d18d73 + 005149fac82d93baa64fa87c3bae1004c9cd11e1 + + + https://github.com/microsoft/testfx + f1ea405d3997a828d15f68be2c239e9053ccb038 + + + https://github.com/microsoft/testfx + f1ea405d3997a828d15f68be2c239e9053ccb038 diff --git a/eng/Versions.props b/eng/Versions.props index 73f0048b6b..543ac123ff 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,13 +1,16 @@ - 3.9.0 + 3.10.0 - 1.7.0 + 1.8.0 preview - 10.0.0-beta.25229.4 - 17.15.0-preview.25229.5 + 10.0.0-beta.25374.4 + 17.14.2 + + 3.10.0-preview.25374.11 + 1.8.0-preview.25374.11 diff --git a/eng/build.ps1 b/eng/build.ps1 index ea65bad4fc..ee14198255 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -29,11 +29,12 @@ Param( [switch] $nativeToolsOnMachine, [switch] $help, [switch] $vs, + [switch] $vscode, [switch] $installWindowsSdk, [Parameter(ValueFromRemainingArguments=$true)][String[]]$properties ) -if ($vs) { +if ($vs -or $vscode) { . $PSScriptRoot\common\tools.ps1 # This tells .NET Core to use the bootstrapped runtime @@ -54,8 +55,19 @@ if ($vs) { # Enables the logginc of Json RPC messages if diagnostic logging for Test Explorer is enabled in Visual Studio. $env:_TestingPlatformDiagnostics_=1; - # Launch Visual Studio with the locally defined environment variables - & "$PSScriptRoot\..\TestFx.sln" + if ($vs) { + # Launch Visual Studio with the locally defined environment variables + & "$PSScriptRoot\..\TestFx.slnx" + } else { + if (Get-Command code -ErrorAction Ignore) { + & code "$PSScriptRoot\.." + } elseif (Get-Command code-insiders -ErrorAction Ignore) { + & code-insiders "$PSScriptRoot\.." + } else { + Write-Error "VS Code not found. Please install it from https://code.visualstudio.com/" + return + } + } return } diff --git a/eng/common/build.ps1 b/eng/common/build.ps1 index 6b3be1916f..8cfee107e7 100644 --- a/eng/common/build.ps1 +++ b/eng/common/build.ps1 @@ -21,6 +21,7 @@ Param( [switch] $publish, [switch] $clean, [switch][Alias('pb')]$productBuild, + [switch]$fromVMR, [switch][Alias('bl')]$binaryLog, [switch][Alias('nobl')]$excludeCIBinarylog, [switch] $ci, @@ -74,6 +75,7 @@ function Print-Usage() { Write-Host " -nativeToolsOnMachine Sets the native tools on machine environment variable (indicating that the script should use native tools on machine)" Write-Host " -nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')" Write-Host " -buildCheck Sets /check msbuild parameter" + Write-Host " -fromVMR Set when building from within the VMR" Write-Host "" Write-Host "Command line arguments not listed above are passed thru to msbuild." @@ -127,7 +129,8 @@ function Build { /p:Deploy=$deploy ` /p:Test=$test ` /p:Pack=$pack ` - /p:DotNetBuildRepo=$productBuild ` + /p:DotNetBuild=$productBuild ` + /p:DotNetBuildFromVMR=$fromVMR ` /p:IntegrationTest=$integrationTest ` /p:PerformanceTest=$performanceTest ` /p:Sign=$sign ` diff --git a/eng/common/build.sh b/eng/common/build.sh index 36fba82a37..9767bb411a 100755 --- a/eng/common/build.sh +++ b/eng/common/build.sh @@ -43,6 +43,7 @@ usage() echo " --nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')" echo " --warnAsError Sets warnaserror msbuild parameter ('true' or 'false')" echo " --buildCheck Sets /check msbuild parameter" + echo " --fromVMR Set when building from within the VMR" echo "" echo "Command line arguments not listed above are passed thru to msbuild." echo "Arguments can also be passed in with a single hyphen." @@ -64,6 +65,7 @@ restore=false build=false source_build=false product_build=false +from_vmr=false rebuild=false test=false integration_test=false @@ -89,7 +91,7 @@ verbosity='minimal' runtime_source_feed='' runtime_source_feed_key='' -properties='' +properties=() while [[ $# > 0 ]]; do opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")" case "$opt" in @@ -129,19 +131,22 @@ while [[ $# > 0 ]]; do -pack) pack=true ;; - -sourcebuild|-sb) + -sourcebuild|-source-build|-sb) build=true source_build=true product_build=true restore=true pack=true ;; - -productBuild|-pb) + -productbuild|-product-build|-pb) build=true product_build=true restore=true pack=true ;; + -fromvmr|-from-vmr) + from_vmr=true + ;; -test|-t) test=true ;; @@ -187,7 +192,7 @@ while [[ $# > 0 ]]; do shift ;; *) - properties="$properties $1" + properties+=("$1") ;; esac @@ -221,7 +226,7 @@ function Build { InitializeCustomToolset if [[ ! -z "$projects" ]]; then - properties="$properties /p:Projects=$projects" + properties+=("/p:Projects=$projects") fi local bl="" @@ -241,8 +246,9 @@ function Build { /p:RepoRoot="$repo_root" \ /p:Restore=$restore \ /p:Build=$build \ - /p:DotNetBuildRepo=$product_build \ + /p:DotNetBuild=$product_build \ /p:DotNetBuildSourceOnly=$source_build \ + /p:DotNetBuildFromVMR=$from_vmr \ /p:Rebuild=$rebuild \ /p:Test=$test \ /p:Pack=$pack \ @@ -251,7 +257,7 @@ function Build { /p:Sign=$sign \ /p:Publish=$publish \ /p:RestoreStaticGraphEnableBinaryLogger=$binary_log \ - $properties + ${properties[@]+"${properties[@]}"} ExitWithExitCode 0 } diff --git a/eng/common/core-templates/job/job.yml b/eng/common/core-templates/job/job.yml index 6badecba7b..d901325154 100644 --- a/eng/common/core-templates/job/job.yml +++ b/eng/common/core-templates/job/job.yml @@ -20,6 +20,7 @@ parameters: artifacts: '' enableMicrobuild: false enableMicrobuildForMacAndLinux: false + microbuildUseESRP: true enablePublishBuildArtifacts: false enablePublishBuildAssets: false enablePublishTestResults: false @@ -128,6 +129,7 @@ jobs: parameters: enableMicrobuild: ${{ parameters.enableMicrobuild }} enableMicrobuildForMacAndLinux: ${{ parameters.enableMicrobuildForMacAndLinux }} + microbuildUseESRP: ${{ parameters.microbuildUseESRP }} continueOnError: ${{ parameters.continueOnError }} - ${{ if and(eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal')) }}: diff --git a/eng/common/core-templates/job/onelocbuild.yml b/eng/common/core-templates/job/onelocbuild.yml index 00feec8ebb..8034815f42 100644 --- a/eng/common/core-templates/job/onelocbuild.yml +++ b/eng/common/core-templates/job/onelocbuild.yml @@ -86,8 +86,7 @@ jobs: isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} ${{ if eq(parameters.CreatePr, true) }}: isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} - ${{ if eq(parameters.RepoType, 'gitHub') }}: - isShouldReusePrSelected: ${{ parameters.ReusePr }} + isShouldReusePrSelected: ${{ parameters.ReusePr }} packageSourceAuth: patAuth patVariable: ${{ parameters.CeapexPat }} ${{ if eq(parameters.RepoType, 'gitHub') }}: @@ -118,4 +117,4 @@ jobs: pathToPublish: '$(Build.SourcesDirectory)/eng/Localize/' publishLocation: Container artifactName: Loc - condition: ${{ parameters.condition }} \ No newline at end of file + condition: ${{ parameters.condition }} diff --git a/eng/common/core-templates/job/publish-build-assets.yml b/eng/common/core-templates/job/publish-build-assets.yml index 4f1dc42e02..d5303229c9 100644 --- a/eng/common/core-templates/job/publish-build-assets.yml +++ b/eng/common/core-templates/job/publish-build-assets.yml @@ -32,6 +32,12 @@ parameters: # Optional: 🌤️ or not the build has assets it wants to publish to BAR isAssetlessBuild: false + # Optional, publishing version + publishingVersion: 3 + + # Optional: A minimatch pattern for the asset manifests to publish to BAR + assetManifestsPattern: '*/manifests/**/*.xml' + jobs: - job: Asset_Registry_Publish @@ -77,13 +83,31 @@ jobs: clean: true - ${{ if eq(parameters.isAssetlessBuild, 'false') }}: - - task: DownloadPipelineArtifact@2 - displayName: Download Asset Manifests - inputs: - artifactName: AssetManifests - targetPath: '$(Build.StagingDirectory)/AssetManifests' - condition: ${{ parameters.condition }} - continueOnError: ${{ parameters.continueOnError }} + - ${{ if eq(parameters.publishingVersion, 3) }}: + - task: DownloadPipelineArtifact@2 + displayName: Download Asset Manifests + inputs: + artifactName: AssetManifests + targetPath: '$(Build.StagingDirectory)/AssetManifests' + condition: ${{ parameters.condition }} + continueOnError: ${{ parameters.continueOnError }} + - ${{ if eq(parameters.publishingVersion, 4) }}: + - task: DownloadPipelineArtifact@2 + displayName: Download V4 asset manifests + inputs: + itemPattern: '*/manifests/**/*.xml' + targetPath: '$(Build.StagingDirectory)/AllAssetManifests' + condition: ${{ parameters.condition }} + continueOnError: ${{ parameters.continueOnError }} + - task: CopyFiles@2 + displayName: Copy V4 asset manifests to AssetManifests + inputs: + SourceFolder: '$(Build.StagingDirectory)/AllAssetManifests' + Contents: ${{ parameters.assetManifestsPattern }} + TargetFolder: '$(Build.StagingDirectory)/AssetManifests' + flattenFolders: true + condition: ${{ parameters.condition }} + continueOnError: ${{ parameters.continueOnError }} - task: NuGetAuthenticate@1 @@ -120,6 +144,17 @@ jobs: Copy-Item -Path $symbolExclusionfile -Destination "$(Build.StagingDirectory)/ReleaseConfigs" } + - ${{ if eq(parameters.publishingVersion, 4) }}: + - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + args: + targetPath: '$(Build.ArtifactStagingDirectory)/MergedManifest.xml' + artifactName: AssetManifests + displayName: 'Publish Merged Manifest' + retryCountOnTaskFailure: 10 # for any logs being locked + sbomEnabled: false # we don't need SBOM for logs + - template: /eng/common/core-templates/steps/publish-build-artifacts.yml parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} diff --git a/eng/common/core-templates/jobs/jobs.yml b/eng/common/core-templates/jobs/jobs.yml index bf35b78faa..2f992b2c6e 100644 --- a/eng/common/core-templates/jobs/jobs.yml +++ b/eng/common/core-templates/jobs/jobs.yml @@ -83,7 +83,6 @@ jobs: - template: /eng/common/core-templates/jobs/source-build.yml parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} - allCompletedJobId: Source_Build_Complete ${{ each parameter in parameters.sourceBuildParameters }}: ${{ parameter.key }}: ${{ parameter.value }} @@ -108,8 +107,6 @@ jobs: - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}: - ${{ each job in parameters.jobs }}: - ${{ job.job }} - - ${{ if eq(parameters.enableSourceBuild, true) }}: - - Source_Build_Complete runAsPublic: ${{ parameters.runAsPublic }} publishAssetsImmediately: ${{ or(parameters.publishAssetsImmediately, parameters.isAssetlessBuild) }} diff --git a/eng/common/core-templates/jobs/source-build.yml b/eng/common/core-templates/jobs/source-build.yml index a10ccfbee6..d92860cba2 100644 --- a/eng/common/core-templates/jobs/source-build.yml +++ b/eng/common/core-templates/jobs/source-build.yml @@ -2,19 +2,13 @@ parameters: # This template adds arcade-powered source-build to CI. A job is created for each platform, as # well as an optional server job that completes when all platform jobs complete. - # The name of the "join" job for all source-build platforms. If set to empty string, the job is - # not included. Existing repo pipelines can use this job depend on all source-build jobs - # completing without maintaining a separate list of every single job ID: just depend on this one - # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'. - allCompletedJobId: '' - # See /eng/common/core-templates/job/source-build.yml jobNamePrefix: 'Source_Build' # This is the default platform provided by Arcade, intended for use by a managed-only repo. defaultManagedPlatform: name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64' # Defines the platforms on which to run build jobs. One job is created for each platform, and the # object in this array is sent to the job template as 'platform'. If no platforms are specified, @@ -31,16 +25,6 @@ parameters: jobs: -- ${{ if ne(parameters.allCompletedJobId, '') }}: - - job: ${{ parameters.allCompletedJobId }} - displayName: Source-Build Complete - pool: server - dependsOn: - - ${{ each platform in parameters.platforms }}: - - ${{ parameters.jobNamePrefix }}_${{ platform.name }} - - ${{ if eq(length(parameters.platforms), 0) }}: - - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }} - - ${{ each platform in parameters.platforms }}: - template: /eng/common/core-templates/job/source-build.yml parameters: diff --git a/eng/common/core-templates/post-build/post-build.yml b/eng/common/core-templates/post-build/post-build.yml index 5757915edb..a151fd811e 100644 --- a/eng/common/core-templates/post-build/post-build.yml +++ b/eng/common/core-templates/post-build/post-build.yml @@ -193,9 +193,6 @@ stages: buildId: $(AzDOBuildId) artifactName: PackageArtifacts checkDownloadedFiles: true - itemPattern: | - ** - !**/Microsoft.SourceBuild.Intermediate.*.nupkg # This is necessary whenever we want to publish/restore to an AzDO private feed # Since sdk-task.ps1 tries to restore packages we need to do this authentication here diff --git a/eng/common/core-templates/steps/install-microbuild.yml b/eng/common/core-templates/steps/install-microbuild.yml index 2bcf974ee1..da30e67bc3 100644 --- a/eng/common/core-templates/steps/install-microbuild.yml +++ b/eng/common/core-templates/steps/install-microbuild.yml @@ -4,8 +4,16 @@ parameters: # Enable install tasks for MicroBuild on Mac and Linux # Will be ignored if 'enableMicrobuild' is false or 'Agent.Os' is 'Windows_NT' enableMicrobuildForMacAndLinux: false + # Determines whether the ESRP service connection information should be passed to the signing plugin. + # This overlaps with _SignType to some degree. We only need the service connection for real signing. + # It's important that the service connection not be passed to the MicroBuildSigningPlugin task in this place. + # Doing so will cause the service connection to be authorized for the pipeline, which isn't allowed and won't work for non-prod. + # Unfortunately, _SignType can't be used to exclude the use of the service connection in non-real sign scenarios. The + # variable is not available in template expression. _SignType has a very large proliferation across .NET, so replacing it is tough. + microbuildUseESRP: true # Location of the MicroBuild output folder microBuildOutputFolder: '$(Build.SourcesDirectory)' + continueOnError: false steps: @@ -21,15 +29,37 @@ steps: workingDirectory: ${{ parameters.microBuildOutputFolder }} condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT')) + - script: | + REM Check if ESRP is disabled while SignType is real + if /I "${{ parameters.microbuildUseESRP }}"=="false" if /I "$(_SignType)"=="real" ( + echo Error: ESRP must be enabled when SignType is real. + exit /b 1 + ) + displayName: 'Validate ESRP usage (Windows)' + condition: and(succeeded(), eq(variables['Agent.Os'], 'Windows_NT')) + - script: | + # Check if ESRP is disabled while SignType is real + if [ "${{ parameters.microbuildUseESRP }}" = "false" ] && [ "$(_SignType)" = "real" ]; then + echo "Error: ESRP must be enabled when SignType is real." + exit 1 + fi + displayName: 'Validate ESRP usage (Non-Windows)' + condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT')) + - task: MicroBuildSigningPlugin@4 displayName: Install MicroBuild plugin inputs: signType: $(_SignType) zipSources: false feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json - ${{ if and(eq(parameters.enableMicrobuildForMacAndLinux, 'true'), ne(variables['Agent.Os'], 'Windows_NT')) }}: - azureSubscription: 'MicroBuild Signing Task (DevDiv)' - useEsrpCli: true + ${{ if eq(parameters.microbuildUseESRP, true) }}: + ${{ if eq(parameters.enableMicrobuildForMacAndLinux, 'true') }}: + azureSubscription: 'MicroBuild Signing Task (DevDiv)' + useEsrpCli: true + ${{ elseif eq(variables['System.TeamProject'], 'DevDiv') }}: + ConnectedPMEServiceName: 6cc74545-d7b9-4050-9dfa-ebefcc8961ea + ${{ else }}: + ConnectedPMEServiceName: 248d384a-b39b-46e3-8ad5-c2c210d5e7ca env: TeamName: $(_TeamName) MicroBuildOutputFolderOverride: ${{ parameters.microBuildOutputFolder }} @@ -48,38 +78,3 @@ steps: eq(variables['_SignType'], 'real') ) )) - - # Workaround for ESRP CLI on Linux - https://github.com/dotnet/source-build/issues/4964 - - ${{ if eq(parameters.enableMicrobuildForMacAndLinux, 'true') }}: - - task: UseDotNet@2 - displayName: Install .NET 9.0 SDK for ESRP CLI Workaround - inputs: - packageType: sdk - version: 9.0.x - installationPath: ${{ parameters.microBuildOutputFolder }}/.dotnet - workingDirectory: ${{ parameters.microBuildOutputFolder }} - condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) - - - task: PowerShell@2 - displayName: Workaround for ESRP CLI on Linux - inputs: - targetType: 'inline' - script: | - Write-Host "Copying Linux Path" - $MBSIGN_APPFOLDER = '$(MBSIGN_APPFOLDER)' - $MBSIGN_APPFOLDER = ($MBSIGN_APPFOLDER -replace '/build', '') - - $versionRegex = '\d+\.\d+\.\d+' - $package = Get-ChildItem -Path $MBSIGN_APPFOLDER -Directory | - Where-Object { $_.Name -match $versionRegex } - - if ($package.Count -ne 1) { - Write-Host "There should be exactly one matching subfolder, but found $($package.Count)." - exit 1 - } - - $MBSIGN_APPFOLDER = $package[0].FullName + '/build' - $MBSIGN_APPFOLDER | Write-Host - $SignConfigPath = $MBSIGN_APPFOLDER + '/signconfig.xml' - Copy-Item -Path "$(MBSIGN_APPFOLDER)/signconfig.xml" -Destination $SignConfigPath -Force - condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) diff --git a/eng/common/core-templates/steps/source-build.yml b/eng/common/core-templates/steps/source-build.yml index c6b9ef51ac..acf16ed349 100644 --- a/eng/common/core-templates/steps/source-build.yml +++ b/eng/common/core-templates/steps/source-build.yml @@ -19,19 +19,6 @@ steps: set -x df -h - # If file changes are detected, set CopyWipIntoInnerSourceBuildRepo to copy the WIP changes into the inner source build repo. - internalRestoreArgs= - if ! git diff --quiet; then - internalRestoreArgs='/p:CopyWipIntoInnerSourceBuildRepo=true' - # The 'Copy WIP' feature of source build uses git stash to apply changes from the original repo. - # This only works if there is a username/email configured, which won't be the case in most CI runs. - git config --get user.email - if [ $? -ne 0 ]; then - git config user.email dn-bot@microsoft.com - git config user.name dn-bot - fi - fi - # If building on the internal project, the internal storage variable may be available (usually only if needed) # In that case, add variables to allow the download of internal runtimes if the specified versions are not found # in the default public locations. @@ -46,36 +33,11 @@ steps: buildConfig='$(_BuildConfig)' fi - officialBuildArgs= - if [ '${{ and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}' = 'True' ]; then - officialBuildArgs='/p:DotNetPublishUsingPipelines=true /p:OfficialBuildId=$(BUILD.BUILDNUMBER)' - fi - targetRidArgs= if [ '${{ parameters.platform.targetRID }}' != '' ]; then targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}' fi - runtimeOsArgs= - if [ '${{ parameters.platform.runtimeOS }}' != '' ]; then - runtimeOsArgs='/p:RuntimeOS=${{ parameters.platform.runtimeOS }}' - fi - - baseOsArgs= - if [ '${{ parameters.platform.baseOS }}' != '' ]; then - baseOsArgs='/p:BaseOS=${{ parameters.platform.baseOS }}' - fi - - publishArgs= - if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then - publishArgs='--publish' - fi - - assetManifestFileName=SourceBuild_RidSpecific.xml - if [ '${{ parameters.platform.name }}' != '' ]; then - assetManifestFileName=SourceBuild_${{ parameters.platform.name }}.xml - fi - portableBuildArgs= if [ '${{ parameters.platform.portableBuild }}' != '' ]; then portableBuildArgs='/p:PortableBuild=${{ parameters.platform.portableBuild }}' @@ -83,40 +45,20 @@ steps: ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ --configuration $buildConfig \ - --restore --build --pack $publishArgs -bl \ + --restore --build --pack -bl \ + --source-build \ ${{ parameters.platform.buildArguments }} \ - $officialBuildArgs \ $internalRuntimeDownloadArgs \ - $internalRestoreArgs \ $targetRidArgs \ - $runtimeOsArgs \ - $baseOsArgs \ $portableBuildArgs \ - /p:DotNetBuildSourceOnly=true \ - /p:DotNetBuildRepo=true \ - /p:AssetManifestFileName=$assetManifestFileName displayName: Build -# Upload build logs for diagnosis. -- task: CopyFiles@2 - displayName: Prepare BuildLogs staging directory - inputs: - SourceFolder: '$(Build.SourcesDirectory)' - Contents: | - **/*.log - **/*.binlog - artifacts/sb/prebuilt-report/** - TargetFolder: '$(Build.StagingDirectory)/BuildLogs' - CleanTargetFolder: true - continueOnError: true - condition: succeededOrFailed() - - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} args: displayName: Publish BuildLogs - targetPath: '$(Build.StagingDirectory)/BuildLogs' + targetPath: artifacts/log/${{ coalesce(variables._BuildConfig, 'Release') }} artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt) continueOnError: true condition: succeededOrFailed() diff --git a/eng/common/core-templates/steps/source-index-stage1-publish.yml b/eng/common/core-templates/steps/source-index-stage1-publish.yml index 99c2326fc1..c2917c1efc 100644 --- a/eng/common/core-templates/steps/source-index-stage1-publish.yml +++ b/eng/common/core-templates/steps/source-index-stage1-publish.yml @@ -1,15 +1,15 @@ parameters: sourceIndexUploadPackageVersion: 2.0.0-20250425.2 - sourceIndexProcessBinlogPackageVersion: 1.0.1-20250425.2 + sourceIndexProcessBinlogPackageVersion: 1.0.1-20250515.1 sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json binlogPath: artifacts/log/Debug/Build.binlog steps: - task: UseDotNet@2 - displayName: "Source Index: Use .NET 8 SDK" + displayName: "Source Index: Use .NET 9 SDK" inputs: packageType: sdk - version: 8.0.x + version: 9.0.x installationPath: $(Agent.TempDirectory)/dotnet workingDirectory: $(Agent.TempDirectory) diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index d6f005b5da..8abfb71f72 100644 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -295,8 +295,8 @@ while :; do ;; noble) # Ubuntu 24.04 __CodeName=noble - if [[ -n "$__LLDB_Package" ]]; then - __LLDB_Package="liblldb-18-dev" + if [[ -z "$__LLDB_Package" ]]; then + __LLDB_Package="liblldb-19-dev" fi ;; stretch) # Debian 9 diff --git a/eng/common/darc-init.sh b/eng/common/darc-init.sh index 36dbd45e1c..e889f439b8 100644 --- a/eng/common/darc-init.sh +++ b/eng/common/darc-init.sh @@ -68,7 +68,7 @@ function InstallDarcCli { fi fi - local arcadeServicesSource="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" + local arcadeServicesSource="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" echo "Installing Darc CLI version $darcVersion..." echo "You may need to restart your command shell if this is the first dotnet tool you have installed." diff --git a/eng/common/dotnet.cmd b/eng/common/dotnet.cmd new file mode 100644 index 0000000000..527fa4bb38 --- /dev/null +++ b/eng/common/dotnet.cmd @@ -0,0 +1,7 @@ +@echo off + +:: This script is used to install the .NET SDK. +:: It will also invoke the SDK with any provided arguments. + +powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0dotnet.ps1""" %*" +exit /b %ErrorLevel% diff --git a/eng/common/dotnet.ps1 b/eng/common/dotnet.ps1 new file mode 100644 index 0000000000..45e5676c9e --- /dev/null +++ b/eng/common/dotnet.ps1 @@ -0,0 +1,11 @@ +# This script is used to install the .NET SDK. +# It will also invoke the SDK with any provided arguments. + +. $PSScriptRoot\tools.ps1 +$dotnetRoot = InitializeDotNetCli -install:$true + +# Invoke acquired SDK with args if they are provided +if ($args.count -gt 0) { + $env:DOTNET_NOLOGO=1 + & "$dotnetRoot\dotnet.exe" $args +} diff --git a/eng/common/dotnet.sh b/eng/common/dotnet.sh new file mode 100644 index 0000000000..2ef6823567 --- /dev/null +++ b/eng/common/dotnet.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +# This script is used to install the .NET SDK. +# It will also invoke the SDK with any provided arguments. + +source="${BASH_SOURCE[0]}" +# resolve $SOURCE until the file is no longer a symlink +while [[ -h $source ]]; do + scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + source="$(readlink "$source")" + + # if $source was a relative symlink, we need to resolve it relative to the path where the + # symlink file was located + [[ $source != /* ]] && source="$scriptroot/$source" +done +scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + +source $scriptroot/tools.sh +InitializeDotNetCli true # install + +# Invoke acquired SDK with args if they are provided +if [[ $# > 0 ]]; then + __dotnetDir=${_InitializeDotNetCli} + dotnetPath=${__dotnetDir}/dotnet + ${dotnetPath} "$@" +fi diff --git a/eng/common/internal/NuGet.config b/eng/common/internal/NuGet.config index 19d3d311b1..f70261ed68 100644 --- a/eng/common/internal/NuGet.config +++ b/eng/common/internal/NuGet.config @@ -4,4 +4,7 @@ + + + diff --git a/eng/common/templates/steps/vmr-sync.yml b/eng/common/templates/steps/vmr-sync.yml new file mode 100644 index 0000000000..599afb6186 --- /dev/null +++ b/eng/common/templates/steps/vmr-sync.yml @@ -0,0 +1,207 @@ +### These steps synchronize new code from product repositories into the VMR (https://github.com/dotnet/dotnet). +### They initialize the darc CLI and pull the new updates. +### Changes are applied locally onto the already cloned VMR (located in $vmrPath). + +parameters: +- name: targetRef + displayName: Target revision in dotnet/ to synchronize + type: string + default: $(Build.SourceVersion) + +- name: vmrPath + displayName: Path where the dotnet/dotnet is checked out to + type: string + default: $(Agent.BuildDirectory)/vmr + +- name: additionalSyncs + displayName: Optional list of package names whose repo's source will also be synchronized in the local VMR, e.g. NuGet.Protocol + type: object + default: [] + +steps: +- checkout: vmr + displayName: Clone dotnet/dotnet + path: vmr + clean: true + +- checkout: self + displayName: Clone $(Build.Repository.Name) + path: repo + fetchDepth: 0 + +# This step is needed so that when we get a detached HEAD / shallow clone, +# we still pull the commit into the temporary repo clone to use it during the sync. +# Also unshallow the clone so that forwardflow command would work. +- script: | + git branch repo-head + git rev-parse HEAD + displayName: Label PR commit + workingDirectory: $(Agent.BuildDirectory)/repo + +- script: | + vmr_sha=$(grep -oP '(?<=Sha=")[^"]*' $(Agent.BuildDirectory)/repo/eng/Version.Details.xml) + echo "##vso[task.setvariable variable=vmr_sha]$vmr_sha" + displayName: Obtain the vmr sha from Version.Details.xml (Unix) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- powershell: | + [xml]$xml = Get-Content -Path $(Agent.BuildDirectory)/repo/eng/Version.Details.xml + $vmr_sha = $xml.SelectSingleNode("//Source").Sha + Write-Output "##vso[task.setvariable variable=vmr_sha]$vmr_sha" + displayName: Obtain the vmr sha from Version.Details.xml (Windows) + condition: eq(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- script: | + git fetch --all + git checkout $(vmr_sha) + displayName: Checkout VMR at correct sha for repo flow + workingDirectory: ${{ parameters.vmrPath }} + +- script: | + git config --global user.name "dotnet-maestro[bot]" + git config --global user.email "dotnet-maestro[bot]@users.noreply.github.com" + displayName: Set git author to dotnet-maestro[bot] + workingDirectory: ${{ parameters.vmrPath }} + +- script: | + ./eng/common/vmr-sync.sh \ + --vmr ${{ parameters.vmrPath }} \ + --tmp $(Agent.TempDirectory) \ + --azdev-pat '$(dn-bot-all-orgs-code-r)' \ + --ci \ + --debug + + if [ "$?" -ne 0 ]; then + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + fi + displayName: Sync repo into VMR (Unix) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- script: | + git config --global diff.astextplain.textconv echo + git config --system core.longpaths true + displayName: Configure Windows git (longpaths, astextplain) + condition: eq(variables['Agent.OS'], 'Windows_NT') + +- powershell: | + ./eng/common/vmr-sync.ps1 ` + -vmr ${{ parameters.vmrPath }} ` + -tmp $(Agent.TempDirectory) ` + -azdevPat '$(dn-bot-all-orgs-code-r)' ` + -ci ` + -debugOutput + + if ($LASTEXITCODE -ne 0) { + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + } + displayName: Sync repo into VMR (Windows) + condition: eq(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: + - task: CopyFiles@2 + displayName: Collect failed patches + condition: failed() + inputs: + SourceFolder: '$(Agent.TempDirectory)' + Contents: '*.patch' + TargetFolder: '$(Build.ArtifactStagingDirectory)/FailedPatches' + + - publish: '$(Build.ArtifactStagingDirectory)/FailedPatches' + artifact: $(System.JobDisplayName)_FailedPatches + displayName: Upload failed patches + condition: failed() + +- ${{ each assetName in parameters.additionalSyncs }}: + # The vmr-sync script ends up staging files in the local VMR so we have to commit those + - script: + git commit --allow-empty -am "Forward-flow $(Build.Repository.Name)" + displayName: Commit local VMR changes + workingDirectory: ${{ parameters.vmrPath }} + + - script: | + set -ex + + echo "Searching for details of asset ${{ assetName }}..." + + # Use darc to get dependencies information + dependencies=$(./.dotnet/dotnet darc get-dependencies --name '${{ assetName }}' --ci) + + # Extract repository URL and commit hash + repository=$(echo "$dependencies" | grep 'Repo:' | sed 's/Repo:[[:space:]]*//' | head -1) + + if [ -z "$repository" ]; then + echo "##vso[task.logissue type=error]Asset ${{ assetName }} not found in the dependency list" + exit 1 + fi + + commit=$(echo "$dependencies" | grep 'Commit:' | sed 's/Commit:[[:space:]]*//' | head -1) + + echo "Updating the VMR from $repository / $commit..." + cd .. + git clone $repository ${{ assetName }} + cd ${{ assetName }} + git checkout $commit + git branch "sync/$commit" + + ./eng/common/vmr-sync.sh \ + --vmr ${{ parameters.vmrPath }} \ + --tmp $(Agent.TempDirectory) \ + --azdev-pat '$(dn-bot-all-orgs-code-r)' \ + --ci \ + --debug + + if [ "$?" -ne 0 ]; then + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + fi + displayName: Sync ${{ assetName }} into (Unix) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + + - powershell: | + $ErrorActionPreference = 'Stop' + + Write-Host "Searching for details of asset ${{ assetName }}..." + + $dependencies = .\.dotnet\dotnet darc get-dependencies --name '${{ assetName }}' --ci + + $repository = $dependencies | Select-String -Pattern 'Repo:\s+([^\s]+)' | Select-Object -First 1 + $repository -match 'Repo:\s+([^\s]+)' | Out-Null + $repository = $matches[1] + + if ($repository -eq $null) { + Write-Error "Asset ${{ assetName }} not found in the dependency list" + exit 1 + } + + $commit = $dependencies | Select-String -Pattern 'Commit:\s+([^\s]+)' | Select-Object -First 1 + $commit -match 'Commit:\s+([^\s]+)' | Out-Null + $commit = $matches[1] + + Write-Host "Updating the VMR from $repository / $commit..." + cd .. + git clone $repository ${{ assetName }} + cd ${{ assetName }} + git checkout $commit + git branch "sync/$commit" + + .\eng\common\vmr-sync.ps1 ` + -vmr ${{ parameters.vmrPath }} ` + -tmp $(Agent.TempDirectory) ` + -azdevPat '$(dn-bot-all-orgs-code-r)' ` + -ci ` + -debugOutput + + if ($LASTEXITCODE -ne 0) { + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + } + displayName: Sync ${{ assetName }} into (Windows) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo diff --git a/eng/common/templates/vmr-build-pr.yml b/eng/common/templates/vmr-build-pr.yml new file mode 100644 index 0000000000..ce3c29a62f --- /dev/null +++ b/eng/common/templates/vmr-build-pr.yml @@ -0,0 +1,42 @@ +# This pipeline is used for running the VMR verification of the PR changes in repo-level PRs. +# +# It will run a full set of verification jobs defined in: +# https://github.com/dotnet/dotnet/blob/10060d128e3f470e77265f8490f5e4f72dae738e/eng/pipelines/templates/stages/vmr-build.yml#L27-L38 +# +# For repos that do not need to run the full set, you would do the following: +# +# 1. Copy this YML file to a repo-specific location, i.e. outside of eng/common. +# +# 2. Add `verifications` parameter to VMR template reference +# +# Examples: +# - For source-build stage 1 verification, add the following: +# verifications: [ "source-build-stage1" ] +# +# - For Windows only verifications, add the following: +# verifications: [ "unified-build-windows-x64", "unified-build-windows-x86" ] + +trigger: none +pr: none + +variables: +- template: /eng/common/templates/variables/pool-providers.yml@self + +- name: skipComponentGovernanceDetection # we run CG on internal builds only + value: true + +- name: Codeql.Enabled # we run CodeQL on internal builds only + value: false + +resources: + repositories: + - repository: vmr + type: github + name: dotnet/dotnet + endpoint: dotnet + +stages: +- template: /eng/pipelines/templates/stages/vmr-build.yml@vmr + parameters: + isBuiltFromVmr: false + scope: lite diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 7373e53054..996a5f9c87 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -65,10 +65,8 @@ $ErrorActionPreference = 'Stop' # Base-64 encoded SAS token that has permission to storage container described by $runtimeSourceFeed [string]$runtimeSourceFeedKey = if (Test-Path variable:runtimeSourceFeedKey) { $runtimeSourceFeedKey } else { $null } -# True if the build is a product build -[bool]$productBuild = if (Test-Path variable:productBuild) { $productBuild } else { $false } - -[String[]]$properties = if (Test-Path variable:properties) { $properties } else { @() } +# True when the build is running within the VMR. +[bool]$fromVMR = if (Test-Path variable:fromVMR) { $fromVMR } else { $false } function Create-Directory ([string[]] $path) { New-Item -Path $path -Force -ItemType 'Directory' | Out-Null @@ -416,7 +414,7 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = # Locate Visual Studio installation or download x-copy msbuild. $vsInfo = LocateVisualStudio $vsRequirements - if ($vsInfo -ne $null) { + if ($vsInfo -ne $null -and $env:ForceUseXCopyMSBuild -eq $null) { # Ensure vsInstallDir has a trailing slash $vsInstallDir = Join-Path $vsInfo.installationPath "\" $vsMajorVersion = $vsInfo.installationVersion.Split('.')[0] @@ -646,7 +644,6 @@ function GetNuGetPackageCachePath() { $env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages\' } else { $env:NUGET_PACKAGES = Join-Path $RepoRoot '.packages\' - $env:RESTORENOHTTPCACHE = $true } } @@ -768,28 +765,13 @@ function MSBuild() { $toolsetBuildProject = InitializeToolset $basePath = Split-Path -parent $toolsetBuildProject - $possiblePaths = @( - # new scripts need to work with old packages, so we need to look for the old names/versions - (Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.ArcadeLogging.dll')), - (Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.Arcade.Sdk.dll')), - - # This list doesn't need to be updated anymore and can eventually be removed. - (Join-Path $basePath (Join-Path net9.0 'Microsoft.DotNet.ArcadeLogging.dll')), - (Join-Path $basePath (Join-Path net9.0 'Microsoft.DotNet.Arcade.Sdk.dll')), - (Join-Path $basePath (Join-Path net8.0 'Microsoft.DotNet.ArcadeLogging.dll')), - (Join-Path $basePath (Join-Path net8.0 'Microsoft.DotNet.Arcade.Sdk.dll')) - ) - $selectedPath = $null - foreach ($path in $possiblePaths) { - if (Test-Path $path -PathType Leaf) { - $selectedPath = $path - break - } - } + $selectedPath = Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.ArcadeLogging.dll') + if (-not $selectedPath) { - Write-PipelineTelemetryError -Category 'Build' -Message 'Unable to find arcade sdk logger assembly.' + Write-PipelineTelemetryError -Category 'Build' -Message "Unable to find arcade sdk logger assembly: $selectedPath" ExitWithExitCode 1 } + $args += "/logger:$selectedPath" } @@ -852,8 +834,8 @@ function MSBuild-Core() { } # When running on Azure Pipelines, override the returned exit code to avoid double logging. - # Skip this when the build is a child of the VMR orchestrator build. - if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$productBuild -and -not($properties -like "*DotNetBuildRepo=true*")) { + # Skip this when the build is a child of the VMR build. + if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR) { Write-PipelineSetResult -Result "Failed" -Message "msbuild execution failed." # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error diff --git a/eng/common/tools.sh b/eng/common/tools.sh index d51f300c77..3def02a638 100644 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -5,6 +5,9 @@ # CI mode - set to true on CI server for PR validation build or official build. ci=${ci:-false} +# Build mode +source_build=${source_build:-false} + # Set to true to use the pipelines logger which will enable Azure logging output. # https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md # This flag is meant as a temporary opt-opt for the feature while validate it across @@ -58,7 +61,8 @@ use_installed_dotnet_cli=${use_installed_dotnet_cli:-true} dotnetInstallScriptVersion=${dotnetInstallScriptVersion:-'v1'} # True to use global NuGet cache instead of restoring packages to repository-local directory. -if [[ "$ci" == true ]]; then +# Keep in sync with NuGetPackageroot in Arcade SDK's RepositoryLayout.props. +if [[ "$ci" == true || "$source_build" == true ]]; then use_global_nuget_cache=${use_global_nuget_cache:-false} else use_global_nuget_cache=${use_global_nuget_cache:-true} @@ -68,8 +72,8 @@ fi runtime_source_feed=${runtime_source_feed:-''} runtime_source_feed_key=${runtime_source_feed_key:-''} -# True if the build is a product build -product_build=${product_build:-false} +# True when the build is running within the VMR. +from_vmr=${from_vmr:-false} # Resolve any symlinks in the given path. function ResolvePath { @@ -341,14 +345,12 @@ function InitializeBuildTool { _InitializeBuildToolCommand="msbuild" } -# Set RestoreNoHttpCache as a workaround for https://github.com/NuGet/Home/issues/3116 function GetNuGetPackageCachePath { if [[ -z ${NUGET_PACKAGES:-} ]]; then if [[ "$use_global_nuget_cache" == true ]]; then export NUGET_PACKAGES="$HOME/.nuget/packages/" else export NUGET_PACKAGES="$repo_root/.packages/" - export RESTORENOHTTPCACHE=true fi fi @@ -445,27 +447,13 @@ function MSBuild { fi local toolset_dir="${_InitializeToolset%/*}" - # new scripts need to work with old packages, so we need to look for the old names/versions - local selectedPath= - local possiblePaths=() - possiblePaths+=( "$toolset_dir/net/Microsoft.DotNet.ArcadeLogging.dll" ) - possiblePaths+=( "$toolset_dir/net/Microsoft.DotNet.Arcade.Sdk.dll" ) - - # This list doesn't need to be updated anymore and can eventually be removed. - possiblePaths+=( "$toolset_dir/net9.0/Microsoft.DotNet.ArcadeLogging.dll" ) - possiblePaths+=( "$toolset_dir/net9.0/Microsoft.DotNet.Arcade.Sdk.dll" ) - possiblePaths+=( "$toolset_dir/net8.0/Microsoft.DotNet.ArcadeLogging.dll" ) - possiblePaths+=( "$toolset_dir/net8.0/Microsoft.DotNet.Arcade.Sdk.dll" ) - for path in "${possiblePaths[@]}"; do - if [[ -f $path ]]; then - selectedPath=$path - break - fi - done + local selectedPath="$toolset_dir/net/Microsoft.DotNet.ArcadeLogging.dll" + if [[ -z "$selectedPath" ]]; then - Write-PipelineTelemetryError -category 'Build' "Unable to find arcade sdk logger assembly." + Write-PipelineTelemetryError -category 'Build' "Unable to find arcade sdk logger assembly: $selectedPath" ExitWithExitCode 1 fi + args+=( "-logger:$selectedPath" ) fi @@ -502,8 +490,8 @@ function MSBuild-Core { echo "Build failed with exit code $exit_code. Check errors above." # When running on Azure Pipelines, override the returned exit code to avoid double logging. - # Skip this when the build is a child of the VMR orchestrator build. - if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$product_build" != true && "$properties" != *"DotNetBuildRepo=true"* ]]; then + # Skip this when the build is a child of the VMR build. + if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$from_vmr" != true ]]; then Write-PipelineSetResult -result "Failed" -message "msbuild execution failed." # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error @@ -526,6 +514,7 @@ function GetDarc { fi "$eng_root/common/darc-init.sh" --toolpath "$darc_path" $version + darc_tool="$darc_path/darc" } # Returns a full path to an Arcade SDK task project file. diff --git a/eng/common/vmr-sync.ps1 b/eng/common/vmr-sync.ps1 new file mode 100644 index 0000000000..97302f3205 --- /dev/null +++ b/eng/common/vmr-sync.ps1 @@ -0,0 +1,138 @@ +<# +.SYNOPSIS + +This script is used for synchronizing the current repository into a local VMR. +It pulls the current repository's code into the specified VMR directory for local testing or +Source-Build validation. + +.DESCRIPTION + +The tooling used for synchronization will clone the VMR repository into a temporary folder if +it does not already exist. These clones can be reused in future synchronizations, so it is +recommended to dedicate a folder for this to speed up re-runs. + +.EXAMPLE + Synchronize current repository into a local VMR: + ./vmr-sync.ps1 -vmrDir "$HOME/repos/dotnet" -tmpDir "$HOME/repos/tmp" + +.PARAMETER tmpDir +Required. Path to the temporary folder where repositories will be cloned + +.PARAMETER vmrBranch +Optional. Branch of the 'dotnet/dotnet' repo to synchronize. The VMR will be checked out to this branch + +.PARAMETER azdevPat +Optional. Azure DevOps PAT to use for cloning private repositories. + +.PARAMETER vmrDir +Optional. Path to the dotnet/dotnet repository. When null, gets cloned to the temporary folder + +.PARAMETER debugOutput +Optional. Enables debug logging in the darc vmr command. + +.PARAMETER ci +Optional. Denotes that the script is running in a CI environment. +#> +param ( + [Parameter(Mandatory=$true, HelpMessage="Path to the temporary folder where repositories will be cloned")] + [string][Alias('t', 'tmp')]$tmpDir, + [string][Alias('b', 'branch')]$vmrBranch, + [string]$remote, + [string]$azdevPat, + [string][Alias('v', 'vmr')]$vmrDir, + [switch]$ci, + [switch]$debugOutput +) + +function Fail { + Write-Host "> $($args[0])" -ForegroundColor 'Red' +} + +function Highlight { + Write-Host "> $($args[0])" -ForegroundColor 'Cyan' +} + +$verbosity = 'verbose' +if ($debugOutput) { + $verbosity = 'debug' +} +# Validation + +if (-not $tmpDir) { + Fail "Missing -tmpDir argument. Please specify the path to the temporary folder where the repositories will be cloned" + exit 1 +} + +# Sanitize the input + +if (-not $vmrDir) { + $vmrDir = Join-Path $tmpDir 'dotnet' +} + +if (-not (Test-Path -Path $tmpDir -PathType Container)) { + New-Item -ItemType Directory -Path $tmpDir | Out-Null +} + +# Prepare the VMR + +if (-not (Test-Path -Path $vmrDir -PathType Container)) { + Highlight "Cloning 'dotnet/dotnet' into $vmrDir.." + git clone https://github.com/dotnet/dotnet $vmrDir + + if ($vmrBranch) { + git -C $vmrDir switch -c $vmrBranch + } +} +else { + if ((git -C $vmrDir diff --quiet) -eq $false) { + Fail "There are changes in the working tree of $vmrDir. Please commit or stash your changes" + exit 1 + } + + if ($vmrBranch) { + Highlight "Preparing $vmrDir" + git -C $vmrDir checkout $vmrBranch + git -C $vmrDir pull + } +} + +Set-StrictMode -Version Latest + +# Prepare darc + +Highlight 'Installing .NET, preparing the tooling..' +. .\eng\common\tools.ps1 +$dotnetRoot = InitializeDotNetCli -install:$true +$darc = Get-Darc +$dotnet = "$dotnetRoot\dotnet.exe" + +Highlight "Starting the synchronization of VMR.." + +# Synchronize the VMR +$darcArgs = ( + "vmr", "forwardflow", + "--tmp", $tmpDir, + "--$verbosity", + $vmrDir +) + +if ($ci) { + $darcArgs += ("--ci") +} + +if ($azdevPat) { + $darcArgs += ("--azdev-pat", $azdevPat) +} + +& "$darc" $darcArgs + +if ($LASTEXITCODE -eq 0) { + Highlight "Synchronization succeeded" +} +else { + Fail "Synchronization of repo to VMR failed!" + Fail "'$vmrDir' is left in its last state (re-run of this script will reset it)." + Fail "Please inspect the logs which contain path to the failing patch file (use -debugOutput to get all the details)." + Fail "Once you make changes to the conflicting VMR patch, commit it locally and re-run this script." + exit 1 +} diff --git a/eng/common/vmr-sync.sh b/eng/common/vmr-sync.sh new file mode 100644 index 0000000000..44239e331c --- /dev/null +++ b/eng/common/vmr-sync.sh @@ -0,0 +1,207 @@ +#!/bin/bash + +### This script is used for synchronizing the current repository into a local VMR. +### It pulls the current repository's code into the specified VMR directory for local testing or +### Source-Build validation. +### +### The tooling used for synchronization will clone the VMR repository into a temporary folder if +### it does not already exist. These clones can be reused in future synchronizations, so it is +### recommended to dedicate a folder for this to speed up re-runs. +### +### USAGE: +### Synchronize current repository into a local VMR: +### ./vmr-sync.sh --tmp "$HOME/repos/tmp" "$HOME/repos/dotnet" +### +### Options: +### -t, --tmp, --tmp-dir PATH +### Required. Path to the temporary folder where repositories will be cloned +### +### -b, --branch, --vmr-branch BRANCH_NAME +### Optional. Branch of the 'dotnet/dotnet' repo to synchronize. The VMR will be checked out to this branch +### +### --debug +### Optional. Turns on the most verbose logging for the VMR tooling +### +### --remote name:URI +### Optional. Additional remote to use during the synchronization +### This can be used to synchronize to a commit from a fork of the repository +### Example: 'runtime:https://github.com/yourfork/runtime' +### +### --azdev-pat +### Optional. Azure DevOps PAT to use for cloning private repositories. +### +### -v, --vmr, --vmr-dir PATH +### Optional. Path to the dotnet/dotnet repository. When null, gets cloned to the temporary folder + +source="${BASH_SOURCE[0]}" + +# resolve $source until the file is no longer a symlink +while [[ -h "$source" ]]; do + scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + source="$(readlink "$source")" + # if $source was a relative symlink, we need to resolve it relative to the path where the + # symlink file was located + [[ $source != /* ]] && source="$scriptroot/$source" +done +scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + +function print_help () { + sed -n '/^### /,/^$/p' "$source" | cut -b 5- +} + +COLOR_RED=$(tput setaf 1 2>/dev/null || true) +COLOR_CYAN=$(tput setaf 6 2>/dev/null || true) +COLOR_CLEAR=$(tput sgr0 2>/dev/null || true) +COLOR_RESET=uniquesearchablestring +FAILURE_PREFIX='> ' + +function fail () { + echo "${COLOR_RED}$FAILURE_PREFIX${1//${COLOR_RESET}/${COLOR_RED}}${COLOR_CLEAR}" >&2 +} + +function highlight () { + echo "${COLOR_CYAN}$FAILURE_PREFIX${1//${COLOR_RESET}/${COLOR_CYAN}}${COLOR_CLEAR}" +} + +tmp_dir='' +vmr_dir='' +vmr_branch='' +additional_remotes='' +verbosity=verbose +azdev_pat='' +ci=false + +while [[ $# -gt 0 ]]; do + opt="$(echo "$1" | tr "[:upper:]" "[:lower:]")" + case "$opt" in + -t|--tmp|--tmp-dir) + tmp_dir=$2 + shift + ;; + -v|--vmr|--vmr-dir) + vmr_dir=$2 + shift + ;; + -b|--branch|--vmr-branch) + vmr_branch=$2 + shift + ;; + --remote) + additional_remotes="$additional_remotes $2" + shift + ;; + --azdev-pat) + azdev_pat=$2 + shift + ;; + --ci) + ci=true + ;; + -d|--debug) + verbosity=debug + ;; + -h|--help) + print_help + exit 0 + ;; + *) + fail "Invalid argument: $1" + print_help + exit 1 + ;; + esac + + shift +done + +# Validation + +if [[ -z "$tmp_dir" ]]; then + fail "Missing --tmp-dir argument. Please specify the path to the temporary folder where the repositories will be cloned" + exit 1 +fi + +# Sanitize the input + +if [[ -z "$vmr_dir" ]]; then + vmr_dir="$tmp_dir/dotnet" +fi + +if [[ ! -d "$tmp_dir" ]]; then + mkdir -p "$tmp_dir" +fi + +if [[ "$verbosity" == "debug" ]]; then + set -x +fi + +# Prepare the VMR + +if [[ ! -d "$vmr_dir" ]]; then + highlight "Cloning 'dotnet/dotnet' into $vmr_dir.." + git clone https://github.com/dotnet/dotnet "$vmr_dir" + + if [[ -n "$vmr_branch" ]]; then + git -C "$vmr_dir" switch -c "$vmr_branch" + fi +else + if ! git -C "$vmr_dir" diff --quiet; then + fail "There are changes in the working tree of $vmr_dir. Please commit or stash your changes" + exit 1 + fi + + if [[ -n "$vmr_branch" ]]; then + highlight "Preparing $vmr_dir" + git -C "$vmr_dir" checkout "$vmr_branch" + git -C "$vmr_dir" pull + fi +fi + +set -e + +# Prepare darc + +highlight 'Installing .NET, preparing the tooling..' +source "./eng/common/tools.sh" +InitializeDotNetCli true +GetDarc +dotnetDir=$( cd ./.dotnet/; pwd -P ) +dotnet=$dotnetDir/dotnet + +highlight "Starting the synchronization of VMR.." +set +e + +if [[ -n "$additional_remotes" ]]; then + additional_remotes="--additional-remotes $additional_remotes" +fi + +if [[ -n "$azdev_pat" ]]; then + azdev_pat="--azdev-pat $azdev_pat" +fi + +ci_arg='' +if [[ "$ci" == "true" ]]; then + ci_arg="--ci" +fi + +# Synchronize the VMR + +export DOTNET_ROOT="$dotnetDir" + +"$darc_tool" vmr forwardflow \ + --tmp "$tmp_dir" \ + $azdev_pat \ + --$verbosity \ + $ci_arg \ + $additional_remotes \ + "$vmr_dir" + +if [[ $? == 0 ]]; then + highlight "Synchronization succeeded" +else + fail "Synchronization of repo to VMR failed!" + fail "'$vmr_dir' is left in its last state (re-run of this script will reset it)." + fail "Please inspect the logs which contain path to the failing patch file (use --debug to get all the details)." + fail "Once you make changes to the conflicting VMR patch, commit it locally and re-run this script." + exit 1 +fi diff --git a/eng/verify-nupkgs.ps1 b/eng/verify-nupkgs.ps1 index cd18465fe1..4e267fc109 100644 --- a/eng/verify-nupkgs.ps1 +++ b/eng/verify-nupkgs.ps1 @@ -20,8 +20,8 @@ function Confirm-NugetPackages { Write-Verbose "Starting Confirm-NugetPackages." $expectedNumOfFiles = @{ "MSTest.Sdk" = 15 - "MSTest.TestFramework" = 154 - "MSTest.TestAdapter" = 93 + "MSTest.TestFramework" = 162 + "MSTest.TestAdapter" = 80 "MSTest" = 14 "MSTest.Analyzers" = 56 } diff --git a/global.json b/global.json index 1814242c89..90d31ae135 100644 --- a/global.json +++ b/global.json @@ -1,21 +1,21 @@ { "tools": { - "dotnet": "10.0.100-preview.4.25206.7", + "dotnet": "10.0.100-preview.7.25368.105", "runtimes": { "dotnet": [ "3.1.32", "6.0.36", "7.0.20", - "8.0.14", - "9.0.3" + "8.0.18", + "9.0.7" ], "dotnet/x86": [ "3.1.32", "6.0.36", - "9.0.3" + "9.0.7" ], "aspnetcore": [ - "9.0.3" + "9.0.7" ] }, "vs": { @@ -23,12 +23,17 @@ } }, "sdk": { - "version": "10.0.100-preview.4.25206.7", + "version": "10.0.100-preview.7.25368.105", + "paths": [ + ".dotnet", + "$host$" + ], + "errorMessage": "The .NET SDK could not be found, please run ./build.cmd on Windows or ./build.sh on Linux and macOS.", "allowPrerelease": true, "rollForward": "latestFeature" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25229.4", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25374.4", "MSBuild.Sdk.Extras": "3.0.44" } } diff --git a/open-code.cmd b/open-code.cmd new file mode 100644 index 0000000000..82dda1d310 --- /dev/null +++ b/open-code.cmd @@ -0,0 +1,2 @@ +@echo off +powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0eng\build.ps1""" -vscode %*" \ No newline at end of file diff --git a/samples/.editorconfig b/samples/.editorconfig index 6fcce99672..2a4c6b6b21 100644 --- a/samples/.editorconfig +++ b/samples/.editorconfig @@ -9,3 +9,6 @@ root = false #### .NET Coding Conventions #### dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none # Disable StyleCop.CSharp.DocumentationRules + +# CA2007: Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.CA2007.severity = none diff --git a/samples/FxExtensibility/FxExtensibility.csproj b/samples/FxExtensibility/FxExtensibility.csproj index 13face57bd..e8a0b1e442 100644 --- a/samples/FxExtensibility/FxExtensibility.csproj +++ b/samples/FxExtensibility/FxExtensibility.csproj @@ -8,9 +8,11 @@ MSTest.Extensibility.Samples MSTest.Extensibility.Samples - TRACE + $(DefineConstants);TRACE prompt 4 + false + $(NoWarn);SA0001;EnableGenerateDocumentationFile diff --git a/samples/Playground/DebuggerUtility.cs b/samples/Playground/DebuggerUtility.cs index 1064e1a597..57f8bdf769 100644 --- a/samples/Playground/DebuggerUtility.cs +++ b/samples/Playground/DebuggerUtility.cs @@ -28,7 +28,7 @@ private static bool AttachVSToProcess(int? pid, int? vsPid, bool enableLog = fal using var process = Process.GetProcessById(pid.Value); Trace($"Starting with pid '{pid}({process.ProcessName})', and vsPid '{vsPid}'", enabled: enableLog); Trace($"Using pid: {pid} to get parent VS.", enabled: enableLog); - Process? vs = GetVsFromPid(Process.GetProcessById(vsPid ?? process.Id)); + using Process? vs = GetVsFromPid(Process.GetProcessById(vsPid ?? process.Id)); if (vs != null) { @@ -38,7 +38,7 @@ private static bool AttachVSToProcess(int? pid, int? vsPid, bool enableLog = fal } Trace("Parent VS not found, finding the first VS that started.", enabled: enableLog); - Process? firstVsProcess = GetFirstVsProcess(); + using Process? firstVsProcess = GetFirstVsProcess(); if (firstVsProcess != null) { @@ -149,7 +149,6 @@ private static bool AttachVs(Process vs, int pid, bool enableLog = false) if (dn.StartsWith("!VisualStudio.DTE.", StringComparison.Ordinal) && dn.EndsWith(dteSuffix, StringComparison.Ordinal)) { - object dbg, lps; runningObjectTable.GetObject(moniker[0], out object dte); // The COM object can be busy, we retry few times, hoping that it won't be busy next time. @@ -157,8 +156,8 @@ private static bool AttachVs(Process vs, int pid, bool enableLog = false) { try { - dbg = dte.GetType().InvokeMember("Debugger", BindingFlags.GetProperty, null, dte, null, CultureInfo.InvariantCulture)!; - lps = dbg.GetType().InvokeMember("LocalProcesses", BindingFlags.GetProperty, null, dbg, null, CultureInfo.InvariantCulture)!; + object dbg = dte.GetType().InvokeMember("Debugger", BindingFlags.GetProperty, null, dte, null, CultureInfo.InvariantCulture)!; + object lps = dbg.GetType().InvokeMember("LocalProcesses", BindingFlags.GetProperty, null, dbg, null, CultureInfo.InvariantCulture)!; var lpn = (System.Collections.IEnumerator)lps.GetType().InvokeMember("GetEnumerator", BindingFlags.InvokeMethod, null, lps, null, CultureInfo.InvariantCulture)!; while (lpn.MoveNext()) diff --git a/samples/Playground/Playground.csproj b/samples/Playground/Playground.csproj index b8570b8348..ba8afed52d 100644 --- a/samples/Playground/Playground.csproj +++ b/samples/Playground/Playground.csproj @@ -5,15 +5,20 @@ net9.0 enable false - $(NoWarn);NETSDK1023 + $(NoWarn);NETSDK1023;SA0001;EnableGenerateDocumentationFile true + false + + + + diff --git a/samples/Playground/Program.cs b/samples/Playground/Program.cs index 4a3d04350a..8e12c8794c 100644 --- a/samples/Playground/Program.cs +++ b/samples/Playground/Program.cs @@ -26,7 +26,7 @@ public static async Task Main(string[] args) { #if NETCOREAPP // To attach to the children - Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess(); + // Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess(); #endif ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args); @@ -57,7 +57,7 @@ public static async Task Main(string[] args) using TestingPlatformClient client = await TestingPlatformClientFactory.StartAsServerAndConnectToTheClientAsync(Environment.ProcessPath!); await client.InitializeAsync(); - List testNodeUpdates = new(); + List testNodeUpdates = []; ResponseListener discoveryResponse = await client.DiscoverTestsAsync(Guid.NewGuid(), node => { testNodeUpdates.AddRange(node); @@ -65,7 +65,7 @@ public static async Task Main(string[] args) }); await discoveryResponse.WaitCompletionAsync(); - ResponseListener runRequest = await client.RunTestsAsync(Guid.NewGuid(), testNodeUpdates.Select(x => x.Node).ToArray(), _ => Task.CompletedTask); + ResponseListener runRequest = await client.RunTestsAsync(Guid.NewGuid(), [.. testNodeUpdates.Select(x => x.Node)], _ => Task.CompletedTask); await runRequest.WaitCompletionAsync(); await client.ExitAsync(); @@ -76,7 +76,7 @@ public static async Task Main(string[] args) } } -internal sealed class DummyAdapter() : ITestFramework, IDataProducer +internal sealed class DummyAdapter : ITestFramework, IDataProducer { public string Uid => nameof(DummyAdapter); @@ -86,7 +86,7 @@ internal sealed class DummyAdapter() : ITestFramework, IDataProducer public string Description => string.Empty; - public Type[] DataTypesProduced => new[] { typeof(TestNodeUpdateMessage) }; + public Type[] DataTypesProduced => [typeof(TestNodeUpdateMessage)]; public Task CloseTestSessionAsync(CloseTestSessionContext context) => Task.FromResult(new CloseTestSessionResult { IsSuccess = true }); diff --git a/samples/Playground/ServerMode/TestNodeUpdateCollector.cs b/samples/Playground/ServerMode/TestNodeUpdateCollector.cs index 067a4f4410..799aab6ab5 100644 --- a/samples/Playground/ServerMode/TestNodeUpdateCollector.cs +++ b/samples/Playground/ServerMode/TestNodeUpdateCollector.cs @@ -10,7 +10,7 @@ public class TestNodeUpdateCollector private readonly TaskCompletionSource _taskCompletionSource = new(); private readonly Func? _completeCollector; - public ConcurrentBag TestNodeUpdates { get; } = new(); + public ConcurrentBag TestNodeUpdates { get; } = []; public TestNodeUpdateCollector(Func? completeCollectorWhen = null) => _completeCollector = completeCollectorWhen; diff --git a/samples/Playground/ServerMode/TestingPlatformClientFactory.cs b/samples/Playground/ServerMode/TestingPlatformClientFactory.cs index 44491c2798..5fe8dc28d6 100644 --- a/samples/Playground/ServerMode/TestingPlatformClientFactory.cs +++ b/samples/Playground/ServerMode/TestingPlatformClientFactory.cs @@ -5,6 +5,7 @@ using System.Net.Sockets; using Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100; +using Microsoft.Testing.TestInfrastructure; namespace MSTest.Acceptance.IntegrationTests.Messages.V100; @@ -382,25 +383,3 @@ public static class WellKnownEnvironmentVariables "TESTINGPLATFORM_CONSOLEOUTPUTDEVICE_SKIP_BANNER" ]; } - -public static class RootFinder -{ - public static string Find() - { - string path = AppContext.BaseDirectory; - string dir = path; - while (Directory.GetDirectoryRoot(dir) != dir) - { - if (Directory.Exists(Path.Combine(dir, ".git"))) - { - return dir; - } - else - { - dir = Directory.GetParent(dir)!.ToString(); - } - } - - throw new InvalidOperationException($"Could not find solution root, .git not found in {path} or any parent directory."); - } -} diff --git a/samples/Playground/ServerMode/v1.0.0/TestingPlatformClient.cs b/samples/Playground/ServerMode/v1.0.0/TestingPlatformClient.cs index 3b40c4d341..d789e2bd04 100644 --- a/samples/Playground/ServerMode/v1.0.0/TestingPlatformClient.cs +++ b/samples/Playground/ServerMode/v1.0.0/TestingPlatformClient.cs @@ -64,14 +64,9 @@ private async Task CheckedInvokeAsync(Func func) { await func(); } - catch (Exception ex) + catch (Exception ex) when (_disconnectionReason.Length > 0) { - if (_disconnectionReason.Length > 0) - { - throw new InvalidOperationException($"{ex.Message}\n{_disconnectionReason}", ex); - } - - throw; + throw new InvalidOperationException($"{ex.Message}\n{_disconnectionReason}", ex); } } @@ -171,11 +166,9 @@ private sealed class TargetHandler private readonly ConcurrentDictionary _listeners = new(); - private readonly ConcurrentBag _logListeners - = new(); + private readonly ConcurrentBag _logListeners = []; - private readonly ConcurrentBag _telemetryPayloads - = new(); + private readonly ConcurrentBag _telemetryPayloads = []; public void RegisterTelemetryListener(TelemetryCollector listener) => _telemetryPayloads.Add(listener); diff --git a/samples/public/Directory.Build.props b/samples/public/Directory.Build.props index 0cee8689b5..fe854da07b 100644 --- a/samples/public/Directory.Build.props +++ b/samples/public/Directory.Build.props @@ -2,12 +2,14 @@ 9.0.0 - 17.13.1 - 3.8.3 - 1.0.0-alpha.25167.5 + 17.14.2 + 3.9.2 + 1.0.0-alpha.25256.6 1.50.0 - 1.6.3 + 1.7.0 17.13.0 + false + $(NoWarn);SA0001;EnableGenerateDocumentationFile diff --git a/samples/public/global.json b/samples/public/global.json index 11074d3c4b..0026bd52f7 100644 --- a/samples/public/global.json +++ b/samples/public/global.json @@ -1,5 +1,5 @@ { "msbuild-sdks": { - "MSTest.Sdk": "3.8.1" + "MSTest.Sdk": "3.9.2" } } diff --git a/src/Adapter/MSTest.Engine/BannedSymbols.txt b/src/Adapter/MSTest.Engine/BannedSymbols.txt index 8c5d85ec6d..f7256d3c54 100644 --- a/src/Adapter/MSTest.Engine/BannedSymbols.txt +++ b/src/Adapter/MSTest.Engine/BannedSymbols.txt @@ -2,5 +2,5 @@ M:System.Threading.Tasks.Task.Run(System.Func{System.Threading.Tasks.Task},System.Threading.CancellationToken); Use 'ITask' instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Adapter/MSTest.Engine/Engine/BFSTestNodeVisitor.cs b/src/Adapter/MSTest.Engine/Engine/BFSTestNodeVisitor.cs index 9d3cf88a38..faa7301a1b 100644 --- a/src/Adapter/MSTest.Engine/Engine/BFSTestNodeVisitor.cs +++ b/src/Adapter/MSTest.Engine/Engine/BFSTestNodeVisitor.cs @@ -9,7 +9,6 @@ namespace Microsoft.Testing.Framework; -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. internal sealed class BFSTestNodeVisitor { private readonly IEnumerable _rootTestNodes; @@ -29,12 +28,12 @@ public BFSTestNodeVisitor(IEnumerable rootTestNodes, ITestExecutionFil _testArgumentsManager = testArgumentsManager; } - internal KeyValuePair>[] DuplicatedNodes { get; private set; } = Array.Empty>>(); + internal KeyValuePair>[] DuplicatedNodes { get; private set; } = []; public async Task VisitAsync(Func onIncludedTestNodeAsync) { // This is case sensitive, and culture insensitive, to keep UIDs unique, and comparable between different system. - Dictionary> testNodesByUid = new(); + Dictionary> testNodesByUid = []; Queue<(TestNode CurrentNode, TestNodeUid? ParentNodeUid, StringBuilder NodeFullPath)> queue = new(); foreach (TestNode node in _rootTestNodes) { @@ -47,7 +46,7 @@ public async Task VisitAsync(Func onIncludedTestNo if (!testNodesByUid.TryGetValue(currentNode.StableUid, out List? testNodes)) { - testNodes = new(); + testNodes = []; testNodesByUid.Add(currentNode.StableUid, testNodes); } @@ -78,14 +77,14 @@ public async Task VisitAsync(Func onIncludedTestNo // If the node is expandable, we expand it (replacing the original node) if (TestArgumentsManager.IsExpandableTestNode(currentNode)) { - currentNode = await _testArgumentsManager.ExpandTestNodeAsync(currentNode); + currentNode = await _testArgumentsManager.ExpandTestNodeAsync(currentNode).ConfigureAwait(false); } // If the node is not filtered out by the test execution filter, we call the callback with the node. if (_testExecutionFilter is not TestNodeUidListFilter listFilter || listFilter.TestNodeUids.Any(uid => currentNode.StableUid.ToPlatformTestNodeUid() == uid)) { - await onIncludedTestNodeAsync(currentNode, parentNodeUid); + await onIncludedTestNodeAsync(currentNode, parentNodeUid).ConfigureAwait(false); } foreach (TestNode childNode in currentNode.Tests) @@ -94,7 +93,7 @@ public async Task VisitAsync(Func onIncludedTestNo } } - DuplicatedNodes = testNodesByUid.Where(x => x.Value.Count > 1).ToArray(); + DuplicatedNodes = [.. testNodesByUid.Where(x => x.Value.Count > 1)]; } private static PropertyBag CreatePropertyBagForFilter(IProperty[] properties) diff --git a/src/Adapter/MSTest.Engine/Engine/TestArgumentsManager.cs b/src/Adapter/MSTest.Engine/Engine/TestArgumentsManager.cs index 1003fe27ef..1fb6ec6235 100644 --- a/src/Adapter/MSTest.Engine/Engine/TestArgumentsManager.cs +++ b/src/Adapter/MSTest.Engine/Engine/TestArgumentsManager.cs @@ -3,11 +3,13 @@ using Microsoft.Testing.Platform; +using Polyfills; + namespace Microsoft.Testing.Framework; internal sealed class TestArgumentsManager : ITestArgumentsManager { - private readonly Dictionary> _testArgumentsEntryProviders = new(); + private readonly Dictionary> _testArgumentsEntryProviders = []; private bool _isRegistrationFrozen; public void RegisterTestArgumentsEntryProvider( @@ -19,12 +21,10 @@ public void RegisterTestArgumentsEntryProvider( throw new InvalidOperationException("Cannot register TestArgumentsEntry provider after registration is frozen."); } - if (_testArgumentsEntryProviders.ContainsKey(testNodeStableUid)) + if (!_testArgumentsEntryProviders.TryAdd(testNodeStableUid, argumentPropertiesProviderCallback)) { throw new InvalidOperationException($"TestArgumentsEntry provider is already registered for test node with UID '{testNodeStableUid}'."); } - - _testArgumentsEntryProviders.Add(testNodeStableUid, argumentPropertiesProviderCallback); } internal void FreezeRegistration() => _isRegistrationFrozen = true; @@ -37,8 +37,6 @@ internal async Task ExpandTestNodeAsync(TestNode currentNode) { RoslynDebug.Assert(IsExpandableTestNode(currentNode), "Test node is not expandable"); - var expandableTestNode = (IExpandableTestNode)currentNode; - int argumentsRowIndex = -1; bool isIndexArgumentPropertiesProvider = false; if (!_testArgumentsEntryProviders.TryGetValue( @@ -53,8 +51,8 @@ internal async Task ExpandTestNodeAsync(TestNode currentNode) }; } - HashSet expandedTestNodeUids = new(); - List expandedTestNodes = new(currentNode.Tests); + HashSet expandedTestNodeUids = []; + List expandedTestNodes = [.. currentNode.Tests]; switch (currentNode) { case IParameterizedTestNode parameterizedTestNode: @@ -67,7 +65,7 @@ internal async Task ExpandTestNodeAsync(TestNode currentNode) break; case ITaskParameterizedTestNode parameterizedTestNode: - foreach (object? arguments in await parameterizedTestNode.GetArguments()) + foreach (object? arguments in await parameterizedTestNode.GetArguments().ConfigureAwait(false)) { ExpandNodeWithArguments(currentNode, arguments, ref argumentsRowIndex, expandedTestNodes, expandedTestNodeUids, argumentPropertiesProvider, isIndexArgumentPropertiesProvider); @@ -77,7 +75,7 @@ internal async Task ExpandTestNodeAsync(TestNode currentNode) #if NET case IAsyncParameterizedTestNode parameterizedTestNode: - await foreach (object? arguments in parameterizedTestNode.GetArguments()) + await foreach (object? arguments in parameterizedTestNode.GetArguments().ConfigureAwait(false)) { ExpandNodeWithArguments(currentNode, arguments, ref argumentsRowIndex, expandedTestNodes, expandedTestNodeUids, argumentPropertiesProvider, isIndexArgumentPropertiesProvider); @@ -98,7 +96,7 @@ internal async Task ExpandTestNodeAsync(TestNode currentNode) DisplayName = currentNode.DisplayName, OverriddenEdgeName = currentNode.OverriddenEdgeName, Properties = currentNode.Properties, - Tests = expandedTestNodes.ToArray(), + Tests = [.. expandedTestNodes], }; return expandedNode; diff --git a/src/Adapter/MSTest.Engine/Engine/TestFixtureManager.cs b/src/Adapter/MSTest.Engine/Engine/TestFixtureManager.cs index 4c26895bc4..9da126c44b 100644 --- a/src/Adapter/MSTest.Engine/Engine/TestFixtureManager.cs +++ b/src/Adapter/MSTest.Engine/Engine/TestFixtureManager.cs @@ -10,13 +10,13 @@ namespace Microsoft.Testing.Framework; internal sealed class TestFixtureManager : ITestFixtureManager { - private readonly Dictionary>> _fixtureInstancesByFixtureId = new(); - private readonly Dictionary _fixtureIdsUsedByTestNode = new(); + private readonly Dictionary>> _fixtureInstancesByFixtureId = []; + private readonly Dictionary _fixtureIdsUsedByTestNode = []; // We could improve this by doing some optimistic lock but we expect a rather low contention on this. // We use a dictionary as performance improvement because we know that when the registration is complete // we will only read the collection (so no need for concurrency handling). - private readonly Dictionary _fixtureUses = new(); + private readonly Dictionary _fixtureUses = []; private readonly CancellationToken _cancellationToken; private bool _isRegistrationFrozen; private bool _isUsageRegistrationFrozen; @@ -58,7 +58,7 @@ public async Task GetFixtureAsync(string fixtureId) if (!fixture.IsValueCreated || !fixture.Value.IsCompleted) { - await fixture.Value; + await fixture.Value.ConfigureAwait(false); } // We can safely cast here because we know that the fixture is of type TFixture and is awaited. @@ -79,7 +79,7 @@ internal void RegisterFixtureUsage(TestNode testNode, string[] fixtureIds) return; } - _fixtureIdsUsedByTestNode.Add(testNode, fixtureIds.Select(x => new FixtureId(x)).ToArray()); + _fixtureIdsUsedByTestNode.Add(testNode, [.. fixtureIds.Select(x => new FixtureId(x))]); foreach (string fixtureId in fixtureIds) { if (!_fixtureUses.TryGetValue(fixtureId, out CountHolder? uses)) @@ -114,7 +114,7 @@ internal async Task SetupUsedFixturesAsync(TestNode testNode) { if (!lazyFixture.IsValueCreated || !lazyFixture.Value.IsCompleted) { - await lazyFixture.Value; + await lazyFixture.Value.ConfigureAwait(false); } } } @@ -142,7 +142,7 @@ internal async Task CleanUnusedFixturesAsync(TestNode testNode) // cleaning the fixture multiple times. if (usesCount == 0) { - await CleanupAndDisposeFixtureAsync(fixtureId); + await CleanupAndDisposeFixtureAsync(fixtureId).ConfigureAwait(false); } } } @@ -167,7 +167,7 @@ private void TryRegisterFixture(string fixtureId, Func> { fixtureInstancesPerType.Add( typeof(TFixture), - new(async () => await CreateAndInitializeFixtureAsync(asyncFactory, _cancellationToken), LazyThreadSafetyMode.ExecutionAndPublication)); + new(async () => await CreateAndInitializeFixtureAsync(asyncFactory, _cancellationToken).ConfigureAwait(false), LazyThreadSafetyMode.ExecutionAndPublication)); } } else @@ -177,14 +177,14 @@ private void TryRegisterFixture(string fixtureId, Func> new() { [typeof(TFixture)] = new( - async () => await CreateAndInitializeFixtureAsync(asyncFactory, _cancellationToken), + async () => await CreateAndInitializeFixtureAsync(asyncFactory, _cancellationToken).ConfigureAwait(false), LazyThreadSafetyMode.ExecutionAndPublication), }); } static async Task CreateAndInitializeFixtureAsync(Func> asyncFactory, CancellationToken cancellationToken) { - TFixture fixture = await asyncFactory(); + TFixture fixture = await asyncFactory().ConfigureAwait(false); return fixture; } } @@ -207,7 +207,7 @@ private async Task CleanupAndDisposeFixtureAsync(FixtureId fixtureId) object fixture = lazyFixture.Value.Result; #pragma warning restore VSTHRD103 // Call async methods when in an async method - await DisposeHelper.DisposeAsync(fixture); + await DisposeHelper.DisposeAsync(fixture).ConfigureAwait(false); } } diff --git a/src/Adapter/MSTest.Engine/Engine/TestFrameworkEngine.cs b/src/Adapter/MSTest.Engine/Engine/TestFrameworkEngine.cs index f78f930f7a..00527b1d27 100644 --- a/src/Adapter/MSTest.Engine/Engine/TestFrameworkEngine.cs +++ b/src/Adapter/MSTest.Engine/Engine/TestFrameworkEngine.cs @@ -38,8 +38,7 @@ public TestFrameworkEngine(TestFrameworkConfiguration testFrameworkConfiguration _configuration = new(configuration); } - public Type[] DataTypesProduced { get; } - = new Type[1] { typeof(TestNodeUpdateMessage) }; + public Type[] DataTypesProduced { get; } = [typeof(TestNodeUpdateMessage)]; public string Uid => _extension.Uid; @@ -49,20 +48,20 @@ public TestFrameworkEngine(TestFrameworkConfiguration testFrameworkConfiguration public string Description => _extension.Description; - public async Task IsEnabledAsync() => await _extension.IsEnabledAsync(); + public async Task IsEnabledAsync() => await _extension.IsEnabledAsync().ConfigureAwait(false); public async Task ExecuteRequestAsync(TestExecutionRequest testExecutionRequest, IMessageBus messageBus, CancellationToken cancellationToken) => testExecutionRequest switch { - DiscoverTestExecutionRequest discoveryRequest => await ExecuteTestNodeDiscoveryAsync(discoveryRequest, messageBus, cancellationToken), - RunTestExecutionRequest runRequest => await ExecuteTestNodeRunAsync(runRequest, messageBus, cancellationToken), + DiscoverTestExecutionRequest discoveryRequest => await ExecuteTestNodeDiscoveryAsync(discoveryRequest, messageBus, cancellationToken).ConfigureAwait(false), + RunTestExecutionRequest runRequest => await ExecuteTestNodeRunAsync(runRequest, messageBus, cancellationToken).ConfigureAwait(false), _ => Result.Fail($"Unexpected request type: '{testExecutionRequest.GetType().FullName}'"), }; private async Task ExecuteTestNodeRunAsync(RunTestExecutionRequest request, IMessageBus messageBus, CancellationToken cancellationToken) { - List allRootTestNodes = new(); + List allRootTestNodes = []; TestFixtureManager fixtureManager = new(cancellationToken); TestArgumentsManager argumentsManager = new(); TestSessionContext testSessionContext = new(_configuration, fixtureManager, argumentsManager, request.Session.SessionUid, @@ -72,7 +71,7 @@ private async Task ExecuteTestNodeRunAsync(RunTestExecutionRequest reque { foreach (ITestNodesBuilder testNodeBuilder in _testNodesBuilders) { - TestNode[] testNodes = await testNodeBuilder.BuildAsync(testSessionContext); + TestNode[] testNodes = await testNodeBuilder.BuildAsync(testSessionContext).ConfigureAwait(false); allRootTestNodes.AddRange(testNodes); } @@ -96,11 +95,11 @@ await testNodesVisitor.VisitAsync((testNode, parentTestNodeUid) => .OfType() .SingleOrDefault() .UsedFixtureIds - ?? Array.Empty(); + ?? []; fixtureManager.RegisterFixtureUsage(testNode, fixtureIds); return Task.CompletedTask; - }); + }).ConfigureAwait(false); if (testNodesVisitor.DuplicatedNodes.Length > 0) { @@ -120,13 +119,13 @@ await testNodesVisitor.VisitAsync((testNode, parentTestNodeUid) => testNodeRunner.StartTests(); // Finally, we want to wait for all tests to complete. - return await testNodeRunner.WaitAllTestsAsync(cancellationToken); + return await testNodeRunner.WaitAllTestsAsync(cancellationToken).ConfigureAwait(false); } finally { foreach (ITestNodesBuilder testNodeBuilder in _testNodesBuilders) { - await DisposeHelper.DisposeAsync(testNodeBuilder); + await DisposeHelper.DisposeAsync(testNodeBuilder).ConfigureAwait(false); } } @@ -142,7 +141,7 @@ Task PublishDataAsync(IData data) private async Task ExecuteTestNodeDiscoveryAsync(DiscoverTestExecutionRequest request, IMessageBus messageBus, CancellationToken cancellationToken) { - List allRootTestNodes = new(); + List allRootTestNodes = []; TestFixtureManager fixtureManager = new(cancellationToken); TestArgumentsManager argumentsManager = new(); TestSessionContext testSessionContext = new(_configuration, fixtureManager, argumentsManager, request.Session.SessionUid, @@ -152,7 +151,7 @@ private async Task ExecuteTestNodeDiscoveryAsync(DiscoverTestExecutionRe { foreach (ITestNodesBuilder testNodeBuilder in _testNodesBuilders) { - TestNode[] testNodes = await testNodeBuilder.BuildAsync(testSessionContext); + TestNode[] testNodes = await testNodeBuilder.BuildAsync(testSessionContext).ConfigureAwait(false); allRootTestNodes.AddRange(testNodes); } @@ -172,8 +171,8 @@ await testNodesVisitor.VisitAsync(async (testNode, parentTestNodeUid) => } await messageBus.PublishAsync(this, new TestNodeUpdateMessage(request.Session.SessionUid, progressNode, - parentTestNodeUid?.ToPlatformTestNodeUid())); - }); + parentTestNodeUid?.ToPlatformTestNodeUid())).ConfigureAwait(false); + }).ConfigureAwait(false); if (testNodesVisitor.DuplicatedNodes.Length > 0) { @@ -192,7 +191,7 @@ await testNodesVisitor.VisitAsync(async (testNode, parentTestNodeUid) => { foreach (ITestNodesBuilder testNodeBuilder in _testNodesBuilders) { - await DisposeHelper.DisposeAsync(testNodeBuilder); + await DisposeHelper.DisposeAsync(testNodeBuilder).ConfigureAwait(false); } } diff --git a/src/Adapter/MSTest.Engine/Engine/TestSessionContext.cs b/src/Adapter/MSTest.Engine/Engine/TestSessionContext.cs index 8db024032c..22042a1e5b 100644 --- a/src/Adapter/MSTest.Engine/Engine/TestSessionContext.cs +++ b/src/Adapter/MSTest.Engine/Engine/TestSessionContext.cs @@ -27,5 +27,5 @@ public TestSessionContext(IConfiguration configuration, ITestFixtureManager _, I public IConfiguration Configuration { get; } public async Task AddTestAttachmentAsync(FileInfo file, string displayName, string? description = null) - => await _publishDataAsync(new SessionFileArtifact(_sessionUid, file, displayName, description)); + => await _publishDataAsync(new SessionFileArtifact(_sessionUid, file, displayName, description)).ConfigureAwait(false); } diff --git a/src/Adapter/MSTest.Engine/Engine/ThreadPoolTestNodeRunner.cs b/src/Adapter/MSTest.Engine/Engine/ThreadPoolTestNodeRunner.cs index 3ef4aa070f..3070130114 100644 --- a/src/Adapter/MSTest.Engine/Engine/ThreadPoolTestNodeRunner.cs +++ b/src/Adapter/MSTest.Engine/Engine/ThreadPoolTestNodeRunner.cs @@ -16,7 +16,7 @@ namespace Microsoft.Testing.Framework; internal sealed class ThreadPoolTestNodeRunner : IDisposable { private readonly SemaphoreSlim? _maxParallelTests; - private readonly ConcurrentBag> _runningTests = new(); + private readonly ConcurrentBag> _runningTests = []; private readonly ConcurrentDictionary _runningTestNodeUids = new(); private readonly CountdownEvent _ensureTaskQueuedCountdownEvent = new(1); private readonly Func _publishDataAsync; @@ -63,12 +63,12 @@ public void EnqueueTest(TestNode frameworkTestNode, TestNodeUid? parentTestNodeU { // We don't have a timeout here because we can have really slow fixture and it's on user // the decision on how much to wait for it. - await _waitForStart.Task; + await _waitForStart.Task.ConfigureAwait(false); // Handle the global parallelism. if (_maxParallelTests is not null) { - await _maxParallelTests.WaitAsync(); + await _maxParallelTests.WaitAsync().ConfigureAwait(false); } try @@ -77,9 +77,9 @@ public void EnqueueTest(TestNode frameworkTestNode, TestNodeUid? parentTestNodeU PlatformTestNode progressNode = frameworkTestNode.ToPlatformTestNode(); progressNode.Properties.Add(InProgressTestNodeStateProperty.CachedInstance); - await _publishDataAsync(new TestNodeUpdateMessage(_sessionUid, progressNode, parentTestNodeUid?.ToPlatformTestNodeUid())); + await _publishDataAsync(new TestNodeUpdateMessage(_sessionUid, progressNode, parentTestNodeUid?.ToPlatformTestNodeUid())).ConfigureAwait(false); - Result result = await CreateTestRunTaskAsync(frameworkTestNode, parentTestNodeUid); + Result result = await CreateTestRunTaskAsync(frameworkTestNode, parentTestNodeUid).ConfigureAwait(false); _runningTestNodeUids.TryRemove(frameworkTestNode.StableUid, out int count); @@ -118,7 +118,7 @@ private async Task CreateTestRunTaskAsync(TestNode testNode, TestNodeUid { try { - await _testFixtureManager.SetupUsedFixturesAsync(testNode); + await _testFixtureManager.SetupUsedFixturesAsync(testNode).ConfigureAwait(false); } catch (Exception ex) { @@ -135,7 +135,7 @@ private async Task CreateTestRunTaskAsync(TestNode testNode, TestNodeUid switch (testNode) { case IAsyncActionTestNode actionTestNode: - await actionTestNode.InvokeAsync(testExecutionContext); + await actionTestNode.InvokeAsync(testExecutionContext).ConfigureAwait(false); break; case IActionTestNode actionTestNode: @@ -145,7 +145,7 @@ private async Task CreateTestRunTaskAsync(TestNode testNode, TestNodeUid case IParameterizedAsyncActionTestNode actionTestNode: await actionTestNode.InvokeAsync( testExecutionContext, - action => InvokeTestNodeAndPublishResultAsync(testNode, parentTestNodeUid, (_, _) => action(), skipPublishResult: false)); + action => InvokeTestNodeAndPublishResultAsync(testNode, parentTestNodeUid, (_, _) => action(), skipPublishResult: false)).ConfigureAwait(false); break; default: @@ -154,12 +154,12 @@ await actionTestNode.InvokeAsync( }, // Because parameterized tests report multiple results (one per parameter set), we don't want to publish the result // of the overall test node execution, but only the results of the individual parameterized tests. - skipPublishResult: testNode is IParameterizedAsyncActionTestNode); + skipPublishResult: testNode is IParameterizedAsyncActionTestNode).ConfigureAwait(false); // Try to cleanup the fixture is not more used. try { - await _testFixtureManager.CleanUnusedFixturesAsync(testNode); + await _testFixtureManager.CleanUnusedFixturesAsync(testNode).ConfigureAwait(false); return result; } catch (Exception ex) @@ -177,8 +177,8 @@ public async Task WaitAllTestsAsync(CancellationToken cancellationToken) try { _ensureTaskQueuedCountdownEvent.Signal(); - await _ensureTaskQueuedCountdownEvent.WaitAsync(cancellationToken); - Result[] results = await Task.WhenAll(_runningTests); + await _ensureTaskQueuedCountdownEvent.WaitAsync(cancellationToken).ConfigureAwait(false); + Result[] results = await Task.WhenAll(_runningTests).ConfigureAwait(false); return Result.Combine(results); } catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken) @@ -216,7 +216,7 @@ private async Task InvokeTestNodeAndPublishResultAsync(TestNode testNode // If we're already enqueued we cancel the test before the start // The test could not use the cancellation and we should wait the end of the test self to cancel. _cancellationToken.ThrowIfCancellationRequested(); - await testNodeInvokeAction(testNode, testExecutionContext); + await testNodeInvokeAction(testNode, testExecutionContext).ConfigureAwait(false); if (!platformTestNode.Properties.Any()) { @@ -245,7 +245,7 @@ private async Task InvokeTestNodeAndPublishResultAsync(TestNode testNode if (!skipPublishResult) { - await _publishDataAsync(new TestNodeUpdateMessage(_sessionUid, platformTestNode, parentTestNodeUid?.ToPlatformTestNodeUid())); + await _publishDataAsync(new TestNodeUpdateMessage(_sessionUid, platformTestNode, parentTestNodeUid?.ToPlatformTestNodeUid())).ConfigureAwait(false); } return Result.Ok(); diff --git a/src/Adapter/MSTest.Engine/Helpers/ISuccessReason.cs b/src/Adapter/MSTest.Engine/Helpers/ISuccessReason.cs index e9f739f4e5..5952b324bf 100644 --- a/src/Adapter/MSTest.Engine/Helpers/ISuccessReason.cs +++ b/src/Adapter/MSTest.Engine/Helpers/ISuccessReason.cs @@ -3,6 +3,4 @@ namespace Microsoft.Testing.Framework; -internal interface ISuccessReason : IReason -{ -} +internal interface ISuccessReason : IReason; diff --git a/src/Adapter/MSTest.Engine/Helpers/IWarningReason.cs b/src/Adapter/MSTest.Engine/Helpers/IWarningReason.cs index 7b38a5ea9c..e5a50b9aba 100644 --- a/src/Adapter/MSTest.Engine/Helpers/IWarningReason.cs +++ b/src/Adapter/MSTest.Engine/Helpers/IWarningReason.cs @@ -3,6 +3,4 @@ namespace Microsoft.Testing.Framework; -internal interface IWarningReason : IReason -{ -} +internal interface IWarningReason : IReason; diff --git a/src/Adapter/MSTest.Engine/Helpers/Result.cs b/src/Adapter/MSTest.Engine/Helpers/Result.cs index 6f6a70af1d..881c9fa4d1 100644 --- a/src/Adapter/MSTest.Engine/Helpers/Result.cs +++ b/src/Adapter/MSTest.Engine/Helpers/Result.cs @@ -5,7 +5,7 @@ namespace Microsoft.Testing.Framework; internal sealed class Result { - private readonly List _reasons = new(); + private readonly List _reasons = []; private Result() { diff --git a/src/Adapter/MSTest.Engine/TestFramework/TestFramework.cs b/src/Adapter/MSTest.Engine/TestFramework/TestFramework.cs index 1fb61c5f9d..88e34f3fea 100644 --- a/src/Adapter/MSTest.Engine/TestFramework/TestFramework.cs +++ b/src/Adapter/MSTest.Engine/TestFramework/TestFramework.cs @@ -23,8 +23,8 @@ internal sealed class TestFramework : IDisposable, ITestFramework private readonly TestingFrameworkExtension _extension; private readonly CountdownEvent _incomingRequestCounter = new(1); private readonly TestFrameworkEngine _engine; - private readonly List _sessionWarningMessages = new(); - private readonly List _sessionErrorMessages = new(); + private readonly List _sessionWarningMessages = []; + private readonly List _sessionErrorMessages = []; private SessionUid? _sessionId; public TestFramework(TestFrameworkConfiguration testFrameworkConfiguration, ITestNodesBuilder[] testNodesBuilders, TestingFrameworkExtension extension, @@ -47,7 +47,7 @@ public TestFramework(TestFrameworkConfiguration testFrameworkConfiguration, ITes public string Description => _extension.Description; /// - public async Task IsEnabledAsync() => await _extension.IsEnabledAsync(); + public async Task IsEnabledAsync() => await _extension.IsEnabledAsync().ConfigureAwait(false); public Task CreateTestSessionAsync(CreateTestSessionContext context) { @@ -71,7 +71,7 @@ public async Task CloseTestSessionAsync(CloseTestSession { // Ensure we have finished processing all requests. _incomingRequestCounter.Signal(); - await _incomingRequestCounter.WaitAsync(context.CancellationToken); + await _incomingRequestCounter.WaitAsync(context.CancellationToken).ConfigureAwait(false); if (_sessionErrorMessages.Count > 0) { @@ -121,7 +121,7 @@ public async Task ExecuteRequestAsync(ExecuteRequestContext context) throw new InvalidOperationException($"Request type '{context.Request.GetType().FullName}' is not supported"); } - Result result = await _engine.ExecuteRequestAsync(testExecutionRequest, context.MessageBus, context.CancellationToken); + Result result = await _engine.ExecuteRequestAsync(testExecutionRequest, context.MessageBus, context.CancellationToken).ConfigureAwait(false); foreach (IReason reason in result.Reasons) { diff --git a/src/Adapter/MSTest.Engine/TestFramework/TestFrameworkCapabilities.cs b/src/Adapter/MSTest.Engine/TestFramework/TestFrameworkCapabilities.cs index 868a1e63db..c7a853b973 100644 --- a/src/Adapter/MSTest.Engine/TestFramework/TestFrameworkCapabilities.cs +++ b/src/Adapter/MSTest.Engine/TestFramework/TestFrameworkCapabilities.cs @@ -18,7 +18,7 @@ public TestFrameworkCapabilities(ITestNodesBuilder[] testNodesBuilders, IBannerM } public IReadOnlyCollection Capabilities - => new[] { new TestFrameworkCapabilitiesSet(_testNodesBuilders), _bannerMessageOwnerCapability }; + => [new TestFrameworkCapabilitiesSet(_testNodesBuilders), _bannerMessageOwnerCapability]; } internal sealed class TestFrameworkCapabilitiesSet : @@ -39,7 +39,7 @@ public TestFrameworkCapabilitiesSet(ITestNodesBuilder[] testNodesBuilders) public bool IsTrxReportCapabilitySupported { get; } - bool ITestNodesTreeFilterTestFrameworkCapability.IsSupported { get; } = true; + bool ITestNodesTreeFilterTestFrameworkCapability.IsSupported => true; bool ITrxReportCapability.IsSupported => IsTrxReportCapabilitySupported; diff --git a/src/Adapter/MSTest.Engine/TestNodes/FactoryTestNodesBuilder.cs b/src/Adapter/MSTest.Engine/TestNodes/FactoryTestNodesBuilder.cs index 8f2b9bc3b6..eaad6454de 100644 --- a/src/Adapter/MSTest.Engine/TestNodes/FactoryTestNodesBuilder.cs +++ b/src/Adapter/MSTest.Engine/TestNodes/FactoryTestNodesBuilder.cs @@ -15,8 +15,7 @@ public FactoryTestNodesBuilder(Func testNodesFactory) public bool IsSupportingTrxProperties { get; } - IReadOnlyCollection ICapabilities.Capabilities - => Array.Empty(); + IReadOnlyCollection ICapabilities.Capabilities => []; public Task BuildAsync(ITestSessionContext _) => Task.FromResult(_testNodesFactory()); } diff --git a/src/Adapter/MSTest.Engine/TestNodes/FrameworkTestNodeProperties.cs b/src/Adapter/MSTest.Engine/TestNodes/FrameworkTestNodeProperties.cs index 718e6b8b40..3c61f91f6c 100644 --- a/src/Adapter/MSTest.Engine/TestNodes/FrameworkTestNodeProperties.cs +++ b/src/Adapter/MSTest.Engine/TestNodes/FrameworkTestNodeProperties.cs @@ -9,5 +9,5 @@ internal readonly struct FrameworkEngineMetadataProperty() : IProperty { public bool PreventArgumentsExpansion { get; init; } - public string[] UsedFixtureIds { get; init; } = Array.Empty(); + public string[] UsedFixtureIds { get; init; } = []; } diff --git a/src/Adapter/MSTest.Engine/TestNodes/IActionableTestNode.cs b/src/Adapter/MSTest.Engine/TestNodes/IActionableTestNode.cs index 158cd96a6e..2631b535d2 100644 --- a/src/Adapter/MSTest.Engine/TestNodes/IActionableTestNode.cs +++ b/src/Adapter/MSTest.Engine/TestNodes/IActionableTestNode.cs @@ -3,6 +3,4 @@ namespace Microsoft.Testing.Framework; -internal interface IActionableTestNode -{ -} +internal interface IActionableTestNode; diff --git a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeActionParameterizedTestNode.cs b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeActionParameterizedTestNode.cs index 749b65b3a0..2f2f7ad49f 100644 --- a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeActionParameterizedTestNode.cs +++ b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeActionParameterizedTestNode.cs @@ -26,7 +26,7 @@ await safeInvoke(() => { Body(testExecutionContext, item); return Task.CompletedTask; - }); + }).ConfigureAwait(false); } } diff --git a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeActionTaskParameterizedTestNode.cs b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeActionTaskParameterizedTestNode.cs index 28dffaa306..b5a195628c 100644 --- a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeActionTaskParameterizedTestNode.cs +++ b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeActionTaskParameterizedTestNode.cs @@ -16,17 +16,17 @@ public sealed class InternalUnsafeActionTaskParameterizedTestNode public required Func>> GetArguments { get; init; } - Func> ITaskParameterizedTestNode.GetArguments => async () => await GetArguments(); + Func> ITaskParameterizedTestNode.GetArguments => async () => await GetArguments().ConfigureAwait(false); async Task IParameterizedAsyncActionTestNode.InvokeAsync(ITestExecutionContext testExecutionContext, Func, Task> safeInvoke) { - foreach (TData item in await GetArguments()) + foreach (TData item in await GetArguments().ConfigureAwait(false)) { await safeInvoke(() => { Body(testExecutionContext, item); return Task.CompletedTask; - }); + }).ConfigureAwait(false); } } diff --git a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionParameterizedTestNode.cs b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionParameterizedTestNode.cs index 3dbc8ace32..84a220e558 100644 --- a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionParameterizedTestNode.cs +++ b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionParameterizedTestNode.cs @@ -22,7 +22,7 @@ async Task IParameterizedAsyncActionTestNode.InvokeAsync(ITestExecutionContext t { foreach (TData item in GetArguments()) { - await safeInvoke(async () => await Body(testExecutionContext, item)); + await safeInvoke(async () => await Body(testExecutionContext, item).ConfigureAwait(false)).ConfigureAwait(false); } } diff --git a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionTaskParameterizedTestNode.cs b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionTaskParameterizedTestNode.cs index f27470ba19..1a56446928 100644 --- a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionTaskParameterizedTestNode.cs +++ b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionTaskParameterizedTestNode.cs @@ -16,13 +16,13 @@ public sealed class InternalUnsafeAsyncActionTaskParameterizedTestNode public required Func>> GetArguments { get; init; } - Func> ITaskParameterizedTestNode.GetArguments => async () => await GetArguments(); + Func> ITaskParameterizedTestNode.GetArguments => async () => await GetArguments().ConfigureAwait(false); async Task IParameterizedAsyncActionTestNode.InvokeAsync(ITestExecutionContext testExecutionContext, Func, Task> safeInvoke) { - foreach (TData item in await GetArguments()) + foreach (TData item in await GetArguments().ConfigureAwait(false)) { - await safeInvoke(async () => await Body(testExecutionContext, item)); + await safeInvoke(async () => await Body(testExecutionContext, item).ConfigureAwait(false)).ConfigureAwait(false); } } diff --git a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionTestNode.cs b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionTestNode.cs index 5d8a0aa48a..f6abe9f436 100644 --- a/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionTestNode.cs +++ b/src/Adapter/MSTest.Engine/TestNodes/InternalUnsafeAsyncActionTestNode.cs @@ -11,5 +11,5 @@ public sealed class InternalUnsafeAsyncActionTestNode : TestNode, IAsyncActionTe public required Func Body { get; init; } async Task IAsyncActionTestNode.InvokeAsync(ITestExecutionContext testExecutionContext) - => await Body(testExecutionContext); + => await Body(testExecutionContext).ConfigureAwait(false); } diff --git a/src/Adapter/MSTest.Engine/TestNodes/TestNode.cs b/src/Adapter/MSTest.Engine/TestNodes/TestNode.cs index 58f015c055..8119973fde 100644 --- a/src/Adapter/MSTest.Engine/TestNodes/TestNode.cs +++ b/src/Adapter/MSTest.Engine/TestNodes/TestNode.cs @@ -17,7 +17,7 @@ public class TestNode /// public string? OverriddenEdgeName { get; init; } - public IProperty[] Properties { get; init; } = Array.Empty(); + public IProperty[] Properties { get; init; } = []; - public TestNode[] Tests { get; init; } = Array.Empty(); + public TestNode[] Tests { get; init; } = []; } diff --git a/src/Adapter/MSTest.TestAdapter/Execution/ClassCleanupManager.cs b/src/Adapter/MSTest.TestAdapter/Execution/ClassCleanupManager.cs deleted file mode 100644 index fca58e95d8..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Execution/ClassCleanupManager.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; -using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; -using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; - -internal sealed class ClassCleanupManager -{ - private readonly ClassCleanupBehavior? _lifecycleFromMsTest; - private readonly ClassCleanupBehavior _lifecycleFromAssembly; - private readonly ReflectHelper _reflectHelper; - private readonly ConcurrentDictionary> _remainingTestsByClass; - - public ClassCleanupManager( - IEnumerable testsToRun, - ClassCleanupBehavior? lifecycleFromMsTest, - ClassCleanupBehavior lifecycleFromAssembly, - ReflectHelper reflectHelper) - { - IEnumerable runnableTests = testsToRun.Where(t => t.Traits is null || !t.Traits.Any(t => t.Name == Constants.FixturesTestTrait)); - _remainingTestsByClass = - new(runnableTests.GroupBy(t => t.TestMethod.FullClassName) - .ToDictionary( - g => g.Key, - g => new List(g.Select(t => t.TestMethod.UniqueName)))); - _lifecycleFromMsTest = lifecycleFromMsTest; - _lifecycleFromAssembly = lifecycleFromAssembly; - _reflectHelper = reflectHelper; - } - - public bool ShouldRunEndOfAssemblyCleanup { get; private set; } - - public void MarkTestComplete(TestMethodInfo testMethodInfo, TestMethod testMethod, out bool shouldRunEndOfClassCleanup) - { - shouldRunEndOfClassCleanup = false; - if (!_remainingTestsByClass.TryGetValue(testMethodInfo.TestClassName, out List? testsByClass)) - { - return; - } - - lock (testsByClass) - { - testsByClass.Remove(testMethod.UniqueName); - if (testsByClass.Count == 0) - { - _remainingTestsByClass.TryRemove(testMethodInfo.TestClassName, out _); - if (testMethodInfo.Parent.HasExecutableCleanupMethod) - { - ClassCleanupBehavior cleanupLifecycle = _reflectHelper.GetClassCleanupBehavior(testMethodInfo.Parent) - ?? _lifecycleFromMsTest - ?? _lifecycleFromAssembly; - - shouldRunEndOfClassCleanup = cleanupLifecycle == ClassCleanupBehavior.EndOfClass; - } - } - - ShouldRunEndOfAssemblyCleanup = _remainingTestsByClass.IsEmpty; - } - } - - internal static void ForceCleanup(TypeCache typeCache, IDictionary sourceLevelParameters, IMessageLogger logger) - { - using var writer = new ThreadSafeStringWriter(CultureInfo.InvariantCulture, "context"); - TestContext testContext = new TestContextImplementation(null, writer, sourceLevelParameters, logger); - IEnumerable classInfoCache = typeCache.ClassInfoListWithExecutableCleanupMethods; - LogMessageListener? listener = null; - foreach (TestClassInfo classInfo in classInfoCache) - { - TestFailedException? ex = classInfo.ExecuteClassCleanup(testContext, out listener); - if (ex is not null) - { - throw ex; - } - } - - IEnumerable assemblyInfoCache = typeCache.AssemblyInfoListWithExecutableCleanupMethods; - foreach (TestAssemblyInfo assemblyInfo in assemblyInfoCache) - { - TestFailedException? ex = assemblyInfo.ExecuteAssemblyCleanup(testContext, ref listener); - if (ex is not null) - { - throw ex; - } - } - } -} diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TcmTestPropertiesProvider.cs b/src/Adapter/MSTest.TestAdapter/Execution/TcmTestPropertiesProvider.cs deleted file mode 100644 index 1735b1cf0b..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Execution/TcmTestPropertiesProvider.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using TestPlatformObjectModel = Microsoft.VisualStudio.TestPlatform.ObjectModel; - -namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; - -/// -/// Reads and parses the TcmTestProperties in order to populate them in TestRunParameters. -/// -internal static class TcmTestPropertiesProvider -{ - /// - /// Gets tcm properties from test case. - /// - /// Test case. - /// Tcm properties. - public static IDictionary GetTcmProperties(TestPlatformObjectModel.TestCase? testCase) - { - var tcmProperties = new Dictionary(); - - // Return empty properties when testCase is null or when test case id is zero. - if (testCase == null || - testCase.GetPropertyValue(Constants.TestCaseIdProperty, default) == 0) - { - return tcmProperties; - } - - // Step 1: Add common properties. - tcmProperties[Constants.TestRunIdProperty] = testCase.GetPropertyValue(Constants.TestRunIdProperty, default); - tcmProperties[Constants.TestPlanIdProperty] = testCase.GetPropertyValue(Constants.TestPlanIdProperty, default); - tcmProperties[Constants.BuildConfigurationIdProperty] = testCase.GetPropertyValue(Constants.BuildConfigurationIdProperty, default); - tcmProperties[Constants.BuildDirectoryProperty] = testCase.GetPropertyValue(Constants.BuildDirectoryProperty, default); - tcmProperties[Constants.BuildFlavorProperty] = testCase.GetPropertyValue(Constants.BuildFlavorProperty, default); - tcmProperties[Constants.BuildNumberProperty] = testCase.GetPropertyValue(Constants.BuildNumberProperty, default); - tcmProperties[Constants.BuildPlatformProperty] = testCase.GetPropertyValue(Constants.BuildPlatformProperty, default); - tcmProperties[Constants.BuildUriProperty] = testCase.GetPropertyValue(Constants.BuildUriProperty, default); - tcmProperties[Constants.TfsServerCollectionUrlProperty] = testCase.GetPropertyValue(Constants.TfsServerCollectionUrlProperty, default); - tcmProperties[Constants.TfsTeamProjectProperty] = testCase.GetPropertyValue(Constants.TfsTeamProjectProperty, default); - tcmProperties[Constants.IsInLabEnvironmentProperty] = testCase.GetPropertyValue(Constants.IsInLabEnvironmentProperty, default); - - // Step 2: Add test case specific properties. - tcmProperties[Constants.TestCaseIdProperty] = testCase.GetPropertyValue(Constants.TestCaseIdProperty, default); - tcmProperties[Constants.TestConfigurationIdProperty] = testCase.GetPropertyValue(Constants.TestConfigurationIdProperty, default); - tcmProperties[Constants.TestConfigurationNameProperty] = testCase.GetPropertyValue(Constants.TestConfigurationNameProperty, default); - tcmProperties[Constants.TestPointIdProperty] = testCase.GetPropertyValue(Constants.TestPointIdProperty, default); - - return tcmProperties; - } -} diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestRunCancellationToken.cs b/src/Adapter/MSTest.TestAdapter/Execution/TestRunCancellationToken.cs deleted file mode 100644 index fbd7b24255..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Execution/TestRunCancellationToken.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; - -/// -/// Cancellation token supporting cancellation of a test run. -/// -#if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] -#else -[Obsolete(Constants.PublicTypeObsoleteMessage)] -#endif -public class TestRunCancellationToken -{ - /// - /// Callbacks to be invoked when canceled. - /// Needs to be a concurrent collection, see https://github.com/microsoft/testfx/issues/3953. - /// - private readonly ConcurrentBag<(Action, object?)> _registeredCallbacks = new(); - - /// - /// Gets a value indicating whether the test run is canceled. - /// - public bool Canceled - { - get; - private set - { - bool previousValue = field; - field = value; - - if (!previousValue && value) - { - foreach ((Action callBack, object? state) in _registeredCallbacks) - { - callBack.Invoke(state); - } - } - } - } - - /// - /// Cancels the execution of a test run. - /// - public void Cancel() => Canceled = true; - - /// - /// Registers a callback method to be invoked when canceled. - /// - /// Callback delegate for handling cancellation. - public void Register(Action callback) => _registeredCallbacks.Add((_ => callback(), null)); - - internal void Register(Action callback, object? state) => _registeredCallbacks.Add((callback, state)); - - /// - /// Unregister the callback method. - /// - public void Unregister() -#if NETCOREAPP || WINDOWS_UWP - => _registeredCallbacks.Clear(); -#else - { - while (!_registeredCallbacks.IsEmpty) - { - _ = _registeredCallbacks.TryTake(out _); - } - } -#endif - - internal void ThrowIfCancellationRequested() - { - if (Canceled) - { - throw new OperationCanceledException(); - } - } -} diff --git a/src/Adapter/MSTest.TestAdapter/Extensions/ExceptionExtensions.cs b/src/Adapter/MSTest.TestAdapter/Extensions/ExceptionExtensions.cs deleted file mode 100644 index 648fbc41db..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Extensions/ExceptionExtensions.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; - -/// -/// Extensions to type. -/// -internal static class ExceptionExtensions -{ - /// - /// TargetInvocationException and TypeInitializationException do not carry any useful information - /// to the user. Find the first inner exception that has useful information. - /// - internal static Exception GetRealException(this Exception exception) - { - // TargetInvocationException: Because .NET Framework wraps method.Invoke() into TargetInvocationException. - // TypeInitializationException: Because AssemblyInitialize is static, and often helpers that are also static - // are used to implement it, and they fail in constructor. - while (exception is TargetInvocationException or TypeInitializationException - && exception.InnerException is not null) - { - exception = exception.InnerException; - } - - return exception; - } - - /// - /// Get the exception message if available, empty otherwise. - /// - /// An object. - /// Exception message. - internal static string TryGetMessage(this Exception? exception) - { - if (exception == null) - { - return string.Format(CultureInfo.CurrentCulture, Resource.UTF_FailedToGetExceptionMessage, "null"); - } - - // It is safe to retrieve an exception message, it should not throw in any case. - return exception.Message ?? string.Empty; - } - - /// - /// Gets the for an exception. - /// - /// An instance. - /// StackTraceInformation for the exception. - internal static StackTraceInformation? TryGetStackTraceInformation(this Exception exception) => !StringEx.IsNullOrEmpty(exception.StackTrace) - ? ExceptionHelper.CreateStackTraceInformation(exception, false, exception.StackTrace) - : null; - - /// - /// Checks whether exception is an Assert exception. - /// - /// An instance. - /// Framework's Outcome depending on type of assertion. - /// Exception message. - /// StackTraceInformation for the exception. - /// True, if Assert exception. False, otherwise. - internal static bool TryGetUnitTestAssertException(this Exception exception, out UTF.UnitTestOutcome outcome, - [NotNullWhen(true)] out string? exceptionMessage, out StackTraceInformation? exceptionStackTrace) - { - if (exception is UnitTestAssertException) - { - outcome = exception is AssertInconclusiveException - ? UTF.UnitTestOutcome.Inconclusive - : UTF.UnitTestOutcome.Failed; - - exceptionMessage = exception.TryGetMessage(); - exceptionStackTrace = exception.TryGetStackTraceInformation(); - return true; - } - - outcome = UTF.UnitTestOutcome.Failed; - exceptionMessage = null; - exceptionStackTrace = null; - return false; - } -} diff --git a/src/Adapter/MSTest.TestAdapter/Friends.cs b/src/Adapter/MSTest.TestAdapter/Friends.cs deleted file mode 100644 index bdfd4316bd..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Friends.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -// Friend assemblies -[assembly: InternalsVisibleTo(assemblyName: "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo(assemblyName: "DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] -[assembly: InternalsVisibleTo(assemblyName: "MSTest.VstestConsoleWrapper.IntegrationTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo(assemblyName: "MSTest.IntegrationTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/AttributeComparer.cs b/src/Adapter/MSTest.TestAdapter/Helpers/AttributeComparer.cs deleted file mode 100644 index c82f46d996..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Helpers/AttributeComparer.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; - -internal static class AttributeComparer -{ - public static bool IsNonDerived(Attribute attribute) => - // We are explicitly checking the given type *exactly*. We don't want to consider inheritance. - // So, this should NOT be refactored to 'attribute is TAttribute'. - attribute.GetType() == typeof(TAttribute); - - public static bool IsDerived(Attribute attribute) => attribute is TAttribute; -} diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/EnvironmentWrapper.cs b/src/Adapter/MSTest.TestAdapter/Helpers/EnvironmentWrapper.cs deleted file mode 100644 index 792366d479..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Helpers/EnvironmentWrapper.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; - -internal sealed class EnvironmentWrapper : IEnvironment -{ - public string MachineName => Environment.MachineName; -} diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/IEnvironment.cs b/src/Adapter/MSTest.TestAdapter/Helpers/IEnvironment.cs deleted file mode 100644 index 96395c6bc4..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Helpers/IEnvironment.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; - -/// -/// Interface to abstract environment related information. -/// -internal interface IEnvironment -{ - /// - /// Gets the machine name. - /// - string MachineName { get; } -} diff --git a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj index 9574cbfe6e..2dcf69d6e8 100644 --- a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj +++ b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj @@ -42,7 +42,7 @@ Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter - TRACE + $(DefineConstants);TRACE true @@ -61,10 +61,6 @@ - - - - @@ -72,17 +68,6 @@ - - True - True - Resource.resx - - - ResXFileCodeGenerator - Resource.Designer.cs - Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter - Designer - @@ -109,13 +94,6 @@ - - - True - True - Resource.resx - - <_TemplateProperties>Version=$(Version) @@ -137,6 +115,13 @@ + + + + + + + diff --git a/src/Adapter/MSTest.TestAdapter/Properties/AssemblyInfo.cs b/src/Adapter/MSTest.TestAdapter/Properties/AssemblyInfo.cs index 03648cfe6d..1986d819e5 100644 --- a/src/Adapter/MSTest.TestAdapter/Properties/AssemblyInfo.cs +++ b/src/Adapter/MSTest.TestAdapter/Properties/AssemblyInfo.cs @@ -3,5 +3,24 @@ using Microsoft.VisualStudio.TestPlatform; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; [assembly: TestExtensionTypes(typeof(MSTestDiscoverer), typeof(MSTestExecutor))] + +#pragma warning disable RS0016 // Add public types and members to the declared API (type forwarding is not public API) +[assembly: TypeForwardedTo(typeof(LogMessageListener))] +[assembly: TypeForwardedTo(typeof(MSTestSettings))] +[assembly: TypeForwardedTo(typeof(RunConfigurationSettings))] +[assembly: TypeForwardedTo(typeof(TestAssemblyInfo))] +[assembly: TypeForwardedTo(typeof(TestClassInfo))] +[assembly: TypeForwardedTo(typeof(TestExecutionManager))] +[assembly: TypeForwardedTo(typeof(TestMethod))] +[assembly: TypeForwardedTo(typeof(TestMethodInfo))] +[assembly: TypeForwardedTo(typeof(TestResultExtensions))] +[assembly: TypeForwardedTo(typeof(TestRunCancellationToken))] +[assembly: TypeForwardedTo(typeof(UnitTestOutcome))] +[assembly: TypeForwardedTo(typeof(UnitTestOutcomeExtensions))] +[assembly: TypeForwardedTo(typeof(UnitTestResult))] +#pragma warning restore RS0016 diff --git a/src/Adapter/MSTest.TestAdapter/PublicAPI/PublicAPI.Shipped.txt b/src/Adapter/MSTest.TestAdapter/PublicAPI/PublicAPI.Shipped.txt index 1a24faebf6..7c85eb0167 100644 --- a/src/Adapter/MSTest.TestAdapter/PublicAPI/PublicAPI.Shipped.txt +++ b/src/Adapter/MSTest.TestAdapter/PublicAPI/PublicAPI.Shipped.txt @@ -1,65 +1,4 @@ #nullable enable -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.TimeoutWhenNotSet = 0 -> int -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.SettingsName = "MSTest" -> string! -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.SettingsNameAlias = "MSTestV2" -> string! -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.TotalHierarchyLevels = 4 -> int -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.SettingsName = "RunConfiguration" -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.DebugTrace.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.Dispose() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.GetAndClearDebugTrace() -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.GetAndClearStandardError() -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.GetAndClearStandardOutput() -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.LogMessageListener(bool captureDebugTraces) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.StandardError.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.StandardOutput.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.AssemblyCleanupMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.AssemblyInitializationException.get -> System.Exception? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.AssemblyInitializeMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.HasExecutableCleanupMethod.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.IsAssemblyInitializeExecuted.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.RunAssemblyCleanup() -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.RunAssemblyInitialize(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext! testContext) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseClassCleanupMethodsStack.get -> System.Collections.Generic.Stack! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseClassInitAndCleanupMethods.get -> System.Collections.Generic.Queue!>! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseTestCleanupMethodsQueue.get -> System.Collections.Generic.Queue! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseTestInitializeMethodsQueue.get -> System.Collections.Generic.Queue! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassAttribute.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassCleanupException.get -> System.Exception? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassCleanupMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassInitializationException.get -> System.Exception? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassInitializeMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassType.get -> System.Type! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.Constructor.get -> System.Reflection.ConstructorInfo! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.HasExecutableCleanupMethod.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.IsClassCleanupExecuted.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.IsClassInitializeExecuted.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.Parent.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.RunClassCleanup(Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior classCleanupLifecycle = Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior.EndOfAssembly) -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.RunClassInitialize(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext! testContext) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.TestCleanupMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.TestContextProperty.get -> System.Reflection.PropertyInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.TestInitializeMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager.RunTests(System.Collections.Generic.IEnumerable! tests, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext? runContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle! frameworkHandle, Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken! runCancellationToken) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager.RunTests(System.Collections.Generic.IEnumerable! sources, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext? runContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle! frameworkHandle, Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken! cancellationToken) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager.TestExecutionManager() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.Arguments.get -> object?[]? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.GetAllAttributes(bool inherit) -> System.Attribute![]? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.GetAttributes(bool inherit) -> TAttributeType![]! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.IsRunnable.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.IsTimeoutSet.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.MethodInfo.get -> System.Reflection.MethodInfo! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.NotRunnableReason.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.ParameterTypes.get -> System.Reflection.ParameterInfo![]! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.ReturnType.get -> System.Type! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.TestClassName.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.TestMethodName.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.TestResultExtensions -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.UnitTestOutcomeExtensions Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestDiscoverer Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestDiscoverer.DiscoverTests(System.Collections.Generic.IEnumerable! sources, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IDiscoveryContext! discoveryContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging.IMessageLogger! logger, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.ITestCaseDiscoverySink! discoverySink) -> void Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestDiscoverer.MSTestDiscoverer() -> void @@ -70,83 +9,7 @@ Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor.RunTests(S Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor.RunTests(System.Collections.Generic.IEnumerable? sources, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext? runContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle? frameworkHandle) -> void Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor.TestExecutionManager.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager! Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor.TestExecutionManager.set -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.CaptureDebugTraces.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ClassCleanupLifecycle.get -> Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.DisableParallelization.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.EnableBaseClassTestMethodsFromOtherAssemblies.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ForcedLegacyMode.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.MapInconclusiveToFailed.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.MapNotRunnableToFailed.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.MSTestSettings() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ParallelizationScope.get -> Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ParallelizationWorkers.get -> int? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TestSettingsFile.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TestTimeout.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TreatClassAndAssemblyCleanupWarningsAsErrors.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TreatDiscoveryWarningsAsErrors.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.AssemblyName.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringAssemblyName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringAssemblyName.set -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringClassFullName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringClassFullName.set -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.FullClassName.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.HasManagedMethodAndTypeProperties.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.Hierarchy.get -> System.Collections.Generic.IReadOnlyCollection! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.IsAsync.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.ManagedMethodName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.ManagedTypeName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.Name.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.TestIdGenerationStrategy.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestIdGenerationStrategy -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.TestMethod(string! name, string! fullClassName, string! assemblyName, bool isAsync) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Error = 0 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Failed = 1 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Ignored = 4 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Inconclusive = 3 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.InProgress = 8 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.NotFound = 7 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.NotRunnable = 5 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Passed = 6 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Timeout = 2 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.DatarowIndex.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.DebugTrace.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.DisplayName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.Duration.get -> System.TimeSpan -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorColumnNumber.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorFilePath.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorLineNumber.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorMessage.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorStackTrace.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ExecutionId.get -> System.Guid -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.InnerResultsCount.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.Outcome.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ParentExecId.get -> System.Guid -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ResultFiles.get -> System.Collections.Generic.IList? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.StandardError.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.StandardOut.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.TestContextMessages.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.CollectSourceInformation.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.RunConfigurationSettings() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Cancel() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Canceled.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Register(System.Action! callback) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.TestRunCancellationToken() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Unregister() -> void Microsoft.VisualStudio.TestTools.UnitTesting.TestApplicationBuilderExtensions Microsoft.VisualStudio.TestTools.UnitTesting.TestingPlatformBuilderHook -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.TestResultExtensions.ToUnitTestResults(this Microsoft.VisualStudio.TestTools.UnitTesting.TestResult![]! testResults) -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult![]! -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.UnitTestOutcomeExtensions.ToUnitTestOutcome(this Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome frameworkTestOutcome) -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.CurrentSettings.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings! -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.IsLegacyScenario(Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging.IMessageLogger! logger) -> bool -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.PopulateSettings(Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings! settings) -> void -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.PopulateSettings(Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IDiscoveryContext? context) -> void -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.RunConfigurationSettings.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings! -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.PopulateSettings(Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IDiscoveryContext? context) -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings! static Microsoft.VisualStudio.TestTools.UnitTesting.TestApplicationBuilderExtensions.AddMSTest(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! testApplicationBuilder, System.Func!>! getTestAssemblies) -> void static Microsoft.VisualStudio.TestTools.UnitTesting.TestingPlatformBuilderHook.AddExtensions(Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! testApplicationBuilder, string![]! arguments) -> void -virtual Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.Invoke(object?[]? arguments) -> Microsoft.VisualStudio.TestTools.UnitTesting.TestResult! diff --git a/src/Adapter/MSTest.TestAdapter/PublicAPI/PublicAPI.Unshipped.txt b/src/Adapter/MSTest.TestAdapter/PublicAPI/PublicAPI.Unshipped.txt index 22b19265a6..7dc5c58110 100644 --- a/src/Adapter/MSTest.TestAdapter/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Adapter/MSTest.TestAdapter/PublicAPI/PublicAPI.Unshipped.txt @@ -1,2 +1 @@ #nullable enable -virtual Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.InvokeAsync(object?[]? arguments) -> System.Threading.Tasks.Task! diff --git a/src/Adapter/MSTest.TestAdapter/PublicAPI/uwp/PublicAPI.Shipped.txt b/src/Adapter/MSTest.TestAdapter/PublicAPI/uwp/PublicAPI.Shipped.txt index 100104fa6b..078eb58f29 100644 --- a/src/Adapter/MSTest.TestAdapter/PublicAPI/uwp/PublicAPI.Shipped.txt +++ b/src/Adapter/MSTest.TestAdapter/PublicAPI/uwp/PublicAPI.Shipped.txt @@ -1,65 +1,4 @@ #nullable enable -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.TimeoutWhenNotSet = 0 -> int -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.SettingsName = "MSTest" -> string! -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.SettingsNameAlias = "MSTestV2" -> string! -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.TotalHierarchyLevels = 4 -> int -const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.SettingsName = "RunConfiguration" -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.DebugTrace.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.Dispose() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.GetAndClearDebugTrace() -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.GetAndClearStandardError() -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.GetAndClearStandardOutput() -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.LogMessageListener(bool captureDebugTraces) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.StandardError.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.StandardOutput.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.AssemblyCleanupMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.AssemblyInitializationException.get -> System.Exception? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.AssemblyInitializeMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.HasExecutableCleanupMethod.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.IsAssemblyInitializeExecuted.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.RunAssemblyCleanup() -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.RunAssemblyInitialize(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext! testContext) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseClassCleanupMethodsStack.get -> System.Collections.Generic.Stack! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseClassInitAndCleanupMethods.get -> System.Collections.Generic.Queue!>! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseTestCleanupMethodsQueue.get -> System.Collections.Generic.Queue! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseTestInitializeMethodsQueue.get -> System.Collections.Generic.Queue! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassAttribute.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassCleanupException.get -> System.Exception? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassCleanupMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassInitializationException.get -> System.Exception? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassInitializeMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassType.get -> System.Type! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.Constructor.get -> System.Reflection.ConstructorInfo! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.HasExecutableCleanupMethod.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.IsClassCleanupExecuted.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.IsClassInitializeExecuted.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.Parent.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.RunClassCleanup(Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior classCleanupLifecycle = Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior.EndOfAssembly) -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.RunClassInitialize(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext! testContext) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.TestCleanupMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.TestContextProperty.get -> System.Reflection.PropertyInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.TestInitializeMethod.get -> System.Reflection.MethodInfo? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager.RunTests(System.Collections.Generic.IEnumerable! tests, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext? runContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle! frameworkHandle, Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken! runCancellationToken) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager.RunTests(System.Collections.Generic.IEnumerable! sources, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext? runContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle! frameworkHandle, Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken! cancellationToken) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager.TestExecutionManager() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.Arguments.get -> object?[]? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.GetAllAttributes(bool inherit) -> System.Attribute![]? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.GetAttributes(bool inherit) -> TAttributeType![]! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.IsRunnable.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.IsTimeoutSet.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.MethodInfo.get -> System.Reflection.MethodInfo! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.NotRunnableReason.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.ParameterTypes.get -> System.Reflection.ParameterInfo![]! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.ReturnType.get -> System.Type! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.TestClassName.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.TestMethodName.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.TestResultExtensions -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.UnitTestOutcomeExtensions Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestDiscoverer Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestDiscoverer.DiscoverTests(System.Collections.Generic.IEnumerable! sources, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IDiscoveryContext! discoveryContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging.IMessageLogger! logger, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.ITestCaseDiscoverySink! discoverySink) -> void Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestDiscoverer.MSTestDiscoverer() -> void @@ -70,79 +9,3 @@ Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor.RunTests(S Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor.RunTests(System.Collections.Generic.IEnumerable? sources, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext? runContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle? frameworkHandle) -> void Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor.TestExecutionManager.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager! Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor.TestExecutionManager.set -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.CaptureDebugTraces.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ClassCleanupLifecycle.get -> Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.DisableParallelization.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.EnableBaseClassTestMethodsFromOtherAssemblies.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ForcedLegacyMode.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.MapInconclusiveToFailed.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.MapNotRunnableToFailed.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.MSTestSettings() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ParallelizationScope.get -> Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ParallelizationWorkers.get -> int? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TestSettingsFile.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TestTimeout.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TreatClassAndAssemblyCleanupWarningsAsErrors.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TreatDiscoveryWarningsAsErrors.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.AssemblyName.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringAssemblyName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringAssemblyName.set -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringClassFullName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringClassFullName.set -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.FullClassName.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.HasManagedMethodAndTypeProperties.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.Hierarchy.get -> System.Collections.Generic.IReadOnlyCollection! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.IsAsync.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.ManagedMethodName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.ManagedTypeName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.Name.get -> string! -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.TestIdGenerationStrategy.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestIdGenerationStrategy -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.TestMethod(string! name, string! fullClassName, string! assemblyName, bool isAsync) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Error = 0 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Failed = 1 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Ignored = 4 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Inconclusive = 3 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.InProgress = 8 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.NotFound = 7 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.NotRunnable = 5 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Passed = 6 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Timeout = 2 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.DatarowIndex.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.DebugTrace.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.DisplayName.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.Duration.get -> System.TimeSpan -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorColumnNumber.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorFilePath.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorLineNumber.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorMessage.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorStackTrace.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ExecutionId.get -> System.Guid -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.InnerResultsCount.get -> int -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.Outcome.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ParentExecId.get -> System.Guid -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ResultFiles.get -> System.Collections.Generic.IList? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.StandardError.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.StandardOut.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.TestContextMessages.get -> string? -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.CollectSourceInformation.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.RunConfigurationSettings() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Cancel() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Canceled.get -> bool -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Register(System.Action! callback) -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.TestRunCancellationToken() -> void -Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Unregister() -> void -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.TestResultExtensions.ToUnitTestResults(this Microsoft.VisualStudio.TestTools.UnitTesting.TestResult![]! testResults) -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult![]! -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.UnitTestOutcomeExtensions.ToUnitTestOutcome(this Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome frameworkTestOutcome) -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.CurrentSettings.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings! -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.IsLegacyScenario(Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging.IMessageLogger! logger) -> bool -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.PopulateSettings(Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings! settings) -> void -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.PopulateSettings(Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IDiscoveryContext? context) -> void -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.RunConfigurationSettings.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings! -static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.PopulateSettings(Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IDiscoveryContext? context) -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings! -virtual Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.Invoke(object?[]? arguments) -> Microsoft.VisualStudio.TestTools.UnitTesting.TestResult! diff --git a/src/Adapter/MSTest.TestAdapter/PublicAPI/uwp/PublicAPI.Unshipped.txt b/src/Adapter/MSTest.TestAdapter/PublicAPI/uwp/PublicAPI.Unshipped.txt index 22b19265a6..7dc5c58110 100644 --- a/src/Adapter/MSTest.TestAdapter/PublicAPI/uwp/PublicAPI.Unshipped.txt +++ b/src/Adapter/MSTest.TestAdapter/PublicAPI/uwp/PublicAPI.Unshipped.txt @@ -1,2 +1 @@ #nullable enable -virtual Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.InvokeAsync(object?[]? arguments) -> System.Threading.Tasks.Task! diff --git a/src/Adapter/MSTest.TestAdapter/Resources/Resource.Designer.cs b/src/Adapter/MSTest.TestAdapter/Resources/Resource.Designer.cs deleted file mode 100644 index 8daf3f194b..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/Resource.Designer.cs +++ /dev/null @@ -1,888 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resource { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resource() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Resources.Resource", typeof(Resource).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Assembly cleanup method '{0}.{1}' timed out after {2}ms. - /// - internal static string AssemblyCleanupTimedOut { - get { - return ResourceManager.GetString("AssemblyCleanupTimedOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Assembly cleanup method '{0}.{1}' was canceled. - /// - internal static string AssemblyCleanupWasCancelled { - get { - return ResourceManager.GetString("AssemblyCleanupWasCancelled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Assembly initialize method '{0}.{1}' timed out after {2}ms. - /// - internal static string AssemblyInitializeTimedOut { - get { - return ResourceManager.GetString("AssemblyInitializeTimedOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Assembly initialize method '{0}.{1}' was canceled. - /// - internal static string AssemblyInitializeWasCancelled { - get { - return ResourceManager.GetString("AssemblyInitializeWasCancelled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MSTestAdapterV2. - /// - internal static string AttachmentSetDisplayName { - get { - return ResourceManager.GetString("AttachmentSetDisplayName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2}. - /// - internal static string CannotEnumerateIDataSourceAttribute { - get { - return ResourceManager.GetString("CannotEnumerateIDataSourceAttribute", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}. - /// - internal static string CannotExpandIDataSourceAttribute { - get { - return ResourceManager.GetString("CannotExpandIDataSourceAttribute", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution".. - /// - internal static string CannotExpandIDataSourceAttribute_CannotSerialize { - get { - return ResourceManager.GetString("CannotExpandIDataSourceAttribute_CannotSerialize", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique.. - /// - internal static string CannotExpandIDataSourceAttribute_DuplicateDisplayName { - get { - return ResourceManager.GetString("CannotExpandIDataSourceAttribute_DuplicateDisplayName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. - ///Test expected {2} parameter(s), with types '{3}', - ///but received {4} argument(s), with types '{5}'.. - /// - internal static string CannotRunTestArgumentsMismatchError { - get { - return ResourceManager.GetString("CannotRunTestArgumentsMismatchError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data.. - /// - internal static string CannotRunTestMethodNoDataError { - get { - return ResourceManager.GetString("CannotRunTestMethodNoDataError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class cleanup method '{0}.{1}' timed out after {2}ms. - /// - internal static string ClassCleanupTimedOut { - get { - return ResourceManager.GetString("ClassCleanupTimedOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class cleanup method '{0}.{1}' was canceled. - /// - internal static string ClassCleanupWasCancelled { - get { - return ResourceManager.GetString("ClassCleanupWasCancelled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class initialize method '{0}.{1}' timed out after {2}ms. - /// - internal static string ClassInitializeTimedOut { - get { - return ResourceManager.GetString("ClassInitializeTimedOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class initialize method '{0}.{1}' was canceled. - /// - internal static string ClassInitializeWasCancelled { - get { - return ResourceManager.GetString("ClassInitializeWasCancelled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}.. - /// - internal static string CouldNotInspectTypeDuringDiscovery { - get { - return ResourceManager.GetString("CouldNotInspectTypeDuringDiscovery", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} (Data Row {1}). - /// - internal static string DataDrivenResultDisplayName { - get { - return ResourceManager.GetString("DataDrivenResultDisplayName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Debug Trace:. - /// - internal static string DebugTraceBanner { - get { - return ResourceManager.GetString("DebugTraceBanner", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [MSTest][Discovery][{0}] {1}. - /// - internal static string DiscoveryWarning { - get { - return ResourceManager.GetString("DiscoveryWarning", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files.. - /// - internal static string DuplicateConfigurationError { - get { - return ResourceManager.GetString("DuplicateConfigurationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0}: {1}. - /// - internal static string EnumeratorLoadTypeErrorFormat { - get { - return ResourceManager.GetString("EnumeratorLoadTypeErrorFormat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to "{0}": (Failed to get exception description due to an exception of type "{1}".. - /// - internal static string ExceptionOccuredWhileGettingTheExceptionDescription { - get { - return ResourceManager.GetString("ExceptionOccuredWhileGettingTheExceptionDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Exceptions thrown:. - /// - internal static string ExceptionsThrown { - get { - return ResourceManager.GetString("ExceptionsThrown", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Test '{0}' was canceled. - /// - internal static string Execution_Test_Cancelled { - get { - return ResourceManager.GetString("Execution_Test_Cancelled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Test '{0}' timed out after {1}ms. - /// - internal static string Execution_Test_Timeout { - get { - return ResourceManager.GetString("Execution_Test_Timeout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}. - /// - internal static string FailedToGetCustomAttribute { - get { - return ResourceManager.GetString("FailedToGetCustomAttribute", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type of the generic parameter '{0}' could not be inferred.. - /// - internal static string GenericParameterCantBeInferred { - get { - return ResourceManager.GetString("GenericParameterCantBeInferred", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.. - /// - internal static string GenericParameterCantBeInferredBecauseNoArguments { - get { - return ResourceManager.GetString("GenericParameterCantBeInferredBecauseNoArguments", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.. - /// - internal static string GenericParameterConflict { - get { - return ResourceManager.GetString("GenericParameterConflict", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.. - /// - internal static string InvalidClassCleanupLifecycleValue { - get { - return ResourceManager.GetString("InvalidClassCleanupLifecycleValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}.. - /// - internal static string InvalidParallelScopeValue { - get { - return ResourceManager.GetString("InvalidParallelScopeValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer.. - /// - internal static string InvalidParallelWorkersValue { - get { - return ResourceManager.GetString("InvalidParallelWorkersValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'.. - /// - internal static string InvalidSettingsXmlAttribute { - get { - return ResourceManager.GetString("InvalidSettingsXmlAttribute", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid settings '{0}'. Unexpected XmlElement: '{1}'.. - /// - internal static string InvalidSettingsXmlElement { - get { - return ResourceManager.GetString("InvalidSettingsXmlElement", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.. - /// - internal static string InvalidValue { - get { - return ResourceManager.GetString("InvalidValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter.. - /// - internal static string LegacyScenariosNotSupportedWarning { - get { - return ResourceManager.GetString("LegacyScenariosNotSupportedWarning", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file.. - /// - internal static string OlderTFMVersionFound { - get { - return ResourceManager.GetString("OlderTFMVersionFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Running tests in any of the provided sources is not supported for the selected platform. - /// - internal static string SourcesNotSupported { - get { - return ResourceManager.GetString("SourcesNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes.. - /// - internal static string STAIsOnlySupportedOnWindowsWarning { - get { - return ResourceManager.GetString("STAIsOnlySupportedOnWindowsWarning", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Failed to discover tests from assembly {0}. Reason:{1}. - /// - internal static string TestAssembly_AssemblyDiscoveryFailure { - get { - return ResourceManager.GetString("TestAssembly_AssemblyDiscoveryFailure", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to File does not exist: {0}. - /// - internal static string TestAssembly_FileDoesNotExist { - get { - return ResourceManager.GetString("TestAssembly_FileDoesNotExist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Test cleanup method '{0}.{1}' timed out after {2}ms. - /// - internal static string TestCleanupTimedOut { - get { - return ResourceManager.GetString("TestCleanupTimedOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Test cleanup method '{0}.{1}' was canceled. - /// - internal static string TestCleanupWasCancelled { - get { - return ResourceManager.GetString("TestCleanupWasCancelled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to TestContext cannot be Null.. - /// - internal static string TestContextIsNull { - get { - return ResourceManager.GetString("TestContextIsNull", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to TestContext Messages:. - /// - internal static string TestContextMessageBanner { - get { - return ResourceManager.GetString("TestContextMessageBanner", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Test initialize method '{0}.{1}' timed out after {2}ms. - /// - internal static string TestInitializeTimedOut { - get { - return ResourceManager.GetString("TestInitializeTimedOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Test initialize method '{0}.{1}' was canceled. - /// - internal static string TestInitializeWasCancelled { - get { - return ResourceManager.GetString("TestInitializeWasCancelled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Test method {0} was not found.. - /// - internal static string TestNotFound { - get { - return ResourceManager.GetString("TestNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}). - /// - internal static string TestParallelizationBanner { - get { - return ResourceManager.GetString("TestParallelizationBanner", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. - ///Error: {1}. - /// - internal static string TypeLoadFailed { - get { - return ResourceManager.GetString("TypeLoadFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3}. - /// - internal static string UTA_AssemblyCleanupMethodWasUnsuccesful { - get { - return ResourceManager.GetString("UTA_AssemblyCleanupMethodWasUnsuccesful", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution.. - /// - internal static string UTA_AssemblyInitMethodThrows { - get { - return ResourceManager.GetString("UTA_AssemblyInitMethodThrows", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3}. - /// - internal static string UTA_ClassCleanupMethodWasUnsuccesful { - get { - return ResourceManager.GetString("UTA_ClassCleanupMethodWasUnsuccesful", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class Initialization method {0}.{1} threw exception. {2}: {3}.. - /// - internal static string UTA_ClassInitMethodThrows { - get { - return ResourceManager.GetString("UTA_ClassInitMethodThrows", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'.. - /// - internal static string UTA_ClassOrAssemblyCleanupMethodHasWrongSignature { - get { - return ResourceManager.GetString("UTA_ClassOrAssemblyCleanupMethodHasWrongSignature", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'.. - /// - internal static string UTA_ClassOrAssemblyInitializeMethodHasWrongSignature { - get { - return ResourceManager.GetString("UTA_ClassOrAssemblyInitializeMethodHasWrongSignature", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to TestCleanup method {0}.{1} threw exception. {2}.. - /// - internal static string UTA_CleanupMethodThrows { - get { - return ResourceManager.GetString("UTA_CleanupMethodThrows", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error calling Test Cleanup method for test class {0}: {1}. - /// - internal static string UTA_CleanupMethodThrowsGeneralError { - get { - return ResourceManager.GetString("UTA_CleanupMethodThrowsGeneralError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to TestCleanup Stack Trace. - /// - internal static string UTA_CleanupStackTrace { - get { - return ResourceManager.GetString("UTA_CleanupStackTrace", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to --- End of inner exception stack trace ---. - /// - internal static string UTA_EndOfInnerExceptionTrace { - get { - return ResourceManager.GetString("UTA_EndOfInnerExceptionTrace", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2(). - /// - internal static string UTA_ErrorIncorrectTestMethodSignature { - get { - return ResourceManager.GetString("UTA_ErrorIncorrectTestMethodSignature", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext.. - /// - internal static string UTA_ErrorInValidTestContextSignature { - get { - return ResourceManager.GetString("UTA_ErrorInValidTestContextSignature", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0.. - /// - internal static string UTA_ErrorInvalidTimeout { - get { - return ResourceManager.GetString("UTA_ErrorInvalidTimeout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly.. - /// - internal static string UTA_ErrorMultiAssemblyClean { - get { - return ResourceManager.GetString("UTA_ErrorMultiAssemblyClean", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly.. - /// - internal static string UTA_ErrorMultiAssemblyInit { - get { - return ResourceManager.GetString("UTA_ErrorMultiAssemblyInit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class.. - /// - internal static string UTA_ErrorMultiClassClean { - get { - return ResourceManager.GetString("UTA_ErrorMultiClassClean", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class.. - /// - internal static string UTA_ErrorMultiClassInit { - get { - return ResourceManager.GetString("UTA_ErrorMultiClassInit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA024: {0}: Cannot define more than one method with the TestCleanup attribute.. - /// - internal static string UTA_ErrorMultiClean { - get { - return ResourceManager.GetString("UTA_ErrorMultiClean", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA018: {0}: Cannot define more than one method with the TestInitialize attribute.. - /// - internal static string UTA_ErrorMultiInit { - get { - return ResourceManager.GetString("UTA_ErrorMultiInit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA001: TestClass attribute defined on non-public class {0}. - /// - internal static string UTA_ErrorNonPublicTestClass { - get { - return ResourceManager.GetString("UTA_ErrorNonPublicTestClass", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA023: {0}: Cannot define predefined property {2} on method {1}.. - /// - internal static string UTA_ErrorPredefinedTestProperty { - get { - return ResourceManager.GetString("UTA_ErrorPredefinedTestProperty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to TestClass attribute defined on generic non-abstract class {0}. - /// - internal static string UTA_ErrorTestClassIsGenericNonAbstract { - get { - return ResourceManager.GetString("UTA_ErrorTestClassIsGenericNonAbstract", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name.. - /// - internal static string UTA_ErrorTestPropertyNullOrEmpty { - get { - return ResourceManager.GetString("UTA_ErrorTestPropertyNullOrEmpty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. - ///{1}. - /// - internal static string UTA_ExecuteThrewException { - get { - return ResourceManager.GetString("UTA_ExecuteThrewException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. - ///{2}. - /// - internal static string UTA_ExpectedExceptionAttributeConstructionException { - get { - return ResourceManager.GetString("UTA_ExpectedExceptionAttributeConstructionException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Failed to obtain the exception thrown by test method {0}.{1}.. - /// - internal static string UTA_FailedToGetTestMethodException { - get { - return ResourceManager.GetString("UTA_FailedToGetTestMethodException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Initialization method {0}.{1} threw exception. {2}.. - /// - internal static string UTA_InitMethodThrows { - get { - return ResourceManager.GetString("UTA_InitMethodThrows", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to create instance of class {0}. Error: {1}.. - /// - internal static string UTA_InstanceCreationError { - get { - return ResourceManager.GetString("UTA_InstanceCreationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method {0}.{1} does not exist.. - /// - internal static string UTA_MethodDoesNotExists { - get { - return ResourceManager.GetString("UTA_MethodDoesNotExists", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The test method {0}.{1} has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.. - /// - internal static string UTA_MultipleAttributesOnTestMethod { - get { - return ResourceManager.GetString("UTA_MultipleAttributesOnTestMethod", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor.. - /// - internal static string UTA_NoTestResult { - get { - return ResourceManager.GetString("UTA_NoTestResult", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'.. - /// - internal static string UTA_NoValidConstructor { - get { - return ResourceManager.GetString("UTA_NoValidConstructor", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to find property {0}.TestContext. Error:{1}.. - /// - internal static string UTA_TestContextLoadError { - get { - return ResourceManager.GetString("UTA_TestContextLoadError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to set TestContext property for the class {0}. Error: {1}.. - /// - internal static string UTA_TestContextSetError { - get { - return ResourceManager.GetString("UTA_TestContextSetError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0}.TestContext has incorrect type.. - /// - internal static string UTA_TestContextTypeMismatchLoadError { - get { - return ResourceManager.GetString("UTA_TestContextTypeMismatchLoadError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'.. - /// - internal static string UTA_TestInitializeAndCleanupMethodHasWrongSignature { - get { - return ResourceManager.GetString("UTA_TestInitializeAndCleanupMethodHasWrongSignature", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Test method {0}.{1} threw exception: - ///{2}. - /// - internal static string UTA_TestMethodThrows { - get { - return ResourceManager.GetString("UTA_TestMethodThrows", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to get type {0}. Error: {1}.. - /// - internal static string UTA_TypeLoadError { - get { - return ResourceManager.GetString("UTA_TypeLoadError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The called code threw an exception that was caught, but the exception value was null. - /// - internal static string UTA_UserCodeThrewNullValueException { - get { - return ResourceManager.GetString("UTA_UserCodeThrewNullValueException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread.. - /// - internal static string UTA_WrongThread { - get { - return ResourceManager.GetString("UTA_WrongThread", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to (Failed to get the message for an exception of type {0} due to an exception.). - /// - internal static string UTF_FailedToGetExceptionMessage { - get { - return ResourceManager.GetString("UTF_FailedToGetExceptionMessage", resourceCulture); - } - } - } -} diff --git a/src/Adapter/MSTest.TestAdapter/Resources/Resource.resx b/src/Adapter/MSTest.TestAdapter/Resources/Resource.resx deleted file mode 100644 index 2d8bfb92aa..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/Resource.resx +++ /dev/null @@ -1,418 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Test '{0}' timed out after {1}ms - - - Running tests in any of the provided sources is not supported for the selected platform - - - TestCleanup method {0}.{1} threw exception. {2}. - - - --- End of inner exception stack trace --- - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - - - Initialization method {0}.{1} threw exception. {2}. - - - Unable to create instance of class {0}. Error: {1}. - - - Unable to set TestContext property for the class {0}. Error: {1}. - - - (Failed to get the message for an exception of type {0} due to an exception.) - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - - - UTA001: TestClass attribute defined on non-public class {0} - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - - - {0}: {1} - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - - - File does not exist: {0} - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - - - TestContext cannot be Null. - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - - - Method {0}.{1} does not exist. - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - - - Unable to find property {0}.TestContext. Error:{1}. - - - The {0}.TestContext has incorrect type. - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - - - Unable to get type {0}. Error: {1}. - - - Test method {0} was not found. - - - Debug Trace: - - - Failed to obtain the exception thrown by test method {0}.{1}. - - - Test method {0}.{1} threw exception: -{2} - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - - - MSTestAdapterV2 - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - - - {0} (Data Row {1}) - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - - - TestContext Messages: - - - Error calling Test Cleanup method for test class {0}: {1} - - - TestCleanup Stack Trace - - - [MSTest][Discovery][{0}] {1} - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - - - Test '{0}' was canceled - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - - - The called code threw an exception that was caught, but the exception value was null - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - - - Assembly initialize method '{0}.{1}' was canceled - - - Class initialize method '{0}.{1}' timed out after {2}ms - - - Class initialize method '{0}.{1}' was canceled - - - TestClass attribute defined on generic non-abstract class {0} - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - - - Assembly cleanup method '{0}.{1}' was canceled - - - Class cleanup method '{0}.{1}' timed out after {2}ms - - - Class cleanup method '{0}.{1}' was canceled - - - Test cleanup method '{0}.{1}' timed out after {2}ms - - - Test cleanup method '{0}.{1}' was canceled - - - Test initialize method '{0}.{1}' timed out after {2}ms - - - Test initialize method '{0}.{1}' was canceled - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - - - The type of the generic parameter '{0}' could not be inferred. - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - - diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.cs.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.cs.xlf deleted file mode 100644 index 53651299cc..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.cs.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - Po {2} ms vypršel časový limit metody čištění sestavení {0}.{1}. - - - - Assembly cleanup method '{0}.{1}' was canceled - Metoda čištění sestavení {0}.{1} byla zrušena. - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - Po {2} ms vypršel časový limit metody inicializace sestavení {0}.{1}. - - - - Assembly initialize method '{0}.{1}' was canceled - Metoda inicializace sestavení {0}.{1} byla zrušena. - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - Testovací metodu {0}.{1} nejde spustit: Testovací data neodpovídají parametrům metody. Liší se počet nebo typy. -Pro test se očekával tento počet parametrů: {2} s typy {3}, -byl však přijat tento počet argumentů: {4} s typy {5}. - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - Nelze spustit testovací metodu {0}.{1}: Metoda má parametry, ale nedefinuje žádný zdroj testu. K poskytování testovacích dat použijte zdroj dat [DataRow] nebo [DynamicData], případně vlastní zdroj dat ITestDataSource. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - Po {2} ms vypršel časový limit metody čištění třídy {0}.{1}. - - - - Class cleanup method '{0}.{1}' was canceled - Metoda čištění třídy {0}.{1} byla zrušena. - - - - Class initialize method '{0}.{1}' timed out after {2}ms - Po {2} ms vypršel časový limit metody inicializace třídy {0}.{1}. - - - - Class initialize method '{0}.{1}' was canceled - Metoda inicializace třídy {0}.{1} byla zrušena. - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - Byly zjištěny soubory .runsettings i .testconfig.json. Vyberte prosím jenom jeden z těchto souborů konfigurace testu. - - - - Test '{0}' timed out after {1}ms - Časový limit '{0}' testu vypršel po {1}ms. - - - - The type of the generic parameter '{0}' could not be inferred. - Typ obecného parametru '{0}' nelze odvodit. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - Obecná testovací metoda '{0}' nemá argumenty, takže obecný parametr nelze odvodit. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - Byly nalezeny dva konfliktní typy pro obecný parametr '{0}'. Konfliktní typy jsou '{1}' a '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - Neplatná hodnota {0} pro položku runsettings {1}. Nastavení bude ignorováno. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - Položka runsettings <ExecutionApartmentState>STA</ExecutionApartmentState> se v operačních systémech jiných než Windows nepodporuje. - - - - Running tests in any of the provided sources is not supported for the selected platform - Spouštění testů v některém z uvedených zdrojů se pro vybranou platformu nepodporuje. - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - Po {2} ms vypršel časový limit metody čištění testu {0}.{1}. - - - - Test cleanup method '{0}.{1}' was canceled - Metoda čištění testu {0}.{1} byla zrušena. - - - - Test initialize method '{0}.{1}' timed out after {2}ms - Po {2} ms vypršel časový limit metody inicializace testu {0}.{1}. - - - - Test initialize method '{0}.{1}' was canceled - Metoda inicializace testu {0}.{1} byla zrušena. - - - - TestCleanup method {0}.{1} threw exception. {2}. - Metoda TestCleanup {0}.{1} vyvolala výjimku. {2}. - - - - --- End of inner exception stack trace --- - --- Konec trasování zásobníku pro vnitřní výjimku --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: V jednom sestavení nejde definovat více jak jednu metodu s atributem AssemblyCleanup. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: V jednom sestavení nejde definovat více jak jednu metodu s atributem AssemblyInitialize. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: Uvnitř třídy nejde definovat více jak jednu metodu s atributem ClassCleanup. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: Uvnitř třídy nejde definovat více jak jednu metodu s atributem ClassInitialize. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: Nejde definovat více jak jednu metodu s atributem TestCleanup. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: Nejde definovat více jak jednu metodu s atributem TestInitialize. - - - - TestClass attribute defined on generic non-abstract class {0} - Atribut TestClass definovaný u obecné neabstraktní třídy {0} - - - - Initialization method {0}.{1} threw exception. {2}. - Inicializační metoda {0}.{1} způsobila výjimku. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - Nepodařilo se vytvořit instanci třídy {0}. Chyba: {1}. - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - Testovací metoda {0}.{1} má definovaných více atributů odvozených od atributu {2}. Povolený je jenom jeden takový atribut. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - Nelze najít platný konstruktor pro testovací třídu {0}. Platné konstruktory jsou public a buď bez parametrů, nebo s jedním parametrem typu TestContext. - - - - Unable to set TestContext property for the class {0}. Error: {1}. - Pro třídu {0} se nepodařilo nastavit vlastnost TestContext. Chyba: {1}. - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (Z důvodu výjimky se nepodařilo získat zprávu o výjimce typu {0}.) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: Třída {0} nemá platnou vlastnost TestContext. Vlastnost TestContext musí být typu TestContext, musí být nestatická a musí být veřejná. Například: public TestContext TestContext - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: Atribut TestClass se definoval v neveřejné třídě {0}. - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - MSTestAdapter nezjistil v třídě {0} sestavení {1} žádný test, protože: {2}. - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - Nepovedlo se načíst typy ze zdroje testu {0}. Je možné, že se některé nebo všechny testy v tomto zdroji nezjistily. -Chyba: {1} - - - - File does not exist: {0} - Neexistující soubor: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: Metoda {1} definovaná ve třídě {0} nemá správný podpis. Testovací metoda označená atributem [TestMethod] nesmí být static ani public, musí mít návratový typ void a nesmí přijímat žádný parametr. Například: public void Test.Class1.Test(). Pokud navíc v testovací metodě používáte operátor async-await, musí být návratový typ Task nebo ValueTask. Například: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext nemůže být Null. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - Čisticí metoda sestavení {0}.{1} selhala. Chybová zpráva: {2}. Trasování zásobníku: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - Inicializační metoda sestavení {0}.{1} vyvolala výjimku. {2}: {3}. Přerušuje se provádění testu. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - Čisticí metoda třídy {0}.{1} selhala. Chybová zpráva: {2}. Trasování zásobníku: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - Inicializační metoda třídy {0}.{1} vyvolala výjimku. {2}: {3}. - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - Metoda Execute vyvolala neošetřenou výjimku. Nahlaste prosím tuto chybu autorovi '{0}' atributu. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - Při provádění testu došlo k chybě. Rozšíření nevrátilo žádný výsledek. Pokud používáte rozšíření třídy TestMethodAttribute, obraťte se na dodavatele. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Metoda {0}.{1} má špatný podpis. Metoda musí být static nebo public, nevrací hodnotu a nesmí přijímat žádný parametr. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task nebo ValueTask. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Metoda {0}.{1} má špatný podpis. Metoda musí být static nebo public, nevrací hodnotu a musí přijímat jeden parametr typu TestContext. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task nebo ValueTask. - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}.{1} má neplatný atribut Timeout. Hodnota timeline musí být celé číslo větší než 0. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: V metodě {1} nejde definovat předdefinovanou vlastnost {2}. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: V metodě {1} je definovaná vlastní vlastnost, která je null nebo je prázdná. Vlastní vlastnost musí mít platný název. - - - - Method {0}.{1} does not exist. - Metoda {0}.{1} neexistuje. - - - - Unable to find property {0}.TestContext. Error:{1}. - Nepodařilo se najít vlastnost {0}.TestContext. Chyba:{1}. - - - - The {0}.TestContext has incorrect type. - {0}.TestContext má nesprávný typ. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Metoda {0}.{1} má špatný podpis. Metoda nesmí být static nebo public, nevrací hodnotu a nesmí přijímat žádný parametr. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task nebo ValueTask. - - - - Unable to get type {0}. Error: {1}. - Nepodařilo se získat typ {0}. Chyba: {1}. - - - - Test method {0} was not found. - Testovací metoda {0} se nenašla. - - - - Debug Trace: - Trasování ladění: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - Nepovedlo se získat výjimku vyvolanou testovací metodou {0}.{1}. - - - - Test method {0}.{1} threw exception: -{2} - V testovací metodě {0}.{1} došlo k výjimce: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0}. Pokud v testu používáte objekty uživatelského rozhraní, zvažte u projektů pro platformu UPW použití atributu [UITestMethod] místo atributu [TestMethod], aby se test provedl ve vlákně uživatelského rozhraní. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - Neplatné nastavení {0}. Neočekávaný XmlAttribute: {1}. - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - Neplatné nastavení {0}. Neočekávaný XmlElement: {1}. - - - - {0} (Data Row {1}) - {0} (datový řádek {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - Atribut ExpectedException definovaný u testovací metody {0}.{1} vyvolal během vytváření výjimku. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - Upozornění: Adaptér MSTest V2 nepodporuje soubor testsettings ani vsmdi. - - - - TestContext Messages: - Zprávy pro TestContext: - - - - Error calling Test Cleanup method for test class {0}: {1} - Při volání čisticí metody testu pro třídu {0} došlo k chybě: {1} - - - - TestCleanup Stack Trace - Trasování zásobníku čištění testu - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Discovery][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - Je povolená paralelizace testu pro {0} (pracovní procesy: {1}, obor: {2}). - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - Pro Obor je zadaná neplatná hodnota {0}. Podporované obory jsou {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - Pro Pracovní procesy je zadaná neplatná hodnota {0}. Hodnota by měla být nezáporné celé číslo. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - Nepovedlo se zjistit testy ze sestavení {0}. Důvod:{1} - - - - Test '{0}' was canceled - Testovací '{0}' se zrušila. - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - Pro classCleanupLifecycle byla zadána neplatná hodnota {0}. Podporované obory jsou {1}. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - Při vytváření výčtu atributu IDataSource došlo k výjimce. „{0}.{1}“: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - „{0}“: (Nepodařilo se získat popis výjimky z důvodu výjimky typu „{1}“. - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - Vyvolané výjimky: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - Získání vlastních atributů pro typ {0} vyvolalo výjimku (bude ignorovat a používat způsob reflexe): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - V sestavení je načtena starší verze balíčku MSTestV2. Zjišťování testů může selhat při zjišťování všech testů dat, pokud jsou závislé na souboru .runsettings. - - - - The called code threw an exception that was caught, but the exception value was null - Volaný kód vyvolal výjimku, která byla zachycena, ale její hodnota byla null. - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - Došlo k výjimce při rozbalování řádků IDataSource z atributu na „{0}.{1}“: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - Zobrazovaný název „{2}“ u indexů {0} a {1} je duplicitní. Zobrazované názvy by měly být jedinečné. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - Data v {0} indexu pro „{1}“ nelze serializovat. Všechna data poskytnutá prostřednictvím „IDataSource“ by měla být serializovatelná. Pokud potřebujete testovat neserializovatelné zdroje dat, nezapomeňte do testovacího sestavení přidat atribut TestDataSourceDiscovery a nastavit možnost zjišťování na „DuringExecution“. - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.de.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.de.xlf deleted file mode 100644 index 458b366659..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.de.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - Timeout der Assemblybereinigungsmethode "{0}.{1}" nach {2} ms - - - - Assembly cleanup method '{0}.{1}' was canceled - Die Assemblybereinigungsmethode "{0}.{1}" wurde abgebrochen - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - Timeout der Assemblyinitialisierungsmethode "{0}.{1}" nach {2} ms - - - - Assembly initialize method '{0}.{1}' was canceled - Die Assemblyinitialisierungsmethode "{0}.{1}" wurde abgebrochen - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - Die Testmethode „{0}.{1}“ kann nicht ausgeführt werden: Testdaten stimmen nicht mit Methodenparametern überein. Die Anzahl oder die Typen unterscheiden sich. -Test erwartete {2} Parameter mit den Typen „{3}“, -aber empfing {4} Argument(e) mit den Typen „{5}“. - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - Die Testmethode „{0}.{1}“ kann nicht ausgeführt werden: Die Methode verfügt über Parameter, definiert jedoch keine Testquelle. Verwenden Sie „[DataRow]“, „[DynamicData]“ oder eine benutzerdefinierte „ITestDataSource-Datenquelle“, um Testdaten bereitzustellen. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - Timeout der Klassenbereinigungsmethode "{0}.{1}" nach {2} ms - - - - Class cleanup method '{0}.{1}' was canceled - Die Klassenbereinigungsmethode "{0}.{1}" wurde abgebrochen - - - - Class initialize method '{0}.{1}' timed out after {2}ms - Timeout der Klasseninitialisierungsmethode "{0}.{1}" nach {2} ms - - - - Class initialize method '{0}.{1}' was canceled - Die Initialisierungsmethode "{0}.{1}" der Klasse wurde abgebrochen - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - Es wurden sowohl die Dateien „.runsettings“ als auch „.testconfig.json“ erkannt. Wählen Sie nur eine dieser Testkonfigurationsdateien aus. - - - - Test '{0}' timed out after {1}ms - Timeout bei test '{0}' nach {1}ms. - - - - The type of the generic parameter '{0}' could not be inferred. - Der Typ des generischen Parameters '{0}' konnte nicht abgeleitet werden. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - Die generische Testmethode '{0}' hat keine Argumente, daher kann der generische Parameter nicht abgeleitet werden. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - Es wurden zwei in Konflikt stehende Typen für den generischen Parameter '{0}' gefunden. Die in Konflikt stehenden Typen sind '{1}' und '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - Ungültiger Wert "{0}" für runsettings-Eintrag "{1}". Die Einstellung wird ignoriert. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - Der Eintrag "<ExecutionApartmentState>STA</ExecutionApartmentState>" der Ausführungseinstellungen wird auf Nicht-Windows-Betriebssystemen nicht unterstützt. - - - - Running tests in any of the provided sources is not supported for the selected platform - Das Ausführen von Tests in einer der angegebenen Quellen wird für die ausgewählte Plattform nicht unterstützt. - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - Timeout der Testbereinigungsmethode "{0}.{1}" nach {2} ms - - - - Test cleanup method '{0}.{1}' was canceled - Die Testbereinigungsmethode "{0}.{1}" wurde abgebrochen - - - - Test initialize method '{0}.{1}' timed out after {2}ms - Timeout der Testinitialisierungsmethode "{0}.{1}" nach {2} ms - - - - Test initialize method '{0}.{1}' was canceled - Die Testinitialisierungsmethode "{0}.{1}" wurde abgebrochen - - - - TestCleanup method {0}.{1} threw exception. {2}. - Die TestCleanup-Methode "{0}.{1}" hat eine Ausnahme ausgelöst. {2}. - - - - --- End of inner exception stack trace --- - --- Ende der internen Ausnahmestapelüberwachung --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: Es darf nur eine Methode mit dem Attribut 'AssemblyCleanup' innerhalb einer Assembly definiert werden. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: Es darf nur eine Methode mit dem Attribut 'AssemblyInitialize' innerhalb einer Assembly definiert werden. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: Es darf nur eine Methode mit dem Attribut 'ClassCleanup' innerhalb einer Klasse definiert werden. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: Es darf nur eine Methode mit dem Attribut 'ClassInitialize' innerhalb einer Klasse definiert werden. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: Es darf nur eine Methode mit dem Attribut 'TestCleanup' definiert werden. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: Es darf nur eine Methode mit dem Attribut 'TestInitialize' definiert werden. - - - - TestClass attribute defined on generic non-abstract class {0} - TestClass-Attribut für generische nicht abstrakte Klasse {0} definiert - - - - Initialization method {0}.{1} threw exception. {2}. - Die Initialisierungsmethode '{0}.{1}' hat eine Ausnahme ausgelöst. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - Es kann keine Instanz der Klasse '{0}' erstellt werden. Fehler: {1}. - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - Für die Testmethode „{0}.{1}“ sind mehrere Attribute definiert, die von „{2}“ abgeleitet sind. Nur ein einziges solches Attribut ist zulässig. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - Es wurde kein gültiger Konstruktor für die Testklasse "{0}" gefunden. Gültige Konstruktoren sind "public" und entweder parameterlos oder mit einem Parameter vom Typ "TestContext". - - - - Unable to set TestContext property for the class {0}. Error: {1}. - Die Eigenschaft 'TestContext' für die Klasse '{0}' kann nicht festgelegt werden. Fehler: {1}. - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (Fehler beim Abrufen der Meldung für eine Ausnahme vom Typ "{0}" aufgrund einer Ausnahme.) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: Die Klasse {0} weist keine gültige Eigenschaft TestContext auf. TestContext muss vom Typ TestContext sein, muss nicht statisch und öffentlich sein. Beispiel: 'public TestContext TestContext'. - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: Für die nicht öffentliche Klasse '{0}' definiertes Attribut 'TestClass'. - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - Fehler von 'MSTestAdapter' beim Ermitteln von Tests in der Klasse "{0}" der Assembly "{1}". Ursache: {2}. - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - Fehler beim Laden von Typen aus der Testquelle "{0}". Möglicherweise werden einige oder alle Tests in dieser Quelle nicht ermittelt. -Fehler: {1} - - - - File does not exist: {0} - Die Datei ist nicht vorhanden: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: Die in der Klasse {0} definierte Methode {1} weist nicht die richtige Signatur auf. Die mit dem [TestMethod]-Attribut markierte Testmethode muss nicht statisch und öffentlich sein, muss den Rückgabetyp „void“ aufweisen und darf keine Parameter annehmen. Beispiel: public void Test.Class1.Test(). Wenn Sie außerdem in der Testmethode „async-await“ verwenden, muss der Rückgabetyp „Task“ oder „ValueTask“ sein. Beispiel: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - "TestContext" darf nicht NULL sein. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - Fehler bei der Methode "{0}.{1}" für die Assemblybereinigung. Fehlermeldung: {2}. "StackTrace": {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - Die Methode "{0}.{1}" für die Assemblyinitialisierung hat eine Ausnahme ausgelöst. {2}: {3}. Die Ausführung des Tests wird abgebrochen. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - Fehler bei der Methode "{0}.{1}" für die Klassenbereinigung. Fehlermeldung: {2}. Stapelüberwachung: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - Die Methode "{0}.{1}" für die Klasseninitialisierung hat eine Ausnahme ausgelöst. {2}: {3}. - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - Von der Methode "Execute" wurde eine nicht behandelte Ausnahme ausgelöst. Melden Sie diesen Fehler dem Autor des Attributs '{0}'. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - Fehler beim Ausführen des Tests. Von der Extension wurde kein Ergebnis zurückgegeben. Wenn Sie eine Extension von "TestMethodAttribute" verwenden, wenden Sie sich bitte an den Anbieter. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Die Methode „{0}.{1}“ weist eine falsche Signatur auf. Die Methode muss statisch und öffentlich sein. Sie darf keinen Wert zurückgeben und keinen Parameter annehmen. Wenn Sie außerdem in der Methode „async-await“ verwenden, muss der Rückgabetyp „Task“ oder „ValueTask“ sein. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Die Methode „{0}.{1}“ weist eine falsche Signatur auf. Die Methode muss statisch und öffentlich sein. Sie darf keinen Wert zurückgeben und muss einen einzigen Parameter des Typs TestContext annehmen. Wenn Sie außerdem in der Methode „async-await“ verwenden, muss der Rückgabetyp „Task“ oder „ValueTask“ sein. - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}.{1} weist ein ungültiges Attribut „Timeout“ auf. Timeout muss eine ganze Zahl größer als 0 sein. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: Die vordefinierte Eigenschaft "{2}" kann nicht für die Methode "{1}" definiert werden. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: Für die Methode "{1}" wurde eine benutzerdefinierte Eigenschaft mit dem Wert NULL oder eine benutzerdefinierte leere Eigenschaft definiert. Die benutzerdefinierte Eigenschaft muss einen gültigen Namen aufweisen. - - - - Method {0}.{1} does not exist. - Die Methode "{0}.{1}" ist nicht vorhanden. - - - - Unable to find property {0}.TestContext. Error:{1}. - Die Eigenschaft "{0}.TestContext" wurde nicht gefunden. Fehler: {1}. - - - - The {0}.TestContext has incorrect type. - "{0}.TestContext" weist einen falschen Typ auf. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Die Methode „{0}.{1}“ weist eine falsche Signatur auf. Die Methode muss nicht statisch und öffentlich sein, und sie darf keinen Wert zurückgeben und keinen Parameter annehmen. Wenn Sie außerdem in der Methode „async-await“ verwenden, muss der Rückgabetyp „Task“ oder „ValueTask“ sein. - - - - Unable to get type {0}. Error: {1}. - Der Typ "{0}" kann nicht abgerufen werden. Fehler: {1}. - - - - Test method {0} was not found. - Die Testmethode "{0}" wurde nicht gefunden. - - - - Debug Trace: - Debugablaufverfolgung: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - Fehler beim Abrufen der von der Testmethode "{0}.{1}" ausgelösten Ausnahme. - - - - Test method {0}.{1} threw exception: -{2} - Die Testmethode "{0}.{1}" hat eine Ausnahme ausgelöst: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0}: Erwägen Sie für UWP-Projekte bei Einsatz von UI-Objekten im Test die Verwendung des [UITestMethod]-Attributs anstelle von "[TestMethod]", um den Test im UI-Thread auszuführen. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - Ungültige Einstellungen "{0}". Unerwartetes XmlAttribute: "{1}". - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - Ungültige Einstellungen "{0}". Unerwartetes XmlElement: "{1}". - - - - {0} (Data Row {1}) - {0} (Datenzeile {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - Das für die Testmethode "{0}.{1}" definierte ExpectedException-Attribut hat während der Konstruktion eine Ausnahme ausgelöst. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - Warnung: Eine TESTSETTINGS-Datei oder eine VSMDI-Datei wird vom MSTest-V2-Adapter nicht unterstützt. - - - - TestContext Messages: - TestContext-Meldungen: - - - - Error calling Test Cleanup method for test class {0}: {1} - Fehler beim Aufruf der Testbereinigungsmethode für die Testklasse "{0}": {1} - - - - TestCleanup Stack Trace - TestCleanup-Stapelüberwachung - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Discovery][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - Testparallelisierung aktiviert für {0} (Worker: {1}, Bereich: {2}) - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - Ungültiger Wert "{0}" für "Scope" angegeben. Unterstützte Bereiche: {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - Ungültiger Wert "{0}" für "Workers" angegeben. Der Wert muss eine nicht negative Ganzzahl sein. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - Fehler beim Ermitteln von Tests aus der Assembly "{0}". Ursache:{1} - - - - Test '{0}' was canceled - Test '{0}' wurde abgebrochen. - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - Für "ClassCleanupLifecycle" wurde ein ungültiger Wert "{0}" angegeben. Unterstützte Bereiche sind {1}. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - Ausnahme beim Auflisten des IDataSource-Attributs für "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - "{0}": (Fehler beim Abrufen der Ausnahmebeschreibung aufgrund einer Ausnahme vom Typ "{1}". - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - Ausgelöste Ausnahmen: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - Beim Abrufen von benutzerdefinierten Attributen für den Typ {0} wurde Ausnahme ausgelöst (wird ignoriert und die Reflektionsart verwendet): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - Eine ältere Version des MSTestV2-Pakets wird in die Assembly geladen. Bei der Testermittlung werden möglicherweise nicht alle Datentests ermittelt, wenn sie von der Datei ".runsettings" abhängen. - - - - The called code threw an exception that was caught, but the exception value was null - Der aufgerufene Code hat eine Ausnahme ausgelöst, die abgefangen wurde, aber der Ausnahmewert war NULL. - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - Ausnahme beim Erweitern von IDataSource-Zeilen aus dem Attribut auf "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - Der Anzeigename "{2}" für Indizes {0} und {1} ist doppelt vorhanden. Anzeigenamen sollten eindeutig sein. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - Daten im Index {0} für "{1}" können nicht serialisiert werden. Alle über "IDataSource" bereitgestellten Daten sollten serialisierbar sein. Wenn Sie nicht serialisierbare Datenquellen testen müssen, stellen Sie sicher, dass Sie der Testassembly das Attribut "TestDataSourceDiscovery" hinzufügen und die Ermittlungsoption auf "DuringExecution" festlegen. - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.es.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.es.xlf deleted file mode 100644 index b629fb9322..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.es.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - Método de limpieza de ensamblado '{0}.{1}' se agotó el tiempo de espera después de {2}ms - - - - Assembly cleanup method '{0}.{1}' was canceled - Método de limpieza de ensamblado "{0}.{1}" se canceló - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - Método de inicialización de ensamblado '{0}.{1}' se agotó el tiempo de espera de después de {2}ms - - - - Assembly initialize method '{0}.{1}' was canceled - Método de inicialización de ensamblado "{0}.{1}" se canceló - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - No se puede ejecutar el método de prueba "{0}.{1}": los datos de prueba no coinciden con los parámetros del método. El recuento o los tipos son diferentes. -La prueba esperaba recibir {2} parámetro(s), con los tipos "{3}", -pero recibió {4} argumento(s), con los tipos "{5}". - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - No se puede ejecutar el método de prueba "{0}.{1}": el método tiene parámetros, pero no define ningún origen de prueba. Use "[DataRow]", "[DynamicData]" o un origen de datos "ITestDataSource" personalizado para proporcionar datos de prueba. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - Método de limpieza de clases '{0}.{1}' se agotó el tiempo de espera después de {2}ms - - - - Class cleanup method '{0}.{1}' was canceled - Método de limpieza de clases "{0}.{1}" se canceló - - - - Class initialize method '{0}.{1}' timed out after {2}ms - Método de inicialización de clase '{0}.{1}' se agotó el tiempo de espera después de {2}ms - - - - Class initialize method '{0}.{1}' was canceled - Método de inicialización de clase "{0}.{1}" se canceló - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - Se han detectado los archivos ".runsettings" y ".testconfig.json". Seleccione solo uno de estos archivos de configuración de prueba. - - - - Test '{0}' timed out after {1}ms - Se agotó el tiempo de espera de la '{0}' de pruebas después de {1}ms - - - - The type of the generic parameter '{0}' could not be inferred. - No se pudo inferir el tipo del parámetro genérico '{0}'. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - El método de prueba genérico '{0}' no tiene argumentos, por lo que no se puede inferir el parámetro genérico. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - Se encontraron dos tipos en conflicto para el parámetro genérico '{0}'. Los tipos en conflicto son '{1}' y '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - Valor ''{0}'' no válido para la entrada runsettings ''{1}'', se omitirá la configuración. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - La entrada runsettings "<ExecutionApartmentState>STA</ExecutionApartmentState>" no se admite en sistemas operativos que no son de Windows. - - - - Running tests in any of the provided sources is not supported for the selected platform - La ejecución de pruebas en las fuentes proporcionadas no se admite para la plataforma seleccionada - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - Método de limpieza de pruebas '{0}.{1}' se agotó el tiempo de espera después de {2}ms - - - - Test cleanup method '{0}.{1}' was canceled - Método de limpieza de pruebas "{0}.{1}" se canceló - - - - Test initialize method '{0}.{1}' timed out after {2}ms - Método de inicialización de prueba '{0}.{1}' se agotó el tiempo de espera después de {2}ms - - - - Test initialize method '{0}.{1}' was canceled - Método de inicialización de prueba "{0}.{1}" se canceló - - - - TestCleanup method {0}.{1} threw exception. {2}. - El método TestCleanup {0}.{1} devolvió una excepción. {2}. - - - - --- End of inner exception stack trace --- - --- Fin del seguimiento de la pila de excepción interna --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: No se puede definir más de un método con el atributo AssemblyCleanup dentro de un ensamblado. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: No se puede definir más de un método con el atributo AssemblyInitialize dentro de un ensamblado. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: No se puede definir más de un método con el atributo ClassCleanup dentro de una clase. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: No se puede definir más de un método con el atributo ClassInitialize dentro de una clase. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: No se puede definir más de un método con el atributo TestCleanup. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: No se puede definir más de un método con el atributo TestInitialize. - - - - TestClass attribute defined on generic non-abstract class {0} - Atributo TestClass definido en una clase genérica no abstracta {0} - - - - Initialization method {0}.{1} threw exception. {2}. - El método de inicialización {0}.{1} devolvió una excepción. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - No se puede crear una instancia de la clase {0}. Error: {1}. - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - El método de prueba '{0}.{1}' tiene varios atributos derivados de '{2}' definidos en él. Solo se permite un atributo de este tipo. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - No se encuentra un constructor válido para la clase de prueba '{0}'. Los constructores válidos son 'public' y sin parámetros o con un parámetro de tipo 'TestContext'. - - - - Unable to set TestContext property for the class {0}. Error: {1}. - No se puede establecer la propiedad TestContext para la clase {0}. Error: {1}. - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (No se pudo obtener el mensaje para una excepción del tipo {0} debido a una excepción.) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: la clase {0}no tiene la propiedad TestContext válida. TestContext debe ser de tipo TestContext, debe ser no estática y debe ser pública. Por ejemplo: public TestContext TestContext. - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: se ha definido el atributo TestClass en la clase no pública {0} - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - MSTestAdapter no detectó pruebas en la clase '{0}' del ensamblado '{1}' porque {2}. - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - No se pueden cargar tipos del origen de prueba "{0}". Puede que no se detecten algunas o ninguna de las pruebas de este origen. -Error: {1} - - - - File does not exist: {0} - El archivo no existe: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: El método {1} definido en la clase {0} no tiene la firma correcta. El método de prueba marcado con el atributo [TestMethod] debe ser no estático, público, con el tipo devuelto void y no debe tomar ningún parámetro. Ejemplo: public void Test.Class1.Test(). Además, si está usando async-await en el método de prueba, entonces el tipo de valor devuelto debe ser 'Task' o 'ValueTask'. Ejemplo: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext no será null. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - Error de método Cleanup de ensamblado {0}.{1}. Mensaje de error: {2}. StackTrace: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - Excepción método inicialización ensamblado {0}.{1}. {2}: {3}. Anulada ejecución de prueba. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - Error de método Cleanup de clase {0}.{1}. Mensaje error: {2}. Seguimiento de pila: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - Excepción del método inicialización clase {0}. {1}. {2}: {3}. - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - El método 'Execute' produjo una excepción no controlada. Informe de este error al autor del atributo '{0}'. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - No se pudo ejecutar prueba. Extensión no devolvió resultados. Si usa extensión TestMethodAttribute, contacte con el proveedor. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - El método {0}.{1} tiene una firma incorrecta. El método debe ser estático, público, no devolver un valor y no aceptar ningún parámetro. Además, si está usando async-await en el método entonces el tipo de valor devuelto debe ser 'Task' o 'ValueTask'. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - El método {0}.{1} tiene una firma incorrecta. El método debe ser estático, público, no devolver ningún valor y debe tomar un único parámetro de tipo TestContext. Además, si está usando async-await en el método entonces el tipo de valor devuelto debe ser 'Task' o 'ValueTask'. - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}.{1} tiene un atributo Timeout no válido. El tiempo de espera debe ser un valor entero mayor que 0. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: no se puede definir la propiedad predefinida {2} en el método {1}. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: se ha definido una propiedad personalizada nula o vacía en el método {1}. La propiedad personalizada debe tener un nombre válido. - - - - Method {0}.{1} does not exist. - El método {0}.{1} no existe. - - - - Unable to find property {0}.TestContext. Error:{1}. - No se puede encontrar la propiedad {0}.TestContext. Error:{1}. - - - - The {0}.TestContext has incorrect type. - Tipo {0}.TestContext no es correcto. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - El método {0}.{1} tiene una firma incorrecta. Debe ser un método no estático, público, no devolver ningún valor y no debe aceptar parámetros. Además, si está usando async-await en el método entonces el tipo de valor devuelto debe ser 'Task' o 'ValueTask'. - - - - Unable to get type {0}. Error: {1}. - No se puede obtener el tipo {0}. Error: {1}. - - - - Test method {0} was not found. - No encontrado método prueba {0}. - - - - Debug Trace: - Seguimiento de depuración: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - No se pudo obtener la excepción iniciada por el método de prueba {0}.{1}. - - - - Test method {0}.{1} threw exception: -{2} - Excepción método de prueba {0}.{1}: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0}. En proyectos de UWP, si usa objetos de interfaz de usuario en la prueba, podría usar el atributo [UITestMethod] en lugar de [TestMethod] para ejecutar la prueba en el subproceso de interfaz de usuario. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - Valor no válido '{0}'. XmlAttribute no esperado: '{1}'. - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - Valor no válido '{0}'. XmlElement no esperado: '{1}'. - - - - {0} (Data Row {1}) - {0} (Fila de datos {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - El atributo ExpectedException definido en el método de prueba {0}.{1} inició una excepción durante la construcción. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - Advertencia: No se admite un archivo testsettings o vsmdi con el adaptador de MSTest V2. - - - - TestContext Messages: - Mensajes de TestContext: - - - - Error calling Test Cleanup method for test class {0}: {1} - Error al llamar al método Test Cleanup para la clase de prueba {0}: {1} - - - - TestCleanup Stack Trace - Seguimiento de pila de TestCleanup - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Discovery][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - Probar paralelización habilitada para {0} (Trabajos: {1}, Ámbito: {2}) - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - Valor no válido "{0}" especificado para "Ámbito". Los ámbitos admitidos son {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - Valor no válido "{0}" especificado para "Trabajadores". El valor debe ser un entero no negativo. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - No se pudieron detectar pruebas desde el ensamblado {0}. Motivo:{1} - - - - Test '{0}' was canceled - Se canceló la '{0}' de pruebas - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - Valor no válido "{0}" especificado para "ClassCleanupLifecycle". Los ámbitos admitidos son {1}. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - Excepción al enumerar el atributo IDataSource en "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - "{0}": (No se pudo obtener la descripción de la excepción debido a una excepción de tipo "{1}". - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - Excepciones devueltas: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - Al obtener atributos personalizados para el tipo {0} se produjo una excepción (se omitirá y se usará la forma de reflexión): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - Hay una versión anterior del paquete MSTestV2 cargada en el ensamblado. Es posible que la detección de pruebas no detecte todas las pruebas de datos si dependen del archivo ".runsettings". - - - - The called code threw an exception that was caught, but the exception value was null - El código llamado produjo una excepción que se detectó, pero el valor de la excepción era null - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - Se produjo una excepción al expandir las filas de IDataSource del atributo en "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - El nombre para mostrar "{2}" en los índices {0} y {1} están duplicados. Los nombres para mostrar deben ser únicos. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - No se pueden serializar los datos del {0} de índice para "{1}". Todos los datos proporcionados a través de "IDataSource" deben ser serializables. Si necesita probar orígenes de datos no serializables, asegúrese de agregar el atributo "TestDataSourceDiscovery" en el ensamblado de prueba y establezca la opción de detección en "DuringExecution". - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.fr.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.fr.xlf deleted file mode 100644 index 945bc54b28..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.fr.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - La méthode de nettoyage d’assembly « {0}.{1} » a expiré après {2}ms - - - - Assembly cleanup method '{0}.{1}' was canceled - La méthode de nettoyage de l’assembly « {0}.{1} » a été annulée - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - La méthode d'initialisation de l’assembly « {0}.{1} » a expiré après {2}ms - - - - Assembly initialize method '{0}.{1}' was canceled - La méthode d’initialisation de l’assembly « {0}.{1} » a été annulée - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - Impossible d’exécuter la méthode de test « {0}.{1} » : les données de test ne correspondent pas aux paramètres de la méthode. Le nombre ou les types sont différents. -Tester le ou les paramètres de {2} attendus, avec les types « {3} », -mais a reçu {4} argument(s), avec les types « {5} ». - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - Impossible d’exécuter la méthode de test « {0}.{1} » : la méthode a des paramètres, mais ne définit aucune source de test. Utilisez « [DataRow] », « [DynamicData] » ou une source de données « ITestDataSource » personnalisée pour fournir des données de test. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - La méthode de nettoyage de classe « {0}.{1} » a expiré après {2}ms - - - - Class cleanup method '{0}.{1}' was canceled - La méthode de nettoyage de la classe « {0}.{1} » a été annulée - - - - Class initialize method '{0}.{1}' timed out after {2}ms - La méthode d'initialisation de la classe « {0}.{1} » a expiré après {2}ms - - - - Class initialize method '{0}.{1}' was canceled - La méthode d’initialisation de la classe « {0}.{1} » a été annulée - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - Les fichiers « .runsettings » et « .testconfig.json » ont été détectés. Veuillez sélectionner un seul de ces fichiers de configuration de test. - - - - Test '{0}' timed out after {1}ms - Délai de '{0}' de test dépassé après {1}ms - - - - The type of the generic parameter '{0}' could not be inferred. - Impossible de déduire le type du paramètre générique '{0}'. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - La méthode de test générique '{0}' n’a pas d’arguments. Le paramètre générique ne peut donc pas être déduit. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - Deux types en conflit ont été trouvés pour le paramètre générique '{0}'. Les types en conflit sont '{1}' et '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - Valeur non valide '{0}' pour l’entrée runsettings '{1}', le paramètre sera ignoré. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - L’entrée Runsettings « <ExecutionApartmentState>STA</ExecutionApartmentState> » n’est pas prise en charge sur les systèmes d’exploitation non Windows. - - - - Running tests in any of the provided sources is not supported for the selected platform - L'exécution de tests dans l'une des sources fournies n'est pas prise en charge pour la plateforme sélectionnée - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - La méthode de nettoyage de test « {0}.{1} » a expiré après {2}ms - - - - Test cleanup method '{0}.{1}' was canceled - La méthode de nettoyage du test « {0}.{1} » a été annulée - - - - Test initialize method '{0}.{1}' timed out after {2}ms - La méthode d’initialisation de test « {0}.{1} » a expiré après {2}ms - - - - Test initialize method '{0}.{1}' was canceled - La méthode d’initialisation du test « {0}.{1} » a été annulée - - - - TestCleanup method {0}.{1} threw exception. {2}. - La méthode TestCleanup {0}.{1} a levé une exception. {2}. - - - - --- End of inner exception stack trace --- - --- Fin de la trace de la pile d'exception interne --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014 : {0} : impossible de définir plus d'une méthode avec l'attribut AssemblyCleanup à l'intérieur d'un assembly. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013 : {0} : impossible de définir plus d'une méthode avec l'attribut AssemblyInitialize à l'intérieur d'un assembly. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026 : {0} : impossible de définir plus d'une méthode avec l'attribut ClassCleanup à l'intérieur d'une classe. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025 : {0} : impossible de définir plus d'une méthode avec l'attribut ClassInitialize à l'intérieur d'une classe. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024 : {0} : impossible de définir plus d'une méthode avec l'attribut TestCleanup. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018 : {0} : impossible de définir plus d'une méthode avec l'attribut TestInitialize. - - - - TestClass attribute defined on generic non-abstract class {0} - Attribut TestClass défini sur une classe non abstraite générique {0} - - - - Initialization method {0}.{1} threw exception. {2}. - La méthode Initialization {0}.{1} a levé une exception. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - Impossible de créer une instance de la classe {0}. Erreur : {1}. - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - La méthode de test « {0}.{1} » possède plusieurs attributs dérivés de « {2} » qui lui sont définis. Un seul attribut de ce type est autorisé. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - Impossible de trouver un constructeur valide pour la classe de test « {0} ». Les constructeurs valides sont « publics » et sans paramètre ou avec un paramètre de type « TestContext ». - - - - Unable to set TestContext property for the class {0}. Error: {1}. - Impossible de définir la propriété TestContext pour la classe {0}. Erreur : {1}. - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (Échec de la réception du message pour une exception de type {0} en raison d'une exception.) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031 : la classe {0} n'a pas de propriété TestContext valide. TestContext doit être de type TestContext, doit être non statique et doit être public. Par exemple : public TestContext TestContext. - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001 : attribut TestClass défini sur la classe non publique {0} - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - MSTestAdapter n'a pas découvert de tests dans la classe '{0}' de l'assembly '{1}', car {2}. - - - - {0}: {1} - {0} : {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - Impossible de charger les types à partir de la source de tests '{0}'. Une partie ou l'ensemble des tests de cette source ne peuvent pas être découverts. -Erreur : {1} - - - - File does not exist: {0} - Fichier inexistant : {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007 : la méthode {1} définie dans la classe {0} ne dispose pas d'une signature correcte. Une méthode de test marquée avec l'attribut [TestMethod] doit être non statique, doit utiliser void pour return-type et ne doit accepter aucun paramètre. Exemple : public void Test.Class1.Test(). En outre, si vous utilisez async-await dans la méthode test, return-type doit être « Task » ou « ValueTask ». Exemple : public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext ne peut pas être null. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - La méthode Cleanup d'assembly {0}.{1} a échoué. Message d'erreur : {2}. StackTrace : {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - La méthode d'assembly Initialization {0}.{1} a levé une exception. {2} : {3}. Abandon de l'exécution de tests. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - La méthode de classe Cleanup {0}.{1} a échoué. Message d'erreur : {2}. Trace de la pile : {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - La méthode de classe Initialization {0}.{1} a levé une exception. {2} : {3}. - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - Une exception non gérée a été levée par la méthode 'Execute'. Signalez cette erreur à l’auteur de l’attribut '{0}'. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - Erreur lors de l'exécution du test. L'extension n'a retourné aucun résultat. Si vous utilisez l'extension de TestMethodAttribute, contactez le fournisseur. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - La méthode {0}.{1} présente une signature incorrecte. La méthode doit être statique, publique et ne doit retourner aucune valeur ni accepter aucun paramètre. En outre, si vous utilisez async-await dans la méthode, return-type doit être « Task » ou « ValueTask ». - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - La méthode {0}.{1} présente une signature incorrecte. La méthode doit être statique, publique et ne doit retourner aucune valeur et accepter un seul paramètre de type TestContext. En outre, si vous utilisez async-await dans la méthode, return-type doit être « Task » ou « ValueTask ». - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054 : {0}.{1}possède un attribut de délai d’expiration non valide. Le délai d’expiration doit être un nombre entier supérieur à 0. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023 : {0} : Impossible de définir la propriété prédéfinie {2} sur la méthode {1}. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021 : {0} : Une propriété null ou vide personnalisée est définie sur la méthode {1}. La propriété personnalisée doit posséder un nom valide. - - - - Method {0}.{1} does not exist. - La méthode {0}.{1} n'existe pas. - - - - Unable to find property {0}.TestContext. Error:{1}. - Propriété {0}.TestContext introuvable. Erreur :{1}. - - - - The {0}.TestContext has incorrect type. - {0}.TestContext possède un type incorrect. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - La méthode {0}.{1} présente une signature incorrecte. La méthode doit être non statique, publique et ne doit retourner aucune valeur ni accepter aucun paramètre. En outre, si vous utilisez async-await dans la méthode, return-type doit être « Task » ou « ValueTask ». - - - - Unable to get type {0}. Error: {1}. - Impossible d'obtenir le type {0}. Erreur : {1}. - - - - Test method {0} was not found. - Méthode de test {0} introuvable. - - - - Debug Trace: - Trace du débogage : - - - - Failed to obtain the exception thrown by test method {0}.{1}. - Échec de l'obtention de l'exception levée par la méthode de test {0}.{1}. - - - - Test method {0}.{1} threw exception: -{2} - La méthode de test {0}.{1} a levé une exception : -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0} Pour les projets UWP, si vous utilisez des objets d'IU dans un test, utilisez l'attribut [UITestMethod] à la place de [TestMethod] pour exécuter le test dans le thread d'interface utilisateur. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - Paramètres non valides '{0}'. XmlAttribute inattendu : '{1}'. - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - Paramètres non valides '{0}'. XmlElement inattendu : '{1}'. - - - - {0} (Data Row {1}) - {0} (ligne de données {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - L'attribut ExpectedException défini dans la méthode de test {0}.{1} a levé une exception durant la construction. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - Avertissement : L'adaptateur MSTest V2 ne prend pas en charge les fichiers testsettings ou vsmdi. - - - - TestContext Messages: - Messages TestContext : - - - - Error calling Test Cleanup method for test class {0}: {1} - Erreur lors de l'appel de la méthode Test Cleanup pour la classe de test {0} : {1} - - - - TestCleanup Stack Trace - Trace de la pile TestCleanup - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Discovery][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - Parallélisation des tests activée pour {0} (Workers : {1}, Étendue : {2}). - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - Valeur non valide '{0}' spécifiée pour la 'Portée'. Les portées prises en charge sont {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - Valeur non valide '{0}' spécifiée pour 'Workers'. La valeur doit être un entier non négatif. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - Échec de la découverte de tests à partir de l'assembly {0}. Raison :{1} - - - - Test '{0}' was canceled - Le test '{0}' a été annulé - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - Valeur non valide '{0}' spécifiée pour la 'ClassCleanupLifecycle'. Les portées prises en charge sont {1}. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - Une exception s’est produite lors de l’énumération de l’attribut IDataSource sur « {0}.{1} » : {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - « {0} » : (Échec de l’obtention de la description de l’exception en raison d’une exception de type « {1} ». - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - Exceptions levées/s : - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - L’obtention d’attributs personnalisés pour le type {0} a levé une exception (ignorera et utilisera la méthode de réflexion) : {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - Une version antérieure du package MSTestV2 est chargée dans l’assembly. La découverte de tests risque de ne pas découvrir tous les tests de données s’ils dépendent du fichier '.runsettings'. - - - - The called code threw an exception that was caught, but the exception value was null - Le code appelé a levé une exception qui a été interceptée, mais la valeur de l’exception était nul - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - Une exception s’est produite lors du développement des lignes IDataSource à partir de l’attribut sur « {0}.{1} » : {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - Le nom d’affichage « {2} » sur les index {0} et {1} est dupliqué. Les noms d’affichage doivent être uniques. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - Impossible de sérialiser les données de l’index {0} pour « {1} ». Toutes les données fournies via « IDataSource » doivent être sérialisables. Si vous devez tester des sources de données non sérialisables, veillez à ajouter l’attribut « TestDataSourceDiscovery » à votre assembly de test et définissez l’option de découverte sur « DuringExecution ». - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.it.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.it.xlf deleted file mode 100644 index 97bff51c03..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.it.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - Metodo di pulizia dell’assembly '{0}. Time out di {1}' dopo {2} ms - - - - Assembly cleanup method '{0}.{1}' was canceled - Il metodo di pulizia dell'assembly "{0}.{1}" è stato annullato - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - Metodo di inizializzazione dell'assembly '{0}. Timeout di {1}' dopo {2} ms - - - - Assembly initialize method '{0}.{1}' was canceled - Il metodo di inizializzazione dell'assembly "{0}.{1}" è stato annullato - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - Impossibile eseguire il metodo di test "{0}.{1}": i dati del test non corrispondono ai parametri del metodo. Il numero o il tipo è diverso. -Il test prevedeva {2} parametri, con tipi "{3}", -ma ha ricevuto {4} argomenti, con tipi "{5}". - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - Impossibile eseguire il metodo di test "{0}.{1}": il metodo contiene parametri, ma non definisce alcuna origine test. Usare "[DataRow]", "[DynamicData]" o un'origine dati "ITestDataSource" personalizzata per fornire i dati del test. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - Time out del metodo di pulizia della classe '{0}. Time out di {1}' dopo {2} ms - - - - Class cleanup method '{0}.{1}' was canceled - Il metodo di pulizia della classe "{0}.{1}" è stato annullato - - - - Class initialize method '{0}.{1}' timed out after {2}ms - Metodo di inizializzazione della classe '{0}. Timeout di {1}' dopo {2} ms - - - - Class initialize method '{0}.{1}' was canceled - Il metodo di inizializzazione della classe "{0}.{1}" è stato annullato - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - Sono stati rilevati sia i file '.runsettings' sia '.testconfig.json'. Selezionare solo uno di questi file di configurazione di test. - - - - Test '{0}' timed out after {1}ms - Timeout del '{0}' di test dopo {1}ms - - - - The type of the generic parameter '{0}' could not be inferred. - Impossibile dedurre il tipo del parametro generico '{0}'. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - Il metodo di test generico '{0}' non contiene argomenti, di conseguenza non è possibile dedurre il parametro generico. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - Sono stati trovati due tipi in conflitto per il parametro generico '{0}'. I tipi in conflitto sono '{1}' e '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - Valore non valido '{0}' per la voce runsettings '{1}'. L'impostazione verrà ignorata. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - La voce Runsettings '<ExecutionApartmentState>STA</ExecutionApartmentState>' non è supportata nei sistemi operativi non Windows. - - - - Running tests in any of the provided sources is not supported for the selected platform - L'esecuzione di test in una delle origini specificate non è supportata per la piattaforma selezionata - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - Time out del metodo di pulizia della classe dei test '{0}. Time out di {1}' dopo {2} ms - - - - Test cleanup method '{0}.{1}' was canceled - Il metodo di pulizia del test "{0}.{1}" è stato annullato - - - - Test initialize method '{0}.{1}' timed out after {2}ms - Metodo di inizializzazione del test '{0}. Timeout di {1}' dopo {2} ms - - - - Test initialize method '{0}.{1}' was canceled - Il metodo di inizializzazione del test "{0}.{1}" è stato annullato - - - - TestCleanup method {0}.{1} threw exception. {2}. - Il metodo TestCleanup {0}.{1} ha generato un'eccezione. {2}. - - - - --- End of inner exception stack trace --- - --- Fine dell'analisi dello stack dell'eccezione interna --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: non è possibile definire più di un metodo con l'attributo AssemblyCleanup all'interno di un assembly. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: non è possibile definire più di un metodo con l'attributo AssemblyInitialize all'interno di un assembly. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: non è possibile definire più di un metodo con l'attributo ClassCleanup all'interno di una classe. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: non è possibile definire più di un metodo con l'attributo ClassInitialize all'interno di una classe. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: non è possibile definire più di un metodo con l'attributo TestCleanup. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: non è possibile definire più di un metodo con l'attributo TestInitialize. - - - - TestClass attribute defined on generic non-abstract class {0} - Attributo TestClass definito nella classe generica non astratta {0} - - - - Initialization method {0}.{1} threw exception. {2}. - Il metodo di inizializzazione {0}.{1} ha generato un'eccezione. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - Non è possibile creare un'istanza della classe {0}. Errore: {1}. - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - Il metodo di test '{0}.{1}' contiene più attributi derivati da '{2}' definito in esso. È consentito solo uno di tali attributi. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - Impossibile trovare un costruttore valido per la classe di test '{0}'. I costruttori validi sono 'public' e senza parametri o con un parametro di tipo 'TestContext'. - - - - Unable to set TestContext property for the class {0}. Error: {1}. - Non è possibile impostare la proprietà TestContext per la classe {0}. Errore: {1}. - - - - (Failed to get the message for an exception of type {0} due to an exception.) - Non è stato possibile ottenere il messaggio per un'eccezione di tipo {0} a causa di un'eccezione. - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: la classe {0} non dispone di una proprietà TestContext valida. La proprietà TestContext deve essere di tipo TestContext, non deve essere statica e deve essere pubblica. Ad esempio: public TestContext TestContext. - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: è stato definito l'attributo TestClass per la classe non pubblica {0} - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - MSTestAdapter non è riuscito a individuare test nella classe '{0}' dell'assembly '{1}' perché {2}. - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - Non è possibile caricare i tipi dall'origine test '{0}'. È possibile che alcuni o tutti i test non siano stati individuati in questa origine. -Errore: {1} - - - - File does not exist: {0} - Il file {0} non esiste - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: la firma del metodo {1} definito nella classe {0} non è corretta. Il metodo di test contrassegnato con l'attributo [TestMethod] deve essere pubblico e non statico, non deve accettare parametri e deve includere un tipo restituito void. Esempio: public void Test.Class1.Test(). Se inoltre nel metodo di test si usa async-await, il tipo restituito deve essere 'Task' o 'ValueTask'. Esempio: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext non può essere Null. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - Il metodo di pulizia assembly {0}.{1} non è riuscito. Messaggio di errore: {2}. Analisi dello stack: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - Il metodo di inizializzazione assembly {0}.{1} ha generato un'eccezione. {2}: {3}. L'esecuzione del test verrà interrotta. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - Il metodo di pulizia classi {0}.{1} non è riuscito. Messaggio di errore: {2}. Analisi dello stack: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - Il metodo di inizializzazione classi {0}.{1} ha generato un'eccezione. {2}: {3}. - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - Eccezione non gestita generata dal metodo 'Execute'. Segnalare l'errore all'autore dell'attributo '{0}'. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - Si è verificato un errore durante l'esecuzione del test. L'estensione non ha restituito alcun risultato. Se si usa l'estensione di TestMethodAttribute, contattare il fornitore. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - La firma del metodo {0}.{1}non è corretta. Il metodo deve essere statico e pubblico, non deve restituire un valore né accettare parametri. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere 'Task' o 'ValueTask'. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - La firma del metodo {0}.{1}non è corretta. Il metodo deve essere statico e pubblico, non deve restituire un valore e deve accettare un singolo parametro di tipo TestContext. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere 'Task' o 'ValueTask'. - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}.{1} ha un attributo Timeout non valido. Il timeout deve essere un valore intero maggiore di 0. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: non è possibile definire la proprietà predefinita {2} per il metodo {1}. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: per il metodo {1} è stata definita una proprietà personalizzata Null o vuota. Specificare un nome valido per la proprietà personalizzata. - - - - Method {0}.{1} does not exist. - Il metodo {0}.{1} non esiste. - - - - Unable to find property {0}.TestContext. Error:{1}. - La proprietà {0}.TestContext non è stata trovata. Errore: {1}. - - - - The {0}.TestContext has incorrect type. - Il tipo di {0}.TestContext non è corretto. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - La firma del metodo {0}.{1}non è corretta. Il metodo deve essere non statico e pubblico, non deve restituire un valore né accettare parametri. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere 'Task' o 'ValueTask'. - - - - Unable to get type {0}. Error: {1}. - Non è possibile ottenere il tipo {0}. Errore: {1}. - - - - Test method {0} was not found. - Il metodo di test {0} non è stato trovato. - - - - Debug Trace: - Traccia di debug: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - Non è stato possibile ottenere l'eccezione generata dal metodo di test {0}.{1}. - - - - Test method {0}.{1} threw exception: -{2} - Il metodo di test {0}.{1} ha generato un'eccezione: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0}. Se, per i progetti della piattaforma UWP, nel test si usano oggetti dell'interfaccia utente, provare a specificare l'attributo [UITestMethod] invece di [TestMethod] per eseguire il test nel thread di UI. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - Le impostazioni '{0}' non sono valide. Elemento XmlAttribute imprevisto: '{1}'. - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - Le impostazioni '{0}' non sono valide. Elemento XmlElement imprevisto: '{1}'. - - - - {0} (Data Row {1}) - {0} (riga dati {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - L'attributo ExpectedException definito nel metodo di test {0}.{1} ha generato un'eccezione durante la costruzione. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - Avviso: con l'adattatore MSTest V2 non è possibile usare un file testsettings o un file vsmdi. - - - - TestContext Messages: - Messaggi di TestContext: - - - - Error calling Test Cleanup method for test class {0}: {1} - Si è verificato un errore durante la chiamata del metodo TestCleanup per la classe di test {0}: {1} - - - - TestCleanup Stack Trace - Analisi dello stato di TestCleanup - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Individuazione][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - Parallelizzazione test abilitata per {0} (Processi di lavoro: {1}. Ambito: {2}). - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - Il valore '{0}', specificato per 'Scope', non è valido. I valori supportati per Scope sono {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - Il valore '{0}', specificato per 'Workers', non è valido. Il valore deve essere un numero intero non negativo. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - Non è stato possibile individuare i test dall'assembly {0}. Motivo: {1} - - - - Test '{0}' was canceled - Il '{0}' di test è stato annullato - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - Il valore '{0}', specificato per 'ClassCleanupLifecycle', non è valido. I valori supportati per Scope sono {1}. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - Si è verificata un'eccezione durante l'enumerazione dell'attributo IDataSource in "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - "{0}": (non è stato possibile ottenere la descrizione dell'eccezione a causa di un'eccezione di tipo "{1}". - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - Eccezioni generate: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - Il recupero degli attributi personalizzati per il tipo {0} ha generato un'eccezione (verrà ignorata e verrà usata la modalità reflection): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - Nell'assembly è caricata una versione precedente del pacchetto MSTestV2. L'individuazione dei test potrebbe non riuscire a individuare tutti i test dei dati se dipendono dal file '.runsettings'. - - - - The called code threw an exception that was caught, but the exception value was null - Il codice chiamato ha generato un'eccezione che è stata rilevata, ma il valore dell'eccezione è Null - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - Si è verificata un'eccezione durante l'espansione delle righe IDataSource dall'attributo in "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - Il nome visualizzato "{2}" negli indici {0} e {1} è duplicato. I nomi visualizzati devono essere univoci. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - Non è possibile serializzare i dati nell'indice {0} per "{1}". Tutti i dati forniti tramite "IDataSource" devono essere serializzabili. Se è necessario testare origini dati non serializzabili, assicurarsi di aggiungere l'attributo "TestDataSourceDiscovery" nell'assembly di test e impostare l'opzione di individuazione su "DuringExecution". - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ja.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ja.xlf deleted file mode 100644 index 0e196b3b3f..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ja.xlf +++ /dev/null @@ -1,483 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - アセンブリ クリーンアップ メソッド '{0}.{1}' が {2}ms 後にタイムアウトしました - - - - Assembly cleanup method '{0}.{1}' was canceled - アセンブリ クリーンアップ メソッド '{0}.{1}' が取り消されました - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - アセンブリ初期化メソッド '{0}.{1}' が {2}ms 後にタイムアウトになりました - - - - Assembly initialize method '{0}.{1}' was canceled - アセンブリ初期化メソッド '{0}.{1}' が取り消されました - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - テスト メソッド '{0}を実行できません。{1}': テスト データがメソッド パラメーターと一致しません。カウントまたは型が異なります。 -型 '{3}'、 - を持つ、予期された {2} パラメーターをテストします -ただし、型 '{5}' の引数 {4} を受け取りました。 - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - テスト メソッド '{0} を実行できません。{1}': メソッドにはパラメーターがありますが、テスト ソースは定義されていません。'[DataRow]'、'[DynamicData]'、カスタムの 'ITestDataSource' データ ソースを使用して、テスト データを提供します。 - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - クラス クリーンアップ メソッド '{0}.{1}' が {2}ms 後にタイムアウトしました - - - - Class cleanup method '{0}.{1}' was canceled - クラス クリーンアップ メソッド '{0}.{1}' が取り消されました - - - - Class initialize method '{0}.{1}' timed out after {2}ms - クラス初期化メソッド '{0}.{1}' が {2}ms 後にタイムアウトになりました - - - - Class initialize method '{0}.{1}' was canceled - クラス初期化メソッド '{0}.{1}' が取り消されました - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - '.runsettings' ファイルと '.testconfig.json' ファイルの両方が検出されました。これらのテスト構成ファイルのいずれか 1 つだけを選択してください。 - - - - Test '{0}' timed out after {1}ms - テスト '{0}' が {1}ミリ秒後にタイムアウトしました - - - - The type of the generic parameter '{0}' could not be inferred. - ジェネリック パラメーター '{0}' の型を推論できませんでした。 - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - '{0}' ジェネリック テスト メソッドに引数がないため、ジェネリック パラメーターを推論できません。 - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - ジェネリック パラメーター '{0}' に 2 つの競合する型が見つかりました。競合する型は '{1}' で '{2}'。 - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - runsettings エントリ '{1}' の値 '{0}' は無効です。設定は無視されます。 - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - Runsettings エントリ '<ExecutionApartmentState>STA</ExecutionApartmentState>' は、Windows OS 以外ではサポートされていません。 - - - - Running tests in any of the provided sources is not supported for the selected platform - 指定されたソースのいずれかでのテストの実行は、選択されたプラットフォームでサポートされていません - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - テスト クリーンアップ メソッド '{0}.{1}' が {2}ms 後にタイムアウトしました - - - - Test cleanup method '{0}.{1}' was canceled - テスト クリーンアップ メソッド '{0}.{1}' が取り消されました - - - - Test initialize method '{0}.{1}' timed out after {2}ms - テスト初期化メソッド '{0}.{1}' が {2}ms 後にタイムアウトになりました - - - - Test initialize method '{0}.{1}' was canceled - テスト初期化メソッド '{0}.{1}' が取り消されました - - - - TestCleanup method {0}.{1} threw exception. {2}. - TestCleanup メソッド {0}.{1} は例外をスローしました。{2}。 - - - - --- End of inner exception stack trace --- - --- 内部例外スタック トレースの終わり --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: 1 つのアセンブリ内で、AssemblyCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。 - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: 1 つのアセンブリ内で、AssemblyInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。 - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: 1 つのクラス内で、ClassCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。 - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: 1 つのクラス内で、ClassInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。 - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: TestCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。 - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: TestInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。 - - - - TestClass attribute defined on generic non-abstract class {0} - 汎用の非抽象クラス {0}で定義された TestClass 属性 - - - - Initialization method {0}.{1} threw exception. {2}. - 初期化メソッド {0}.{1} は例外をスローしました。{2}。 - - - - Unable to create instance of class {0}. Error: {1}. - クラス {0} のインスタンスを作成できません。エラー: {1}。 - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - テスト メソッド '{0}.{1}' には、 '{2}' から派生した属性が複数定義されています。このような属性は 1 つしか許可されません。 - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - テスト クラス '{0}' の有効なコンストラクターが見つかりません。有効なコンストラクターは、'public' で、パラメーターがないもの、または 'TestContext' 型のパラメーター 1 個を取るものです。 - - - - Unable to set TestContext property for the class {0}. Error: {1}. - クラス {0} の TestContext プロパティを設定できません。エラー: {1}。 - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (例外が発生したため、型 {0} の例外のメッセージを取得できませんでした。) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: クラス {0} に有効な TestContext プロパティがありません。TestContext は TestContext 型で、非静的である必要があり、public である必要があります。たとえば、public TestContext TestContext です。 - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: TestClass 属性がパブリックでないクラス {0} で定義されています - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - MSTestAdapter でアセンブリ '{1}' のクラス '{0}' にテストが見つかりませんでした。理由 {2}。 - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - テスト ソース '{0}' から型を読み込むことができません。このソース内の一部またはすべてのテストが見つからない可能性があります。 -エラー: {1} - - - - File does not exist: {0} - ファイルが存在しません: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: クラス {0} で定義されているメソッド {1} に適切なシグネチャが含まれていません。[TestMethod] 属性でマークされたテスト メソッドは、non-static および public である必要があり、戻り値の型は void である必要があります。また、パラメーターを受け取ることはできません。例: public void Test.Class1.Test()。また、テスト メソッドで async-await を使用している場合、戻り値の型は 'Task' または 'ValueTask' である必要があります。例: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext を Null にすることはできません。 - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - アセンブリ クリーンアップ メソッド {0}.{1} に失敗しました。エラー メッセージ: {2}。スタック トレース: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - アセンブリ初期化メソッド {0}.{1} は例外をスローしました。{2}: {3}。テストの実行を中止しています。 - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - クラス クリーンアップ メソッド {0}.{1} に失敗しました。エラー メッセージ: {2}。スタック トレース: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - クラス初期化メソッド {0}.{1} は例外をスローしました。{2}: {3}。 - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - 'Execute' メソッドによってハンドルされない例外がスローされました。属性 '{0}' の作成者にこのエラーを報告してください。 -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - テストの実行中にエラーが発生しました。拡張から結果が返されませんでした。TestMethodAttribute の拡張クラスを使用している場合は、ベンダーに連絡してください。 - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - メソッド {0}。{1} は不適切なシグネチャを含んでいます。メソッドは static および public である必要があり、値を返しません。また、パラメーターを受け取ることはできません。また、メソッドで async-await を使用している場合、戻り値の型は 'Task' または 'ValueTask' である必要があります。 - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - メソッド {0}。{1} は不適切なシグネチャを含んでいます。メソッドは static および public である必要があり、値を返しません。また、TestContext 型の 1 つのパラメーターを受け取る必要があります。また、メソッドで async-await を使用している場合、戻り値の型は 'Task' または 'ValueTask' である必要があります。 - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}。{1} に無効な Timeout 属性があります。タイムアウトには、0 より大きい整数値を指定する必要があります。 - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: メソッド {1} 上の以前に定義されたプロパティ {2} を定義することはできません。 - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: Null または空のカスタム プロパティが、メソッド {1} で定義されています。カスタム プロパティには有効な名前を指定しなければなりません。 - - - - Method {0}.{1} does not exist. - メソッド {0}.{1} は存在しません。 - - - - Unable to find property {0}.TestContext. Error:{1}. - プロパティ {0}.TestContext が見つかりません。エラー: {1}。 - - - - The {0}.TestContext has incorrect type. - {0}.TestContext は不適切な型を含んでいます。 - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - メソッド {0}。{1} は不適切なシグネチャを含んでいます。メソッドは non-static および public である必要があり、値を返しません。また、パラメーターを受け取ることはできません。また、メソッドで async-await を使用している場合、戻り値の型は 'Task' または 'ValueTask' である必要があります。 - - - - Unable to get type {0}. Error: {1}. - 型 {0} を取得できません。エラー: {1}。 - - - - Test method {0} was not found. - テスト メソッド {0} が見つかりませんでした。 - - - - Debug Trace: - デバッグ トレース: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - テスト メソッド {0}.{1} によってスローされた例外を取得できませんでした。 - - - - Test method {0}.{1} threw exception: -{2} - テスト メソッド {0}.{1} が例外をスローしました: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0} UWP プロジェクトについて、テスト内で UI オブジェクトを使用している場合は、[TestMethod] の代わりに [UITestMethod] 属性を使用して UI スレッド内でテストを実行することを検討してください。 - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - 設定 '{0}' は無効です。予期しない XmlAttribute: '{1}'。 - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - 設定 '{0}' は無効です。予期しない XmlElement: '{1}'。 - - - - {0} (Data Row {1}) - {0} (データ行 {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - テスト メソッド {0}.{1} に定義されている ExpectedException 属性が、作成中に例外をスローしました。 -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - 警告: testsettings ファイル、vsmdi ファイルは MSTest V2 アダプターではサポートされていません。 - - - - TestContext Messages: - TestContext メッセージ: - - - - Error calling Test Cleanup method for test class {0}: {1} - テスト クラス {0} のテスト クリーンアップ メソッドの呼び出しでエラーが発生しました: {1} - - - - TestCleanup Stack Trace - TestCleanup スタック トレース - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Discovery][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - {0} でテスト並列処理が有効にされています (Workers: {1}、Scope: {2})。 - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - 無効な値 '{0}' が 'Scope' に指定されました。サポートされているスコープは {1} です。 - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - 無効な値 '{0}' が 'Workers' に指定されました。値は負ではない整数である必要があります。 - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - アセンブリ {0} からテストを検出できませんでした。理由:{1} - - - - Test '{0}' was canceled - テスト '{0}' が取り消されました - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - 'ClassCleanupLifecycle' に無効な値 '{0}' が指定されました。サポートされているスコープは {1} です。 - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - "{0}.{1}" で IDataSource 属性を列挙中に例外が発生しました: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - "{0}": (種類が "{1}"の例外のため、例外の説明を取得できませんでした。 - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - スローされた例外: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - 型 {0} のカスタム属性を取得中に例外がスローされました (無視してリフレクションの方法を使用します): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - 古いバージョンの MSTestV2 パッケージがアセンブリに読み込まれています。`.runsettings` ファイルに依存している場合、テスト検出ですべてのデータ テストを検出できない可能性があります。 - - - - The called code threw an exception that was caught, but the exception value was null - 呼び出されたコードはキャッチされた例外をスローしましたが、例外値が null でした - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - "{0}.{1}" の属性から IDataSource 行を展開中に例外が発生しました: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - インデックス {0} と {1} の表示名 "{2}" が重複しています。表示名は一意である必要があります。 - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - "{1}" のインデックス {0} のデータをシリアル化できません。"IDataSource" を介して提供されるすべてのデータはシリアル化可能である必要があります。シリアル化できないデータ ソースをテストする必要がある場合は、テスト アセンブリに "TestDataSourceDiscovery" 属性を追加し、検出オプションを "DuringExecution" に設定してください。 - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ko.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ko.xlf deleted file mode 100644 index b652734ad5..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ko.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - {2}밀리초 후 어셈블리 정리 메서드 '{0}.{1}'이(가) 시간 초과되었습니다. - - - - Assembly cleanup method '{0}.{1}' was canceled - 어셈블리 정리 메서드 '{0}.{1}'이(가) 취소되었습니다. - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - {2}밀리초 후 '{0}.{1}' 어셈블리 초기화 메서드의 시간이 초과되었습니다. - - - - Assembly initialize method '{0}.{1}' was canceled - 어셈블리 초기화 메서드 '{0}.{1}'(이)가 취소되었습니다. - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - 테스트 메서드 '{0}{1}'을(를) 실행할 수 없음: 테스트 데이터가 메서드 매개 변수와 일치하지 않습니다. 개수 또는 형식이 다릅니다. -테스트에 {2} 매개 변수로 ‘{3}’ 형식이 필요하지만, -{4} 인수의 ‘{5}’ 형식을 받았습니다. - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - 테스트 메서드 '{0}{1}'을(를) 실행할 수 없음: 메서드에 매개 변수가 있지만 테스트 원본을 정의하지 않습니다. '[DataRow]', '[DynamicData]' 또는 사용자 지정 'ITestDataSource' 데이터 원본을 사용하여 테스트 데이터를 제공합니다. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - {2}밀리초 후 클래스 정리 메서드 '{0}.{1}'이(가) 시간 초과되었습니다. - - - - Class cleanup method '{0}.{1}' was canceled - 클래스 정리 메서드 '{0}.{1}'이(가) 취소되었습니다. - - - - Class initialize method '{0}.{1}' timed out after {2}ms - {2}밀리초 후 '{0}.{1}' 클래스 초기화 메서드의 시간이 초과되었습니다. - - - - Class initialize method '{0}.{1}' was canceled - '클래스 초기화 메서드 '{0}.{1}'이(가) 취소되었습니다. - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - '.runsettings' 및 '.testconfig.json' 파일이 모두 검색되었습니다. 이러한 테스트 구성 파일 중 하나만 선택하세요. - - - - Test '{0}' timed out after {1}ms - 테스트 '{0}' {1}밀리초 후에 시간 초과되었습니다. - - - - The type of the generic parameter '{0}' could not be inferred. - 제네릭 매개 변수 '{0}' 형식을 유추할 수 없습니다. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - 제네릭 테스트 메서드 '{0}' 인수가 없으므로 제네릭 매개 변수를 유추할 수 없습니다. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - 제네릭 매개 변수 '{0}' 충돌하는 두 가지 형식을 찾았습니다. 충돌하는 형식은 '{1}' '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - runsettings 항목 '{1}'에 대해 '{0}' 값이 잘못되었습니다. 설정은 무시됩니다. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - Runsettings 항목 '<ExecutionApartmentState>STA</ExecutionApartmentState>'는 Windows 이외의 OS에서는 지원되지 않습니다. - - - - Running tests in any of the provided sources is not supported for the selected platform - 선택된 플랫폼의 경우 제공된 소스에서 테스트를 실행할 수 없습니다. - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - {2}밀리초 후 테스트 정리 메서드 '{0}.{1}'이(가) 시간 초과되었습니다. - - - - Test cleanup method '{0}.{1}' was canceled - 테스트 정리 메서드 '{0}.{1}'이(가) 취소되었습니다. - - - - Test initialize method '{0}.{1}' timed out after {2}ms - {2}밀리초 후 '{0}.{1}' 테스트 초기화 메서드의 시간이 초과되었습니다. - - - - Test initialize method '{0}.{1}' was canceled - 테스트 초기화 메서드 '{0}.{1}'이(가) 취소되었습니다. - - - - TestCleanup method {0}.{1} threw exception. {2}. - TestCleanup 메서드 {0}.{1}에서 예외가 발생했습니다. {2}. - - - - --- End of inner exception stack trace --- - --- 내부 예외 스택 추적의 끝 --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: 어셈블리 내부에서 AssemblyCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: 어셈블리 내부에서 AssemblyInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: 클래스 내부에서 ClassCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: 클래스 내부에서 ClassInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: TestCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: TestInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. - - - - TestClass attribute defined on generic non-abstract class {0} - 일반 비추상 클래스 {0}에 정의된 TestClass 속성 - - - - Initialization method {0}.{1} threw exception. {2}. - 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - {0} 클래스의 인스턴스를 만들 수 없습니다. 오류: {1} - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - 테스트 메서드 '{0}.{1}'에 {2}에서 파생된 여러 특성이 정의되어 있습니다. 이러한 특성은 하나만 허용됩니다. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - 테스트 클래스 '{0}'에 대한 유효한 생성자를 찾을 수 없습니다. 유효한 생성자는 'public'이며 매개 변수가 없거나 'TestContext' 유형의 매개 변수가 하나 있습니다. - - - - Unable to set TestContext property for the class {0}. Error: {1}. - {0} 클래스에 대해 TestContext 속성을 설정할 수 없습니다. 오류: {1} - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (예외로 인해 {0} 형식의 예외에 대한 메시지를 가져오지 못했습니다.) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: {0} 클래스에 유효한 TestContext 속성이 없습니다. TestContext는 TestContext 유형이어야 하고, 정적이 아니어야 하며, 일반적이어야 합니다. 예: public TestContext TestContext. - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: public이 아닌 클래스 {0}에서 TestClass 특성을 정의했습니다. - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - MSTestAdapter가 {2} 때문에 어셈블리 '{1}'의 클래스 '{0}'에서 테스트를 검색하지 못했습니다. - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - 테스트 소스 '{0}'에서 형식을 로드할 수 없습니다. 이 소스의 일부 또는 모든 테스트를 검색할 수 없습니다. -오류: {1} - - - - File does not exist: {0} - 파일이 없습니다. {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: 클래스 {0}에 정의된 메서드 {1}에 올바른 서명이 없습니다. [TestMethod] 특성으로 표시된 테스트 메서드는 non-static, public, return-type이 void여야 하며 매개 변수를 사용하지 않아야 합니다. 예: public void Test.Class1.Test(). 또한 테스트 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다. 예: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext는 null일 수 없습니다. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - 어셈블리 정리 메서드 {0}.{1}이(가) 실패했습니다. 오류 메시지: {2}. StackTrace: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - 어셈블리 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3}. 테스트 실행을 중단합니다. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - 클래스 정리 메서드 {0}.{1}이(가) 실패했습니다. 오류 메시지: {2}. 스택 추적: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - 클래스 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3} - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - 'Execute' 메서드에서 처리되지 않은 예외가 throw되었습니다. 특성 '{0}' 만든 이에게 이 오류를 보고하십시오. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - 테스트를 실행하는 중에 오류가 발생했습니다. 확장에서 결과가 반환되지 않았습니다. TestMethodAttribute 확장을 사용하는 경우 공급업체에 문의하세요. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이고 공용이어야 하며, 값을 반환하거나 매개 변수를 취하지 않습니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 'Task' 또는 'ValueTask'여야 합니다. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 static, public이어야 하고, 값을 반환하지 않으며, TestContext 형식의 단일 매개 변수를 사용해야 합니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 'Task' 또는 'ValueTask'여야 합니다. - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}.{1}에 잘못된 Timeout 특성이 있습니다. 시간 제한 값은 0보다 큰 정수여야 합니다. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: {1} 메서드에서 미리 정의된 속성 {2}을(를) 정의할 수 없습니다. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: {1} 메서드에서 Null 또는 빈 사용자 지정 속성을 정의했습니다. 사용자 지정 속성에는 올바른 이름이 지정되어 있어야 합니다. - - - - Method {0}.{1} does not exist. - {0}.{1} 메서드가 없습니다. - - - - Unable to find property {0}.TestContext. Error:{1}. - {0}.TestContext 속성을 찾을 수 없습니다. 오류: {1} - - - - The {0}.TestContext has incorrect type. - {0}.TestContext의 형식이 잘못되었습니다. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이 아니고 공용이어야 하며, 값을 반환하거나 매개 변수를 사용할 수 없습니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 'Task' 또는 'ValueTask'여야 합니다. - - - - Unable to get type {0}. Error: {1}. - {0} 형식을 가져올 수 없습니다. 오류: {1} - - - - Test method {0} was not found. - {0} 테스트 메서드를 찾을 수 없습니다. - - - - Debug Trace: - 디버그 추적: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - 테스트 메서드 {0}.{1}에서 throw한 예외를 가져오지 못했습니다. - - - - Test method {0}.{1} threw exception: -{2} - 테스트 메서드 {0}.{1}에서 예외를 throw했습니다. -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0} UWP 프로젝트의 경우 테스트에서 UI 개체를 사용 중이면 [TestMethod] 대신 [UITestMethod] 특성을 사용하여 UI 스레드에서 테스트를 실행하세요. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - '{0}' 설정이 잘못되었습니다. 예기치 않은 XmlAttribute '{1}'이(가) 있습니다. - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - '{0}' 설정이 잘못되었습니다. 예기치 않은 XmlElement '{1}'이(가) 있습니다. - - - - {0} (Data Row {1}) - {0}(데이터 행 {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - 테스트 메서드 {0}.{1}에 정의된 ExpectedException 특성이 생성하는 동안 예외를 throw했습니다. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - 경고: MSTest V2 어댑터에서는 testsettings 파일 또는 vsmdi 파일이 지원되지 않습니다. - - - - TestContext Messages: - TestContext 메시지: - - - - Error calling Test Cleanup method for test class {0}: {1} - 테스트 클래스 {0}에 대한 테스트 정리 메서드를 호출하는 오류: {1} - - - - TestCleanup Stack Trace - TestCleanup 스택 추적 - - - - [MSTest][Discovery][{0}] {1} - [MSTest][검색][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - {0}에 대해 테스트 병렬 처리를 사용합니다(Workers: {1}, Scope: {2}). - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - 'Scope'에 대해 잘못된 값 '{0}'이(가) 지정되었습니다. 지원되는 범위는 {1}입니다. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - 'Workers'에 대해 잘못된 값 '{0}'이(가) 지정되었습니다. 이 값은 음수가 아닌 정수여야 합니다. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - 어셈블리 {0}에서 테스트를 검색하지 못했습니다. 이유:{1} - - - - Test '{0}' was canceled - 테스트 '{0}' 취소되었습니다. - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - 'ClassCleanupLifecycle'에 대해 '{0}' 잘못된 값이 지정되었습니다. 지원되는 범위는 {1}입니다. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - "{0}.{1}"에서 IDataSource 특성을 열거하는 동안 예외가 발생했습니다. {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - "{0}": ("{1}" 형식의 예외로 인해 예외 설명을 가져오지 못했습니다. - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - 예외 발생: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - {0} 형식에 대한 사용자 지정 특성을 가져오는 데 예외가 발생했습니다(무시하고 리플렉션 방법 사용). {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - 이전 버전 MSTestV2 패키지가 어셈블리에 로드되어 테스트 검색이 '.runsettings' 파일에 종속된 경우 모든 데이터 테스트를 검색하지 못할 수 있습니다. - - - - The called code threw an exception that was caught, but the exception value was null - 호출된 코드에서 확인된 예외가 발생했지만 예외 값이 null입니다. - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - "{0}.{1}"의 특성에서 IDataSource 행을 확장하는 동안 예외가 발생했습니다. {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - {0} 및 {1} 인덱스의 "{2}" 표시 이름이 중복됩니다. 표시 이름은 고유해야 합니다. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - "{1}"에 대한 {0} 인덱스의 데이터를 직렬화할 수 없습니다. "IDataSource"를 통해 제공된 모든 데이터를 직렬화할 수 있어야 합니다. 직렬화할 수 없는 데이터 원본을 테스트해야 하는 경우 테스트 어셈블리에 "TestDataSourceDiscovery" 특성을 추가하고 검색 옵션을 "DuringExecution"으로 설정하세요. - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pl.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pl.xlf deleted file mode 100644 index e229b5db52..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pl.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - Metoda oczyszczania zestawu „{0}.{1}” przekroczyła limit czasu po {2}ms - - - - Assembly cleanup method '{0}.{1}' was canceled - Anulowano metodę oczyszczania zestawu „{0}.{1}” - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - Metoda inicjalizacji zestawu „{0}.{1}” przekroczyła limit czasu po {2}ms - - - - Assembly initialize method '{0}.{1}' was canceled - Anulowano metodę inicjowania zestawu „{0}.{1}” - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - Nie można uruchomić metody testowej „{0}.{1}”: dane testowe nie są zgodne z parametrami metody. Liczba lub typy są różne. -Testowanie oczekiwanych {2} parametrów z typami „{3}”, -ale liczba odebranych argumentów to {4} z typami „{5}”. - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - Nie można uruchomić metody testowej „{0}.{1}”: metoda ma parametry, ale nie definiuje żadnego źródła testu. Użyj źródła danych „[DataRow]”, „[DynamicData]” lub niestandardowego źródła danych „ITestDataSource”, aby dostarczyć dane testowe. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - Metoda oczyszczania klasy „{0}.{1}” przekroczyła limit czasu po {2}ms - - - - Class cleanup method '{0}.{1}' was canceled - Anulowano metodę oczyszczania klasy „{0}.{1}” - - - - Class initialize method '{0}.{1}' timed out after {2}ms - Metoda inicjalizacji klasy „{0}.{1}” przekroczyła limit czasu po {2}ms - - - - Class initialize method '{0}.{1}' was canceled - Anulowano metodę inicjowania klasy „{0}.{1}” - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - Wykryto zarówno pliki „.runsettings”, jak i „.testconfig.json”. Wybierz tylko jeden z tych plików konfiguracji testu. - - - - Test '{0}' timed out after {1}ms - Upłynął limit czasu '{0}' testu po {1}ms - - - - The type of the generic parameter '{0}' could not be inferred. - Nie można wywnioskować typu '{0}' parametru ogólnego. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - Ogólna metoda testowa '{0}' nie ma argumentów, więc nie można wywnioskować parametru ogólnego. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - Znaleziono dwa typy powodujące konflikt dla parametru ogólnego '{0}'. Typy powodujące konflikty są '{1}' i '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - Nieprawidłowa wartość „{0}” dla wpisu runsettings „{1}”. Ustawienie zostanie zignorowane. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - Wpis runsettings „<ExecutionApartmentState>STA</ExecutionApartmentState>” nie jest obsługiwany w systemach operacyjnych innych niż Windows. - - - - Running tests in any of the provided sources is not supported for the selected platform - Uruchamianie testów w żadnym z podanych źródeł nie jest obsługiwane dla wybranej platformy - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - Metoda oczyszczania testu „{0}.{1}” przekroczyła limit czasu po {2}ms - - - - Test cleanup method '{0}.{1}' was canceled - Anulowano metodę oczyszczania testu „{0}.{1}” - - - - Test initialize method '{0}.{1}' timed out after {2}ms - Metoda inicjalizacji testu „{0}.{1}” przekroczyła limit czasu po {2}ms - - - - Test initialize method '{0}.{1}' was canceled - Anulowano metodę inicjowania testu „{0}.{1}” - - - - TestCleanup method {0}.{1} threw exception. {2}. - Metoda TestCleanup {0}.{1} zgłosiła wyjątek {2}. - - - - --- End of inner exception stack trace --- - --- Koniec śledzenia stosu wyjątku wewnętrznego --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: W zestawie nie można zdefiniować więcej niż jednej metody z atrybutem AssemblyCleanup. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: W zestawie nie można zdefiniować więcej niż jednej metody z atrybutem AssemblyInitialize. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: W klasie nie można zdefiniować więcej niż jednej metody z atrybutem ClassCleanup. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: W klasie nie można zdefiniować więcej niż jednej metody z atrybutem ClassInitialize. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: Nie można zdefiniować więcej niż jednej metody z atrybutem TestCleanup. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: Nie można zdefiniować więcej niż jednej metody z atrybutem TestInitialize. - - - - TestClass attribute defined on generic non-abstract class {0} - Atrybut TestClass zdefiniowany w ogólnej klasie nieabstrakcyjnej {0} - - - - Initialization method {0}.{1} threw exception. {2}. - Metoda inicjowania {0}.{1} zgłosiła wyjątek. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - Nie można utworzyć wystąpienia klasy {0}. Błąd: {1}. - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - Metoda testowa "{0}.{1}” ma zdefiniowanych wiele atrybutów pochodzących z „{2}”. Dozwolony jest tylko jeden taki atrybut. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - Nie można odnaleźć prawidłowego konstruktora dla klasy testowej „{0}”. Prawidłowe konstruktory są „publiczne” i albo bez parametrów, albo z jednym parametrem typu „TestContext”. - - - - Unable to set TestContext property for the class {0}. Error: {1}. - Nie można ustawić właściwości TestContext w klasie {0}. Błąd: {1}. - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (Nie można pobrać komunikatu dotyczącego wyjątku typu {0} z powodu wyjątku). - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: Klasa {0}nie ma prawidłowej właściwości TestContext. Element TestContext musi być typu TestContext, musi być niestatyczny i musi być publiczny. Na przykład : public TestContext TestContext. - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: Atrybut TestClass zdefiniowany dla niepublicznej klasy {0} - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - Adapter MSTestAdapter nie mógł odnaleźć testów w klasie „{0}” zestawu „{1}”, przyczyna: {2}. - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - Nie można załadować typów ze źródła testów „{0}”. Niektóre lub wszystkie testy w tym źródle mogły nie zostać odnalezione. -Błąd: {1} - - - - File does not exist: {0} - Plik nie istnieje: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: metoda {1} zdefiniowana w klasie {0}nie ma poprawnej sygnatury. Metoda testowa oznaczona przez atrybut [TestMethod] musi być niestatyczna, publiczna, zwracać wartość typu void i nie powinna przyjmować żadnego parametru. Przykład: public void Test.Class1.Test(). Ponadto, jeśli używasz oczekiwanie asynchroniczne w metodzie testowej, wtedy zwracanym typem musi być „Task” lub „ValueTask”. Przykład: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - Wartość TestContext nie może być równa null. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - Metoda czyszczenia zestawu {0}.{1} nie powiodła się. Komunikat o błędzie: {2}. Ślad stosu: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - Metoda inicjująca zestaw {0}.{1} nie powiodła się. {2}: {3}. Przerywanie wykonywania testu. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - Metoda czyszczenia klasy {0}.{1} nie powiodła się. Komunikat o błędzie: {2}. Ślad stosu: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - Metoda inicjowania klasy {0}.{1} zgłosiła wyjątek. {2}: {3}. - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - Metoda Execute zgłosiła nieobsługiwany wyjątek. Zgłoś ten błąd autorowi atrybutu '{0}'. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - Błąd podczas wykonywania testu. Rozszerzenie nie zwróciło żadnego wyniku. W przypadku korzystania z rozszerzenia atrybutu TestMethodAttribute należy skontaktować się z dostawcą. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Metoda {0}.{1}ma nieprawidłową sygnaturę. Metoda musi być statyczna, publiczna, nie może zwracać wartości i nie powinna przyjmować żadnego parametru. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, wtedy zwracanym typem musi być typ „Task” lub „ValueTask”. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Metoda {0}.{1}ma nieprawidłową sygnaturę. Metoda musi być statyczna, publiczna, nie może zwracać wartości i powinna mieć jeden parametr typu TestContext. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, wtedy zwracanym typem musi być typ „Task” lub „ValueTask”. - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}.{1} ma nieprawidłowy atrybut Timeout. Limit czasu musi być liczbą całkowitą większą niż 0. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: Nie można zdefiniować wstępnie zdefiniowanej właściwości {2} dla metody {1}. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: Zerowa lub pusta niestandardowa właściwość została zdefiniowana dla metody {1}. Niestandardowa właściwość musi mieć prawidłową nazwę. - - - - Method {0}.{1} does not exist. - Metoda {0}.{1} nie istnieje. - - - - Unable to find property {0}.TestContext. Error:{1}. - Nie można znaleźć właściwości {0}.TestContext. Błąd:{1}. - - - - The {0}.TestContext has incorrect type. - Element {0}.TestContext ma niepoprawny typ. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Metoda {0}.{1}ma nieprawidłową sygnaturę. Metoda musi być niestatyczna, publiczna, nie może zwracać wartości i nie powinna przyjmować żadnego parametru. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, wtedy zwracanym typem musi być typ „Task” lub „ValueTask”. - - - - Unable to get type {0}. Error: {1}. - Nie można uzyskać typu {0}. Błąd: {1}. - - - - Test method {0} was not found. - Nie znaleziono metody testowej {0}. - - - - Debug Trace: - Ślad debugowania: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - Nie powiodło się uzyskanie wyjątku zgłoszonego przez metodę testową {0}.{1}. - - - - Test method {0}.{1} threw exception: -{2} - Metoda testowa {0}.{1} zgłosiła wyjątek: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0} Jeśli w projektach UWP korzystasz z obiektów interfejsu użytkownika podczas testowania, rozważ użycie atrybutu [UITestMethod] zamiast atrybutu [TestMethod], aby wykonywać test w wątku interfejsu użytkownika. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - Nieprawidłowe ustawienia „{0}”. Nieoczekiwany atrybut XmlAttribute: „{1}”. - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - Nieprawidłowe ustawienia „{0}”. Nieoczekiwany atrybut XmlElement: „{1}”. - - - - {0} (Data Row {1}) - {0} (wiersz danych {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - Atrybut ExpectedException zdefiniowany dla metody testowej {0}.{1} zgłosił wyjątek w trakcie konstruowania. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - Ostrzeżenie: Plik testsettings lub plik vsmdi nie jest obsługiwany przez adapter MSTest w wersji 2. - - - - TestContext Messages: - Komunikaty TestContext: - - - - Error calling Test Cleanup method for test class {0}: {1} - Błąd podczas wywoływania metody czyszczącej testu dla klasy testowej {0}: {1} - - - - TestCleanup Stack Trace - Ślad stosu dla TestCleanup - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Discovery][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - Przetwarzanie równoległe testów włączono dla {0} (procesy robocze: {1}, zakres: {2}) - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - Określono nieprawidłową wartość „{0}” dla właściwości „Scope”. Obsługiwane zakresy to {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - Określono nieprawidłową wartość „{0}” dla właściwości „Workers”. Wartość musi być nieujemną liczbą całkowitą. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - Nie można odnaleźć testów z zestawu {0}. Przyczyna:{1} - - - - Test '{0}' was canceled - Anulowano '{0}' testowe - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - Dla ustawienia „ClassCleanupLifecycle” określono nieprawidłową wartość „{0}”. Obsługiwane zakresy to {1}. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - Wystąpił wyjątek podczas wyliczania atrybutu IDataSource w przestrzeni nazwy „{0}.{1}”: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - „{0}”: (Nie można uzyskać opisu wyjątku z powodu wyjątku typu „{1}”. - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - Zgłoszone wyjątki: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - Pobieranie atrybutów niestandardowych dla typu {0} zgłosiło wyjątek (zignoruje i użyje sposobu odbicia): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - Starsza wersja pakietu MSTestV2 jest załadowana do zestawu. Odnajdywanie testów może nie odnaleźć wszystkich testów danych, jeśli zależą od pliku „.runsettings”. - - - - The called code threw an exception that was caught, but the exception value was null - Wywołany kod zgłosił wyjątek, który został przechwycony, ale wartość wyjątku miała wartość null - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - Wystąpił wyjątek podczas rozwijania wierszy IDataSource z atrybutu w przestrzeni nazw „{0}.{1}”: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - Nazwa wyświetlana „{2}” w indeksach {0} i {1} jest duplikatem. Nazwy wyświetlane powinny być unikatowe. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - Nie można serializować danych w indeksie {0} dla „{1}”. Wszystkie dane dostarczane za pomocą źródła „IDataSource” powinny być możliwe do serializacji. Jeśli chcesz przetestować nieserializowalne źródła danych, upewnij się, że dodasz atrybut „ TestDataSourceDiscovery” w zestawie testowym i ustaw opcję odnajdywania na wartość „DuringExecution”. - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pt-BR.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pt-BR.xlf deleted file mode 100644 index fbd82fe886..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pt-BR.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - O método de limpeza da montagem '{0}.{1}' atingiu o tempo limite após {2}ms - - - - Assembly cleanup method '{0}.{1}' was canceled - O método de limpeza do assembly "{0}.{1}" foi cancelado - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - O método de inicialização da montagem '{0}.{1}' atingiu o tempo limite após {2}ms - - - - Assembly initialize method '{0}.{1}' was canceled - O método de inicialização do assembly "{0}.{1}" foi cancelado - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - Não é possível executar o método de teste '{0}.{1}': Os dados de teste não correspondem aos parâmetros do método. A contagem ou os tipos são diferentes. -Testar {2} parâmetros esperados, com tipos '{3}', -mas {4} argumentos recebidos, com tipos '{5}'. - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - Não é possível executar o método de teste '{0}.{1}': o método tem parâmetros, mas não define nenhuma fonte de teste. Use '[DataRow]', '[DynamicData]' ou uma fonte de dados 'ITestDataSource' personalizada para fornecer dados de teste. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - O método de limpeza da classe '{0}.{1}' atingiu o tempo limite após {2}ms - - - - Class cleanup method '{0}.{1}' was canceled - O método de limpeza de classe "{0}.{1}" foi cancelado - - - - Class initialize method '{0}.{1}' timed out after {2}ms - O método de inicialização da classe '{0}.{1}' atingiu o tempo limite após {2}ms - - - - Class initialize method '{0}.{1}' was canceled - O método de inicialização de classe "{0}.{1}" foi cancelado - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - Ambos os arquivos '.runsettings' e '.testconfig.json' foram detectados. Selecione apenas um desses arquivos de configuração de teste. - - - - Test '{0}' timed out after {1}ms - Tempo '{0}' tempo limite do teste após {1}ms - - - - The type of the generic parameter '{0}' could not be inferred. - Não foi possível inferir o tipo '{0}' parâmetro genérico. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - O método de teste genérico '{0}' não tem argumentos, portanto, o parâmetro genérico não pode ser inferido. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - Foram encontrados dois tipos conflitativos para parâmetro genérico '{0}'. Os tipos conflitativos são '{1}' e '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - Valor inválido "{0}" para a entrada runsettings "{1}", a configuração será ignorada. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - Não há suporte para a entrada runsettings "<ExecutionApartmentState>STA</ExecutionApartmentState>" em sistemas operacionais que não sejam Windows. - - - - Running tests in any of the provided sources is not supported for the selected platform - Não há suporte para execução de teste em qualquer uma das origens fontes fornecidas para a plataforma selecionada - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - O método de limpeza do teste '{0}.{1}' atingiu o tempo limite após {2}ms - - - - Test cleanup method '{0}.{1}' was canceled - O método de limpeza de teste "{0}.{1}" foi cancelado - - - - Test initialize method '{0}.{1}' timed out after {2}ms - O método de inicialização do teste '{0}.{1}' atingiu o tempo limite após {2}ms - - - - Test initialize method '{0}.{1}' was canceled - O método de inicialização de teste "{0}.{1}" foi cancelado - - - - TestCleanup method {0}.{1} threw exception. {2}. - O método TestCleanup {0}.{1} gerou a exceção. {2}. - - - - --- End of inner exception stack trace --- - --- Fim do rastreamento de pilha de exceção interna --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: não é possível definir mais de um método com o atributo AssemblyCleanup em um assembly. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: não é possível definir mais de um método com o atributo AssemblyInitialize dentro de um assembly. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: não é possível definir mais de um método com o atributo ClassCleanup dentro de uma classe. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: não é possível definir mais de um método com o atributo ClassInitialize em uma classe. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: não é possível definir mais de um método com o atributo TestCleanup. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: não é possível definir mais de um método com o atributo TestInitialize. - - - - TestClass attribute defined on generic non-abstract class {0} - Atributo TestClass definido em uma classe genérica não abstrata {0} - - - - Initialization method {0}.{1} threw exception. {2}. - O método de inicialização {0}.{1} gerou exceção. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - Não é possível criar instância da classe {0}. Erro: {1}. - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - O método de teste '{0}.{1}' tem várias características derivadas de '{2}' definidas nele. Apenas uma dessas características tem permissão. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - Não é possível localizar um construtor válido para a classe de teste '{0}'. Construtores válidos são 'public' e sem parâmetros ou com um parâmetro do tipo 'TestContext'. - - - - Unable to set TestContext property for the class {0}. Error: {1}. - Não é definir a propriedade TestContext para a classe {0}. Erro: {1}. - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (Falha ao obter a mensagem para uma exceção do tipo {0} devido a uma exceção.) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: a classe {0} não tem uma propriedade TestContext válida. TestContext deve ser do tipo TestContext, não deve ser estático e deve ser público. Por exemplo: public TestContext TestContext. - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: atributo TestClass definido em classe não pública {0} - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - O MSTestAdapter não conseguiu descobrir testes na classe '{0}' do assembly '{1}' devido a {2}. - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - Não é possível carregar tipos da fonte de teste '{0}'. Alguns ou todos os testes nessa fonte podem não ser descobertos. -Erro: {1} - - - - File does not exist: {0} - O arquivo não existe: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: o método {1} definido na classe {0} não tem a assinatura correta. O método de teste marcado com o atributo [TestMethod] deve ser não estático, público, com tipo de retorno nulo e não deve receber parâmetros. Exemplo: Test.Class1.Test() público nulo. Além disso, se você estiver usando async-await no método de teste, return-type deverá ser "Task" ou "ValueTask". Exemplo: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext não pode ser Nulo. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - Falha no método de Limpeza de Assembly {0}.{1}. Mensagem de Erro: {2}. StackTrace: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - O método de Inicialização de Assembly {0}.{1} lançou uma exceção. {2}: {3}. Anulando execução de teste. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - Falha no método de Limpeza de Classe {0}.{1}. Mensagem de Erro: {2}. Rastreamento de Pilha: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - O método de Inicialização de Classe {0}.{1} lançou uma exceção. {2}: {3}. - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - Uma exceção sem tratamento foi lançada pelo método 'Execute'. Relate este erro ao autor do atributo '{0}'. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - Erro ao executar o teste. Nenhum resultado retornado pela extensão. Se usar a extensão de TestMethodAttribute, entre em contato com o fornecedor. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - O método {0}.{1} tem a assinatura incorreta. O método deve ser estático, público, não deve retornar um valor nem receber parâmetro. Além disso, se você estiver usando async-await no método, o return-type deverá ser "Task" ou "ValueTask". - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - O método {0}.{1} tem a assinatura incorreta. O método deve ser estático, público, não retornar um valor e deve usar um único parâmetro do tipo TestContext. Além disso, se você estiver usando async-await no método, o return-type deverá ser "Task" ou "ValueTask". - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}.{1} tem atributo Timeout inválido. O tempo limite deve ser um valor inteiro maior que 0. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: não é possível definir a propriedade predefinida {2} no método {1}. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: Propriedade personalizada nula ou vazia definida no método {1}. A propriedade personalizada deve ter um nome válido. - - - - Method {0}.{1} does not exist. - O método {0}.{1} não existe. - - - - Unable to find property {0}.TestContext. Error:{1}. - Não é possível encontrar propriedade {0}.TestContext. Erro:{1}. - - - - The {0}.TestContext has incorrect type. - O {0}.TestContext é do tipo incorreto. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - O método {0}.{1} tem a assinatura incorreta. O método deve ser não estático, público, não deve retornar um valor e não deve receber nenhum parâmetro. Além disso, se você estiver usando async-await no método, o return-type deverá ser "Task" ou "ValueTask". - - - - Unable to get type {0}. Error: {1}. - Não é possível obter o tipo {0}. Erro: {1}. - - - - Test method {0} was not found. - O método de teste {0} não foi encontrado. - - - - Debug Trace: - Rastreamento de Depuração: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - Falha ao obter a exceção lançada pelo método de teste {0}.{1}. - - - - Test method {0}.{1} threw exception: -{2} - O método de teste {0}.{1} lançou a exceção: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0} Para projetos UWP, se você está usando objetos de IU no teste, considere usar o atributo [UITestMethod] em vez de [TestMethod] para executar o teste no thread da IU. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - Configurações inválidas '{0}'. XmlAttribute inesperado: '{1}'. - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - Configurações inválidas '{0}'. XmlElement inesperado: '{1}'. - - - - {0} (Data Row {1}) - {0} (Linha de Dados {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - O atributo ExpectedException definido no método de teste {0}.{1} emitiu uma exceção durante a construção. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - Aviso: um arquivo testsettings ou um arquivo vsmdi não tem suporte no MSTest V2 Adapter. - - - - TestContext Messages: - Mensagens TestContext: - - - - Error calling Test Cleanup method for test class {0}: {1} - Erro ao chamar o método Test Cleanup para a classe de teste {0}: {1} - - - - TestCleanup Stack Trace - Rastreamento de pilha TestCleanup - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Descoberta][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - Paralelização de Teste habilitada para {0} (Trabalhos: {1}, Escopo: {2}) - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - Valor inválido '{0}' especificado para 'Scope'. Os escopos compatíveis são {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - Valor inválido '{0}' especificado para 'Workers'. O valor deve ser um inteiro não negativo. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - Falha ao descobrir testes por meio do assembly {0}. Motivo: {1} - - - - Test '{0}' was canceled - O '{0}' teste foi cancelado - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - Valor inválido '{0}' especificado para 'ClassCleanupLifecycle'. Os escopos suportados são {1}. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - Ocorreu uma exceção ao enumerar o atributo IDataSource em "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - "{0}": (Falha ao obter a descrição da exceção devido a uma exceção do tipo "{1}". - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - Exceções lançadas: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - A obtenção de atributos personalizados para o tipo {0} gerou uma exceção (irá ignorar e usar o modo de reflexão): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - Uma versão mais antiga do pacote MSTestV2 é carregada no assembly, a descoberta de teste pode falhar ao descobrir todos os testes de dados se eles dependerem do arquivo `.runsettings`. - - - - The called code threw an exception that was caught, but the exception value was null - O código chamado lançou uma exceção que foi capturada, mas o valor da exceção era nulo - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - Ocorreu uma exceção ao expandir as linhas IDataSource do atributo em "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - O nome de exibição "{2}" nos índices {0} e {1} são duplicados. Os nomes de exibição devem ser exclusivos. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - Os dados no índice {0} para "{1}" não podem ser serializados. Todos os dados fornecidos por meio de "IDataSource" devem ser serializáveis. Se você precisar testar fontes de dados não serializáveis, certifique-se de adicionar o atributo "TestDataSourceDiscovery" em seu assembly de teste e defina a opção de descoberta como "DuringExecution". - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ru.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ru.xlf deleted file mode 100644 index 058011a770..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ru.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - Время ожидания метода очистки сборки "{0}.{1}" истекло через {2} мс - - - - Assembly cleanup method '{0}.{1}' was canceled - Метод очистки сборки "{0}.{1}" отменен - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - Время ожидания метода инициализации сборки "{0}.{1}" истекло через {2} мс - - - - Assembly initialize method '{0}.{1}' was canceled - Метод инициализации сборки "{0}.{1}" отменен - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - Не удается запустить метод теста "{0}.{1}": тестовые данные не соответствуют параметрам метода. Количество или типы отличаются. -Число ожидаемых для теста параметров: {2} с типами "{3}", -но число полученных аргументов: {4} с типами "{5}". - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - Не удается запустить метод теста "{0}.{1}": метод имеет параметры, но не определяет источник теста. Используйте "[DataRow]", "[DynamicData]" или настраиваемый источник данных "ITestDataSource" для предоставления тестовых данных. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - Время ожидания метода очистки класса "{0}.{1}" истекло через {2} мс - - - - Class cleanup method '{0}.{1}' was canceled - Метод очистки класса "{0}.{1}" отменен - - - - Class initialize method '{0}.{1}' timed out after {2}ms - Время ожидания метода инициализации класса "{0}.{1}" истекло через {2} мс - - - - Class initialize method '{0}.{1}' was canceled - Метод инициализации класса "{0}.{1}" отменен - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - Обнаружены файлы ".runsettings" и ".testconfig.json". Выберите только один из этих файлов тестовой конфигурации. - - - - Test '{0}' timed out after {1}ms - Время ожидания '{0}' истекло через {1}мс - - - - The type of the generic parameter '{0}' could not be inferred. - Не удалось определить тип универсального '{0}' параметра. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - Универсальный метод '{0}' не имеет аргументов, поэтому невозможно вывести универсальный параметр. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - Обнаружены два конфликтующих типа для универсального параметра '{0}'. Конфликтуют типы '{1}' и '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - Недопустимое значение "{0}" для записи runsettings "{1}", параметр будет пропущен. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - Запись Runsettings "<ExecutionApartmentState>STA</ExecutionApartmentState>" не поддерживается в ОС, отличных от Windows. - - - - Running tests in any of the provided sources is not supported for the selected platform - Запуск тестов в любом из предоставленных источников не поддерживается на выбранной платформе - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - Время ожидания метода очистки теста "{0}.{1}" истекло через {2} мс - - - - Test cleanup method '{0}.{1}' was canceled - Метод очистки теста "{0}.{1}" отменен - - - - Test initialize method '{0}.{1}' timed out after {2}ms - Время ожидания метода инициализации теста "{0}.{1}" истекло через {2} мс - - - - Test initialize method '{0}.{1}' was canceled - Метод инициализации теста "{0}.{1}" отменен - - - - TestCleanup method {0}.{1} threw exception. {2}. - Метод TestCleanup {0}.{1} создал исключение. {2}. - - - - --- End of inner exception stack trace --- - --- Конец трассировки стека внутренних исключений --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: в сборке невозможно определить несколько методов с атрибутом AssemblyCleanup. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: в сборке невозможно определить несколько методов с атрибутом AssemblyInitialize. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: в классе невозможно определить несколько методов с атрибутом ClassCleanup. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: в классе невозможно определить несколько методов с атрибутом ClassInitialize. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: невозможно определить несколько методов с атрибутом TestCleanup. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: невозможно определить несколько методов с атрибутом TestInitialize. - - - - TestClass attribute defined on generic non-abstract class {0} - Атрибут TestClass, определенный в универсальном не абстрактном классе {0} - - - - Initialization method {0}.{1} threw exception. {2}. - Метод инициализации {0}.{1} вызвал исключение. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - Не удалось создать экземпляр класса {0}. Ошибка: {1}. - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - У метода тестирования "{0}.{1}" есть несколько атрибутов, производных от заданного в нем "{2}". Допускается только один такой атрибут. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - Не удается найти допустимый конструктор для тестового класса "{0}". Допустимые конструкторы : "public" и конструкторы без параметров или с одним параметром типа "TestContext". - - - - Unable to set TestContext property for the class {0}. Error: {1}. - Не удалось задать свойство TestContext для класса {0}. Ошибка: {1}. - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (Не удалось получить сообщение для исключения с типом {0} в связи с возникновением исключения.) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: в классе {0} отсутствует допустимое свойство TestContext. Свойство TestContext должно относиться к типу TestContext, быть нестатическим и открытым. Например: public TestContext TestContext. - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: атрибут TestClass определен в классе {0}, не являющемся открытым - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - Средству MSTestAdapter не удалось обнаружить тесты в классе "{0}" сборки "{1}", так как {2}. - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - Не удалось загрузить типы из тестового источника "{0}". В этом источнике могут быть не обнаружены некоторые или все тесты. -Ошибка: {1} - - - - File does not exist: {0} - Файл не существует: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: метод {1}, определенный в классе {0}, имеет неправильную сигнатуру. Метод теста, помеченный атрибутом [TestMethod], должен быть нестатическим, открытым и иметь тип возвращаемого значения void; он также не должен принимать параметры. Пример: public void Test.Class1.Test(). Кроме того, при использовании async-await в методе теста возвращаемое значение должно иметь тип "Task" или "ValueTask". Пример: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext не может иметь значение NULL. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - Не удалось применить метод очистки сборки {0}.{1}. Сообщение об ошибке: {2}. Трассировка стека (StackTrace): {3}. - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - Методом инициализации сборки {0}.{1} создано исключение. {2}: {3}. Выполнение теста прекращается. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - Не удалось применить метод очистки класса {0}.{1}. Сообщение об ошибке: {2}. Трассировка стека: {3}. - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - Методом инициализации класса {0}.{1} создано исключение. {2}: {3}. - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - Необработанное исключение вызвано методом Execute. Сообщить об этой ошибке автору атрибута '{0}'. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - Ошибка при выполнении теста. Расширение не возвратило результаты. Если используется расширение атрибута TestMethodAttribute, обратитесь к поставщику. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть статическим и открытым, не должен возвращать значение и принимать параметры. Кроме того, при использовании async-await в методе возвращаемое значение должно иметь тип "Task" или "ValueTask". - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть статическим и открытым, не должен возвращать значение и должен принимать один параметр, имеющий тип TestContext. Кроме того, при использовании async-await в методе возвращаемое значение должно иметь тип "Task" или "ValueTask". - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}. {1} имеет недопустимый атрибут времени ожидания. Значение времени ожидания должно быть положительным целым числом. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: не удается определить предопределенное свойство {2} в методе {1}. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: в методе {1} определено пользовательское свойство, имя которого имеет значение NULL или пусто. Пользовательское свойство должно иметь допустимое имя. - - - - Method {0}.{1} does not exist. - Метод {0}.{1} не существует. - - - - Unable to find property {0}.TestContext. Error:{1}. - Не удается найти свойство {0}.TestContext. Ошибка: {1}. - - - - The {0}.TestContext has incorrect type. - Для свойства {0}.TestContext указан неправильный тип. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть нестатическим и открытым, не должен возвращать значение и принимать параметры. Кроме того, при использовании async-await в методе возвращаемое значение должно иметь тип "Task" или "ValueTask". - - - - Unable to get type {0}. Error: {1}. - Не удается получить тип {0}. Ошибка: {1}. - - - - Test method {0} was not found. - Метод теста {0} не найден. - - - - Debug Trace: - Трассировка отладки: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - Не удалось получить исключение, созданное методом теста {0}.{1}. - - - - Test method {0}.{1} threw exception: -{2} - Метод теста {0}.{1} создал исключение: -{2}. - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0} В проектах UWP, если в тесте используются объекты пользовательского интерфейса, рассмотрите возможность использования атрибута [UITestMethod] вместо атрибута [TestMethod] для выполнения теста в потоке пользовательского интерфейса. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - Недопустимые параметры "{0}". Непредвиденный атрибут XmlAttribute: "{1}". - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - Недопустимые параметры "{0}". Непредвиденный элемент XmlElement: "{1}". - - - - {0} (Data Row {1}) - {0} (строка данных {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - Атрибут ExpectedException, определенный в методе теста {0}.{1}, породил исключение во время создания. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - Внимание! Адаптер MSTest версии 2 не поддерживает файл TESTSETTINGS или VSMDI. - - - - TestContext Messages: - Сообщения TestContext: - - - - Error calling Test Cleanup method for test class {0}: {1} - Ошибка при вызове метода TestCleanup для тестового класса {0}: {1} - - - - TestCleanup Stack Trace - Трассировка стека TestCleanup - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Discovery][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - Включена параллелизация тестов для {0} (рабочие роли: {1}, область: {2}) - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - В поле "Область" указано недопустимое значение "{0}". Поддерживаемые области: {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - В поле "Рабочие роли" указано недопустимое значение "{0}". Оно должно быть неотрицательным целым числом. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - Не удалось обнаружить тесты из сборки {0}. Причина:{1} - - - - Test '{0}' was canceled - Проверка '{0}' отменена - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - Для параметра "ClassCleanupLifecycle" указано недопустимое значение "{0}". Поддерживаемые области: {1}. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - Возникло исключение при перечислении атрибута IDataSource в "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - "{0}": (Не удалось получить описание исключения из-за исключения типа "{1}". - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - Выданные исключения: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - При получении настраиваемых атрибутов для типа {0} возникло исключение (оно будет проигнорировано и будет использовано отражение): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - В сборку загружена старая версия пакета MSTestV2. При обнаружении тестов могут быть обнаружены не все тесты данных, если они зависят от файла ".runsettings". - - - - The called code threw an exception that was caught, but the exception value was null - Вызванный код вызвал исключение, которое было перехвачено, но значение исключения было равно NULL - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - Возникло исключение при развертывании строк IDataSource из атрибута "{0}.{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - Отображаемые имена "{2}" в индексах {0} и {1} дублируются. Отображаемые имена должны быть уникальными. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - Не удается сериализовать данные в индексе {0} для "{1}". Все данные, предоставленные через IDataSource, должны быть сериализуемыми. Если необходимо протестировать несериализуемые источники данных, добавьте атрибут "TestDataSourceDiscovery" в тестовую сборку и установите для параметра обнаружения значение "DuringExecution". - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.tr.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.tr.xlf deleted file mode 100644 index 5713804864..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.tr.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - '{0}.{1}' derleme temizleme yöntemi {2}ms sonra zaman aşımına uğradı - - - - Assembly cleanup method '{0}.{1}' was canceled - '{0}.{1}' bütünleştirilmiş kod temizleme yöntemi iptal edildi - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - '{0}.{1}' derleme başlatma yöntemi {2}ms sonra zaman aşımına uğradı - - - - Assembly initialize method '{0}.{1}' was canceled - '{0}.{1}' derleme başlatma yöntemi iptal edildi - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - '{0}.{1}' test yöntemi çalıştırılamıyor: Test verileri yöntem parametreleriyle eşleşmiyor. Ya sayı ya da türler farklıdır. -Test '{3}' türüyle {2} parametre bekledi, -ancak, '{5}' türüyle {4} argüman aldı. - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - '{0}.{1}' test yöntemi çalıştırılamıyor: Yöntemin parametreleri var ancak herhangi bir test kaynağı tanımlamıyor. Test verilerini sağlamak için '[DataRow]', '[DynamicData]' veya özel bir 'ITestDataSource' veri kaynağı kullanın. - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - '{0}.{1}' sınıf temizleme yöntemi {2}ms sonra zaman aşımına uğradı - - - - Class cleanup method '{0}.{1}' was canceled - '{0}.{1}' sınıf temizleme yöntemi iptal edildi - - - - Class initialize method '{0}.{1}' timed out after {2}ms - '{0}.{1}' sınıf başlatma yöntemi {2}ms sonra zaman aşımına uğradı - - - - Class initialize method '{0}.{1}' was canceled - '{0}.{1}' sınıf başlatma yöntemi iptal edildi - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - Hem '.runsettings' hem de '.testconfig.json' dosyaları algılandı. Lütfen bu test yapılandırma dosyalarından yalnızca birini seçin. - - - - Test '{0}' timed out after {1}ms - Test '{0}' ms sonra zaman aşımına {1}oldu - - - - The type of the generic parameter '{0}' could not be inferred. - Genel parametre türü '{0}' çıkarsanamadı. - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - Genel test '{0}' bağımsız değişkene sahip olmadığından genel parametre çıkarsanamıyor. - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - Genel parametre türü için iki çakışan tür '{0}'. Çakışan türler '{1}' '{2}'. - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - '{1}' çalıştırma ayarları girişi için '{0}' değeri geçersiz, ayar yoksayılacak. - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - '<ExecutionApartmentState>STA</ExecutionApartmentState>' çalışma ayarları girişi Windows dışı işletim sistemlerinde desteklenmiyor. - - - - Running tests in any of the provided sources is not supported for the selected platform - Testlerin sağlanan kaynakların herhangi birinde çalıştırılması seçili platformda desteklenmiyor - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - '{0}.{1}' test temizleme yöntemi {2}ms sonra zaman aşımına uğradı - - - - Test cleanup method '{0}.{1}' was canceled - '{0}.{1}' test temizleme yöntemi iptal edildi - - - - Test initialize method '{0}.{1}' timed out after {2}ms - '{0}.{1}' test başlatma yöntemi {2}ms sonra zaman aşımına uğradı - - - - Test initialize method '{0}.{1}' was canceled - '{0}.{1}' test başlatma yöntemi iptal edildi - - - - TestCleanup method {0}.{1} threw exception. {2}. - TestCleanup metodu {0}.{1} özel durum oluşturdu. {2}. - - - - --- End of inner exception stack trace --- - --- İç özel durum yığın izlemesinin sonu --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: Bir bütünleştirilmiş kod içinde AssemblyCleanup özniteliği ile birden fazla metot tanımlanamaz. - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: Bir bütünleştirilmiş kod içinde AssemblyInitialize özniteliği ile birden fazla metot tanımlanamaz. - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: Bir sınıf içinde ClassCleanup özniteliği ile birden fazla metot tanımlanamaz. - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: Bir sınıf içinde ClassInitialize özniteliği ile birden fazla metot tanımlanamaz. - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: TestCleanup özniteliği ile birden fazla metot tanımlanamaz. - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: TestInitialize özniteliği ile birden fazla metot tanımlanamaz. - - - - TestClass attribute defined on generic non-abstract class {0} - {0} genel soyut olmayan sınıf üzerinde tanımlanan TestClass özniteliği - - - - Initialization method {0}.{1} threw exception. {2}. - Başlatma metodu {0}.{1} özel durum oluşturdu. {2}. - - - - Unable to create instance of class {0}. Error: {1}. - {0} sınıfının örneği oluşturulamıyor. Hata: {1}. - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - “{0}.{1}” test yöntemi, üzerinde tanımlanan “{2}” öğesinden türetilmiş birden fazla öznitelik içeriyor. Bu türde yalnızca bir tane özniteliğe izin verilir. - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - '{0}' test sınıfı için geçerli bir oluşturucu bulunamıyor. Geçerli oluşturucular 'public' ve parametresiz veya 'TestContext' türünde tek bir parametre içeriyor. - - - - Unable to set TestContext property for the class {0}. Error: {1}. - {0} sınıfı için TestContext özelliği ayarlanamıyor. Hata: {1}. - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (Bir özel durum nedeniyle, {0} türündeki özel durum iletisi alınamadı.) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: {0}sınıfı geçerli bir TestContext özelliğine sahip değil. TestContext, TestContext türünde olmalı, static olmamalı ve public olmalıdır. Örnek: public TestContext TestContext. - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: TestClass özniteliği genel olmayan {0} sınıfında tanımlanmış - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - MSTestAdapter, '{1}' bütünleştirilmiş kodunun '{0}' sınıfındaki testleri bulamadı. Nedeni: {2}. - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - '{0}' test kaynağından türler yüklenemiyor. Kaynaktaki testlerin bazıları veya tümü bulunamayabilir. -Hata: {1} - - - - File does not exist: {0} - Dosya yok: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: {0} sınıfında tanımlanan {1} yönteminin imzası doğru değil. [TestMethod] özniteliğiyle işaretlenmiş test yöntemi statik olmayan, genel, dönüş türü void olan bir yöntem olmalıdır ve hiçbir parametre almamalıdır. Örnek: public void Test.Class1.Test(). Bunlara ek olarak, test metodunda async-await kullanıyorsanız return-type değeri 'Task' veya 'ValueTask' olmalıdır. Örnek: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext, Null olamaz. - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - Bütünleştirilmiş Kod Temizleme metodu ({0}.{1}) başarısız oldu. Hata İletisi: {2}. StackTrace: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - Bütünleştirilmiş Kod Başlatma metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}. Test yürütmesi durduruluyor. - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - Sınıf Temizleme metodu ({0}.{1}) başarısız oldu. Hata İletisi: {2}. Yığın İzlemesi: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - Sınıf Başlatma metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}. - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - 'Execute' metodu tarafından işlenmeyen bir özel durum oluşturuldu. Lütfen bu hatayı özniteliğin yazarına '{0}'. -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - Test yürütülürken hata oluştu. Uzantı tarafından hiç sonuç döndürülmedi. TestMethodAttribute uzantısı kullanılıyorsa, lütfen satıcıya başvurun. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - {0}.{1} yönteminin imzası yanlış. Yöntem statik, genel, değer döndürmeyen bir yöntem olmalı, hiçbir parametre almamalıdır. Bunlara ek olarak, yöntemde async-await kullanıyorsanız return-type değeri 'Task' veya 'ValueTask' olmalıdır. - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - {0}.{1} yönteminin imzası yanlış. Yöntem statik, genel, değer döndürmeyen bir yöntem olmalı ve TestContext türünde tek bir parametre almalıdır. Bunlara ek olarak, yöntemde async-await kullanıyorsanız return-type değeri 'Task' veya 'ValueTask' olmalıdır. - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}.{1} Timeout özniteliği geçersiz. Zaman aşımı değeri 0'dan büyük bir tamsayı olmalıdır. - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: Önceden tanımlanmış {2} özelliği {1} metodunda tanımlanamaz. - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: {1} metodunda null veya boş özel özellik tanımlanmış. Özel özellik geçerli bir ada sahip olmalıdır. - - - - Method {0}.{1} does not exist. - {0}.{1} metodu yok. - - - - Unable to find property {0}.TestContext. Error:{1}. - {0}.TestContext özelliği bulunamıyor. Hata:{1}. - - - - The {0}.TestContext has incorrect type. - {0}.TestContext yanlış türe sahip. - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - {0}.{1} yönteminin imzası yanlış. Yöntem statik olmayan, genel, değer döndürmeyen bir yöntem olmalı, hiçbir parametre almamalıdır. Bunlara ek olarak, yöntemde async-await kullanıyorsanız return-type değeri 'Task' veya 'ValueTask' olmalıdır. - - - - Unable to get type {0}. Error: {1}. - {0} türü alınamıyor. Hata: {1}. - - - - Test method {0} was not found. - {0} test metodu bulunamadı. - - - - Debug Trace: - Hata Ayıklama İzleyici: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - {0}.{1} metodu tarafından oluşturulan özel durum alınamadı. - - - - Test method {0}.{1} threw exception: -{2} - {0}.{1} test metodu özel durum oluşturdu: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0} UWP projeleri için testte UI nesneleri kullanıyorsanız, testi UI iş parçacığında yürütmek için [TestMethod] yerine [UITestMethod] özniteliğini kullanabilirsiniz. - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - Geçersiz '{0}' ayarları. Beklenmeyen XmlAttribute: '{1}'. - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - Geçersiz '{0}' ayarları. Beklenmeyen XmlElement: '{1}'. - - - - {0} (Data Row {1}) - {0} (Veri Satırı {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - {0}.{1} test yöntemi üzerinde tanımlanan ExpectedException özniteliği, oluşturma sırasında bir özel durum oluşturdu. -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - Uyarı : MSTest V2 Adapter ile bir testsettings dosyası veya bir vsmdi dosyası desteklenmez. - - - - TestContext Messages: - TestContext İletileri: - - - - Error calling Test Cleanup method for test class {0}: {1} - {0} test sınıfı için Test Temizleme metodu çağrılırken hata oluştu: {1} - - - - TestCleanup Stack Trace - TestCleanup Yığın İzleme - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Discovery][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - {0} için Test Paralelleştirme etkin (Çalışanlar: {1}, Kapsam: {2}). - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - 'Scope' için geçersiz '{0}' değeri belirtildi. Desteklenen kapsamlar {1}. - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - 'Workers' için geçersiz '{0}' değeri belirtildi. Değer negatif olmayan bir tamsayı olmalıdır. - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - {0} bütünleştirilmiş kodundan testler bulunamadı. Neden:{1} - - - - Test '{0}' was canceled - Test '{0}' iptal edildi - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - 'ClassCleanupLifecycle' için geçersiz '{0}' değeri belirtildi. Desteklenen kapsamlar {1}'dir. - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - "{0}.{1} " üzerinde IDataSource özniteliği numaralandırılırken özel durum oluştu: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - "{0}": ("{1}" türündeki bir istisna nedeniyle özel durum açıklaması alınamadı. - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - Oluşturulan özel durumlar: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - {0} tipi için özel niteliklerin alınması özel durum oluşturdu (yok sayar ve yansıma yolunu kullanır): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - Montaja MSTestV2 paketinin daha eski bir sürümü yüklenir, test keşfi, `.runsettings` dosyasına bağlılarsa tüm veri testlerini keşfetmede başarısız olabilir. - - - - The called code threw an exception that was caught, but the exception value was null - Çağrılan kod, yakalanan bir özel durum yarattı, ancak özel durum değeri boştu - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - "{0}. {1}" üzerindeki öznitelikten IDataSource satırları genişletilirken özel durum oluştu: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - {0} ve {1}dizinlerinde görünen ad " {2}" yineleniyor. Görünen adlar benzersiz olmalıdır. - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - "{1}" için {0} indeksindeki veriler serileştirilemez. "IDataSource" aracılığıyla sağlanan tüm veriler serileştirilebilir olmalıdır. Serileştirilemeyen veri kaynaklarını test etmeniz gerekiyorsa, lütfen test derlemenize "TestDataSourceDiscovery" özniteliğini eklediğinizden ve keşif seçeneğini "DuringExecution" olarak ayarladığınızdan emin olun. - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hans.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hans.xlf deleted file mode 100644 index 0e0b87553b..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hans.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - 程序集清理方法“{0}.{1}”在 {2} ms 后超时 - - - - Assembly cleanup method '{0}.{1}' was canceled - 已取消程序集清理方法“{0}.{1}” - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - 程序集初始化方法“{0}.{1}”在 {2} ms 后超时 - - - - Assembly initialize method '{0}.{1}' was canceled - 已取消程序集初始化方法“{0}.{1}” - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - 无法运行测试方法“{0}.{1}”: 测试数据与方法参数不匹配。计数或类型不同。 -测试需要类型为“{3}”的 {2} 参数, -但收到了类型为“{5}”的 {4} 参数。 - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - 无法运行测试方法“{0}.{1}”: 方法具有参数,但未定义任何测试源。使用 “[DataRow]”、“[DynamicData]” 或自定义 “ITestDataSource” 数据源提供测试数据。 - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - 类清理方法“{0}.{1}”在 {2} ms 后超时 - - - - Class cleanup method '{0}.{1}' was canceled - 已取消类清理方法“{0}.{1}” - - - - Class initialize method '{0}.{1}' timed out after {2}ms - 类初始化方法“{0}.{1}”在 {2} ms 后超时 - - - - Class initialize method '{0}.{1}' was canceled - 已取消类初始化方法“{0}.{1}” - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - 检测到 ".runsettings" 和 ".testconfig.json" 文件。请仅选择其中一个测试配置文件。 - - - - Test '{0}' timed out after {1}ms - 测试 '{0}' 在 {1}毫秒后超时 - - - - The type of the generic parameter '{0}' could not be inferred. - 无法推断 '{0}' 泛型参数的类型。 - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - 泛型测试方法 '{0}' 没有参数,因此无法推断泛型参数。 - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - 发现泛型参数 '{0}' 的两个冲突类型。冲突类型 '{1}' 和 '{2}'。 - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - runsettings 项“{0}”的值“{1}”无效,将忽略设置。 - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - 非 Windows 操作系统不支持 Runsettings 条目 "<ExecutionApartmentState>STA</ExecutionApartmentState>"。 - - - - Running tests in any of the provided sources is not supported for the selected platform - 选定的平台不支持在任何提供的源中运行测试 - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - 测试清理方法“{0}.{1}”在 {2} ms 后超时 - - - - Test cleanup method '{0}.{1}' was canceled - 已取消测试清理方法“{0}.{1}” - - - - Test initialize method '{0}.{1}' timed out after {2}ms - 测试初始化方法“{0}.{1}”在 {2} ms 后超时 - - - - Test initialize method '{0}.{1}' was canceled - 已取消测试初始化方法“{0}.{1}” - - - - TestCleanup method {0}.{1} threw exception. {2}. - TestCleanup 方法 {0}.{1} 引发异常。{2}。 - - - - --- End of inner exception stack trace --- - ---内部异常堆栈跟踪结束--- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: 在一个程序集内部,不能定义多个具有 AssemblyCleanup 特性的方法。 - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: 在一个程序集内部,不能定义多个具有 AssemblyInitialize 特性的方法。 - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: 在一个类内部,不能定义多个具有 ClassCleanup 特性的方法。 - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: 在一个类内部,不能定义多个具有 ClassInitialize 特性的方法。 - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: 不能定义多个具有 TestCleanup 特性的方法。 - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: 不能定义多个具有 TestInitialize 特性的方法。 - - - - TestClass attribute defined on generic non-abstract class {0} - 在泛型非抽象类 {0} 上定义的 TestClass 特性 - - - - Initialization method {0}.{1} threw exception. {2}. - 初始化方法 {0}.{1} 引发异常。{2}。 - - - - Unable to create instance of class {0}. Error: {1}. - 无法创建类 {0} 的实例。错误: {1}。 - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - 测试方法“{0}.{1}”具有多个在其上定义的“{2}”的派生属性。仅允许一个此类属性。 - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - 找不到测试类“{0}”的有效构造函数。有效的构造函数为 “public”,但该构造函数无参数或具有一个类型为 “TestContext” 的参数。 - - - - Unable to set TestContext property for the class {0}. Error: {1}. - 无法设置类 {0} 的 TestContext 属性。错误: {1}。 - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (因异常而未能获取类型为 {0} 的异常的消息。) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: 类 {0} 没有有效的 TestContext 属性。TestContext 必须是 TestContext 类型并且必须是非静态和公共的。例如: public TestContext TestContext。 - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: 在非公共类 {0} 上定义的 TestClass 特性 - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - 由于 {2},MSTestAdapter 未能在程序集“{1}”的类“{0}”中发现测试。 - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - 无法从测试源“{0}”加载类型。可能无法发现此源中的部分或所有测试。 -错误: {1} - - - - File does not exist: {0} - 文件不存在: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: 在类 {0} 中定义的方法 {1} 没有正确的签名。用 [TestMethod] 特性标记的测试方法必须是返回类型为 void 的非静态的公共方法,并且不应采用任何参数。示例: public void Test.Class1.Test()。此外,如果在测试方法中使用同步等待,则返回类型必须为“Task”或“Value Task”。示例: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext 不能为 NULL。 - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - 程序集清理方法 {0}.{1} 失败。错误消息: {2}。StackTrace: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - 程序集初始化方法 {0}.{1} 引发异常。{2}: {3}。正在中止测试的执行。 - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - 类清理方法 {0}.{1} 失败。错误消息: {2}。堆栈跟踪: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - 类初始化方法 {0}.{1} 引发异常。{2}: {3}。 - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - “Execute”方法引发了未经处理的异常。请将此错误报告给属性 '{0}' 的作者。 -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - 执行测试时出错。扩展未返回任何结果。如果使用的是扩展 TestMethodAttribute ,请与供应商联系。 - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - 方法 {0}。{1}的签名错误。该方法必须是静态的公共方法、不返回值并且不应采用任何参数。此外,如果在方法中使用同步等待,则返回类型必须为“Task”或“Value Task”。 - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - 方法 {0}。{1}的签名错误。该方法必须是静态的公共方法,不返回值,并且应采用一个 TestContext 类型的参数。此外,如果在方法中使用同步等待,则返回类型必须为“Task”或“Value Task”。 - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}。{1} 的超时属性无效。“超时”必须是大于零的整数值。 - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: 不能在方法 {1} 上定义预定义属性 {2}。 - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: 对方法 {1} 定义了为 NULL 或为空的自定义属性。自定义属性必须具有有效名称。 - - - - Method {0}.{1} does not exist. - 方法 {0}.{1} 不存在。 - - - - Unable to find property {0}.TestContext. Error:{1}. - 无法找到属性 {0}.TestContext。错误: {1}。 - - - - The {0}.TestContext has incorrect type. - {0}.TestContext 的类型不正确。 - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - 方法 {0}。{1}的签名错误。该方法必须是非静态的公共方法、不返回值并且不应采用任何参数。此外,如果在方法中使用同步等待,则返回类型必须为“Task”或“Value Task”。 - - - - Unable to get type {0}. Error: {1}. - 无法获取类型 {0}。错误: {1}。 - - - - Test method {0} was not found. - 未找到测试方法 {0}。 - - - - Debug Trace: - 调试跟踪: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - 未能获取测试方法 {0}.{1} 引发的异常。 - - - - Test method {0}.{1} threw exception: -{2} - 测试方法 {0}.{1} 引发了异常: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0} 对于 UWP 项目,如果在测试中使用 UI 对象,请考虑使用 [UITestMethod] 属性代替 [TestMethod] 属性在 UI 线程中执行测试。 - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - 设置“{0}”无效。意外的 XmlAttribute:“{1}”。 - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - 设置“{0}”无效。意外的 XmlElement:“{1}”。 - - - - {0} (Data Row {1}) - {0} (数据行 {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - 测试方法 {0}.{1} 上定义的 ExpectedException 属性在构造过程中引发了一个异常。 -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - 警告: MSTest V2 适配器不支持 testsettings 文件或 vsmdi 文件。 - - - - TestContext Messages: - TestContext 消息: - - - - Error calling Test Cleanup method for test class {0}: {1} - 为测试类 {0} 调用 Test Cleanup 方法时出错: {1} - - - - TestCleanup Stack Trace - TestCleanup 堆栈跟踪 - - - - [MSTest][Discovery][{0}] {1} - [MSTest][发现][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - 已为 {0} 启用测试并行化(工作线程: {1},范围: {2}) - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - 为“范围”指定的值“{0}”无效。受支持的范围为 {1}。 - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - 为“辅助角色”指定的值“{0}”无效。该值应为非负整数。 - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - 未能发现程序集 {0} 中的测试。原因: {1} - - - - Test '{0}' was canceled - 测试 '{0}' 已取消 - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - 为“ClassCleanupLifecycle”指定的值“{0}”无效。支持的作用域为 {1}。 - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - 枚举 {0} 上的 IDataSource 属性时发生异常。{1}": {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - “{0}”:(由于类型“{1}”异常,无法获取异常说明。 - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - 引发的异常: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - 获取类型 {0} 自定义属性引发异常(将忽略并使用反射方式): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - 程序集中加载了 MSTestV2 包的较旧版本,如果测试发现依赖于“.runsettings”文件,则它们可能无法发现所有数据测试。 - - - - The called code threw an exception that was caught, but the exception value was null - 调用的代码引发了捕获的异常,但异常值为 null - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - 从“{0}.{1}”上的属性扩展 IDataSource 行时出现异常: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - 索引 {0} 和 {1} 上的显示名称“{2}”重复。显示名称应是唯一的。 - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - 无法序列化“{1}”的索引 {0} 上的数据。通过“IDataSource”提供的所有数据都应可序列化。如果需要测试不可序列化的数据源,请确保在测试程序集上添加“TestDataSourceDiscovery”属性,并将发现选项设置为“DuringExecution”。 - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hant.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hant.xlf deleted file mode 100644 index d247e040da..0000000000 --- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hant.xlf +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - Assembly cleanup method '{0}.{1}' timed out after {2}ms - 組件清理方法 '{0}.{1}' 在 {2} 毫秒後已逾時 - - - - Assembly cleanup method '{0}.{1}' was canceled - 已取消組件清理方法 '{0}.{1}' - - - - Assembly initialize method '{0}.{1}' timed out after {2}ms - 組件初始化方法 '{0}.{1}' 在 {2} 毫秒後已逾時 - - - - Assembly initialize method '{0}.{1}' was canceled - 已取消組件初始化方法 '{0}.{1}' - - - - Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. -Test expected {2} parameter(s), with types '{3}', -but received {4} argument(s), with types '{5}'. - 無法執行測試方法 '{0}.{1}': 測試資料不符合方法參數。計數或類型不同。 -測試預期的 {2} 參數,類型為 '{3}', -但收到 {4} 引數,類型為 '{5}'。 - - - - Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. - 無法執行測試方法 '{0}.{1}': 方法具有參數,但未定義任何測試來源。使用 '[DataRow]'、'[DynamicData]' 或自訂 'ITestDataSource' 資料來源來提供測試資料。 - - - - Class cleanup method '{0}.{1}' timed out after {2}ms - 類別清理方法 '{0}.{1}' 在 {2} 毫秒後已逾時 - - - - Class cleanup method '{0}.{1}' was canceled - 已取消類別清理方法 '{0}.{1}' - - - - Class initialize method '{0}.{1}' timed out after {2}ms - 類別初始化方法 '{0}.{1}' 在 {2} 毫秒後已逾時 - - - - Class initialize method '{0}.{1}' was canceled - 已取消類別初始化方法 '{0}.{1}' - - - - Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. - 偵測到 '.runsettings' 和 '.testconfig.json' 檔案。請只選取其中一個測試設定檔。 - - - - Test '{0}' timed out after {1}ms - 測試 '{0}' 在 {1}毫秒後逾時 - - - - The type of the generic parameter '{0}' could not be inferred. - 無法推斷泛型參數 '{0}' 的類型。 - - - - The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. - 泛型測試方法 '{0}' 沒有自變數,因此無法推斷泛型參數。 - - - - Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. - 發現兩個衝突的泛型參數類型 '{0}'。衝突的類型 '{1}' 且 '{2}'。 - - - - Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. - runsettings 項目 '{1}' 的值 '{0}' 無效,將忽略設定。 - - - - Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. - 非 Windows OS 不支援 Runsettings 項目 '<ExecutionApartmentState>STA</ExecutionApartmentState>'。 - - - - Running tests in any of the provided sources is not supported for the selected platform - 所選取的平台不支援在任何提供的來源中執行測試 - - - - Test cleanup method '{0}.{1}' timed out after {2}ms - 測試清理方法 '{0}.{1}' 在 {2} 毫秒後已逾時 - - - - Test cleanup method '{0}.{1}' was canceled - 已取消測試清理方法 '{0}.{1}' - - - - Test initialize method '{0}.{1}' timed out after {2}ms - 測試初始化方法 '{0}.{1}' 在 {2} 毫秒後已逾時 - - - - Test initialize method '{0}.{1}' was canceled - 已取消測試初始化方法 '{0}.{1}' - - - - TestCleanup method {0}.{1} threw exception. {2}. - TestCleanup 方法 {0}.{1} 擲回例外狀況。{2}。 - - - - --- End of inner exception stack trace --- - --- 已到達內部例外狀況堆疊追蹤的結尾 --- - - - - UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. - UTA014: {0}: 組件內不可定義一個以上具有 AssemblyCleanup 屬性的方法。 - - - - UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. - UTA013: {0}: 組件內不可定義一個以上具有 AssemblyInitialize 屬性的方法。 - - - - UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. - UTA026: {0}: 類別內不可定義一個以上具有 ClassCleanup 屬性的方法。 - - - - UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. - UTA025: {0}: 類別內不可定義一個以上具有 ClassInitialize 屬性的方法。 - - - - UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. - UTA024: {0}: 不可定義一個以上具有 TestCleanup 屬性的方法。 - - - - UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. - UTA018: {0}: 不可定義一個以上具有 TestInitialize 屬性的方法。 - - - - TestClass attribute defined on generic non-abstract class {0} - 在一般非抽象類別上定義的 TestClass 屬性 {0} - - - - Initialization method {0}.{1} threw exception. {2}. - 初始設定方法 {0}.{1} 擲回例外狀況。{2}。 - - - - Unable to create instance of class {0}. Error: {1}. - 無法建立類別 {0} 的執行個體。錯誤: {1}。 - - - - The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. - 測試方法 '{0}.{1}' 具有多個衍生自 '{2}' 的屬性根據其定義。只允許一個此類屬性。 - - - - Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. - 找不到測試類別 '{0}' 的有效建構函式。有效的建構函式為 'public' 且無參數或具有一個類型為 'TestContext' 的參數。 - - - - Unable to set TestContext property for the class {0}. Error: {1}. - 無法設定類別 {0} 的 TestContext 屬性。錯誤: {1}。 - - - - (Failed to get the message for an exception of type {0} due to an exception.) - (因為發生例外狀況,所以無法取得類型 {0} 之例外狀況的訊息。) - - - - UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. - UTA031: 類別 {0}不具備有效的 TestContext 屬性。TestContext 必須是 TestContext 類型、必須是非靜態的,而且必須是公用的。例如: public TestContext TestContext。 - - - - UTA001: TestClass attribute defined on non-public class {0} - UTA001: 在非公用類別 {0} 上定義了 TestClass 屬性 - - - - MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. - MSTestAdapter 無法在組件 '{1}' 的類別 '{0}' 中探索測試,因為 {2}。 - - - - {0}: {1} - {0}: {1} - - - - Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. -Error: {1} - 無法從測試來源 '{0}' 載入類型。有可能無法探索此來源中的部分或所有測試。 -錯誤: {1} - - - - File does not exist: {0} - 檔案不存在: {0} - - - - UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() - UTA007: 類別 {0} 中定義的方法 {1} 沒有正確的簽章。標記 [TestMethod] 屬性的測試方法必須為非靜態、公用、傳回類型為 void,而且不應該接受任何參數。範例: public void Test.Class1.Test()。此外,如果您在測試方法中使用 async-await,則傳回類型必須是 'Task' 或 'ValueTask'。範例: public async Task Test.Class1.Test2() - - - - TestContext cannot be Null. - TestContext 不可為 Null。 - - - - Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} - 組件清除方法 {0}.{1} 失敗。錯誤訊息: {2}。堆疊追蹤: {3} - - - - Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. - 組件初始設定方法 {0}.{1} 擲回例外狀況。{2}: {3}。正在中止測試執行。 - - - - Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} - 類別清除方法 {0}.{1} 失敗。錯誤訊息: {2}。堆疊追蹤: {3} - - - - Class Initialization method {0}.{1} threw exception. {2}: {3}. - 類別初始設定方法 {0}.{1} 擲回例外狀況。{2}: {3}。 - - - - An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. -{1} - 'Execute' 方法擲回未處理的例外狀況。請將此錯誤回報給屬性 '{0}' 的作者。 -{1} - - - - Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. - 執行測試時發生錯誤。擴充功能未傳回任何結果。如果您使用 TestMethodAttribute 的擴充功能,請連絡廠商。 - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - 方法 {0}.{1} 有錯誤的簽章。方法必須為靜態、公用、不傳回值,並且不應該接受任何參數。此外,如果您在方法中使用 async-await,則傳回類型必須是 'Task' 或 'ValueTask'。 - - - - Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - 方法 {0}.{1} 有錯誤的簽章。方法必須為靜態、公用、不傳回值,並且應接受類型為 TestContext 的單一參數。此外,如果您在方法中使用 async-await,則傳回類型必須是 'Task' 或 'ValueTask'。 - - - - UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. - UTA054: {0}。{1} 中具有無效的 Timeout 屬性。逾時必須為大於 0 的整數值。 - - - - UTA023: {0}: Cannot define predefined property {2} on method {1}. - UTA023: {0}: 不可在方法 {1} 上定義預先定義的屬性 {2}。 - - - - UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. - UTA021: {0}: 在方法 {1} 上定義了 Null 或空白的自訂屬性。自訂屬性的名稱必須有效。 - - - - Method {0}.{1} does not exist. - 方法 {0}.{1} 不存在。 - - - - Unable to find property {0}.TestContext. Error:{1}. - 找不到屬性 {0}.TestContext。錯誤: {1}。 - - - - The {0}.TestContext has incorrect type. - {0}.TestContext 有不正確的類型。 - - - - Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. - 方法 {0}.{1} 有錯誤的簽章。方法必須為非靜態、公用、不傳回值,並且不應該接受任何參數。此外,如果您在方法中使用 async-await,則傳回類型必須是 'Task' 或 'ValueTask'。 - - - - Unable to get type {0}. Error: {1}. - 無法取得類型 {0}。錯誤: {1}。 - - - - Test method {0} was not found. - 找不到測試方法 {0}。 - - - - Debug Trace: - 偵錯追蹤: - - - - Failed to obtain the exception thrown by test method {0}.{1}. - 無法取得測試方法 {0}.{1} 所擲回的例外狀況。 - - - - Test method {0}.{1} threw exception: -{2} - 測試方法 {0}.{1} 擲回例外狀況: -{2} - - - - {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. - {0} 針對 UWP 專案,如果您在測試中使用 UI 物件,請考慮使用 [UITestMethod] 屬性取代 [TestMethod] 在 UI 執行緒中執行測試。 - - - - MSTestAdapterV2 - MSTestAdapterV2 - - - - Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. - 設定 '{0}' 無效。未預期的 XmlAttribute: '{1}'。 - - - - Invalid settings '{0}'. Unexpected XmlElement: '{1}'. - 設定 '{0}' 無效。未預期的 XmlElement: '{1}'。 - - - - {0} (Data Row {1}) - {0} (資料列 {1}) - - - - The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. -{2} - 測試方法 {0} 上定義的 ExpectedException 屬性。{1} 在建構期間擲回例外狀況。 -{2} - - - - Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. - 警告: MSTest V2 配接器不支援 testsettings 檔案 vsmdi 檔案。 - - - - TestContext Messages: - TestContext 訊息: - - - - Error calling Test Cleanup method for test class {0}: {1} - 呼叫測試類別 {0} 的測試清除方法時發生錯誤: {1} - - - - TestCleanup Stack Trace - TestCleanup 堆疊追蹤 - - - - [MSTest][Discovery][{0}] {1} - [MSTest][Discovery][{0}] {1} - - - - Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) - 已為 {0} 啟用平行測試 (背景工作角色: {1},範圍: {2}) - `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. - 為 'Scope' 指定的值 '{0}' 無效。支援的範圍為 {1}。 - 'Scope' is a setting name that shouldn't be localized. - - - Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. - 為 'Workers' 的值 '{0}' 無效。值應為非負整數。 - `Workers` is a setting name that shouldn't be localized. - - - Failed to discover tests from assembly {0}. Reason:{1} - 無法從組件 {0} 中探索測試。原因:{1} - - - - Test '{0}' was canceled - 已取消測試 '{0}' - - - - Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. - 為 'ClassCleanupLifecycle' 指定的值 '{0}' 無效。支援的範圍為 {1}。 - 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. - - - Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} - 列舉「{0}.{1}」上的 IDataSource 屬性時發生例外狀況: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: Exception details - - - "{0}": (Failed to get exception description due to an exception of type "{1}". - 「{0}」: (因為類型「{1}」的例外狀況而無法取得例外狀況描述。 - {0}: Type of the original exception that we're trying to get the description of. -{1}: Thrown exception - - - Exceptions thrown: - 擲回的例外狀況數: - This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. - - - Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} - 取得類型 {0} 擲回例外狀況的自訂屬性 (將會略過並使用反映方式): {1} - {0}: Attribute full type name. -{1}: Exception description - - - An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. - 元件中已載入舊版的 MSTestV2 套件,如果測試探索相依於 '.runsettings' 檔案,則測試探索可能無法探索所有資料測試。 - - - - The called code threw an exception that was caught, but the exception value was null - 被呼叫的程式碼擲回攔截到的例外狀況,但例外狀況值為 Null - - - - Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} - 從「{0}.{1}」上的屬性展開 IDataSource 資料列時發生例外狀況: {2} - {0}: TypeName with namespace, -{1}: Method name, -{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize - - - Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. - 索引 {0} 和 {1} 上的顯示名稱「{2}」重複。顯示名稱必須是唯一的。 - {0}, {1}: Zero based index if an element inside of an array -{2}: Test display name. - - - Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". - 無法序列化「{1}"」索引 {0} 上的資料。透過「IDataSource」提供的所有資料應可序列化。如果您需要測試不可序列化的資料來源,請務必在測試元件上新增「TestDataSourceDiscovery」屬性,並將探索選項設定為「DuringExecution」。 - {0}: Zero based index if an element inside of an array, -{1}: Test name - - - - \ No newline at end of file diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/BridgedTraceLogger.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/BridgedTraceLogger.cs index e5332169f0..86cdf28df1 100644 --- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/BridgedTraceLogger.cs +++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/BridgedTraceLogger.cs @@ -16,12 +16,27 @@ public BridgedTraceLogger(ILogger logger) => _logger = logger; public void LogError(string format, params object?[] args) - => _logger.LogError(string.Format(CultureInfo.CurrentCulture, format, args)); + { + if (_logger.IsEnabled(LogLevel.Error)) + { + _logger.LogError(string.Format(CultureInfo.CurrentCulture, format, args)); + } + } public void LogInfo(string format, params object?[] args) - => _logger.LogInformation(string.Format(CultureInfo.CurrentCulture, format, args)); + { + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation(string.Format(CultureInfo.CurrentCulture, format, args)); + } + } public void LogWarning(string format, params object?[] args) - => _logger.LogWarning(string.Format(CultureInfo.CurrentCulture, format, args)); + { + if (_logger.IsEnabled(LogLevel.Warning)) + { + _logger.LogWarning(string.Format(CultureInfo.CurrentCulture, format, args)); + } + } } #endif diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBannerCapability.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBannerCapability.cs index 3ebc32ee6d..f00335287c 100644 --- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBannerCapability.cs +++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBannerCapability.cs @@ -7,8 +7,6 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - [SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")] internal sealed class MSTestBannerCapability : IBannerMessageOwnerCapability { diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBridgedTestFramework.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBridgedTestFramework.cs index e529cae9cb..d09665cf53 100644 --- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBridgedTestFramework.cs +++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBridgedTestFramework.cs @@ -53,7 +53,7 @@ protected override async Task SynchronizedRunTestsAsync(VSTestRunTestExecutionRe PlatformServiceProvider.Instance.AdapterTraceLogger = new BridgedTraceLogger(_loggerFactory.CreateLogger("mstest-trace")); MSTestExecutor testExecutor = new(cancellationToken); - await testExecutor.RunTestsAsync(request.AssemblyPaths, request.RunContext, request.FrameworkHandle, _configuration); + await testExecutor.RunTestsAsync(request.AssemblyPaths, request.RunContext, request.FrameworkHandle, _configuration).ConfigureAwait(false); } } #endif diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestGracefulStopTestExecutionCapability.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestGracefulStopTestExecutionCapability.cs index ea80488cb6..01bce0f496 100644 --- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestGracefulStopTestExecutionCapability.cs +++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestGracefulStopTestExecutionCapability.cs @@ -7,11 +7,8 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - [SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")] internal sealed class MSTestGracefulStopTestExecutionCapability : IGracefulStopTestExecutionCapability -#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. { private MSTestGracefulStopTestExecutionCapability() { diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs index 326c85f88f..4166a55daa 100644 --- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs +++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs @@ -39,17 +39,13 @@ public static void AddMSTest(this ITestApplicationBuilder testApplicationBuilder testApplicationBuilder.AddRunSettingsService(extension); testApplicationBuilder.AddTestCaseFilterService(extension); testApplicationBuilder.AddTestRunParametersService(extension); -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. testApplicationBuilder.AddMaximumFailedTestsService(extension); -#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. testApplicationBuilder.AddRunSettingsEnvironmentVariableProvider(extension); testApplicationBuilder.RegisterTestFramework( serviceProvider => new TestFrameworkCapabilities( new MSTestCapabilities(), -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. new MSTestBannerCapability(serviceProvider.GetRequiredService()), MSTestGracefulStopTestExecutionCapability.Instance), -#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. (capabilities, serviceProvider) => new MSTestBridgedTestFramework(extension, getTestAssemblies, serviceProvider, capabilities)); } } diff --git a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestDiscoverer.cs b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestDiscoverer.cs index 7fcb8c825d..27fe223424 100644 --- a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestDiscoverer.cs +++ b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestDiscoverer.cs @@ -11,15 +11,15 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; /// /// Contains the discovery logic for this adapter. /// -[DefaultExecutorUri(Constants.ExecutorUriString)] +[DefaultExecutorUri(MSTestAdapter.PlatformServices.EngineConstants.ExecutorUriString)] [FileExtension(".xap")] [FileExtension(".appx")] [FileExtension(".dll")] [FileExtension(".exe")] #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class MSTestDiscoverer : ITestDiscoverer { diff --git a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs index 35f125d683..82b316d549 100644 --- a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs +++ b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs @@ -2,21 +2,23 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; /// /// Contains the execution logic for this adapter. /// -[ExtensionUri(Constants.ExecutorUriString)] +[ExtensionUri(EngineConstants.ExecutorUriString)] #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class MSTestExecutor : ITestExecutor { @@ -47,6 +49,20 @@ internal MSTestExecutor(CancellationToken cancellationToken) /// public TestExecutionManager TestExecutionManager { get; protected set; } +#pragma warning disable CA2255 // The 'ModuleInitializer' attribute should not be used in libraries + [ModuleInitializer] +#pragma warning restore CA2255 // The 'ModuleInitializer' attribute should not be used in libraries + internal static void EnsureAdapterAndFrameworkVersions() + { + string? adapterVersion = typeof(MSTestExecutor).Assembly.GetCustomAttribute()?.InformationalVersion; + string? frameworkVersion = typeof(TestMethodAttribute).Assembly.GetCustomAttribute()?.InformationalVersion; + if (adapterVersion is not null && frameworkVersion is not null + && adapterVersion != frameworkVersion) + { + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, Resource.VersionMismatchBetweenAdapterAndFramework, adapterVersion, frameworkVersion)); + } + } + /// /// Runs the tests. /// @@ -82,7 +98,7 @@ internal async Task RunTestsAsync(IEnumerable? tests, IRunContext? run return; } - await RunTestsFromRightContextAsync(frameworkHandle, async testRunToken => await TestExecutionManager.RunTestsAsync(tests, runContext, frameworkHandle, testRunToken)); + await RunTestsFromRightContextAsync(frameworkHandle, async testRunToken => await TestExecutionManager.RunTestsAsync(tests, runContext, frameworkHandle, testRunToken).ConfigureAwait(false)).ConfigureAwait(false); } internal async Task RunTestsAsync(IEnumerable? sources, IRunContext? runContext, IFrameworkHandle? frameworkHandle, IConfiguration? configuration) @@ -96,7 +112,7 @@ internal async Task RunTestsAsync(IEnumerable? sources, IRunContext? run } sources = PlatformServiceProvider.Instance.TestSource.GetTestSources(sources); - await RunTestsFromRightContextAsync(frameworkHandle, async testRunToken => await TestExecutionManager.RunTestsAsync(sources, runContext, frameworkHandle, testRunToken)); + await RunTestsFromRightContextAsync(frameworkHandle, async testRunToken => await TestExecutionManager.RunTestsAsync(sources, runContext, frameworkHandle, testRunToken).ConfigureAwait(false)).ConfigureAwait(false); } /// @@ -126,7 +142,7 @@ private async Task RunTestsFromRightContextAsync(IFrameworkHandle frameworkHandl try { var threadTask = Task.Run(entryPointThread.Join, _cancellationToken); - await threadTask; + await threadTask.ConfigureAwait(false); } catch (Exception ex) { @@ -142,7 +158,7 @@ private async Task RunTestsFromRightContextAsync(IFrameworkHandle frameworkHandl frameworkHandle.SendMessage(TestMessageLevel.Warning, Resource.STAIsOnlySupportedOnWindowsWarning); } - await DoRunTestsAsync(); + await DoRunTestsAsync().ConfigureAwait(false); } // Local functions @@ -152,8 +168,8 @@ async Task DoRunTestsAsync() { try { - _testRunCancellationToken = new TestRunCancellationToken(); - await runTestsAction(_testRunCancellationToken); + _testRunCancellationToken = new TestRunCancellationToken(_cancellationToken); + await runTestsAction(_testRunCancellationToken).ConfigureAwait(false); } finally { diff --git a/src/Adapter/MSTest.TestAdapter/buildTransitive/common/MSTest.TestAdapter.targets b/src/Adapter/MSTest.TestAdapter/buildTransitive/common/MSTest.TestAdapter.targets index 63ad3b5b08..2feb8c652b 100644 --- a/src/Adapter/MSTest.TestAdapter/buildTransitive/common/MSTest.TestAdapter.targets +++ b/src/Adapter/MSTest.TestAdapter/buildTransitive/common/MSTest.TestAdapter.targets @@ -1,4 +1,10 @@ - + + + + + diff --git a/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs b/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs index 1ac452a754..22480e260c 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs @@ -20,9 +20,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// #if NETFRAMEWORK #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public #else @@ -408,7 +408,7 @@ protected virtual return null; } - s_currentlyLoading ??= new List(); + s_currentlyLoading ??= []; s_currentlyLoading.Add(assemblyPath); // Push isPushed = true; } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Constants.cs b/src/Adapter/MSTestAdapter.PlatformServices/Constants.cs deleted file mode 100644 index 9651fb5b97..0000000000 --- a/src/Adapter/MSTestAdapter.PlatformServices/Constants.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Microsoft.VisualStudio.TestPlatform.ObjectModel; - -namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; - -internal static class Constants -{ -#if NETFRAMEWORK - /// - /// Constants for detecting .net framework. - /// - public const string TargetFrameworkAttributeFullName = "System.Runtime.Versioning.TargetFrameworkAttribute"; - - public const string DotNetFrameWorkStringPrefix = ".NETFramework,Version="; - - public const string TargetFrameworkName = "TargetFrameworkName"; - - public const string PublicAssemblies = "PublicAssemblies"; - - public const string PrivateAssemblies = "PrivateAssemblies"; -#endif - - public static readonly TestProperty DeploymentItemsProperty = TestProperty.Register("MSTestDiscoverer.DeploymentItems", DeploymentItemsLabel, typeof(KeyValuePair[]), TestPropertyAttributes.Hidden, typeof(TestCase)); - - internal const string DllExtension = ".dll"; - internal const string ExeExtension = ".exe"; - internal const string AppxPackageExtension = ".appx"; - -#if NETFRAMEWORK - internal const string PhoneAppxPackageExtension = ".appx"; - - // These are tied to a specific VS version. Can be changed to have a list of supported version instead. - internal const string VisualStudioRootRegKey32ForDev14 = @"SOFTWARE\Microsoft\VisualStudio\" + VisualStudioVersion; - internal const string VisualStudioRootRegKey64ForDev14 = @"SOFTWARE\Wow6432Node\Microsoft\VisualStudio\" + VisualStudioVersion; - - internal const string VisualStudioVersion = "14.0"; -#endif - - private const string DeploymentItemsLabel = "DeploymentItems"; - - internal const string PublicTypeObsoleteMessage = "We will remove or hide this type starting with v4. If you are using this type, reach out to our team on https://github.com/microsoft/testfx."; -} diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Data/TestDataConnectionSql.cs b/src/Adapter/MSTestAdapter.PlatformServices/Data/TestDataConnectionSql.cs index f2af39ca11..90c377b952 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Data/TestDataConnectionSql.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Data/TestDataConnectionSql.cs @@ -282,7 +282,7 @@ public string PrepareNameForSql(string tableName) return null; } - return parts.ToArray(); + return [.. parts]; } } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Deployment/AssemblyLoadWorker.cs b/src/Adapter/MSTestAdapter.PlatformServices/Deployment/AssemblyLoadWorker.cs index 323487a79f..3c2b3f7e20 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Deployment/AssemblyLoadWorker.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Deployment/AssemblyLoadWorker.cs @@ -41,7 +41,7 @@ public IReadOnlyCollection GetFullPathToDependentAssemblies(string assem { DebugEx.Assert(!StringEx.IsNullOrEmpty(assemblyPath), "assemblyPath"); - warnings = new List(); + warnings = []; Assembly? assembly; try { @@ -130,7 +130,7 @@ private static string GetTargetFrameworkStringFromAssembly(Assembly assembly) string attributeName = declaringType.FullName; if (string.Equals( attributeName, - Constants.TargetFrameworkAttributeFullName, + EngineConstants.TargetFrameworkAttributeFullName, StringComparison.OrdinalIgnoreCase)) { dotNetVersion = data.ConstructorArguments[0].Value.ToString(); diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Deployment/TestRunDirectories.cs b/src/Adapter/MSTestAdapter.PlatformServices/Deployment/TestRunDirectories.cs index 1ed2e71877..c2c085bb46 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Deployment/TestRunDirectories.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Deployment/TestRunDirectories.cs @@ -11,9 +11,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Dep /// The test run directories. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif [Serializable] public class TestRunDirectories diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerationResult.cs b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerationResult.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerationResult.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerationResult.cs diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerator.cs similarity index 88% rename from src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerator.cs index 6cd0f3970b..7ea3298836 100644 --- a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerator.cs @@ -7,6 +7,7 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting.Internal; @@ -65,7 +66,7 @@ public AssemblyEnumerator(MSTestSettings settings) => /// A collection of Test Elements. internal AssemblyEnumerationResult EnumerateAssembly(string assemblyFileName) { - List warnings = new(); + List warnings = []; DebugEx.Assert(!StringEx.IsNullOrWhiteSpace(assemblyFileName), "Invalid assembly file name."); var tests = new List(); // Contains list of assembly/class names for which we have already added fixture tests. @@ -172,9 +173,8 @@ internal static string GetLoadExceptionDetails(ReflectionTypeLoadException ex) { DebugEx.Assert(loaderException != null, "loader exception should not be null."); string line = string.Format(CultureInfo.CurrentCulture, Resource.EnumeratorLoadTypeErrorFormat, loaderException.GetType(), loaderException.Message); - if (!map.ContainsKey(line)) + if (map.TryAdd(line, null)) { - map.Add(line, null); errorDetails.AppendLine(line); } } @@ -271,13 +271,13 @@ private static void AddFixtureTests(DiscoveryTestMethodInfo testMethodInfo, List if (testMethodInfo.Parent.Parent.AssemblyInitializeMethod is not null) { tests.Add(GetAssemblyFixtureTest(testMethodInfo.Parent.Parent.AssemblyInitializeMethod, assemblyName, - classFullName, assemblyLocation, Constants.AssemblyInitializeFixtureTrait)); + classFullName, assemblyLocation, EngineConstants.AssemblyInitializeFixtureTrait)); } if (testMethodInfo.Parent.Parent.AssemblyCleanupMethod is not null) { tests.Add(GetAssemblyFixtureTest(testMethodInfo.Parent.Parent.AssemblyCleanupMethod, assemblyName, - classFullName, assemblyLocation, Constants.AssemblyCleanupFixtureTrait)); + classFullName, assemblyLocation, EngineConstants.AssemblyCleanupFixtureTrait)); } } @@ -290,13 +290,13 @@ private static void AddFixtureTests(DiscoveryTestMethodInfo testMethodInfo, List if (testMethodInfo.Parent.ClassInitializeMethod is not null) { tests.Add(GetClassFixtureTest(testMethodInfo.Parent.ClassInitializeMethod, classFullName, - assemblyLocation, Constants.ClassInitializeFixtureTrait)); + assemblyLocation, EngineConstants.ClassInitializeFixtureTrait)); } if (testMethodInfo.Parent.ClassCleanupMethod is not null) { tests.Add(GetClassFixtureTest(testMethodInfo.Parent.ClassCleanupMethod, classFullName, - assemblyLocation, Constants.ClassCleanupFixtureTrait)); + assemblyLocation, EngineConstants.ClassCleanupFixtureTrait)); } } @@ -304,7 +304,7 @@ static UnitTestElement GetAssemblyFixtureTest(MethodInfo methodInfo, string asse string assemblyLocation, string fixtureType) { string methodName = GetMethodName(methodInfo); - string[] hierarchy = [null!, assemblyName, Constants.AssemblyFixturesHierarchyClassName, methodName]; + string[] hierarchy = [null!, assemblyName, EngineConstants.AssemblyFixturesHierarchyClassName, methodName]; return GetFixtureTest(classFullName, assemblyLocation, fixtureType, methodName, hierarchy); } @@ -320,7 +320,7 @@ static string GetMethodName(MethodInfo methodInfo) { ParameterInfo[] args = methodInfo.GetParameters(); return args.Length > 0 - ? $"{methodInfo.Name}({string.Join(",", args.Select(a => a.ParameterType.FullName))})" + ? $"{methodInfo.Name}({string.Join(',', args.Select(a => a.ParameterType.FullName))})" : methodInfo.Name; } @@ -330,7 +330,7 @@ static UnitTestElement GetFixtureTest(string classFullName, string assemblyLocat return new UnitTestElement(method) { DisplayName = $"[{fixtureType}] {methodName}", - Traits = [new Trait(Constants.FixturesTestTrait, fixtureType)], + Traits = [new Trait(EngineConstants.FixturesTestTrait, fixtureType)], }; } } @@ -347,10 +347,10 @@ private static bool TryUnfoldITestDataSources(UnitTestElement test, DiscoveryTes // We don't have a special method to filter attributes that are not derived from Attribute, so we take all // attributes and filter them. We don't have to care if there is one, because this method is only entered when // there is at least one (we determine this in TypeEnumerator.GetTestFromMethod. - IEnumerable testDataSources = ReflectHelper.Instance.GetDerivedAttributes(testMethodInfo.MethodInfo, inherit: false).OfType(); + IEnumerable testDataSources = ReflectHelper.Instance.GetAttributes(testMethodInfo.MethodInfo, inherit: false).OfType(); // We need to use a temporary list to avoid adding tests to the main list if we fail to expand any data source. - List tempListOfTests = new(); + List tempListOfTests = []; try { @@ -438,14 +438,43 @@ private static bool TryUnfoldITestDataSource(ITestDataSource dataSource, TestDat foreach (object?[] dataOrTestDataRow in data) { object?[] d = dataOrTestDataRow; - if (TestDataSourceHelpers.TryHandleITestDataRow(d, methodInfo.GetParameters(), out d, out string? ignoreMessageFromTestDataRow, out string? displayNameFromTestDataRow)) + ParameterInfo[] parameters = methodInfo.GetParameters(); + if (TestDataSourceHelpers.TryHandleITestDataRow(d, parameters, out d, out string? ignoreMessageFromTestDataRow, out string? displayNameFromTestDataRow, out IList? testCategoriesFromTestDataRow)) { testDataSourceIgnoreMessage = ignoreMessageFromTestDataRow ?? testDataSourceIgnoreMessage; } + else if (TestDataSourceHelpers.IsDataConsideredSingleArgumentValue(d, parameters)) + { + // SPECIAL CASE: + // This condition is a duplicate of the condition in InvokeAsSynchronousTask. + // + // The known scenario we know of that shows importance of that check is if we have DynamicData using this member + // + // public static IEnumerable GetData() + // { + // yield return new object[] { ("Hello", "World") }; + // } + // + // If the test method has a single parameter which is 'object[]', then we should pass the tuple array as is. + // Note that normally, the array in this code path represents the arguments of the test method. + // However, InvokeAsSynchronousTask uses the above check to mean "the whole array is the single argument to the test method" + } + else if (d?.Length == 1 && TestDataSourceHelpers.TryHandleTupleDataSource(d[0], parameters, out object?[] tupleExpandedToArray)) + { + d = tupleExpandedToArray; + } UnitTestElement discoveredTest = test.Clone(); discoveredTest.DisplayName = displayNameFromTestDataRow ?? dataSource.GetDisplayName(methodInfo, d) ?? discoveredTest.DisplayName; + // Merge test categories from the test data row with the existing categories + if (testCategoriesFromTestDataRow is { Count: > 0 }) + { + discoveredTest.TestCategory = discoveredTest.TestCategory is { Length: > 0 } + ? [.. testCategoriesFromTestDataRow, .. discoveredTest.TestCategory] + : [.. testCategoriesFromTestDataRow]; + } + // If strategy is DisplayName and we have a duplicate test name don't expand the test, bail out. #pragma warning disable CS0618 // Type or member is obsolete if (test.TestMethod.TestIdGenerationStrategy == TestIdGenerationStrategy.DisplayName @@ -463,6 +492,7 @@ private static bool TryUnfoldITestDataSource(ITestDataSource dataSource, TestDat try { discoveredTest.TestMethod.SerializedData = DataSerializationHelper.Serialize(d); + discoveredTest.TestMethod.ActualData = d; discoveredTest.TestMethod.TestDataSourceIgnoreMessage = testDataSourceIgnoreMessage; discoveredTest.TestMethod.DataType = DynamicDataType.ITestDataSource; } diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumeratorWrapper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumeratorWrapper.cs similarity index 98% rename from src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumeratorWrapper.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumeratorWrapper.cs index 7e14d56e6b..5bb2e65b9a 100644 --- a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumeratorWrapper.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumeratorWrapper.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -26,7 +27,7 @@ internal sealed class AssemblyEnumeratorWrapper /// A collection of test elements. internal ICollection? GetTests(string? assemblyFileName, IRunSettings? runSettings, out List warnings) { - warnings = new List(); + warnings = []; if (StringEx.IsNullOrEmpty(assemblyFileName)) { diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/DiscoveryTestMethodInfo.cs b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/DiscoveryTestMethodInfo.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Discovery/DiscoveryTestMethodInfo.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Discovery/DiscoveryTestMethodInfo.cs diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/TestMethodValidator.cs b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/TestMethodValidator.cs similarity index 95% rename from src/Adapter/MSTest.TestAdapter/Discovery/TestMethodValidator.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Discovery/TestMethodValidator.cs index c9099700e3..846a92dd72 100644 --- a/src/Adapter/MSTest.TestAdapter/Discovery/TestMethodValidator.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/TestMethodValidator.cs @@ -3,6 +3,7 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery; @@ -44,7 +45,7 @@ internal virtual bool IsValidTestMethod(MethodInfo testMethodInfo, Type type, IC // but the difference is quite small, and we don't expect a huge amount of non-test methods in the assembly. // // Also skip all methods coming from object, because they cannot be tests. - if (testMethodInfo.DeclaringType == typeof(object) || !_reflectHelper.IsDerivedAttributeDefined(testMethodInfo, inherit: false)) + if (testMethodInfo.DeclaringType == typeof(object) || !_reflectHelper.IsAttributeDefined(testMethodInfo, inherit: false)) { return false; } diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/TypeEnumerator.cs b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/TypeEnumerator.cs similarity index 90% rename from src/Adapter/MSTest.TestAdapter/Discovery/TypeEnumerator.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Discovery/TypeEnumerator.cs index c2db89fa3d..8b7e0db86c 100644 --- a/src/Adapter/MSTest.TestAdapter/Discovery/TypeEnumerator.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/TypeEnumerator.cs @@ -110,11 +110,10 @@ internal List GetTests(List warnings) currentType = currentType.BaseType; } - return tests.GroupBy( + return [.. tests.GroupBy( t => t.TestMethod.Name, (_, elements) => - elements.OrderBy(t => inheritanceDepths[t.TestMethod.DeclaringClassFullName ?? t.TestMethod.FullClassName]).First()) - .ToList(); + elements.OrderBy(t => inheritanceDepths[t.TestMethod.DeclaringClassFullName ?? t.TestMethod.FullClassName]).First())]; } /// @@ -153,28 +152,13 @@ internal UnitTestElement GetTestFromMethod(MethodInfo method, bool isDeclaredInT DoNotParallelize = _reflectHelper.IsDoNotParallelizeSet(method, _type), Priority = _reflectHelper.GetPriority(method), DeploymentItems = PlatformServiceProvider.Instance.TestDeployment.GetDeploymentItems(method, _type, warnings), + Traits = [.. _reflectHelper.GetTestPropertiesAsTraits(method)], }; - var traits = _reflectHelper.GetTestPropertiesAsTraits(method).ToList(); - - TestPlatform.ObjectModel.Trait? ownerTrait = _reflectHelper.GetTestOwnerAsTraits(method); - if (ownerTrait != null) - { - traits.Add(ownerTrait); - } - - TestPlatform.ObjectModel.Trait? priorityTrait = _reflectHelper.GetTestPriorityAsTraits(testElement.Priority); - if (priorityTrait != null) - { - traits.Add(priorityTrait); - } - - testElement.Traits = traits.ToArray(); - Attribute[] attributes = _reflectHelper.GetCustomAttributesCached(method, inherit: true); TestMethodAttribute? testMethodAttribute = null; - // Backward looping for backcompat. This used to be calls to _reflectHelper.GetFirstDerivedAttributeOrDefault + // Backward looping for backcompat. This used to be calls to _reflectHelper.GetFirstAttributeOrDefault // So, to make sure the first attribute always wins, we loop from end to start. for (int i = attributes.Length - 1; i >= 0; i--) { @@ -190,16 +174,12 @@ internal UnitTestElement GetTestFromMethod(MethodInfo method, bool isDeclaredInT { testElement.CssProjectStructure = cssProjectStructure.CssProjectStructure; } - else if (attributes[i] is DescriptionAttribute descriptionAttribute) - { - testElement.Description = descriptionAttribute.Description; - } } IEnumerable workItemAttributes = attributes.OfType(); if (workItemAttributes.Any()) { - testElement.WorkItemIds = workItemAttributes.Select(x => x.Id.ToString(CultureInfo.InvariantCulture)).ToArray(); + testElement.WorkItemIds = [.. workItemAttributes.Select(x => x.Id.ToString(CultureInfo.InvariantCulture))]; } // In production, we always have a TestMethod attribute because GetTestFromMethod is called under IsValidTestMethod diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/TypeValidator.cs similarity index 98% rename from src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Discovery/TypeValidator.cs index 9e8e1c98d6..5589955516 100644 --- a/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/TypeValidator.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery; @@ -52,7 +53,7 @@ internal virtual bool IsValidTestClass(Type type, List warnings) // gives us a better performance. // It would be possible to use non-caching reflection here if we knew that we are only doing discovery that won't be followed by run, // but the difference is quite small, and we don't expect a huge amount of non-test classes in the assembly. - if (!type.IsClass || !_reflectHelper.IsDerivedAttributeDefined(type, inherit: false)) + if (!type.IsClass || !_reflectHelper.IsAttributeDefined(type, inherit: false)) { return false; } diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/UnitTestDiscoverer.cs b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/UnitTestDiscoverer.cs similarity index 91% rename from src/Adapter/MSTest.TestAdapter/Discovery/UnitTestDiscoverer.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Discovery/UnitTestDiscoverer.cs index b3b92c1548..79a2d02642 100644 --- a/src/Adapter/MSTest.TestAdapter/Discovery/UnitTestDiscoverer.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Discovery/UnitTestDiscoverer.cs @@ -3,6 +3,7 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; @@ -84,6 +85,13 @@ internal virtual void DiscoverTestsInSource( SendTestCases(source, testElements, discoverySink, discoveryContext, logger); } +#pragma warning disable IDE0028 // Collection initialization can be simplified - cannot be done for all TFMs. So suppressing. + private static readonly ConditionalWeakTable TestCaseToDataDictionary = new(); +#pragma warning restore IDE0028 // Collection initialization can be simplified + + internal static bool TryGetActualData(TestCase testCase, [NotNullWhen(true)] out object?[]? actualData) + => TestCaseToDataDictionary.TryGetValue(testCase, out actualData); + internal void SendTestCases(string source, IEnumerable testElements, ITestCaseDiscoverySink discoverySink, IDiscoveryContext? discoveryContext, IMessageLogger logger) { bool shouldCollectSourceInformation = MSTestSettings.RunConfigurationSettings.CollectSourceInformation; @@ -108,7 +116,7 @@ internal void SendTestCases(string source, IEnumerable testElem foreach (UnitTestElement testElement in testElements) { var testCase = testElement.ToTestCase(); - bool hasFixtureTraits = testCase.Traits.Any(t => t.Name == Constants.FixturesTestTrait); + bool hasFixtureTraits = testCase.Traits.Any(t => t.Name == EngineConstants.FixturesTestTrait); // Filter tests based on test case filters if (filterExpression != null && !filterExpression.MatchTestCase(testCase, p => _testMethodFilter.PropertyValueProvider(testCase, p))) @@ -122,6 +130,11 @@ internal void SendTestCases(string source, IEnumerable testElem continue; } + if (testElement.TestMethod.ActualData is { } actualData) + { + TestCaseToDataDictionary.Add(testCase, actualData); + } + if (!hasAnyRunnableTests) { hasAnyRunnableTests = !hasFixtureTraits; diff --git a/src/Adapter/MSTest.TestAdapter/Constants.cs b/src/Adapter/MSTestAdapter.PlatformServices/EngineConstants.cs similarity index 92% rename from src/Adapter/MSTest.TestAdapter/Constants.cs rename to src/Adapter/MSTestAdapter.PlatformServices/EngineConstants.cs index 7052dcda1a..d7b3b0e940 100644 --- a/src/Adapter/MSTest.TestAdapter/Constants.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/EngineConstants.cs @@ -3,14 +3,32 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; -namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; +namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; -/// -/// Constants used throughout. -/// -internal static class Constants +internal static class EngineConstants { - internal const string PublicTypeObsoleteMessage = "We will remove or hide this type starting with v4. If you are using this type, reach out to our team on https://github.com/microsoft/testfx."; +#if NETFRAMEWORK + /// + /// Constants for detecting .net framework. + /// + public const string TargetFrameworkAttributeFullName = "System.Runtime.Versioning.TargetFrameworkAttribute"; + + public const string DotNetFrameWorkStringPrefix = ".NETFramework,Version="; + + public const string TargetFrameworkName = "TargetFrameworkName"; + + public const string PublicAssemblies = "PublicAssemblies"; + + public const string PrivateAssemblies = "PrivateAssemblies"; +#endif + + internal const string DllExtension = ".dll"; + internal const string ExeExtension = ".exe"; + internal const string AppxPackageExtension = ".appx"; + +#if NETFRAMEWORK + internal const string PhoneAppxPackageExtension = ".appx"; +#endif /// /// The 3rd level entry (class) name in the hierarchy array. @@ -42,23 +60,12 @@ internal static class Constants /// internal const string ClassCleanupFixtureTrait = "ClassCleanup"; - /// - /// Uri of the MSTest executor. - /// - internal const string ExecutorUriString = "executor://MSTestAdapter/v2"; - /// /// The name of test run parameters node in the runsettings. /// internal const string TestRunParametersName = "TestRunParameters"; - /// - /// The executor uri for this adapter. - /// - internal static readonly Uri ExecutorUri = new(ExecutorUriString); - #region Test Property registration - internal static readonly TestProperty DescriptionProperty = TestProperty.Register("Description", DescriptionLabel, typeof(string), TestPropertyAttributes.Hidden, typeof(TestCase)); internal static readonly TestProperty WorkItemIdsProperty = TestProperty.Register("WorkItemIds", WorkItemIdsLabel, typeof(string[]), TestPropertyAttributes.Hidden, typeof(TestCase)); @@ -141,7 +148,6 @@ internal static class Constants private const string ExecutionIdLabel = "ExecutionId"; private const string ParentExecIdLabel = "ParentExecId"; private const string InnerResultsCountLabel = "InnerResultsCount"; - private const string DescriptionLabel = "Description"; private const string CssIterationLabel = "CssIteration"; private const string CssProjectStructureLabel = "CssProjectStructure"; private const string WorkItemIdsLabel = "WorkItemIds"; @@ -163,4 +169,14 @@ internal static class Constants private const string TfsTeamProject = "__Tfs_TeamProject__"; #endregion + + /// + /// Uri of the MSTest executor. + /// + internal const string ExecutorUriString = "executor://MSTestAdapter/v2"; + + /// + /// The executor uri for this adapter. + /// + internal static readonly Uri ExecutorUri = new(ExecutorUriString); } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/ClassCleanupManager.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/ClassCleanupManager.cs new file mode 100644 index 0000000000..0fbfdb5bff --- /dev/null +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/ClassCleanupManager.cs @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; + +internal sealed class ClassCleanupManager +{ + private readonly ClassCleanupBehavior _lifecycleFromMsTestOrAssembly; + private readonly ReflectHelper _reflectHelper; + private readonly ConcurrentDictionary _remainingTestCountsByClass; + + public ClassCleanupManager( + IEnumerable testsToRun, + ClassCleanupBehavior lifecycleFromMsTestOrAssembly, + ReflectHelper reflectHelper) + { + IEnumerable runnableTests = testsToRun.Where(t => t.Traits is null || !t.Traits.Any(t => t.Name == EngineConstants.FixturesTestTrait)); + _remainingTestCountsByClass = + new(runnableTests.GroupBy(t => t.TestMethod.FullClassName) + .ToDictionary( + g => g.Key, + g => g.Count())); + _lifecycleFromMsTestOrAssembly = lifecycleFromMsTestOrAssembly; + _reflectHelper = reflectHelper; + } + + public bool ShouldRunEndOfAssemblyCleanup => _remainingTestCountsByClass.IsEmpty; + + public void MarkTestComplete(TestMethodInfo testMethodInfo, out bool shouldRunEndOfClassCleanup) + { + shouldRunEndOfClassCleanup = false; + + lock (_remainingTestCountsByClass) + { + if (!_remainingTestCountsByClass.TryGetValue(testMethodInfo.TestClassName, out int remainingCount)) + { + return; + } + + remainingCount--; + _remainingTestCountsByClass[testMethodInfo.TestClassName] = remainingCount; + if (remainingCount == 0) + { + _remainingTestCountsByClass.TryRemove(testMethodInfo.TestClassName, out _); + if (testMethodInfo.Parent.HasExecutableCleanupMethod) + { + ClassCleanupBehavior cleanupLifecycle = GetClassCleanupBehavior(testMethodInfo.Parent); + + shouldRunEndOfClassCleanup = cleanupLifecycle == ClassCleanupBehavior.EndOfClass; + } + } + } + } + + /// + /// Gets the class cleanup lifecycle for the class, if set. + /// + /// The class to inspect. + /// Returns if provided, otherwise null. + private ClassCleanupBehavior GetClassCleanupBehavior(TestClassInfo classInfo) + { + // TODO: not discovery related but seems expensive and unnecessary, because we do inheritance lookup, and to put the method into the stack we've already did this lookup before? + DebugEx.Assert(classInfo.HasExecutableCleanupMethod, "'GetClassCleanupBehavior' should only be called if 'HasExecutableCleanupMethod' is true"); + + bool hasEndOfAssembly = false; + if (classInfo.ClassCleanupMethod is not null) + { + ClassCleanupBehavior? cleanupBehavior = _reflectHelper.GetFirstAttributeOrDefault(classInfo.ClassCleanupMethod, inherit: true)?.CleanupBehavior; + if (cleanupBehavior == ClassCleanupBehavior.EndOfClass) + { + return ClassCleanupBehavior.EndOfClass; + } + else if (cleanupBehavior == ClassCleanupBehavior.EndOfAssembly) + { + hasEndOfAssembly = true; + } + } + + foreach (MethodInfo baseClassCleanupMethod in classInfo.BaseClassCleanupMethods) + { + ClassCleanupBehavior? cleanupBehavior = _reflectHelper.GetFirstAttributeOrDefault(baseClassCleanupMethod, inherit: true)?.CleanupBehavior; + if (cleanupBehavior == ClassCleanupBehavior.EndOfClass) + { + return ClassCleanupBehavior.EndOfClass; + } + else if (cleanupBehavior == ClassCleanupBehavior.EndOfAssembly) + { + hasEndOfAssembly = true; + } + } + + return hasEndOfAssembly ? ClassCleanupBehavior.EndOfAssembly : _lifecycleFromMsTestOrAssembly; + } + + internal static void ForceCleanup(TypeCache typeCache, IDictionary sourceLevelParameters, IMessageLogger logger) + { + TestContext testContext = new TestContextImplementation(null, sourceLevelParameters, logger, testRunCancellationToken: null); + IEnumerable classInfoCache = typeCache.ClassInfoListWithExecutableCleanupMethods; + foreach (TestClassInfo classInfo in classInfoCache) + { + TestFailedException? ex = classInfo.ExecuteClassCleanup(testContext); + if (ex is not null) + { + throw ex; + } + } + + IEnumerable assemblyInfoCache = typeCache.AssemblyInfoListWithExecutableCleanupMethods; + foreach (TestAssemblyInfo assemblyInfo in assemblyInfoCache) + { + TestFailedException? ex = assemblyInfo.ExecuteAssemblyCleanup(testContext); + if (ex is not null) + { + throw ex; + } + } + } +} diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/ConsoleErrorRouter.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/ConsoleErrorRouter.cs new file mode 100644 index 0000000000..7ca55cf1f2 --- /dev/null +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/ConsoleErrorRouter.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; + +namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; + +internal sealed class ConsoleErrorRouter : TextWriter +{ + private readonly TextWriter _originalConsoleErr; + + public ConsoleErrorRouter(TextWriter originalConsoleErr) + => _originalConsoleErr = originalConsoleErr; + + public override Encoding Encoding => Encoding.UTF8; + + public override void Write(char value) + { + if (TestContextImplementation.CurrentTestContext is { } testContext) + { + testContext.WriteConsoleErr(value); + } + else + { + _originalConsoleErr.Write(value); + } + } + + public override void Write(string? value) + { + if (TestContextImplementation.CurrentTestContext is { } testContext) + { + testContext.WriteConsoleErr(value); + } + else + { + _originalConsoleErr.Write(value); + } + } + + public override void Write(char[] buffer, int index, int count) + { + if (TestContextImplementation.CurrentTestContext is { } testContext) + { + testContext.WriteConsoleErr(buffer, index, count); + } + else + { + _originalConsoleErr.Write(buffer, index, count); + } + } +} diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/ConsoleOutRouter.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/ConsoleOutRouter.cs new file mode 100644 index 0000000000..c4774ec629 --- /dev/null +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/ConsoleOutRouter.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; + +namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; + +internal sealed class ConsoleOutRouter : TextWriter +{ + private readonly TextWriter _originalConsoleOut; + + public ConsoleOutRouter(TextWriter originalConsoleOut) + => _originalConsoleOut = originalConsoleOut; + + public override Encoding Encoding => Encoding.UTF8; + + public override void Write(char value) + { + if (TestContextImplementation.CurrentTestContext is { } testContext) + { + testContext.WriteConsoleOut(value); + } + else + { + _originalConsoleOut.Write(value); + } + } + + public override void Write(string? value) + { + if (TestContextImplementation.CurrentTestContext is { } testContext) + { + testContext.WriteConsoleOut(value); + } + else + { + _originalConsoleOut.Write(value); + } + } + + public override void Write(char[] buffer, int index, int count) + { + if (TestContextImplementation.CurrentTestContext is { } testContext) + { + testContext.WriteConsoleOut(buffer, index, count); + } + else + { + _originalConsoleOut.Write(buffer, index, count); + } + } +} diff --git a/src/Adapter/MSTest.TestAdapter/Execution/ExceptionHelper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/ExceptionHelper.cs similarity index 91% rename from src/Adapter/MSTest.TestAdapter/Execution/ExceptionHelper.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/ExceptionHelper.cs index f4820a5be7..8e774940c0 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/ExceptionHelper.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/ExceptionHelper.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; @@ -15,7 +16,7 @@ internal static class ExceptionHelper /// Gets the types whose methods should be ignored in the reported call stacks. /// This is used to remove our stack that the user will not care about. /// - private static readonly List TypesToBeExcluded = [typeof(Assert).Namespace!, typeof(MSTestExecutor).Namespace!]; + private static readonly List TypesToBeExcluded = [typeof(Assert).Namespace!, "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter"]; /// /// Gets the stack trace for an exception, including all stack traces for inner @@ -83,7 +84,7 @@ internal static class ExceptionHelper first = false; } - return CreateStackTraceInformation(ex, true, result.ToString()); + return CreateStackTraceInformation(result.ToString()); } /// @@ -173,28 +174,14 @@ internal static string GetFormattedExceptionMessage(this Exception ex) /// /// Create stack trace information. /// - /// - /// The exception. - /// - /// - /// Whether the inner exception needs to be checked too. - /// /// /// The stack Trace String. /// /// /// The . /// - internal static StackTraceInformation? CreateStackTraceInformation( - Exception ex, - bool checkInnerExceptions, - string stackTraceString) + internal static StackTraceInformation? CreateStackTraceInformation(string stackTraceString) { - if (checkInnerExceptions && ex.InnerException != null) - { - return CreateStackTraceInformation(ex.InnerException, checkInnerExceptions, stackTraceString); - } - string stackTrace = TrimStackTrace(stackTraceString); return !StringEx.IsNullOrEmpty(stackTrace) ? new StackTraceInformation(stackTrace, null, 0, 0) : null; diff --git a/src/Adapter/MSTest.TestAdapter/Execution/LogMessageListener.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/LogMessageListener.cs similarity index 97% rename from src/Adapter/MSTest.TestAdapter/Execution/LogMessageListener.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/LogMessageListener.cs index a3e3581682..f58c8ce44f 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/LogMessageListener.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/LogMessageListener.cs @@ -12,9 +12,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; /// Note that this class is not thread-safe and thus should only be used when unit tests are being run serially. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class LogMessageListener : IDisposable { @@ -169,5 +169,7 @@ public void Dispose() s_listenerCount--; } + + GC.SuppressFinalize(this); } } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TcmTestPropertiesProvider.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TcmTestPropertiesProvider.cs new file mode 100644 index 0000000000..5a80df389a --- /dev/null +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TcmTestPropertiesProvider.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; + +using TestPlatformObjectModel = Microsoft.VisualStudio.TestPlatform.ObjectModel; + +namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; + +/// +/// Reads and parses the TcmTestProperties in order to populate them in TestRunParameters. +/// +internal static class TcmTestPropertiesProvider +{ + /// + /// Gets tcm properties from test case. + /// + /// Test case. + /// Tcm properties. + public static IDictionary GetTcmProperties(TestPlatformObjectModel.TestCase? testCase) + { + var tcmProperties = new Dictionary(); + + // Return empty properties when testCase is null or when test case id is zero. + if (testCase == null || + testCase.GetPropertyValue(EngineConstants.TestCaseIdProperty, default) == 0) + { + return tcmProperties; + } + + // Step 1: Add common properties. + tcmProperties[EngineConstants.TestRunIdProperty] = testCase.GetPropertyValue(EngineConstants.TestRunIdProperty, default); + tcmProperties[EngineConstants.TestPlanIdProperty] = testCase.GetPropertyValue(EngineConstants.TestPlanIdProperty, default); + tcmProperties[EngineConstants.BuildConfigurationIdProperty] = testCase.GetPropertyValue(EngineConstants.BuildConfigurationIdProperty, default); + tcmProperties[EngineConstants.BuildDirectoryProperty] = testCase.GetPropertyValue(EngineConstants.BuildDirectoryProperty, default); + tcmProperties[EngineConstants.BuildFlavorProperty] = testCase.GetPropertyValue(EngineConstants.BuildFlavorProperty, default); + tcmProperties[EngineConstants.BuildNumberProperty] = testCase.GetPropertyValue(EngineConstants.BuildNumberProperty, default); + tcmProperties[EngineConstants.BuildPlatformProperty] = testCase.GetPropertyValue(EngineConstants.BuildPlatformProperty, default); + tcmProperties[EngineConstants.BuildUriProperty] = testCase.GetPropertyValue(EngineConstants.BuildUriProperty, default); + tcmProperties[EngineConstants.TfsServerCollectionUrlProperty] = testCase.GetPropertyValue(EngineConstants.TfsServerCollectionUrlProperty, default); + tcmProperties[EngineConstants.TfsTeamProjectProperty] = testCase.GetPropertyValue(EngineConstants.TfsTeamProjectProperty, default); + tcmProperties[EngineConstants.IsInLabEnvironmentProperty] = testCase.GetPropertyValue(EngineConstants.IsInLabEnvironmentProperty, default); + + // Step 2: Add test case specific properties. + tcmProperties[EngineConstants.TestCaseIdProperty] = testCase.GetPropertyValue(EngineConstants.TestCaseIdProperty, default); + tcmProperties[EngineConstants.TestConfigurationIdProperty] = testCase.GetPropertyValue(EngineConstants.TestConfigurationIdProperty, default); + tcmProperties[EngineConstants.TestConfigurationNameProperty] = testCase.GetPropertyValue(EngineConstants.TestConfigurationNameProperty, default); + tcmProperties[EngineConstants.TestPointIdProperty] = testCase.GetPropertyValue(EngineConstants.TestPointIdProperty, default); + + return tcmProperties; + } +} diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestAssemblyInfo.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestAssemblyInfo.cs similarity index 87% rename from src/Adapter/MSTest.TestAdapter/Execution/TestAssemblyInfo.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/TestAssemblyInfo.cs index e3155f5def..c9afd88c68 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/TestAssemblyInfo.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestAssemblyInfo.cs @@ -4,6 +4,8 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; using Microsoft.VisualStudio.TestTools.UnitTesting; using UnitTestOutcome = Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome; @@ -14,9 +16,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; /// Defines TestAssembly Info object. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TestAssemblyInfo { @@ -29,6 +31,10 @@ public class TestAssemblyInfo internal TestAssemblyInfo(Assembly assembly) => Assembly = assembly; + internal List<(MethodInfo Method, TimeoutInfo? TimeoutInfo)> GlobalTestInitializations { get; } = []; + + internal List<(MethodInfo Method, TimeoutInfo? TimeoutInfo)> GlobalTestCleanups { get; } = []; + /// /// Gets AssemblyInitialize method for the assembly. /// @@ -112,13 +118,7 @@ internal set /// The test context. /// Throws a test failed exception if the initialization method throws an exception. public void RunAssemblyInitialize(TestContext testContext) - => RunAssemblyInitialize(testContext, out _); - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")] - internal void RunAssemblyInitialize(TestContext testContext, out LogMessageListener? logListener) { - logListener = null; - // No assembly initialize => nothing to do. if (AssemblyInitializeMethod == null) { @@ -144,15 +144,18 @@ internal void RunAssemblyInitialize(TestContext testContext, out LogMessageListe // Perform a check again. if (!IsAssemblyInitializeExecuted) { - LogMessageListener? logMessageListener = null; - try { AssemblyInitializationException = FixtureMethodRunner.RunWithTimeoutAndCancellation( () => { - logMessageListener = new LogMessageListener(MSTestSettings.CurrentSettings.CaptureDebugTraces); - AssemblyInitializeMethod.InvokeAsSynchronousTask(null, testContext); + // NOTE: It's unclear what the effect is if we reset the current test context before vs after the capture. + // It's safer to reset it before the capture. + using (TestContextImplementation.SetCurrentTestContext(testContext as TestContextImplementation)) + { + AssemblyInitializeMethod.InvokeAsSynchronousTask(null, testContext); + } + // **After** we have executed the assembly initialize, we save the current context. // This context will contain async locals set by the assembly initialize method. ExecutionContext = ExecutionContext.Capture(); @@ -171,7 +174,6 @@ internal void RunAssemblyInitialize(TestContext testContext, out LogMessageListe finally { IsAssemblyInitializeExecuted = true; - logListener = logMessageListener; } } } @@ -278,7 +280,7 @@ internal void RunAssemblyInitialize(TestContext testContext, out LogMessageListe /// It is a replacement for RunAssemblyCleanup but as we are in a bug-fix version, we do not want to touch /// public API and so we introduced this method. /// - internal TestFailedException? ExecuteAssemblyCleanup(TestContext testContext, ref LogMessageListener? logListener) + internal TestFailedException? ExecuteAssemblyCleanup(TestContext testContext) { if (AssemblyCleanupMethod == null) { @@ -287,20 +289,23 @@ internal void RunAssemblyInitialize(TestContext testContext, out LogMessageListe lock (_assemblyInfoExecuteSyncObject) { - LogMessageListener? logMessageListener = logListener; try { AssemblyCleanupException = FixtureMethodRunner.RunWithTimeoutAndCancellation( () => { - logMessageListener ??= new LogMessageListener(MSTestSettings.CurrentSettings.CaptureDebugTraces); - if (AssemblyCleanupMethod.GetParameters().Length == 0) - { - AssemblyCleanupMethod.InvokeAsSynchronousTask(null); - } - else + // NOTE: It's unclear what the effect is if we reset the current test context before vs after the capture. + // It's safer to reset it before the capture. + using (TestContextImplementation.SetCurrentTestContext(testContext as TestContextImplementation)) { - AssemblyCleanupMethod.InvokeAsSynchronousTask(null, testContext); + if (AssemblyCleanupMethod.GetParameters().Length == 0) + { + AssemblyCleanupMethod.InvokeAsSynchronousTask(null); + } + else + { + AssemblyCleanupMethod.InvokeAsSynchronousTask(null, testContext); + } } ExecutionContext = ExecutionContext.Capture(); @@ -316,10 +321,6 @@ internal void RunAssemblyInitialize(TestContext testContext, out LogMessageListe { AssemblyCleanupException = ex; } - finally - { - logListener = logMessageListener; - } } // If assemblyCleanup was successful, then don't do anything diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestAssemblySettingsProvider.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestAssemblySettingsProvider.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Execution/TestAssemblySettingsProvider.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/TestAssemblySettingsProvider.cs diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestCaseDiscoverySink.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestCaseDiscoverySink.cs similarity index 92% rename from src/Adapter/MSTest.TestAdapter/Execution/TestCaseDiscoverySink.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/TestCaseDiscoverySink.cs index 2315b67113..8ae3f43e28 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/TestCaseDiscoverySink.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestCaseDiscoverySink.cs @@ -14,7 +14,7 @@ internal sealed class TestCaseDiscoverySink : ITestCaseDiscoverySink /// /// Gets the tests. /// - public ICollection Tests { get; } = new List(); + public ICollection Tests { get; } = []; /// /// Sends the test case. diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestClassInfo.cs similarity index 85% rename from src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/TestClassInfo.cs index 8d7b2cda24..8243abc9fb 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestClassInfo.cs @@ -4,6 +4,8 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -15,9 +17,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; /// Defines the TestClassInfo object. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TestClassInfo { @@ -102,25 +104,25 @@ internal set /// Gets the timeout for the class initialize methods. /// We can use a dictionary because the MethodInfo is unique in an inheritance hierarchy. /// - internal Dictionary ClassInitializeMethodTimeoutMilliseconds { get; } = new(); + internal Dictionary ClassInitializeMethodTimeoutMilliseconds { get; } = []; /// /// Gets the timeout for the class cleanup methods. /// We can use a dictionary because the MethodInfo is unique in an inheritance hierarchy. /// - internal Dictionary ClassCleanupMethodTimeoutMilliseconds { get; } = new(); + internal Dictionary ClassCleanupMethodTimeoutMilliseconds { get; } = []; /// /// Gets the timeout for the test initialize methods. /// We can use a dictionary because the MethodInfo is unique in an inheritance hierarchy. /// - internal Dictionary TestInitializeMethodTimeoutMilliseconds { get; } = new(); + internal Dictionary TestInitializeMethodTimeoutMilliseconds { get; } = []; /// /// Gets the timeout for the test cleanup methods. /// We can use a dictionary because the MethodInfo is unique in an inheritance hierarchy. /// - internal Dictionary TestCleanupMethodTimeoutMilliseconds { get; } = new(); + internal Dictionary TestCleanupMethodTimeoutMilliseconds { get; } = []; /// /// Gets a value indicating whether class initialize has executed. @@ -138,9 +140,9 @@ internal set [Obsolete("API will be dropped in v4")] public Stack BaseClassCleanupMethodsStack { get; } = new(); - internal List BaseClassInitMethods { get; } = new(); + internal List BaseClassInitMethods { get; } = []; - internal List BaseClassCleanupMethods { get; } = new(); + internal List BaseClassCleanupMethods { get; } = []; /// /// Gets the exception thrown during method invocation. @@ -248,13 +250,7 @@ internal set /// The test context. /// Throws a test failed exception if the initialization method throws an exception. public void RunClassInitialize(TestContext testContext) - => RunClassInitialize(testContext, out _); - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")] - internal void RunClassInitialize(TestContext testContext, out LogMessageListener? logListener) { - logListener = null; - // If no class initialize and no base class initialize, return if (ClassInitializeMethod is null && BaseClassInitMethods.Count == 0) { @@ -285,7 +281,7 @@ internal void RunClassInitialize(TestContext testContext, out LogMessageListener for (int i = BaseClassInitMethods.Count - 1; i >= 0; i--) { initializeMethod = BaseClassInitMethods[i]; - ClassInitializationException = InvokeInitializeMethod(initializeMethod, testContext, ref logListener); + ClassInitializationException = InvokeInitializeMethod(initializeMethod, testContext); if (ClassInitializationException is not null) { break; @@ -295,7 +291,7 @@ internal void RunClassInitialize(TestContext testContext, out LogMessageListener if (ClassInitializationException is null) { initializeMethod = ClassInitializeMethod; - ClassInitializationException = InvokeInitializeMethod(ClassInitializeMethod, testContext, ref logListener); + ClassInitializationException = InvokeInitializeMethod(ClassInitializeMethod, testContext); } } catch (Exception ex) @@ -359,7 +355,7 @@ internal void RunClassInitialize(TestContext testContext, out LogMessageListener TestFailureException = _classInitializeResult.TestFailureException, }; - internal TestResult GetResultOrRunClassInitialize(ITestContext testContext, string initializationLogs, string initializationErrorLogs, string initializationTrace, string initializationTestContextMessages) + internal TestResult GetResultOrRunClassInitialize(ITestContext testContext, string? initializationLogs, string? initializationErrorLogs, string? initializationTrace, string? initializationTestContextMessages) { TestResult? clonedInitializeResult = TryGetClonedCachedClassInitializeResult(); @@ -399,7 +395,7 @@ internal TestResult GetResultOrRunClassInitialize(ITestContext testContext, stri DebugEx.Assert(!IsClassInitializeExecuted, "If class initialize was executed, we should have been in the previous if were we have a result available."); - bool isSTATestClass = AttributeComparer.IsDerived(ClassAttribute); + bool isSTATestClass = ClassAttribute is STATestClassAttribute; bool isWindowsOS = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); if (isSTATestClass && isWindowsOS @@ -456,26 +452,8 @@ TestResult DoRun() try { - LogMessageListener? logListener = null; - try - { - // This runs the ClassInitialize methods only once but saves the - RunClassInitialize(testContext.Context, out logListener); - } - finally - { - if (logListener is not null) - { - ExecutionContextHelpers.RunOnContext(ExecutionContext, () => - { - initializationLogs += logListener.GetAndClearStandardOutput(); - initializationTrace += logListener.GetAndClearDebugTrace(); - initializationErrorLogs += logListener.GetAndClearStandardError(); - initializationTestContextMessages += testContext.GetAndClearDiagnosticMessages(); - logListener?.Dispose(); - }); - } - } + // This runs the ClassInitialize methods only once but saves the + RunClassInitialize(testContext.Context); } catch (TestFailedException ex) { @@ -492,10 +470,11 @@ TestResult DoRun() finally { // Assembly initialize and class initialize logs are pre-pended to the first result. - result.LogOutput = initializationLogs; - result.LogError = initializationErrorLogs; - result.DebugTrace = initializationTrace; - result.TestContextMessages = initializationTestContextMessages; + var testContextImpl = testContext as TestContextImplementation; + result.LogOutput = initializationLogs + testContextImpl?.GetOut(); + result.LogError = initializationErrorLogs + testContextImpl?.GetErr(); + result.DebugTrace = initializationTrace + testContextImpl?.GetTrace(); + result.TestContextMessages = initializationTestContextMessages + testContext.GetAndClearDiagnosticMessages(); } _classInitializeResult = result; @@ -503,7 +482,7 @@ TestResult DoRun() } } - private TestFailedException? InvokeInitializeMethod(MethodInfo? methodInfo, TestContext testContext, ref LogMessageListener? logListener) + private TestFailedException? InvokeInitializeMethod(MethodInfo? methodInfo, TestContext testContext) { if (methodInfo is null) { @@ -516,12 +495,16 @@ TestResult DoRun() timeout = localTimeout; } - LogMessageListener? logMessageListener = logListener; TestFailedException? result = FixtureMethodRunner.RunWithTimeoutAndCancellation( () => { - logMessageListener ??= new LogMessageListener(MSTestSettings.CurrentSettings.CaptureDebugTraces); - methodInfo.InvokeAsSynchronousTask(null, testContext); + // NOTE: It's unclear what the effect is if we reset the current test context before vs after the capture. + // It's safer to reset it before the capture. + using (TestContextImplementation.SetCurrentTestContext(testContext as TestContextImplementation)) + { + methodInfo.InvokeAsSynchronousTask(null, testContext); + } + // **After** we have executed the class initialize, we save the current context. // This context will contain async locals set by the class initialize method. ExecutionContext = ExecutionContext.Capture(); @@ -532,7 +515,7 @@ TestResult DoRun() ExecutionContext ?? Parent?.ExecutionContext, Resource.ClassInitializeWasCancelled, Resource.ClassInitializeTimedOut); - logListener = logMessageListener; + return result; } @@ -569,13 +552,12 @@ TestResult DoRun() try { classCleanupMethod = ClassCleanupMethod; - LogMessageListener? listener = null; - ClassCleanupException = classCleanupMethod is not null ? InvokeCleanupMethod(classCleanupMethod, null!, ref listener) : null; + ClassCleanupException = classCleanupMethod is not null ? InvokeCleanupMethod(classCleanupMethod, null!) : null; var baseClassCleanupQueue = new Queue(BaseClassCleanupMethods); while (baseClassCleanupQueue.Count > 0 && ClassCleanupException is null) { classCleanupMethod = baseClassCleanupQueue.Dequeue(); - ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, null!, ref listener); + ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, null!); } IsClassCleanupExecuted = ClassCleanupException is null; @@ -627,10 +609,8 @@ TestResult DoRun() /// This is a replacement for RunClassCleanup but as we are on a bug fix version, we do not want to change /// the public API, hence this method. /// - internal TestFailedException? ExecuteClassCleanup(TestContext testContext, out LogMessageListener? logListener) + internal TestFailedException? ExecuteClassCleanup(TestContext testContext) { - logListener = null; - if ((ClassCleanupMethod is null && BaseClassCleanupMethods.Count == 0) || IsClassCleanupExecuted) { @@ -657,7 +637,7 @@ TestResult DoRun() { if (!classCleanupMethod.DeclaringType!.IsIgnored(out _)) { - ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, testContext, ref logListener); + ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, testContext); } } @@ -668,7 +648,7 @@ TestResult DoRun() classCleanupMethod = BaseClassCleanupMethods[i]; if (!classCleanupMethod.DeclaringType!.IsIgnored(out _)) { - ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, testContext, ref logListener); + ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, testContext); if (ClassCleanupException is not null) { break; @@ -724,16 +704,18 @@ TestResult DoRun() return testFailedException; } - internal void RunClassCleanup(ITestContext testContext, ClassCleanupManager classCleanupManager, TestMethodInfo testMethodInfo, TestMethod testMethod, TestResult[] results) + internal void RunClassCleanup(ITestContext testContext, ClassCleanupManager classCleanupManager, TestMethodInfo testMethodInfo, TestResult[] results) { DebugEx.Assert(testMethodInfo.Parent == this, "Parent of testMethodInfo should be this TestClassInfo."); - classCleanupManager.MarkTestComplete(testMethodInfo, testMethod, out bool shouldRunEndOfClassCleanup); + classCleanupManager.MarkTestComplete(testMethodInfo, out bool shouldRunEndOfClassCleanup); if (!shouldRunEndOfClassCleanup) { return; } + // TODO: Looks like 'ClassCleanupMethod is null && BaseClassCleanupMethods.Count == 0' is always false? + // shouldRunEndOfClassCleanup should be false if there are no class cleanup methods at all. if ((ClassCleanupMethod is null && BaseClassCleanupMethods.Count == 0) || IsClassCleanupExecuted) { @@ -741,7 +723,7 @@ internal void RunClassCleanup(ITestContext testContext, ClassCleanupManager clas return; } - bool isSTATestClass = AttributeComparer.IsDerived(ClassAttribute); + bool isSTATestClass = ClassAttribute is STATestClassAttribute; bool isWindowsOS = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); if (isSTATestClass && isWindowsOS @@ -778,38 +760,16 @@ internal void RunClassCleanup(ITestContext testContext, ClassCleanupManager clas // Local functions void DoRun() { - string? initializationLogs = string.Empty; - string? initializationErrorLogs = string.Empty; - string? initializationTrace = string.Empty; - string? initializationTestContextMessages = string.Empty; try { - LogMessageListener? logListener = null; - try + TestFailedException? ex = ExecuteClassCleanup(testContext.Context); + if (ex is not null && results.Length > 0) { - TestFailedException? ex = ExecuteClassCleanup(testContext.Context, out logListener); - if (ex is not null && results.Length > 0) - { #pragma warning disable IDE0056 // Use index operator - TestResult lastResult = results[results.Length - 1]; + TestResult lastResult = results[results.Length - 1]; #pragma warning restore IDE0056 // Use index operator - lastResult.Outcome = TestTools.UnitTesting.UnitTestOutcome.Error; - lastResult.TestFailureException = ex; - } - } - finally - { - if (logListener is not null) - { - ExecutionContextHelpers.RunOnContext(ExecutionContext, () => - { - initializationLogs = logListener.GetAndClearStandardOutput(); - initializationErrorLogs = logListener.GetAndClearStandardError(); - initializationTrace = logListener.GetAndClearDebugTrace(); - initializationTestContextMessages = testContext.GetAndClearDiagnosticMessages(); - logListener.Dispose(); - }); - } + lastResult.Outcome = TestTools.UnitTesting.UnitTestOutcome.Error; + lastResult.TestFailureException = ex; } } finally @@ -819,16 +779,17 @@ void DoRun() #pragma warning disable IDE0056 // Use index operator TestResult lastResult = results[results.Length - 1]; #pragma warning restore IDE0056 // Use index operator - lastResult.LogOutput += initializationLogs; - lastResult.LogError += initializationErrorLogs; - lastResult.DebugTrace += initializationTrace; - lastResult.TestContextMessages += initializationTestContextMessages; + var testContextImpl = testContext as TestContextImplementation; + lastResult.LogOutput += testContextImpl?.GetOut(); + lastResult.LogError += testContextImpl?.GetErr(); + lastResult.DebugTrace += testContextImpl?.GetTrace(); + lastResult.TestContextMessages += testContext.GetAndClearDiagnosticMessages(); } } } } - private TestFailedException? InvokeCleanupMethod(MethodInfo methodInfo, TestContext testContext, ref LogMessageListener? logListener) + private TestFailedException? InvokeCleanupMethod(MethodInfo methodInfo, TestContext testContext) { TimeoutInfo? timeout = null; if (ClassCleanupMethodTimeoutMilliseconds.TryGetValue(methodInfo, out TimeoutInfo localTimeout)) @@ -836,19 +797,21 @@ void DoRun() timeout = localTimeout; } - LogMessageListener? logMessageListener = logListener; TestFailedException? result = FixtureMethodRunner.RunWithTimeoutAndCancellation( () => { - logMessageListener ??= new LogMessageListener(MSTestSettings.CurrentSettings.CaptureDebugTraces); - - if (methodInfo.GetParameters().Length == 0) - { - methodInfo.InvokeAsSynchronousTask(null); - } - else + // NOTE: It's unclear what the effect is if we reset the current test context before vs after the capture. + // It's safer to reset it before the capture. + using (TestContextImplementation.SetCurrentTestContext(testContext as TestContextImplementation)) { - methodInfo.InvokeAsSynchronousTask(null, testContext); + if (methodInfo.GetParameters().Length == 0) + { + methodInfo.InvokeAsSynchronousTask(null); + } + else + { + methodInfo.InvokeAsSynchronousTask(null, testContext); + } } // **After** we have executed the class cleanup, we save the current context. @@ -863,7 +826,6 @@ void DoRun() Resource.ClassCleanupWasCancelled, Resource.ClassCleanupTimedOut); - logListener = logMessageListener; return result; } diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestExecutionManager.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs similarity index 93% rename from src/Adapter/MSTest.TestAdapter/Execution/TestExecutionManager.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs index bd5dde9130..5f88bfbea8 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/TestExecutionManager.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs @@ -4,20 +4,23 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; +using ExecutionScope = Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope; + namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; /// /// Class responsible for execution of tests at assembly level and sending tests via framework handle. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TestExecutionManager { @@ -159,7 +162,7 @@ internal async Task RunTestsAsync(IEnumerable tests, IRunContext? runC CacheSessionParameters(runContext, frameworkHandle); // Execute the tests - await ExecuteTestsAsync(tests, runContext, frameworkHandle, isDeploymentDone); + await ExecuteTestsAsync(tests, runContext, frameworkHandle, isDeploymentDone).ConfigureAwait(false); if (!_hasAnyTestFailed) { @@ -245,7 +248,7 @@ internal async Task RunTestsAsync(IEnumerable sources, IRunContext? runC CacheSessionParameters(runContext, frameworkHandle); // Run tests. - await ExecuteTestsAsync(tests, runContext, frameworkHandle, isDeploymentDone); + await ExecuteTestsAsync(tests, runContext, frameworkHandle, isDeploymentDone).ConfigureAwait(false); if (!_hasAnyTestFailed) { @@ -269,7 +272,7 @@ group test by test.Source into testGroup foreach (var group in testsBySource) { _testRunCancellationToken?.ThrowIfCancellationRequested(); - await ExecuteTestsInSourceAsync(group.Tests, runContext, frameworkHandle, group.Source, isDeploymentDone); + await ExecuteTestsInSourceAsync(group.Tests, runContext, frameworkHandle, group.Source, isDeploymentDone).ConfigureAwait(false); } } @@ -318,7 +321,7 @@ private static bool MatchTestFilter(ITestCaseFilterExpression? filterExpression, && !filterExpression.MatchTestCase(test, p => testMethodFilter.PropertyValueProvider(test, p))) { // If this is a fixture test, return true. Fixture tests are not filtered out and are always available for the status. - if (test.Traits.Any(t => t.Name == Constants.FixturesTestTrait)) + if (test.Traits.Any(t => t.Name == EngineConstants.FixturesTestTrait)) { return true; } @@ -348,7 +351,7 @@ private async Task ExecuteTestsInSourceAsync(IEnumerable tests, IRunCo } using MSTestAdapter.PlatformServices.Interface.ITestSourceHost isolationHost = PlatformServiceProvider.Instance.CreateTestSourceHost(source, runContext?.RunSettings, frameworkHandle); - bool usesAppDomains = isolationHost is MSTestAdapter.PlatformServices.TestSourceHost { UsesAppDomain: true }; + bool usesAppDomains = isolationHost is TestSourceHost { UsesAppDomain: true }; PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("Created unit-test runner {0}", source); // Default test set is filtered tests based on user provided filter criteria @@ -389,8 +392,8 @@ private async Task ExecuteTestsInSourceAsync(IEnumerable tests, IRunCo int parallelWorkers = sourceSettings.Workers; ExecutionScope parallelScope = sourceSettings.Scope; - TestCase[] testsToRun = tests.Where(t => MatchTestFilter(filterExpression, t, _testMethodFilter)).ToArray(); - UnitTestElement[] unitTestElements = testsToRun.Select(e => e.ToUnitTestElement(source)).ToArray(); + TestCase[] testsToRun = [.. tests.Where(t => MatchTestFilter(filterExpression, t, _testMethodFilter))]; + UnitTestElement[] unitTestElements = [.. testsToRun.Select(e => e.ToUnitTestElement(source))]; // Create an instance of a type defined in adapter so that adapter gets loaded in the child app domain var testRunner = (UnitTestRunner)isolationHost.CreateInstanceForType( typeof(UnitTestRunner), @@ -420,7 +423,7 @@ private async Task ExecuteTestsInSourceAsync(IEnumerable tests, IRunCo // Create test sets for execution, we can execute them in parallel based on parallel settings // Parallel and not parallel sets. - IEnumerable> testSets = testsToRun.GroupBy(t => t.GetPropertyValue(Constants.DoNotParallelizeProperty, false)); + IEnumerable> testSets = testsToRun.GroupBy(t => t.GetPropertyValue(EngineConstants.DoNotParallelizeProperty, false)); IGrouping? parallelizableTestSet = testSets.FirstOrDefault(g => !g.Key); IGrouping? nonParallelizableTestSet = testSets.FirstOrDefault(g => g.Key); @@ -437,7 +440,7 @@ private async Task ExecuteTestsInSourceAsync(IEnumerable tests, IRunCo break; case ExecutionScope.ClassLevel: - queue = new ConcurrentQueue>(parallelizableTestSet.GroupBy(t => t.GetPropertyValue(Constants.TestClassNameProperty) as string)); + queue = new ConcurrentQueue>(parallelizableTestSet.GroupBy(t => t.GetPropertyValue(EngineConstants.TestClassNameProperty) as string)); break; } @@ -457,7 +460,7 @@ private async Task ExecuteTestsInSourceAsync(IEnumerable tests, IRunCo if (queue.TryDequeue(out IEnumerable? testSet)) { - await ExecuteTestsWithTestRunnerAsync(testSet, frameworkHandle, source, sourceLevelParameters, testRunner, usesAppDomains); + await ExecuteTestsWithTestRunnerAsync(testSet, frameworkHandle, source, sourceLevelParameters, testRunner, usesAppDomains).ConfigureAwait(false); } } } @@ -469,7 +472,7 @@ private async Task ExecuteTestsInSourceAsync(IEnumerable tests, IRunCo try { - await Task.WhenAll(tasks); + await Task.WhenAll(tasks).ConfigureAwait(false); } catch (Exception ex) { @@ -483,12 +486,12 @@ private async Task ExecuteTestsInSourceAsync(IEnumerable tests, IRunCo // Queue the non parallel set if (nonParallelizableTestSet != null) { - await ExecuteTestsWithTestRunnerAsync(nonParallelizableTestSet, frameworkHandle, source, sourceLevelParameters, testRunner, usesAppDomains); + await ExecuteTestsWithTestRunnerAsync(nonParallelizableTestSet, frameworkHandle, source, sourceLevelParameters, testRunner, usesAppDomains).ConfigureAwait(false); } } else { - await ExecuteTestsWithTestRunnerAsync(testsToRun, frameworkHandle, source, sourceLevelParameters, testRunner, usesAppDomains); + await ExecuteTestsWithTestRunnerAsync(testsToRun, frameworkHandle, source, sourceLevelParameters, testRunner, usesAppDomains).ConfigureAwait(false); } if (PlatformServiceProvider.Instance.IsGracefulStopRequested) @@ -530,7 +533,7 @@ private async Task ExecuteTestsWithTestRunnerAsync( // If it is a fixture test, add it to the list of fixture tests and do not execute it. // It is executed by test itself. - if (currentTest.Traits.Any(t => t.Name == Constants.FixturesTestTrait)) + if (currentTest.Traits.Any(t => t.Name == EngineConstants.FixturesTestTrait)) { fixtureTests.Add(currentTest); continue; @@ -550,16 +553,21 @@ private async Task ExecuteTestsWithTestRunnerAsync( Dictionary testContextProperties = GetTestContextProperties(tcmProperties, sourceLevelParameters); TestTools.UnitTesting.TestResult[] unitTestResult; - if (usesAppDomains) + if (usesAppDomains || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) { #pragma warning disable VSTHRD103 // Call async methods when in an async method - We cannot do right now because we are crossing app domains. // TODO: When app domains support is dropped, we can finally always be calling the async version. + // In addition to app domains, if we are STA thread (e.g, because runsettings setting ExecutionApartmentState to STA), we want to preserve that. + // If we await, we could end up in a thread pool thread, which is not what we want. + // Alternatively, if we want to use RunSingleTestAsync for the case of STA, we should have: + // 1. A custom single threaded synchronization context that keeps us in STA. + // 2. Use ConfigureAwait(true). unitTestResult = testRunner.RunSingleTest(unitTestElement.TestMethod, testContextProperties, remotingMessageLogger); #pragma warning restore VSTHRD103 // Call async methods when in an async method } else { - unitTestResult = await testRunner.RunSingleTestAsync(unitTestElement.TestMethod, testContextProperties, remotingMessageLogger); + unitTestResult = await testRunner.RunSingleTestAsync(unitTestElement.TestMethod, testContextProperties, remotingMessageLogger).ConfigureAwait(false); } PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("Executed test {0}", unitTestElement.TestMethod.Name); @@ -588,7 +596,7 @@ private async Task ExecuteTestsWithTestRunnerAsync( continue; } - Trait trait = currentTest.Traits.First(t => t.Name == Constants.FixturesTestTrait); + Trait trait = currentTest.Traits.First(t => t.Name == EngineConstants.FixturesTestTrait); var unitTestElement = currentTest.ToUnitTestElement(source); FixtureTestResult fixtureTestResult = testRunner.GetFixtureTestResult(unitTestElement.TestMethod, trait.Value); diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestMethodInfo.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.cs similarity index 79% rename from src/Adapter/MSTest.TestAdapter/Execution/TestMethodInfo.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.cs index 6caf17ce4e..97af7c95f6 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/TestMethodInfo.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.cs @@ -18,9 +18,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; /// Defines the TestMethod Info object. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(Microsoft.VisualStudio.TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(Microsoft.VisualStudio.TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TestMethodInfo : ITestMethod { @@ -41,7 +41,7 @@ internal TestMethodInfo( DebugEx.Assert(testMethod != null, "TestMethod should not be null"); DebugEx.Assert(parent != null, "Parent should not be null"); - TestMethod = testMethod; + MethodInfo = testMethod; Parent = parent; TestContext = testContext; ExpectedException = ResolveExpectedException(); @@ -74,12 +74,12 @@ internal TestMethodInfo( /// /// Gets the parameter types of the test method. /// - public ParameterInfo[] ParameterTypes => TestMethod.GetParameters(); + public ParameterInfo[] ParameterTypes => MethodInfo.GetParameters(); /// /// Gets the return type of the test method. /// - public Type ReturnType => TestMethod.ReturnType; + public Type ReturnType => MethodInfo.ReturnType; /// /// Gets the name of the class declaring the test method. @@ -89,23 +89,18 @@ internal TestMethodInfo( /// /// Gets the name of the test method. /// - public string TestMethodName => TestMethod.Name; + public string TestMethodName => MethodInfo.Name; /// /// Gets the methodInfo for test method. /// - public MethodInfo MethodInfo => TestMethod; + public MethodInfo MethodInfo { get; } /// /// Gets the arguments with which test method is invoked. /// public object?[]? Arguments { get; private set; } - /// - /// Gets testMethod referred by this object. - /// - internal MethodInfo TestMethod { get; } - /// /// Gets the parent class Info object. /// @@ -121,7 +116,7 @@ internal TestMethodInfo( /// Whether or not getting the attributes that are inherited. /// An array of the attributes. public Attribute[]? GetAllAttributes(bool inherit) - => ReflectHelper.Instance.GetDerivedAttributes(TestMethod, inherit).ToArray(); + => [.. ReflectHelper.Instance.GetAttributes(MethodInfo, inherit)]; /// /// Gets all attributes of the test method. @@ -131,7 +126,7 @@ internal TestMethodInfo( /// An array of the attributes. public TAttributeType[] GetAttributes(bool inherit) where TAttributeType : Attribute - => ReflectHelper.Instance.GetDerivedAttributes(TestMethod, inherit).ToArray(); + => [.. ReflectHelper.Instance.GetAttributes(MethodInfo, inherit)]; /// public virtual TestResult Invoke(object?[]? arguments) @@ -152,23 +147,13 @@ public virtual async Task InvokeAsync(object?[]? arguments) // check if arguments are set for data driven tests arguments ??= Arguments; - LogMessageListener? listener = null; watch.Start(); - ExecutionContext? executionContext = Parent.ExecutionContext ?? Parent.Parent.ExecutionContext; - try { - ExecutionContextHelpers.RunOnContext(executionContext, () => - { - ThreadSafeStringWriter.CleanState(); - listener = new LogMessageListener(MSTestSettings.CurrentSettings.CaptureDebugTraces); - executionContext = ExecutionContext.Capture(); - }); - result = IsTimeoutSet - ? await ExecuteInternalWithTimeoutAsync(arguments, executionContext) - : await ExecuteInternalAsync(arguments, executionContext, null); + ? await ExecuteInternalWithTimeoutAsync(arguments).ConfigureAwait(false) + : await ExecuteInternalAsync(arguments, null).ConfigureAwait(false); } finally { @@ -177,30 +162,24 @@ public virtual async Task InvokeAsync(object?[]? arguments) if (result != null) { + var testContextImpl = TestContext as TestContextImplementation; + result.LogOutput = testContextImpl?.GetOut(); + result.LogError = testContextImpl?.GetErr(); + result.DebugTrace = testContextImpl?.GetTrace(); + result.TestContextMessages = TestContext?.GetAndClearDiagnosticMessages(); + result.ResultFiles = TestContext?.GetResultFiles(); result.Duration = watch.Elapsed; - if (listener is not null) - { - ExecutionContextHelpers.RunOnContext(executionContext, () => - { - result.DebugTrace = listener.GetAndClearDebugTrace(); - result.LogOutput = listener.GetAndClearStandardOutput(); - result.LogError = listener.GetAndClearStandardError(); - result.TestContextMessages = TestContext?.GetAndClearDiagnosticMessages(); - result.ResultFiles = TestContext?.GetResultFiles(); - listener.Dispose(); - }); - } } } - return result; + return result!; } internal void SetArguments(object?[]? arguments) => Arguments = arguments == null ? null : ResolveArguments(arguments); internal object?[] ResolveArguments(object?[] arguments) { - ParameterInfo[] parametersInfo = TestMethod.GetParameters(); + ParameterInfo[] parametersInfo = MethodInfo.GetParameters(); int requiredParameterCount = 0; bool hasParamsValue = false; object? paramsValues = null; @@ -279,8 +258,8 @@ public virtual async Task InvokeAsync(object?[]? arguments) /// The timeout value if defined in milliseconds. 0 if not defined. private TimeoutInfo GetTestTimeout() { - DebugEx.Assert(TestMethod != null, "TestMethod should be non-null"); - TimeoutAttribute? timeoutAttribute = ReflectHelper.Instance.GetFirstNonDerivedAttributeOrDefault(TestMethod, inherit: false); + DebugEx.Assert(MethodInfo != null, "TestMethod should be non-null"); + TimeoutAttribute? timeoutAttribute = ReflectHelper.Instance.GetFirstAttributeOrDefault(MethodInfo, inherit: false); if (timeoutAttribute is null) { return TimeoutInfo.FromTestTimeoutSettings(); @@ -288,7 +267,7 @@ private TimeoutInfo GetTestTimeout() if (!timeoutAttribute.HasCorrectTimeout) { - string message = string.Format(CultureInfo.CurrentCulture, Resource.UTA_ErrorInvalidTimeout, TestMethod.DeclaringType!.FullName, TestMethod.Name); + string message = string.Format(CultureInfo.CurrentCulture, Resource.UTA_ErrorInvalidTimeout, MethodInfo.DeclaringType!.FullName, MethodInfo.Name); throw new TypeInspectionException(message); } @@ -303,7 +282,7 @@ private TestMethodAttribute GetTestMethodAttribute() { // Get the derived TestMethod attribute from reflection. // It should be non-null as it was already validated by IsValidTestMethod. - TestMethodAttribute testMethodAttribute = ReflectHelper.Instance.GetFirstDerivedAttributeOrDefault(TestMethod, inherit: false)!; + TestMethodAttribute testMethodAttribute = ReflectHelper.Instance.GetFirstAttributeOrDefault(MethodInfo, inherit: false)!; // Get the derived TestMethod attribute from Extended TestClass Attribute // If the extended TestClass Attribute doesn't have extended TestMethod attribute then base class returns back the original testMethod Attribute @@ -323,7 +302,7 @@ private TestMethodAttribute GetTestMethodAttribute() try { - expectedExceptions = ReflectHelper.Instance.GetDerivedAttributes(TestMethod, inherit: true); + expectedExceptions = ReflectHelper.Instance.GetAttributes(MethodInfo, inherit: true); } catch (Exception ex) { @@ -333,7 +312,7 @@ private TestMethodAttribute GetTestMethodAttribute() CultureInfo.CurrentCulture, Resource.UTA_ExpectedExceptionAttributeConstructionException, Parent.ClassType.FullName, - TestMethod.Name, + MethodInfo.Name, ex.GetFormattedExceptionMessage()); throw new TypeInspectionException(errorMessage); } @@ -359,7 +338,7 @@ private TestMethodAttribute GetTestMethodAttribute() /// private RetryBaseAttribute? GetRetryAttribute() { - IEnumerable attributes = ReflectHelper.Instance.GetDerivedAttributes(TestMethod, inherit: true); + IEnumerable attributes = ReflectHelper.Instance.GetAttributes(MethodInfo, inherit: true); using IEnumerator enumerator = attributes.GetEnumerator(); if (!enumerator.MoveNext()) { @@ -385,7 +364,7 @@ private void ThrowMultipleAttributesException(string attributeName) CultureInfo.CurrentCulture, Resource.UTA_MultipleAttributesOnTestMethod, Parent.ClassType.FullName, - TestMethod.Name, + MethodInfo.Name, attributeName); throw new TypeInspectionException(errorMessage); } @@ -394,66 +373,117 @@ private void ThrowMultipleAttributesException(string attributeName) /// Execute test without timeout. /// /// Arguments to be passed to the method. - /// The execution context to execute the test method on. /// The timeout token source. /// The result of the execution. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")] - private async Task ExecuteInternalAsync(object?[]? arguments, ExecutionContext? executionContext, CancellationTokenSource? timeoutTokenSource) + private async Task ExecuteInternalAsync(object?[]? arguments, CancellationTokenSource? timeoutTokenSource) { - DebugEx.Assert(TestMethod != null, "UnitTestExecuter.DefaultTestMethodInvoke: testMethod = null."); + DebugEx.Assert(MethodInfo != null, "UnitTestExecuter.DefaultTestMethodInvoke: testMethod = null."); var result = new TestResult(); - // TODO remove dry violation with TestMethodRunner - ExecutionContextHelpers.RunOnContext(executionContext, () => - { - _classInstance = CreateTestClassInstance(result); - executionContext = ExecutionContext.Capture(); - }); bool isExceptionThrown = false; bool hasTestInitializePassed = false; Exception? testRunnerException = null; _isTestCleanupInvoked = false; + ExecutionContext? executionContext = null; try { try { - if (_classInstance != null && SetTestContext(_classInstance, result)) + // We invoke global test initialize methods before creating the test class instance. + // We consider the test class constructor as a "local" initialization. + // We want to invoke first the global initializations, then local ones, then test method. + // After that, we invoke local cleanups (including Dispose) and finally global cleanups at last. + foreach ((MethodInfo method, TimeoutInfo? timeoutInfo) in Parent.Parent.GlobalTestInitializations) + { + InvokeGlobalInitializeMethod(method, ref executionContext, timeoutInfo, timeoutTokenSource); + } + + // TODO remove dry violation with TestMethodRunner + bool setTestContextSucessful = false; + if (executionContext is null) + { + _classInstance = CreateTestClassInstance(result); + setTestContextSucessful = _classInstance != null && SetTestContext(_classInstance, result); + } + else + { + // The whole ExecuteInternalAsync method is already running on the execution context we got after class init. + // However, if the global test initialize call above is using a non-cooperative timeout, it will + // need to capture the execution context from the thread running it (after it has finished). + // This is the case when executionContext is not null (this code path). + // In this case, we want to ensure the constructor and setting TestContext are both run on the correct execution context. + // Also we re-capture the execution context in case constructor or TestContext setter modifies an async local value. + ExecutionContext updatedExecutionContext = executionContext; + ExecutionContextHelpers.RunOnContext(executionContext, () => + { + try + { + _classInstance = CreateTestClassInstance(result); + setTestContextSucessful = _classInstance != null && SetTestContext(_classInstance, result); + } + finally + { + updatedExecutionContext = ExecutionContext.Capture() ?? executionContext; + } + }); + + executionContext = updatedExecutionContext; + } + + if (setTestContextSucessful) { // For any failure after this point, we must run TestCleanup _isTestContextSet = true; - if (RunTestInitializeMethod(_classInstance, result, ref executionContext, timeoutTokenSource)) + if (RunTestInitializeMethod(_classInstance!, result, ref executionContext, timeoutTokenSource)) { hasTestInitializePassed = true; - var tcs = new TaskCompletionSource(); -#pragma warning disable VSTHRD101 // Avoid unsupported async delegates - ExecutionContextHelpers.RunOnContext(executionContext, async () => + + if (executionContext is null) + { + Task? invokeResult = MethodInfo.GetInvokeResultAsync(_classInstance, arguments); + if (invokeResult is not null) + { + await invokeResult.ConfigureAwait(false); + } + } + else { - try + var tcs = new TaskCompletionSource(); + ExecutionContext? updatedExecutionContext = executionContext; +#pragma warning disable VSTHRD101 // Avoid unsupported async delegates + ExecutionContextHelpers.RunOnContext(executionContext, async () => { - object? invokeResult = TestMethod.GetInvokeResult(_classInstance, arguments); - if (invokeResult is Task task) + try + { + Task? invokeResult = MethodInfo.GetInvokeResultAsync(_classInstance, arguments); + if (invokeResult is not null) + { + await invokeResult.ConfigureAwait(false); + } + } + catch (Exception e) { - await task; + tcs.SetException(e); } - else if (invokeResult is ValueTask valueTask) + finally { - await valueTask; + updatedExecutionContext = ExecutionContext.Capture(); + tcs.TrySetResult(null); } + }); +#pragma warning restore VSTHRD101 // Avoid unsupported async delegates - executionContext = ExecutionContext.Capture(); - tcs.SetResult(null); - } - catch (Exception ex) + await tcs.Task.ConfigureAwait(false); + + if (updatedExecutionContext is not null) { - tcs.SetException(ex); + executionContext = updatedExecutionContext; } - }); -#pragma warning restore VSTHRD101 // Avoid unsupported async delegates - - await tcs.Task; + } result.Outcome = UTF.UnitTestOutcome.Passed; } @@ -532,7 +562,7 @@ private async Task ExecuteInternalAsync(object?[]? arguments, Execut // Pulling it out so extension writers can abort custom cleanups if need be. Having this in a finally block // does not allow a thread abort exception to be raised within the block but throws one after finally is executed // crashing the process. This was blocking writing an extension for Dynamic Timeout in VSO. - RunTestCleanupMethod(result, executionContext, timeoutTokenSource); + await RunTestCleanupMethodAsync(result, executionContext, timeoutTokenSource).ConfigureAwait(false); return testRunnerException != null ? throw testRunnerException : result; } @@ -641,7 +671,7 @@ private static TestFailedException HandleMethodException(Exception ex, Exception } // Get the real exception thrown by the test method - if (realException.TryGetUnitTestAssertException(out UTF.UnitTestOutcome outcome, out string? exceptionMessage, out StackTraceInformation? exceptionStackTraceInfo)) + if (realException.TryGetUnitTestAssertException(out UTFUnitTestOutcome outcome, out string? exceptionMessage, out StackTraceInformation? exceptionStackTraceInfo)) { return new TestFailedException(outcome, exceptionMessage, exceptionStackTraceInfo, realException); } @@ -677,16 +707,25 @@ private static TestFailedException HandleMethodException(Exception ex, Exception /// Runs TestCleanup methods of parent TestClass and base classes. /// /// Instance of TestResult. - /// The execution context to execute the test cleanup on. + /// The execution context to run on. /// The timeout token source. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")] - private void RunTestCleanupMethod(TestResult result, ExecutionContext? executionContext, CancellationTokenSource? timeoutTokenSource) + private +#if NET6_0_OR_GREATER + async +#endif + Task + RunTestCleanupMethodAsync(TestResult result, ExecutionContext? executionContext, CancellationTokenSource? timeoutTokenSource) { DebugEx.Assert(result != null, "result != null"); if (_classInstance is null || !_isTestContextSet || _isTestCleanupInvoked) { +#if NET6_0_OR_GREATER return; +#else + return Task.CompletedTask; +#endif } _isTestCleanupInvoked = true; @@ -723,20 +762,17 @@ private void RunTestCleanupMethod(TestResult result, ExecutionContext? execution if (_classInstance is IAsyncDisposable classInstanceAsAsyncDisposable) { // If you implement IAsyncDisposable without calling the DisposeAsync this would result a resource leak. - ExecutionContextHelpers.RunOnContext(executionContext, () => - { - classInstanceAsAsyncDisposable.DisposeAsync().AsTask().Wait(); - executionContext = ExecutionContext.Capture(); - }); + await classInstanceAsAsyncDisposable.DisposeAsync().ConfigureAwait(false); } #endif if (_classInstance is IDisposable classInstanceAsDisposable) { - ExecutionContextHelpers.RunOnContext(executionContext, () => - { - classInstanceAsDisposable.Dispose(); - executionContext = ExecutionContext.Capture(); - }); + classInstanceAsDisposable.Dispose(); + } + + foreach ((MethodInfo method, TimeoutInfo? timeoutInfo) in Parent.Parent.GlobalTestCleanups) + { + InvokeGlobalCleanupMethod(method, ref executionContext, timeoutInfo, timeoutTokenSource); } } } @@ -748,11 +784,15 @@ private void RunTestCleanupMethod(TestResult result, ExecutionContext? execution // If testCleanup was successful, then don't do anything if (testCleanupException == null) { +#if NET6_0_OR_GREATER return; +#else + return Task.CompletedTask; +#endif } Exception realException = testCleanupException.GetRealException(); - UTF.UnitTestOutcome outcomeFromRealException = realException is AssertInconclusiveException ? UTF.UnitTestOutcome.Inconclusive : UTF.UnitTestOutcome.Failed; + UTFUnitTestOutcome outcomeFromRealException = realException is AssertInconclusiveException ? UTF.UnitTestOutcome.Inconclusive : UTF.UnitTestOutcome.Failed; result.Outcome = result.Outcome.GetMoreImportantOutcome(outcomeFromRealException); realException = testCleanupMethod != null @@ -768,6 +808,10 @@ private void RunTestCleanupMethod(TestResult result, ExecutionContext? execution realException); result.TestFailureException = realException; + +#if !NET6_0_OR_GREATER + return Task.CompletedTask; +#endif } /// @@ -775,7 +819,7 @@ private void RunTestCleanupMethod(TestResult result, ExecutionContext? execution /// /// Instance of TestClass. /// Instance of TestResult. - /// The execution context to execute the test initialize on. + /// The execution context to run on. /// The timeout token source. /// True if the TestInitialize method(s) did not throw an exception. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")] @@ -865,15 +909,18 @@ private bool RunTestInitializeMethod(object classInstance, TestResult result, re timeout = localTimeout; } - ExecutionContext? updatedExecutionContext = executionContext; - + int originalThreadId = Environment.CurrentManagedThreadId; + ExecutionContext? updatedExecutionContext = null; TestFailedException? result = FixtureMethodRunner.RunWithTimeoutAndCancellation( () => { methodInfo.InvokeAsSynchronousTask(classInstance, null); - // **After** we have executed the current test initialize (it could be from the current class or from base class), we save the current context. - // This context will contain async locals set by the test initialize method. - updatedExecutionContext = ExecutionContext.Capture(); + if (originalThreadId != Environment.CurrentManagedThreadId) + { + // We ended up running on a different thread, because of use of non-cooperative timeout. + // Re-capture the execution context. + updatedExecutionContext = ExecutionContext.Capture(); + } }, TestContext!.Context.CancellationTokenSource, timeout, @@ -885,7 +932,44 @@ timeoutTokenSource is null ? null : (timeoutTokenSource, TimeoutInfo.Timeout)); - executionContext = updatedExecutionContext; + if (updatedExecutionContext != null) + { + executionContext = updatedExecutionContext; + } + + return result; + } + + private TestFailedException? InvokeGlobalInitializeMethod(MethodInfo methodInfo, ref ExecutionContext? executionContext, TimeoutInfo? timeoutInfo, CancellationTokenSource? timeoutTokenSource) + { + int originalThreadId = Environment.CurrentManagedThreadId; + ExecutionContext? updatedExecutionContext = null; + TestFailedException? result = FixtureMethodRunner.RunWithTimeoutAndCancellation( + () => + { + methodInfo.InvokeAsSynchronousTask(null, [TestContext]); + if (originalThreadId != Environment.CurrentManagedThreadId) + { + // We ended up running on a different thread, because of use of non-cooperative timeout. + // Re-capture the execution context. + updatedExecutionContext = ExecutionContext.Capture(); + } + }, + TestContext!.Context.CancellationTokenSource, + timeoutInfo: timeoutInfo, + methodInfo, + executionContext, + Resource.TestInitializeWasCancelled, + Resource.TestInitializeTimedOut, + timeoutTokenSource is null + ? null + : (timeoutTokenSource, TimeoutInfo.Timeout)); + + if (updatedExecutionContext != null) + { + executionContext = updatedExecutionContext; + } + return result; } @@ -897,14 +981,18 @@ timeoutTokenSource is null timeout = localTimeout; } - ExecutionContext? updatedExecutionContext = executionContext; + int originalThreadId = Environment.CurrentManagedThreadId; + ExecutionContext? updatedExecutionContext = null; TestFailedException? result = FixtureMethodRunner.RunWithTimeoutAndCancellation( () => { methodInfo.InvokeAsSynchronousTask(classInstance, null); - // **After** we have executed the current test cleanup (it could be from the current class or from base class), we save the current context. - // This context will contain async locals set by the test cleanup method. - updatedExecutionContext = ExecutionContext.Capture(); + if (originalThreadId != Environment.CurrentManagedThreadId) + { + // We ended up running on a different thread, because of use of non-cooperative timeout. + // Re-capture the execution context. + updatedExecutionContext = ExecutionContext.Capture(); + } }, TestContext!.Context.CancellationTokenSource, timeout, @@ -916,7 +1004,44 @@ timeoutTokenSource is null ? null : (timeoutTokenSource, TimeoutInfo.Timeout)); - executionContext = updatedExecutionContext; + if (updatedExecutionContext != null) + { + executionContext = updatedExecutionContext; + } + + return result; + } + + private TestFailedException? InvokeGlobalCleanupMethod(MethodInfo methodInfo, ref ExecutionContext? executionContext, TimeoutInfo? timeoutInfo, CancellationTokenSource? timeoutTokenSource) + { + int originalThreadId = Environment.CurrentManagedThreadId; + ExecutionContext? updatedExecutionContext = null; + TestFailedException? result = FixtureMethodRunner.RunWithTimeoutAndCancellation( + () => + { + methodInfo.InvokeAsSynchronousTask(null, [TestContext]); + if (originalThreadId != Environment.CurrentManagedThreadId) + { + // We ended up running on a different thread, because of use of non-cooperative timeout. + // Re-capture the execution context. + updatedExecutionContext = ExecutionContext.Capture(); + } + }, + TestContext!.Context.CancellationTokenSource, + timeoutInfo: timeoutInfo, + methodInfo, + executionContext, + Resource.TestCleanupWasCancelled, + Resource.TestCleanupTimedOut, + timeoutTokenSource is null + ? null + : (timeoutTokenSource, TimeoutInfo.Timeout)); + + if (updatedExecutionContext != null) + { + executionContext = updatedExecutionContext; + } + return result; } @@ -1031,10 +1156,9 @@ private bool SetTestContext(object classInstance, TestResult result) /// Execute test with a timeout. /// /// The arguments to be passed. - /// The execution context to execute the test method on. /// The result of execution. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")] - private async Task ExecuteInternalWithTimeoutAsync(object?[]? arguments, ExecutionContext? executionContext) + private async Task ExecuteInternalWithTimeoutAsync(object?[]? arguments) { DebugEx.Assert(IsTimeoutSet, "Timeout should be set"); @@ -1058,7 +1182,7 @@ private async Task ExecuteInternalWithTimeoutAsync(object?[]? argume try { - return await ExecuteInternalAsync(arguments, executionContext, timeoutTokenSource); + return await ExecuteInternalAsync(arguments, timeoutTokenSource).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -1084,6 +1208,7 @@ private async Task ExecuteInternalWithTimeoutAsync(object?[]? argume TestResult? result = null; Exception? failure = null; + ExecutionContext? executionContext = null; if (PlatformServiceProvider.Instance.ThreadOperations.Execute(ExecuteAsyncAction, TimeoutInfo.Timeout, TestContext!.Context.CancellationTokenSource.Token)) { @@ -1093,10 +1218,6 @@ private async Task ExecuteInternalWithTimeoutAsync(object?[]? argume } DebugEx.Assert(result is not null, "result is not null"); - - // It's possible that some failures happened and that the cleanup wasn't executed, so we need to run it here. - // The method already checks if the cleanup was already executed. - RunTestCleanupMethod(result, executionContext, null); return result; } @@ -1109,7 +1230,7 @@ private async Task ExecuteInternalWithTimeoutAsync(object?[]? argume else { // Cancel the token source as test has timed out - await TestContext.Context.CancellationTokenSource.CancelAsync(); + await TestContext.Context.CancellationTokenSource.CancelAsync().ConfigureAwait(false); } TestResult timeoutResult = new() { Outcome = UTF.UnitTestOutcome.Timeout, TestFailureException = new TestFailedException(UTFUnitTestOutcome.Timeout, errorMessage) }; @@ -1120,7 +1241,7 @@ private async Task ExecuteInternalWithTimeoutAsync(object?[]? argume // We don't know when the cancellation happened so it's possible that the cleanup wasn't executed, so we need to run it here. // The method already checks if the cleanup was already executed. - RunTestCleanupMethod(timeoutResult, executionContext, null); + await RunTestCleanupMethodAsync(timeoutResult, executionContext, null).ConfigureAwait(false); return timeoutResult; // Local functions @@ -1135,7 +1256,7 @@ void ExecuteAsyncAction() // dispatched back to the SynchronizationContext which offloads the work to the UI thread. // However, the GetAwaiter().GetResult() here will block the current thread which is also the UI thread. // So, the continuations will not be able, thus this task never completes. - result = ExecuteInternalAsync(arguments, executionContext, null).GetAwaiter().GetResult(); + result = ExecuteInternalAsync(arguments, null).GetAwaiter().GetResult(); } catch (Exception ex) { diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestMethodRunner.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodRunner.cs similarity index 85% rename from src/Adapter/MSTest.TestAdapter/Execution/TestMethodRunner.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodRunner.cs index 078d97c4cb..443e2443c7 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/TestMethodRunner.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodRunner.cs @@ -6,6 +6,8 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting.Internal; @@ -61,11 +63,11 @@ public TestMethodRunner(TestMethodInfo testMethodInfo, TestMethod testMethod, IT /// Executes a test. /// /// The test results. - internal async Task ExecuteAsync(string initializationLogs, string initializationErrorLogs, string initializationTrace, string initializationTestContextMessages) + internal async Task ExecuteAsync(string? initializationLogs, string? initializationErrorLogs, string? initializationTrace, string? initializationTestContextMessages) { _testContext.Context.TestRunCount++; - bool isSTATestClass = AttributeComparer.IsDerived(_testMethodInfo.Parent.ClassAttribute); - bool isSTATestMethod = AttributeComparer.IsDerived(_testMethodInfo.Executor); + bool isSTATestClass = _testMethodInfo.Parent.ClassAttribute is STATestClassAttribute; + bool isSTATestMethod = _testMethodInfo.Executor is STATestMethodAttribute; bool isSTARequested = isSTATestClass || isSTATestMethod; bool isWindowsOS = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); if (isSTARequested && isWindowsOS && Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) @@ -93,7 +95,7 @@ internal async Task ExecuteAsync(string initializationLogs, string PlatformServiceProvider.Instance.AdapterTraceLogger.LogError(ex.ToString()); } - return results ?? Array.Empty(); + return results ?? []; } else { @@ -103,17 +105,17 @@ internal async Task ExecuteAsync(string initializationLogs, string PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning(Resource.STAIsOnlySupportedOnWindowsWarning); } - return await SafeRunTestMethodAsync(initializationLogs, initializationErrorLogs, initializationTrace, initializationTestContextMessages); + return await SafeRunTestMethodAsync(initializationLogs, initializationErrorLogs, initializationTrace, initializationTestContextMessages).ConfigureAwait(false); } // Local functions - async Task SafeRunTestMethodAsync(string initializationLogs, string initializationErrorLogs, string initializationTrace, string initializationTestContextMessages) + async Task SafeRunTestMethodAsync(string? initializationLogs, string? initializationErrorLogs, string? initializationTrace, string? initializationTestContextMessages) { TestResult[]? result = null; try { - result = await RunTestMethodAsync(); + result = await RunTestMethodAsync().ConfigureAwait(false); } catch (TestFailedException ex) { @@ -159,7 +161,7 @@ async Task SafeRunTestMethodAsync(string initializationLogs, strin internal async Task RunTestMethodAsync() { DebugEx.Assert(_test != null, "Test should not be null."); - DebugEx.Assert(_testMethodInfo.TestMethod != null, "Test method should not be null."); + DebugEx.Assert(_testMethodInfo.MethodInfo != null, "Test method should not be null."); List results = []; if (_testMethodInfo.Executor == null) @@ -177,22 +179,22 @@ internal async Task RunTestMethodAsync() return [TestResult.CreateIgnoredResult(_test.TestDataSourceIgnoreMessage)]; } - object?[]? data = DataSerializationHelper.Deserialize(_test.SerializedData); - TestResult[] testResults = await ExecuteTestWithDataSourceAsync(null, data); + object?[]? data = _test.ActualData ?? DataSerializationHelper.Deserialize(_test.SerializedData); + TestResult[] testResults = await ExecuteTestWithDataSourceAsync(null, data, actualDataAlreadyHandledDuringDiscovery: true).ConfigureAwait(false); results.AddRange(testResults); } - else if (await TryExecuteDataSourceBasedTestsAsync(results)) + else if (await TryExecuteDataSourceBasedTestsAsync(results).ConfigureAwait(false)) { isDataDriven = true; } - else if (await TryExecuteFoldedDataDrivenTestsAsync(results)) + else if (await TryExecuteFoldedDataDrivenTestsAsync(results).ConfigureAwait(false)) { isDataDriven = true; } else { _testContext.SetDisplayName(_test.DisplayName); - TestResult[] testResults = await ExecuteTestAsync(_testMethodInfo); + TestResult[] testResults = await ExecuteTestAsync(_testMethodInfo).ConfigureAwait(false); foreach (TestResult testResult in testResults) { @@ -245,7 +247,7 @@ internal async Task RunTestMethodAsync() results.Add(emptyResult); } - return results.ToArray(); + return [.. results]; } private async Task TryExecuteDataSourceBasedTestsAsync(List results) @@ -253,7 +255,7 @@ private async Task TryExecuteDataSourceBasedTestsAsync(List re DataSourceAttribute[] dataSourceAttribute = _testMethodInfo.GetAttributes(false); if (dataSourceAttribute is { Length: 1 }) { - await ExecuteTestFromDataSourceAttributeAsync(results); + await ExecuteTestFromDataSourceAttributeAsync(results).ConfigureAwait(false); return true; } @@ -301,7 +303,7 @@ private async Task TryExecuteFoldedDataDrivenTestsAsync(List r { try { - TestResult[] testResults = await ExecuteTestWithDataSourceAsync(testDataSource, data); + TestResult[] testResults = await ExecuteTestWithDataSourceAsync(testDataSource, data, actualDataAlreadyHandledDuringDiscovery: false).ConfigureAwait(false); results.AddRange(testResults); } @@ -340,7 +342,7 @@ private async Task ExecuteTestFromDataSourceAttributeAsync(List resu foreach (object dataRow in dataRows) { - TestResult[] testResults = await ExecuteTestWithDataRowAsync(dataRow, rowIndex++); + TestResult[] testResults = await ExecuteTestWithDataRowAsync(dataRow, rowIndex++).ConfigureAwait(false); results.AddRange(testResults); } } @@ -362,7 +364,7 @@ private async Task ExecuteTestFromDataSourceAttributeAsync(List resu } } - private async Task ExecuteTestWithDataSourceAsync(UTF.ITestDataSource? testDataSource, object?[]? data) + private async Task ExecuteTestWithDataSourceAsync(UTF.ITestDataSource? testDataSource, object?[]? data, bool actualDataAlreadyHandledDuringDiscovery) { string? displayName = StringEx.IsNullOrWhiteSpace(_test.DisplayName) ? _test.Name @@ -370,12 +372,12 @@ private async Task ExecuteTestWithDataSourceAsync(UTF.ITestDataSou string? displayNameFromTestDataRow = null; string? ignoreFromTestDataRow = null; - if (data is not null && + if (!actualDataAlreadyHandledDuringDiscovery && data is not null && TestDataSourceHelpers.TryHandleITestDataRow(data, _testMethodInfo.ParameterTypes, out data, out ignoreFromTestDataRow, out displayNameFromTestDataRow)) { // Handled already. } - else if (TestDataSourceHelpers.IsDataConsideredSingleArgumentValue(data, _testMethodInfo.ParameterTypes)) + else if (!actualDataAlreadyHandledDuringDiscovery && TestDataSourceHelpers.IsDataConsideredSingleArgumentValue(data, _testMethodInfo.ParameterTypes)) { // SPECIAL CASE: // This condition is a duplicate of the condition in InvokeAsSynchronousTask. @@ -391,16 +393,14 @@ private async Task ExecuteTestWithDataSourceAsync(UTF.ITestDataSou // Note that normally, the array in this code path represents the arguments of the test method. // However, InvokeAsSynchronousTask uses the above check to mean "the whole array is the single argument to the test method" } - else if (data?.Length == 1 && TestDataSourceHelpers.TryHandleTupleDataSource(data[0], _testMethodInfo.ParameterTypes, out object?[] tupleExpandedToArray)) + else if (!actualDataAlreadyHandledDuringDiscovery && data?.Length == 1 && TestDataSourceHelpers.TryHandleTupleDataSource(data[0], _testMethodInfo.ParameterTypes, out object?[] tupleExpandedToArray)) { data = tupleExpandedToArray; } - displayName = testDataSource != null - ? displayNameFromTestDataRow - ?? testDataSource.GetDisplayName(new ReflectionTestMethodInfo(_testMethodInfo.MethodInfo, _test.DisplayName), data) - ?? displayName - : displayNameFromTestDataRow ?? displayName; + displayName = displayNameFromTestDataRow + ?? testDataSource?.GetDisplayName(new ReflectionTestMethodInfo(_testMethodInfo.MethodInfo, _test.DisplayName), data) + ?? displayName; var stopwatch = Stopwatch.StartNew(); _testMethodInfo.SetArguments(data); @@ -409,7 +409,7 @@ private async Task ExecuteTestWithDataSourceAsync(UTF.ITestDataSou TestResult[] testResults = ignoreFromTestDataRow is not null ? [TestResult.CreateIgnoredResult(ignoreFromTestDataRow)] - : await ExecuteTestAsync(_testMethodInfo); + : await ExecuteTestAsync(_testMethodInfo).ConfigureAwait(false); stopwatch.Stop(); @@ -436,7 +436,7 @@ private async Task ExecuteTestWithDataRowAsync(object dataRow, int { stopwatch = Stopwatch.StartNew(); _testContext.SetDataRow(dataRow); - testResults = await ExecuteTestAsync(_testMethodInfo); + testResults = await ExecuteTestAsync(_testMethodInfo).ConfigureAwait(false); } finally { @@ -458,7 +458,27 @@ private async Task ExecuteTestAsync(TestMethodInfo testMethodInfo) { try { - return await _testMethodInfo.Executor.ExecuteAsync(testMethodInfo); + var tcs = new TaskCompletionSource(); + +#pragma warning disable VSTHRD101 // Avoid unsupported async delegates + ExecutionContextHelpers.RunOnContext( + testMethodInfo.Parent.ExecutionContext ?? testMethodInfo.Parent.Parent.ExecutionContext, + async () => + { + try + { + using (TestContextImplementation.SetCurrentTestContext(_testMethodInfo.TestContext as TestContextImplementation)) + { + tcs.SetResult(await _testMethodInfo.Executor.ExecuteAsync(testMethodInfo).ConfigureAwait(false)); + } + } + catch (Exception e) + { + tcs.SetException(e); + } + }); +#pragma warning restore VSTHRD101 // Avoid unsupported async delegates + return await tcs.Task.ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunCancellationToken.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunCancellationToken.cs new file mode 100644 index 0000000000..6a229f30cf --- /dev/null +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunCancellationToken.cs @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; + +/// +/// Cancellation token supporting cancellation of a test run. +/// +#if NET6_0_OR_GREATER +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +#else +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] +#endif +#pragma warning disable CA1001 // Types that own disposable fields should be disposable +public class TestRunCancellationToken +#pragma warning restore CA1001 // Types that own disposable fields should be disposable +{ + private readonly CancellationTokenSource _cancellationTokenSource = new(); + private readonly CancellationToken? _originalCancellationToken; + + /// + /// Initializes a new instance of the class. + /// + public TestRunCancellationToken() + { + } + + internal TestRunCancellationToken(CancellationToken originalCancellationToken) + => _originalCancellationToken = originalCancellationToken; + + /// + /// Gets a value indicating whether the test run is canceled. + /// + public bool Canceled + { + get; + private set + { + bool previousValue = field; + field = value; + + if (!previousValue && value) + { + _cancellationTokenSource.Cancel(); + } + } + } + + /// + /// Cancels the execution of a test run. + /// + public void Cancel() => Canceled = true; + + /// + /// Registers a callback method to be invoked when canceled. + /// + /// Callback delegate for handling cancellation. + public void Register(Action callback) => _cancellationTokenSource.Token.Register(_ => callback(), null); + + internal CancellationTokenRegistration Register(Action callback, object? state) => _cancellationTokenSource.Token.Register(callback, state); + + /// + /// This method does nothing and is kept for binary compatibility. It should be removed in v4. + /// Note that the whole class is marked obsolete and will be made internal in v4. + /// + public void Unregister() + { + } + + internal void ThrowIfCancellationRequested() + // If ThrowIfCancellationRequested is called from the main AppDomain where we have the original + // cancellation token, we should use that token. + // Otherwise, we have no choice other than using the cancellation token from the source created by TestRunCancellationToken. + => (_originalCancellationToken ?? _cancellationTokenSource.Token).ThrowIfCancellationRequested(); +} diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TimeoutInfo.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TimeoutInfo.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Execution/TimeoutInfo.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/TimeoutInfo.cs diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TraceTextWriter.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TraceTextWriter.cs new file mode 100644 index 0000000000..261de5d466 --- /dev/null +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TraceTextWriter.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; + +namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; + +internal sealed class TraceTextWriter : TextWriter +{ + public override Encoding Encoding => Encoding.UTF8; + + public override void Write(char value) + { + if (TestContextImplementation.CurrentTestContext is { } testContext) + { + testContext.WriteTrace(value); + } + } + + public override void Write(string? value) + { + if (TestContextImplementation.CurrentTestContext is { } testContext) + { + testContext.WriteTrace(value); + } + } +} diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs similarity index 90% rename from src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs index 55f1cc63c6..3ac9676a1e 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs @@ -8,6 +8,7 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -302,7 +303,7 @@ private TestClassInfo CreateClassInfo(Type classType) TestAssemblyInfo assemblyInfo = GetAssemblyInfo(classType.Assembly); - TestClassAttribute? testClassAttribute = ReflectHelper.Instance.GetFirstDerivedAttributeOrDefault(classType, inherit: false); + TestClassAttribute? testClassAttribute = ReflectHelper.Instance.GetFirstAttributeOrDefault(classType, inherit: false); DebugEx.Assert(testClassAttribute is not null, "testClassAttribute is null"); var classInfo = new TestClassInfo(classType, constructor, isParameterLessConstructor, testClassAttribute, assemblyInfo); @@ -354,7 +355,7 @@ private TestClassInfo CreateClassInfo(Type classType) private TimeoutInfo? TryGetTimeoutInfo(MethodInfo methodInfo, FixtureKind fixtureKind) { - TimeoutAttribute? timeoutAttribute = _reflectionHelper.GetFirstNonDerivedAttributeOrDefault(methodInfo, inherit: false); + TimeoutAttribute? timeoutAttribute = _reflectionHelper.GetFirstAttributeOrDefault(methodInfo, inherit: false); if (timeoutAttribute != null) { if (!timeoutAttribute.HasCorrectTimeout) @@ -391,7 +392,7 @@ private TestAssemblyInfo GetAssemblyInfo(Assembly assembly) try { // Only examine classes which are TestClass or derives from TestClass attribute - if (!@this._reflectionHelper.IsDerivedAttributeDefined(t, inherit: false)) + if (!@this._reflectionHelper.IsAttributeDefined(t, inherit: false)) { continue; } @@ -420,6 +421,23 @@ private TestAssemblyInfo GetAssemblyInfo(Assembly assembly) assemblyInfo.AssemblyCleanupMethod = methodInfo; assemblyInfo.AssemblyCleanupMethodTimeoutMilliseconds = @this.TryGetTimeoutInfo(methodInfo, FixtureKind.AssemblyCleanup); } + + if (methodInfo is { IsPublic: true, IsStatic: true, IsGenericMethod: false, DeclaringType.IsGenericType: false, DeclaringType.IsPublic: true } && + methodInfo.GetParameters() is { } parameters && parameters.Length == 1 && parameters[0].ParameterType == typeof(TestContext) && + methodInfo.IsValidReturnType()) + { + bool isGlobalTestInitialize = @this._reflectionHelper.IsAttributeDefined(methodInfo, inherit: true); + bool isGlobalTestCleanup = @this._reflectionHelper.IsAttributeDefined(methodInfo, inherit: true); + if (isGlobalTestInitialize) + { + assemblyInfo.GlobalTestInitializations.Add((methodInfo, @this.TryGetTimeoutInfo(methodInfo, FixtureKind.TestInitialize))); + } + + if (isGlobalTestCleanup) + { + assemblyInfo.GlobalTestCleanups.Add((methodInfo, @this.TryGetTimeoutInfo(methodInfo, FixtureKind.TestCleanup))); + } + } } } @@ -440,7 +458,7 @@ private bool IsAssemblyOrClassInitializeMethod(MethodInfo // { // return false; // } - if (!_reflectionHelper.IsNonDerivedAttributeDefined(methodInfo, false)) + if (!_reflectionHelper.IsAttributeDefined(methodInfo, false)) { return false; } @@ -468,7 +486,7 @@ private bool IsAssemblyOrClassCleanupMethod(MethodInfo method // { // return false; // } - if (!_reflectionHelper.IsNonDerivedAttributeDefined(methodInfo, false)) + if (!_reflectionHelper.IsAttributeDefined(methodInfo, false)) { return false; } @@ -550,7 +568,7 @@ private void UpdateInfoIfClassInitializeOrCleanupMethod( if (isBase) { - if (_reflectionHelper.GetFirstDerivedAttributeOrDefault(methodInfo, inherit: true)? + if (_reflectionHelper.GetFirstAttributeOrDefault(methodInfo, inherit: true)? .InheritanceBehavior == InheritanceBehavior.BeforeEachDerivedClass) { initAndCleanupMethods[0] = methodInfo; @@ -572,7 +590,7 @@ private void UpdateInfoIfClassInitializeOrCleanupMethod( if (isBase) { - if (_reflectionHelper.GetFirstDerivedAttributeOrDefault(methodInfo, inherit: true)? + if (_reflectionHelper.GetFirstAttributeOrDefault(methodInfo, inherit: true)? .InheritanceBehavior == InheritanceBehavior.BeforeEachDerivedClass) { initAndCleanupMethods[1] = methodInfo; @@ -599,8 +617,8 @@ private void UpdateInfoIfTestInitializeOrCleanupMethod( bool isBase, Dictionary instanceMethods) { - bool hasTestInitialize = _reflectionHelper.IsNonDerivedAttributeDefined(methodInfo, inherit: false); - bool hasTestCleanup = _reflectionHelper.IsNonDerivedAttributeDefined(methodInfo, inherit: false); + bool hasTestInitialize = _reflectionHelper.IsAttributeDefined(methodInfo, inherit: false); + bool hasTestCleanup = _reflectionHelper.IsAttributeDefined(methodInfo, inherit: false); if (!hasTestCleanup && !hasTestInitialize) { @@ -736,9 +754,9 @@ private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassIn } else if (methodBase != null) { - Type[] parameters = methodBase.GetParameters().Select(i => i.ParameterType).ToArray(); + Type[] parameters = [.. methodBase.GetParameters().Select(i => i.ParameterType)]; // TODO: Should we pass true for includeNonPublic? - testMethodInfo = PlatformServiceProvider.Instance.ReflectionOperations.GetRuntimeMethod(methodBase.DeclaringType!, methodBase.Name, parameters, includeNonPublic: false); + testMethodInfo = PlatformServiceProvider.Instance.ReflectionOperations.GetRuntimeMethod(methodBase.DeclaringType!, methodBase.Name, parameters, includeNonPublic: true); } return testMethodInfo is null @@ -776,16 +794,16 @@ private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassIn private void SetCustomProperties(TestMethodInfo testMethodInfo, ITestContext testContext) { DebugEx.Assert(testMethodInfo != null, "testMethodInfo is Null"); - DebugEx.Assert(testMethodInfo.TestMethod != null, "testMethodInfo.TestMethod is Null"); + DebugEx.Assert(testMethodInfo.MethodInfo != null, "testMethodInfo.TestMethod is Null"); - IEnumerable attributes = _reflectionHelper.GetDerivedAttributes(testMethodInfo.TestMethod, inherit: true); + IEnumerable attributes = _reflectionHelper.GetAttributes(testMethodInfo.MethodInfo, inherit: true); DebugEx.Assert(attributes != null, "attributes is null"); - attributes = attributes.Concat(_reflectionHelper.GetDerivedAttributes(testMethodInfo.Parent.ClassType, inherit: true)); + attributes = attributes.Concat(_reflectionHelper.GetAttributes(testMethodInfo.Parent.ClassType, inherit: true)); foreach (TestPropertyAttribute attribute in attributes) { - if (!ValidateAndAssignTestProperty(testMethodInfo, testContext, attribute.Name, attribute.Value)) + if (!ValidateAndAssignTestProperty(testMethodInfo, testContext, attribute.Name, attribute.Value, isPredefinedAttribute: attribute is OwnerAttribute or PriorityAttribute)) { break; } @@ -799,20 +817,22 @@ private void SetCustomProperties(TestMethodInfo testMethodInfo, ITestContext tes /// The test context. /// The property name. /// The property value. + /// If the property originates from a predefined attribute. /// True if its a valid Test Property. private static bool ValidateAndAssignTestProperty( TestMethodInfo testMethodInfo, ITestContext testContext, string propertyName, - string propertyValue) + string propertyValue, + bool isPredefinedAttribute) { - if (PredefinedNames.Any(predefinedProp => predefinedProp == propertyName)) + if (!isPredefinedAttribute && PredefinedNames.Any(predefinedProp => predefinedProp == propertyName)) { testMethodInfo.NotRunnableReason = string.Format( CultureInfo.CurrentCulture, Resource.UTA_ErrorPredefinedTestProperty, - testMethodInfo.TestMethod.DeclaringType!.FullName, - testMethodInfo.TestMethod.Name, + testMethodInfo.MethodInfo.DeclaringType!.FullName, + testMethodInfo.MethodInfo.Name, propertyName); return false; @@ -823,8 +843,8 @@ private static bool ValidateAndAssignTestProperty( testMethodInfo.NotRunnableReason = string.Format( CultureInfo.CurrentCulture, Resource.UTA_ErrorTestPropertyNullOrEmpty, - testMethodInfo.TestMethod.DeclaringType!.FullName, - testMethodInfo.TestMethod.Name); + testMethodInfo.MethodInfo.DeclaringType!.FullName, + testMethodInfo.MethodInfo.Name); return false; } diff --git a/src/Adapter/MSTest.TestAdapter/Execution/UnitTestRunner.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs similarity index 66% rename from src/Adapter/MSTest.TestAdapter/Execution/UnitTestRunner.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs index 873252874d..0afe682950 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/UnitTestRunner.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs @@ -8,9 +8,11 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting.Logging; using UnitTestOutcome = Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome; using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; @@ -22,9 +24,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; /// internal sealed class UnitTestRunner : MarshalByRefObject { - private readonly ConcurrentDictionary _fixtureTests = new(); + private readonly ConcurrentDictionary _assemblyFixtureTests = new(); + private readonly ConcurrentDictionary _classFixtureTests = new(); private readonly TypeCache _typeCache; - private readonly ReflectHelper _reflectHelper; private readonly ClassCleanupManager _classCleanupManager; /// @@ -51,9 +53,15 @@ internal UnitTestRunner(MSTestSettings settings, UnitTestElement[] testsToRun, i // This would just be resetting the settings to itself in non desktop workflows. MSTestSettings.PopulateSettings(settings); - PlatformServiceProvider.Instance.TestRunCancellationToken ??= new TestRunCancellationToken(); + Logger.OnLogMessage += message => TestContextImplementation.CurrentTestContext?.WriteConsoleOut(message); + if (MSTestSettings.CurrentSettings.CaptureDebugTraces) + { + Console.SetOut(new ConsoleOutRouter(Console.Out)); + Console.SetError(new ConsoleErrorRouter(Console.Error)); + Trace.Listeners.Add(new TextWriterTraceListener(new TraceTextWriter())); + } - _reflectHelper = reflectHelper; + PlatformServiceProvider.Instance.TestRunCancellationToken ??= new TestRunCancellationToken(); _typeCache = new TypeCache(reflectHelper); // We can't transport the Enum across AppDomain boundaries because of backwards and forwards compatibility. @@ -66,9 +74,8 @@ internal UnitTestRunner(MSTestSettings settings, UnitTestElement[] testsToRun, i _classCleanupManager = new ClassCleanupManager( testsToRun, - MSTestSettings.CurrentSettings.ClassCleanupLifecycle, - lifecycle, - _reflectHelper); + MSTestSettings.CurrentSettings.ClassCleanupLifecycle ?? lifecycle, + reflectHelper); } #pragma warning disable CA1822 // Mark members as static @@ -92,33 +99,29 @@ internal FixtureTestResult GetFixtureTestResult(TestMethod testMethod, string fi { // For the fixture methods, we need to return the appropriate result. // Get matching testMethodInfo from the cache and return UnitTestOutcome for the fixture test. - if (_fixtureTests.TryGetValue(testMethod.AssemblyName + testMethod.FullClassName, out TestMethodInfo? testMethodInfo)) + if (fixtureType is EngineConstants.ClassInitializeFixtureTrait or EngineConstants.ClassCleanupFixtureTrait && + _classFixtureTests.TryGetValue(testMethod.AssemblyName + testMethod.FullClassName, out TestClassInfo? testClassInfo)) { - if (fixtureType == Constants.ClassInitializeFixtureTrait) + UnitTestOutcome outcome = fixtureType switch { - return testMethodInfo.Parent.IsClassInitializeExecuted - ? new(true, GetOutcome(testMethodInfo.Parent.ClassInitializationException)) - : new(true, UnitTestOutcome.Inconclusive); - } + EngineConstants.ClassInitializeFixtureTrait => testClassInfo.IsClassInitializeExecuted ? GetOutcome(testClassInfo.ClassInitializationException) : UnitTestOutcome.Inconclusive, + EngineConstants.ClassCleanupFixtureTrait => testClassInfo.IsClassCleanupExecuted ? GetOutcome(testClassInfo.ClassCleanupException) : UnitTestOutcome.Inconclusive, + _ => throw ApplicationStateGuard.Unreachable(), + }; - if (fixtureType == Constants.ClassCleanupFixtureTrait) - { - return testMethodInfo.Parent.IsClassInitializeExecuted - ? new(true, GetOutcome(testMethodInfo.Parent.ClassCleanupException)) - : new(true, UnitTestOutcome.Inconclusive); - } + return new FixtureTestResult(true, outcome); } - - if (_fixtureTests.TryGetValue(testMethod.AssemblyName, out testMethodInfo)) + else if (fixtureType is EngineConstants.AssemblyInitializeFixtureTrait or EngineConstants.AssemblyCleanupFixtureTrait && + _assemblyFixtureTests.TryGetValue(testMethod.AssemblyName, out TestAssemblyInfo? testAssemblyInfo)) { - if (fixtureType == Constants.AssemblyInitializeFixtureTrait) + Exception? exception = fixtureType switch { - return new(true, GetOutcome(testMethodInfo.Parent.Parent.AssemblyInitializationException)); - } - else if (fixtureType == Constants.AssemblyCleanupFixtureTrait) - { - return new(true, GetOutcome(testMethodInfo.Parent.Parent.AssemblyCleanupException)); - } + EngineConstants.AssemblyInitializeFixtureTrait => testAssemblyInfo.AssemblyInitializationException, + EngineConstants.AssemblyCleanupFixtureTrait => testAssemblyInfo.AssemblyCleanupException, + _ => throw ApplicationStateGuard.Unreachable(), + }; + + return new(true, GetOutcome(exception)); } return new(false, UnitTestOutcome.Inconclusive); @@ -144,11 +147,16 @@ internal async Task RunSingleTestAsync(TestMethod testMethod, IDic { Guard.NotNull(testMethod); + ITestContext? testContextForTestExecution = null; + ITestContext? testContextForAssemblyInit = null; + ITestContext? testContextForClassInit = null; + ITestContext? testContextForClassCleanup = null; + ITestContext? testContextForAssemblyCleanup = null; + try { - using var writer = new ThreadSafeStringWriter(CultureInfo.InvariantCulture, "context"); var properties = new Dictionary(testContextProperties); - ITestContext testContextForTestExecution = PlatformServiceProvider.Instance.GetTestContext(testMethod, writer, properties, messageLogger, UTF.UnitTestOutcome.InProgress); + testContextForTestExecution = PlatformServiceProvider.Instance.GetTestContext(testMethod, properties, messageLogger, UTF.UnitTestOutcome.InProgress); // Get the testMethod TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( @@ -165,10 +173,10 @@ internal async Task RunSingleTestAsync(TestMethod testMethod, IDic DebugEx.Assert(testMethodInfo is not null, "testMethodInfo should not be null."); // Keep track of all non-runnable methods so that we can return the appropriate result at the end. - _fixtureTests.TryAdd(testMethod.AssemblyName, testMethodInfo); - _fixtureTests.TryAdd(testMethod.AssemblyName + testMethod.FullClassName, testMethodInfo); + _assemblyFixtureTests.TryAdd(testMethod.AssemblyName, testMethodInfo.Parent.Parent); + _classFixtureTests.TryAdd(testMethod.AssemblyName + testMethod.FullClassName, testMethodInfo.Parent); - ITestContext testContextForAssemblyInit = PlatformServiceProvider.Instance.GetTestContext(testMethod, writer, properties, messageLogger, testContextForTestExecution.Context.CurrentTestOutcome); + testContextForAssemblyInit = PlatformServiceProvider.Instance.GetTestContext(testMethod, properties, messageLogger, testContextForTestExecution.Context.CurrentTestOutcome); TestResult assemblyInitializeResult = RunAssemblyInitializeIfNeeded(testMethodInfo, testContextForAssemblyInit); @@ -178,9 +186,9 @@ internal async Task RunSingleTestAsync(TestMethod testMethod, IDic } else { - ITestContext testContextForClassInit = PlatformServiceProvider.Instance.GetTestContext(testMethod, writer, properties, messageLogger, testContextForAssemblyInit.Context.CurrentTestOutcome); + testContextForClassInit = PlatformServiceProvider.Instance.GetTestContext(testMethod, properties, messageLogger, testContextForAssemblyInit.Context.CurrentTestOutcome); - TestResult classInitializeResult = testMethodInfo.Parent.GetResultOrRunClassInitialize(testContextForClassInit, assemblyInitializeResult.LogOutput!, assemblyInitializeResult.LogError!, assemblyInitializeResult.DebugTrace!, assemblyInitializeResult.TestContextMessages!); + TestResult classInitializeResult = testMethodInfo.Parent.GetResultOrRunClassInitialize(testContextForClassInit, assemblyInitializeResult.LogOutput, assemblyInitializeResult.LogError, assemblyInitializeResult.DebugTrace, assemblyInitializeResult.TestContextMessages); DebugEx.Assert(testMethodInfo.Parent.IsClassInitializeExecuted, "IsClassInitializeExecuted should be true after attempting to run it."); if (classInitializeResult.Outcome != UTF.UnitTestOutcome.Passed) { @@ -192,16 +200,13 @@ internal async Task RunSingleTestAsync(TestMethod testMethod, IDic testContextForTestExecution.SetOutcome(testContextForClassInit.Context.CurrentTestOutcome); RetryBaseAttribute? retryAttribute = testMethodInfo.RetryAttribute; var testMethodRunner = new TestMethodRunner(testMethodInfo, testMethod, testContextForTestExecution); - result = await testMethodRunner.ExecuteAsync(classInitializeResult.LogOutput!, classInitializeResult.LogError!, classInitializeResult.DebugTrace!, classInitializeResult.TestContextMessages!); + result = await testMethodRunner.ExecuteAsync(classInitializeResult.LogOutput, classInitializeResult.LogError, classInitializeResult.DebugTrace, classInitializeResult.TestContextMessages).ConfigureAwait(false); if (retryAttribute is not null && !RetryBaseAttribute.IsAcceptableResultForRetry(result)) { RetryResult retryResult = await retryAttribute.ExecuteAsync( new RetryContext( - async () => await testMethodRunner.ExecuteAsync( - classInitializeResult.LogOutput!, - classInitializeResult.LogError!, - classInitializeResult.DebugTrace!, - classInitializeResult.TestContextMessages!), result)); + async () => await testMethodRunner.ExecuteAsync(classInitializeResult.LogOutput, classInitializeResult.LogError, classInitializeResult.DebugTrace, classInitializeResult.TestContextMessages).ConfigureAwait(false), + result)).ConfigureAwait(false); result = retryResult.TryGetLast() ?? throw ApplicationStateGuard.Unreachable(); } @@ -209,12 +214,12 @@ internal async Task RunSingleTestAsync(TestMethod testMethod, IDic } } - ITestContext testContextForClassCleanup = PlatformServiceProvider.Instance.GetTestContext(testMethod, writer, properties, messageLogger, testContextForTestExecution.Context.CurrentTestOutcome); - testMethodInfo?.Parent.RunClassCleanup(testContextForClassCleanup, _classCleanupManager, testMethodInfo, testMethod, result); + testContextForClassCleanup = PlatformServiceProvider.Instance.GetTestContext(testMethod, properties, messageLogger, testContextForTestExecution.Context.CurrentTestOutcome); + testMethodInfo?.Parent.RunClassCleanup(testContextForClassCleanup, _classCleanupManager, testMethodInfo, result); if (testMethodInfo?.Parent.Parent.IsAssemblyInitializeExecuted == true) { - ITestContext testContextForAssemblyCleanup = PlatformServiceProvider.Instance.GetTestContext(testMethod, writer, properties, messageLogger, testContextForClassCleanup.Context.CurrentTestOutcome); + testContextForAssemblyCleanup = PlatformServiceProvider.Instance.GetTestContext(testMethod, properties, messageLogger, testContextForClassCleanup.Context.CurrentTestOutcome); RunAssemblyCleanupIfNeeded(testContextForAssemblyCleanup, _classCleanupManager, _typeCache, result); } @@ -232,37 +237,23 @@ internal async Task RunSingleTestAsync(TestMethod testMethod, IDic } ]; } + finally + { + (testContextForTestExecution as IDisposable)?.Dispose(); + (testContextForAssemblyInit as IDisposable)?.Dispose(); + (testContextForClassInit as IDisposable)?.Dispose(); + (testContextForClassCleanup as IDisposable)?.Dispose(); + (testContextForAssemblyCleanup as IDisposable)?.Dispose(); + } } private static TestResult RunAssemblyInitializeIfNeeded(TestMethodInfo testMethodInfo, ITestContext testContext) { - string? initializationLogs = string.Empty; - string? initializationErrorLogs = string.Empty; - string? initializationTrace = string.Empty; - string? initializationTestContextMessages = string.Empty; var result = new TestResult { Outcome = UnitTestOutcome.Passed }; try { - LogMessageListener? logListener = null; - try - { - testMethodInfo.Parent.Parent.RunAssemblyInitialize(testContext.Context, out logListener); - } - finally - { - if (logListener is not null) - { - ExecutionContextHelpers.RunOnContext(testMethodInfo.Parent.Parent.ExecutionContext, () => - { - initializationLogs = logListener.GetAndClearStandardOutput(); - initializationErrorLogs = logListener.GetAndClearStandardError(); - initializationTrace = logListener.GetAndClearDebugTrace(); - initializationTestContextMessages = testContext.GetAndClearDiagnosticMessages(); - logListener.Dispose(); - }); - } - } + testMethodInfo.Parent.Parent.RunAssemblyInitialize(testContext.Context); } catch (TestFailedException ex) { @@ -275,10 +266,11 @@ private static TestResult RunAssemblyInitializeIfNeeded(TestMethodInfo testMetho } finally { - result.LogOutput = initializationLogs; - result.LogError = initializationErrorLogs; - result.DebugTrace = initializationTrace; - result.TestContextMessages = initializationTestContextMessages; + var testContextImpl = testContext.Context as TestContextImplementation; + result.LogOutput = testContextImpl?.GetOut(); + result.LogError = testContextImpl?.GetErr(); + result.DebugTrace = testContextImpl?.GetTrace(); + result.TestContextMessages = testContext.GetAndClearDiagnosticMessages(); } return result; @@ -291,33 +283,16 @@ private static void RunAssemblyCleanupIfNeeded(ITestContext testContext, ClassCl return; } - string? initializationLogs = string.Empty; - string? initializationErrorLogs = string.Empty; - string? initializationTrace = string.Empty; - string? initializationTestContextMessages = string.Empty; try { - LogMessageListener? logListener = null; // TODO: We are using the same TestContext here for ClassCleanup and AssemblyCleanup. // They should be different. IEnumerable classInfoCache = typeCache.ClassInfoListWithExecutableCleanupMethods; foreach (TestClassInfo classInfo in classInfoCache) { - TestFailedException? ex = classInfo.ExecuteClassCleanup(testContext.Context, out logListener); - if (logListener is not null) - { - ExecutionContextHelpers.RunOnContext(classInfo.ExecutionContext, () => - { - initializationLogs += logListener.GetAndClearStandardOutput(); - initializationErrorLogs += logListener.GetAndClearStandardError(); - initializationTrace += logListener.GetAndClearDebugTrace(); - initializationTestContextMessages += testContext.GetAndClearDiagnosticMessages(); - logListener.Dispose(); - logListener = null; - }); - } + TestFailedException? ex = classInfo.ExecuteClassCleanup(testContext.Context); - if (ex is not null && results.Length > 0) + if (results.Length > 0 && ex is not null) { #pragma warning disable IDE0056 // Use index operator TestResult lastResult = results[results.Length - 1]; @@ -331,21 +306,9 @@ private static void RunAssemblyCleanupIfNeeded(ITestContext testContext, ClassCl IEnumerable assemblyInfoCache = typeCache.AssemblyInfoListWithExecutableCleanupMethods; foreach (TestAssemblyInfo assemblyInfo in assemblyInfoCache) { - TestFailedException? ex = assemblyInfo.ExecuteAssemblyCleanup(testContext.Context, ref logListener); - if (logListener is not null) - { - ExecutionContextHelpers.RunOnContext(assemblyInfo.ExecutionContext, () => - { - initializationLogs += logListener.GetAndClearStandardOutput(); - initializationErrorLogs += logListener.GetAndClearStandardError(); - initializationTrace += logListener.GetAndClearDebugTrace(); - initializationTestContextMessages += testContext.GetAndClearDiagnosticMessages(); - logListener.Dispose(); - logListener = null; - }); - } + TestFailedException? ex = assemblyInfo.ExecuteAssemblyCleanup(testContext.Context); - if (ex is not null && results.Length > 0) + if (results.Length > 0 && ex is not null) { #pragma warning disable IDE0056 // Use index operator TestResult lastResult = results[results.Length - 1]; @@ -363,10 +326,11 @@ private static void RunAssemblyCleanupIfNeeded(ITestContext testContext, ClassCl #pragma warning disable IDE0056 // Use index operator TestResult lastResult = results[results.Length - 1]; #pragma warning restore IDE0056 // Use index operator - lastResult.LogOutput += initializationLogs; - lastResult.LogError += initializationErrorLogs; - lastResult.DebugTrace += initializationTrace; - lastResult.TestContextMessages += initializationTestContextMessages; + var testContextImpl = testContext as TestContextImplementation; + lastResult.LogOutput += testContextImpl?.GetOut(); + lastResult.LogError += testContextImpl?.GetErr(); + lastResult.DebugTrace += testContextImpl?.GetTrace(); + lastResult.TestContextMessages += testContext.GetAndClearDiagnosticMessages(); } } } @@ -416,7 +380,7 @@ private static bool IsTestMethodRunnable( } bool shouldIgnoreClass = testMethodInfo.Parent.ClassType.IsIgnored(out string? ignoreMessageOnClass); - bool shouldIgnoreMethod = testMethodInfo.TestMethod.IsIgnored(out string? ignoreMessageOnMethod); + bool shouldIgnoreMethod = testMethodInfo.MethodInfo.IsIgnored(out string? ignoreMessageOnMethod); string? ignoreMessage = ignoreMessageOnClass; if (StringEx.IsNullOrEmpty(ignoreMessage) && shouldIgnoreMethod) diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Extensions/ExceptionExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/ExceptionExtensions.cs index 249c88e47f..4dac689e2b 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Extensions/ExceptionExtensions.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/ExceptionExtensions.cs @@ -1,6 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; + namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; /// @@ -30,4 +36,76 @@ internal static string GetExceptionMessage(this Exception exception) internal static bool IsOperationCanceledExceptionFromToken(this Exception ex, CancellationToken cancellationToken) => (ex is OperationCanceledException oce && oce.CancellationToken == cancellationToken) || (ex is AggregateException aggregateEx && aggregateEx.InnerExceptions.OfType().Any(oce => oce.CancellationToken == cancellationToken)); + + /// + /// TargetInvocationException and TypeInitializationException do not carry any useful information + /// to the user. Find the first inner exception that has useful information. + /// + internal static Exception GetRealException(this Exception exception) + { + // TargetInvocationException: Because .NET Framework wraps method.Invoke() into TargetInvocationException. + // TypeInitializationException: Because AssemblyInitialize is static, and often helpers that are also static + // are used to implement it, and they fail in constructor. + while (exception is TargetInvocationException or TypeInitializationException + && exception.InnerException is not null) + { + exception = exception.InnerException; + } + + return exception; + } + + /// + /// Get the exception message if available, empty otherwise. + /// + /// An object. + /// Exception message. + internal static string TryGetMessage(this Exception? exception) + { + if (exception == null) + { + return string.Format(CultureInfo.CurrentCulture, Resource.UTF_FailedToGetExceptionMessage, "null"); + } + + // It is safe to retrieve an exception message, it should not throw in any case. + return exception.Message ?? string.Empty; + } + + /// + /// Gets the for an exception. + /// + /// An instance. + /// StackTraceInformation for the exception. + internal static StackTraceInformation? TryGetStackTraceInformation(this Exception exception) + => !StringEx.IsNullOrEmpty(exception.StackTrace) + ? ExceptionHelper.CreateStackTraceInformation(exception.StackTrace) + : null; + + /// + /// Checks whether exception is an Assert exception. + /// + /// An instance. + /// Framework's Outcome depending on type of assertion. + /// Exception message. + /// StackTraceInformation for the exception. + /// True, if Assert exception. False, otherwise. + internal static bool TryGetUnitTestAssertException(this Exception exception, out UTF.UnitTestOutcome outcome, + [NotNullWhen(true)] out string? exceptionMessage, out StackTraceInformation? exceptionStackTrace) + { + if (exception is UnitTestAssertException) + { + outcome = exception is AssertInconclusiveException + ? UTF.UnitTestOutcome.Inconclusive + : UTF.UnitTestOutcome.Failed; + + exceptionMessage = exception.TryGetMessage(); + exceptionStackTrace = exception.TryGetStackTraceInformation(); + return true; + } + + outcome = UTF.UnitTestOutcome.Failed; + exceptionMessage = null; + exceptionStackTrace = null; + return false; + } } diff --git a/src/Adapter/MSTest.TestAdapter/Extensions/MethodInfoExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs similarity index 87% rename from src/Adapter/MSTest.TestAdapter/Extensions/MethodInfoExtensions.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs index 87be62dd88..46fb6e6d53 100644 --- a/src/Adapter/MSTest.TestAdapter/Extensions/MethodInfoExtensions.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs @@ -4,6 +4,8 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; @@ -91,8 +93,17 @@ internal static bool HasCorrectTestMethodSignature(this MethodInfo method, bool /// True if the method has a void/task return type.. internal static bool IsValidReturnType(this MethodInfo method, ReflectHelper? reflectHelper = null) => ReflectHelper.MatchReturnType(method, typeof(Task)) - || ReflectHelper.MatchReturnType(method, typeof(ValueTask)) - || (ReflectHelper.MatchReturnType(method, typeof(void)) && method.GetAsyncTypeName(reflectHelper) == null); + || (ReflectHelper.MatchReturnType(method, typeof(void)) && method.GetAsyncTypeName(reflectHelper) == null) + // Keep this the last check, as it avoids loading System.Threading.Tasks.Extensions unnecessarily. + || method.IsValueTask(); + + // Avoid loading System.Threading.Tasks.Extensions if not needed. + // Note: .NET runtime will load all types once it's entering the method. + // So, moving this out of the method will load System.Threading.Tasks.Extensions + // Even when invokeResult is null or Task. + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsValueTask(this MethodInfo method) + => ReflectHelper.MatchReturnType(method, typeof(ValueTask)); /// /// For async methods compiler generates different type and method. @@ -103,11 +114,11 @@ internal static bool IsValidReturnType(this MethodInfo method, ReflectHelper? re /// Compiler generated type name for given async test method.. internal static string? GetAsyncTypeName(this MethodInfo method, ReflectHelper? reflectHelper = null) { - AsyncStateMachineAttribute? asyncStateMachineAttribute = (reflectHelper ?? ReflectHelper.Instance).GetFirstNonDerivedAttributeOrDefault(method, inherit: false); + AsyncStateMachineAttribute? asyncStateMachineAttribute = (reflectHelper ?? ReflectHelper.Instance).GetFirstAttributeOrDefault(method, inherit: false); return asyncStateMachineAttribute?.StateMachineType?.FullName; } - internal static object? GetInvokeResult(this MethodInfo methodInfo, object? classInstance, params object?[]? arguments) + internal static Task? GetInvokeResultAsync(this MethodInfo methodInfo, object? classInstance, params object?[]? arguments) { ParameterInfo[]? methodParameters = methodInfo.GetParameters(); @@ -166,15 +177,28 @@ internal static bool IsValidReturnType(this MethodInfo method, ReflectHelper? re methodInfo.DeclaringType!.FullName, methodInfo.Name, methodParametersLengthOrZero, - string.Join(", ", methodParameters?.Select(p => p.ParameterType.Name) ?? Array.Empty()), + string.Join(", ", methodParameters?.Select(p => p.ParameterType.Name) ?? []), argumentsLengthOrZero, - string.Join(", ", arguments?.Select(a => a?.GetType().Name ?? "null") ?? Array.Empty())), ex); + string.Join(", ", arguments?.Select(a => a?.GetType().Name ?? "null") ?? [])), ex); } } - return invokeResult; + return invokeResult switch + { + null => null, + Task t => t, + _ => TryGetTaskFromValueTaskAsync(invokeResult), + }; } + // Avoid loading System.Threading.Tasks.Extensions if not needed. + // Note: .NET runtime will load all types once it's entering the method. + // So, moving this out of the method will load System.Threading.Tasks.Extensions + // Even when invokeResult is null or Task. + [MethodImpl(MethodImplOptions.NoInlining)] + private static Task? TryGetTaskFromValueTaskAsync(object invokeResult) + => (invokeResult as ValueTask?)?.AsTask(); + /// /// Invoke a as a synchronous . /// @@ -189,17 +213,8 @@ internal static bool IsValidReturnType(this MethodInfo method, ReflectHelper? re /// internal static void InvokeAsSynchronousTask(this MethodInfo methodInfo, object? classInstance, params object?[]? arguments) { - object? invokeResult = methodInfo.GetInvokeResult(classInstance, arguments); - - // If methodInfo is an async method, wait for returned task - if (invokeResult is Task task) - { - task.GetAwaiter().GetResult(); - } - else if (invokeResult is ValueTask valueTask) - { - valueTask.GetAwaiter().GetResult(); - } + Task? invokeResult = methodInfo.GetInvokeResultAsync(classInstance, arguments); + invokeResult?.GetAwaiter().GetResult(); } private static void InferGenerics(Type parameterType, Type argumentType, List<(Type ParameterType, Type Substitution)> result) diff --git a/src/Adapter/MSTest.TestAdapter/Extensions/TestCaseExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/TestCaseExtensions.cs similarity index 81% rename from src/Adapter/MSTest.TestAdapter/Extensions/TestCaseExtensions.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Extensions/TestCaseExtensions.cs index 35f2d18207..a016393e82 100644 --- a/src/Adapter/MSTest.TestAdapter/Extensions/TestCaseExtensions.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/TestCaseExtensions.cs @@ -3,6 +3,7 @@ using Microsoft.TestPlatform.AdapterUtilities; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -69,73 +70,72 @@ internal static string GetTestName(this TestCase testCase, string? testClassName /// The converted . internal static UnitTestElement ToUnitTestElement(this TestCase testCase, string source) { - string? testClassName = testCase.GetPropertyValue(Constants.TestClassNameProperty) as string; + string? testClassName = testCase.GetPropertyValue(EngineConstants.TestClassNameProperty) as string; string name = testCase.GetTestName(testClassName); var testIdGenerationStrategy = (TestIdGenerationStrategy)testCase.GetPropertyValue( - Constants.TestIdGenerationStrategyProperty, + EngineConstants.TestIdGenerationStrategyProperty, (int)TestIdGenerationStrategy.FullyQualified); TestMethod testMethod = testCase.ContainsManagedMethodAndType() ? new(testCase.GetManagedType(), testCase.GetManagedMethod(), testCase.GetHierarchy()!, name, testClassName!, source, testCase.DisplayName, testIdGenerationStrategy) : new(name, testClassName!, source, testCase.DisplayName, testIdGenerationStrategy); - var dataType = (DynamicDataType)testCase.GetPropertyValue(Constants.TestDynamicDataTypeProperty, (int)DynamicDataType.None); + var dataType = (DynamicDataType)testCase.GetPropertyValue(EngineConstants.TestDynamicDataTypeProperty, (int)DynamicDataType.None); if (dataType != DynamicDataType.None) { - string[]? data = testCase.GetPropertyValue(Constants.TestDynamicDataProperty, null); + string[]? data = testCase.GetPropertyValue(EngineConstants.TestDynamicDataProperty, null); testMethod.DataType = dataType; testMethod.SerializedData = data; - testMethod.TestDataSourceIgnoreMessage = testCase.GetPropertyValue(Constants.TestDataSourceIgnoreMessageProperty) as string; + if (UnitTestDiscoverer.TryGetActualData(testCase, out object?[]? actualData)) + { + testMethod.ActualData = actualData; + } + + testMethod.TestDataSourceIgnoreMessage = testCase.GetPropertyValue(EngineConstants.TestDataSourceIgnoreMessageProperty) as string; } - if (testCase.GetPropertyValue(Constants.DeclaringClassNameProperty) is string declaringClassName && declaringClassName != testClassName) + if (testCase.GetPropertyValue(EngineConstants.DeclaringClassNameProperty) is string declaringClassName && declaringClassName != testClassName) { testMethod.DeclaringClassFullName = declaringClassName; } UnitTestElement testElement = new(testMethod) { - TestCategory = testCase.GetPropertyValue(Constants.TestCategoryProperty) as string[], - Priority = testCase.GetPropertyValue(Constants.PriorityProperty) as int?, + TestCategory = testCase.GetPropertyValue(EngineConstants.TestCategoryProperty) as string[], + Priority = testCase.GetPropertyValue(EngineConstants.PriorityProperty) as int?, DisplayName = testCase.DisplayName, }; if (testCase.Traits.Any()) { - testElement.Traits = testCase.Traits.ToArray(); + testElement.Traits = [.. testCase.Traits]; } - string? cssIteration = testCase.GetPropertyValue(Constants.CssIterationProperty, null); + string? cssIteration = testCase.GetPropertyValue(EngineConstants.CssIterationProperty, null); if (!StringEx.IsNullOrWhiteSpace(cssIteration)) { testElement.CssIteration = cssIteration; } - string? cssProjectStructure = testCase.GetPropertyValue(Constants.CssProjectStructureProperty, null); + string? cssProjectStructure = testCase.GetPropertyValue(EngineConstants.CssProjectStructureProperty, null); if (!StringEx.IsNullOrWhiteSpace(cssProjectStructure)) { testElement.CssProjectStructure = cssProjectStructure; } - string? description = testCase.GetPropertyValue(Constants.DescriptionProperty, null); - if (!StringEx.IsNullOrWhiteSpace(description)) - { - testElement.Description = description; - } - - string[]? workItemIds = testCase.GetPropertyValue(Constants.WorkItemIdsProperty, null); + string[]? workItemIds = testCase.GetPropertyValue(EngineConstants.WorkItemIdsProperty, null); if (workItemIds is { Length: > 0 }) { testElement.WorkItemIds = workItemIds; } - KeyValuePair[]? deploymentItems = testCase.GetPropertyValue[]>(Constants.DeploymentItemsProperty, null); + KeyValuePair[]? deploymentItems = testCase.GetPropertyValue[]>(EngineConstants.DeploymentItemsProperty, null); if (deploymentItems is { Length: > 0 }) { testElement.DeploymentItems = deploymentItems; } - testElement.DoNotParallelize = testCase.GetPropertyValue(Constants.DoNotParallelizeProperty, false); + testElement.DoNotParallelize = testCase.GetPropertyValue(EngineConstants.DoNotParallelizeProperty, false); return testElement; } @@ -146,8 +146,6 @@ internal static UnitTestElement ToUnitTestElement(this TestCase testCase, string internal static string? GetManagedMethod(this TestCase testCase) => testCase.GetPropertyValue(ManagedMethodProperty, null); - internal static void SetManagedMethod(this TestCase testCase, string value) => testCase.SetPropertyValue(ManagedMethodProperty, value); - internal static bool ContainsManagedMethodAndType(this TestCase testCase) => !StringEx.IsNullOrWhiteSpace(testCase.GetManagedMethod()) && !StringEx.IsNullOrWhiteSpace(testCase.GetManagedType()); internal static string[]? GetHierarchy(this TestCase testCase) => testCase.GetPropertyValue(HierarchyProperty, null); diff --git a/src/Adapter/MSTest.TestAdapter/Extensions/TestContextExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/TestContextExtensions.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Extensions/TestContextExtensions.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Extensions/TestContextExtensions.cs diff --git a/src/Adapter/MSTest.TestAdapter/Extensions/TestResultExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/TestResultExtensions.cs similarity index 80% rename from src/Adapter/MSTest.TestAdapter/Extensions/TestResultExtensions.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Extensions/TestResultExtensions.cs index 7f5c5b80ac..b6e54ec833 100644 --- a/src/Adapter/MSTest.TestAdapter/Extensions/TestResultExtensions.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/TestResultExtensions.cs @@ -3,6 +3,8 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; using Microsoft.VisualStudio.TestTools.UnitTesting; using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; @@ -19,9 +21,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; /// Extension methods for TestResult. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public static class TestResultExtensions { @@ -34,7 +36,7 @@ public static class TestResultExtensions /// The end Time. /// The computer name. /// Current MSTest settings. - internal static VSTestTestResult ToTestResult(this UTF.TestResult frameworkTestResult, VSTestTestCase testCase, DateTimeOffset startTime, DateTimeOffset endTime, string computerName, MSTestSettings currentSettings) + internal static VSTestTestResult ToTestResult(this TestResult frameworkTestResult, VSTestTestCase testCase, DateTimeOffset startTime, DateTimeOffset endTime, string computerName, MSTestSettings currentSettings) { DebugEx.Assert(testCase != null, "testCase"); @@ -50,9 +52,9 @@ internal static VSTestTestResult ToTestResult(this UTF.TestResult frameworkTestR ComputerName = computerName, }; - testResult.SetPropertyValue(Constants.ExecutionIdProperty, frameworkTestResult.ExecutionId); - testResult.SetPropertyValue(Constants.ParentExecIdProperty, frameworkTestResult.ParentExecId); - testResult.SetPropertyValue(Constants.InnerResultsCountProperty, frameworkTestResult.InnerResultsCount); + testResult.SetPropertyValue(EngineConstants.ExecutionIdProperty, frameworkTestResult.ExecutionId); + testResult.SetPropertyValue(EngineConstants.ParentExecIdProperty, frameworkTestResult.ParentExecId); + testResult.SetPropertyValue(EngineConstants.InnerResultsCountProperty, frameworkTestResult.InnerResultsCount); if (!StringEx.IsNullOrEmpty(frameworkTestResult.LogOutput)) { @@ -68,21 +70,33 @@ internal static VSTestTestResult ToTestResult(this UTF.TestResult frameworkTestR if (!StringEx.IsNullOrEmpty(frameworkTestResult.DebugTrace)) { - string debugTraceMessagesInStdOut = string.Format(CultureInfo.CurrentCulture, "{2}{2}{0}{2}{1}", Resource.DebugTraceBanner, frameworkTestResult.DebugTrace, Environment.NewLine); + string debugTraceMessagesInStdOut = + $""" + + + {Resource.DebugTraceBanner} + {frameworkTestResult.DebugTrace} + """; VSTestTestResultMessage debugTraceMessage = new(VSTestTestResultMessage.StandardOutCategory, debugTraceMessagesInStdOut); testResult.Messages.Add(debugTraceMessage); } if (!StringEx.IsNullOrEmpty(frameworkTestResult.TestContextMessages)) { - string testContextMessagesInStdOut = string.Format(CultureInfo.InvariantCulture, "{2}{2}{0}{2}{1}", Resource.TestContextMessageBanner, frameworkTestResult.TestContextMessages, Environment.NewLine); + string testContextMessagesInStdOut = + $""" + + + {Resource.TestContextMessageBanner} + {frameworkTestResult.TestContextMessages} + """; VSTestTestResultMessage testContextMessage = new(VSTestTestResultMessage.StandardOutCategory, testContextMessagesInStdOut); testResult.Messages.Add(testContextMessage); } if (frameworkTestResult.ResultFiles is { Count: > 0 }) { - VSTestAttachmentSet attachmentSet = new(Constants.ExecutorUri, Resource.AttachmentSetDisplayName); + VSTestAttachmentSet attachmentSet = new(EngineConstants.ExecutorUri, Resource.AttachmentSetDisplayName); foreach (string resultFile in frameworkTestResult.ResultFiles) { string pathToResultFile = PlatformServiceProvider.Instance.FileOperations.GetFullFilePath(resultFile); @@ -106,12 +120,12 @@ internal static VSTestTestResult ToTestResult(this UTF.TestResult frameworkTestR /// /// The test framework's TestResult object array. /// The serializable UnitTestResult object array. - public static UnitTestResult[] ToUnitTestResults(this UTF.TestResult[] testResults) + public static UnitTestResult[] ToUnitTestResults(this TestResult[] testResults) { var unitTestResults = new UnitTestResult[testResults.Length]; int i = 0; - foreach (UTF.TestResult testResult in testResults) + foreach (TestResult testResult in testResults) { UTF.UnitTestOutcome outcome = testResult.Outcome; diff --git a/src/Adapter/MSTest.TestAdapter/Extensions/UnitTestOutcomeExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/UnitTestOutcomeExtensions.cs similarity index 92% rename from src/Adapter/MSTest.TestAdapter/Extensions/UnitTestOutcomeExtensions.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Extensions/UnitTestOutcomeExtensions.cs index ee6489d37e..171d7280b8 100644 --- a/src/Adapter/MSTest.TestAdapter/Extensions/UnitTestOutcomeExtensions.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/UnitTestOutcomeExtensions.cs @@ -11,9 +11,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; /// Extension methods for . /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public static class UnitTestOutcomeExtensions { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Friends.cs b/src/Adapter/MSTestAdapter.PlatformServices/Friends.cs deleted file mode 100644 index ca53146909..0000000000 --- a/src/Adapter/MSTestAdapter.PlatformServices/Friends.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -// Friend assemblies -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.UWP.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.WinUI.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("MSTestAdapter.PlatformServices.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("PlatformServices.Desktop.IntegrationTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] -[assembly: InternalsVisibleTo("MSTest.TestAnywhereAdapter, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/AttributeHelpers.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/AttributeHelpers.cs similarity index 94% rename from src/Adapter/MSTest.TestAdapter/Helpers/AttributeHelpers.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/AttributeHelpers.cs index 673fbfb4fd..b112d05c87 100644 --- a/src/Adapter/MSTest.TestAdapter/Helpers/AttributeHelpers.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/AttributeHelpers.cs @@ -9,7 +9,7 @@ internal static class AttributeExtensions { public static bool IsIgnored(this ICustomAttributeProvider type, out string? ignoreMessage) { - IEnumerable attributes = ReflectHelper.Instance.GetDerivedAttributes(type, inherit: false); + IEnumerable attributes = ReflectHelper.Instance.GetAttributes(type, inherit: false); IEnumerable> groups = attributes.GroupBy(attr => attr.GroupName); foreach (IGrouping? group in groups) { diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/DataSerializationHelper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/DataSerializationHelper.cs similarity index 68% rename from src/Adapter/MSTest.TestAdapter/Helpers/DataSerializationHelper.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/DataSerializationHelper.cs index efafabaa74..c7c980e9fd 100644 --- a/src/Adapter/MSTest.TestAdapter/Helpers/DataSerializationHelper.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/DataSerializationHelper.cs @@ -1,6 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#if NETFRAMEWORK +using System.CodeDom; +using System.Collections.ObjectModel; +#endif +using System.Runtime.Serialization; using System.Runtime.Serialization.Json; namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; @@ -12,7 +17,11 @@ internal static class DataSerializationHelper { UseSimpleDictionaryFormat = true, EmitTypeInformation = System.Runtime.Serialization.EmitTypeInformation.Always, - DateTimeFormat = new System.Runtime.Serialization.DateTimeFormat("O", CultureInfo.InvariantCulture), + DateTimeFormat = new DateTimeFormat("O", CultureInfo.InvariantCulture), +#if NETFRAMEWORK + DataContractSurrogate = SerializationSurrogateProvider.Instance, +#endif + KnownTypes = [typeof(SurrogatedDateOnly), typeof(SurrogatedTimeOnly)], }; /// @@ -47,6 +56,9 @@ internal static class DataSerializationHelper serializedData[typeIndex] = typeName; DataContractJsonSerializer serializer = GetSerializer(type); +#if NET7_0_OR_GREATER + serializer.SetSerializationSurrogateProvider(SerializationSurrogateProvider.Instance); +#endif using var memoryStream = new MemoryStream(); // This should be safe as long as our generator mentions @@ -93,6 +105,9 @@ internal static class DataSerializationHelper } DataContractJsonSerializer serializer = GetSerializer(assemblyQualifiedName); +#if NET7_0_OR_GREATER + serializer.SetSerializationSurrogateProvider(SerializationSurrogateProvider.Instance); +#endif byte[] serializedDataBytes = Encoding.UTF8.GetBytes(serializedValue); using var memoryStream = new MemoryStream(serializedDataBytes); @@ -104,6 +119,9 @@ internal static class DataSerializationHelper data[i] = serializer.ReadObject(memoryStream); #pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT #pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming + // For some reason, we don't get SerializationSurrogateProvider.GetDeserializedObject to be called by .NET runtime. + // So we manually call it. + data[i] = SerializationSurrogateProvider.GetDeserializedObject(data[i]!); } return data; @@ -130,6 +148,93 @@ private static DataContractJsonSerializer GetSerializer(Type type) #pragma warning disable IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT #pragma warning disable IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming _ => new DataContractJsonSerializer(type, SerializerSettings)); + + [DataContract] + private sealed class SurrogatedDateOnly + { + [DataMember] + public int DayNumber { get; set; } + } + + [DataContract] + private sealed class SurrogatedTimeOnly + { + [DataMember] + public long Ticks { get; set; } + } + + private sealed class SerializationSurrogateProvider +#if NETFRAMEWORK + : IDataContractSurrogate +#else + : ISerializationSurrogateProvider +#endif + { + public static SerializationSurrogateProvider Instance { get; } = new(); + +#if NETFRAMEWORK + public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) => null!; + + public object GetCustomDataToExport(Type clrType, Type dataContractType) => null!; + + public void GetKnownCustomDataTypes(Collection customDataTypes) + { + } + + public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) => null!; + + public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) => typeDeclaration; +#endif + + public object GetDeserializedObject(object obj, Type targetType) + => GetDeserializedObject(obj); + + internal static object GetDeserializedObject(object obj) + { +#if NET6_0_OR_GREATER + if (obj is SurrogatedDateOnly surrogatedDateOnly) + { + return DateOnly.FromDayNumber(surrogatedDateOnly.DayNumber); + } + else if (obj is SurrogatedTimeOnly surrogatedTimeOnly) + { + return new TimeOnly(surrogatedTimeOnly.Ticks); + } +#endif + + return obj; + } + + public object GetObjectToSerialize(object obj, Type targetType) + => obj switch + { +#if NET6_0_OR_GREATER + DateOnly dateOnly => new SurrogatedDateOnly() { DayNumber = dateOnly.DayNumber }, + TimeOnly timeOnly => new SurrogatedTimeOnly() { Ticks = timeOnly.Ticks }, +#endif + _ => obj, + }; + +#if NETFRAMEWORK + public Type GetDataContractType(Type type) +#else + public Type GetSurrogateType(Type type) +#endif + { +#if NET6_0_OR_GREATER + if (type == typeof(DateOnly)) + { + return typeof(SurrogatedDateOnly); + } + else if (type == typeof(TimeOnly)) + { + return typeof(SurrogatedTimeOnly); + } +#endif + + return type; + } + } #pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT #pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming } diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/DictionaryHelper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/DictionaryHelper.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Helpers/DictionaryHelper.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/DictionaryHelper.cs diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/ExecutionContextHelpers.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ExecutionContextHelpers.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Helpers/ExecutionContextHelpers.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/ExecutionContextHelpers.cs diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/FixtureKind.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/FixtureKind.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Helpers/FixtureKind.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/FixtureKind.cs diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/FixtureMethodRunner.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/FixtureMethodRunner.cs similarity index 85% rename from src/Adapter/MSTest.TestAdapter/Helpers/FixtureMethodRunner.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/FixtureMethodRunner.cs index 6653057879..5feb0ce26b 100644 --- a/src/Adapter/MSTest.TestAdapter/Helpers/FixtureMethodRunner.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/FixtureMethodRunner.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; @@ -36,26 +35,22 @@ internal static class FixtureMethodRunner return null; } catch (Exception ex) + when (ex.GetRealException().IsOperationCanceledExceptionFromToken(cancellationTokenSource.Token)) { - if (ex.GetRealException().IsOperationCanceledExceptionFromToken(cancellationTokenSource.Token)) - { - return new( - UnitTestOutcome.Timeout, - testTimeoutInfo?.TokenSource.Token.IsCancellationRequested == true - ? string.Format( - CultureInfo.InvariantCulture, - methodTimedOutMessageFormat, - methodInfo.DeclaringType!.FullName, - methodInfo.Name, - testTimeoutInfo.Value.Timeout) - : string.Format( - CultureInfo.InvariantCulture, - methodCanceledMessageFormat, - methodInfo.DeclaringType!.FullName, - methodInfo.Name)); - } - - throw; + return new( + UnitTestOutcome.Timeout, + testTimeoutInfo?.TokenSource.Token.IsCancellationRequested == true + ? string.Format( + CultureInfo.InvariantCulture, + methodTimedOutMessageFormat, + methodInfo.DeclaringType!.FullName, + methodInfo.Name, + testTimeoutInfo.Value.Timeout) + : string.Format( + CultureInfo.InvariantCulture, + methodCanceledMessageFormat, + methodInfo.DeclaringType!.FullName, + methodInfo.Name)); } } @@ -173,15 +168,10 @@ internal static class FixtureMethodRunner UnitTestOutcome.Timeout, string.Format(CultureInfo.InvariantCulture, methodCanceledMessageFormat, methodInfo.DeclaringType!.FullName, methodInfo.Name)); } - catch (Exception) + catch (Exception) when (realException is not null) { // We throw the real exception to have the original stack trace to elaborate up the chain. - if (realException is not null) - { - throw realException; - } - - throw; + throw realException; } } @@ -237,20 +227,15 @@ internal static class FixtureMethodRunner UnitTestOutcome.Timeout, string.Format(CultureInfo.InvariantCulture, methodCanceledMessageFormat, methodInfo.DeclaringType!.FullName, methodInfo.Name)); } - catch (Exception) + catch (Exception) when (realException is not null) { // We throw the real exception to have the original stack trace to elaborate up the chain. - // Also note that tcs.Task.Exception can be an AggregateException, so we favor the "real exception". - if (realException is not null) - { - throw realException; - } - else if (tcs.Task.Exception is not null) - { - throw tcs.Task.Exception; - } - - throw; + throw realException; + } + catch (Exception) when (tcs.Task.Exception is not null) + { + // The tcs.Task.Exception can be an AggregateException, so we favor the "real exception". + throw tcs.Task.Exception; } } } diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/MSTestDiscovererHelpers.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/MSTestDiscovererHelpers.cs similarity index 96% rename from src/Adapter/MSTest.TestAdapter/Helpers/MSTestDiscovererHelpers.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/MSTestDiscovererHelpers.cs index 3b76323e58..1a5b5ef336 100644 --- a/src/Adapter/MSTest.TestAdapter/Helpers/MSTestDiscovererHelpers.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/MSTestDiscovererHelpers.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ReflectHelper.cs similarity index 69% rename from src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/ReflectHelper.cs index 3d3cd4e937..c671899b5a 100644 --- a/src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ReflectHelper.cs @@ -3,7 +3,7 @@ using System.Security; -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -24,35 +24,6 @@ internal class ReflectHelper : MarshalByRefObject public static ReflectHelper Instance => InstanceValue.Value; - /// - /// Checks to see if a member or type is decorated with the given attribute. The type is checked exactly. If attribute is derived (inherits from) a class, e.g. [MyTestClass] from [TestClass] it won't match if you look for [TestClass]. The inherit parameter does not impact this checking. - /// - /// - /// Note that because derived attribute types are not considered, should be sealed. - /// - /// Attribute to search for by fully qualified name. - /// Member/Type to test. - /// Inspect inheritance chain of the member or class. E.g. if parent class has this attribute defined. - /// True if the attribute of the specified type is defined on this member or a class. - public virtual bool IsNonDerivedAttributeDefined(MemberInfo memberInfo, bool inherit) - where TAttribute : Attribute - { - Guard.NotNull(memberInfo); - - // Get attributes defined on the member from the cache. - Attribute[] attributes = GetCustomAttributesCached(memberInfo, inherit); - - foreach (Attribute attribute in attributes) - { - if (AttributeComparer.IsNonDerived(attribute)) - { - return true; - } - } - - return false; - } - /// /// Checks to see if a member or type is decorated with the given attribute, or an attribute that derives from it. e.g. [MyTestClass] from [TestClass] will match if you look for [TestClass]. The inherit parameter does not impact this checking. /// @@ -60,7 +31,7 @@ public virtual bool IsNonDerivedAttributeDefined(MemberInfo memberIn /// Member to inspect for attributes. /// Inspect inheritance chain of the member or class. E.g. if parent class has this attribute defined. /// True if the attribute of the specified type is defined on this member or a class. - public virtual /* for testing */ bool IsDerivedAttributeDefined(MemberInfo memberInfo, bool inherit) + public virtual /* for testing */ bool IsAttributeDefined(MemberInfo memberInfo, bool inherit) where TAttribute : Attribute { Guard.NotNull(memberInfo); @@ -73,7 +44,7 @@ public virtual bool IsNonDerivedAttributeDefined(MemberInfo memberIn { DebugEx.Assert(attribute != null, $"{nameof(ReflectHelper)}.{nameof(GetCustomAttributesCached)}: internal error: wrong value in the attributes dictionary."); - if (AttributeComparer.IsDerived(attribute)) + if (attribute is TAttribute) { return true; } @@ -94,31 +65,6 @@ public virtual bool IsNonDerivedAttributeDefined(MemberInfo memberIn #endif public override object InitializeLifetimeService() => null!; - /// - /// Gets first attribute that matches the type (but is not derived from it). Use this together with attribute that is both sealed and does not allow multiple. - /// In such case there cannot be more attributes, and this will avoid the cost of - /// checking for more than one attribute. - /// - /// Type of the attribute to find. - /// The type, assembly or method. - /// If we should inspect parents of this type. - /// The attribute that is found or null. - public virtual /* for tests, for moq */ TAttribute? GetFirstNonDerivedAttributeOrDefault(ICustomAttributeProvider attributeProvider, bool inherit) - where TAttribute : Attribute - { - Attribute[] cachedAttributes = GetCustomAttributesCached(attributeProvider, inherit); - - foreach (Attribute cachedAttribute in cachedAttributes) - { - if (AttributeComparer.IsNonDerived(cachedAttribute)) - { - return (TAttribute)cachedAttribute; - } - } - - return null; - } - /// /// Gets first attribute that matches the type or is derived from it. /// Use this together with attribute that does not allow multiple. In such case there cannot be more attributes, and this will avoid the cost of @@ -129,16 +75,16 @@ public virtual bool IsNonDerivedAttributeDefined(MemberInfo memberIn /// If we should inspect parents of this type. /// The attribute that is found or null. /// Throws when multiple attributes are found (the attribute must allow multiple). - public virtual /* for tests, for moq */ TAttribute? GetFirstDerivedAttributeOrDefault(ICustomAttributeProvider attributeProvider, bool inherit) + public virtual /* for tests, for moq */ TAttribute? GetFirstAttributeOrDefault(ICustomAttributeProvider attributeProvider, bool inherit) where TAttribute : Attribute { Attribute[] cachedAttributes = GetCustomAttributesCached(attributeProvider, inherit); foreach (Attribute cachedAttribute in cachedAttributes) { - if (AttributeComparer.IsDerived(cachedAttribute)) + if (cachedAttribute is TAttribute cachedAttributeAsTAttribute) { - return (TAttribute)cachedAttribute; + return cachedAttributeAsTAttribute; } } @@ -175,11 +121,11 @@ internal virtual bool IsMethodDeclaredInSameAssemblyAsType(MethodInfo method, Ty /// Categories defined. internal virtual /* for tests, we are mocking this */ string[] GetTestCategories(MemberInfo categoryAttributeProvider, Type owningType) { - IEnumerable methodCategories = GetDerivedAttributes(categoryAttributeProvider, inherit: true); - IEnumerable typeCategories = GetDerivedAttributes(owningType, inherit: true); - IEnumerable assemblyCategories = GetDerivedAttributes(owningType.Assembly, inherit: true); + IEnumerable methodCategories = GetAttributes(categoryAttributeProvider, inherit: true); + IEnumerable typeCategories = GetAttributes(owningType, inherit: true); + IEnumerable assemblyCategories = GetAttributes(owningType.Assembly, inherit: true); - return methodCategories.Concat(typeCategories).Concat(assemblyCategories).SelectMany(c => c.TestCategories).ToArray(); + return [.. methodCategories.Concat(typeCategories).Concat(assemblyCategories).SelectMany(c => c.TestCategories)]; } /// @@ -236,8 +182,8 @@ internal static TestIdGenerationStrategy GetTestIdGenerationStrategy(Assembly as /// The type that owns . /// True if test method should not run in parallel. internal bool IsDoNotParallelizeSet(MemberInfo testMethod, Type owningType) - => IsDerivedAttributeDefined(testMethod, inherit: true) - || IsDerivedAttributeDefined(owningType, inherit: true); + => IsAttributeDefined(testMethod, inherit: true) + || IsAttributeDefined(owningType, inherit: true); /// /// Get the parallelization behavior for a test assembly. @@ -258,29 +204,6 @@ internal static bool IsDoNotParallelizeSet(Assembly assembly) .OfType() .FirstOrDefault(); - /// - /// KeyValue pairs that are provided by TestOwnerAttribute of the given test method. - /// - /// The member to inspect. - /// The owner trait. - internal virtual Trait? GetTestOwnerAsTraits(MemberInfo ownerAttributeProvider) - { - string? owner = GetOwner(ownerAttributeProvider); - - return StringEx.IsNullOrEmpty(owner) - ? null - : new Trait("Owner", owner); - } - - /// - /// KeyValue pairs that are provided by TestPriorityAttributes of the given test method. - /// - /// The priority. - /// The corresponding trait. - internal virtual Trait? GetTestPriorityAsTraits(int? testPriority) => testPriority == null - ? null - : new Trait("Priority", ((int)testPriority).ToString(CultureInfo.InvariantCulture)); - /// /// Priority if any set for test method. Will return priority if attribute is applied to TestMethod /// else null. @@ -288,33 +211,7 @@ internal static bool IsDoNotParallelizeSet(Assembly assembly) /// The member to inspect. /// Priority value if defined. Null otherwise. internal virtual int? GetPriority(MemberInfo priorityAttributeProvider) => - GetFirstDerivedAttributeOrDefault(priorityAttributeProvider, inherit: true)?.Priority; - - /// - /// Gets the class cleanup lifecycle for the class, if set. - /// - /// The class to inspect. - /// Returns if provided, otherwise null. - internal virtual ClassCleanupBehavior? GetClassCleanupBehavior(TestClassInfo classInfo) - { - // TODO: not discovery related but seems expensive and unnecessary, because we do inheritance lookup, and to put the method into the stack we've already did this lookup before? - if (!classInfo.HasExecutableCleanupMethod) - { - return null; - } - - var cleanupBehaviors = - new HashSet( - classInfo.BaseClassCleanupMethods - .Select(x => GetFirstDerivedAttributeOrDefault(x, inherit: true)?.CleanupBehavior)) - { - classInfo.ClassCleanupMethod == null ? null : GetFirstDerivedAttributeOrDefault(classInfo.ClassCleanupMethod, inherit: true)?.CleanupBehavior, - }; - - return cleanupBehaviors.Contains(ClassCleanupBehavior.EndOfClass) - ? ClassCleanupBehavior.EndOfClass - : cleanupBehaviors.Contains(ClassCleanupBehavior.EndOfAssembly) ? ClassCleanupBehavior.EndOfAssembly : null; - } + GetFirstAttributeOrDefault(priorityAttributeProvider, inherit: true)?.Priority; /// /// KeyValue pairs that are provided by TestPropertyAttributes of the given test method. @@ -323,11 +220,11 @@ internal static bool IsDoNotParallelizeSet(Assembly assembly) /// List of traits. internal virtual IEnumerable GetTestPropertiesAsTraits(MemberInfo testPropertyProvider) { - IEnumerable testPropertyAttributes = GetDerivedAttributes(testPropertyProvider, inherit: true); + IEnumerable testPropertyAttributes = GetAttributes(testPropertyProvider, inherit: true); if (testPropertyProvider.DeclaringType is { } testClass) { - testPropertyAttributes = testPropertyAttributes.Concat(GetDerivedAttributes(testClass, inherit: true)); + testPropertyAttributes = testPropertyAttributes.Concat(GetAttributes(testClass, inherit: true)); } foreach (TestPropertyAttribute testProperty in testPropertyAttributes) @@ -344,7 +241,7 @@ internal virtual IEnumerable GetTestPropertiesAsTraits(MemberInfo testPro /// The member to inspect. /// Look at inheritance chain. /// An instance of the attribute. - internal virtual /* for tests, for moq */ IEnumerable GetDerivedAttributes(ICustomAttributeProvider attributeProvider, bool inherit) + internal virtual /* for tests, for moq */ IEnumerable GetAttributes(ICustomAttributeProvider attributeProvider, bool inherit) where TAttributeType : Attribute { Attribute[] attributes = GetCustomAttributesCached(attributeProvider, inherit); @@ -354,25 +251,13 @@ internal virtual IEnumerable GetTestPropertiesAsTraits(MemberInfo testPro { DebugEx.Assert(attribute != null, "ReflectHelper.DefinesAttributeDerivedFrom: internal error: wrong value in the attributes dictionary."); - if (AttributeComparer.IsDerived(attribute)) + if (attribute is TAttributeType attributeAsAttributeType) { - yield return (TAttributeType)attribute; + yield return attributeAsAttributeType; } } } - /// - /// Returns owner if attribute is applied to TestMethod, else null. - /// - /// The member to inspect. - /// owner if attribute is applied to TestMethod, else null. - private string? GetOwner(MemberInfo ownerAttributeProvider) - { - OwnerAttribute? ownerAttribute = GetFirstDerivedAttributeOrDefault(ownerAttributeProvider, inherit: true); - - return ownerAttribute?.Owner; - } - /// /// Gets and caches the attributes for the given type, or method. /// @@ -400,7 +285,7 @@ static Attribute[] GetAttributes(ICustomAttributeProvider attributeProvider, boo try { object[]? attributes = NotCachedReflectionAccessor.GetCustomAttributesNotCached(attributeProvider, inherit); - return attributes is null ? [] : attributes as Attribute[] ?? attributes.Cast().ToArray(); + return attributes is null ? [] : attributes as Attribute[] ?? [.. attributes.Cast()]; } catch (Exception ex) { diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/RunSettingsUtilities.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/RunSettingsUtilities.cs similarity index 97% rename from src/Adapter/MSTest.TestAdapter/Helpers/RunSettingsUtilities.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/RunSettingsUtilities.cs index e4a457b0cc..fa73447efd 100644 --- a/src/Adapter/MSTest.TestAdapter/Helpers/RunSettingsUtilities.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/RunSettingsUtilities.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/RuntimeContext.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/RuntimeContext.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Helpers/RuntimeContext.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/RuntimeContext.cs diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/TestDataSourceHelpers.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestDataSourceHelpers.cs similarity index 91% rename from src/Adapter/MSTest.TestAdapter/Helpers/TestDataSourceHelpers.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestDataSourceHelpers.cs index ddac9f6ded..4f3e0b614a 100644 --- a/src/Adapter/MSTest.TestAdapter/Helpers/TestDataSourceHelpers.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestDataSourceHelpers.cs @@ -19,12 +19,22 @@ public static bool TryHandleITestDataRow( out object?[] data, out string? ignoreMessageFromTestDataRow, out string? displayNameFromTestDataRow) + => TryHandleITestDataRow(d, testMethodParameters, out data, out ignoreMessageFromTestDataRow, out displayNameFromTestDataRow, out _); + + public static bool TryHandleITestDataRow( + object?[] d, + ParameterInfo[] testMethodParameters, + out object?[] data, + out string? ignoreMessageFromTestDataRow, + out string? displayNameFromTestDataRow, + out IList? testCategoriesFromTestDataRow) { if (d.Length == 1 && d[0] is ITestDataRow testDataRow) { object? dataFromTestDataRow = testDataRow.Value; ignoreMessageFromTestDataRow = testDataRow.IgnoreMessage; displayNameFromTestDataRow = testDataRow.DisplayName; + testCategoriesFromTestDataRow = testDataRow.TestCategories; data = TryHandleTupleDataSource(dataFromTestDataRow, testMethodParameters, out object?[] tupleExpandedToArray) ? tupleExpandedToArray @@ -36,6 +46,7 @@ public static bool TryHandleITestDataRow( data = d; ignoreMessageFromTestDataRow = null; displayNameFromTestDataRow = null; + testCategoriesFromTestDataRow = null; return false; } @@ -44,7 +55,7 @@ public static bool TryHandleTupleDataSource(object? data, ParameterInfo[] testMe if (testMethodParameters.Length == 1 && data?.GetType().IsAssignableTo(testMethodParameters[0].ParameterType) == true) { - array = Array.Empty(); + array = []; return false; } @@ -103,7 +114,7 @@ static void ProcessTuple(object data, object?[] array, int startingIndex) } #endif - array = Array.Empty(); + array = []; return false; } diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/TestRunParameters.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestRunParameters.cs similarity index 96% rename from src/Adapter/MSTest.TestAdapter/Helpers/TestRunParameters.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestRunParameters.cs index 9a324be172..8cd4b81655 100644 --- a/src/Adapter/MSTest.TestAdapter/Helpers/TestRunParameters.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestRunParameters.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/UnitTestOutcomeHelper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/UnitTestOutcomeHelper.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/Helpers/UnitTestOutcomeHelper.cs rename to src/Adapter/MSTestAdapter.PlatformServices/Helpers/UnitTestOutcomeHelper.cs diff --git a/src/Adapter/MSTest.TestAdapter/IPlatformServiceProvider.cs b/src/Adapter/MSTestAdapter.PlatformServices/IPlatformServiceProvider.cs similarity index 94% rename from src/Adapter/MSTest.TestAdapter/IPlatformServiceProvider.cs rename to src/Adapter/MSTestAdapter.PlatformServices/IPlatformServiceProvider.cs index 9df85c3521..b1857bf2ef 100644 --- a/src/Adapter/MSTest.TestAdapter/IPlatformServiceProvider.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/IPlatformServiceProvider.cs @@ -117,9 +117,6 @@ ITestSourceHost CreateTestSourceHost( /// /// The test method. /// - /// - /// The writer instance for logging. - /// /// /// The default set of properties the test context needs to be filled with. /// @@ -131,5 +128,5 @@ ITestSourceHost CreateTestSourceHost( /// /// This was required for compatibility reasons since the TestContext object that the V1 adapter had for desktop is not .Net Core compliant. /// - ITestContext GetTestContext(ITestMethod testMethod, StringWriter writer, IDictionary properties, IMessageLogger messageLogger, UTF.UnitTestOutcome outcome); + ITestContext GetTestContext(ITestMethod testMethod, IDictionary properties, IMessageLogger messageLogger, UTF.UnitTestOutcome outcome); } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IAdapterTraceLogger.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IAdapterTraceLogger.cs index 14d14d6337..b751ea57bd 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IAdapterTraceLogger.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IAdapterTraceLogger.cs @@ -9,9 +9,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// A service to log any trace messages from the adapter that would be shown in *.TpTrace files. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface IAdapterTraceLogger { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IFileOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IFileOperations.cs index b4b2c6b52d..ba498a72ba 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IFileOperations.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IFileOperations.cs @@ -7,9 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// This service is responsible for any file based operations. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface IFileOperations { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IReflectionOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IReflectionOperations.cs index 7a0c28d00e..e228b5ffae 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IReflectionOperations.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IReflectionOperations.cs @@ -7,9 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// This service is responsible for platform specific reflection operations. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface IReflectionOperations { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ISettingsProvider.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ISettingsProvider.cs index eee9c84973..10a6767f95 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ISettingsProvider.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ISettingsProvider.cs @@ -7,9 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// To read settings from the runsettings xml for the corresponding platform service. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface ISettingsProvider { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestDeployment.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestDeployment.cs index d7c914e5dd..4af0d5407f 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestDeployment.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestDeployment.cs @@ -3,6 +3,7 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; @@ -10,9 +11,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// The TestDeployment interface. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface ITestDeployment { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestSource.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestSource.cs index 04d3f8a063..98d497656c 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestSource.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestSource.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Microsoft.VisualStudio.TestTools.UnitTesting; + namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; /// @@ -8,9 +10,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// the test sources provided to the adapter. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface ITestSource { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestSourceHost.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestSourceHost.cs index 403e6c2d2e..b82ce61587 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestSourceHost.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestSourceHost.cs @@ -7,9 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// A host that loads the test source.This can be in isolation for desktop using an AppDomain or just loading the source in the current context. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface ITestSourceHost : IDisposable { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IThreadOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IThreadOperations.cs index f03762ff1d..44856437e2 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IThreadOperations.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IThreadOperations.cs @@ -7,9 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// This service is responsible for any thread operations specific to a platform. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface IThreadOperations { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITraceListener.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITraceListener.cs index 6bc98aaec5..d5cf7dea56 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITraceListener.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITraceListener.cs @@ -7,9 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// Operations on the TraceListener object that is implemented differently for each platform. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(Microsoft.VisualStudio.TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(Microsoft.VisualStudio.TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface ITraceListener { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITraceListenerManager.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITraceListenerManager.cs index 9dbe78d52e..22a133d415 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITraceListenerManager.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITraceListenerManager.cs @@ -8,9 +8,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int /// These operations are implemented differently for each platform service. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public interface ITraceListenerManager { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj b/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj index 15b5a1ee54..e3a37a6b2d 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj +++ b/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj @@ -13,7 +13,7 @@ Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices - TRACE + $(DefineConstants);TRACE @@ -40,15 +40,16 @@ + - - - true - - + + + + + diff --git a/src/Adapter/MSTest.TestAdapter/MSTestSettings.cs b/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs similarity index 97% rename from src/Adapter/MSTest.TestAdapter/MSTestSettings.cs rename to src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs index 65381bcc72..54f8c20c6e 100644 --- a/src/Adapter/MSTest.TestAdapter/MSTestSettings.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs @@ -2,15 +2,15 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; -using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; -#if !WINDOWS_UWP using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; -#endif +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using Microsoft.VisualStudio.TestTools.UnitTesting; +using ExecutionScope = Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope; + namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; /// @@ -18,9 +18,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; /// [Serializable] #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class MSTestSettings { @@ -260,9 +260,6 @@ public static void PopulateSettings(MSTestSettings settings) #if !WINDOWS_UWP private static bool IsRunSettingsFileHasMSTestSettings(string? runSettingsXml) - => IsRunSettingsFileHasSettingName(runSettingsXml, SettingsName) || IsRunSettingsFileHasSettingName(runSettingsXml, SettingsNameAlias); - - private static bool IsRunSettingsFileHasSettingName(string? runSettingsXml, string SettingName) { if (StringEx.IsNullOrWhiteSpace(runSettingsXml)) { @@ -277,7 +274,8 @@ private static bool IsRunSettingsFileHasSettingName(string? runSettingsXml, stri reader.ReadToNextElement(); // Read till we reach nodeName element or reach EOF - while (!string.Equals(reader.Name, SettingName, StringComparison.OrdinalIgnoreCase) + while (!string.Equals(reader.Name, SettingsName, StringComparison.OrdinalIgnoreCase) + && !string.Equals(reader.Name, SettingsNameAlias, StringComparison.OrdinalIgnoreCase) && !reader.EOF) { reader.SkipToNextElement(); @@ -308,6 +306,8 @@ internal static void PopulateSettings(IDiscoveryContext? context, IMessageLogger var settings = new MSTestSettings(); var runConfigurationSettings = RunConfigurationSettings.PopulateSettings(context); + // We have runsettings, but we don't have testconfig. + // Just use runsettings. #if !WINDOWS_UWP if (!StringEx.IsNullOrEmpty(context?.RunSettings?.SettingsXml) && configuration?["mstest"] is null) @@ -495,7 +495,7 @@ private static MSTestSettings ToSettings(XmlReader reader, IMessageLogger? logge CultureInfo.CurrentCulture, Resource.InvalidClassCleanupLifecycleValue, value, - string.Join(", ", EnumPolyfill.GetNames()))); + string.Join(", ", Enum.GetNames()))); break; } @@ -822,7 +822,7 @@ private static void SetParallelSettings(XmlReader reader, MSTestSettings setting CultureInfo.CurrentCulture, Resource.InvalidParallelScopeValue, value, - string.Join(", ", EnumPolyfill.GetNames()))); + string.Join(", ", Enum.GetNames()))); break; } @@ -833,8 +833,8 @@ private static void SetParallelSettings(XmlReader reader, MSTestSettings setting string.Format( CultureInfo.CurrentCulture, Resource.InvalidSettingsXmlElement, - ParallelizeSettingsName, - reader.Name)); + reader.Name, + ParallelizeSettingsName)); } } } @@ -849,7 +849,7 @@ private static void SetParallelSettings(XmlReader reader, MSTestSettings setting private static bool TryParseEnum(string value, out T result) where T : struct, Enum => Enum.TryParse(value, true, out result) - && EnumPolyfill.IsDefined(result); + && Enum.IsDefined(result); private static void SetGlobalSettings( [StringSyntax(StringSyntaxAttribute.Xml, nameof(runsettingsXml))] string runsettingsXml, @@ -978,7 +978,7 @@ internal static void SetSettingsFromConfig(IConfiguration configuration, IMessag CultureInfo.CurrentCulture, Resource.InvalidClassCleanupLifecycleValue, classCleanupLifecycle, - string.Join(", ", EnumPolyfill.GetNames()))); + string.Join(", ", Enum.GetNames()))); } settings.ClassCleanupLifecycle = lifecycle; @@ -992,9 +992,9 @@ internal static void SetSettingsFromConfig(IConfiguration configuration, IMessag : parallelWorkers > 0 ? parallelWorkers : throw new AdapterSettingsException(string.Format( - CultureInfo.CurrentCulture, - Resource.InvalidParallelWorkersValue, - workers)) + CultureInfo.CurrentCulture, + Resource.InvalidParallelWorkersValue, + workers)) : throw new AdapterSettingsException(string.Format( CultureInfo.CurrentCulture, Resource.InvalidParallelWorkersValue, @@ -1011,7 +1011,7 @@ internal static void SetSettingsFromConfig(IConfiguration configuration, IMessag CultureInfo.CurrentCulture, Resource.InvalidParallelScopeValue, value, - string.Join(", ", EnumPolyfill.GetNames()))); + string.Join(", ", Enum.GetNames()))); } settings.ParallelizationScope = scope; diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/AdapterSettingsException.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/AdapterSettingsException.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/AdapterSettingsException.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/AdapterSettingsException.cs diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/DynamicDataType.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/DynamicDataType.cs similarity index 75% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/DynamicDataType.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/DynamicDataType.cs index 572a628955..6046f3dfd8 100644 --- a/src/Adapter/MSTest.TestAdapter/ObjectModel/DynamicDataType.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/DynamicDataType.cs @@ -13,13 +13,8 @@ internal enum DynamicDataType : int /// None = 0, - /// - /// Dynamic data from . - /// - DataSourceAttribute = 1, - /// /// Dynamic data from . /// - ITestDataSource = 2, + ITestDataSource = 1, } diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/FixtureTestResult.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/FixtureTestResult.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/FixtureTestResult.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/FixtureTestResult.cs diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/StackTraceInformation.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/StackTraceInformation.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/StackTraceInformation.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/StackTraceInformation.cs diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/TestAssemblySettings.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestAssemblySettings.cs similarity index 92% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/TestAssemblySettings.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestAssemblySettings.cs index 5e9a68270d..8854d53de3 100644 --- a/src/Adapter/MSTest.TestAdapter/ObjectModel/TestAssemblySettings.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestAssemblySettings.cs @@ -3,6 +3,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using ExecutionScope = Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope; + namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; [Serializable] diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/TestFailedException.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestFailedException.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/TestFailedException.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestFailedException.cs diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/TestMethod.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestMethod.cs similarity index 93% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/TestMethod.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestMethod.cs index 2bb1e1a1b6..92eaf123e3 100644 --- a/src/Adapter/MSTest.TestAdapter/ObjectModel/TestMethod.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestMethod.cs @@ -16,9 +16,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; /// TestMethod contains information about a unit test method that needs to be executed. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif [Serializable] public sealed class TestMethod : ITestMethod @@ -147,6 +147,12 @@ public string? DeclaringClassFullName /// internal string?[]? SerializedData { get; set; } + // This holds user types that may not be serializable. + // If app domains are enabled, we have no choice other than losing the original data. + // In that case, we fallback to deserializing the SerializedData. + [field: NonSerialized] + internal object?[]? ActualData { get; set; } + /// /// Gets or sets the test data source ignore message. /// @@ -165,10 +171,5 @@ public string? DeclaringClassFullName /// internal string DisplayName { get; } - internal string UniqueName - => HasManagedMethodAndTypeProperties - ? $"{ManagedTypeName}.{ManagedMethodName}->{string.Join(", ", SerializedData ?? [])}" - : $"{FullClassName}.{Name}->{string.Join(", ", SerializedData ?? [])}"; - internal TestMethod Clone() => (TestMethod)MemberwiseClone(); } diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/TypeInspectionException.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TypeInspectionException.cs similarity index 100% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/TypeInspectionException.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TypeInspectionException.cs diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/UnitTestElement.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs similarity index 85% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/UnitTestElement.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs index 54bcc8fb98..aa7fd4ec74 100644 --- a/src/Adapter/MSTest.TestAdapter/ObjectModel/UnitTestElement.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs @@ -3,6 +3,7 @@ using Microsoft.TestPlatform.AdapterUtilities; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -107,7 +108,7 @@ internal TestCase ToTestCase() // : string.Format(CultureInfo.InvariantCulture, "{0}.{1}", this.TestMethod.FullClassName, this.TestMethod.Name); string testFullName = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", TestMethod.FullClassName, TestMethod.Name); - TestCase testCase = new(testFullName, Constants.ExecutorUri, TestMethod.AssemblyName) + TestCase testCase = new(testFullName, EngineConstants.ExecutorUri, TestMethod.AssemblyName) { DisplayName = GetDisplayName(), }; @@ -116,35 +117,35 @@ internal TestCase ToTestCase() { testCase.SetPropertyValue(TestCaseExtensions.ManagedTypeProperty, TestMethod.ManagedTypeName); testCase.SetPropertyValue(TestCaseExtensions.ManagedMethodProperty, TestMethod.ManagedMethodName); - testCase.SetPropertyValue(Constants.TestClassNameProperty, TestMethod.ManagedTypeName); + testCase.SetPropertyValue(EngineConstants.TestClassNameProperty, TestMethod.ManagedTypeName); } else { - testCase.SetPropertyValue(Constants.TestClassNameProperty, TestMethod.FullClassName); + testCase.SetPropertyValue(EngineConstants.TestClassNameProperty, TestMethod.FullClassName); } IReadOnlyCollection hierarchy = TestMethod.Hierarchy; if (hierarchy is { Count: > 0 }) { - testCase.SetHierarchy(hierarchy.ToArray()); + testCase.SetHierarchy([.. hierarchy]); } // Set declaring type if present so the correct method info can be retrieved if (TestMethod.DeclaringClassFullName != null) { - testCase.SetPropertyValue(Constants.DeclaringClassNameProperty, TestMethod.DeclaringClassFullName); + testCase.SetPropertyValue(EngineConstants.DeclaringClassNameProperty, TestMethod.DeclaringClassFullName); } // Set only if some test category is present if (TestCategory is { Length: > 0 }) { - testCase.SetPropertyValue(Constants.TestCategoryProperty, TestCategory); + testCase.SetPropertyValue(EngineConstants.TestCategoryProperty, TestCategory); } // Set priority if present if (Priority != null) { - testCase.SetPropertyValue(Constants.PriorityProperty, Priority.Value); + testCase.SetPropertyValue(EngineConstants.PriorityProperty, Priority.Value); } if (Traits is { Length: > 0 }) @@ -154,34 +155,29 @@ internal TestCase ToTestCase() if (!StringEx.IsNullOrEmpty(CssIteration)) { - testCase.SetPropertyValue(Constants.CssIterationProperty, CssIteration); + testCase.SetPropertyValue(EngineConstants.CssIterationProperty, CssIteration); } if (!StringEx.IsNullOrEmpty(CssProjectStructure)) { - testCase.SetPropertyValue(Constants.CssProjectStructureProperty, CssProjectStructure); - } - - if (!StringEx.IsNullOrEmpty(Description)) - { - testCase.SetPropertyValue(Constants.DescriptionProperty, Description); + testCase.SetPropertyValue(EngineConstants.CssProjectStructureProperty, CssProjectStructure); } if (WorkItemIds != null) { - testCase.SetPropertyValue(Constants.WorkItemIdsProperty, WorkItemIds); + testCase.SetPropertyValue(EngineConstants.WorkItemIdsProperty, WorkItemIds); } // The list of items to deploy before running this test. if (DeploymentItems is { Length: > 0 }) { - testCase.SetPropertyValue(Constants.DeploymentItemsProperty, DeploymentItems); + testCase.SetPropertyValue(EngineConstants.DeploymentItemsProperty, DeploymentItems); } // Set the Do not parallelize state if present if (DoNotParallelize) { - testCase.SetPropertyValue(Constants.DoNotParallelizeProperty, DoNotParallelize); + testCase.SetPropertyValue(EngineConstants.DoNotParallelizeProperty, DoNotParallelize); } // Store resolved data if any @@ -189,12 +185,12 @@ internal TestCase ToTestCase() { string?[]? data = TestMethod.SerializedData; - testCase.SetPropertyValue(Constants.TestDynamicDataTypeProperty, (int)TestMethod.DataType); - testCase.SetPropertyValue(Constants.TestDynamicDataProperty, data); + testCase.SetPropertyValue(EngineConstants.TestDynamicDataTypeProperty, (int)TestMethod.DataType); + testCase.SetPropertyValue(EngineConstants.TestDynamicDataProperty, data); // VSTest serialization doesn't handle null so instead don't set the property so that it's deserialized as null if (TestMethod.TestDataSourceIgnoreMessage is not null) { - testCase.SetPropertyValue(Constants.TestDataSourceIgnoreMessageProperty, TestMethod.TestDataSourceIgnoreMessage); + testCase.SetPropertyValue(EngineConstants.TestDataSourceIgnoreMessageProperty, TestMethod.TestDataSourceIgnoreMessage); } } @@ -205,7 +201,7 @@ internal TestCase ToTestCase() private void SetTestCaseId(TestCase testCase, string testFullName) { - testCase.SetPropertyValue(Constants.TestIdGenerationStrategyProperty, (int)TestMethod.TestIdGenerationStrategy); + testCase.SetPropertyValue(EngineConstants.TestIdGenerationStrategyProperty, (int)TestMethod.TestIdGenerationStrategy); switch (TestMethod.TestIdGenerationStrategy) { @@ -277,7 +273,7 @@ private Guid GenerateSerializedDataStrategyTestId(string testFullName) { var idProvider = new TestIdProvider(); - idProvider.AppendString(Constants.ExecutorUriString); + idProvider.AppendString(EngineConstants.ExecutorUriString); // Below comment is copied over from Test Platform. // If source is a file name then just use the filename for the identifier since the file might have moved between diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/UnitTestOutcome.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestOutcome.cs similarity index 89% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/UnitTestOutcome.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestOutcome.cs index a519c454eb..4b8eaddc68 100644 --- a/src/Adapter/MSTest.TestAdapter/ObjectModel/UnitTestOutcome.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestOutcome.cs @@ -7,9 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; /// Outcome of a test. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public enum UnitTestOutcome : int { diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/UnitTestResult.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestResult.cs similarity index 96% rename from src/Adapter/MSTest.TestAdapter/ObjectModel/UnitTestResult.cs rename to src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestResult.cs index c317fa9dde..251e6df0e9 100644 --- a/src/Adapter/MSTest.TestAdapter/ObjectModel/UnitTestResult.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestResult.cs @@ -11,9 +11,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; [Serializable] [DebuggerDisplay("{DisplayName} ({Outcome})")] #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class UnitTestResult { diff --git a/src/Adapter/MSTest.TestAdapter/PlatformServiceProvider.cs b/src/Adapter/MSTestAdapter.PlatformServices/PlatformServiceProvider.cs similarity index 92% rename from src/Adapter/MSTest.TestAdapter/PlatformServiceProvider.cs rename to src/Adapter/MSTestAdapter.PlatformServices/PlatformServiceProvider.cs index 21b7acea5b..755127a1eb 100644 --- a/src/Adapter/MSTest.TestAdapter/PlatformServiceProvider.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/PlatformServiceProvider.cs @@ -15,8 +15,6 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; /// internal sealed class PlatformServiceProvider : IPlatformServiceProvider { - private static readonly Action CancelDelegate = static state => ((TestContextImplementation)state!).Context.CancellationTokenSource.Cancel(); - /// /// Initializes a new instance of the class - a singleton. /// @@ -194,9 +192,6 @@ public ITestSourceHost CreateTestSourceHost( /// /// The test method. /// - /// - /// The writer instance for logging. - /// /// /// The default set of properties the test context needs to be filled with. /// @@ -208,10 +203,9 @@ public ITestSourceHost CreateTestSourceHost( /// /// This was required for compatibility reasons since the TestContext object that the V1 adapter had for desktop is not .Net Core compliant. /// - public ITestContext GetTestContext(ITestMethod testMethod, StringWriter writer, IDictionary properties, IMessageLogger messageLogger, UTF.UnitTestOutcome outcome) + public ITestContext GetTestContext(ITestMethod testMethod, IDictionary properties, IMessageLogger messageLogger, UTF.UnitTestOutcome outcome) { - var testContextImplementation = new TestContextImplementation(testMethod, writer, properties, messageLogger); - TestRunCancellationToken?.Register(CancelDelegate, testContextImplementation); + var testContextImplementation = new TestContextImplementation(testMethod, properties, messageLogger, TestRunCancellationToken); testContextImplementation.SetOutcome(outcome); return testContextImplementation; } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Shipped.txt index 6a36504523..feb5effa2e 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Shipped.txt +++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Shipped.txt @@ -1,4 +1,132 @@ #nullable enable +const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.TimeoutWhenNotSet = 0 -> int +const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.SettingsName = "MSTest" -> string! +const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.SettingsNameAlias = "MSTestV2" -> string! +const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.TotalHierarchyLevels = 4 -> int +const Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.SettingsName = "RunConfiguration" -> string! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.DebugTrace.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.Dispose() -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.GetAndClearDebugTrace() -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.GetAndClearStandardError() -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.GetAndClearStandardOutput() -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.LogMessageListener(bool captureDebugTraces) -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.StandardError.get -> string! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.LogMessageListener.StandardOutput.get -> string! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.AssemblyCleanupMethod.get -> System.Reflection.MethodInfo? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.AssemblyInitializationException.get -> System.Exception? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.AssemblyInitializeMethod.get -> System.Reflection.MethodInfo? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.HasExecutableCleanupMethod.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.IsAssemblyInitializeExecuted.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.RunAssemblyCleanup() -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo.RunAssemblyInitialize(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext! testContext) -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseClassCleanupMethodsStack.get -> System.Collections.Generic.Stack! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseClassInitAndCleanupMethods.get -> System.Collections.Generic.Queue!>! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseTestCleanupMethodsQueue.get -> System.Collections.Generic.Queue! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.BaseTestInitializeMethodsQueue.get -> System.Collections.Generic.Queue! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassAttribute.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassCleanupException.get -> System.Exception? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassCleanupMethod.get -> System.Reflection.MethodInfo? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassInitializationException.get -> System.Exception? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassInitializeMethod.get -> System.Reflection.MethodInfo? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.ClassType.get -> System.Type! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.Constructor.get -> System.Reflection.ConstructorInfo! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.HasExecutableCleanupMethod.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.IsClassCleanupExecuted.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.IsClassInitializeExecuted.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.Parent.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.RunClassCleanup(Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior classCleanupLifecycle = Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior.EndOfAssembly) -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.RunClassInitialize(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext! testContext) -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.TestCleanupMethod.get -> System.Reflection.MethodInfo? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.TestContextProperty.get -> System.Reflection.PropertyInfo? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo.TestInitializeMethod.get -> System.Reflection.MethodInfo? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager.RunTests(System.Collections.Generic.IEnumerable! tests, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext? runContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle! frameworkHandle, Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken! runCancellationToken) -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager.RunTests(System.Collections.Generic.IEnumerable! sources, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext? runContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle! frameworkHandle, Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken! cancellationToken) -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestExecutionManager.TestExecutionManager() -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.Arguments.get -> object?[]? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.GetAllAttributes(bool inherit) -> System.Attribute![]? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.GetAttributes(bool inherit) -> TAttributeType![]! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.IsRunnable.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.IsTimeoutSet.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.MethodInfo.get -> System.Reflection.MethodInfo! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.NotRunnableReason.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.ParameterTypes.get -> System.Reflection.ParameterInfo![]! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.ReturnType.get -> System.Type! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.TestClassName.get -> string! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.TestMethodName.get -> string! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.TestResultExtensions +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.UnitTestOutcomeExtensions +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.CaptureDebugTraces.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ClassCleanupLifecycle.get -> Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.DisableParallelization.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.EnableBaseClassTestMethodsFromOtherAssemblies.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ForcedLegacyMode.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.MapInconclusiveToFailed.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.MapNotRunnableToFailed.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.MSTestSettings() -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ParallelizationScope.get -> Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.ParallelizationWorkers.get -> int? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TestSettingsFile.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TestTimeout.get -> int +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TreatClassAndAssemblyCleanupWarningsAsErrors.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.TreatDiscoveryWarningsAsErrors.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.AssemblyName.get -> string! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringAssemblyName.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringAssemblyName.set -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringClassFullName.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.DeclaringClassFullName.set -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.FullClassName.get -> string! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.HasManagedMethodAndTypeProperties.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.Hierarchy.get -> System.Collections.Generic.IReadOnlyCollection! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.IsAsync.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.ManagedMethodName.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.ManagedTypeName.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.Name.get -> string! +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.TestIdGenerationStrategy.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestIdGenerationStrategy +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod.TestMethod(string! name, string! fullClassName, string! assemblyName, bool isAsync) -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Error = 0 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Failed = 1 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Ignored = 4 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Inconclusive = 3 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.InProgress = 8 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.NotFound = 7 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.NotRunnable = 5 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Passed = 6 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome.Timeout = 2 -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.DatarowIndex.get -> int +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.DebugTrace.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.DisplayName.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.Duration.get -> System.TimeSpan +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorColumnNumber.get -> int +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorFilePath.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorLineNumber.get -> int +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorMessage.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ErrorStackTrace.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ExecutionId.get -> System.Guid +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.InnerResultsCount.get -> int +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.Outcome.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ParentExecId.get -> System.Guid +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.ResultFiles.get -> System.Collections.Generic.IList? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.StandardError.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.StandardOut.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult.TestContextMessages.get -> string? +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.CollectSourceInformation.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.RunConfigurationSettings() -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Cancel() -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Canceled.get -> bool +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Register(System.Action! callback) -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.TestRunCancellationToken() -> void +Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestRunCancellationToken.Unregister() -> void Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AdapterTraceLogger Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AdapterTraceLogger.AdapterTraceLogger() -> void Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AdapterTraceLogger.LogError(string! format, params object?[]! args) -> void @@ -11,7 +139,7 @@ Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.FileOperation Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.FileOperations.FileOperations() -> void Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.FileOperations.GetAssemblyPath(System.Reflection.Assembly! assembly) -> string? Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.FileOperations.GetFullFilePath(string! assemblyFileName) -> string! -Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.FileOperations.GetNavigationData(object! navigationSession, string! className, string! methodName, out int minLineNumber, out string? fileName) -> void +Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.FileOperations.GetNavigationData(object? navigationSession, string! className, string! methodName, out int minLineNumber, out string? fileName) -> void Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.FileOperations.LoadAssembly(string! assemblyName, bool isReflectionOnly) -> System.Reflection.Assembly! Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.IAdapterTraceLogger Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.IAdapterTraceLogger.LogError(string! format, params object?[]! args) -> void @@ -81,7 +209,7 @@ Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.Obj Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel.ITestMethod.Name.get -> string! Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel.ITestMethod.TestIdGenerationStrategy.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestIdGenerationStrategy Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider -Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.GetProperties(string! source) -> System.Collections.Generic.IDictionary! +Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.GetProperties(string? source) -> System.Collections.Generic.IDictionary! Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Load(System.Xml.XmlReader! reader) -> void Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.MSTestSettingsProvider() -> void Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.ReflectionOperations @@ -150,3 +278,13 @@ override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Thre override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.ThreadSafeStringWriter.Write(char[]! buffer, int index, int count) -> void override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.ThreadSafeStringWriter.Write(string? value) -> void override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.ThreadSafeStringWriter.WriteLine(string? value) -> void +static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.TestResultExtensions.ToUnitTestResults(this Microsoft.VisualStudio.TestTools.UnitTesting.TestResult![]! testResults) -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestResult![]! +static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions.UnitTestOutcomeExtensions.ToUnitTestOutcome(this Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome frameworkTestOutcome) -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome +static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.CurrentSettings.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings! +static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.IsLegacyScenario(Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging.IMessageLogger! logger) -> bool +static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.PopulateSettings(Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings! settings) -> void +static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.PopulateSettings(Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IDiscoveryContext? context) -> void +static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings.RunConfigurationSettings.get -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings! +static Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings.PopulateSettings(Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IDiscoveryContext? context) -> Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.RunConfigurationSettings! +virtual Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.Invoke(object?[]? arguments) -> Microsoft.VisualStudio.TestTools.UnitTesting.TestResult! +virtual Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.InvokeAsync(object?[]? arguments) -> System.Threading.Tasks.Task! diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Unshipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Unshipped.txt index 6a828f7e91..043a57fc4f 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Unshipped.txt @@ -1,5 +1,3 @@ #nullable enable -*REMOVED*Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.FileOperations.GetNavigationData(object! navigationSession, string! className, string! methodName, out int minLineNumber, out string? fileName) -> void -Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.FileOperations.GetNavigationData(object? navigationSession, string! className, string! methodName, out int minLineNumber, out string? fileName) -> void -*REMOVED*Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.GetProperties(string! source) -> System.Collections.Generic.IDictionary! -Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.GetProperties(string? source) -> System.Collections.Generic.IDictionary! +Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.Dispose() -> void +virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.Dispose(bool disposing) -> void diff --git a/src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs b/src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs index c91bf7ed34..5593828ee9 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs @@ -20,9 +20,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// [Serializable] #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1603:DocumentationMustContainValidXml", Justification = "Reviewed. Suppression is ok here.")] public class RecursiveDirectoryPath : MarshalByRefObject diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/Resource.Designer.cs b/src/Adapter/MSTestAdapter.PlatformServices/Resources/Resource.Designer.cs index 33f4d030e6..b934d1b01d 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/Resource.Designer.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/Resource.Designer.cs @@ -61,6 +61,87 @@ internal Resource() { } } + /// + /// Looks up a localized string similar to Assembly cleanup method '{0}.{1}' timed out after {2}ms. + /// + internal static string AssemblyCleanupTimedOut { + get { + return ResourceManager.GetString("AssemblyCleanupTimedOut", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assembly cleanup method '{0}.{1}' was canceled. + /// + internal static string AssemblyCleanupWasCancelled { + get { + return ResourceManager.GetString("AssemblyCleanupWasCancelled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assembly initialize method '{0}.{1}' timed out after {2}ms. + /// + internal static string AssemblyInitializeTimedOut { + get { + return ResourceManager.GetString("AssemblyInitializeTimedOut", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assembly initialize method '{0}.{1}' was canceled. + /// + internal static string AssemblyInitializeWasCancelled { + get { + return ResourceManager.GetString("AssemblyInitializeWasCancelled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MSTestAdapterV2. + /// + internal static string AttachmentSetDisplayName { + get { + return ResourceManager.GetString("AttachmentSetDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2}. + /// + internal static string CannotEnumerateIDataSourceAttribute { + get { + return ResourceManager.GetString("CannotEnumerateIDataSourceAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}. + /// + internal static string CannotExpandIDataSourceAttribute { + get { + return ResourceManager.GetString("CannotExpandIDataSourceAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution".. + /// + internal static string CannotExpandIDataSourceAttribute_CannotSerialize { + get { + return ResourceManager.GetString("CannotExpandIDataSourceAttribute_CannotSerialize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique.. + /// + internal static string CannotExpandIDataSourceAttribute_DuplicateDisplayName { + get { + return ResourceManager.GetString("CannotExpandIDataSourceAttribute_DuplicateDisplayName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Could not find file '{0}'.. /// @@ -70,6 +151,62 @@ internal static string CannotFindFile { } } + /// + /// Looks up a localized string similar to Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. + ///Test expected {2} parameter(s), with types '{3}', + ///but received {4} argument(s), with types '{5}'.. + /// + internal static string CannotRunTestArgumentsMismatchError { + get { + return ResourceManager.GetString("CannotRunTestArgumentsMismatchError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data.. + /// + internal static string CannotRunTestMethodNoDataError { + get { + return ResourceManager.GetString("CannotRunTestMethodNoDataError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class cleanup method '{0}.{1}' timed out after {2}ms. + /// + internal static string ClassCleanupTimedOut { + get { + return ResourceManager.GetString("ClassCleanupTimedOut", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class cleanup method '{0}.{1}' was canceled. + /// + internal static string ClassCleanupWasCancelled { + get { + return ResourceManager.GetString("ClassCleanupWasCancelled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class initialize method '{0}.{1}' timed out after {2}ms. + /// + internal static string ClassInitializeTimedOut { + get { + return ResourceManager.GetString("ClassInitializeTimedOut", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class initialize method '{0}.{1}' was canceled. + /// + internal static string ClassInitializeWasCancelled { + get { + return ResourceManager.GetString("ClassInitializeWasCancelled", resourceCulture); + } + } + /// /// Looks up a localized string similar to The parameter should not be null or empty.. /// @@ -79,6 +216,33 @@ internal static string Common_CannotBeNullOrEmpty { } } + /// + /// Looks up a localized string similar to MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}.. + /// + internal static string CouldNotInspectTypeDuringDiscovery { + get { + return ResourceManager.GetString("CouldNotInspectTypeDuringDiscovery", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} (Data Row {1}). + /// + internal static string DataDrivenResultDisplayName { + get { + return ResourceManager.GetString("DataDrivenResultDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Debug Trace:. + /// + internal static string DebugTraceBanner { + get { + return ResourceManager.GetString("DebugTraceBanner", resourceCulture); + } + } + /// /// Looks up a localized string similar to Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed.. /// @@ -196,6 +360,141 @@ internal static string DeploymentItemWithOutputDirectory { } } + /// + /// Looks up a localized string similar to [MSTest][Discovery][{0}] {1}. + /// + internal static string DiscoveryWarning { + get { + return ResourceManager.GetString("DiscoveryWarning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files.. + /// + internal static string DuplicateConfigurationError { + get { + return ResourceManager.GetString("DuplicateConfigurationError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: {1}. + /// + internal static string EnumeratorLoadTypeErrorFormat { + get { + return ResourceManager.GetString("EnumeratorLoadTypeErrorFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to "{0}": (Failed to get exception description due to an exception of type "{1}".. + /// + internal static string ExceptionOccuredWhileGettingTheExceptionDescription { + get { + return ResourceManager.GetString("ExceptionOccuredWhileGettingTheExceptionDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exceptions thrown:. + /// + internal static string ExceptionsThrown { + get { + return ResourceManager.GetString("ExceptionsThrown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test '{0}' was canceled. + /// + internal static string Execution_Test_Cancelled { + get { + return ResourceManager.GetString("Execution_Test_Cancelled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test '{0}' timed out after {1}ms. + /// + internal static string Execution_Test_Timeout { + get { + return ResourceManager.GetString("Execution_Test_Timeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}. + /// + internal static string FailedToGetCustomAttribute { + get { + return ResourceManager.GetString("FailedToGetCustomAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type of the generic parameter '{0}' could not be inferred.. + /// + internal static string GenericParameterCantBeInferred { + get { + return ResourceManager.GetString("GenericParameterCantBeInferred", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.. + /// + internal static string GenericParameterCantBeInferredBecauseNoArguments { + get { + return ResourceManager.GetString("GenericParameterCantBeInferredBecauseNoArguments", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.. + /// + internal static string GenericParameterConflict { + get { + return ResourceManager.GetString("GenericParameterConflict", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.. + /// + internal static string InvalidClassCleanupLifecycleValue { + get { + return ResourceManager.GetString("InvalidClassCleanupLifecycleValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}.. + /// + internal static string InvalidParallelScopeValue { + get { + return ResourceManager.GetString("InvalidParallelScopeValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer.. + /// + internal static string InvalidParallelWorkersValue { + get { + return ResourceManager.GetString("InvalidParallelWorkersValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'.. + /// + internal static string InvalidSettingsXmlAttribute { + get { + return ResourceManager.GetString("InvalidSettingsXmlAttribute", resourceCulture); + } + } + /// /// Looks up a localized string similar to MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again.. /// @@ -205,6 +504,15 @@ internal static string InvalidSettingsXmlElement { } } + /// + /// Looks up a localized string similar to Invalid settings '{0}'. Unexpected XmlElement: '{1}'.. + /// + internal static string InvalidSettingsXmlElement1 { + get { + return ResourceManager.GetString("InvalidSettingsXmlElement1", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.. /// @@ -214,6 +522,24 @@ internal static string InvalidValue { } } + /// + /// Looks up a localized string similar to Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.. + /// + internal static string InvalidValue1 { + get { + return ResourceManager.GetString("InvalidValue1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter.. + /// + internal static string LegacyScenariosNotSupportedWarning { + get { + return ResourceManager.GetString("LegacyScenariosNotSupportedWarning", resourceCulture); + } + } + /// /// Looks up a localized string similar to Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1}. /// @@ -233,29 +559,537 @@ internal static string MissingDeploymentDependencyWithoutReason { } /// - /// Looks up a localized string similar to {0}_{1} {2}. + /// Looks up a localized string similar to An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file.. /// - internal static string TestRunName { + internal static string OlderTFMVersionFound { get { - return ResourceManager.GetString("TestRunName", resourceCulture); + return ResourceManager.GetString("OlderTFMVersionFound", resourceCulture); } } /// - /// Looks up a localized string similar to Data source '{0}' cannot be found in the test configuration settings. + /// Looks up a localized string similar to Running tests in any of the provided sources is not supported for the selected platform. /// - internal static string UTA_DataSourceConfigurationSectionMissing { + internal static string SourcesNotSupported { get { - return ResourceManager.GetString("UTA_DataSourceConfigurationSectionMissing", resourceCulture); + return ResourceManager.GetString("SourcesNotSupported", resourceCulture); } } /// - /// Looks up a localized string similar to The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0}. + /// Looks up a localized string similar to Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes.. /// - internal static string UTA_ErrorDataConnectionFailed { + internal static string STAIsOnlySupportedOnWindowsWarning { get { - return ResourceManager.GetString("UTA_ErrorDataConnectionFailed", resourceCulture); + return ResourceManager.GetString("STAIsOnlySupportedOnWindowsWarning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to discover tests from assembly {0}. Reason:{1}. + /// + internal static string TestAssembly_AssemblyDiscoveryFailure { + get { + return ResourceManager.GetString("TestAssembly_AssemblyDiscoveryFailure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File does not exist: {0}. + /// + internal static string TestAssembly_FileDoesNotExist { + get { + return ResourceManager.GetString("TestAssembly_FileDoesNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test cleanup method '{0}.{1}' timed out after {2}ms. + /// + internal static string TestCleanupTimedOut { + get { + return ResourceManager.GetString("TestCleanupTimedOut", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test cleanup method '{0}.{1}' was canceled. + /// + internal static string TestCleanupWasCancelled { + get { + return ResourceManager.GetString("TestCleanupWasCancelled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TestContext cannot be Null.. + /// + internal static string TestContextIsNull { + get { + return ResourceManager.GetString("TestContextIsNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TestContext Messages:. + /// + internal static string TestContextMessageBanner { + get { + return ResourceManager.GetString("TestContextMessageBanner", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test initialize method '{0}.{1}' timed out after {2}ms. + /// + internal static string TestInitializeTimedOut { + get { + return ResourceManager.GetString("TestInitializeTimedOut", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test initialize method '{0}.{1}' was canceled. + /// + internal static string TestInitializeWasCancelled { + get { + return ResourceManager.GetString("TestInitializeWasCancelled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test method {0} was not found.. + /// + internal static string TestNotFound { + get { + return ResourceManager.GetString("TestNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}). + /// + internal static string TestParallelizationBanner { + get { + return ResourceManager.GetString("TestParallelizationBanner", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}_{1} {2}. + /// + internal static string TestRunName { + get { + return ResourceManager.GetString("TestRunName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. + ///Error: {1}. + /// + internal static string TypeLoadFailed { + get { + return ResourceManager.GetString("TypeLoadFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3}. + /// + internal static string UTA_AssemblyCleanupMethodWasUnsuccesful { + get { + return ResourceManager.GetString("UTA_AssemblyCleanupMethodWasUnsuccesful", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution.. + /// + internal static string UTA_AssemblyInitMethodThrows { + get { + return ResourceManager.GetString("UTA_AssemblyInitMethodThrows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3}. + /// + internal static string UTA_ClassCleanupMethodWasUnsuccesful { + get { + return ResourceManager.GetString("UTA_ClassCleanupMethodWasUnsuccesful", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class Initialization method {0}.{1} threw exception. {2}: {3}.. + /// + internal static string UTA_ClassInitMethodThrows { + get { + return ResourceManager.GetString("UTA_ClassInitMethodThrows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'.. + /// + internal static string UTA_ClassOrAssemblyCleanupMethodHasWrongSignature { + get { + return ResourceManager.GetString("UTA_ClassOrAssemblyCleanupMethodHasWrongSignature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'.. + /// + internal static string UTA_ClassOrAssemblyInitializeMethodHasWrongSignature { + get { + return ResourceManager.GetString("UTA_ClassOrAssemblyInitializeMethodHasWrongSignature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TestCleanup method {0}.{1} threw exception. {2}.. + /// + internal static string UTA_CleanupMethodThrows { + get { + return ResourceManager.GetString("UTA_CleanupMethodThrows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error calling Test Cleanup method for test class {0}: {1}. + /// + internal static string UTA_CleanupMethodThrowsGeneralError { + get { + return ResourceManager.GetString("UTA_CleanupMethodThrowsGeneralError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TestCleanup Stack Trace. + /// + internal static string UTA_CleanupStackTrace { + get { + return ResourceManager.GetString("UTA_CleanupStackTrace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data source '{0}' cannot be found in the test configuration settings. + /// + internal static string UTA_DataSourceConfigurationSectionMissing { + get { + return ResourceManager.GetString("UTA_DataSourceConfigurationSectionMissing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to --- End of inner exception stack trace ---. + /// + internal static string UTA_EndOfInnerExceptionTrace { + get { + return ResourceManager.GetString("UTA_EndOfInnerExceptionTrace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0}. + /// + internal static string UTA_ErrorDataConnectionFailed { + get { + return ResourceManager.GetString("UTA_ErrorDataConnectionFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2(). + /// + internal static string UTA_ErrorIncorrectTestMethodSignature { + get { + return ResourceManager.GetString("UTA_ErrorIncorrectTestMethodSignature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext.. + /// + internal static string UTA_ErrorInValidTestContextSignature { + get { + return ResourceManager.GetString("UTA_ErrorInValidTestContextSignature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0.. + /// + internal static string UTA_ErrorInvalidTimeout { + get { + return ResourceManager.GetString("UTA_ErrorInvalidTimeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly.. + /// + internal static string UTA_ErrorMultiAssemblyClean { + get { + return ResourceManager.GetString("UTA_ErrorMultiAssemblyClean", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly.. + /// + internal static string UTA_ErrorMultiAssemblyInit { + get { + return ResourceManager.GetString("UTA_ErrorMultiAssemblyInit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class.. + /// + internal static string UTA_ErrorMultiClassClean { + get { + return ResourceManager.GetString("UTA_ErrorMultiClassClean", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class.. + /// + internal static string UTA_ErrorMultiClassInit { + get { + return ResourceManager.GetString("UTA_ErrorMultiClassInit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA024: {0}: Cannot define more than one method with the TestCleanup attribute.. + /// + internal static string UTA_ErrorMultiClean { + get { + return ResourceManager.GetString("UTA_ErrorMultiClean", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA018: {0}: Cannot define more than one method with the TestInitialize attribute.. + /// + internal static string UTA_ErrorMultiInit { + get { + return ResourceManager.GetString("UTA_ErrorMultiInit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA001: TestClass attribute defined on non-public class {0}. + /// + internal static string UTA_ErrorNonPublicTestClass { + get { + return ResourceManager.GetString("UTA_ErrorNonPublicTestClass", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA023: {0}: Cannot define predefined property {2} on method {1}.. + /// + internal static string UTA_ErrorPredefinedTestProperty { + get { + return ResourceManager.GetString("UTA_ErrorPredefinedTestProperty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TestClass attribute defined on generic non-abstract class {0}. + /// + internal static string UTA_ErrorTestClassIsGenericNonAbstract { + get { + return ResourceManager.GetString("UTA_ErrorTestClassIsGenericNonAbstract", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name.. + /// + internal static string UTA_ErrorTestPropertyNullOrEmpty { + get { + return ResourceManager.GetString("UTA_ErrorTestPropertyNullOrEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. + ///{1}. + /// + internal static string UTA_ExecuteThrewException { + get { + return ResourceManager.GetString("UTA_ExecuteThrewException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. + ///{2}. + /// + internal static string UTA_ExpectedExceptionAttributeConstructionException { + get { + return ResourceManager.GetString("UTA_ExpectedExceptionAttributeConstructionException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to obtain the exception thrown by test method {0}.{1}.. + /// + internal static string UTA_FailedToGetTestMethodException { + get { + return ResourceManager.GetString("UTA_FailedToGetTestMethodException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initialization method {0}.{1} threw exception. {2}.. + /// + internal static string UTA_InitMethodThrows { + get { + return ResourceManager.GetString("UTA_InitMethodThrows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to create instance of class {0}. Error: {1}.. + /// + internal static string UTA_InstanceCreationError { + get { + return ResourceManager.GetString("UTA_InstanceCreationError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method {0}.{1} does not exist.. + /// + internal static string UTA_MethodDoesNotExists { + get { + return ResourceManager.GetString("UTA_MethodDoesNotExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.. + /// + internal static string UTA_MultipleAttributesOnTestMethod { + get { + return ResourceManager.GetString("UTA_MultipleAttributesOnTestMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor.. + /// + internal static string UTA_NoTestResult { + get { + return ResourceManager.GetString("UTA_NoTestResult", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'.. + /// + internal static string UTA_NoValidConstructor { + get { + return ResourceManager.GetString("UTA_NoValidConstructor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to find property {0}.TestContext. Error:{1}.. + /// + internal static string UTA_TestContextLoadError { + get { + return ResourceManager.GetString("UTA_TestContextLoadError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to set TestContext property for the class {0}. Error: {1}.. + /// + internal static string UTA_TestContextSetError { + get { + return ResourceManager.GetString("UTA_TestContextSetError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The {0}.TestContext has incorrect type.. + /// + internal static string UTA_TestContextTypeMismatchLoadError { + get { + return ResourceManager.GetString("UTA_TestContextTypeMismatchLoadError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'.. + /// + internal static string UTA_TestInitializeAndCleanupMethodHasWrongSignature { + get { + return ResourceManager.GetString("UTA_TestInitializeAndCleanupMethodHasWrongSignature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test method {0}.{1} threw exception: + ///{2}. + /// + internal static string UTA_TestMethodThrows { + get { + return ResourceManager.GetString("UTA_TestMethodThrows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to get type {0}. Error: {1}.. + /// + internal static string UTA_TypeLoadError { + get { + return ResourceManager.GetString("UTA_TypeLoadError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The called code threw an exception that was caught, but the exception value was null. + /// + internal static string UTA_UserCodeThrewNullValueException { + get { + return ResourceManager.GetString("UTA_UserCodeThrewNullValueException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread.. + /// + internal static string UTA_WrongThread { + get { + return ResourceManager.GetString("UTA_WrongThread", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (Failed to get the message for an exception of type {0} due to an exception.). + /// + internal static string UTF_FailedToGetExceptionMessage { + get { + return ResourceManager.GetString("UTF_FailedToGetExceptionMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'.. + /// + internal static string VersionMismatchBetweenAdapterAndFramework { + get { + return ResourceManager.GetString("VersionMismatchBetweenAdapterAndFramework", resourceCulture); } } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/Resource.resx b/src/Adapter/MSTestAdapter.PlatformServices/Resources/Resource.resx index 414073c307..473060ad60 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/Resource.resx +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/Resource.resx @@ -186,4 +186,305 @@ Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + + + Assembly cleanup method '{0}.{1}' was canceled + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + + + Assembly initialize method '{0}.{1}' was canceled + + + MSTestAdapterV2 + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + + + Class cleanup method '{0}.{1}' timed out after {2}ms + + + Class cleanup method '{0}.{1}' was canceled + + + Class initialize method '{0}.{1}' timed out after {2}ms + + + Class initialize method '{0}.{1}' was canceled + + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + + + {0} (Data Row {1}) + + + Debug Trace: + + + [MSTest][Discovery][{0}] {1} + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + + + {0}: {1} + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + + + Test '{0}' timed out after {1}ms + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + + + Running tests in any of the provided sources is not supported for the selected platform + + + Failed to discover tests from assembly {0}. Reason:{1} + + + File does not exist: {0} + + + Test cleanup method '{0}.{1}' timed out after {2}ms + + + Test cleanup method '{0}.{1}' was canceled + + + TestContext cannot be Null. + + + TestContext Messages: + + + Test initialize method '{0}.{1}' timed out after {2}ms + + + Test initialize method '{0}.{1}' was canceled + + + Test method {0} was not found. + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + + + TestCleanup method {0}.{1} threw exception. {2}. + + + Error calling Test Cleanup method for test class {0}: {1} + + + TestCleanup Stack Trace + + + --- End of inner exception stack trace --- + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + + + UTA001: TestClass attribute defined on non-public class {0} + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + + + TestClass attribute defined on generic non-abstract class {0} + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + + + Failed to obtain the exception thrown by test method {0}.{1}. + + + Initialization method {0}.{1} threw exception. {2}. + + + Unable to create instance of class {0}. Error: {1}. + + + Method {0}.{1} does not exist. + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + + + Unable to find property {0}.TestContext. Error:{1}. + + + Unable to set TestContext property for the class {0}. Error: {1}. + + + The {0}.TestContext has incorrect type. + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + + + Test method {0}.{1} threw exception: +{2} + + + Unable to get type {0}. Error: {1}. + + + The called code threw an exception that was caught, but the exception value was null + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + + + (Failed to get the message for an exception of type {0} due to an exception.) + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + \ No newline at end of file diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.cs.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.cs.xlf index b82c787000..1efbb9e1cc 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.cs.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.cs.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + Po {2} ms vypršel časový limit metody čištění sestavení {0}.{1}. + + + + Assembly cleanup method '{0}.{1}' was canceled + Metoda čištění sestavení {0}.{1} byla zrušena. + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + Po {2} ms vypršel časový limit metody inicializace sestavení {0}.{1}. + + + + Assembly initialize method '{0}.{1}' was canceled + Metoda inicializace sestavení {0}.{1} byla zrušena. + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + Při vytváření výčtu atributu IDataSource došlo k výjimce. „{0}.{1}“: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + Došlo k výjimce při rozbalování řádků IDataSource z atributu na „{0}.{1}“: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + Data v {0} indexu pro „{1}“ nelze serializovat. Všechna data poskytnutá prostřednictvím „IDataSource“ by měla být serializovatelná. Pokud potřebujete testovat neserializovatelné zdroje dat, nezapomeňte do testovacího sestavení přidat atribut TestDataSourceDiscovery a nastavit možnost zjišťování na „DuringExecution“. + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + Zobrazovaný název „{2}“ u indexů {0} a {1} je duplicitní. Zobrazované názvy by měly být jedinečné. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. Soubor {0} se nenašel. + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + Testovací metodu {0}.{1} nejde spustit: Testovací data neodpovídají parametrům metody. Liší se počet nebo typy. +Pro test se očekával tento počet parametrů: {2} s typy {3}, +byl však přijat tento počet argumentů: {4} s typy {5}. + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + Nelze spustit testovací metodu {0}.{1}: Metoda má parametry, ale nedefinuje žádný zdroj testu. K poskytování testovacích dat použijte zdroj dat [DataRow] nebo [DynamicData], případně vlastní zdroj dat ITestDataSource. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + Po {2} ms vypršel časový limit metody čištění třídy {0}.{1}. + + + + Class cleanup method '{0}.{1}' was canceled + Metoda čištění třídy {0}.{1} byla zrušena. + + + + Class initialize method '{0}.{1}' timed out after {2}ms + Po {2} ms vypršel časový limit metody inicializace třídy {0}.{1}. + + + + Class initialize method '{0}.{1}' was canceled + Metoda inicializace třídy {0}.{1} byla zrušena. + + The parameter should not be null or empty. Parametr nemůže být null nebo prázdný. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + MSTestAdapter nezjistil v třídě {0} sestavení {1} žádný test, protože: {2}. + + + + {0} (Data Row {1}) + {0} (datový řádek {1}) + + + + Debug Trace: + Trasování ladění: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. Problém nasazení testovacího běhu: Chybná položka nasazení: {0}: výstupní adresář {1} určuje položku, která se má nasadit mimo kořenový adresář nasazení, což není povolené. @@ -77,16 +177,108 @@ položka nasazení {0} (adresář výstupu {1}) + + [MSTest][Discovery][{0}] {1} + [MSTest][Discovery][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + Byly zjištěny soubory .runsettings i .testconfig.json. Vyberte prosím jenom jeden z těchto souborů konfigurace testu. + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + „{0}“: (Nepodařilo se získat popis výjimky z důvodu výjimky typu „{1}“. + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + Vyvolané výjimky: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + Test {0} byl zrušen. + + + + Test '{0}' timed out after {1}ms + Časový limit testu {0} vypršel po {1} ms. + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + Získání vlastních atributů pro typ {0} vyvolalo výjimku (bude ignorovat a používat způsob reflexe): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + Typ obecného parametru {0} nelze odvodit. + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + Obecná testovací metoda {0}'nemá argumenty, takže nelze odvodit obecný parametr. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + Byly nalezeny dva konfliktní typy pro obecný parametr {0}. Konfliktní typy jsou {1} a {2}. + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + Pro classCleanupLifecycle byla zadána neplatná hodnota {0}. Podporované obory jsou {1}. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + Pro Obor je zadaná neplatná hodnota {0}. Podporované obory jsou {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + Pro Pracovní procesy je zadaná neplatná hodnota {0}. Hodnota by měla být nezáporné celé číslo. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + Neplatné nastavení {0}. Neočekávaný XmlAttribute: {1}. + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. Nástroj MSTestAdapter zjistil neočekávaný prvek {0} v nastavení {1}. Odeberte tento prvek a zkuste to znovu. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + Neplatné nastavení {0}. Neočekávaný XmlElement: {1}. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. Neplatná hodnota {0} pro položku runsettings {1}. Nastavení bude ignorováno. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + Neplatná hodnota {0} pro položku runsettings {1}. Nastavení bude ignorováno. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + Upozornění: Adaptér MSTest V2 nepodporuje soubor testsettings ani vsmdi. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} Problém nasazení testovacího běhu: Sestavení nebo modul {0} se nenašly. Důvod: {1} @@ -97,21 +289,309 @@ Problém nasazení testovacího běhu: Sestavení nebo modul {0} se nenašly. + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + V sestavení je načtena starší verze balíčku MSTestV2. Zjišťování testů může selhat při zjišťování všech testů dat, pokud jsou závislé na souboru .runsettings. + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + Položka runsettings <ExecutionApartmentState>STA</ExecutionApartmentState> se v operačních systémech jiných než Windows nepodporuje. + + + + Running tests in any of the provided sources is not supported for the selected platform + Spouštění testů v některém z uvedených zdrojů se pro vybranou platformu nepodporuje. + + + + Failed to discover tests from assembly {0}. Reason:{1} + Nepovedlo se zjistit testy ze sestavení {0}. Důvod:{1} + + + + File does not exist: {0} + Neexistující soubor: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + Po {2} ms vypršel časový limit metody čištění testu {0}.{1}. + + + + Test cleanup method '{0}.{1}' was canceled + Metoda čištění testu {0}.{1} byla zrušena. + + + + TestContext cannot be Null. + TestContext nemůže být Null. + + + + TestContext Messages: + Zprávy pro TestContext: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + Po {2} ms vypršel časový limit metody inicializace testu {0}.{1}. + + + + Test initialize method '{0}.{1}' was canceled + Metoda inicializace testu {0}.{1} byla zrušena. + + + + Test method {0} was not found. + Testovací metoda {0} se nenašla. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + Je povolená paralelizace testu pro {0} (pracovní procesy: {1}, obor: {2}). + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + Nepovedlo se načíst typy ze zdroje testu {0}. Je možné, že se některé nebo všechny testy v tomto zdroji nezjistily. +Chyba: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + Čisticí metoda sestavení {0}.{1} selhala. Chybová zpráva: {2}. Trasování zásobníku: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + Inicializační metoda sestavení {0}.{1} vyvolala výjimku. {2}: {3}. Přerušuje se provádění testu. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + Čisticí metoda třídy {0}.{1} selhala. Chybová zpráva: {2}. Trasování zásobníku: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + Inicializační metoda třídy {0}.{1} vyvolala výjimku. {2}: {3}. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Metoda {0}.{1} má špatný podpis. Metoda musí být static nebo public, nevrací hodnotu a nesmí přijímat žádný parametr. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task nebo ValueTask. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Metoda {0}.{1} má špatný podpis. Metoda musí být static nebo public, nevrací hodnotu a musí přijímat jeden parametr typu TestContext. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task nebo ValueTask. + + + + TestCleanup method {0}.{1} threw exception. {2}. + Metoda TestCleanup {0}.{1} vyvolala výjimku. {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + Při volání čisticí metody testu pro třídu {0} došlo k chybě: {1} + + + + TestCleanup Stack Trace + Trasování zásobníku čištění testu + + Data source '{0}' cannot be found in the test configuration settings Zdroj dat {0} se v nastavení konfigurace testu nenašel. + + --- End of inner exception stack trace --- + --- Konec trasování zásobníku pro vnitřní výjimku --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} Adaptéru testování částí se buď nepodařilo připojit ke zdroji dat, nebo přečíst data. Další informace o odstraňování této chyby najdete v knihovně MSDN v tématu Troubleshooting Data-Driven Unit Tests (http://go.microsoft.com/fwlink/?LinkId=62412). Podrobnosti o chybě: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: Třída {0} nemá platnou vlastnost TestContext. Vlastnost TestContext musí být typu TestContext, musí být nestatická a musí být veřejná. Například: public TestContext TestContext + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: Metoda {1} definovaná ve třídě {0} nemá správný podpis. Testovací metoda označená atributem [TestMethod] nesmí být static ani public, musí mít návratový typ void a nesmí přijímat žádný parametr. Například: public void Test.Class1.Test(). Pokud navíc v testovací metodě používáte operátor async-await, musí být návratový typ Task nebo ValueTask. Například: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}.{1} má neplatný atribut Timeout. Hodnota timeline musí být celé číslo větší než 0. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: V jednom sestavení nejde definovat více jak jednu metodu s atributem AssemblyCleanup. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: V jednom sestavení nejde definovat více jak jednu metodu s atributem AssemblyInitialize. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: Uvnitř třídy nejde definovat více jak jednu metodu s atributem ClassCleanup. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: Uvnitř třídy nejde definovat více jak jednu metodu s atributem ClassInitialize. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: Nejde definovat více jak jednu metodu s atributem TestCleanup. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: Nejde definovat více jak jednu metodu s atributem TestInitialize. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: Atribut TestClass se definoval v neveřejné třídě {0}. + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: V metodě {1} nejde definovat předdefinovanou vlastnost {2}. + + + + TestClass attribute defined on generic non-abstract class {0} + Atribut TestClass definovaný u obecné neabstraktní třídy {0} + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: V metodě {1} je definovaná vlastní vlastnost, která je null nebo je prázdná. Vlastní vlastnost musí mít platný název. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + Metoda Execute vyvolala neošetřenou výjimku. Nahlaste prosím tuto chybu autorovi atributu {0}. +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + Atribut ExpectedException definovaný u testovací metody {0}.{1} vyvolal během vytváření výjimku. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + Nepovedlo se získat výjimku vyvolanou testovací metodou {0}.{1}. + + + + Initialization method {0}.{1} threw exception. {2}. + Inicializační metoda {0}.{1} způsobila výjimku. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + Nepodařilo se vytvořit instanci třídy {0}. Chyba: {1}. + + + + Method {0}.{1} does not exist. + Metoda {0}.{1} neexistuje. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + Testovací metoda {0}.{1} má definovaných více atributů odvozených od atributu {2}. Povolený je jenom jeden takový atribut. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + Při provádění testu došlo k chybě. Rozšíření nevrátilo žádný výsledek. Pokud používáte rozšíření třídy TestMethodAttribute, obraťte se na dodavatele. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + Nelze najít platný konstruktor pro testovací třídu {0}. Platné konstruktory jsou public a buď bez parametrů, nebo s jedním parametrem typu TestContext. + + + + Unable to find property {0}.TestContext. Error:{1}. + Nepodařilo se najít vlastnost {0}.TestContext. Chyba:{1}. + + + + Unable to set TestContext property for the class {0}. Error: {1}. + Pro třídu {0} se nepodařilo nastavit vlastnost TestContext. Chyba: {1}. + + + + The {0}.TestContext has incorrect type. + {0}.TestContext má nesprávný typ. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Metoda {0}.{1} má špatný podpis. Metoda nesmí být static nebo public, nevrací hodnotu a nesmí přijímat žádný parametr. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task nebo ValueTask. + + + + Test method {0}.{1} threw exception: +{2} + V testovací metodě {0}.{1} došlo k výjimce: +{2} + + + + Unable to get type {0}. Error: {1}. + Nepodařilo se získat typ {0}. Chyba: {1}. + + + + The called code threw an exception that was caught, but the exception value was null + Volaný kód vyvolal výjimku, která byla zachycena, ale její hodnota byla null. + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0}. Pokud v testu používáte objekty uživatelského rozhraní, zvažte u projektů pro platformu UPW použití atributu [UITestMethod] místo atributu [TestMethod], aby se test provedl ve vlákně uživatelského rozhraní. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (Z důvodu výjimky se nepodařilo získat zprávu o výjimce typu {0}.) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + MSTest.TestAdapter a MSTest.TestFramework musí mít stejnou verzi. Byla nalezena verze MSTest.TestAdapter {0} a verze MSTest.TestFramework {1}. Ujistěte se prosím, že verze balíčků NuGet MSTest.TestAdapter a MSTest.TestFramework jsou shodné. + + Wrong number of objects for permutation. Should be greater than zero. Chybný počet objektů pro permutaci. Počet musí být větší než nula. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.de.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.de.xlf index a2fe24f8c5..45fefe8360 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.de.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.de.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + Timeout der Assemblybereinigungsmethode "{0}.{1}" nach {2} ms + + + + Assembly cleanup method '{0}.{1}' was canceled + Die Assemblybereinigungsmethode "{0}.{1}" wurde abgebrochen + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + Timeout der Assemblyinitialisierungsmethode "{0}.{1}" nach {2} ms + + + + Assembly initialize method '{0}.{1}' was canceled + Die Assemblyinitialisierungsmethode "{0}.{1}" wurde abgebrochen + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + Ausnahme beim Auflisten des IDataSource-Attributs für "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + Ausnahme beim Erweitern von IDataSource-Zeilen aus dem Attribut auf "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + Daten im Index {0} für "{1}" können nicht serialisiert werden. Alle über "IDataSource" bereitgestellten Daten sollten serialisierbar sein. Wenn Sie nicht serialisierbare Datenquellen testen müssen, stellen Sie sicher, dass Sie der Testassembly das Attribut "TestDataSourceDiscovery" hinzufügen und die Ermittlungsoption auf "DuringExecution" festlegen. + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + Der Anzeigename "{2}" für Indizes {0} und {1} ist doppelt vorhanden. Anzeigenamen sollten eindeutig sein. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. Die Datei "{0}" konnte nicht gefunden werden. + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + Die Testmethode „{0}.{1}“ kann nicht ausgeführt werden: Testdaten stimmen nicht mit Methodenparametern überein. Die Anzahl oder die Typen unterscheiden sich. +Test erwartete {2} Parameter mit den Typen „{3}“, +aber empfing {4} Argument(e) mit den Typen „{5}“. + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + Die Testmethode „{0}.{1}“ kann nicht ausgeführt werden: Die Methode verfügt über Parameter, definiert jedoch keine Testquelle. Verwenden Sie „[DataRow]“, „[DynamicData]“ oder eine benutzerdefinierte „ITestDataSource-Datenquelle“, um Testdaten bereitzustellen. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + Timeout der Klassenbereinigungsmethode "{0}.{1}" nach {2} ms + + + + Class cleanup method '{0}.{1}' was canceled + Die Klassenbereinigungsmethode "{0}.{1}" wurde abgebrochen + + + + Class initialize method '{0}.{1}' timed out after {2}ms + Timeout der Klasseninitialisierungsmethode "{0}.{1}" nach {2} ms + + + + Class initialize method '{0}.{1}' was canceled + Die Initialisierungsmethode "{0}.{1}" der Klasse wurde abgebrochen + + The parameter should not be null or empty. Der Parameter darf nicht NULL oder leer sein. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + Fehler von 'MSTestAdapter' beim Ermitteln von Tests in der Klasse "{0}" der Assembly "{1}". Ursache: {2}. + + + + {0} (Data Row {1}) + {0} (Datenzeile {1}) + + + + Debug Trace: + Debugablaufverfolgung: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. Problem bei der Testlaufbereitstellung: Ungültiges Bereitstellungselement: "{0}". Das Ausgabeverzeichnis "{1}" gibt das unzulässige Element an, das außerhalb des Bereitstellungsstammverzeichnisses bereitgestellt werden soll. @@ -77,16 +177,108 @@ Bereitstellungselement "{0}" (Ausgabeverzeichnis "{1}") + + [MSTest][Discovery][{0}] {1} + [MSTest][Discovery][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + Es wurden sowohl die Dateien „.runsettings“ als auch „.testconfig.json“ erkannt. Wählen Sie nur eine dieser Testkonfigurationsdateien aus. + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + "{0}": (Fehler beim Abrufen der Ausnahmebeschreibung aufgrund einer Ausnahme vom Typ "{1}". + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + Ausgelöste Ausnahmen: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + Test „{0}“ wurde abgebrochen + + + + Test '{0}' timed out after {1}ms + Timeout bei Test „{0}“ nach {1} ms + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + Beim Abrufen von benutzerdefinierten Attributen für den Typ {0} wurde Ausnahme ausgelöst (wird ignoriert und die Reflektionsart verwendet): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + Der Typ des generischen Parameters „{0}“ konnte nicht abgeleitet werden. + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + Die generische Testmethode „{0}“ hat keine Argumente, daher kann der generische Parameter nicht abgeleitet werden. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + Es wurden zwei in Konflikt stehende Typen für den generischen Parameter „{0}“ gefunden. Die in Konflikt stehenden Typen sind „{1}“ und „{2}“. + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + Für "ClassCleanupLifecycle" wurde ein ungültiger Wert "{0}" angegeben. Unterstützte Bereiche sind {1}. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + Ungültiger Wert "{0}" für "Scope" angegeben. Unterstützte Bereiche: {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + Ungültiger Wert "{0}" für "Workers" angegeben. Der Wert muss eine nicht negative Ganzzahl sein. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + Ungültige Einstellungen "{0}". Unerwartetes XmlAttribute: "{1}". + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. "MSTestAdapter" hat ein unerwartetes Element "{0}" in den Einstellungen "{1}" ermittelt. Entfernen Sie dieses Element, und versuchen Sie es erneut. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + Ungültige Einstellungen "{0}". Unerwartetes XmlElement: "{1}". + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. Ungültiger Wert "{0}" für runsettings-Eintrag "{1}". Die Einstellung wird ignoriert. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + Ungültiger Wert "{0}" für runsettings-Eintrag "{1}". Die Einstellung wird ignoriert. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + Warnung: Eine TESTSETTINGS-Datei oder eine VSMDI-Datei wird vom MSTest-V2-Adapter nicht unterstützt. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} Problem bei der Testlaufbereitstellung: Die Assembly oder das Modul "{0}" wurde nicht gefunden. Ursache: {1} @@ -97,21 +289,309 @@ Problem bei der Testlaufbereitstellung: Die Assembly oder das Modul "{0}" wurde nicht gefunden. + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + Eine ältere Version des MSTestV2-Pakets wird in die Assembly geladen. Bei der Testermittlung werden möglicherweise nicht alle Datentests ermittelt, wenn sie von der Datei ".runsettings" abhängen. + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + Der Eintrag "<ExecutionApartmentState>STA</ExecutionApartmentState>" der Ausführungseinstellungen wird auf Nicht-Windows-Betriebssystemen nicht unterstützt. + + + + Running tests in any of the provided sources is not supported for the selected platform + Das Ausführen von Tests in einer der angegebenen Quellen wird für die ausgewählte Plattform nicht unterstützt. + + + + Failed to discover tests from assembly {0}. Reason:{1} + Fehler beim Ermitteln von Tests aus der Assembly "{0}". Ursache:{1} + + + + File does not exist: {0} + Die Datei ist nicht vorhanden: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + Timeout der Testbereinigungsmethode "{0}.{1}" nach {2} ms + + + + Test cleanup method '{0}.{1}' was canceled + Die Testbereinigungsmethode "{0}.{1}" wurde abgebrochen + + + + TestContext cannot be Null. + "TestContext" darf nicht NULL sein. + + + + TestContext Messages: + TestContext-Meldungen: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + Timeout der Testinitialisierungsmethode "{0}.{1}" nach {2} ms + + + + Test initialize method '{0}.{1}' was canceled + Die Testinitialisierungsmethode "{0}.{1}" wurde abgebrochen + + + + Test method {0} was not found. + Die Testmethode "{0}" wurde nicht gefunden. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + Testparallelisierung aktiviert für {0} (Worker: {1}, Bereich: {2}) + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + Fehler beim Laden von Typen aus der Testquelle "{0}". Möglicherweise werden einige oder alle Tests in dieser Quelle nicht ermittelt. +Fehler: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + Fehler bei der Methode "{0}.{1}" für die Assemblybereinigung. Fehlermeldung: {2}. "StackTrace": {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + Die Methode "{0}.{1}" für die Assemblyinitialisierung hat eine Ausnahme ausgelöst. {2}: {3}. Die Ausführung des Tests wird abgebrochen. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + Fehler bei der Methode "{0}.{1}" für die Klassenbereinigung. Fehlermeldung: {2}. Stapelüberwachung: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + Die Methode "{0}.{1}" für die Klasseninitialisierung hat eine Ausnahme ausgelöst. {2}: {3}. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Die Methode „{0}.{1}“ weist eine falsche Signatur auf. Die Methode muss statisch und öffentlich sein. Sie darf keinen Wert zurückgeben und keinen Parameter annehmen. Wenn Sie außerdem in der Methode „async-await“ verwenden, muss der Rückgabetyp „Task“ oder „ValueTask“ sein. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Die Methode „{0}.{1}“ weist eine falsche Signatur auf. Die Methode muss statisch und öffentlich sein. Sie darf keinen Wert zurückgeben und muss einen einzigen Parameter des Typs TestContext annehmen. Wenn Sie außerdem in der Methode „async-await“ verwenden, muss der Rückgabetyp „Task“ oder „ValueTask“ sein. + + + + TestCleanup method {0}.{1} threw exception. {2}. + Die TestCleanup-Methode "{0}.{1}" hat eine Ausnahme ausgelöst. {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + Fehler beim Aufruf der Testbereinigungsmethode für die Testklasse "{0}": {1} + + + + TestCleanup Stack Trace + TestCleanup-Stapelüberwachung + + Data source '{0}' cannot be found in the test configuration settings Die Datenquelle "{0}" wurde in den Testkonfigurationseinstellungen nicht gefunden. + + --- End of inner exception stack trace --- + --- Ende der internen Ausnahmestapelüberwachung --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} Der Komponententestadapter konnte keine Verbindung mit der Datenquelle herstellen bzw. die Daten nicht lesen. Weitere Informationen zur Problembehandlung dieses Fehlers finden Sie unter "Problembehandlung von datengesteuerten Komponententests" (http://go.microsoft.com/fwlink/?LinkId=62412) in der MSDN Library. Fehlerdetails: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: Die Klasse {0} weist keine gültige Eigenschaft TestContext auf. TestContext muss vom Typ TestContext sein, muss nicht statisch und öffentlich sein. Beispiel: 'public TestContext TestContext'. + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: Die in der Klasse {0} definierte Methode {1} weist nicht die richtige Signatur auf. Die mit dem [TestMethod]-Attribut markierte Testmethode muss nicht statisch und öffentlich sein, muss den Rückgabetyp „void“ aufweisen und darf keine Parameter annehmen. Beispiel: public void Test.Class1.Test(). Wenn Sie außerdem in der Testmethode „async-await“ verwenden, muss der Rückgabetyp „Task“ oder „ValueTask“ sein. Beispiel: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}.{1} weist ein ungültiges Attribut „Timeout“ auf. Timeout muss eine ganze Zahl größer als 0 sein. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: Es darf nur eine Methode mit dem Attribut 'AssemblyCleanup' innerhalb einer Assembly definiert werden. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: Es darf nur eine Methode mit dem Attribut 'AssemblyInitialize' innerhalb einer Assembly definiert werden. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: Es darf nur eine Methode mit dem Attribut 'ClassCleanup' innerhalb einer Klasse definiert werden. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: Es darf nur eine Methode mit dem Attribut 'ClassInitialize' innerhalb einer Klasse definiert werden. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: Es darf nur eine Methode mit dem Attribut 'TestCleanup' definiert werden. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: Es darf nur eine Methode mit dem Attribut 'TestInitialize' definiert werden. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: Für die nicht öffentliche Klasse '{0}' definiertes Attribut 'TestClass'. + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: Die vordefinierte Eigenschaft "{2}" kann nicht für die Methode "{1}" definiert werden. + + + + TestClass attribute defined on generic non-abstract class {0} + TestClass-Attribut für generische nicht abstrakte Klasse {0} definiert + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: Für die Methode "{1}" wurde eine benutzerdefinierte Eigenschaft mit dem Wert NULL oder eine benutzerdefinierte leere Eigenschaft definiert. Die benutzerdefinierte Eigenschaft muss einen gültigen Namen aufweisen. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + Von der„Execute“-Methode wurde ein Ausnahmefehler ausgelöst. Melden Sie diesen Fehler dem Autor des Attributs „{0}“. +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + Das für die Testmethode "{0}.{1}" definierte ExpectedException-Attribut hat während der Konstruktion eine Ausnahme ausgelöst. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + Fehler beim Abrufen der von der Testmethode "{0}.{1}" ausgelösten Ausnahme. + + + + Initialization method {0}.{1} threw exception. {2}. + Die Initialisierungsmethode '{0}.{1}' hat eine Ausnahme ausgelöst. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + Es kann keine Instanz der Klasse '{0}' erstellt werden. Fehler: {1}. + + + + Method {0}.{1} does not exist. + Die Methode "{0}.{1}" ist nicht vorhanden. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + Für die Testmethode „{0}.{1}“ sind mehrere Attribute definiert, die von „{2}“ abgeleitet sind. Nur ein einziges solches Attribut ist zulässig. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + Fehler beim Ausführen des Tests. Von der Extension wurde kein Ergebnis zurückgegeben. Wenn Sie eine Extension von "TestMethodAttribute" verwenden, wenden Sie sich bitte an den Anbieter. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + Es wurde kein gültiger Konstruktor für die Testklasse "{0}" gefunden. Gültige Konstruktoren sind "public" und entweder parameterlos oder mit einem Parameter vom Typ "TestContext". + + + + Unable to find property {0}.TestContext. Error:{1}. + Die Eigenschaft "{0}.TestContext" wurde nicht gefunden. Fehler: {1}. + + + + Unable to set TestContext property for the class {0}. Error: {1}. + Die Eigenschaft 'TestContext' für die Klasse '{0}' kann nicht festgelegt werden. Fehler: {1}. + + + + The {0}.TestContext has incorrect type. + "{0}.TestContext" weist einen falschen Typ auf. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Die Methode „{0}.{1}“ weist eine falsche Signatur auf. Die Methode muss nicht statisch und öffentlich sein, und sie darf keinen Wert zurückgeben und keinen Parameter annehmen. Wenn Sie außerdem in der Methode „async-await“ verwenden, muss der Rückgabetyp „Task“ oder „ValueTask“ sein. + + + + Test method {0}.{1} threw exception: +{2} + Die Testmethode "{0}.{1}" hat eine Ausnahme ausgelöst: +{2} + + + + Unable to get type {0}. Error: {1}. + Der Typ "{0}" kann nicht abgerufen werden. Fehler: {1}. + + + + The called code threw an exception that was caught, but the exception value was null + Der aufgerufene Code hat eine Ausnahme ausgelöst, die abgefangen wurde, aber der Ausnahmewert war NULL. + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0}: Erwägen Sie für UWP-Projekte bei Einsatz von UI-Objekten im Test die Verwendung des [UITestMethod]-Attributs anstelle von "[TestMethod]", um den Test im UI-Thread auszuführen. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (Fehler beim Abrufen der Meldung für eine Ausnahme vom Typ "{0}" aufgrund einer Ausnahme.) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + „MSTest.TestAdapter“ und „MSTest.TestFramework“ müssen dieselbe Version aufweisen. Gefunden wurde „MSTest.TestAdapter“ Version „{0}“ und „MSTest.TestFramework“ Version „{1}“. Stellen Sie sicher, dass die Versionen der NuGet-Pakete „MSTest.TestAdapter“ und „MSTest.TestFramework“ übereinstimmen. + + Wrong number of objects for permutation. Should be greater than zero. Falsche Anzahl von Objekten für die Permutation. Die Anzahl muss größer als NULL sein. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.es.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.es.xlf index 1c05e7b8c1..d2af8480fa 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.es.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.es.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + Método de limpieza de ensamblado '{0}.{1}' se agotó el tiempo de espera después de {2}ms + + + + Assembly cleanup method '{0}.{1}' was canceled + Método de limpieza de ensamblado "{0}.{1}" se canceló + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + Método de inicialización de ensamblado '{0}.{1}' se agotó el tiempo de espera de después de {2}ms + + + + Assembly initialize method '{0}.{1}' was canceled + Método de inicialización de ensamblado "{0}.{1}" se canceló + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + Excepción al enumerar el atributo IDataSource en "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + Se produjo una excepción al expandir las filas de IDataSource del atributo en "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + No se pueden serializar los datos del {0} de índice para "{1}". Todos los datos proporcionados a través de "IDataSource" deben ser serializables. Si necesita probar orígenes de datos no serializables, asegúrese de agregar el atributo "TestDataSourceDiscovery" en el ensamblado de prueba y establezca la opción de detección en "DuringExecution". + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + El nombre para mostrar "{2}" en los índices {0} y {1} están duplicados. Los nombres para mostrar deben ser únicos. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. No se pudo encontrar el archivo '{0}'. + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + No se puede ejecutar el método de prueba '{0}.{1}': Los datos de prueba no coinciden con los parámetros del método. El recuento o los tipos son diferentes. +Probar los parámetros de {2} esperados, con los tipos '{3}', +pero recibió {4} argumentos, con los tipos '{5}'. + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + No se puede ejecutar el método de prueba "{0}.{1}": el método tiene parámetros, pero no define ningún origen de prueba. Use "[DataRow]", "[DynamicData]" o un origen de datos "ITestDataSource" personalizado para proporcionar datos de prueba. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + Método de limpieza de clases '{0}.{1}' se agotó el tiempo de espera después de {2}ms + + + + Class cleanup method '{0}.{1}' was canceled + Método de limpieza de clases "{0}.{1}" se canceló + + + + Class initialize method '{0}.{1}' timed out after {2}ms + Método de inicialización de clase '{0}.{1}' se agotó el tiempo de espera después de {2}ms + + + + Class initialize method '{0}.{1}' was canceled + Método de inicialización de clase "{0}.{1}" se canceló + + The parameter should not be null or empty. El parámetro no debe ser NULL ni estar vacío. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + MSTestAdapter no detectó pruebas en la clase '{0}' del ensamblado '{1}' porque {2}. + + + + {0} (Data Row {1}) + {0} (Fila de datos {1}) + + + + Debug Trace: + Seguimiento de depuración: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. Problema de implementación en la serie de pruebas: elemento de implementación incorrecto '{0}': el directorio de salida '{1}' especifica el elemento que se va a implementar fuera del directorio raíz de implementación, lo cual no está permitido. @@ -77,16 +177,108 @@ elemento de implementación '{0}' (directorio de salida '{1}') + + [MSTest][Discovery][{0}] {1} + [MSTest][Discovery][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + Se han detectado los archivos ".runsettings" y ".testconfig.json". Seleccione solo uno de estos archivos de configuración de prueba. + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + "{0}": (No se pudo obtener la descripción de la excepción debido a una excepción de tipo "{1}". + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + Excepciones devueltas: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + Se canceló la prueba '{0}' + + + + Test '{0}' timed out after {1}ms + La prueba '{0}' agotó el tiempo de espera después de {1} ms + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + Al obtener atributos personalizados para el tipo {0} se produjo una excepción (se omitirá y se usará la forma de reflexión): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + No se pudo inferir el tipo del parámetro genérico '{0}'. + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + El método de prueba genérico '{0}' no tiene argumentos, por lo que no se puede inferir el parámetro genérico. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + Se encontraron dos tipos en conflicto para el parámetro genérico '{0}'. Los tipos en conflicto son '{1}' y ''{2}. + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + Valor no válido "{0}" especificado para "ClassCleanupLifecycle". Los ámbitos admitidos son {1}. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + Valor no válido "{0}" especificado para "Ámbito". Los ámbitos admitidos son {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + Valor no válido "{0}" especificado para "Trabajadores". El valor debe ser un entero no negativo. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + Valor no válido '{0}'. XmlAttribute no esperado: '{1}'. + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter encontró un elemento inesperado '{0}' en su configuración '{1}'. Quite este elemento e inténtelo de nuevo. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + Valor no válido '{0}'. XmlElement no esperado: '{1}'. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. Valor ''{0}'' no válido para la entrada runsettings ''{1}'', se omitirá la configuración. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + Valor ''{0}'' no válido para la entrada runsettings ''{1}'', se omitirá la configuración. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + Advertencia: No se admite un archivo testsettings o vsmdi con el adaptador de MSTest V2. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} Problema de implementación en la serie de pruebas: no se encontró el ensamblado o el módulo '{0}'. Motivo: {1} @@ -97,21 +289,309 @@ Problema de implementación en la serie de pruebas: no se encontró el ensamblado o el módulo '{0}'. + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + Hay una versión anterior del paquete MSTestV2 cargada en el ensamblado. Es posible que la detección de pruebas no detecte todas las pruebas de datos si dependen del archivo ".runsettings". + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + La entrada runsettings "<ExecutionApartmentState>STA</ExecutionApartmentState>" no se admite en sistemas operativos que no son de Windows. + + + + Running tests in any of the provided sources is not supported for the selected platform + La ejecución de pruebas en las fuentes proporcionadas no se admite para la plataforma seleccionada + + + + Failed to discover tests from assembly {0}. Reason:{1} + No se pudieron detectar pruebas desde el ensamblado {0}. Motivo:{1} + + + + File does not exist: {0} + El archivo no existe: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + Método de limpieza de pruebas '{0}.{1}' se agotó el tiempo de espera después de {2}ms + + + + Test cleanup method '{0}.{1}' was canceled + Método de limpieza de pruebas "{0}.{1}" se canceló + + + + TestContext cannot be Null. + TestContext no será null. + + + + TestContext Messages: + Mensajes de TestContext: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + Método de inicialización de prueba '{0}.{1}' se agotó el tiempo de espera después de {2}ms + + + + Test initialize method '{0}.{1}' was canceled + Método de inicialización de prueba "{0}.{1}" se canceló + + + + Test method {0} was not found. + No encontrado método prueba {0}. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + Probar paralelización habilitada para {0} (Trabajos: {1}, Ámbito: {2}) + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0} {1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + No se pueden cargar tipos del origen de prueba "{0}". Puede que no se detecten algunas o ninguna de las pruebas de este origen. +Error: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + Error de método Cleanup de ensamblado {0}.{1}. Mensaje de error: {2}. StackTrace: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + Excepción método inicialización ensamblado {0}.{1}. {2}: {3}. Anulada ejecución de prueba. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + Error de método Cleanup de clase {0}.{1}. Mensaje error: {2}. Seguimiento de pila: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + Excepción del método inicialización clase {0}. {1}. {2}: {3}. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + El método {0}.{1} tiene una firma incorrecta. El método debe ser estático, público, no devolver un valor y no aceptar ningún parámetro. Además, si está usando async-await en el método entonces el tipo de valor devuelto debe ser 'Task' o 'ValueTask'. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + El método {0}.{1} tiene una firma incorrecta. El método debe ser estático, público, no devolver ningún valor y debe tomar un único parámetro de tipo TestContext. Además, si está usando async-await en el método entonces el tipo de valor devuelto debe ser 'Task' o 'ValueTask'. + + + + TestCleanup method {0}.{1} threw exception. {2}. + El método TestCleanup {0}.{1} devolvió una excepción. {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + Error al llamar al método Test Cleanup para la clase de prueba {0}: {1} + + + + TestCleanup Stack Trace + Seguimiento de pila de TestCleanup + + Data source '{0}' cannot be found in the test configuration settings No se encuentra el origen de datos '{0}' en los valores de configuración de prueba + + --- End of inner exception stack trace --- + --- Fin del seguimiento de la pila de excepción interna --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} El adaptador de pruebas unitarias no puede conectarse al origen de datos o leer los datos. Para obtener más información acerca de cómo solucionar este error, consulte "Solución de problemas de pruebas unitarias orientadas a datos" (http://go.microsoft.com/fwlink/?LinkId=62412) en la biblioteca de MSDN. Detalles del error: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: la clase {0}no tiene la propiedad TestContext válida. TestContext debe ser de tipo TestContext, debe ser no estática y debe ser pública. Por ejemplo: public TestContext TestContext. + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: El método {1} definido en la clase {0} no tiene la firma correcta. El método de prueba marcado con el atributo [TestMethod] debe ser no estático, público, con el tipo devuelto void y no debe tomar ningún parámetro. Ejemplo: public void Test.Class1.Test(). Además, si está usando async-await en el método de prueba, entonces el tipo de valor devuelto debe ser 'Task' o 'ValueTask'. Ejemplo: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}.{1} tiene un atributo Timeout no válido. El tiempo de espera debe ser un valor entero mayor que 0. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: No se puede definir más de un método con el atributo AssemblyCleanup dentro de un ensamblado. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: No se puede definir más de un método con el atributo AssemblyInitialize dentro de un ensamblado. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: No se puede definir más de un método con el atributo ClassCleanup dentro de una clase. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: No se puede definir más de un método con el atributo ClassInitialize dentro de una clase. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: No se puede definir más de un método con el atributo TestCleanup. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: No se puede definir más de un método con el atributo TestInitialize. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: se ha definido el atributo TestClass en la clase no pública {0} + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: no se puede definir la propiedad predefinida {2} en el método {1}. + + + + TestClass attribute defined on generic non-abstract class {0} + Atributo TestClass definido en una clase genérica no abstracta {0} + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: se ha definido una propiedad personalizada nula o vacía en el método {1}. La propiedad personalizada debe tener un nombre válido. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + El método 'Execute' produjo una excepción no controlada. Notifique este error al autor del atributo ''{0}. +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + El atributo ExpectedException definido en el método de prueba {0}.{1} inició una excepción durante la construcción. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + No se pudo obtener la excepción iniciada por el método de prueba {0}.{1}. + + + + Initialization method {0}.{1} threw exception. {2}. + El método de inicialización {0}.{1} devolvió una excepción. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + No se puede crear una instancia de la clase {0}. Error: {1}. + + + + Method {0}.{1} does not exist. + El método {0}.{1} no existe. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + El método de prueba '{0}.{1}' tiene varios atributos derivados de '{2}' definidos en él. Solo se permite un atributo de este tipo. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + No se pudo ejecutar prueba. Extensión no devolvió resultados. Si usa extensión TestMethodAttribute, contacte con el proveedor. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + No se encuentra un constructor válido para la clase de prueba '{0}'. Los constructores válidos son 'public' y sin parámetros o con un parámetro de tipo 'TestContext'. + + + + Unable to find property {0}.TestContext. Error:{1}. + No se puede encontrar la propiedad {0}.TestContext. Error:{1}. + + + + Unable to set TestContext property for the class {0}. Error: {1}. + No se puede establecer la propiedad TestContext para la clase {0}. Error: {1}. + + + + The {0}.TestContext has incorrect type. + Tipo {0}.TestContext no es correcto. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + El método {0}.{1} tiene una firma incorrecta. Debe ser un método no estático, público, no devolver ningún valor y no debe aceptar parámetros. Además, si está usando async-await en el método entonces el tipo de valor devuelto debe ser 'Task' o 'ValueTask'. + + + + Test method {0}.{1} threw exception: +{2} + Excepción método de prueba {0}.{1}: +{2} + + + + Unable to get type {0}. Error: {1}. + No se puede obtener el tipo {0}. Error: {1}. + + + + The called code threw an exception that was caught, but the exception value was null + El código llamado produjo una excepción que se detectó, pero el valor de la excepción era null + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0}. En proyectos de UWP, si usa objetos de interfaz de usuario en la prueba, podría usar el atributo [UITestMethod] en lugar de [TestMethod] para ejecutar la prueba en el subproceso de interfaz de usuario. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (No se pudo obtener el mensaje para una excepción del tipo {0} debido a una excepción.) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + "MSTest.TestAdapter" y "MSTest.TestFramework" deben tener la misma versión. Se encontró la versión "{0}" de "MSTest.TestAdapter" y la versión "{1}" de "MSTest.TestFramework". Asegúrese de que las versiones de los paquetes NuGet "MSTest.TestAdapter" y "MSTest.TestFramework" tienen la misma versión. + + Wrong number of objects for permutation. Should be greater than zero. Número incorrecto de objetos para permutación. Debe ser una cantidad mayor que cero. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.fr.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.fr.xlf index 0233a28fb8..1929980124 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.fr.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.fr.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + La méthode de nettoyage d’assembly « {0}.{1} » a expiré après {2}ms + + + + Assembly cleanup method '{0}.{1}' was canceled + La méthode de nettoyage de l’assembly « {0}.{1} » a été annulée + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + La méthode d'initialisation de l’assembly « {0}.{1} » a expiré après {2}ms + + + + Assembly initialize method '{0}.{1}' was canceled + La méthode d’initialisation de l’assembly « {0}.{1} » a été annulée + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + Une exception s’est produite lors de l’énumération de l’attribut IDataSource sur « {0}.{1} » : {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + Une exception s’est produite lors du développement des lignes IDataSource à partir de l’attribut sur « {0}.{1} » : {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + Impossible de sérialiser les données de l’index {0} pour « {1} ». Toutes les données fournies via « IDataSource » doivent être sérialisables. Si vous devez tester des sources de données non sérialisables, veillez à ajouter l’attribut « TestDataSourceDiscovery » à votre assembly de test et définissez l’option de découverte sur « DuringExecution ». + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + Le nom d’affichage « {2} » sur les index {0} et {1} est dupliqué. Les noms d’affichage doivent être uniques. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. Le fichier '{0}' est introuvable. + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + Impossible d’exécuter la méthode de test « {0}.{1} » : les données de test ne correspondent pas aux paramètres de la méthode. Le nombre ou les types sont différents. +Tester le ou les paramètres de {2} attendus, avec les types « {3} », +mais a reçu {4} argument(s), avec les types « {5} ». + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + Impossible d’exécuter la méthode de test « {0}.{1} » : la méthode a des paramètres, mais ne définit aucune source de test. Utilisez « [DataRow] », « [DynamicData] » ou une source de données « ITestDataSource » personnalisée pour fournir des données de test. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + La méthode de nettoyage de classe « {0}.{1} » a expiré après {2}ms + + + + Class cleanup method '{0}.{1}' was canceled + La méthode de nettoyage de la classe « {0}.{1} » a été annulée + + + + Class initialize method '{0}.{1}' timed out after {2}ms + La méthode d'initialisation de la classe « {0}.{1} » a expiré après {2}ms + + + + Class initialize method '{0}.{1}' was canceled + La méthode d’initialisation de la classe « {0}.{1} » a été annulée + + The parameter should not be null or empty. Le paramètre ne doit pas être une valeur Null ou être vide. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + MSTestAdapter n'a pas découvert de tests dans la classe '{0}' de l'assembly '{1}', car {2}. + + + + {0} (Data Row {1}) + {0} (ligne de données {1}) + + + + Debug Trace: + Trace du débogage : + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. Problème de déploiement de la série de tests : élément de déploiement incorrect : '{0}' : le répertoire de sortie '{1}' spécifie l'élément à déployer en dehors du répertoire racine du déploiement, ce qui n'est pas autorisé. @@ -77,16 +177,108 @@ élément de déploiement '{0}' (répertoire de sortie '{1}') + + [MSTest][Discovery][{0}] {1} + [MSTest][Discovery][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + Les fichiers « .runsettings » et « .testconfig.json » ont été détectés. Veuillez sélectionner un seul de ces fichiers de configuration de test. + + + + {0}: {1} + {0} : {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + « {0} » : (Échec de l’obtention de la description de l’exception en raison d’une exception de type « {1} ». + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + Exceptions levées/s : + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + Le test {0} a été annulé + + + + Test '{0}' timed out after {1}ms + Le test « {0} » a expiré après {1} ms + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + L’obtention d’attributs personnalisés pour le type {0} a levé une exception (ignorera et utilisera la méthode de réflexion) : {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + Le type du paramètre générique « {0} » n'a pas pu être déduit. + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + La méthode de test générique « {0} » n’a pas d’arguments, donc le paramètre générique ne peut pas être déduit. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + Deux types en conflit ont été trouvés pour le paramètre générique « {0} ». Les types en conflit sont « {1} » et « {2} ». + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + Valeur non valide '{0}' spécifiée pour la 'ClassCleanupLifecycle'. Les portées prises en charge sont {1}. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + Valeur non valide '{0}' spécifiée pour la 'Portée'. Les portées prises en charge sont {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + Valeur non valide '{0}' spécifiée pour 'Workers'. La valeur doit être un entier non négatif. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + Paramètres non valides '{0}'. XmlAttribute inattendu : '{1}'. + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter a rencontré un élément inattendu '{0}' dans ses paramètres '{1}'. Supprimez cet élément, puis réessayez. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + Paramètres non valides '{0}'. XmlElement inattendu : '{1}'. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. Valeur non valide '{0}' pour l’entrée runsettings '{1}', le paramètre sera ignoré. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + Valeur non valide '{0}' pour l’entrée runsettings '{1}', le paramètre sera ignoré. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + Avertissement : L'adaptateur MSTest V2 ne prend pas en charge les fichiers testsettings ou vsmdi. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} Problème de déploiement de la série de tests : l'assembly ou le module '{0}' est introuvable. Raison : {1} @@ -97,21 +289,309 @@ Problème de déploiement de la série de tests : l'assembly ou le module '{0}' est introuvable. + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + Une version antérieure du package MSTestV2 est chargée dans l’assembly. La découverte de tests risque de ne pas découvrir tous les tests de données s’ils dépendent du fichier '.runsettings'. + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + L’entrée Runsettings « <ExecutionApartmentState>STA</ExecutionApartmentState> » n’est pas prise en charge sur les systèmes d’exploitation non Windows. + + + + Running tests in any of the provided sources is not supported for the selected platform + L'exécution de tests dans l'une des sources fournies n'est pas prise en charge pour la plateforme sélectionnée + + + + Failed to discover tests from assembly {0}. Reason:{1} + Échec de la découverte de tests à partir de l'assembly {0}. Raison :{1} + + + + File does not exist: {0} + Fichier inexistant : {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + La méthode de nettoyage de test « {0}.{1} » a expiré après {2}ms + + + + Test cleanup method '{0}.{1}' was canceled + La méthode de nettoyage du test « {0}.{1} » a été annulée + + + + TestContext cannot be Null. + TestContext ne peut pas être null. + + + + TestContext Messages: + Messages TestContext : + + + + Test initialize method '{0}.{1}' timed out after {2}ms + La méthode d’initialisation de test « {0}.{1} » a expiré après {2}ms + + + + Test initialize method '{0}.{1}' was canceled + La méthode d’initialisation du test « {0}.{1} » a été annulée + + + + Test method {0} was not found. + Méthode de test {0} introuvable. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + Parallélisation des tests activée pour {0} (Workers : {1}, Étendue : {2}). + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + Impossible de charger les types à partir de la source de tests '{0}'. Une partie ou l'ensemble des tests de cette source ne peuvent pas être découverts. +Erreur : {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + La méthode Cleanup d'assembly {0}.{1} a échoué. Message d'erreur : {2}. StackTrace : {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + La méthode d'assembly Initialization {0}.{1} a levé une exception. {2} : {3}. Abandon de l'exécution de tests. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + La méthode de classe Cleanup {0}.{1} a échoué. Message d'erreur : {2}. Trace de la pile : {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + La méthode de classe Initialization {0}.{1} a levé une exception. {2} : {3}. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + La méthode {0}.{1} présente une signature incorrecte. La méthode doit être statique, publique et ne doit retourner aucune valeur ni accepter aucun paramètre. En outre, si vous utilisez async-await dans la méthode, return-type doit être « Task » ou « ValueTask ». + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + La méthode {0}.{1} présente une signature incorrecte. La méthode doit être statique, publique et ne doit retourner aucune valeur et accepter un seul paramètre de type TestContext. En outre, si vous utilisez async-await dans la méthode, return-type doit être « Task » ou « ValueTask ». + + + + TestCleanup method {0}.{1} threw exception. {2}. + La méthode TestCleanup {0}.{1} a levé une exception. {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + Erreur lors de l'appel de la méthode Test Cleanup pour la classe de test {0} : {1} + + + + TestCleanup Stack Trace + Trace de la pile TestCleanup + + Data source '{0}' cannot be found in the test configuration settings Source de données '{0}' introuvable dans les paramètres de configuration de test + + --- End of inner exception stack trace --- + --- Fin de la trace de la pile d'exception interne --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} L'adaptateur de test unitaire n'a pas réussi à se connecter à la source de données ou à lire les données. Pour plus d'informations sur le dépannage de l'erreur, consultez "Résolution des problèmes liés aux tests unitaires pilotés par les données" (http://go.microsoft.com/fwlink/?LinkId=62412) dans MSDN Library. Détails de l'erreur : {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031 : la classe {0} n'a pas de propriété TestContext valide. TestContext doit être de type TestContext, doit être non statique et doit être public. Par exemple : public TestContext TestContext. + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007 : la méthode {1} définie dans la classe {0} ne dispose pas d'une signature correcte. Une méthode de test marquée avec l'attribut [TestMethod] doit être non statique, doit utiliser void pour return-type et ne doit accepter aucun paramètre. Exemple : public void Test.Class1.Test(). En outre, si vous utilisez async-await dans la méthode test, return-type doit être « Task » ou « ValueTask ». Exemple : public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054 : {0}.{1}possède un attribut de délai d’expiration non valide. Le délai d’expiration doit être un nombre entier supérieur à 0. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014 : {0} : impossible de définir plus d'une méthode avec l'attribut AssemblyCleanup à l'intérieur d'un assembly. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013 : {0} : impossible de définir plus d'une méthode avec l'attribut AssemblyInitialize à l'intérieur d'un assembly. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026 : {0} : impossible de définir plus d'une méthode avec l'attribut ClassCleanup à l'intérieur d'une classe. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025 : {0} : impossible de définir plus d'une méthode avec l'attribut ClassInitialize à l'intérieur d'une classe. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024 : {0} : impossible de définir plus d'une méthode avec l'attribut TestCleanup. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018 : {0} : impossible de définir plus d'une méthode avec l'attribut TestInitialize. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001 : attribut TestClass défini sur la classe non publique {0} + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023 : {0} : Impossible de définir la propriété prédéfinie {2} sur la méthode {1}. + + + + TestClass attribute defined on generic non-abstract class {0} + Attribut TestClass défini sur une classe non abstraite générique {0} + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021 : {0} : Une propriété null ou vide personnalisée est définie sur la méthode {1}. La propriété personnalisée doit posséder un nom valide. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + Une exception non gérée a été levée par la méthode « Execute ». Veuillez signaler cette erreur à l’auteur de l’attribut « {0} ». +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + L'attribut ExpectedException défini dans la méthode de test {0}.{1} a levé une exception durant la construction. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + Échec de l'obtention de l'exception levée par la méthode de test {0}.{1}. + + + + Initialization method {0}.{1} threw exception. {2}. + La méthode Initialization {0}.{1} a levé une exception. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + Impossible de créer une instance de la classe {0}. Erreur : {1}. + + + + Method {0}.{1} does not exist. + La méthode {0}.{1} n'existe pas. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + La méthode de test « {0}.{1} » possède plusieurs attributs dérivés de « {2} » qui lui sont définis. Un seul attribut de ce type est autorisé. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + Erreur lors de l'exécution du test. L'extension n'a retourné aucun résultat. Si vous utilisez l'extension de TestMethodAttribute, contactez le fournisseur. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + Impossible de trouver un constructeur valide pour la classe de test « {0} ». Les constructeurs valides sont « publics » et sans paramètre ou avec un paramètre de type « TestContext ». + + + + Unable to find property {0}.TestContext. Error:{1}. + Propriété {0}.TestContext introuvable. Erreur :{1}. + + + + Unable to set TestContext property for the class {0}. Error: {1}. + Impossible de définir la propriété TestContext pour la classe {0}. Erreur : {1}. + + + + The {0}.TestContext has incorrect type. + {0}.TestContext possède un type incorrect. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + La méthode {0}.{1} présente une signature incorrecte. La méthode doit être non statique, publique et ne doit retourner aucune valeur ni accepter aucun paramètre. En outre, si vous utilisez async-await dans la méthode, return-type doit être « Task » ou « ValueTask ». + + + + Test method {0}.{1} threw exception: +{2} + La méthode de test {0}.{1} a levé une exception : +{2} + + + + Unable to get type {0}. Error: {1}. + Impossible d'obtenir le type {0}. Erreur : {1}. + + + + The called code threw an exception that was caught, but the exception value was null + Le code appelé a levé une exception qui a été interceptée, mais la valeur de l’exception était nul + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0} Pour les projets UWP, si vous utilisez des objets d'IU dans un test, utilisez l'attribut [UITestMethod] à la place de [TestMethod] pour exécuter le test dans le thread d'interface utilisateur. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (Échec de la réception du message pour une exception de type {0} en raison d'une exception.) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + « MSTest.TestAdapter » et « MSTest.TestFramework » doivent avoir la même version. Version de « MSTest.TestAdapter » : « {0} » et version de « MSTest.TestFramework » : « {1} ». Veuillez vous assurer que les versions des packages NuGet « MSTest.TestAdapter » et « MSTest.TestFramework » sont identiques. + + Wrong number of objects for permutation. Should be greater than zero. Nombre d'objets erroné pour la permutation. Il doit être supérieur à zéro. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.it.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.it.xlf index 4808a47f8f..237f15eff0 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.it.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.it.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + Metodo di pulizia dell’assembly '{0}. Time out di {1}' dopo {2} ms + + + + Assembly cleanup method '{0}.{1}' was canceled + Il metodo di pulizia dell'assembly "{0}.{1}" è stato annullato + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + Metodo di inizializzazione dell'assembly '{0}. Timeout di {1}' dopo {2} ms + + + + Assembly initialize method '{0}.{1}' was canceled + Il metodo di inizializzazione dell'assembly "{0}.{1}" è stato annullato + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + Si è verificata un'eccezione durante l'enumerazione dell'attributo IDataSource in "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + Si è verificata un'eccezione durante l'espansione delle righe IDataSource dall'attributo in "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + Non è possibile serializzare i dati nell'indice {0} per "{1}". Tutti i dati forniti tramite "IDataSource" devono essere serializzabili. Se è necessario testare origini dati non serializzabili, assicurarsi di aggiungere l'attributo "TestDataSourceDiscovery" nell'assembly di test e impostare l'opzione di individuazione su "DuringExecution". + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + Il nome visualizzato "{2}" negli indici {0} e {1} è duplicato. I nomi visualizzati devono essere univoci. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. Il file '{0}' non è stato trovato. + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + Non è possibile eseguire il metodo di test '{0}.{1}': i dati del test non corrispondono ai parametri del metodo. Il numero o il tipo è diverso. +Il test prevedeva {2} parametri, con tipi '{3}', +ma ha ricevuto {4} argomenti, con tipi '{5}'. + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + Impossibile eseguire il metodo di test "{0}.{1}": il metodo contiene parametri, ma non definisce alcuna origine test. Usare "[DataRow]", "[DynamicData]" o un'origine dati "ITestDataSource" personalizzata per fornire i dati del test. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + Time out del metodo di pulizia della classe '{0}. Time out di {1}' dopo {2} ms + + + + Class cleanup method '{0}.{1}' was canceled + Il metodo di pulizia della classe "{0}.{1}" è stato annullato + + + + Class initialize method '{0}.{1}' timed out after {2}ms + Metodo di inizializzazione della classe '{0}. Timeout di {1}' dopo {2} ms + + + + Class initialize method '{0}.{1}' was canceled + Il metodo di inizializzazione della classe "{0}.{1}" è stato annullato + + The parameter should not be null or empty. Il parametro non deve essere vuoto o Null. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + MSTestAdapter non è riuscito a individuare test nella classe '{0}' dell'assembly '{1}' perché {2}. + + + + {0} (Data Row {1}) + {0} (riga dati {1}) + + + + Debug Trace: + Traccia di debug: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. Problema di distribuzione dell'esecuzione dei test: l'elemento di distribuzione '{0}' non è corretto. La directory di output '{1}' specifica l'elemento da distribuire all'esterno della directory radice della distribuzione e questa operazione non consentita. @@ -77,16 +177,108 @@ elemento di distribuzione '{0}' (directory di output '{1}') + + [MSTest][Discovery][{0}] {1} + [MSTest][Individuazione][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + Sono stati rilevati sia i file '.runsettings' sia '.testconfig.json'. Selezionare solo uno di questi file di configurazione di test. + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + "{0}": (non è stato possibile ottenere la descrizione dell'eccezione a causa di un'eccezione di tipo "{1}". + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + Eccezioni generate: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + Il test '{0}' è stato annullato + + + + Test '{0}' timed out after {1}ms + Timeout del test '{0}' dopo {1} ms + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + Il recupero degli attributi personalizzati per il tipo {0} ha generato un'eccezione (verrà ignorata e verrà usata la modalità reflection): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + Non è possibile dedurre il tipo del parametro generico '{0}'. + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + Il metodo di test generico '{0}' non ha argomenti, quindi non è possibile dedurre il parametro generico. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + Sono stati trovati due tipi in conflitto per il parametro generico '{0}'. I tipi in conflitto sono '{1}' e '{2}'. + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + Il valore '{0}', specificato per 'ClassCleanupLifecycle', non è valido. I valori supportati per Scope sono {1}. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + Il valore '{0}', specificato per 'Scope', non è valido. I valori supportati per Scope sono {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + Il valore '{0}', specificato per 'Workers', non è valido. Il valore deve essere un numero intero non negativo. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + Le impostazioni '{0}' non sono valide. Elemento XmlAttribute imprevisto: '{1}'. + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter ha rilevato un elemento imprevisto '{0}' nelle impostazioni '{1}'. Rimuovere l'elemento e riprovare. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + Le impostazioni '{0}' non sono valide. Elemento XmlElement imprevisto: '{1}'. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. Valore non valido '{0}' per la voce runsettings '{1}'. L'impostazione verrà ignorata. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + Valore non valido '{0}' per la voce runsettings '{1}'. L'impostazione verrà ignorata. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + Avviso: con l'adattatore MSTest V2 non è possibile usare un file testsettings o un file vsmdi. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} Problema di distribuzione dell'esecuzione dei test: l'assembly o il modulo '{0}' non è stato trovato. Motivo: {1} @@ -97,21 +289,309 @@ Problema di distribuzione dell'esecuzione dei test: l'assembly o il modulo '{0}' non è stato trovato. + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + Nell'assembly è caricata una versione precedente del pacchetto MSTestV2. L'individuazione dei test potrebbe non riuscire a individuare tutti i test dei dati se dipendono dal file '.runsettings'. + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + La voce Runsettings '<ExecutionApartmentState>STA</ExecutionApartmentState>' non è supportata nei sistemi operativi non Windows. + + + + Running tests in any of the provided sources is not supported for the selected platform + L'esecuzione di test in una delle origini specificate non è supportata per la piattaforma selezionata + + + + Failed to discover tests from assembly {0}. Reason:{1} + Non è stato possibile individuare i test dall'assembly {0}. Motivo: {1} + + + + File does not exist: {0} + Il file {0} non esiste + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + Time out del metodo di pulizia della classe dei test '{0}. Time out di {1}' dopo {2} ms + + + + Test cleanup method '{0}.{1}' was canceled + Il metodo di pulizia del test "{0}.{1}" è stato annullato + + + + TestContext cannot be Null. + TestContext non può essere Null. + + + + TestContext Messages: + Messaggi di TestContext: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + Metodo di inizializzazione del test '{0}. Timeout di {1}' dopo {2} ms + + + + Test initialize method '{0}.{1}' was canceled + Il metodo di inizializzazione del test "{0}.{1}" è stato annullato + + + + Test method {0} was not found. + Il metodo di test {0} non è stato trovato. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + Parallelizzazione test abilitata per {0} (Processi di lavoro: {1}. Ambito: {2}). + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + Non è possibile caricare i tipi dall'origine test '{0}'. È possibile che alcuni o tutti i test non siano stati individuati in questa origine. +Errore: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + Il metodo di pulizia assembly {0}.{1} non è riuscito. Messaggio di errore: {2}. Analisi dello stack: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + Il metodo di inizializzazione assembly {0}.{1} ha generato un'eccezione. {2}: {3}. L'esecuzione del test verrà interrotta. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + Il metodo di pulizia classi {0}.{1} non è riuscito. Messaggio di errore: {2}. Analisi dello stack: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + Il metodo di inizializzazione classi {0}.{1} ha generato un'eccezione. {2}: {3}. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + La firma del metodo {0}.{1}non è corretta. Il metodo deve essere statico e pubblico, non deve restituire un valore né accettare parametri. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere 'Task' o 'ValueTask'. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + La firma del metodo {0}.{1}non è corretta. Il metodo deve essere statico e pubblico, non deve restituire un valore e deve accettare un singolo parametro di tipo TestContext. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere 'Task' o 'ValueTask'. + + + + TestCleanup method {0}.{1} threw exception. {2}. + Il metodo TestCleanup {0}.{1} ha generato un'eccezione. {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + Si è verificato un errore durante la chiamata del metodo TestCleanup per la classe di test {0}: {1} + + + + TestCleanup Stack Trace + Analisi dello stato di TestCleanup + + Data source '{0}' cannot be found in the test configuration settings L'origine dati '{0}' non è stata trovata nelle impostazioni della configurazione di test + + --- End of inner exception stack trace --- + --- Fine dell'analisi dello stack dell'eccezione interna --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} L'adattatore di unit test non è riuscito a connettersi all'origine dati o a leggere i dati. Per altre informazioni sulla risoluzione di questo errore, vedere "Risoluzione dei problemi relativi a unit test basati su dati" (http://go.microsoft.com/fwlink/?LinkId=62412) in MSDN Library. Dettagli errore: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: la classe {0} non dispone di una proprietà TestContext valida. La proprietà TestContext deve essere di tipo TestContext, non deve essere statica e deve essere pubblica. Ad esempio: public TestContext TestContext. + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: la firma del metodo {1} definito nella classe {0} non è corretta. Il metodo di test contrassegnato con l'attributo [TestMethod] deve essere pubblico e non statico, non deve accettare parametri e deve includere un tipo restituito void. Esempio: public void Test.Class1.Test(). Se inoltre nel metodo di test si usa async-await, il tipo restituito deve essere 'Task' o 'ValueTask'. Esempio: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}.{1} ha un attributo Timeout non valido. Il timeout deve essere un valore intero maggiore di 0. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: non è possibile definire più di un metodo con l'attributo AssemblyCleanup all'interno di un assembly. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: non è possibile definire più di un metodo con l'attributo AssemblyInitialize all'interno di un assembly. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: non è possibile definire più di un metodo con l'attributo ClassCleanup all'interno di una classe. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: non è possibile definire più di un metodo con l'attributo ClassInitialize all'interno di una classe. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: non è possibile definire più di un metodo con l'attributo TestCleanup. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: non è possibile definire più di un metodo con l'attributo TestInitialize. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: è stato definito l'attributo TestClass per la classe non pubblica {0} + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: non è possibile definire la proprietà predefinita {2} per il metodo {1}. + + + + TestClass attribute defined on generic non-abstract class {0} + Attributo TestClass definito nella classe generica non astratta {0} + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: per il metodo {1} è stata definita una proprietà personalizzata Null o vuota. Specificare un nome valido per la proprietà personalizzata. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + Un'eccezione non gestita è stata generata dal metodo 'Execute'. Segnalare questo errore all'autore dell'attributo '{0}'. +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + L'attributo ExpectedException definito nel metodo di test {0}.{1} ha generato un'eccezione durante la costruzione. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + Non è stato possibile ottenere l'eccezione generata dal metodo di test {0}.{1}. + + + + Initialization method {0}.{1} threw exception. {2}. + Il metodo di inizializzazione {0}.{1} ha generato un'eccezione. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + Non è possibile creare un'istanza della classe {0}. Errore: {1}. + + + + Method {0}.{1} does not exist. + Il metodo {0}.{1} non esiste. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + Il metodo di test '{0}.{1}' contiene più attributi derivati da '{2}' definito in esso. È consentito solo uno di tali attributi. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + Si è verificato un errore durante l'esecuzione del test. L'estensione non ha restituito alcun risultato. Se si usa l'estensione di TestMethodAttribute, contattare il fornitore. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + Impossibile trovare un costruttore valido per la classe di test '{0}'. I costruttori validi sono 'public' e senza parametri o con un parametro di tipo 'TestContext'. + + + + Unable to find property {0}.TestContext. Error:{1}. + La proprietà {0}.TestContext non è stata trovata. Errore: {1}. + + + + Unable to set TestContext property for the class {0}. Error: {1}. + Non è possibile impostare la proprietà TestContext per la classe {0}. Errore: {1}. + + + + The {0}.TestContext has incorrect type. + Il tipo di {0}.TestContext non è corretto. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + La firma del metodo {0}.{1}non è corretta. Il metodo deve essere non statico e pubblico, non deve restituire un valore né accettare parametri. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere 'Task' o 'ValueTask'. + + + + Test method {0}.{1} threw exception: +{2} + Il metodo di test {0}.{1} ha generato un'eccezione: +{2} + + + + Unable to get type {0}. Error: {1}. + Non è possibile ottenere il tipo {0}. Errore: {1}. + + + + The called code threw an exception that was caught, but the exception value was null + Il codice chiamato ha generato un'eccezione che è stata rilevata, ma il valore dell'eccezione è Null + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0}. Se, per i progetti della piattaforma UWP, nel test si usano oggetti dell'interfaccia utente, provare a specificare l'attributo [UITestMethod] invece di [TestMethod] per eseguire il test nel thread di UI. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + Non è stato possibile ottenere il messaggio per un'eccezione di tipo {0} a causa di un'eccezione. + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + 'MSTest.TestAdapter' e 'MSTest.TestFramework' devono avere la stessa versione. Trovato 'MSTest.TestAdapter' versione '{0}' e 'MSTest.TestFramework' versione '{1}'. Assicurarsi che le versioni dei pacchetti NuGet 'MSTest.TestAdapter' e 'MSTest.TestFramework' siano identiche. + + Wrong number of objects for permutation. Should be greater than zero. Il numero di oggetti non è corretto per la permutazione. Deve essere maggiore di zero. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ja.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ja.xlf index 68681a9ea2..59cf4cb86e 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ja.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ja.xlf @@ -2,16 +2,117 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + アセンブリ クリーンアップ メソッド '{0}.{1}' が {2}ms 後にタイムアウトしました + + + + Assembly cleanup method '{0}.{1}' was canceled + アセンブリ クリーンアップ メソッド '{0}.{1}' が取り消されました + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + アセンブリ初期化メソッド '{0}.{1}' が {2}ms 後にタイムアウトになりました + + + + Assembly initialize method '{0}.{1}' was canceled + アセンブリ初期化メソッド '{0}.{1}' が取り消されました + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + "{0}.{1}" で IDataSource 属性を列挙中に例外が発生しました: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + "{0}.{1}" の属性から IDataSource 行を展開中に例外が発生しました: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + "{1}" のインデックス {0} のデータをシリアル化できません。"IDataSource" を介して提供されるすべてのデータはシリアル化可能である必要があります。シリアル化できないデータ ソースをテストする必要がある場合は、テスト アセンブリに "TestDataSourceDiscovery" 属性を追加し、検出オプションを "DuringExecution" に設定してください。 + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + インデックス {0} と {1} の表示名 "{2}" が重複しています。表示名は一意である必要があります。 + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. ファイル '{0}' が見つかりませんでした。 + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + テスト メソッド '{0}.{1}' を実行できません: テスト データがメソッド パラメーターと一致しません。カウントまたは型が異なります。 +型 '{3}'、 + を持つ、予期された {2} パラメーターをテストします +ただし、型 '{5}' の引数 {4} を受け取りました。 + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + テスト メソッド '{0} を実行できません。{1}': メソッドにはパラメーターがありますが、テスト ソースは定義されていません。'[DataRow]'、'[DynamicData]'、カスタムの 'ITestDataSource' データ ソースを使用して、テスト データを提供します。 + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + クラス クリーンアップ メソッド '{0}.{1}' が {2}ms 後にタイムアウトしました + + + + Class cleanup method '{0}.{1}' was canceled + クラス クリーンアップ メソッド '{0}.{1}' が取り消されました + + + + Class initialize method '{0}.{1}' timed out after {2}ms + クラス初期化メソッド '{0}.{1}' が {2}ms 後にタイムアウトになりました + + + + Class initialize method '{0}.{1}' was canceled + クラス初期化メソッド '{0}.{1}' が取り消されました + + The parameter should not be null or empty. パラメーターを null または空にすることはできません。 + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + MSTestAdapter でアセンブリ '{1}' のクラス '{0}' にテストが見つかりませんでした。理由 {2}。 + + + + {0} (Data Row {1}) + {0} (データ行 {1}) + + + + Debug Trace: + デバッグ トレース: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. テストの実行の配置問題です: 配置項目が正しくありません: '{0}': 出力ディレクトリ '{1}' は、項目が配置ルート ディレクトリ外に配置されるように指定していますが、それは許可されません。 @@ -77,16 +178,108 @@ 配置項目 '{0}' (出力ディレクトリ '{1}') + + [MSTest][Discovery][{0}] {1} + [MSTest][Discovery][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + '.runsettings' ファイルと '.testconfig.json' ファイルの両方が検出されました。これらのテスト構成ファイルのいずれか 1 つだけを選択してください。 + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + "{0}": (種類が "{1}"の例外のため、例外の説明を取得できませんでした。 + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + スローされた例外: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + テスト '{0}' が取り消されました + + + + Test '{0}' timed out after {1}ms + テスト '{0}' が {1} ミリ秒後にタイムアウトしました + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + 型 {0} のカスタム属性を取得中に例外がスローされました (無視してリフレクションの方法を使用します): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + ジェネリック パラメーター '{0}' の型を推論できませんでした。 + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + ジェネリック テスト メソッド '{0}' に引数がないため、ジェネリック パラメーターを推論できません。 + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + ジェネリック パラメーター '{0}' に 2 つの競合する型が見つかりました。競合する型は '{1}' および '{2}' です。 + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + 'ClassCleanupLifecycle' に無効な値 '{0}' が指定されました。サポートされているスコープは {1} です。 + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + 無効な値 '{0}' が 'Scope' に指定されました。サポートされているスコープは {1} です。 + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + 無効な値 '{0}' が 'Workers' に指定されました。値は負ではない整数である必要があります。 + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + 設定 '{0}' は無効です。予期しない XmlAttribute: '{1}'。 + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter で設定 '{1}' に予期しない要素 '{0}' が見つかりました。この要素を削除して、もう一度お試しください。 + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + 設定 '{0}' は無効です。予期しない XmlElement: '{1}'。 + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. runsettings エントリ '{1}' の値 '{0}' は無効です。設定は無視されます。 + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + runsettings エントリ '{1}' の値 '{0}' は無効です。設定は無視されます。 + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + 警告: testsettings ファイル、vsmdi ファイルは MSTest V2 アダプターではサポートされていません。 + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} テストの実行の配置問題です: アセンブリまたはモジュール '{0}' が見つかりませんでした。理由: {1} @@ -97,21 +290,309 @@ テストの実行の配置問題です: アセンブリまたはモジュール '{0}' が見つかりませんでした。 + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + 古いバージョンの MSTestV2 パッケージがアセンブリに読み込まれています。`.runsettings` ファイルに依存している場合、テスト検出ですべてのデータ テストを検出できない可能性があります。 + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + Runsettings エントリ '<ExecutionApartmentState>STA</ExecutionApartmentState>' は、Windows OS 以外ではサポートされていません。 + + + + Running tests in any of the provided sources is not supported for the selected platform + 指定されたソースのいずれかでのテストの実行は、選択されたプラットフォームでサポートされていません + + + + Failed to discover tests from assembly {0}. Reason:{1} + アセンブリ {0} からテストを検出できませんでした。理由:{1} + + + + File does not exist: {0} + ファイルが存在しません: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + テスト クリーンアップ メソッド '{0}.{1}' が {2}ms 後にタイムアウトしました + + + + Test cleanup method '{0}.{1}' was canceled + テスト クリーンアップ メソッド '{0}.{1}' が取り消されました + + + + TestContext cannot be Null. + TestContext を Null にすることはできません。 + + + + TestContext Messages: + TestContext メッセージ: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + テスト初期化メソッド '{0}.{1}' が {2}ms 後にタイムアウトになりました + + + + Test initialize method '{0}.{1}' was canceled + テスト初期化メソッド '{0}.{1}' が取り消されました + + + + Test method {0} was not found. + テスト メソッド {0} が見つかりませんでした。 + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + {0} でテスト並列処理が有効にされています (Workers: {1}、Scope: {2})。 + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + テスト ソース '{0}' から型を読み込むことができません。このソース内の一部またはすべてのテストが見つからない可能性があります。 +エラー: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + アセンブリ クリーンアップ メソッド {0}.{1} に失敗しました。エラー メッセージ: {2}。スタック トレース: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + アセンブリ初期化メソッド {0}.{1} は例外をスローしました。{2}: {3}。テストの実行を中止しています。 + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + クラス クリーンアップ メソッド {0}.{1} に失敗しました。エラー メッセージ: {2}。スタック トレース: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + クラス初期化メソッド {0}.{1} は例外をスローしました。{2}: {3}。 + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + メソッド {0}。{1} は不適切なシグネチャを含んでいます。メソッドは static および public である必要があり、値を返しません。また、パラメーターを受け取ることはできません。また、メソッドで async-await を使用している場合、戻り値の型は 'Task' または 'ValueTask' である必要があります。 + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + メソッド {0}。{1} は不適切なシグネチャを含んでいます。メソッドは static および public である必要があり、値を返しません。また、TestContext 型の 1 つのパラメーターを受け取る必要があります。また、メソッドで async-await を使用している場合、戻り値の型は 'Task' または 'ValueTask' である必要があります。 + + + + TestCleanup method {0}.{1} threw exception. {2}. + TestCleanup メソッド {0}.{1} は例外をスローしました。{2}。 + + + + Error calling Test Cleanup method for test class {0}: {1} + テスト クラス {0} のテスト クリーンアップ メソッドの呼び出しでエラーが発生しました: {1} + + + + TestCleanup Stack Trace + TestCleanup スタック トレース + + Data source '{0}' cannot be found in the test configuration settings データ ソース '{0}' がテスト構成の設定に見つかりません + + --- End of inner exception stack trace --- + --- 内部例外スタック トレースの終わり --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} 単体テスト アダプターがデータ ソースに接続できなかったか、データを読み取れませんでした。このエラーのトラブルシューティングの詳細については、MSDN ライブラリの「方法: データ ドリブン単体テストを作成する」(http://go.microsoft.com/fwlink/?LinkId=62412) をご覧ください。エラーの詳細: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: クラス {0} に有効な TestContext プロパティがありません。TestContext は TestContext 型で、非静的である必要があり、public である必要があります。たとえば、public TestContext TestContext です。 + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: クラス {0} で定義されているメソッド {1} に適切なシグネチャが含まれていません。[TestMethod] 属性でマークされたテスト メソッドは、non-static および public である必要があり、戻り値の型は void である必要があります。また、パラメーターを受け取ることはできません。例: public void Test.Class1.Test()。また、テスト メソッドで async-await を使用している場合、戻り値の型は 'Task' または 'ValueTask' である必要があります。例: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}。{1} に無効な Timeout 属性があります。タイムアウトには、0 より大きい整数値を指定する必要があります。 + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: 1 つのアセンブリ内で、AssemblyCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。 + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: 1 つのアセンブリ内で、AssemblyInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。 + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: 1 つのクラス内で、ClassCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。 + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: 1 つのクラス内で、ClassInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。 + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: TestCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。 + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: TestInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。 + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: TestClass 属性がパブリックでないクラス {0} で定義されています + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: メソッド {1} 上の以前に定義されたプロパティ {2} を定義することはできません。 + + + + TestClass attribute defined on generic non-abstract class {0} + 汎用の非抽象クラス {0}で定義された TestClass 属性 + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: Null または空のカスタム プロパティが、メソッド {1} で定義されています。カスタム プロパティには有効な名前を指定しなければなりません。 + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + 'Execute' メソッドによってハンドルされない例外がスローされました。属性 '{0}' の作成者にこのエラーを報告してください。 +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + テスト メソッド {0}.{1} に定義されている ExpectedException 属性が、作成中に例外をスローしました。 +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + テスト メソッド {0}.{1} によってスローされた例外を取得できませんでした。 + + + + Initialization method {0}.{1} threw exception. {2}. + 初期化メソッド {0}.{1} は例外をスローしました。{2}。 + + + + Unable to create instance of class {0}. Error: {1}. + クラス {0} のインスタンスを作成できません。エラー: {1}。 + + + + Method {0}.{1} does not exist. + メソッド {0}.{1} は存在しません。 + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + テスト メソッド '{0}.{1}' には、 '{2}' から派生した属性が複数定義されています。このような属性は 1 つしか許可されません。 + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + テストの実行中にエラーが発生しました。拡張から結果が返されませんでした。TestMethodAttribute の拡張クラスを使用している場合は、ベンダーに連絡してください。 + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + テスト クラス '{0}' の有効なコンストラクターが見つかりません。有効なコンストラクターは、'public' で、パラメーターがないもの、または 'TestContext' 型のパラメーター 1 個を取るものです。 + + + + Unable to find property {0}.TestContext. Error:{1}. + プロパティ {0}.TestContext が見つかりません。エラー: {1}。 + + + + Unable to set TestContext property for the class {0}. Error: {1}. + クラス {0} の TestContext プロパティを設定できません。エラー: {1}。 + + + + The {0}.TestContext has incorrect type. + {0}.TestContext は不適切な型を含んでいます。 + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + メソッド {0}。{1} は不適切なシグネチャを含んでいます。メソッドは non-static および public である必要があり、値を返しません。また、パラメーターを受け取ることはできません。また、メソッドで async-await を使用している場合、戻り値の型は 'Task' または 'ValueTask' である必要があります。 + + + + Test method {0}.{1} threw exception: +{2} + テスト メソッド {0}.{1} が例外をスローしました: +{2} + + + + Unable to get type {0}. Error: {1}. + 型 {0} を取得できません。エラー: {1}。 + + + + The called code threw an exception that was caught, but the exception value was null + 呼び出されたコードはキャッチされた例外をスローしましたが、例外値が null でした + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0} UWP プロジェクトについて、テスト内で UI オブジェクトを使用している場合は、[TestMethod] の代わりに [UITestMethod] 属性を使用して UI スレッド内でテストを実行することを検討してください。 + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (例外が発生したため、型 {0} の例外のメッセージを取得できませんでした。) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + 'MSTest.TestAdapter' と 'MSTest.TestFramework' は同じバージョンである必要があります。'MSTest.TestAdapter' バージョン '{0}' と 'MSTest.TestFramework' バージョン '{1}' が見つかりました。'MSTest.TestAdapter' と 'MSTest.TestFramework' の NuGet パッケージのバージョンが同じであることを確認してください。 + + Wrong number of objects for permutation. Should be greater than zero. 順列のオブジェクト数が正しくありません。ゼロより大きくなければなりません。 diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ko.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ko.xlf index d602b1e260..56084fe47c 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ko.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ko.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + {2}밀리초 후 어셈블리 정리 메서드 '{0}.{1}'이(가) 시간 초과되었습니다. + + + + Assembly cleanup method '{0}.{1}' was canceled + 어셈블리 정리 메서드 '{0}.{1}'이(가) 취소되었습니다. + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + {2}밀리초 후 '{0}.{1}' 어셈블리 초기화 메서드의 시간이 초과되었습니다. + + + + Assembly initialize method '{0}.{1}' was canceled + 어셈블리 초기화 메서드 '{0}.{1}'(이)가 취소되었습니다. + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + "{0}.{1}"에서 IDataSource 특성을 열거하는 동안 예외가 발생했습니다. {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + "{0}.{1}"의 특성에서 IDataSource 행을 확장하는 동안 예외가 발생했습니다. {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + "{1}"에 대한 {0} 인덱스의 데이터를 직렬화할 수 없습니다. "IDataSource"를 통해 제공된 모든 데이터를 직렬화할 수 있어야 합니다. 직렬화할 수 없는 데이터 원본을 테스트해야 하는 경우 테스트 어셈블리에 "TestDataSourceDiscovery" 특성을 추가하고 검색 옵션을 "DuringExecution"으로 설정하세요. + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + {0} 및 {1} 인덱스의 "{2}" 표시 이름이 중복됩니다. 표시 이름은 고유해야 합니다. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. '{0}' 파일을 찾을 수 없습니다. + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + 테스트 메서드 '{0}{1}'을(를) 실행할 수 없음: 테스트 데이터가 메서드 매개 변수와 일치하지 않습니다. 개수 또는 형식이 다릅니다. +테스트에 {2} 매개 변수로 ‘{3}’ 형식이 필요하지만, +{4} 인수의 ‘{5}’ 형식을 받았습니다. + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + 테스트 메서드 '{0}{1}'을(를) 실행할 수 없음: 메서드에 매개 변수가 있지만 테스트 원본을 정의하지 않습니다. '[DataRow]', '[DynamicData]' 또는 사용자 지정 'ITestDataSource' 데이터 원본을 사용하여 테스트 데이터를 제공합니다. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + {2}밀리초 후 클래스 정리 메서드 '{0}.{1}'이(가) 시간 초과되었습니다. + + + + Class cleanup method '{0}.{1}' was canceled + 클래스 정리 메서드 '{0}.{1}'이(가) 취소되었습니다. + + + + Class initialize method '{0}.{1}' timed out after {2}ms + {2}밀리초 후 '{0}.{1}' 클래스 초기화 메서드의 시간이 초과되었습니다. + + + + Class initialize method '{0}.{1}' was canceled + '클래스 초기화 메서드 '{0}.{1}'이(가) 취소되었습니다. + + The parameter should not be null or empty. 매개 변수는 null이거나 비워 둘 수 없습니다. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + MSTestAdapter가 {2} 때문에 어셈블리 '{1}'의 클래스 '{0}'에서 테스트를 검색하지 못했습니다. + + + + {0} (Data Row {1}) + {0}(데이터 행 {1}) + + + + Debug Trace: + 디버그 추적: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. 테스트 실행 배포 문제: 잘못된 배포 항목: '{0}': 출력 디렉터리 '{1}'에서 항목을 배포 루트 디렉터리 외부에 배포하도록 지정하며 이는 허용되지 않습니다. @@ -77,16 +177,108 @@ 배포 항목 '{0}'(출력 디렉터리 '{1}') + + [MSTest][Discovery][{0}] {1} + [MSTest][검색][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + '.runsettings' 및 '.testconfig.json' 파일이 모두 검색되었습니다. 이러한 테스트 구성 파일 중 하나만 선택하세요. + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + "{0}": ("{1}" 형식의 예외로 인해 예외 설명을 가져오지 못했습니다. + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + 예외 발생: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + 테스트 '{0}'이(가) 취소되었습니다. + + + + Test '{0}' timed out after {1}ms + 테스트 '{0}'이(가) {1}밀리초 후에 시간 초과되었습니다. + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + {0} 형식에 대한 사용자 지정 특성을 가져오는 데 예외가 발생했습니다(무시하고 리플렉션 방법 사용). {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + 제네릭 매개 변수 '{0}'의 형식을 유추할 수 없습니다. + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + 제네릭 테스트 메서드 '{0}'에 인수가 없으므로 제네릭 매개 변수를 유추할 수 없습니다. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + 제네릭 매개 변수 '{0}'에 대해 충돌하는 두 가지 형식을 찾았습니다. 충돌하는 형식은 '{1}' 및 ''{2}입니다. + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + 'ClassCleanupLifecycle'에 대해 '{0}' 잘못된 값이 지정되었습니다. 지원되는 범위는 {1}입니다. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + 'Scope'에 대해 잘못된 값 '{0}'이(가) 지정되었습니다. 지원되는 범위는 {1}입니다. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + 'Workers'에 대해 잘못된 값 '{0}'이(가) 지정되었습니다. 이 값은 음수가 아닌 정수여야 합니다. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + '{0}' 설정이 잘못되었습니다. 예기치 않은 XmlAttribute '{1}'이(가) 있습니다. + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter의 '{1}' 설정에서 예기치 않은 요소 '{0}'이(가) 발견되었습니다. 이 요소를 제거하고 다시 시도하세요. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + '{0}' 설정이 잘못되었습니다. 예기치 않은 XmlElement '{1}'이(가) 있습니다. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. runsettings 항목 '{1}'에 대해 '{0}' 값이 잘못되었습니다. 설정은 무시됩니다. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + runsettings 항목 '{1}'에 대해 '{0}' 값이 잘못되었습니다. 설정은 무시됩니다. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + 경고: MSTest V2 어댑터에서는 testsettings 파일 또는 vsmdi 파일이 지원되지 않습니다. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} 테스트 실행 배포 문제: 어셈블리 또는 모듈 '{0}'을(를) 찾을 수 없습니다. 이유: {1} @@ -97,21 +289,309 @@ 테스트 실행 배포 문제: 어셈블리 또는 모듈 '{0}'을(를) 찾을 수 없습니다. + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + 이전 버전 MSTestV2 패키지가 어셈블리에 로드되어 테스트 검색이 '.runsettings' 파일에 종속된 경우 모든 데이터 테스트를 검색하지 못할 수 있습니다. + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + Runsettings 항목 '<ExecutionApartmentState>STA</ExecutionApartmentState>'는 Windows 이외의 OS에서는 지원되지 않습니다. + + + + Running tests in any of the provided sources is not supported for the selected platform + 선택된 플랫폼의 경우 제공된 소스에서 테스트를 실행할 수 없습니다. + + + + Failed to discover tests from assembly {0}. Reason:{1} + 어셈블리 {0}에서 테스트를 검색하지 못했습니다. 이유:{1} + + + + File does not exist: {0} + 파일이 없습니다. {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + {2}밀리초 후 테스트 정리 메서드 '{0}.{1}'이(가) 시간 초과되었습니다. + + + + Test cleanup method '{0}.{1}' was canceled + 테스트 정리 메서드 '{0}.{1}'이(가) 취소되었습니다. + + + + TestContext cannot be Null. + TestContext는 null일 수 없습니다. + + + + TestContext Messages: + TestContext 메시지: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + {2}밀리초 후 '{0}.{1}' 테스트 초기화 메서드의 시간이 초과되었습니다. + + + + Test initialize method '{0}.{1}' was canceled + 테스트 초기화 메서드 '{0}.{1}'이(가) 취소되었습니다. + + + + Test method {0} was not found. + {0} 테스트 메서드를 찾을 수 없습니다. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + {0}에 대해 테스트 병렬 처리를 사용합니다(Workers: {1}, Scope: {2}). + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + 테스트 소스 '{0}'에서 형식을 로드할 수 없습니다. 이 소스의 일부 또는 모든 테스트를 검색할 수 없습니다. +오류: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + 어셈블리 정리 메서드 {0}.{1}이(가) 실패했습니다. 오류 메시지: {2}. StackTrace: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + 어셈블리 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3}. 테스트 실행을 중단합니다. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + 클래스 정리 메서드 {0}.{1}이(가) 실패했습니다. 오류 메시지: {2}. 스택 추적: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + 클래스 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3} + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이고 공용이어야 하며, 값을 반환하거나 매개 변수를 취하지 않습니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 'Task' 또는 'ValueTask'여야 합니다. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 static, public이어야 하고, 값을 반환하지 않으며, TestContext 형식의 단일 매개 변수를 사용해야 합니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 'Task' 또는 'ValueTask'여야 합니다. + + + + TestCleanup method {0}.{1} threw exception. {2}. + TestCleanup 메서드 {0}.{1}에서 예외가 발생했습니다. {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + 테스트 클래스 {0}에 대한 테스트 정리 메서드를 호출하는 오류: {1} + + + + TestCleanup Stack Trace + TestCleanup 스택 추적 + + Data source '{0}' cannot be found in the test configuration settings 테스트 구성 설정에서 데이터 원본 '{0}'을(를) 찾을 수 없습니다. + + --- End of inner exception stack trace --- + --- 내부 예외 스택 추적의 끝 --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} 단위 테스트 어댑터가 데이터 원본에 연결하거나 데이터를 읽지 못했습니다. 이 오류를 해결하는 방법에 대한 자세한 내용은 MSDN 라이브러리에서 "데이터 기반 단위 테스트 문제 해결"(http://go.microsoft.com/fwlink/?LinkId=62412)을 참조하십시오. 오류 세부 정보: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: {0} 클래스에 유효한 TestContext 속성이 없습니다. TestContext는 TestContext 유형이어야 하고, 정적이 아니어야 하며, 일반적이어야 합니다. 예: public TestContext TestContext. + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: 클래스 {0}에 정의된 메서드 {1}에 올바른 서명이 없습니다. [TestMethod] 특성으로 표시된 테스트 메서드는 non-static, public, return-type이 void여야 하며 매개 변수를 사용하지 않아야 합니다. 예: public void Test.Class1.Test(). 또한 테스트 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다. 예: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}.{1}에 잘못된 Timeout 특성이 있습니다. 시간 제한 값은 0보다 큰 정수여야 합니다. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: 어셈블리 내부에서 AssemblyCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: 어셈블리 내부에서 AssemblyInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: 클래스 내부에서 ClassCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: 클래스 내부에서 ClassInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: TestCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: TestInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: public이 아닌 클래스 {0}에서 TestClass 특성을 정의했습니다. + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: {1} 메서드에서 미리 정의된 속성 {2}을(를) 정의할 수 없습니다. + + + + TestClass attribute defined on generic non-abstract class {0} + 일반 비추상 클래스 {0}에 정의된 TestClass 속성 + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: {1} 메서드에서 Null 또는 빈 사용자 지정 속성을 정의했습니다. 사용자 지정 속성에는 올바른 이름이 지정되어 있어야 합니다. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + 'Execute' 메서드에서 처리되지 않은 예외가 발생했습니다. '{0}' 특성의 작성자에게 이 오류를 보고하세요. +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + 테스트 메서드 {0}.{1}에 정의된 ExpectedException 특성이 생성하는 동안 예외를 throw했습니다. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + 테스트 메서드 {0}.{1}에서 throw한 예외를 가져오지 못했습니다. + + + + Initialization method {0}.{1} threw exception. {2}. + 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + {0} 클래스의 인스턴스를 만들 수 없습니다. 오류: {1} + + + + Method {0}.{1} does not exist. + {0}.{1} 메서드가 없습니다. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + 테스트 메서드 '{0}.{1}'에 {2}에서 파생된 여러 특성이 정의되어 있습니다. 이러한 특성은 하나만 허용됩니다. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + 테스트를 실행하는 중에 오류가 발생했습니다. 확장에서 결과가 반환되지 않았습니다. TestMethodAttribute 확장을 사용하는 경우 공급업체에 문의하세요. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + 테스트 클래스 '{0}'에 대한 유효한 생성자를 찾을 수 없습니다. 유효한 생성자는 'public'이며 매개 변수가 없거나 'TestContext' 유형의 매개 변수가 하나 있습니다. + + + + Unable to find property {0}.TestContext. Error:{1}. + {0}.TestContext 속성을 찾을 수 없습니다. 오류: {1} + + + + Unable to set TestContext property for the class {0}. Error: {1}. + {0} 클래스에 대해 TestContext 속성을 설정할 수 없습니다. 오류: {1} + + + + The {0}.TestContext has incorrect type. + {0}.TestContext의 형식이 잘못되었습니다. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이 아니고 공용이어야 하며, 값을 반환하거나 매개 변수를 사용할 수 없습니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 'Task' 또는 'ValueTask'여야 합니다. + + + + Test method {0}.{1} threw exception: +{2} + 테스트 메서드 {0}.{1}에서 예외를 throw했습니다. +{2} + + + + Unable to get type {0}. Error: {1}. + {0} 형식을 가져올 수 없습니다. 오류: {1} + + + + The called code threw an exception that was caught, but the exception value was null + 호출된 코드에서 확인된 예외가 발생했지만 예외 값이 null입니다. + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0} UWP 프로젝트의 경우 테스트에서 UI 개체를 사용 중이면 [TestMethod] 대신 [UITestMethod] 특성을 사용하여 UI 스레드에서 테스트를 실행하세요. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (예외로 인해 {0} 형식의 예외에 대한 메시지를 가져오지 못했습니다.) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + 'MSTest.TestAdapter'와 'MSTest.TestFramework'의 버전이 같아야 합니다. 'MSTest.TestAdapter'의 버전은 '{0}'이고, 'MSTest.TestFramework'의 버전은 '{1}'입니다. 'MSTest.TestAdapter'와 'MSTest.TestFramework' NuGet 패키지의 버전이 동일한지 확인하세요. + + Wrong number of objects for permutation. Should be greater than zero. 순열의 개체 수가 잘못되었습니다. 개체 수는 0보다 커야 합니다. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.pl.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.pl.xlf index 56730517f6..ab1778d736 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.pl.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.pl.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + Metoda oczyszczania zestawu „{0}.{1}” przekroczyła limit czasu po {2}ms + + + + Assembly cleanup method '{0}.{1}' was canceled + Anulowano metodę oczyszczania zestawu „{0}.{1}” + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + Metoda inicjalizacji zestawu „{0}.{1}” przekroczyła limit czasu po {2}ms + + + + Assembly initialize method '{0}.{1}' was canceled + Anulowano metodę inicjowania zestawu „{0}.{1}” + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + Wystąpił wyjątek podczas wyliczania atrybutu IDataSource w przestrzeni nazwy „{0}.{1}”: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + Wystąpił wyjątek podczas rozwijania wierszy IDataSource z atrybutu w przestrzeni nazw „{0}.{1}”: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + Nie można serializować danych w indeksie {0} dla „{1}”. Wszystkie dane dostarczane za pomocą źródła „IDataSource” powinny być możliwe do serializacji. Jeśli chcesz przetestować nieserializowalne źródła danych, upewnij się, że dodasz atrybut „ TestDataSourceDiscovery” w zestawie testowym i ustaw opcję odnajdywania na wartość „DuringExecution”. + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + Nazwa wyświetlana „{2}” w indeksach {0} i {1} jest duplikatem. Nazwy wyświetlane powinny być unikatowe. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. Nie można odnaleźć pliku „{0}”. + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + Nie można uruchomić metody testowej „{0}.{1}”: dane testowe nie są zgodne z parametrami metody. Liczba lub typy są różne. +Testowanie oczekiwał parametrów {2} z typami „{3}”, +ale odebrał argumenty {4} z typami „{5}”. + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + Nie można uruchomić metody testowej „{0}.{1}”: metoda ma parametry, ale nie definiuje żadnego źródła testowego. Użyj źródła danych „[DataRow]”, „[DynamicData]” lub niestandardowego źródła danych „ITestDataSource”, aby dostarczyć dane testowe. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + Metoda oczyszczania klasy „{0}.{1}” przekroczyła limit czasu po {2}ms + + + + Class cleanup method '{0}.{1}' was canceled + Anulowano metodę oczyszczania klasy „{0}.{1}” + + + + Class initialize method '{0}.{1}' timed out after {2}ms + Metoda inicjalizacji klasy „{0}.{1}” przekroczyła limit czasu po {2}ms + + + + Class initialize method '{0}.{1}' was canceled + Anulowano metodę inicjowania klasy „{0}.{1}” + + The parameter should not be null or empty. Parametr nie może mieć wartości null ani być pusty. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + Adapter MSTestAdapter nie mógł odnaleźć testów w klasie „{0}” zestawu „{1}”, przyczyna: {2}. + + + + {0} (Data Row {1}) + {0} (wiersz danych {1}) + + + + Debug Trace: + Ślad debugowania: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. Problem wdrażania przebiegu testu: nieprawidłowy element wdrożenia: „{0}”: katalog wyjściowy „{1}” określa element do wdrożenia poza głównym katalogiem wdrożenia. Taka sytuacja jest niedozwolona. @@ -77,16 +177,108 @@ element wdrożenia „{0}” (katalog wyjściowy „{1}”) + + [MSTest][Discovery][{0}] {1} + [MSTest][Discovery][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + Wykryto zarówno pliki „.runsettings”, jak i „.testconfig.json”. Wybierz tylko jeden z tych plików konfiguracji testu. + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + „{0}”: (Nie można uzyskać opisu wyjątku z powodu wyjątku typu „{1}”. + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + Zgłoszone wyjątki: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + Test „{0}” został anulowany + + + + Test '{0}' timed out after {1}ms + Upłynął limit czasu testu „{0}” po {1}ms + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + Pobieranie atrybutów niestandardowych dla typu {0} zgłosiło wyjątek (zignoruje i użyje sposobu odbicia): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + Nie można wywnioskować typu parametru ogólnego „{0}”. + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + Ogólna metoda testowa „{0}” nie ma argumentów, więc nie można wywnioskować parametru ogólnego. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + Znaleziono dwa typy powodujące konflikt dla parametru ogólnego „{0}”. Typy powodujące konflikt to „{1}” i „{2}”. + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + Dla ustawienia „ClassCleanupLifecycle” określono nieprawidłową wartość „{0}”. Obsługiwane zakresy to {1}. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + Określono nieprawidłową wartość „{0}” dla właściwości „Scope”. Obsługiwane zakresy to {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + Określono nieprawidłową wartość „{0}” dla właściwości „Workers”. Wartość musi być nieujemną liczbą całkowitą. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + Nieprawidłowe ustawienia „{0}”. Nieoczekiwany atrybut XmlAttribute: „{1}”. + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. Adapter MSTestAdapter napotkał nieoczekiwany element „{0}” w ustawieniach „{1}”. Usuń ten element i spróbuj ponownie. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + Nieprawidłowe ustawienia „{0}”. Nieoczekiwany atrybut XmlElement: „{1}”. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. Nieprawidłowa wartość „{0}” dla wpisu runsettings „{1}”. Ustawienie zostanie zignorowane. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + Nieprawidłowa wartość „{0}” dla wpisu runsettings „{1}”. Ustawienie zostanie zignorowane. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + Ostrzeżenie: Plik testsettings lub plik vsmdi nie jest obsługiwany przez adapter MSTest w wersji 2. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} Problem wdrażania przebiegu testu: nie znaleziono zestawu lub modułu „{0}”. Przyczyna: {1} @@ -97,21 +289,309 @@ Problem wdrażania przebiegu testu: nie znaleziono zestawu lub modułu „{0}”. + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + Starsza wersja pakietu MSTestV2 jest załadowana do zestawu. Odnajdywanie testów może nie odnaleźć wszystkich testów danych, jeśli zależą od pliku „.runsettings”. + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + Wpis runsettings „<ExecutionApartmentState>STA</ExecutionApartmentState>” nie jest obsługiwany w systemach operacyjnych innych niż Windows. + + + + Running tests in any of the provided sources is not supported for the selected platform + Uruchamianie testów w żadnym z podanych źródeł nie jest obsługiwane dla wybranej platformy + + + + Failed to discover tests from assembly {0}. Reason:{1} + Nie można odnaleźć testów z zestawu {0}. Przyczyna:{1} + + + + File does not exist: {0} + Plik nie istnieje: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + Metoda oczyszczania testu „{0}.{1}” przekroczyła limit czasu po {2}ms + + + + Test cleanup method '{0}.{1}' was canceled + Anulowano metodę oczyszczania testu „{0}.{1}” + + + + TestContext cannot be Null. + Wartość TestContext nie może być równa null. + + + + TestContext Messages: + Komunikaty TestContext: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + Metoda inicjalizacji testu „{0}.{1}” przekroczyła limit czasu po {2}ms + + + + Test initialize method '{0}.{1}' was canceled + Anulowano metodę inicjowania testu „{0}.{1}” + + + + Test method {0} was not found. + Nie znaleziono metody testowej {0}. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + Przetwarzanie równoległe testów włączono dla {0} (procesy robocze: {1}, zakres: {2}) + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + Nie można załadować typów ze źródła testów „{0}”. Niektóre lub wszystkie testy w tym źródle mogły nie zostać odnalezione. +Błąd: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + Metoda czyszczenia zestawu {0}.{1} nie powiodła się. Komunikat o błędzie: {2}. Ślad stosu: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + Metoda inicjująca zestaw {0}.{1} nie powiodła się. {2}: {3}. Przerywanie wykonywania testu. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + Metoda czyszczenia klasy {0}.{1} nie powiodła się. Komunikat o błędzie: {2}. Ślad stosu: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + Metoda inicjowania klasy {0}.{1} zgłosiła wyjątek. {2}: {3}. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Metoda {0}.{1}ma nieprawidłową sygnaturę. Metoda musi być statyczna, publiczna, nie może zwracać wartości i nie powinna przyjmować żadnego parametru. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, wtedy zwracanym typem musi być typ „Task” lub „ValueTask”. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Metoda {0}.{1}ma nieprawidłową sygnaturę. Metoda musi być statyczna, publiczna, nie może zwracać wartości i powinna mieć jeden parametr typu TestContext. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, wtedy zwracanym typem musi być typ „Task” lub „ValueTask”. + + + + TestCleanup method {0}.{1} threw exception. {2}. + Metoda TestCleanup {0}.{1} zgłosiła wyjątek {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + Błąd podczas wywoływania metody czyszczącej testu dla klasy testowej {0}: {1} + + + + TestCleanup Stack Trace + Ślad stosu dla TestCleanup + + Data source '{0}' cannot be found in the test configuration settings W ustawieniach konfiguracji testu nie można znaleźć źródła danych „{0}” + + --- End of inner exception stack trace --- + --- Koniec śledzenia stosu wyjątku wewnętrznego --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} Adapter testu jednostkowego nie mógł połączyć się ze źródłem danych lub odczytać danych. Aby uzyskać więcej informacji o rozwiązywaniu tego błędu, zobacz „Rozwiązywanie problemów z testami jednostkowymi sterowanymi danymi” (http://go.microsoft.com/fwlink/?LinkId=62412) w bibliotece MSDN. Szczegóły błędu: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: Klasa {0}nie ma prawidłowej właściwości TestContext. Element TestContext musi być typu TestContext, musi być niestatyczny i musi być publiczny. Na przykład : public TestContext TestContext. + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: metoda {1} zdefiniowana w klasie {0}nie ma poprawnej sygnatury. Metoda testowa oznaczona przez atrybut [TestMethod] musi być niestatyczna, publiczna, zwracać wartość typu void i nie powinna przyjmować żadnego parametru. Przykład: public void Test.Class1.Test(). Ponadto, jeśli używasz oczekiwanie asynchroniczne w metodzie testowej, wtedy zwracanym typem musi być „Task” lub „ValueTask”. Przykład: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}.{1} ma nieprawidłowy atrybut Timeout. Limit czasu musi być liczbą całkowitą większą niż 0. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: W zestawie nie można zdefiniować więcej niż jednej metody z atrybutem AssemblyCleanup. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: W zestawie nie można zdefiniować więcej niż jednej metody z atrybutem AssemblyInitialize. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: W klasie nie można zdefiniować więcej niż jednej metody z atrybutem ClassCleanup. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: W klasie nie można zdefiniować więcej niż jednej metody z atrybutem ClassInitialize. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: Nie można zdefiniować więcej niż jednej metody z atrybutem TestCleanup. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: Nie można zdefiniować więcej niż jednej metody z atrybutem TestInitialize. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: Atrybut TestClass zdefiniowany dla niepublicznej klasy {0} + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: Nie można zdefiniować wstępnie zdefiniowanej właściwości {2} dla metody {1}. + + + + TestClass attribute defined on generic non-abstract class {0} + Atrybut TestClass zdefiniowany w ogólnej klasie nieabstrakcyjnej {0} + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: Zerowa lub pusta niestandardowa właściwość została zdefiniowana dla metody {1}. Niestandardowa właściwość musi mieć prawidłową nazwę. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + Metoda „Execute” zgłosiła nieobsługiwany wyjątek. Zgłoś ten błąd autorowi atrybutu „{0}”. +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + Atrybut ExpectedException zdefiniowany dla metody testowej {0}.{1} zgłosił wyjątek w trakcie konstruowania. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + Nie powiodło się uzyskanie wyjątku zgłoszonego przez metodę testową {0}.{1}. + + + + Initialization method {0}.{1} threw exception. {2}. + Metoda inicjowania {0}.{1} zgłosiła wyjątek. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + Nie można utworzyć wystąpienia klasy {0}. Błąd: {1}. + + + + Method {0}.{1} does not exist. + Metoda {0}.{1} nie istnieje. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + Metoda testowa "{0}.{1}” ma zdefiniowanych wiele atrybutów pochodzących z „{2}”. Dozwolony jest tylko jeden taki atrybut. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + Błąd podczas wykonywania testu. Rozszerzenie nie zwróciło żadnego wyniku. W przypadku korzystania z rozszerzenia atrybutu TestMethodAttribute należy skontaktować się z dostawcą. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + Nie można odnaleźć prawidłowego konstruktora dla klasy testowej „{0}”. Prawidłowe konstruktory są „publiczne” i albo bez parametrów, albo z jednym parametrem typu „TestContext”. + + + + Unable to find property {0}.TestContext. Error:{1}. + Nie można znaleźć właściwości {0}.TestContext. Błąd:{1}. + + + + Unable to set TestContext property for the class {0}. Error: {1}. + Nie można ustawić właściwości TestContext w klasie {0}. Błąd: {1}. + + + + The {0}.TestContext has incorrect type. + Element {0}.TestContext ma niepoprawny typ. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Metoda {0}.{1}ma nieprawidłową sygnaturę. Metoda musi być niestatyczna, publiczna, nie może zwracać wartości i nie powinna przyjmować żadnego parametru. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, wtedy zwracanym typem musi być typ „Task” lub „ValueTask”. + + + + Test method {0}.{1} threw exception: +{2} + Metoda testowa {0}.{1} zgłosiła wyjątek: +{2} + + + + Unable to get type {0}. Error: {1}. + Nie można uzyskać typu {0}. Błąd: {1}. + + + + The called code threw an exception that was caught, but the exception value was null + Wywołany kod zgłosił wyjątek, który został przechwycony, ale wartość wyjątku miała wartość null + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0} Jeśli w projektach UWP korzystasz z obiektów interfejsu użytkownika podczas testowania, rozważ użycie atrybutu [UITestMethod] zamiast atrybutu [TestMethod], aby wykonywać test w wątku interfejsu użytkownika. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (Nie można pobrać komunikatu dotyczącego wyjątku typu {0} z powodu wyjątku). + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + Elementy „MSTest.TestAdapter” i „MSTest.TestFramework” muszą mieć tę samą wersję. Znaleziono element „MSTest.TestAdapter” w wersji „{0}” i element „MSTest.TestFramework” w wersji „{1}”. Upewnij się, że wersje pakietów NuGet „MSTest.TestAdapter” i „MSTest.TestFramework” mają tę samą wersję. + + Wrong number of objects for permutation. Should be greater than zero. Nieprawidłowa liczba obiektów permutacji. Ta liczba powinna być większa od zera. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.pt-BR.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.pt-BR.xlf index 613c27c07d..352c0d1f34 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.pt-BR.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.pt-BR.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + O método de limpeza da montagem '{0}.{1}' atingiu o tempo limite após {2}ms + + + + Assembly cleanup method '{0}.{1}' was canceled + O método de limpeza do assembly "{0}.{1}" foi cancelado + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + O método de inicialização da montagem '{0}.{1}' atingiu o tempo limite após {2}ms + + + + Assembly initialize method '{0}.{1}' was canceled + O método de inicialização do assembly "{0}.{1}" foi cancelado + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + Ocorreu uma exceção ao enumerar o atributo IDataSource em "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + Ocorreu uma exceção ao expandir as linhas IDataSource do atributo em "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + Os dados no índice {0} para "{1}" não podem ser serializados. Todos os dados fornecidos por meio de "IDataSource" devem ser serializáveis. Se você precisar testar fontes de dados não serializáveis, certifique-se de adicionar o atributo "TestDataSourceDiscovery" em seu assembly de teste e defina a opção de descoberta como "DuringExecution". + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + O nome de exibição "{2}" nos índices {0} e {1} são duplicados. Os nomes de exibição devem ser exclusivos. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. Não foi possível encontrar o arquivo '{0}'. + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + Não é possível executar o método de teste '{0}.{1}': Os dados de teste não correspondem aos parâmetros do método. A contagem ou os tipos são diferentes. +Testar {2} parâmetros esperados, com tipos '{3}', +mas {4} argumentos recebidos, com tipos '{5}'. + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + Não é possível executar o método de teste '{0}.{1}': o método tem parâmetros, mas não define nenhuma fonte de teste. Use '[DataRow]', '[DynamicData]' ou uma fonte de dados 'ITestDataSource' personalizada para fornecer dados de teste. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + O método de limpeza da classe '{0}.{1}' atingiu o tempo limite após {2}ms + + + + Class cleanup method '{0}.{1}' was canceled + O método de limpeza de classe "{0}.{1}" foi cancelado + + + + Class initialize method '{0}.{1}' timed out after {2}ms + O método de inicialização da classe '{0}.{1}' atingiu o tempo limite após {2}ms + + + + Class initialize method '{0}.{1}' was canceled + O método de inicialização de classe "{0}.{1}" foi cancelado + + The parameter should not be null or empty. O parâmetro não deve ser nulo ou vazio. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + O MSTestAdapter não conseguiu descobrir testes na classe '{0}' do assembly '{1}' devido a {2}. + + + + {0} (Data Row {1}) + {0} (Linha de Dados {1}) + + + + Debug Trace: + Rastreamento de Depuração: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. Problema de implantação de Execução de Teste: item de implantação inválido: '{0}': o diretório de saída '{1}' especifica o item a ser implantado fora do diretório raiz de implantação, o que não é permitido. @@ -77,16 +177,108 @@ item de implantação '{0}' (diretório de saída '{1}') + + [MSTest][Discovery][{0}] {1} + [MSTest][Descoberta][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + Ambos os arquivos '.runsettings' e '.testconfig.json' foram detectados. Selecione apenas um desses arquivos de configuração de teste. + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + "{0}": (Falha ao obter a descrição da exceção devido a uma exceção do tipo "{1}". + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + Exceções lançadas: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + O teste "{0}" foi cancelado + + + + Test '{0}' timed out after {1}ms + O teste "{0}" atingiu o tempo limite após {1}ms + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + A obtenção de atributos personalizados para o tipo {0} gerou uma exceção (irá ignorar e usar o modo de reflexão): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + O tipo do parâmetro genérico "{0}" não pôde ser inferido. + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + O método de teste genérico "{0}" não tem argumentos; portanto, o parâmetro genérico não pode ser inferido. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + Foram encontrados dois tipos conflitantes para o parâmetro genérico "{0}". Os tipos conflitantes são "{1}" e "{2}". + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + Valor inválido '{0}' especificado para 'ClassCleanupLifecycle'. Os escopos suportados são {1}. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + Valor inválido '{0}' especificado para 'Scope'. Os escopos compatíveis são {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + Valor inválido '{0}' especificado para 'Workers'. O valor deve ser um inteiro não negativo. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + Configurações inválidas '{0}'. XmlAttribute inesperado: '{1}'. + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter encontrou um elemento inesperado '{0}' em suas configurações '{1}'. Remova este elemento e tente novamente. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + Configurações inválidas '{0}'. XmlElement inesperado: '{1}'. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. Valor inválido "{0}" para a entrada runsettings "{1}", a configuração será ignorada. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + Valor inválido "{0}" para a entrada runsettings "{1}", a configuração será ignorada. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + Aviso: um arquivo testsettings ou um arquivo vsmdi não tem suporte no MSTest V2 Adapter. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} Problema de implantação de Execução de Teste: o assembly ou módulo '{0}' não foi encontrado. Motivo: {1} @@ -97,21 +289,309 @@ Problema de implantação de Execução de Teste: o assembly ou módulo '{0}' não foi encontrado. + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + Uma versão mais antiga do pacote MSTestV2 é carregada no assembly, a descoberta de teste pode falhar ao descobrir todos os testes de dados se eles dependerem do arquivo `.runsettings`. + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + Não há suporte para a entrada runsettings "<ExecutionApartmentState>STA</ExecutionApartmentState>" em sistemas operacionais que não sejam Windows. + + + + Running tests in any of the provided sources is not supported for the selected platform + Não há suporte para execução de teste em qualquer uma das origens fontes fornecidas para a plataforma selecionada + + + + Failed to discover tests from assembly {0}. Reason:{1} + Falha ao descobrir testes por meio do assembly {0}. Motivo: {1} + + + + File does not exist: {0} + O arquivo não existe: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + O método de limpeza do teste '{0}.{1}' atingiu o tempo limite após {2}ms + + + + Test cleanup method '{0}.{1}' was canceled + O método de limpeza de teste "{0}.{1}" foi cancelado + + + + TestContext cannot be Null. + TestContext não pode ser Nulo. + + + + TestContext Messages: + Mensagens TestContext: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + O método de inicialização do teste '{0}.{1}' atingiu o tempo limite após {2}ms + + + + Test initialize method '{0}.{1}' was canceled + O método de inicialização de teste "{0}.{1}" foi cancelado + + + + Test method {0} was not found. + O método de teste {0} não foi encontrado. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + Paralelização de Teste habilitada para {0} (Trabalhos: {1}, Escopo: {2}) + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + Não é possível carregar tipos da fonte de teste '{0}'. Alguns ou todos os testes nessa fonte podem não ser descobertos. +Erro: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + Falha no método de Limpeza de Assembly {0}.{1}. Mensagem de Erro: {2}. StackTrace: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + O método de Inicialização de Assembly {0}.{1} lançou uma exceção. {2}: {3}. Anulando execução de teste. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + Falha no método de Limpeza de Classe {0}.{1}. Mensagem de Erro: {2}. Rastreamento de Pilha: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + O método de Inicialização de Classe {0}.{1} lançou uma exceção. {2}: {3}. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + O método {0}.{1} tem a assinatura incorreta. O método deve ser estático, público, não deve retornar um valor nem receber parâmetro. Além disso, se você estiver usando async-await no método, o return-type deverá ser "Task" ou "ValueTask". + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + O método {0}.{1} tem a assinatura incorreta. O método deve ser estático, público, não retornar um valor e deve usar um único parâmetro do tipo TestContext. Além disso, se você estiver usando async-await no método, o return-type deverá ser "Task" ou "ValueTask". + + + + TestCleanup method {0}.{1} threw exception. {2}. + O método TestCleanup {0}.{1} gerou a exceção. {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + Erro ao chamar o método Test Cleanup para a classe de teste {0}: {1} + + + + TestCleanup Stack Trace + Rastreamento de pilha TestCleanup + + Data source '{0}' cannot be found in the test configuration settings A fonte de dados '{0}' não pode ser encontrada nas configurações de teste + + --- End of inner exception stack trace --- + --- Fim do rastreamento de pilha de exceção interna --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} O adaptador de teste de unidade falhou ao conectar-se à fonte de dados ou ao ler os dados. Para obter mais informações sobre como solucionar esse erro, consulte "Solucionando Problemas em Testes de Unidade Controlados por Dados" (http://go.microsoft.com/fwlink/?LinkId=62412) na Biblioteca do MSDN. Detalhes do erro: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: a classe {0} não tem uma propriedade TestContext válida. TestContext deve ser do tipo TestContext, não deve ser estático e deve ser público. Por exemplo: public TestContext TestContext. + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: o método {1} definido na classe {0} não tem a assinatura correta. O método de teste marcado com o atributo [TestMethod] deve ser não estático, público, com tipo de retorno nulo e não deve receber parâmetros. Exemplo: Test.Class1.Test() público nulo. Além disso, se você estiver usando async-await no método de teste, return-type deverá ser "Task" ou "ValueTask". Exemplo: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}.{1} tem atributo Timeout inválido. O tempo limite deve ser um valor inteiro maior que 0. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: não é possível definir mais de um método com o atributo AssemblyCleanup em um assembly. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: não é possível definir mais de um método com o atributo AssemblyInitialize dentro de um assembly. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: não é possível definir mais de um método com o atributo ClassCleanup dentro de uma classe. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: não é possível definir mais de um método com o atributo ClassInitialize em uma classe. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: não é possível definir mais de um método com o atributo TestCleanup. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: não é possível definir mais de um método com o atributo TestInitialize. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: atributo TestClass definido em classe não pública {0} + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: não é possível definir a propriedade predefinida {2} no método {1}. + + + + TestClass attribute defined on generic non-abstract class {0} + Atributo TestClass definido em uma classe genérica não abstrata {0} + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: Propriedade personalizada nula ou vazia definida no método {1}. A propriedade personalizada deve ter um nome válido. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + Uma exceção sem tratamento foi lançada pelo método "Execute". Relate esse erro ao autor do atributo "{0}". +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + O atributo ExpectedException definido no método de teste {0}.{1} emitiu uma exceção durante a construção. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + Falha ao obter a exceção lançada pelo método de teste {0}.{1}. + + + + Initialization method {0}.{1} threw exception. {2}. + O método de inicialização {0}.{1} gerou exceção. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + Não é possível criar instância da classe {0}. Erro: {1}. + + + + Method {0}.{1} does not exist. + O método {0}.{1} não existe. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + O método de teste '{0}.{1}' tem várias características derivadas de '{2}' definidas nele. Apenas uma dessas características tem permissão. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + Erro ao executar o teste. Nenhum resultado retornado pela extensão. Se usar a extensão de TestMethodAttribute, entre em contato com o fornecedor. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + Não é possível localizar um construtor válido para a classe de teste '{0}'. Construtores válidos são 'public' e sem parâmetros ou com um parâmetro do tipo 'TestContext'. + + + + Unable to find property {0}.TestContext. Error:{1}. + Não é possível encontrar propriedade {0}.TestContext. Erro:{1}. + + + + Unable to set TestContext property for the class {0}. Error: {1}. + Não é definir a propriedade TestContext para a classe {0}. Erro: {1}. + + + + The {0}.TestContext has incorrect type. + O {0}.TestContext é do tipo incorreto. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + O método {0}.{1} tem a assinatura incorreta. O método deve ser não estático, público, não deve retornar um valor e não deve receber nenhum parâmetro. Além disso, se você estiver usando async-await no método, o return-type deverá ser "Task" ou "ValueTask". + + + + Test method {0}.{1} threw exception: +{2} + O método de teste {0}.{1} lançou a exceção: +{2} + + + + Unable to get type {0}. Error: {1}. + Não é possível obter o tipo {0}. Erro: {1}. + + + + The called code threw an exception that was caught, but the exception value was null + O código chamado lançou uma exceção que foi capturada, mas o valor da exceção era nulo + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0} Para projetos UWP, se você está usando objetos de IU no teste, considere usar o atributo [UITestMethod] em vez de [TestMethod] para executar o teste no thread da IU. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (Falha ao obter a mensagem para uma exceção do tipo {0} devido a uma exceção.) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + 'MSTest.TestAdapter' e 'MSTest.TestFramework' devem ter a mesma versão. Encontrada a versão '{0}' do 'MSTest.TestAdapter' e a versão '{1}' do 'MSTest.TestFramework'. Por favor, verifique se as versões dos pacotes NuGet 'MSTest.TestAdapter' e 'MSTest.TestFramework' são iguais. + + Wrong number of objects for permutation. Should be greater than zero. Número incorreto de objetos para permutação. Deve ser maior que zero. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ru.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ru.xlf index adadbea84e..6fd7005d92 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ru.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.ru.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + Время ожидания метода очистки сборки "{0}.{1}" истекло через {2} мс + + + + Assembly cleanup method '{0}.{1}' was canceled + Метод очистки сборки "{0}.{1}" отменен + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + Время ожидания метода инициализации сборки "{0}.{1}" истекло через {2} мс + + + + Assembly initialize method '{0}.{1}' was canceled + Метод инициализации сборки "{0}.{1}" отменен + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + Возникло исключение при перечислении атрибута IDataSource в "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + Возникло исключение при развертывании строк IDataSource из атрибута "{0}.{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + Не удается сериализовать данные в индексе {0} для "{1}". Все данные, предоставленные через IDataSource, должны быть сериализуемыми. Если необходимо протестировать несериализуемые источники данных, добавьте атрибут "TestDataSourceDiscovery" в тестовую сборку и установите для параметра обнаружения значение "DuringExecution". + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + Отображаемые имена "{2}" в индексах {0} и {1} дублируются. Отображаемые имена должны быть уникальными. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. Не удалось найти файл "{0}". + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + Не удается запустить метод теста "{0}.{1}": тестовые данные не соответствуют параметрам метода. Не совпадают количество или типы. +Для теста ожидается следующее количество параметров: {2} типов "{3}", +но число полученных аргументов — {4} и они принадлежат к типам "{5}". + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + Не удается запустить метод теста "{0}.{1}": метод имеет параметры, но не определяет источник теста. Используйте "[DataRow]", "[DynamicData]" или настраиваемый источник данных "ITestDataSource" для предоставления тестовых данных. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + Время ожидания метода очистки класса "{0}.{1}" истекло через {2} мс + + + + Class cleanup method '{0}.{1}' was canceled + Метод очистки класса "{0}.{1}" отменен + + + + Class initialize method '{0}.{1}' timed out after {2}ms + Время ожидания метода инициализации класса "{0}.{1}" истекло через {2} мс + + + + Class initialize method '{0}.{1}' was canceled + Метод инициализации класса "{0}.{1}" отменен + + The parameter should not be null or empty. Этот параметр не должен быть пустым или иметь значение NULL. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + Средству MSTestAdapter не удалось обнаружить тесты в классе "{0}" сборки "{1}", так как {2}. + + + + {0} (Data Row {1}) + {0} (строка данных {1}) + + + + Debug Trace: + Трассировка отладки: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. Ошибка развертывания при тестовом запуске: недопустимый элемент развертывания "{0}". В выходном каталоге "{1}" указано, что развертывание этого элемента должно быть выполнено не в корневом каталоге развертывания, что запрещено. @@ -77,16 +177,108 @@ элемент развертывания "{0}" (выходной каталог "{1}") + + [MSTest][Discovery][{0}] {1} + [MSTest][Discovery][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + Обнаружены одновременно файлы ".runsettings" и ".testconfig.json". Выберите только один из этих файлов тестовой конфигурации. + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + "{0}": (Не удалось получить описание исключения из-за исключения типа "{1}". + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + Выданные исключения: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + Тест "{0}" был отменен + + + + Test '{0}' timed out after {1}ms + Время ожидания теста "{0}" истекло через {1} мс + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + При получении настраиваемых атрибутов для типа {0} возникло исключение (оно будет проигнорировано и будет использовано отражение): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + Не удалось определить тип универсального параметра "{0}". + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + Универсальный метод "{0}" не имеет аргументов, поэтому невозможно вывести универсальный параметр. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + Обнаружены два конфликтующих типа для универсального параметра "{0}". Конфликтующие типы: "{1}" и "{2}". + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + Для параметра "ClassCleanupLifecycle" указано недопустимое значение "{0}". Поддерживаемые области: {1}. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + В поле "Область" указано недопустимое значение "{0}". Поддерживаемые области: {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + В поле "Рабочие роли" указано недопустимое значение "{0}". Оно должно быть неотрицательным целым числом. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + Недопустимые параметры "{0}". Непредвиденный атрибут XmlAttribute: "{1}". + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter обнаружил непредвиденный элемент "{0}" в параметрах "{1}". Удалите этот элемент и повторите попытку. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + Недопустимые параметры "{0}". Непредвиденный элемент XmlElement: "{1}". + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. Недопустимое значение "{0}" для записи runsettings "{1}", параметр будет пропущен. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + Недопустимое значение "{0}" для записи runsettings "{1}", параметр будет пропущен. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + Внимание! Адаптер MSTest версии 2 не поддерживает файл TESTSETTINGS или VSMDI. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} Ошибка развертывания тестового запуска: не удалось найти сборку или модуль "{0}". Причина: {1} @@ -97,21 +289,309 @@ Ошибка развертывания тестового запуска: не удалось найти сборку или модуль "{0}". + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + В сборку загружена старая версия пакета MSTestV2. При обнаружении тестов могут быть обнаружены не все тесты данных, если они зависят от файла ".runsettings". + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + Запись Runsettings "<ExecutionApartmentState>STA</ExecutionApartmentState>" не поддерживается в ОС, отличных от Windows. + + + + Running tests in any of the provided sources is not supported for the selected platform + Запуск тестов в любом из предоставленных источников не поддерживается на выбранной платформе + + + + Failed to discover tests from assembly {0}. Reason:{1} + Не удалось обнаружить тесты из сборки {0}. Причина:{1} + + + + File does not exist: {0} + Файл не существует: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + Время ожидания метода очистки теста "{0}.{1}" истекло через {2} мс + + + + Test cleanup method '{0}.{1}' was canceled + Метод очистки теста "{0}.{1}" отменен + + + + TestContext cannot be Null. + TestContext не может иметь значение NULL. + + + + TestContext Messages: + Сообщения TestContext: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + Время ожидания метода инициализации теста "{0}.{1}" истекло через {2} мс + + + + Test initialize method '{0}.{1}' was canceled + Метод инициализации теста "{0}.{1}" отменен + + + + Test method {0} was not found. + Метод теста {0} не найден. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + Включена параллелизация тестов для {0} (рабочие роли: {1}, область: {2}) + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + Не удалось загрузить типы из тестового источника "{0}". В этом источнике могут быть не обнаружены некоторые или все тесты. +Ошибка: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + Не удалось применить метод очистки сборки {0}.{1}. Сообщение об ошибке: {2}. Трассировка стека (StackTrace): {3}. + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + Методом инициализации сборки {0}.{1} создано исключение. {2}: {3}. Выполнение теста прекращается. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + Не удалось применить метод очистки класса {0}.{1}. Сообщение об ошибке: {2}. Трассировка стека: {3}. + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + Методом инициализации класса {0}.{1} создано исключение. {2}: {3}. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть статическим и открытым, не должен возвращать значение и принимать параметры. Кроме того, при использовании async-await в методе возвращаемое значение должно иметь тип "Task" или "ValueTask". + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть статическим и открытым, не должен возвращать значение и должен принимать один параметр, имеющий тип TestContext. Кроме того, при использовании async-await в методе возвращаемое значение должно иметь тип "Task" или "ValueTask". + + + + TestCleanup method {0}.{1} threw exception. {2}. + Метод TestCleanup {0}.{1} создал исключение. {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + Ошибка при вызове метода TestCleanup для тестового класса {0}: {1} + + + + TestCleanup Stack Trace + Трассировка стека TestCleanup + + Data source '{0}' cannot be found in the test configuration settings Не удалось найти источник данных "{0}" в параметрах конфигурации теста + + --- End of inner exception stack trace --- + --- Конец трассировки стека внутренних исключений --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} Адаптеру модульных тестов не удалось подключиться к источнику данных, чтобы считать данные. Дополнительные сведения об устранении этой ошибки см. в разделе "Устранение неполадок в модульных тестах на основе данных" (http://go.microsoft.com/fwlink/?LinkId=62412) в библиотеке MSDN. Подробности об ошибке: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: в классе {0} отсутствует допустимое свойство TestContext. Свойство TestContext должно относиться к типу TestContext, быть нестатическим и открытым. Например: public TestContext TestContext. + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: метод {1}, определенный в классе {0}, имеет неправильную сигнатуру. Метод теста, помеченный атрибутом [TestMethod], должен быть нестатическим, открытым и иметь тип возвращаемого значения void; он также не должен принимать параметры. Пример: public void Test.Class1.Test(). Кроме того, при использовании async-await в методе теста возвращаемое значение должно иметь тип "Task" или "ValueTask". Пример: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}. {1} имеет недопустимый атрибут времени ожидания. Значение времени ожидания должно быть положительным целым числом. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: в сборке невозможно определить несколько методов с атрибутом AssemblyCleanup. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: в сборке невозможно определить несколько методов с атрибутом AssemblyInitialize. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: в классе невозможно определить несколько методов с атрибутом ClassCleanup. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: в классе невозможно определить несколько методов с атрибутом ClassInitialize. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: невозможно определить несколько методов с атрибутом TestCleanup. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: невозможно определить несколько методов с атрибутом TestInitialize. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: атрибут TestClass определен в классе {0}, не являющемся открытым + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: не удается определить предопределенное свойство {2} в методе {1}. + + + + TestClass attribute defined on generic non-abstract class {0} + Атрибут TestClass определен в универсальном неабстрактном классе {0} + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: в методе {1} определено пользовательское свойство, имя которого имеет значение NULL или пусто. Пользовательское свойство должно иметь допустимое имя. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + Метод "Execute" сгенерировал необработанное исключение. Сообщите об этой ошибке автору атрибута "{0}". +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + Атрибут ExpectedException, определенный в методе теста {0}.{1}, породил исключение во время создания. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + Не удалось получить исключение, созданное методом теста {0}.{1}. + + + + Initialization method {0}.{1} threw exception. {2}. + Метод инициализации {0}.{1} вызвал исключение. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + Не удалось создать экземпляр класса {0}. Ошибка: {1}. + + + + Method {0}.{1} does not exist. + Метод {0}.{1} не существует. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + У метода тестирования "{0}.{1}" есть несколько атрибутов, производных от заданного в нем "{2}". Допускается только один такой атрибут. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + Ошибка при выполнении теста. Расширение не возвратило результаты. Если используется расширение атрибута TestMethodAttribute, обратитесь к поставщику. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + Не удается найти допустимый конструктор для тестового класса "{0}". Допустимые конструкторы должны быть определены как "public" и либо не иметь параметров, либо иметь один параметр типа "TestContext". + + + + Unable to find property {0}.TestContext. Error:{1}. + Не удается найти свойство {0}.TestContext. Ошибка: {1}. + + + + Unable to set TestContext property for the class {0}. Error: {1}. + Не удалось задать свойство TestContext для класса {0}. Ошибка: {1}. + + + + The {0}.TestContext has incorrect type. + Для свойства {0}.TestContext указан неправильный тип. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть нестатическим и открытым, не должен возвращать значение и принимать параметры. Кроме того, при использовании async-await в методе возвращаемое значение должно иметь тип "Task" или "ValueTask". + + + + Test method {0}.{1} threw exception: +{2} + Метод теста {0}.{1} создал исключение: +{2}. + + + + Unable to get type {0}. Error: {1}. + Не удается получить тип {0}. Ошибка: {1}. + + + + The called code threw an exception that was caught, but the exception value was null + Вызванный код вызвал исключение, которое было перехвачено, но значение исключения было равно NULL + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0} В проектах UWP, если в тесте используются объекты пользовательского интерфейса, рассмотрите возможность использования атрибута [UITestMethod] вместо атрибута [TestMethod] для выполнения теста в потоке пользовательского интерфейса. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (Не удалось получить сообщение для исключения с типом {0} в связи с возникновением исключения.) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + "MSTest.TestAdapter" и "MSTest.TestFramework" должны использовать одинаковую версию. Обнаружены "MSTest.TestAdapter" версии "{0}" и "MSTest.TestFramework" версии "{1}". Убедитесь, что версии пакетов NuGet "MSTest.TestAdapter" и "MSTest.TestFramework" совпадают. + + Wrong number of objects for permutation. Should be greater than zero. Неправильное число объектов для перестановки. Оно должно быть больше нуля. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.tr.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.tr.xlf index 79d35b165a..2c2dc60814 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.tr.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.tr.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + '{0}.{1}' derleme temizleme yöntemi {2}ms sonra zaman aşımına uğradı + + + + Assembly cleanup method '{0}.{1}' was canceled + '{0}.{1}' bütünleştirilmiş kod temizleme yöntemi iptal edildi + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + '{0}.{1}' derleme başlatma yöntemi {2}ms sonra zaman aşımına uğradı + + + + Assembly initialize method '{0}.{1}' was canceled + '{0}.{1}' derleme başlatma yöntemi iptal edildi + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + "{0}.{1} " üzerinde IDataSource özniteliği numaralandırılırken özel durum oluştu: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + "{0}. {1}" üzerindeki öznitelikten IDataSource satırları genişletilirken özel durum oluştu: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + "{1}" için {0} indeksindeki veriler serileştirilemez. "IDataSource" aracılığıyla sağlanan tüm veriler serileştirilebilir olmalıdır. Serileştirilemeyen veri kaynaklarını test etmeniz gerekiyorsa, lütfen test derlemenize "TestDataSourceDiscovery" özniteliğini eklediğinizden ve keşif seçeneğini "DuringExecution" olarak ayarladığınızdan emin olun. + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + {0} ve {1}dizinlerinde görünen ad " {2}" yineleniyor. Görünen adlar benzersiz olmalıdır. + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. '{0}' adlı dosya bulunamadı. + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + '{0}.{1}' test yöntemi çalıştırılamıyor: Test verileri yöntem parametreleriyle eşleşmiyor. Ya sayıları ya da türleri birbirinden farklı. +Test '{3}' türünde {2} parametre bekledi, +ancak, '{5}' türünde {4} bağımsız değişken aldı. + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + '{0}.{1}' test yöntemi çalıştırılamıyor: Yöntemin parametreleri var ancak herhangi bir test kaynağı tanımlamıyor. Test verilerini sağlamak için '[DataRow]', '[DynamicData]' veya özel bir 'ITestDataSource' veri kaynağı kullanın. + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + '{0}.{1}' sınıf temizleme yöntemi {2}ms sonra zaman aşımına uğradı + + + + Class cleanup method '{0}.{1}' was canceled + '{0}.{1}' sınıf temizleme yöntemi iptal edildi + + + + Class initialize method '{0}.{1}' timed out after {2}ms + '{0}.{1}' sınıf başlatma yöntemi {2}ms sonra zaman aşımına uğradı + + + + Class initialize method '{0}.{1}' was canceled + '{0}.{1}' sınıf başlatma yöntemi iptal edildi + + The parameter should not be null or empty. Parametre null veya boş olmamalıdır. + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + MSTestAdapter, '{1}' bütünleştirilmiş kodunun '{0}' sınıfındaki testleri bulamadı. Nedeni: {2}. + + + + {0} (Data Row {1}) + {0} (Veri Satırı {1}) + + + + Debug Trace: + Hata Ayıklama İzleyici: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. Test Çalıştırması dağıtım sorunu: '{0}' dağıtım öğesi hatalı: '{1}' çıktı dizininde öğenin dağıtım kök dizini dışında dağıtılması gerektiği belirtilmiş, ancak buna izin verilmiyor. @@ -77,16 +177,108 @@ '{0}' dağıtım öğesi (çıktı dizini '{1}') + + [MSTest][Discovery][{0}] {1} + [MSTest][Discovery][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + Hem '.runsettings' hem de '.testconfig.json' dosyaları algılandı. Lütfen bu test yapılandırma dosyalarından yalnızca birini seçin. + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + "{0}": ("{1}" türündeki bir istisna nedeniyle özel durum açıklaması alınamadı. + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + Oluşturulan özel durumlar: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + '{0}' testi iptal edildi + + + + Test '{0}' timed out after {1}ms + '{0}' testi {1} ms sonra zaman aşımına uğradı + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + {0} tipi için özel niteliklerin alınması özel durum oluşturdu (yok sayar ve yansıma yolunu kullanır): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + '{0}' genel parametre türü çıkarsanamadı. + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + '{0}' genel test metodu bağımsız değişkenlere sahip olmadığından, genel parametre çıkarsanamıyor. + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + '{0}' genel parametresi için iki çakışan tür bulundu. Çakışan türler '{1}' ile '{2}'. + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + 'ClassCleanupLifecycle' için geçersiz '{0}' değeri belirtildi. Desteklenen kapsamlar {1}'dir. + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + 'Scope' için geçersiz '{0}' değeri belirtildi. Desteklenen kapsamlar {1}. + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + 'Workers' için geçersiz '{0}' değeri belirtildi. Değer negatif olmayan bir tamsayı olmalıdır. + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + Geçersiz '{0}' ayarları. Beklenmeyen XmlAttribute: '{1}'. + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter, '{1}' ayarlarında beklenmedik bir öğeyle ('{0}') karşılaştı. Bu öğeyi kaldırıp yeniden deneyin. + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + Geçersiz '{0}' ayarları. Beklenmeyen XmlElement: '{1}'. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. '{1}' çalıştırma ayarları girişi için '{0}' değeri geçersiz, ayar yoksayılacak. + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + '{1}' çalıştırma ayarları girişi için '{0}' değeri geçersiz, ayar yoksayılacak. + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + Uyarı : MSTest V2 Adapter ile bir testsettings dosyası veya bir vsmdi dosyası desteklenmez. + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} Test Çalıştırması dağıtım sorunu: '{0}' adlı bütünleştirilmiş kod veya modül bulunamadı. Nedeni: {1} @@ -97,21 +289,309 @@ Test Çalıştırması dağıtım sorunu: '{0}' adlı bütünleştirilmiş kod veya modül bulunamadı. + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + Montaja MSTestV2 paketinin daha eski bir sürümü yüklenir, test keşfi, `.runsettings` dosyasına bağlılarsa tüm veri testlerini keşfetmede başarısız olabilir. + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + '<ExecutionApartmentState>STA</ExecutionApartmentState>' çalışma ayarları girişi Windows dışı işletim sistemlerinde desteklenmiyor. + + + + Running tests in any of the provided sources is not supported for the selected platform + Testlerin sağlanan kaynakların herhangi birinde çalıştırılması seçili platformda desteklenmiyor + + + + Failed to discover tests from assembly {0}. Reason:{1} + {0} bütünleştirilmiş kodundan testler bulunamadı. Neden:{1} + + + + File does not exist: {0} + Dosya yok: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + '{0}.{1}' test temizleme yöntemi {2}ms sonra zaman aşımına uğradı + + + + Test cleanup method '{0}.{1}' was canceled + '{0}.{1}' test temizleme yöntemi iptal edildi + + + + TestContext cannot be Null. + TestContext, Null olamaz. + + + + TestContext Messages: + TestContext İletileri: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + '{0}.{1}' test başlatma yöntemi {2}ms sonra zaman aşımına uğradı + + + + Test initialize method '{0}.{1}' was canceled + '{0}.{1}' test başlatma yöntemi iptal edildi + + + + Test method {0} was not found. + {0} test metodu bulunamadı. + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + {0} için Test Paralelleştirme etkin (Çalışanlar: {1}, Kapsam: {2}). + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + '{0}' test kaynağından türler yüklenemiyor. Kaynaktaki testlerin bazıları veya tümü bulunamayabilir. +Hata: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + Bütünleştirilmiş Kod Temizleme metodu ({0}.{1}) başarısız oldu. Hata İletisi: {2}. StackTrace: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + Bütünleştirilmiş Kod Başlatma metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}. Test yürütmesi durduruluyor. + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + Sınıf Temizleme metodu ({0}.{1}) başarısız oldu. Hata İletisi: {2}. Yığın İzlemesi: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + Sınıf Başlatma metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + {0}.{1} yönteminin imzası yanlış. Yöntem statik, genel, değer döndürmeyen bir yöntem olmalı, hiçbir parametre almamalıdır. Bunlara ek olarak, yöntemde async-await kullanıyorsanız return-type değeri 'Task' veya 'ValueTask' olmalıdır. + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + {0}.{1} yönteminin imzası yanlış. Yöntem statik, genel, değer döndürmeyen bir yöntem olmalı ve TestContext türünde tek bir parametre almalıdır. Bunlara ek olarak, yöntemde async-await kullanıyorsanız return-type değeri 'Task' veya 'ValueTask' olmalıdır. + + + + TestCleanup method {0}.{1} threw exception. {2}. + TestCleanup metodu {0}.{1} özel durum oluşturdu. {2}. + + + + Error calling Test Cleanup method for test class {0}: {1} + {0} test sınıfı için Test Temizleme metodu çağrılırken hata oluştu: {1} + + + + TestCleanup Stack Trace + TestCleanup Yığın İzleme + + Data source '{0}' cannot be found in the test configuration settings Test yapılandırması ayarlarında '{0}' adlı veri kaynağı bulunamıyor + + --- End of inner exception stack trace --- + --- İç özel durum yığın izlemesinin sonu --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} Birim test bağdaştırıcısı, veri kaynağına bağlanamadı veya verileri okuyamadı. Bu hata ile ilgili daha fazla sorun giderme bilgisi için MSDN Kitaplığı'ndaki "Veri Temelli Birim Testleriyle İlgili Sorunları Giderme" (http://go.microsoft.com/fwlink/?LinkId=62412) konusuna bakın. Hata ayrıntıları: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: {0}sınıfı geçerli bir TestContext özelliğine sahip değil. TestContext, TestContext türünde olmalı, static olmamalı ve public olmalıdır. Örnek: public TestContext TestContext. + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: {0} sınıfında tanımlanan {1} yönteminin imzası doğru değil. [TestMethod] özniteliğiyle işaretlenmiş test yöntemi statik olmayan, genel, dönüş türü void olan bir yöntem olmalıdır ve hiçbir parametre almamalıdır. Örnek: public void Test.Class1.Test(). Bunlara ek olarak, test metodunda async-await kullanıyorsanız return-type değeri 'Task' veya 'ValueTask' olmalıdır. Örnek: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}.{1} Timeout özniteliği geçersiz. Zaman aşımı değeri 0'dan büyük bir tamsayı olmalıdır. + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: Bir bütünleştirilmiş kod içinde AssemblyCleanup özniteliği ile birden fazla metot tanımlanamaz. + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: Bir bütünleştirilmiş kod içinde AssemblyInitialize özniteliği ile birden fazla metot tanımlanamaz. + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: Bir sınıf içinde ClassCleanup özniteliği ile birden fazla metot tanımlanamaz. + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: Bir sınıf içinde ClassInitialize özniteliği ile birden fazla metot tanımlanamaz. + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: TestCleanup özniteliği ile birden fazla metot tanımlanamaz. + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: TestInitialize özniteliği ile birden fazla metot tanımlanamaz. + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: TestClass özniteliği genel olmayan {0} sınıfında tanımlanmış + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: Önceden tanımlanmış {2} özelliği {1} metodunda tanımlanamaz. + + + + TestClass attribute defined on generic non-abstract class {0} + {0} genel soyut olmayan sınıf üzerinde tanımlanan TestClass özniteliği + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: {1} metodunda null veya boş özel özellik tanımlanmış. Özel özellik geçerli bir ada sahip olmalıdır. + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + 'Execute' yöntemi tarafından işlenmeyen bir özel durum oluştu. Lütfen bu hatayı '{0}' özniteliğinin yazarına bildirin. +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + {0}.{1} test yöntemi üzerinde tanımlanan ExpectedException özniteliği, oluşturma sırasında bir özel durum oluşturdu. +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + {0}.{1} metodu tarafından oluşturulan özel durum alınamadı. + + + + Initialization method {0}.{1} threw exception. {2}. + Başlatma metodu {0}.{1} özel durum oluşturdu. {2}. + + + + Unable to create instance of class {0}. Error: {1}. + {0} sınıfının örneği oluşturulamıyor. Hata: {1}. + + + + Method {0}.{1} does not exist. + {0}.{1} metodu yok. + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + “{0}.{1}” test yöntemi, üzerinde tanımlanan “{2}” öğesinden türetilmiş birden fazla öznitelik içeriyor. Bu türde yalnızca bir tane özniteliğe izin verilir. + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + Test yürütülürken hata oluştu. Uzantı tarafından hiç sonuç döndürülmedi. TestMethodAttribute uzantısı kullanılıyorsa, lütfen satıcıya başvurun. + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + '{0}' test sınıfı için geçerli bir oluşturucu bulunamıyor. Geçerli oluşturucular 'public' ve parametresiz veya 'TestContext' türünde tek bir parametre içeriyor. + + + + Unable to find property {0}.TestContext. Error:{1}. + {0}.TestContext özelliği bulunamıyor. Hata:{1}. + + + + Unable to set TestContext property for the class {0}. Error: {1}. + {0} sınıfı için TestContext özelliği ayarlanamıyor. Hata: {1}. + + + + The {0}.TestContext has incorrect type. + {0}.TestContext yanlış türe sahip. + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + {0}.{1} yönteminin imzası yanlış. Yöntem statik olmayan, genel, değer döndürmeyen bir yöntem olmalı, hiçbir parametre almamalıdır. Bunlara ek olarak, yöntemde async-await kullanıyorsanız return-type değeri 'Task' veya 'ValueTask' olmalıdır. + + + + Test method {0}.{1} threw exception: +{2} + {0}.{1} test metodu özel durum oluşturdu: +{2} + + + + Unable to get type {0}. Error: {1}. + {0} türü alınamıyor. Hata: {1}. + + + + The called code threw an exception that was caught, but the exception value was null + Çağrılan kod, yakalanan bir özel durum yarattı, ancak özel durum değeri boştu + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0} UWP projeleri için testte UI nesneleri kullanıyorsanız, testi UI iş parçacığında yürütmek için [TestMethod] yerine [UITestMethod] özniteliğini kullanabilirsiniz. + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (Bir özel durum nedeniyle, {0} türündeki özel durum iletisi alınamadı.) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + 'MSTest.TestAdapter' ve 'MSTest.TestFramework' aynı sürüme sahip olmalıdır. 'MSTest.TestAdapter' sürümü '{0}' ve 'MSTest.TestFramework' sürümü '{1}' bulundu. Lütfen 'MSTest.TestAdapter' ve 'MSTest.TestFramework' NuGet paketlerinin aynı sürüme sahip olduğundan emin olun. + + Wrong number of objects for permutation. Should be greater than zero. Permütasyon için nesne sayısı yanlış. Değer, sıfırdan büyük olmalıdır. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.zh-Hans.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.zh-Hans.xlf index 813ddf8f72..4d80166a18 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.zh-Hans.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.zh-Hans.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + 程序集清理方法“{0}.{1}”在 {2} ms 后超时 + + + + Assembly cleanup method '{0}.{1}' was canceled + 已取消程序集清理方法“{0}.{1}” + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + 程序集初始化方法“{0}.{1}”在 {2} ms 后超时 + + + + Assembly initialize method '{0}.{1}' was canceled + 已取消程序集初始化方法“{0}.{1}” + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + 枚举 {0} 上的 IDataSource 属性时发生异常。{1}": {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + 从“{0}.{1}”上的属性扩展 IDataSource 行时出现异常: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + 无法序列化“{1}”的索引 {0} 上的数据。通过“IDataSource”提供的所有数据都应可序列化。如果需要测试不可序列化的数据源,请确保在测试程序集上添加“TestDataSourceDiscovery”属性,并将发现选项设置为“DuringExecution”。 + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + 索引 {0} 和 {1} 上的显示名称“{2}”重复。显示名称应是唯一的。 + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. 找不到文件“{0}”。 + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + 无法运行测试方法“{0}.{1}”: 测试数据与方法参数不匹配。计数或类型不同。 +测试需要类型为“{3}”的 {2} 参数, +但收到了类型为“{5}”的 {4} 参数。 + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + 无法运行测试方法“{0}.{1}”: 方法具有参数,但未定义任何测试源。使用 “[DataRow]”、“[DynamicData]” 或自定义 “ITestDataSource” 数据源提供测试数据。 + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + 类清理方法“{0}.{1}”在 {2} ms 后超时 + + + + Class cleanup method '{0}.{1}' was canceled + 已取消类清理方法“{0}.{1}” + + + + Class initialize method '{0}.{1}' timed out after {2}ms + 类初始化方法“{0}.{1}”在 {2} ms 后超时 + + + + Class initialize method '{0}.{1}' was canceled + 已取消类初始化方法“{0}.{1}” + + The parameter should not be null or empty. 参数不应为 NULL 或为空。 + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + 由于 {2},MSTestAdapter 未能在程序集“{1}”的类“{0}”中发现测试。 + + + + {0} (Data Row {1}) + {0} (数据行 {1}) + + + + Debug Trace: + 调试跟踪: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. 测试运行部署问题: 错误的部署项:“{0}”: 输出目录“{1}”指定将该项部署到部署根目录的外部,这是不允许的。 @@ -77,16 +177,108 @@ 部署项“{0}”(输出目录“{1}”) + + [MSTest][Discovery][{0}] {1} + [MSTest][发现][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + 检测到 ".runsettings" 和 ".testconfig.json" 文件。请仅选择其中一个测试配置文件。 + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + “{0}”:(由于类型“{1}”异常,无法获取异常说明。 + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + 引发的异常: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + 测试“{0}”已取消 + + + + Test '{0}' timed out after {1}ms + 测试“{0}”在 {1} 毫秒后超时 + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + 获取类型 {0} 自定义属性引发异常(将忽略并使用反射方式): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + 无法推断泛型参数“{0}”的类型。 + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + 泛型测试方法“{0}”没有参数,因此无法推断泛型参数。 + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + 发现泛型参数“{0}”有两种冲突类型。冲突类型为“{1}”和“{2}”。 + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + 为“ClassCleanupLifecycle”指定的值“{0}”无效。支持的作用域为 {1}。 + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + 为“范围”指定的值“{0}”无效。受支持的范围为 {1}。 + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + 为“辅助角色”指定的值“{0}”无效。该值应为非负整数。 + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + 设置“{0}”无效。意外的 XmlAttribute:“{1}”。 + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter 在其设置“{1}”中遇到意外的元素“{0}”。删除此元素,然后再试一次。 + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + 设置“{0}”无效。意外的 XmlElement:“{1}”。 + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. runsettings 项 ‘{1}’ 的值 ‘{0}’ 无效,将忽略设置。 + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + runsettings 项 ‘{1}’ 的值 ‘{0}’ 无效,将忽略设置。 + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + 警告: MSTest V2 适配器不支持 testsettings 文件或 vsmdi 文件。 + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} 测试运行部署问题: 找不到程序集或模块“{0}”。原因: {1} @@ -97,21 +289,309 @@ 测试运行部署问题: 找不到程序集或模块“{0}”。 + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + 程序集中加载了 MSTestV2 包的较旧版本,如果测试发现依赖于“.runsettings”文件,则它们可能无法发现所有数据测试。 + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + 非 Windows 操作系统不支持 Runsettings 条目 "<ExecutionApartmentState>STA</ExecutionApartmentState>"。 + + + + Running tests in any of the provided sources is not supported for the selected platform + 选定的平台不支持在任何提供的源中运行测试 + + + + Failed to discover tests from assembly {0}. Reason:{1} + 未能发现程序集 {0} 中的测试。原因: {1} + + + + File does not exist: {0} + 文件不存在: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + 测试清理方法“{0}.{1}”在 {2} ms 后超时 + + + + Test cleanup method '{0}.{1}' was canceled + 已取消测试清理方法“{0}.{1}” + + + + TestContext cannot be Null. + TestContext 不能为 NULL。 + + + + TestContext Messages: + TestContext 消息: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + 测试初始化方法“{0}.{1}”在 {2} ms 后超时 + + + + Test initialize method '{0}.{1}' was canceled + 已取消测试初始化方法“{0}.{1}” + + + + Test method {0} was not found. + 未找到测试方法 {0}。 + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + 已为 {0} 启用测试并行化(工作线程: {1},范围: {2}) + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + 无法从测试源“{0}”加载类型。可能无法发现此源中的部分或所有测试。 +错误: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + 程序集清理方法 {0}.{1} 失败。错误消息: {2}。StackTrace: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + 程序集初始化方法 {0}.{1} 引发异常。{2}: {3}。正在中止测试的执行。 + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + 类清理方法 {0}.{1} 失败。错误消息: {2}。堆栈跟踪: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + 类初始化方法 {0}.{1} 引发异常。{2}: {3}。 + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + 方法 {0}。{1}的签名错误。该方法必须是静态的公共方法、不返回值并且不应采用任何参数。此外,如果在方法中使用同步等待,则返回类型必须为“Task”或“Value Task”。 + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + 方法 {0}。{1}的签名错误。该方法必须是静态的公共方法,不返回值,并且应采用一个 TestContext 类型的参数。此外,如果在方法中使用同步等待,则返回类型必须为“Task”或“Value Task”。 + + + + TestCleanup method {0}.{1} threw exception. {2}. + TestCleanup 方法 {0}.{1} 引发异常。{2}。 + + + + Error calling Test Cleanup method for test class {0}: {1} + 为测试类 {0} 调用 Test Cleanup 方法时出错: {1} + + + + TestCleanup Stack Trace + TestCleanup 堆栈跟踪 + + Data source '{0}' cannot be found in the test configuration settings 在测试配置设置中找不到数据源“{0}” + + --- End of inner exception stack trace --- + ---内部异常堆栈跟踪结束--- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} 单元测试适配器未能连接到数据源或读取数据。有关解决此错误的详细信息,请查看 MSDN 库中的“数据驱动单元测试疑难解答”(http://go.microsoft.com/fwlink/?LinkId=62412)。错误详细信息: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: 类 {0} 没有有效的 TestContext 属性。TestContext 必须是 TestContext 类型并且必须是非静态和公共的。例如: public TestContext TestContext。 + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: 在类 {0} 中定义的方法 {1} 没有正确的签名。用 [TestMethod] 特性标记的测试方法必须是返回类型为 void 的非静态的公共方法,并且不应采用任何参数。示例: public void Test.Class1.Test()。此外,如果在测试方法中使用同步等待,则返回类型必须为“Task”或“Value Task”。示例: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}。{1} 的超时属性无效。“超时”必须是大于零的整数值。 + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: 在一个程序集内部,不能定义多个具有 AssemblyCleanup 特性的方法。 + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: 在一个程序集内部,不能定义多个具有 AssemblyInitialize 特性的方法。 + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: 在一个类内部,不能定义多个具有 ClassCleanup 特性的方法。 + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: 在一个类内部,不能定义多个具有 ClassInitialize 特性的方法。 + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: 不能定义多个具有 TestCleanup 特性的方法。 + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: 不能定义多个具有 TestInitialize 特性的方法。 + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: 在非公共类 {0} 上定义的 TestClass 特性 + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: 不能在方法 {1} 上定义预定义属性 {2}。 + + + + TestClass attribute defined on generic non-abstract class {0} + 在泛型非抽象类 {0} 上定义的 TestClass 特性 + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: 对方法 {1} 定义了为 NULL 或为空的自定义属性。自定义属性必须具有有效名称。 + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + “Execute”方法引发了未经处理的异常。请将此错误报告给属性“{0}”的作者。 +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + 测试方法 {0}.{1} 上定义的 ExpectedException 属性在构造过程中引发了一个异常。 +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + 未能获取测试方法 {0}.{1} 引发的异常。 + + + + Initialization method {0}.{1} threw exception. {2}. + 初始化方法 {0}.{1} 引发异常。{2}。 + + + + Unable to create instance of class {0}. Error: {1}. + 无法创建类 {0} 的实例。错误: {1}。 + + + + Method {0}.{1} does not exist. + 方法 {0}.{1} 不存在。 + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + 测试方法“{0}.{1}”具有多个在其上定义的“{2}”的派生属性。仅允许一个此类属性。 + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + 执行测试时出错。扩展未返回任何结果。如果使用的是扩展 TestMethodAttribute ,请与供应商联系。 + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + 找不到测试类“{0}”的有效构造函数。有效的构造函数为 “public”,但该构造函数无参数或具有一个类型为 “TestContext” 的参数。 + + + + Unable to find property {0}.TestContext. Error:{1}. + 无法找到属性 {0}.TestContext。错误: {1}。 + + + + Unable to set TestContext property for the class {0}. Error: {1}. + 无法设置类 {0} 的 TestContext 属性。错误: {1}。 + + + + The {0}.TestContext has incorrect type. + {0}.TestContext 的类型不正确。 + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + 方法 {0}。{1}的签名错误。该方法必须是非静态的公共方法、不返回值并且不应采用任何参数。此外,如果在方法中使用同步等待,则返回类型必须为“Task”或“Value Task”。 + + + + Test method {0}.{1} threw exception: +{2} + 测试方法 {0}.{1} 引发了异常: +{2} + + + + Unable to get type {0}. Error: {1}. + 无法获取类型 {0}。错误: {1}。 + + + + The called code threw an exception that was caught, but the exception value was null + 调用的代码引发了捕获的异常,但异常值为 null + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0} 对于 UWP 项目,如果在测试中使用 UI 对象,请考虑使用 [UITestMethod] 属性代替 [TestMethod] 属性在 UI 线程中执行测试。 + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (因异常而未能获取类型为 {0} 的异常的消息。) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + 'MSTest.TestAdapter' 和 'MSTest.TestFramework' 必须具有相同的版本。找到 'MSTest.TestAdapter' 版本“{0}”和 'MSTest.TestFramework' 版本“{1}”。请确保 'MSTest.TestAdapter' 和 'MSTest.TestFramework' NuGet 包的版本具有相同的版本。 + + Wrong number of objects for permutation. Should be greater than zero. 排列的对象数不正确。应大于零。 diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.zh-Hant.xlf b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.zh-Hant.xlf index aae5f14299..b933d9305b 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.zh-Hant.xlf +++ b/src/Adapter/MSTestAdapter.PlatformServices/Resources/xlf/Resource.zh-Hant.xlf @@ -2,16 +2,116 @@ + + Assembly cleanup method '{0}.{1}' timed out after {2}ms + 組件清理方法 '{0}.{1}' 在 {2} 毫秒後已逾時 + + + + Assembly cleanup method '{0}.{1}' was canceled + 已取消組件清理方法 '{0}.{1}' + + + + Assembly initialize method '{0}.{1}' timed out after {2}ms + 組件初始化方法 '{0}.{1}' 在 {2} 毫秒後已逾時 + + + + Assembly initialize method '{0}.{1}' was canceled + 已取消組件初始化方法 '{0}.{1}' + + + + MSTestAdapterV2 + MSTestAdapterV2 + + + + Exception occurred while enumerating IDataSource attribute on "{0}.{1}": {2} + 列舉「{0}.{1}」上的 IDataSource 屬性時發生例外狀況: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: Exception details + + + Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2} + 從「{0}.{1}」上的屬性展開 IDataSource 資料列時發生例外狀況: {2} + {0}: TypeName with namespace, +{1}: Method name, +{2}: CannotExpandIDataSourceAttribute_DuplicateDisplayName or CannotExpandIDataSourceAttribute_CannotSerialize + + + Data on index {0} for "{1}" cannot be serialized. All data provided through "IDataSource" should be serializable. If you need to test non-serializable data sources, please make sure you add "TestDataSourceDiscovery" attribute on your test assembly and set the discovery option to "DuringExecution". + 無法序列化「{1}"」索引 {0} 上的資料。透過「IDataSource」提供的所有資料應可序列化。如果您需要測試不可序列化的資料來源,請務必在測試元件上新增「TestDataSourceDiscovery」屬性,並將探索選項設定為「DuringExecution」。 + {0}: Zero based index if an element inside of an array, +{1}: Test name + + + Display name "{2}" on indexes {0} and {1} are duplicate. Display names should be unique. + 索引 {0} 和 {1} 上的顯示名稱「{2}」重複。顯示名稱必須是唯一的。 + {0}, {1}: Zero based index if an element inside of an array +{2}: Test display name. + Could not find file '{0}'. 找不到檔案 '{0}'。 + + Cannot run test method '{0}.{1}': Test data doesn't match method parameters. Either the count or types are different. +Test expected {2} parameter(s), with types '{3}', +but received {4} argument(s), with types '{5}'. + 無法執行測試方法 '{0}.{1}': 測試資料不符合方法參數。計數或類型不同。 +測試預期的 {2} 參數,類型為 '{3}', +但收到 {4} 引數,類型為 '{5}'。 + + + + Cannot run test method '{0}.{1}': Method has parameters, but does not define any test source. Use '[DataRow]', '[DynamicData]', or a custom 'ITestDataSource' data source to provide test data. + 無法執行測試方法 '{0}.{1}': 方法具有參數,但未定義任何測試來源。使用 '[DataRow]'、'[DynamicData]' 或自訂 'ITestDataSource' 資料來源來提供測試資料。 + + + + Class cleanup method '{0}.{1}' timed out after {2}ms + 類別清理方法 '{0}.{1}' 在 {2} 毫秒後已逾時 + + + + Class cleanup method '{0}.{1}' was canceled + 已取消類別清理方法 '{0}.{1}' + + + + Class initialize method '{0}.{1}' timed out after {2}ms + 類別初始化方法 '{0}.{1}' 在 {2} 毫秒後已逾時 + + + + Class initialize method '{0}.{1}' was canceled + 已取消類別初始化方法 '{0}.{1}' + + The parameter should not be null or empty. 參數不可為 null 或空白。 + + MSTestAdapter failed to discover tests in class '{0}' of assembly '{1}' because {2}. + MSTestAdapter 無法在組件 '{1}' 的類別 '{0}' 中探索測試,因為 {2}。 + + + + {0} (Data Row {1}) + {0} (資料列 {1}) + + + + Debug Trace: + 偵錯追蹤: + + Test Run deployment issue: Bad deployment item: '{0}': output directory '{1}' specifies the item to be deployed outside deployment root directory which is not allowed. 測試回合部署問題: 部署項目錯誤: '{0}': 輸出目錄 '{1}' 指定要將項目部署到部署根目錄之外,但不允許這情況。 @@ -77,16 +177,108 @@ 部署項目 '{0}' (輸出目錄 '{1}') + + [MSTest][Discovery][{0}] {1} + [MSTest][Discovery][{0}] {1} + + + + Both '.runsettings' and '.testconfig.json' files have been detected. Please select only one of these test configuration files. + 偵測到 '.runsettings' 和 '.testconfig.json' 檔案。請只選取其中一個測試設定檔。 + + + + {0}: {1} + {0}: {1} + + + + "{0}": (Failed to get exception description due to an exception of type "{1}". + 「{0}」: (因為類型「{1}」的例外狀況而無法取得例外狀況描述。 + {0}: Type of the original exception that we're trying to get the description of. +{1}: Thrown exception + + + Exceptions thrown: + 擲回的例外狀況數: + This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session. + + + Test '{0}' was canceled + 測試 '{0}' 已取消 + + + + Test '{0}' timed out after {1}ms + 測試 '{0}' 在 {1} 毫秒後逾時 + + + + Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1} + 取得類型 {0} 擲回例外狀況的自訂屬性 (將會略過並使用反映方式): {1} + {0}: Attribute full type name. +{1}: Exception description + + + The type of the generic parameter '{0}' could not be inferred. + 無法推斷泛型參數 '{0}' 的類型。 + + + + The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred. + 泛型測試方法 '{0}' 沒有引數,因此無法推斷泛型參數。 + + + + Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'. + 發現泛型參數 '{0}' 有兩個衝突類型。衝突類型為 '{1}' 和 '{2}'。 + + + + Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}. + 為 'ClassCleanupLifecycle' 指定的值 '{0}' 無效。支援的範圍為 {1}。 + 'ClassCleanupLifecycle' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}. + 為 'Scope' 指定的值 '{0}' 無效。支援的範圍為 {1}。 + 'Scope' is a setting name that shouldn't be localized. + + + Invalid value '{0}' specified for 'Workers'. The value should be a non-negative integer. + 為 'Workers' 的值 '{0}' 無效。值應為非負整數。 + `Workers` is a setting name that shouldn't be localized. + + + Invalid settings '{0}'. Unexpected XmlAttribute: '{1}'. + 設定 '{0}' 無效。未預期的 XmlAttribute: '{1}'。 + + MSTestAdapter encountered an unexpected element '{0}' in its settings '{1}'. Remove this element and try again. MSTestAdapter 在其設定 '{1}' 中遇到未預期的項目 '{0}'。請移除此項目,然後再試一次。 + + Invalid settings '{0}'. Unexpected XmlElement: '{1}'. + 設定 '{0}' 無效。未預期的 XmlElement: '{1}'。 + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. runsettings 項目 '{1}' 的值 '{0}' 無效,將忽略設定。 + + Invalid value '{0}' for runsettings entry '{1}', setting will be ignored. + runsettings 項目 '{1}' 的值 '{0}' 無效,將忽略設定。 + + + + Warning : A testsettings file or a vsmdi file is not supported with the MSTest V2 Adapter. + 警告: MSTest V2 配接器不支援 testsettings 檔案 vsmdi 檔案。 + + Test Run deployment issue: The assembly or module '{0}' was not found. Reason: {1} 測試回合部署問題: 找不到組件或模組 '{0}'。原因: {1} @@ -97,21 +289,309 @@ 測試回合部署問題: 找不到組件或模組 '{0}'。 + + An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file. + 元件中已載入舊版的 MSTestV2 套件,如果測試探索相依於 '.runsettings' 檔案,則測試探索可能無法探索所有資料測試。 + + + + Runsettings entry '<ExecutionApartmentState>STA</ExecutionApartmentState>' is not supported on non-Windows OSes. + 非 Windows OS 不支援 Runsettings 項目 '<ExecutionApartmentState>STA</ExecutionApartmentState>'。 + + + + Running tests in any of the provided sources is not supported for the selected platform + 所選取的平台不支援在任何提供的來源中執行測試 + + + + Failed to discover tests from assembly {0}. Reason:{1} + 無法從組件 {0} 中探索測試。原因:{1} + + + + File does not exist: {0} + 檔案不存在: {0} + + + + Test cleanup method '{0}.{1}' timed out after {2}ms + 測試清理方法 '{0}.{1}' 在 {2} 毫秒後已逾時 + + + + Test cleanup method '{0}.{1}' was canceled + 已取消測試清理方法 '{0}.{1}' + + + + TestContext cannot be Null. + TestContext 不可為 Null。 + + + + TestContext Messages: + TestContext 訊息: + + + + Test initialize method '{0}.{1}' timed out after {2}ms + 測試初始化方法 '{0}.{1}' 在 {2} 毫秒後已逾時 + + + + Test initialize method '{0}.{1}' was canceled + 已取消測試初始化方法 '{0}.{1}' + + + + Test method {0} was not found. + 找不到測試方法 {0}。 + + + + Test Parallelization enabled for {0} (Workers: {1}, Scope: {2}) + 已為 {0} 啟用平行測試 (背景工作角色: {1},範圍: {2}) + `Workers` is a setting name that shouldn't be localized. 'Scope' is a setting name that shouldn't be localized. + {0}_{1} {2} {0}_{1} {2} + + Unable to load types from the test source '{0}'. Some or all of the tests in this source may not be discovered. +Error: {1} + 無法從測試來源 '{0}' 載入類型。有可能無法探索此來源中的部分或所有測試。 +錯誤: {1} + + + + Assembly Cleanup method {0}.{1} failed. Error Message: {2}. StackTrace: {3} + 組件清除方法 {0}.{1} 失敗。錯誤訊息: {2}。堆疊追蹤: {3} + + + + Assembly Initialization method {0}.{1} threw exception. {2}: {3}. Aborting test execution. + 組件初始設定方法 {0}.{1} 擲回例外狀況。{2}: {3}。正在中止測試執行。 + + + + Class Cleanup method {0}.{1} failed. Error Message: {2}. Stack Trace: {3} + 類別清除方法 {0}.{1} 失敗。錯誤訊息: {2}。堆疊追蹤: {3} + + + + Class Initialization method {0}.{1} threw exception. {2}: {3}. + 類別初始設定方法 {0}.{1} 擲回例外狀況。{2}: {3}。 + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + 方法 {0}.{1} 有錯誤的簽章。方法必須為靜態、公用、不傳回值,並且不應該接受任何參數。此外,如果您在方法中使用 async-await,則傳回類型必須是 'Task' 或 'ValueTask'。 + + + + Method {0}.{1} has wrong signature. The method must be static, public, does not return a value and should take a single parameter of type TestContext. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + 方法 {0}.{1} 有錯誤的簽章。方法必須為靜態、公用、不傳回值,並且應接受類型為 TestContext 的單一參數。此外,如果您在方法中使用 async-await,則傳回類型必須是 'Task' 或 'ValueTask'。 + + + + TestCleanup method {0}.{1} threw exception. {2}. + TestCleanup 方法 {0}.{1} 擲回例外狀況。{2}。 + + + + Error calling Test Cleanup method for test class {0}: {1} + 呼叫測試類別 {0} 的測試清除方法時發生錯誤: {1} + + + + TestCleanup Stack Trace + TestCleanup 堆疊追蹤 + + Data source '{0}' cannot be found in the test configuration settings 在測試組態設定中找不到資料來源 '{0}' + + --- End of inner exception stack trace --- + --- 已到達內部例外狀況堆疊追蹤的結尾 --- + + The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library. Error details: {0} 單元測試配接器無法連接至資料來源或無法讀取資料。如需為此錯誤進行疑難排解的詳細資訊,請參閱 MSDN Library 上的<如何: 建立資料驅動型單元測試>(http://go.microsoft.com/fwlink/?LinkId=62412)。錯誤詳細資料: {0} + + UTA031: class {0} does not have valid TestContext property. TestContext must be of type TestContext, must be non-static, and must be public. For example: public TestContext TestContext. + UTA031: 類別 {0}不具備有效的 TestContext 屬性。TestContext 必須是 TestContext 類型、必須是非靜態的,而且必須是公用的。例如: public TestContext TestContext。 + + + + UTA007: Method {1} defined in class {0} does not have correct signature. Test method marked with the [TestMethod] attribute must be non-static, public, return-type as void and should not take any parameter. Example: public void Test.Class1.Test(). Additionally, if you are using async-await in test method then return-type must be 'Task' or 'ValueTask'. Example: public async Task Test.Class1.Test2() + UTA007: 類別 {0} 中定義的方法 {1} 沒有正確的簽章。標記 [TestMethod] 屬性的測試方法必須為非靜態、公用、傳回類型為 void,而且不應該接受任何參數。範例: public void Test.Class1.Test()。此外,如果您在測試方法中使用 async-await,則傳回類型必須是 'Task' 或 'ValueTask'。範例: public async Task Test.Class1.Test2() + + + + UTA054: {0}.{1} has invalid Timeout attribute. The timeout must be an integer value greater than 0. + UTA054: {0}。{1} 中具有無效的 Timeout 屬性。逾時必須為大於 0 的整數值。 + + + + UTA014: {0}: Cannot define more than one method with the AssemblyCleanup attribute inside an assembly. + UTA014: {0}: 組件內不可定義一個以上具有 AssemblyCleanup 屬性的方法。 + + + + UTA013: {0}: Cannot define more than one method with the AssemblyInitialize attribute inside an assembly. + UTA013: {0}: 組件內不可定義一個以上具有 AssemblyInitialize 屬性的方法。 + + + + UTA026: {0}: Cannot define more than one method with the ClassCleanup attribute inside a class. + UTA026: {0}: 類別內不可定義一個以上具有 ClassCleanup 屬性的方法。 + + + + UTA025: {0}: Cannot define more than one method with the ClassInitialize attribute inside a class. + UTA025: {0}: 類別內不可定義一個以上具有 ClassInitialize 屬性的方法。 + + + + UTA024: {0}: Cannot define more than one method with the TestCleanup attribute. + UTA024: {0}: 不可定義一個以上具有 TestCleanup 屬性的方法。 + + + + UTA018: {0}: Cannot define more than one method with the TestInitialize attribute. + UTA018: {0}: 不可定義一個以上具有 TestInitialize 屬性的方法。 + + + + UTA001: TestClass attribute defined on non-public class {0} + UTA001: 在非公用類別 {0} 上定義了 TestClass 屬性 + + + + UTA023: {0}: Cannot define predefined property {2} on method {1}. + UTA023: {0}: 不可在方法 {1} 上定義預先定義的屬性 {2}。 + + + + TestClass attribute defined on generic non-abstract class {0} + 在一般非抽象類別上定義的 TestClass 屬性 {0} + + + + UTA021: {0}: Null or empty custom property defined on method {1}. The custom property must have a valid name. + UTA021: {0}: 在方法 {1} 上定義了 Null 或空白的自訂屬性。自訂屬性的名稱必須有效。 + + + + An unhandled exception was thrown by the 'Execute' method. Please report this error to the author of the attribute '{0}'. +{1} + 'Execute' 方法擲回未處理的例外狀況。請將此錯誤回報給屬性 '{0}' 的作者。 +{1} + + + + The ExpectedException attribute defined on test method {0}.{1} threw an exception during construction. +{2} + 測試方法 {0} 上定義的 ExpectedException 屬性。{1} 在建構期間擲回例外狀況。 +{2} + + + + Failed to obtain the exception thrown by test method {0}.{1}. + 無法取得測試方法 {0}.{1} 所擲回的例外狀況。 + + + + Initialization method {0}.{1} threw exception. {2}. + 初始設定方法 {0}.{1} 擲回例外狀況。{2}。 + + + + Unable to create instance of class {0}. Error: {1}. + 無法建立類別 {0} 的執行個體。錯誤: {1}。 + + + + Method {0}.{1} does not exist. + 方法 {0}.{1} 不存在。 + + + + The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed. + 測試方法 '{0}.{1}' 具有多個衍生自 '{2}' 的屬性根據其定義。只允許一個此類屬性。 + + + + Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor. + 執行測試時發生錯誤。擴充功能未傳回任何結果。如果您使用 TestMethodAttribute 的擴充功能,請連絡廠商。 + + + + Cannot find a valid constructor for test class '{0}'. Valid constructors are 'public' and either parameterless or with one parameter of type 'TestContext'. + 找不到測試類別 '{0}' 的有效建構函式。有效的建構函式為 'public' 且無參數或具有一個類型為 'TestContext' 的參數。 + + + + Unable to find property {0}.TestContext. Error:{1}. + 找不到屬性 {0}.TestContext。錯誤: {1}。 + + + + Unable to set TestContext property for the class {0}. Error: {1}. + 無法設定類別 {0} 的 TestContext 屬性。錯誤: {1}。 + + + + The {0}.TestContext has incorrect type. + {0}.TestContext 有不正確的類型。 + + + + Method {0}.{1} has wrong signature. The method must be non-static, public, does not return a value and should not take any parameter. Additionally, if you are using async-await in method then return-type must be 'Task' or 'ValueTask'. + 方法 {0}.{1} 有錯誤的簽章。方法必須為非靜態、公用、不傳回值,並且不應該接受任何參數。此外,如果您在方法中使用 async-await,則傳回類型必須是 'Task' 或 'ValueTask'。 + + + + Test method {0}.{1} threw exception: +{2} + 測試方法 {0}.{1} 擲回例外狀況: +{2} + + + + Unable to get type {0}. Error: {1}. + 無法取得類型 {0}。錯誤: {1}。 + + + + The called code threw an exception that was caught, but the exception value was null + 被呼叫的程式碼擲回攔截到的例外狀況,但例外狀況值為 Null + + + + {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread. + {0} 針對 UWP 專案,如果您在測試中使用 UI 物件,請考慮使用 [UITestMethod] 屬性取代 [TestMethod] 在 UI 執行緒中執行測試。 + + + + (Failed to get the message for an exception of type {0} due to an exception.) + (因為發生例外狀況,所以無法取得類型 {0} 之例外狀況的訊息。) + + + + 'MSTest.TestAdapter' and 'MSTest.TestFramework' must have the same version. Found 'MSTest.TestAdapter' version '{0}' and 'MSTest.TestFramework' version '{1}'. Please make sure that the versions of 'MSTest.TestAdapter' and 'MSTest.TestFramework' NuGet packages have the same version. + 'MSTest.TestAdapter' 和 'MSTest.TestFramework' 必須使用相同的版本。發現 'MSTest.TestAdapter' 的版本為 '{0}',而 'MSTest.TestFramework' 的版本為 '{1}'。請確保 'MSTest.TestAdapter' 和 'MSTest.TestFramework' 的 NuGet 套件版本一致。 + + Wrong number of objects for permutation. Should be greater than zero. 排列的物件數目錯誤。應大於零。 diff --git a/src/Adapter/MSTest.TestAdapter/RunConfigurationSettings.cs b/src/Adapter/MSTestAdapter.PlatformServices/RunConfigurationSettings.cs similarity index 97% rename from src/Adapter/MSTest.TestAdapter/RunConfigurationSettings.cs rename to src/Adapter/MSTestAdapter.PlatformServices/RunConfigurationSettings.cs index b2c9b24b54..41b1ad7058 100644 --- a/src/Adapter/MSTest.TestAdapter/RunConfigurationSettings.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/RunConfigurationSettings.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. #if !WINDOWS_UWP +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; #endif @@ -16,9 +17,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; /// The run configuration settings. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class RunConfigurationSettings { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs index 9f5399670c..7fb908212a 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs @@ -16,9 +16,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// The file operations. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class FileOperations : IFileOperations { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs index 8266bf58e7..8f4f179327 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs @@ -14,9 +14,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// The MSTest settings. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class MSTestAdapterSettings { @@ -161,7 +161,7 @@ internal static MSTestAdapterSettings ToSettings(IConfiguration configuration) // }, // ... remaining settings // } - var settings = new MSTestAdapterSettings(); + MSTestAdapterSettings settings = MSTestSettingsProvider.Settings; Configuration = configuration; ParseBooleanSetting(configuration, "deployment:enabled", value => settings.DeploymentEnabled = value); ParseBooleanSetting(configuration, "deployment:deployTestSourceDependencies", value => settings.DeployTestSourceDependencies = value); diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs index 2e37b5afba..cf49b2781d 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; +using Microsoft.VisualStudio.TestTools.UnitTesting; #if NETFRAMEWORK using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities; #endif @@ -12,9 +13,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// This service is responsible for platform specific reflection operations. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class ReflectionOperations : IReflectionOperations { @@ -27,7 +28,7 @@ public class ReflectionOperations : IReflectionOperations [return: NotNullIfNotNull(nameof(memberInfo))] public object[]? GetCustomAttributes(MemberInfo memberInfo, bool inherit) #if NETFRAMEWORK - => ReflectionUtility.GetCustomAttributes(memberInfo, inherit).ToArray(); + => [.. ReflectionUtility.GetCustomAttributes(memberInfo, inherit)]; #else { object[] attributes = memberInfo.GetCustomAttributes(typeof(Attribute), inherit); @@ -51,7 +52,7 @@ public class ReflectionOperations : IReflectionOperations [return: NotNullIfNotNull(nameof(memberInfo))] public object[]? GetCustomAttributes(MemberInfo memberInfo, Type type, bool inherit) => #if NETFRAMEWORK - ReflectionUtility.GetCustomAttributes(memberInfo, type, inherit).ToArray(); + [.. ReflectionUtility.GetCustomAttributes(memberInfo, type, inherit)]; #else memberInfo.GetCustomAttributes(type, inherit); #endif diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs index 26e97bf5d5..c530d8d802 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs @@ -9,9 +9,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// Class to read settings from the runsettings xml for the desktop. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class MSTestSettingsProvider : ISettingsProvider { @@ -37,9 +37,16 @@ public static MSTestAdapterSettings Settings internal static void Load(IConfiguration configuration) { #if !WINDOWS_UWP -#pragma warning disable IDE0022 // Use expression body for method var settings = MSTestAdapterSettings.ToSettings(configuration); -#pragma warning restore IDE0022 // Use expression body for method + if (!ReferenceEquals(settings, Settings)) + { + // NOTE: ToSettings mutates the Settings property and just returns it. + // This invariant is important to preserve, because we load from from runsettings through the XmlReader overload below. + // Then we read via IConfiguration. + // So this path should be unreachable. + // In v4 when we will make this class internal, we can start changing the API to clean this up. + throw ApplicationStateGuard.Unreachable(); + } #endif } @@ -51,7 +58,16 @@ public void Load(XmlReader reader) { #if !WINDOWS_UWP Guard.NotNull(reader); - Settings = MSTestAdapterSettings.ToSettings(reader); + var settings = MSTestAdapterSettings.ToSettings(reader); + if (!ReferenceEquals(settings, Settings)) + { + // NOTE: ToSettings mutates the Settings property and just returns it. + // This invariant is important to preserve, because we load from from runsettings through the XmlReader overload below. + // Then we read via IConfiguration. + // So this path should be unreachable. + // In v4 when we will make this class internal, we can start changing the API to clean this up. + throw ApplicationStateGuard.Unreachable(); + } #endif } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs index c129f79d52..b2d0ab97d1 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs @@ -6,6 +6,7 @@ using System.Data.Common; #endif +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -20,33 +21,36 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// like GetProperty<string>("TestName") or GetProperty<string>("FullyQualifiedTestClassName"). /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif -public class TestContextImplementation : TestContext, ITestContext +public class TestContextImplementation : TestContext, ITestContext, IDisposable { + private static readonly AsyncLocal CurrentTestContextAsyncLocal = new(); + /// /// List of result files associated with the test. /// private readonly List _testResultFiles; - /// - /// Writer on which the messages given by the user should be written. - /// - private readonly StringWriter _stringWriter; - private readonly ThreadSafeStringWriter? _threadSafeStringWriter; + // This should be removed. Don't rely on it. + // We only keep it for public constructor, but we don't pass it by the adapter. + private readonly StringWriter? _stringWriter; /// /// Properties. /// private readonly Dictionary _properties; private readonly IMessageLogger? _messageLogger; + private readonly CancellationTokenRegistration? _cancellationTokenRegistration; - /// - /// Specifies whether the writer is disposed or not. - /// - private bool _stringWriterDisposed; + private StringBuilder? _stdOutStringBuilder; + private StringBuilder? _stdErrStringBuilder; + private StringBuilder? _traceStringBuilder; + private StringBuilder? _testContextMessageStringBuilder; + + private bool _isDisposed; /// /// Unit test outcome. @@ -65,16 +69,21 @@ public class TestContextImplementation : TestContext, ITestContext private DataRow? _dataRow; #endif + private static readonly Action CancelDelegate = static state => ((TestContextImplementation)state!).Context.CancellationTokenSource.Cancel(); + /// /// Initializes a new instance of the class. /// /// The test method. - /// The writer where diagnostic messages are written to. /// Properties/configuration passed in. /// The message logger to use. - internal TestContextImplementation(ITestMethod? testMethod, StringWriter stringWriter, IDictionary properties, IMessageLogger messageLogger) - : this(testMethod, stringWriter, properties) - => _messageLogger = messageLogger; + /// The global test run cancellation token. + internal TestContextImplementation(ITestMethod? testMethod, IDictionary properties, IMessageLogger messageLogger, TestRunCancellationToken? testRunCancellationToken) + : this(testMethod, null!, properties) + { + _messageLogger = messageLogger; + _cancellationTokenRegistration = testRunCancellationToken?.Register(CancelDelegate, this); + } /// /// Initializes a new instance of the class. @@ -87,14 +96,7 @@ public TestContextImplementation(ITestMethod? testMethod, StringWriter stringWri // testMethod can be null when running ForceCleanup (done when reaching --maximum-failed-tests. DebugEx.Assert(properties != null, "properties is not null"); -#if NETFRAMEWORK - DebugEx.Assert(stringWriter != null, "StringWriter is not null"); -#endif - _stringWriter = stringWriter; - - // Cannot get this type in constructor directly, because all signatures for all platforms need to be the same. - _threadSafeStringWriter = stringWriter as ThreadSafeStringWriter; _properties = testMethod is null ? new Dictionary(properties) : new Dictionary(properties) @@ -108,6 +110,8 @@ public TestContextImplementation(ITestMethod? testMethod, StringWriter stringWri _testResultFiles = []; } + internal static TestContextImplementation? CurrentTestContext => CurrentTestContextAsyncLocal.Value; + #region TestContext impl /// @@ -178,20 +182,9 @@ public override void AddResultFile(string fileName) /// The formatted string that contains the trace message. public override void Write(string? message) { - if (_stringWriterDisposed) - { - return; - } - - try - { - string? msg = message?.Replace("\0", "\\0"); - _stringWriter.Write(msg); - } - catch (ObjectDisposedException) - { - _stringWriterDisposed = true; - } + string? msg = message?.Replace("\0", "\\0"); + GetTestContextMessagesStringBuilder().Append(msg); + _stringWriter?.Write(msg); } /// @@ -202,20 +195,9 @@ public override void Write(string? message) /// Arguments to add to the trace message. public override void Write(string format, params object?[] args) { - if (_stringWriterDisposed) - { - return; - } - - try - { - string message = string.Format(CultureInfo.CurrentCulture, format.Replace("\0", "\\0"), args); - _stringWriter.Write(message); - } - catch (ObjectDisposedException) - { - _stringWriterDisposed = true; - } + string message = string.Format(CultureInfo.CurrentCulture, format.Replace("\0", "\\0"), args); + GetTestContextMessagesStringBuilder().Append(message); + _stringWriter?.Write(message); } /// @@ -225,20 +207,9 @@ public override void Write(string format, params object?[] args) /// The formatted string that contains the trace message. public override void WriteLine(string? message) { - if (_stringWriterDisposed) - { - return; - } - - try - { - string? msg = message?.Replace("\0", "\\0"); - _stringWriter.WriteLine(msg); - } - catch (ObjectDisposedException) - { - _stringWriterDisposed = true; - } + string? msg = message?.Replace("\0", "\\0"); + GetTestContextMessagesStringBuilder().AppendLine(msg); + _stringWriter?.Write(msg); } /// @@ -249,20 +220,9 @@ public override void WriteLine(string? message) /// Arguments to add to the trace message. public override void WriteLine(string format, params object?[] args) { - if (_stringWriterDisposed) - { - return; - } - - try - { - string message = string.Format(CultureInfo.CurrentCulture, format.Replace("\0", "\\0"), args); - _stringWriter.WriteLine(message); - } - catch (ObjectDisposedException) - { - _stringWriterDisposed = true; - } + string message = string.Format(CultureInfo.CurrentCulture, format.Replace("\0", "\\0"), args); + GetTestContextMessagesStringBuilder().AppendLine(message); + _stringWriter?.Write(message); } /// @@ -354,13 +314,16 @@ public void AddProperty(string propertyName, string propertyValue) /// /// The test context messages added so far. public string? GetDiagnosticMessages() - => _stringWriter.ToString(); + => _testContextMessageStringBuilder?.ToString(); /// /// Clears the previous testContext writeline messages. /// public void ClearDiagnosticMessages() - => _threadSafeStringWriter?.ToStringAndClear(); + { + _testContextMessageStringBuilder?.Clear(); + (_stringWriter as ThreadSafeStringWriter)?.ToStringAndClear(); + } /// public void SetDisplayName(string? displayName) @@ -370,4 +333,103 @@ public void SetDisplayName(string? displayName) public override void DisplayMessage(MessageLevel messageLevel, string message) => _messageLogger?.SendMessage(messageLevel.ToTestMessageLevel(), message); #endregion + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// The dispose pattern. + /// + /// Whether to dispose managed state. + protected virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + _isDisposed = true; + + if (disposing) + { + _cancellationTokenRegistration?.Dispose(); + } + } + } + + internal readonly struct ScopedTestContextSetter : IDisposable + { + internal ScopedTestContextSetter(TestContextImplementation? testContext) + => CurrentTestContextAsyncLocal.Value = testContext; + + public void Dispose() + => CurrentTestContextAsyncLocal.Value = null; + } + + internal static ScopedTestContextSetter SetCurrentTestContext(TestContextImplementation? testContext) + => new(testContext); + + internal void WriteConsoleOut(char value) + => GetOutStringBuilder().Append(value); + + internal void WriteConsoleOut(string? value) + => GetOutStringBuilder().Append(value); + + internal void WriteConsoleOut(char[] buffer, int index, int count) + => GetOutStringBuilder().Append(buffer, index, count); + + internal void WriteConsoleErr(char value) + => GetErrStringBuilder().Append(value); + + internal void WriteConsoleErr(string? value) + => GetErrStringBuilder().Append(value); + + internal void WriteConsoleErr(char[] buffer, int index, int count) + => GetErrStringBuilder().Append(buffer, index, count); + + internal void WriteTrace(char value) + => GetTraceStringBuilder().Append(value); + + internal void WriteTrace(string? value) + => GetTraceStringBuilder().Append(value); + + private StringBuilder GetOutStringBuilder() + { + _ = _stdOutStringBuilder ?? Interlocked.CompareExchange(ref _stdOutStringBuilder, new StringBuilder(), null)!; + return _stdOutStringBuilder; + } + + private StringBuilder GetErrStringBuilder() + { + _ = _stdErrStringBuilder ?? Interlocked.CompareExchange(ref _stdErrStringBuilder, new StringBuilder(), null)!; + return _stdErrStringBuilder; + } + + private StringBuilder GetTraceStringBuilder() + { + _ = _traceStringBuilder ?? Interlocked.CompareExchange(ref _traceStringBuilder, new StringBuilder(), null)!; + return _traceStringBuilder; + } + + private StringBuilder GetTestContextMessagesStringBuilder() + { + // Prefer writing to the current test context instead of 'this'. + // This is just a hack to preserve backward compatibility. + // It's relevant for cases where users store 'TestContext' in a static field. + // Then, they write to the "wrong" test context. + // Here, we are correcting user's fault by finding out the correct TestContext that should receive the message. + TestContextImplementation @this = CurrentTestContext ?? this; + _ = @this._testContextMessageStringBuilder ?? Interlocked.CompareExchange(ref @this._testContextMessageStringBuilder, new StringBuilder(), null)!; + return @this._testContextMessageStringBuilder; + } + + internal string? GetOut() + => _stdOutStringBuilder?.ToString(); + + internal string? GetErr() + => _stdErrStringBuilder?.ToString(); + + internal string? GetTrace() + => _traceStringBuilder?.ToString(); } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs index 4f1a4f90d9..328576496c 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs @@ -24,9 +24,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// a ReflectionTypeLoadException. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TestDataSource : ITestDataSource { @@ -147,7 +147,7 @@ private static void GetConnectionProperties(DataSourceAttribute dataSourceAttrib providerNameInvariant = ConfigurationManager.ConnectionStrings[element.ConnectionString].ProviderName; connectionString = ConfigurationManager.ConnectionStrings[element.ConnectionString].ConnectionString; tableName = element.DataTableName; - dataAccessMethod = EnumPolyfill.Parse(element.DataAccessMethod); + dataAccessMethod = Enum.Parse(element.DataAccessMethod); } #endif } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs index 03a50cdfa3..bb745acf5b 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs @@ -23,9 +23,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// The test deployment. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TestDeployment : ITestDeployment { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSource.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSource.cs index c0cbeab9cd..b93d0aaa05 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSource.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSource.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AppContainer; #endif using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; +using Microsoft.VisualStudio.TestTools.UnitTesting; #if NETFRAMEWORK using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; #endif @@ -16,9 +17,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// the test sources provided to the adapter. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TestSource : ITestSource { @@ -27,22 +28,22 @@ public class TestSource : ITestSource private static readonly IEnumerable ExecutableExtensions = new HashSet() { - Constants.ExeExtension, + EngineConstants.ExeExtension, // Required only for store 8.1. In future if that support is needed, uncomment this. // Constants.DllExtension }; - private static readonly HashSet SystemAssemblies = new(new string[] - { + private static readonly HashSet SystemAssemblies = + [ "MICROSOFT.CSHARP.DLL", "MICROSOFT.VISUALBASIC.DLL", "CLRCOMPRESSION.DLL", - }); + ]; // Well known platform assemblies. - private static readonly HashSet PlatformAssemblies = new(new string[] - { + private static readonly HashSet PlatformAssemblies = + [ "MICROSOFT.VISUALSTUDIO.TESTPLATFORM.TESTFRAMEWORK.DLL", "MICROSOFT.VISUALSTUDIO.TESTPLATFORM.TESTFRAMEWORK.EXTENSIONS.CORE.DLL", "MICROSOFT.VISUALSTUDIO.TESTPLATFORM.CORE.DLL", @@ -54,7 +55,7 @@ public class TestSource : ITestSource "VSTEST_EXECUTIONENGINE_PLATFORMBRIDGE.DLL", "VSTEST_EXECUTIONENGINE_PLATFORMBRIDGE.WINMD", "VSTEST.EXECUTIONENGINE.WINDOWSPHONE.DLL", - }); + ]; #endif /// @@ -62,13 +63,13 @@ public class TestSource : ITestSource /// public IEnumerable ValidSourceExtensions => new List { - Constants.DllExtension, + EngineConstants.DllExtension, #if NETFRAMEWORK - Constants.PhoneAppxPackageExtension, + EngineConstants.PhoneAppxPackageExtension, #elif WINDOWS_UWP || WIN_UI - Constants.AppxPackageExtension, + EngineConstants.AppxPackageExtension, #endif - Constants.ExeExtension, + EngineConstants.ExeExtension, }; /// @@ -149,7 +150,7 @@ public IEnumerable GetTestSources(IEnumerable sources) { // WinUI Desktop uses .NET 6, which builds both a .dll and an .exe. // The manifest will provide the .exe, but the tests are inside the .dll, so we replace the name here. - newSources.Add(Path.Combine(appxSourceDirectory, Path.ChangeExtension(filePath, Constants.DllExtension))); + newSources.Add(Path.Combine(appxSourceDirectory, Path.ChangeExtension(filePath, EngineConstants.DllExtension))); } } @@ -170,7 +171,7 @@ private static bool ContainsAppxSource(IEnumerable sources) { foreach (string source in sources) { - if (string.Equals(Path.GetExtension(source), Constants.AppxPackageExtension, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(Path.GetExtension(source), EngineConstants.AppxPackageExtension, StringComparison.OrdinalIgnoreCase)) { return true; } @@ -190,7 +191,7 @@ private static bool ContainsAppxSource(IEnumerable sources) { foreach (string source in sources) { - if (string.Equals(Path.GetExtension(source), Constants.AppxPackageExtension, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(Path.GetExtension(source), EngineConstants.AppxPackageExtension, StringComparison.OrdinalIgnoreCase)) { return source; } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs index 54f530d721..a88a8d463e 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs @@ -22,9 +22,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// A host that loads the test source. This can be in isolation for desktop using an AppDomain or just loading the source in the current context. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TestSourceHost : ITestSourceHost { @@ -120,7 +120,7 @@ public void SetupHost() if (EqtTrace.IsInfoEnabled) { - EqtTrace.Info("DesktopTestSourceHost.SetupHost(): Creating assembly resolver with resolution paths {0}.", string.Join(",", resolutionPaths)); + EqtTrace.Info("DesktopTestSourceHost.SetupHost(): Creating assembly resolver with resolution paths {0}.", string.Join(',', resolutionPaths)); } var assemblyResolver = new AssemblyResolver(resolutionPaths); @@ -137,7 +137,7 @@ public void SetupHost() if (EqtTrace.IsInfoEnabled) { - EqtTrace.Info("DesktopTestSourceHost.SetupHost(): Creating assembly resolver with resolution paths {0}.", string.Join(",", resolutionPaths)); + EqtTrace.Info("DesktopTestSourceHost.SetupHost(): Creating assembly resolver with resolution paths {0}.", string.Join(',', resolutionPaths)); } // NOTE: These 2 lines are super important, see https://github.com/microsoft/testfx/issues/2922 @@ -221,19 +221,13 @@ public void SetupHost() public void Dispose() { #if NETFRAMEWORK || (NET && !WINDOWS_UWP) - if (_parentDomainAssemblyResolver != null) - { - _parentDomainAssemblyResolver.Dispose(); - _parentDomainAssemblyResolver = null; - } + _parentDomainAssemblyResolver?.Dispose(); + _parentDomainAssemblyResolver = null; #endif #if NETFRAMEWORK - if (_childDomainAssemblyResolver != null) - { - _childDomainAssemblyResolver.Dispose(); - _childDomainAssemblyResolver = null; - } + _childDomainAssemblyResolver?.Dispose(); + _childDomainAssemblyResolver = null; if (AppDomain != null) { @@ -346,7 +340,7 @@ internal string GetAppBaseAsPerPlatform() // UWP platform service assembly at the test source location and since CLR starts looking for assemblies from the app base location, // there would be a mismatch of platform service assemblies during discovery. DebugEx.Assert(_targetFrameworkVersion is not null, "Target framework version is null."); - return _targetFrameworkVersion.Contains(Constants.DotNetFrameWorkStringPrefix) + return _targetFrameworkVersion.Contains(EngineConstants.DotNetFrameWorkStringPrefix) ? Path.GetDirectoryName(_sourceFileName) ?? Path.GetDirectoryName(typeof(TestSourceHost).Assembly.Location) : Path.GetDirectoryName(typeof(TestSourceHost).Assembly.Location); } @@ -428,10 +422,6 @@ private static bool TryAddSearchDirectoriesSpecifiedInRunSettingsToAssemblyResol { // Check if user specified any adapter settings MSTestAdapterSettings adapterSettings = MSTestSettingsProvider.Settings; - if (adapterSettings == null) - { - return false; - } try { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadOperations.cs index 294ec53bfd..756793e443 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadOperations.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadOperations.cs @@ -10,9 +10,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// This service is responsible for any Async operations specific to a platform. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class ThreadOperations : IThreadOperations { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadSafeStringWriter.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadSafeStringWriter.cs index 821e25829d..3859b40cd8 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadSafeStringWriter.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadSafeStringWriter.cs @@ -7,9 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// AsyncContext aware, thread safe string writer that allows output writes from different threads to end up in the same async local context. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class ThreadSafeStringWriter : StringWriter { @@ -183,7 +183,7 @@ internal static void CleanState() { lock (StaticLockObject) { - State.Value = new(); + State.Value = []; } } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListener.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListener.cs index 5308c23d72..485b351528 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListener.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListener.cs @@ -13,9 +13,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// like Close(), Dispose() etc. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TraceListenerWrapper : #if !WINDOWS_UWP && !WIN_UI diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListenerManager.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListenerManager.cs index e811d1cd15..1e427fc766 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListenerManager.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListenerManager.cs @@ -10,9 +10,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// Responsible for performing Add(), Remove(), Close(), Dispose() operations on traceListener object. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class TraceListenerManager : ITraceListenerManager { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceLogger.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceLogger.cs index 44baf76b71..982509eaef 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceLogger.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceLogger.cs @@ -10,9 +10,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; /// A service to log any trace messages from the adapter that would be shown in *.TpTrace files. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public class AdapterTraceLogger : IAdapterTraceLogger { diff --git a/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs b/src/Adapter/MSTestAdapter.PlatformServices/TestMethodFilter.cs similarity index 92% rename from src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs rename to src/Adapter/MSTestAdapter.PlatformServices/TestMethodFilter.cs index a713f7acc8..33f554a96c 100644 --- a/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/TestMethodFilter.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; @@ -17,12 +18,12 @@ internal sealed class TestMethodFilter internal TestMethodFilter() => _supportedProperties = new Dictionary(StringComparer.OrdinalIgnoreCase) { - [Constants.TestCategoryProperty.Label] = Constants.TestCategoryProperty, - [Constants.PriorityProperty.Label] = Constants.PriorityProperty, + [EngineConstants.TestCategoryProperty.Label] = EngineConstants.TestCategoryProperty, + [EngineConstants.PriorityProperty.Label] = EngineConstants.PriorityProperty, [TestCaseProperties.FullyQualifiedName.Label] = TestCaseProperties.FullyQualifiedName, [TestCaseProperties.DisplayName.Label] = TestCaseProperties.DisplayName, [TestCaseProperties.Id.Label] = TestCaseProperties.Id, - [Constants.TestClassNameProperty.Label] = Constants.TestClassNameProperty, + [EngineConstants.TestClassNameProperty.Label] = EngineConstants.TestClassNameProperty, }; /// @@ -124,15 +125,14 @@ internal TestProperty PropertyProvider(string propertyName) MethodInfo? methodGetTestCaseFilter = context.GetType().GetRuntimeMethod("GetTestCaseFilter", [typeof(IEnumerable), typeof(Func)]); return (ITestCaseFilterExpression?)methodGetTestCaseFilter?.Invoke(context, [_supportedProperties.Keys, (Func)PropertyProvider]); } - catch (Exception ex) + catch (TargetInvocationException ex) { // In case of UWP .Net Native Tool Chain compilation. Invoking methods via Reflection doesn't work, hence discovery always fails. // Hence throwing exception only if it is of type TargetInvocationException(i.e. Method got invoked but something went wrong in GetTestCaseFilter Method) - if (ex is TargetInvocationException) - { - throw ex.InnerException!; - } - + throw ex.InnerException!; + } + catch (Exception ex) + { logger.SendMessage(TestMessageLevel.Warning, ex.Message); } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainUtilities.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainUtilities.cs index a80126e0b1..a4151b99a3 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainUtilities.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainUtilities.cs @@ -42,7 +42,7 @@ internal static void SetAppDomainFrameworkVersionBasedOnTestSource(AppDomainSetu { if (GetTargetFrameworkVersionFromVersionString(frameworkVersionString).CompareTo(Version45) > 0) { - PropertyInfo? pInfo = typeof(AppDomainSetup).GetProperty(Constants.TargetFrameworkName); + PropertyInfo? pInfo = typeof(AppDomainSetup).GetProperty(EngineConstants.TargetFrameworkName); pInfo?.SetValue(setup, frameworkVersionString, null); } } @@ -227,9 +227,9 @@ internal static Version GetTargetFrameworkVersionFromVersionString(string versio { try { - if (version.Length > Constants.DotNetFrameWorkStringPrefix.Length + 1) + if (version.Length > EngineConstants.DotNetFrameWorkStringPrefix.Length + 1) { - string versionPart = version.Substring(Constants.DotNetFrameWorkStringPrefix.Length + 1); + string versionPart = version.Substring(EngineConstants.DotNetFrameWorkStringPrefix.Length + 1); return new Version(versionPart); } } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs index bd8c0d78e6..892345da66 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs @@ -212,7 +212,7 @@ private static List GetDeploymentItems(IEnumerable deploymentIte return deploymentItemList1; } - IList result = new List(deploymentItemList1); + IList result = [.. deploymentItemList1]; foreach (DeploymentItem item in deploymentItemList2) { @@ -227,7 +227,7 @@ private static List GetDeploymentItems(IEnumerable deploymentIte /// /// The test Case. /// The . - private static KeyValuePair[]? GetDeploymentItems(TestCase testCase) => testCase.GetPropertyValue(Constants.DeploymentItemsProperty) as + private static KeyValuePair[]? GetDeploymentItems(TestCase testCase) => testCase.GetPropertyValue(EngineConstants.DeploymentItemsProperty) as KeyValuePair[]; private static KeyValuePair[]? ToKeyValuePairs(IEnumerable deploymentItemList) @@ -247,7 +247,7 @@ private static List GetDeploymentItems(IEnumerable deploymentIte } } - return result.ToArray(); + return [.. result]; } private static IList? FromKeyValuePairs(KeyValuePair[] deploymentItemsData) @@ -257,7 +257,7 @@ private static List GetDeploymentItems(IEnumerable deploymentIte return null; } - IList result = new List(); + IList result = []; foreach ((string? key, string? value) in deploymentItemsData) { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs index af43490bde..e7f32535b3 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs @@ -62,11 +62,7 @@ public override void AddDeploymentItemsBasedOnMsTestSetting(string testSource, I /// Root deployment directory. public override string GetRootDeploymentDirectory(string baseDirectory) { -#if NETFRAMEWORK || NETSTANDARD || NETCOREAPP3_1 - string dateTimeSuffix = $"{DateTime.Now.ToString("yyyyMMddTHHmmss", DateTimeFormatInfo.InvariantInfo)}_{Process.GetCurrentProcess().Id}"; -#else string dateTimeSuffix = $"{DateTime.Now.ToString("yyyyMMddTHHmmss", DateTimeFormatInfo.InvariantInfo)}_{Environment.ProcessId}"; -#endif string directoryName = string.Format(CultureInfo.InvariantCulture, Resource.TestRunName, DeploymentFolderPrefix, #if NETFRAMEWORK Environment.UserName, diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs index 21de3f1a79..7b2f77a9a6 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs @@ -407,7 +407,7 @@ private bool Deploy(string source, IRunContext? runContext, ITestExecutionRecord // Do the deployment. EqtTrace.InfoIf(EqtTrace.IsInfoEnabled, "MSTestExecutor: Using deployment directory {0} for source {1}.", runDirectories.OutDirectory, source); - IEnumerable warnings = Deploy(new List(deploymentItems), source, runDirectories.OutDirectory, GetTestResultsDirectory(runContext)); + IEnumerable warnings = Deploy([.. deploymentItems], source, runDirectories.OutDirectory, GetTestResultsDirectory(runContext)); // Log warnings LogWarnings(testExecutionRecorder, warnings); diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs index b9fe555b32..1ef57c713c 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs @@ -126,7 +126,7 @@ internal static List GetCustomAttributes(Assembly assembly, Type type { if (!assembly.ReflectionOnly) { - return assembly.GetCustomAttributes(type).ToList(); + return [.. assembly.GetCustomAttributes(type)]; } List customAttributes = [.. CustomAttributeData.GetCustomAttributes(assembly)]; @@ -195,8 +195,8 @@ internal static List GetCustomAttributes(Assembly assembly, Type type constructorArguments.Add(list.ToArray(parameterType.GetElementType())); } - ConstructorInfo constructor = attributeType.GetConstructor(constructorParameters.ToArray()); - attribute = constructor.Invoke(constructorArguments.ToArray()); + ConstructorInfo constructor = attributeType.GetConstructor([.. constructorParameters]); + attribute = constructor.Invoke([.. constructorArguments]); foreach (CustomAttributeNamedArgument namedArgument in attributeData.NamedArguments) { diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/VSInstallationUtilities.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/VSInstallationUtilities.cs index 3083c603c8..07b01ef1dc 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/VSInstallationUtilities.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/VSInstallationUtilities.cs @@ -11,9 +11,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Uti /// Utilities to get Visual Studio installation paths. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(TestTools.UnitTesting.FrameworkConstants.PublicTypeObsoleteMessage)] #endif public static class VSInstallationUtilities { diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/AddTestClassFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/AddTestClassFixer.cs index 2b6488f8de..bca1789d1b 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/AddTestClassFixer.cs +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/AddTestClassFixer.cs @@ -52,13 +52,36 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) // Find the type declaration identified by the diagnostic. TypeDeclarationSyntax declaration = syntaxToken.Parent.AncestorsAndSelf().OfType().First(); - // Register a code action that will invoke the fix. - context.RegisterCodeFix( - CodeAction.Create( - title: CodeFixResources.AddTestClassFix, - createChangedDocument: c => AddTestClassAttributeAsync(context.Document, declaration, c), - equivalenceKey: $"{nameof(AddTestClassFixer)}_{diagnostic.Id}"), - diagnostic); + // For structs and record structs, we need to change them to classes/record classes since [TestClass] cannot be applied to structs + if (declaration is StructDeclarationSyntax) + { + context.RegisterCodeFix( + CodeAction.Create( + title: CodeFixResources.ChangeStructToClassAndAddTestClassFix, + createChangedDocument: c => ChangeStructToClassAndAddTestClassAttributeAsync(context.Document, declaration, c), + equivalenceKey: $"{nameof(AddTestClassFixer)}_ChangeStructToClass_{diagnostic.Id}"), + diagnostic); + } + else if (declaration is RecordDeclarationSyntax recordDeclaration + && recordDeclaration.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword)) + { + context.RegisterCodeFix( + CodeAction.Create( + title: CodeFixResources.ChangeStructToClassAndAddTestClassFix, + createChangedDocument: c => ChangeRecordStructToRecordClassAndAddTestClassAttributeAsync(context.Document, recordDeclaration, c), + equivalenceKey: $"{nameof(AddTestClassFixer)}_ChangeRecordStructToClass_{diagnostic.Id}"), + diagnostic); + } + else + { + // For classes and record classes, just add the [TestClass] attribute + context.RegisterCodeFix( + CodeAction.Create( + title: CodeFixResources.AddTestClassFix, + createChangedDocument: c => AddTestClassAttributeAsync(context.Document, declaration, c), + equivalenceKey: $"{nameof(AddTestClassFixer)}_{diagnostic.Id}"), + diagnostic); + } } private static async Task AddTestClassAttributeAsync(Document document, TypeDeclarationSyntax typeDeclaration, CancellationToken cancellationToken) @@ -75,4 +98,67 @@ private static async Task AddTestClassAttributeAsync(Document document SyntaxNode newRoot = editor.GetChangedRoot(); return document.WithSyntaxRoot(newRoot); } + + private static async Task ChangeStructToClassAndAddTestClassAttributeAsync(Document document, TypeDeclarationSyntax structDeclaration, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); + + // Create the [TestClass] attribute + AttributeSyntax testClassAttribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName("TestClass")); + AttributeListSyntax attributeList = SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(testClassAttribute)); + + // Convert struct to class + ClassDeclarationSyntax classDeclaration = SyntaxFactory.ClassDeclaration(structDeclaration.Identifier) + .WithModifiers(structDeclaration.Modifiers) + .WithTypeParameterList(structDeclaration.TypeParameterList) + .WithConstraintClauses(structDeclaration.ConstraintClauses) + .WithBaseList(structDeclaration.BaseList) + .WithMembers(structDeclaration.Members) + .WithAttributeLists(structDeclaration.AttributeLists.Add(attributeList)) + .WithLeadingTrivia(structDeclaration.GetLeadingTrivia()) + .WithTrailingTrivia(structDeclaration.GetTrailingTrivia()); + + editor.ReplaceNode(structDeclaration, classDeclaration); + + SyntaxNode newRoot = editor.GetChangedRoot(); + return document.WithSyntaxRoot(newRoot); + } + + private static async Task ChangeRecordStructToRecordClassAndAddTestClassAttributeAsync(Document document, RecordDeclarationSyntax recordStructDeclaration, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); + + // Create the [TestClass] attribute + AttributeSyntax testClassAttribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName("TestClass")); + AttributeListSyntax attributeList = SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(testClassAttribute)); + + // Filter out readonly modifier since it's not valid for record classes + SyntaxTokenList filteredModifiers = SyntaxFactory.TokenList( + recordStructDeclaration.Modifiers.Where(modifier => !modifier.IsKind(SyntaxKind.ReadOnlyKeyword))); + + // Convert record struct to record class by creating a new RecordDeclarationSyntax + // We need to create a new record declaration instead of just changing the keyword + RecordDeclarationSyntax recordClassDeclaration = SyntaxFactory.RecordDeclaration( + recordStructDeclaration.Keyword, + recordStructDeclaration.Identifier) + .WithModifiers(filteredModifiers) + .WithTypeParameterList(recordStructDeclaration.TypeParameterList) + .WithParameterList(recordStructDeclaration.ParameterList) + .WithBaseList(recordStructDeclaration.BaseList) + .WithConstraintClauses(recordStructDeclaration.ConstraintClauses) + .WithOpenBraceToken(recordStructDeclaration.OpenBraceToken) + .WithMembers(recordStructDeclaration.Members) + .WithCloseBraceToken(recordStructDeclaration.CloseBraceToken) + .WithSemicolonToken(recordStructDeclaration.SemicolonToken) + .WithAttributeLists(recordStructDeclaration.AttributeLists.Add(attributeList)) + .WithLeadingTrivia(recordStructDeclaration.GetLeadingTrivia()) + .WithTrailingTrivia(recordStructDeclaration.GetTrailingTrivia()); + + editor.ReplaceNode(recordStructDeclaration, recordClassDeclaration); + + SyntaxNode newRoot = editor.GetChangedRoot(); + return document.WithSyntaxRoot(newRoot); + } } diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldAvoidConditionalAccessFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldAvoidConditionalAccessFixer.cs index 830253f2e4..8e5eefd5e2 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldAvoidConditionalAccessFixer.cs +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldAvoidConditionalAccessFixer.cs @@ -40,7 +40,7 @@ private sealed class CustomFixAll : DocumentBasedFixAllProvider protected override async Task FixAllAsync(FixAllContext fixAllContext, Document document, ImmutableArray diagnostics) { SyntaxNode root = await document.GetRequiredSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); - DocumentEditor editor = await DocumentEditor.CreateAsync(document, fixAllContext.CancellationToken); + DocumentEditor editor = await DocumentEditor.CreateAsync(document, fixAllContext.CancellationToken).ConfigureAwait(false); Document currentDocument = document; foreach (Diagnostic diagnostic in diagnostics) { diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.Designer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.Designer.cs index 9cab8f2e12..39751da4c0 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.Designer.cs +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.Designer.cs @@ -114,6 +114,15 @@ internal static string ChangeMethodAccessibilityToPrivateFix { } } + /// + /// Looks up a localized string similar to Change to 'class' and add '[TestClass]'. + /// + internal static string ChangeStructToClassAndAddTestClassFix { + get { + return ResourceManager.GetString("ChangeStructToClassAndAddTestClassFix", resourceCulture); + } + } + /// /// Looks up a localized string similar to Fix actual/expected arguments order. /// @@ -132,6 +141,24 @@ internal static string FixSignatureCodeFix { } } + /// + /// Looks up a localized string similar to Pass 'TestContext.CancellationTokenSource.Token' argument to method call. + /// + internal static string PassCancellationTokenFix { + get { + return ResourceManager.GetString("PassCancellationTokenFix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Replace 'DataTestMethod' with 'TestMethod'. + /// + internal static string ReplaceDataTestMethodWithTestMethodTitle { + get { + return ResourceManager.GetString("ReplaceDataTestMethodWithTestMethodTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to Replace TestInitialize method with constructor. /// @@ -177,6 +204,15 @@ internal static string ReplaceWithTestInitializeFix { } } + /// + /// Looks up a localized string similar to Use 'Assert.{0}' instead of 'StringAssert'. + /// + internal static string StringAssertToAssertTitle { + get { + return ResourceManager.GetString("StringAssertToAssertTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to Fix test class signature. /// @@ -222,6 +258,15 @@ internal static string UseAttributeOnTestMethodFix { } } + /// + /// Looks up a localized string similar to Use 'CooperativeCancellation = true'. + /// + internal static string UseCooperativeCancellationForTimeoutFix { + get { + return ResourceManager.GetString("UseCooperativeCancellationForTimeoutFix", resourceCulture); + } + } + /// /// Looks up a localized string similar to Use '{0}'. /// diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.resx b/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.resx index 27cd7731e9..5c5033b0df 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.resx +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.resx @@ -129,6 +129,9 @@ Add '[TestClass]' + + Change to 'class' and add '[TestClass]' + Fix test method signature @@ -177,4 +180,16 @@ Use '{0}' + + Replace 'DataTestMethod' with 'TestMethod' + + + Use 'CooperativeCancellation = true' + + + Use 'Assert.{0}' instead of 'StringAssert' + + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/FlowTestContextCancellationTokenFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/FlowTestContextCancellationTokenFixer.cs new file mode 100644 index 0000000000..0941d05e6c --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/FlowTestContextCancellationTokenFixer.cs @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Composition; + +using Analyzer.Utilities; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Text; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// Code fixer for . +/// +[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(FlowTestContextCancellationTokenFixer))] +[Shared] +public sealed class FlowTestContextCancellationTokenFixer : CodeFixProvider +{ + /// + public sealed override ImmutableArray FixableDiagnosticIds { get; } + = ImmutableArray.Create(DiagnosticIds.FlowTestContextCancellationTokenRuleId); + + /// + public override FixAllProvider GetFixAllProvider() + // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/FixAllProvider.md for more information on Fix All Providers + => WellKnownFixAllProviders.BatchFixer; + + /// + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + SyntaxNode root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + Diagnostic diagnostic = context.Diagnostics[0]; + TextSpan diagnosticSpan = diagnostic.Location.SourceSpan; + + // Find the invocation expression identified by the diagnostic + SyntaxNode node = root.FindNode(diagnosticSpan, getInnermostNodeForTie: true); + if (node is not InvocationExpressionSyntax invocationExpression) + { + return; + } + + diagnostic.Properties.TryGetValue(FlowTestContextCancellationTokenAnalyzer.TestContextMemberNamePropertyKey, out string? testContextMemberName); + + // Register a code action that will invoke the fix + context.RegisterCodeFix( + CodeAction.Create( + title: CodeFixResources.PassCancellationTokenFix, + createChangedDocument: c => AddCancellationTokenParameterAsync(context.Document, invocationExpression, testContextMemberName, c), + equivalenceKey: "AddTestContextCancellationToken"), + diagnostic); + } + + private static async Task AddCancellationTokenParameterAsync( + Document document, + InvocationExpressionSyntax invocationExpression, + string? testContextMemberName, + CancellationToken cancellationToken) + { + DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); + + // Create the TestContext.CancellationTokenSource.Token expression + MemberAccessExpressionSyntax testContextExpression = SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName(testContextMemberName ?? "testContext"), + SyntaxFactory.IdentifierName("CancellationTokenSource")), + SyntaxFactory.IdentifierName("Token")); + + ArgumentListSyntax currentArguments = invocationExpression.ArgumentList; + SeparatedSyntaxList newArguments = currentArguments.Arguments.Add(SyntaxFactory.Argument(testContextExpression)); + InvocationExpressionSyntax newInvocation = invocationExpression.WithArgumentList(currentArguments.WithArguments(newArguments)); + editor.ReplaceNode(invocationExpression, newInvocation); + return editor.GetChangedDocument(); + } +} diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferConstructorOverTestInitializeFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferConstructorOverTestInitializeFixer.cs index efeecd6dbd..2c0f2df3fb 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferConstructorOverTestInitializeFixer.cs +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferConstructorOverTestInitializeFixer.cs @@ -68,7 +68,7 @@ private static async Task ReplaceTestInitializeWithConstructorAsync(Do { ConstructorDeclarationSyntax? existingConstructor = containingClass.Members .OfType() - .FirstOrDefault(); + .FirstOrDefault(c => !c.Modifiers.Any(SyntaxKind.StaticKeyword)); // Move the body of the TestInitialize method BlockSyntax? testInitializeBody = testInitializeMethod.Body; @@ -81,7 +81,7 @@ private static async Task ReplaceTestInitializeWithConstructorAsync(Do // If a constructor already exists, append the body of the TestInitialize method to it if (existingConstructor.Body != null) { - BlockSyntax newConstructorBody = existingConstructor.Body.AddStatements(testInitializeStatements ?? Array.Empty()); + BlockSyntax newConstructorBody = existingConstructor.Body.AddStatements(testInitializeStatements ?? []); newConstructor = existingConstructor.WithBody(newConstructorBody); } else @@ -90,19 +90,20 @@ private static async Task ReplaceTestInitializeWithConstructorAsync(Do } editor.ReplaceNode(existingConstructor, newConstructor); + + // Remove the TestInitialize method + editor.RemoveNode(testInitializeMethod); } else { // Create a new constructor with the TestInitialize body if one doesn't exist - ConstructorDeclarationSyntax constructor = SyntaxFactory.ConstructorDeclaration(containingClass.Identifier) + ConstructorDeclarationSyntax constructor = SyntaxFactory.ConstructorDeclaration(containingClass.Identifier.WithoutTrivia()) .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) .WithBody(testInitializeBody); - editor.AddMember(containingClass, constructor); + // Insert the constructor at the position of the existing TestInitialize method + editor.ReplaceNode(testInitializeMethod, constructor); } - - // Remove the TestInitialize method - editor.RemoveNode(testInitializeMethod); } return editor.GetChangedDocument(); diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferDisposeOverTestCleanupFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferDisposeOverTestCleanupFixer.cs index 9911ee7287..309ccadb67 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferDisposeOverTestCleanupFixer.cs +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferDisposeOverTestCleanupFixer.cs @@ -69,7 +69,7 @@ private static bool IsTestCleanupMethodValid(MethodDeclarationSyntax methodDecla methodDeclaration.ReturnType is PredefinedTypeSyntax predefinedType && predefinedType.Keyword.IsKind(SyntaxKind.VoidKeyword); - private static async Task AddDisposeAndBaseClassAsync( + private static async Task AddDisposeAndBaseClassAsync( Document document, MethodDeclarationSyntax testCleanupMethod, TypeDeclarationSyntax containingType, @@ -82,23 +82,54 @@ private static async Task AddDisposeAndBaseClassAsync( SyntaxGenerator generator = editor.Generator; TypeDeclarationSyntax newParent = containingType; INamedTypeSymbol? iDisposableSymbol = semanticModel.Compilation.GetTypeByMetadataName(WellKnownTypeNames.SystemIDisposable); - INamedTypeSymbol? testCleanupAttributeSymbol = semanticModel.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestCleanupAttribute); // Move the code from TestCleanup to Dispose method - MethodDeclarationSyntax? existingDisposeMethod = containingType.Members - .OfType() - .FirstOrDefault(m => semanticModel.GetDeclaredSymbol(m) is IMethodSymbol methodSymbol && methodSymbol.IsDisposeImplementation(iDisposableSymbol)); + // For partial classes, we need to check all parts of the type, not just the current partial declaration + Document? disposeDocument = null; + MethodDeclarationSyntax? existingDisposeMethod = null; + if (semanticModel.GetDeclaredSymbol(containingType, cancellationToken) is INamedTypeSymbol typeSymbol) + { + // Find existing Dispose method in any part of the partial class + IMethodSymbol? existingDisposeSymbol = typeSymbol.GetMembers("Dispose") + .OfType() + .FirstOrDefault(m => m.IsDisposeImplementation(iDisposableSymbol)); + + if (existingDisposeSymbol is not null) + { + // Find the syntax node for the existing Dispose method + foreach (SyntaxReference syntaxRef in existingDisposeSymbol.DeclaringSyntaxReferences) + { + if (await syntaxRef.GetSyntaxAsync(cancellationToken).ConfigureAwait(false) is MethodDeclarationSyntax methodSyntax) + { + existingDisposeMethod = methodSyntax; + // Find the document containing the Dispose method + foreach (Document projectDocument in document.Project.Documents) + { + SyntaxTree? docSyntaxTree = await projectDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + if (docSyntaxTree == syntaxRef.SyntaxTree) + { + disposeDocument = projectDocument; + break; + } + } + + break; + } + } + } + } BlockSyntax? cleanupBody = testCleanupMethod.Body; + Solution solution = document.Project.Solution; - if (existingDisposeMethod != null) + if (existingDisposeMethod is not null && disposeDocument is not null) { // Append the TestCleanup body to the existing Dispose method StatementSyntax[]? cleanupStatements = cleanupBody?.Statements.ToArray(); MethodDeclarationSyntax newDisposeMethod; - if (existingDisposeMethod.Body != null) + if (existingDisposeMethod.Body is not null) { - BlockSyntax newDisposeBody = existingDisposeMethod.Body.AddStatements(cleanupStatements ?? Array.Empty()); + BlockSyntax newDisposeBody = existingDisposeMethod.Body.AddStatements(cleanupStatements ?? []); newDisposeMethod = existingDisposeMethod.WithBody(newDisposeBody); } else @@ -106,8 +137,24 @@ private static async Task AddDisposeAndBaseClassAsync( newDisposeMethod = existingDisposeMethod.WithBody(cleanupBody); } - editor.ReplaceNode(existingDisposeMethod, newDisposeMethod); - editor.RemoveNode(testCleanupMethod); + if (disposeDocument.Id == document.Id) + { + // Both methods are in the same document, use single editor + editor.ReplaceNode(existingDisposeMethod, newDisposeMethod); + editor.RemoveNode(testCleanupMethod); + solution = solution.WithDocumentSyntaxRoot(document.Id, editor.GetChangedRoot()); + } + else + { + // Methods are in different documents, use separate editors + DocumentEditor disposeEditor = await DocumentEditor.CreateAsync(disposeDocument, cancellationToken).ConfigureAwait(false); + disposeEditor.ReplaceNode(existingDisposeMethod, newDisposeMethod); + solution = solution.WithDocumentSyntaxRoot(disposeDocument.Id, disposeEditor.GetChangedRoot()); + + // Remove the TestCleanup method from the current document + editor.RemoveNode(testCleanupMethod); + solution = solution.WithDocumentSyntaxRoot(document.Id, editor.GetChangedRoot()); + } } else { @@ -123,9 +170,10 @@ private static async Task AddDisposeAndBaseClassAsync( } editor.ReplaceNode(containingType, newParent); + solution = solution.WithDocumentSyntaxRoot(document.Id, editor.GetChangedRoot()); } - return editor.GetChangedDocument(); + return solution; } private static bool ImplementsIDisposable(TypeDeclarationSyntax typeDeclaration, INamedTypeSymbol iDisposableSymbol, SemanticModel semanticModel) diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestInitializeOverConstructorFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestInitializeOverConstructorFixer.cs index 9ea85da311..5961aa1747 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestInitializeOverConstructorFixer.cs +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestInitializeOverConstructorFixer.cs @@ -86,7 +86,7 @@ private static async Task ReplaceConstructorWithTestInitializeAsync(Do MethodDeclarationSyntax newTestInitialize; if (existingTestInitialize.Body != null) { - BlockSyntax newTestInitializeBody = existingTestInitialize.Body.AddStatements(constructorStatements ?? Array.Empty()); + BlockSyntax newTestInitializeBody = existingTestInitialize.Body.AddStatements(constructorStatements ?? []); newTestInitialize = existingTestInitialize.WithBody(newTestInitializeBody); } else diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestMethodOverDataTestMethodFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestMethodOverDataTestMethodFixer.cs new file mode 100644 index 0000000000..580a90cb3e --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestMethodOverDataTestMethodFixer.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Composition; + +using Analyzer.Utilities; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// Code fixer for . +/// +[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(PreferTestMethodOverDataTestMethodFixer))] +[Shared] +public sealed class PreferTestMethodOverDataTestMethodFixer : CodeFixProvider +{ + /// + public override ImmutableArray FixableDiagnosticIds { get; } + = ImmutableArray.Create(DiagnosticIds.PreferTestMethodOverDataTestMethodRuleId); + + /// + public override FixAllProvider GetFixAllProvider() + => WellKnownFixAllProviders.BatchFixer; + + /// + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + SyntaxNode root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + + foreach (Diagnostic diagnostic in context.Diagnostics) + { + SyntaxNode? diagnosticNode = root?.FindNode(diagnostic.Location.SourceSpan); + if (diagnosticNode is not AttributeSyntax attributeSyntax) + { + continue; + } + + // Replace DataTestMethod with TestMethod + var action = CodeAction.Create( + title: CodeFixResources.ReplaceDataTestMethodWithTestMethodTitle, + createChangedDocument: c => Task.FromResult(ReplaceDataTestMethod(context.Document, root!, attributeSyntax)), + equivalenceKey: nameof(PreferTestMethodOverDataTestMethodFixer)); + + context.RegisterCodeFix(action, diagnostic); + } + } + + private static Document ReplaceDataTestMethod(Document document, SyntaxNode root, AttributeSyntax attributeSyntax) + { + AttributeSyntax newAttribute = attributeSyntax.WithName(SyntaxFactory.IdentifierName("TestMethod")); + SyntaxNode newRoot = root.ReplaceNode(attributeSyntax, newAttribute); + + return document.WithSyntaxRoot(newRoot); + } +} diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/StringAssertToAssertFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/StringAssertToAssertFixer.cs new file mode 100644 index 0000000000..735626a8d1 --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/StringAssertToAssertFixer.cs @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Composition; + +using Analyzer.Utilities; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers.CodeFixes; + +/// +/// Code fixer for . +/// +[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(StringAssertToAssertFixer))] +[Shared] +public sealed class StringAssertToAssertFixer : CodeFixProvider +{ + /// + public override ImmutableArray FixableDiagnosticIds { get; } + = ImmutableArray.Create(DiagnosticIds.StringAssertToAssertRuleId); + + /// + public sealed override FixAllProvider GetFixAllProvider() + // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/FixAllProvider.md for more information on Fix All Providers + => WellKnownFixAllProviders.BatchFixer; + + /// + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + SyntaxNode? root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + + Diagnostic diagnostic = context.Diagnostics[0]; + if (!diagnostic.Properties.TryGetValue(StringAssertToAssertAnalyzer.ProperAssertMethodNameKey, out string? properAssertMethodName) + || properAssertMethodName == null) + { + return; + } + + if (root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is not InvocationExpressionSyntax invocationExpressionSyntax) + { + return; + } + + // Register a code fix that will invoke the fix operation. + string title = string.Format(CultureInfo.InvariantCulture, CodeFixResources.StringAssertToAssertTitle, properAssertMethodName); + var action = CodeAction.Create( + title: title, + createChangedDocument: ct => FixStringAssertAsync(context.Document, invocationExpressionSyntax, properAssertMethodName, ct), + equivalenceKey: title); + + context.RegisterCodeFix(action, diagnostic); + } + + private static async Task FixStringAssertAsync( + Document document, + InvocationExpressionSyntax invocationExpr, + string properAssertMethodName, + CancellationToken cancellationToken) + { + // Check if the invocation expression has a member access expression + if (invocationExpr.Expression is not MemberAccessExpressionSyntax memberAccessExpr) + { + return document; + } + + SeparatedSyntaxList arguments = invocationExpr.ArgumentList.Arguments; + if (arguments.Count < 2) + { + return document; + } + + DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); + + // Create new argument list with swapped first two arguments + ArgumentSyntax[] newArguments = [.. arguments]; + (newArguments[0], newArguments[1]) = (newArguments[1], newArguments[0]); + + ArgumentListSyntax newArgumentList = SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(newArguments)); + InvocationExpressionSyntax newInvocationExpr = invocationExpr.WithArgumentList(newArgumentList); + + // Replace StringAssert with Assert in the member access expression + // Change StringAssert.MethodName to Assert.ProperMethodName + MemberAccessExpressionSyntax newMemberAccess = memberAccessExpr.WithExpression(SyntaxFactory.IdentifierName("Assert")) + .WithName(SyntaxFactory.IdentifierName(properAssertMethodName)); + newInvocationExpr = newInvocationExpr.WithExpression(newMemberAccess); + + editor.ReplaceNode(invocationExpr, newInvocationExpr); + return editor.GetChangedDocument(); + } +} diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/TestContextShouldBeValidFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/TestContextShouldBeValidFixer.cs index c15765fa46..14639ce961 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/TestContextShouldBeValidFixer.cs +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/TestContextShouldBeValidFixer.cs @@ -62,9 +62,6 @@ private static async Task FixMemberDeclarationAsync(Document document, { cancellationToken.ThrowIfCancellationRequested(); - // Get the SemanticModel and Compilation - SemanticModel semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); // Remove the static and readonly modifiers if it exists @@ -103,7 +100,7 @@ private static async Task FixMemberDeclarationAsync(Document document, AccessorDeclarationSyntax setAccessor = accessors.FirstOrDefault(a => a.Kind() == SyntaxKind.SetAccessorDeclaration) ?? SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); - newMemberDeclaration = propertyDeclaration.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(new[] { getAccessor, setAccessor }))); + newMemberDeclaration = propertyDeclaration.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List([getAccessor, setAccessor]))); } // Create a new member declaration with the updated modifiers. @@ -121,13 +118,13 @@ private static PropertyDeclarationSyntax ConvertFieldToProperty(FieldDeclaration PropertyDeclarationSyntax propertyDeclaration = SyntaxFactory.PropertyDeclaration(type, TestContextShouldBeValidAnalyzer.TestContextPropertyName) .WithModifiers(SyntaxFactory.TokenList(fieldDeclaration.Modifiers)) .WithAccessorList(SyntaxFactory.AccessorList( - SyntaxFactory.List(new[] - { + SyntaxFactory.List( + [ SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) - .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), - }))); + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) + ]))); return propertyDeclaration; } diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/TestMethodShouldBeValidCodeFix.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/TestMethodShouldBeValidCodeFix.cs index 0facc4173f..f7bf2b94e9 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/TestMethodShouldBeValidCodeFix.cs +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/TestMethodShouldBeValidCodeFix.cs @@ -98,7 +98,6 @@ private static async Task FixTestMethodAsync(Document document, Method // Ensure the method returns void or Task/ValueTask. SemanticModel semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - Compilation compilation = semanticModel.Compilation; var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(semanticModel.Compilation); INamedTypeSymbol? taskSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask); INamedTypeSymbol? valueTaskSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask); diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/UseCooperativeCancellationForTimeoutFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/UseCooperativeCancellationForTimeoutFixer.cs new file mode 100644 index 0000000000..a3052a78f1 --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/UseCooperativeCancellationForTimeoutFixer.cs @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Composition; + +using Analyzer.Utilities; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Text; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// Code fixer for . +/// +[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseCooperativeCancellationForTimeoutFixer))] +[Shared] +public sealed class UseCooperativeCancellationForTimeoutFixer : CodeFixProvider +{ + /// + public sealed override ImmutableArray FixableDiagnosticIds { get; } + = ImmutableArray.Create(DiagnosticIds.UseCooperativeCancellationForTimeoutRuleId); + + /// + public override FixAllProvider GetFixAllProvider() + // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/FixAllProvider.md for more information on Fix All Providers + => WellKnownFixAllProviders.BatchFixer; + + /// + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + SyntaxNode root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + Diagnostic diagnostic = context.Diagnostics[0]; + TextSpan diagnosticSpan = diagnostic.Location.SourceSpan; + + // Find the attribute syntax node identified by the diagnostic + SyntaxNode attributeNode = root.FindNode(diagnosticSpan, getInnermostNodeForTie: true); + if (attributeNode is not AttributeSyntax attributeSyntax) + { + return; + } + + // Register a code action that will invoke the fix + context.RegisterCodeFix( + CodeAction.Create( + title: CodeFixResources.UseCooperativeCancellationForTimeoutFix, + createChangedDocument: c => AddCooperativeCancellationAsync(context.Document, attributeSyntax, c), + equivalenceKey: nameof(UseCooperativeCancellationForTimeoutFixer)), + diagnostic); + } + + private static async Task AddCooperativeCancellationAsync(Document document, AttributeSyntax attributeSyntax, CancellationToken cancellationToken) + { + DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); + + AttributeSyntax newAttributeSyntax; + + if (attributeSyntax.ArgumentList == null) + { + // No argument list exists, create one with CooperativeCancellation = true + AttributeArgumentSyntax cooperativeCancellationArg = SyntaxFactory.AttributeArgument( + SyntaxFactory.NameEquals("CooperativeCancellation"), + null, + SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression)); + + newAttributeSyntax = attributeSyntax.WithArgumentList( + SyntaxFactory.AttributeArgumentList( + SyntaxFactory.SingletonSeparatedList(cooperativeCancellationArg))); + } + else + { + // Argument list exists, check if CooperativeCancellation is already specified + bool hasCooperativeCancellation = false; + List newArguments = []; + + foreach (AttributeArgumentSyntax arg in attributeSyntax.ArgumentList.Arguments) + { + if (arg.NameEquals?.Name.Identifier.ValueText == "CooperativeCancellation") + { + // Replace existing CooperativeCancellation = false with true + hasCooperativeCancellation = true; + AttributeArgumentSyntax newArg = arg.WithExpression( + SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression)); + newArguments.Add(newArg); + } + else + { + newArguments.Add(arg); + } + } + + if (!hasCooperativeCancellation) + { + // Add CooperativeCancellation = true to existing arguments + AttributeArgumentSyntax cooperativeCancellationArg = SyntaxFactory.AttributeArgument( + SyntaxFactory.NameEquals("CooperativeCancellation"), + null, + SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression)); + + newArguments.Add(cooperativeCancellationArg); + } + + newAttributeSyntax = attributeSyntax.WithArgumentList( + attributeSyntax.ArgumentList.WithArguments( + SyntaxFactory.SeparatedList(newArguments))); + } + + // Replace the old attribute with the new one + editor.ReplaceNode(attributeSyntax, newAttributeSyntax); + + return editor.GetChangedDocument(); + } +} diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/UseProperAssertMethodsFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/UseProperAssertMethodsFixer.cs index 37be3ecc36..3c5ef8c80f 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/UseProperAssertMethodsFixer.cs +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/UseProperAssertMethodsFixer.cs @@ -78,6 +78,9 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) case UseProperAssertMethodsAnalyzer.CodeFixModeRemoveArgument: createChangedDocument = ct => FixAssertMethodForRemoveArgumentModeAsync(context.Document, diagnostic.AdditionalLocations, root, simpleNameSyntax, properAssertMethodName, diagnostic.Properties.ContainsKey(UseProperAssertMethodsAnalyzer.NeedsNullableBooleanCastKey), ct); break; + case UseProperAssertMethodsAnalyzer.CodeFixModeCollectionCount: + createChangedDocument = ct => FixAssertMethodForCollectionCountModeAsync(context.Document, diagnostic.AdditionalLocations, root, simpleNameSyntax, properAssertMethodName, ct); + break; default: break; } @@ -132,7 +135,8 @@ private static async Task FixAssertMethodForAddArgumentModeAsync(Docum return document; } - if (root.FindNode(expectedLocation.SourceSpan) is not ExpressionSyntax expectedNode) + if (root.FindNode(expectedLocation.SourceSpan) is not { } expectedNode + || expectedNode is not ArgumentSyntax and not ExpressionSyntax) { return document; } @@ -146,7 +150,13 @@ private static async Task FixAssertMethodForAddArgumentModeAsync(Docum FixInvocationMethodName(editor, simpleNameSyntax, properAssertMethodName); ArgumentListSyntax newArgumentList = argumentList; - newArgumentList = newArgumentList.ReplaceNode(conditionNode, SyntaxFactory.Argument(expectedNode).WithAdditionalAnnotations(Formatter.Annotation)); + ExpressionSyntax expectedExpression = expectedNode switch + { + ArgumentSyntax argument => argument.Expression, + ExpressionSyntax expression => expression, + _ => throw new InvalidOperationException($"Unexpected node type for expected argument: {expectedNode.GetType()}"), + }; + newArgumentList = newArgumentList.ReplaceNode(conditionNode, SyntaxFactory.Argument(expectedExpression).WithAdditionalAnnotations(Formatter.Annotation)); int insertionIndex = argumentList.Arguments.IndexOf(conditionNode) + 1; newArgumentList = newArgumentList.WithArguments(newArgumentList.Arguments.Insert(insertionIndex, SyntaxFactory.Argument(actualNode).WithAdditionalAnnotations(Formatter.Annotation))); @@ -203,6 +213,76 @@ private static async Task FixAssertMethodForRemoveArgumentModeAsync( return editor.GetChangedDocument(); } + private static async Task FixAssertMethodForCollectionCountModeAsync( + Document document, + IReadOnlyList additionalLocations, + SyntaxNode root, + SimpleNameSyntax simpleNameSyntax, + string properAssertMethodName, + CancellationToken cancellationToken) + { + // Handle collection count transformations: + // Assert.AreEqual(0, list.Count) -> Assert.IsEmpty(list) + // Assert.AreEqual(3, list.Count) -> Assert.HasCount(3, list) + // Assert.AreEqual(list.Count, 0) -> Assert.IsEmpty(list) + // Assert.AreEqual(list.Count, 3) -> Assert.HasCount(3, list) + if (root.FindNode(additionalLocations[0].SourceSpan) is not ArgumentSyntax firstArgument || + root.FindNode(additionalLocations[1].SourceSpan) is not ArgumentSyntax || + firstArgument.Parent is not ArgumentListSyntax argumentList) + { + return document; + } + + if (root.FindNode(additionalLocations[2].SourceSpan) is not ExpressionSyntax collectionExpression) + { + return document; + } + + DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); + FixInvocationMethodName(editor, simpleNameSyntax, properAssertMethodName); + + // Preserve any additional arguments beyond the first two (expected/actual) + var additionalArguments = argumentList.Arguments.Skip(2).ToList(); + + ArgumentListSyntax newArgumentList; + + if (properAssertMethodName == "IsEmpty") + { + // For IsEmpty, we just need the collection argument plus any additional arguments + var newArguments = new List + { + SyntaxFactory.Argument(collectionExpression).WithAdditionalAnnotations(Formatter.Annotation), + }; + newArguments.AddRange(additionalArguments); + newArgumentList = argumentList.WithArguments(SyntaxFactory.SeparatedList(newArguments)); + } + else // HasCount + { + // For HasCount, we need count and collection arguments plus any additional arguments + // additionalLocations[3] should contain the count expression + if (additionalLocations.Count > 3 && + root.FindNode(additionalLocations[3].SourceSpan) is ArgumentSyntax countArgument) + { + var newArguments = new List + { + SyntaxFactory.Argument(countArgument.Expression).WithAdditionalAnnotations(Formatter.Annotation), + SyntaxFactory.Argument(collectionExpression).WithAdditionalAnnotations(Formatter.Annotation), + }; + newArguments.AddRange(additionalArguments); + newArgumentList = argumentList.WithArguments(SyntaxFactory.SeparatedList(newArguments)); + } + else + { + // Fallback: something went wrong, don't apply the fix + return document; + } + } + + editor.ReplaceNode(argumentList, newArgumentList); + + return editor.GetChangedDocument(); + } + private static void FixInvocationMethodName(DocumentEditor editor, SimpleNameSyntax simpleNameSyntax, string properAssertMethodName) // NOTE: Switching Assert.IsTrue(x == y) to Assert.AreEqual(x, y) MAY produce an overload resolution error. // For example, Assert.AreEqual("string", true) will fail the inference for generic argument. diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf index 5e01c72cca..7c85a47db8 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf @@ -27,6 +27,11 @@ Změnit přístupnost metody na private + + Change to 'class' and add '[TestClass]' + Změňte na class a přidejte [TestClass] + + Fix actual/expected arguments order Opravit pořadí skutečných/očekávaných argumentů @@ -42,6 +47,16 @@ Opravit podpis + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + Předejte argument TestContext.CancellationTokenSource.Token volání metody. + + + + Replace 'DataTestMethod' with 'TestMethod' + Nahradit DataTestMethod hodnotou TestMethod + + Replace TestInitialize method with constructor Nahradit metodu TestInitialize konstruktorem @@ -67,6 +82,11 @@ Nahradit konstruktor metodou TestInitialize + + Use 'Assert.{0}' instead of 'StringAssert' + Použijte Assert.{0}místo StringAssert + + Fix test class signature Oprava podpisu testovací třídy @@ -92,6 +112,11 @@ Přidat [TestMethod] + + Use 'CooperativeCancellation = true' + Použijte „CooperativeCancellation = true“ + + Use '{0}' Použít {0} diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.de.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.de.xlf index ecef33e935..16776cafc7 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.de.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.de.xlf @@ -27,6 +27,11 @@ Methodenzugriff auf „privat“ ändern + + Change to 'class' and add '[TestClass]' + Wechseln Sie zu „Klasse“, und fügen Sie „[Testklasse]“ hinzu + + Fix actual/expected arguments order Reihenfolge der tatsächlichen/erwarteten Argumente korrigieren @@ -42,6 +47,16 @@ Signatur korrigieren + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + Argument „TestContext.CancellationTokenSource.Token“ an den Methodenaufruf übergeben + + + + Replace 'DataTestMethod' with 'TestMethod' + „DataTestMethod“ durch „TestMethod“ ersetzen + + Replace TestInitialize method with constructor TestInitialize-Methode durch Konstruktor ersetzen @@ -67,6 +82,11 @@ Konstruktor durch TestInitialize-Methode ersetzen + + Use 'Assert.{0}' instead of 'StringAssert' + Verwenden Sie „Assert.{0}“ anstelle von „StringAssert“. + + Fix test class signature Testklassensignatur korrigieren @@ -92,6 +112,11 @@ „[TestMethod]“ hinzufügen + + Use 'CooperativeCancellation = true' + Verwenden Sie „CooperativeCancellation = true“. + + Use '{0}' „{0}“ verwenden diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.es.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.es.xlf index 1edccf3e61..5fe2aeef20 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.es.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.es.xlf @@ -27,6 +27,11 @@ Cambiar la accesibilidad del método a "private" + + Change to 'class' and add '[TestClass]' + Cambiar a "class" y agregar "[TestClass]" + + Fix actual/expected arguments order Corregir el orden de los argumentos reales o esperados @@ -42,6 +47,16 @@ Corregir firma + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + Pasa el argumento 'TestContext.CancellationTokenSource.Token' a la llamada de método + + + + Replace 'DataTestMethod' with 'TestMethod' + Reemplazar "DataTestMethod" por "TestMethod" + + Replace TestInitialize method with constructor Reemplazar el método TestInitialize por el constructor @@ -67,6 +82,11 @@ Reemplazar constructor por el método TestInitialize + + Use 'Assert.{0}' instead of 'StringAssert' + Use "Assert.{0}" en lugar de "StringAssert" + + Fix test class signature Corregir firma de clase de prueba @@ -92,6 +112,11 @@ Agregar '[TestMethod]' + + Use 'CooperativeCancellation = true' + Usa "CooperativeCancellation = true" + + Use '{0}' Usar "{0}" diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.fr.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.fr.xlf index ed28b55f45..821c7fe651 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.fr.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.fr.xlf @@ -27,6 +27,11 @@ Remplacer l’accessibilité de la méthode par « privé » + + Change to 'class' and add '[TestClass]' + Remplacez par « classe » et ajoutez « [TestClass] » + + Fix actual/expected arguments order Corriger l’ordre des arguments réels/attendus @@ -42,6 +47,16 @@ Corriger la signature numérique + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + Passer l’argument « TestContext.CancellationTokenSource.Token » à l’appel de méthode + + + + Replace 'DataTestMethod' with 'TestMethod' + Remplacer « DataTestMethod » par « TestMethod » + + Replace TestInitialize method with constructor Remplacer la méthode TestInitialize par un constructeur @@ -67,6 +82,11 @@ Remplacer le constructeur par la méthode TestInitialize + + Use 'Assert.{0}' instead of 'StringAssert' + Utilisez « Assert.{0} » au lieu de « StringAssert » + + Fix test class signature Correction de la signature de classe de test @@ -92,6 +112,11 @@ Ajouter « [TestMethod] » + + Use 'CooperativeCancellation = true' + Utilisez 'CooperativeCancellation = true' + + Use '{0}' Utiliser « {0} » diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.it.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.it.xlf index 10aafdcc89..31788d3248 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.it.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.it.xlf @@ -27,6 +27,11 @@ Modifica l'accessibilità del metodo in 'privato' + + Change to 'class' and add '[TestClass]' + Cambia in 'class' e aggiungi '[TestClass]' + + Fix actual/expected arguments order Correggi l'ordine degli argomenti effettivi/previsti @@ -42,6 +47,16 @@ Correggi firma + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + Passare l'argomento 'TestContext.CancellationTokenSource.Token' alla chiamata al metodo + + + + Replace 'DataTestMethod' with 'TestMethod' + Sostituisci 'DataTestMethod' con 'TestMethod' + + Replace TestInitialize method with constructor Sostituisci il metodo TestInitialize con il costruttore @@ -67,6 +82,11 @@ Sostituisci costruttore con metodo TestInitialize + + Use 'Assert.{0}' instead of 'StringAssert' + Usa 'Assert.{0}' invece di 'StringAssert' + + Fix test class signature Correggi la firma della classe di test @@ -92,6 +112,11 @@ Aggiungi '[TestMethod]' + + Use 'CooperativeCancellation = true' + Usa "CooperativeCancellation = true" + + Use '{0}' Usare ‘{0}’ diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ja.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ja.xlf index ad8e53d586..94549b537e 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ja.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ja.xlf @@ -27,6 +27,11 @@ メソッドのアクセシビリティを 'private' に変更する + + Change to 'class' and add '[TestClass]' + 'class' に変更し、'[TestClass]' を追加します + + Fix actual/expected arguments order 実際の引数と予想される引数の順序を修正する @@ -42,6 +47,16 @@ 署名の修正 + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + 'TestContext.CancellationTokenSource.Token' 引数をメソッド呼び出しに渡す + + + + Replace 'DataTestMethod' with 'TestMethod' + 'DataTestMethod' を 'TestMethod' に置き換えます + + Replace TestInitialize method with constructor TestInitialize メソッドをコンストラクターに置き換える @@ -67,6 +82,11 @@ コンストラクターを TestInitialize メソッドに置き換える + + Use 'Assert.{0}' instead of 'StringAssert' + 'StringAssert' の代わりに 'Assert.{0}' を使用 + + Fix test class signature テスト クラスのシグネチャの修正 @@ -92,6 +112,11 @@ '[TestMethod]' の追加 + + Use 'CooperativeCancellation = true' + 'CooperativeCancellation = true' を使用する + + Use '{0}' '{0}' を使用する diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ko.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ko.xlf index 9d32dc54eb..1d3b2b6c7d 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ko.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ko.xlf @@ -27,6 +27,11 @@ 메서드 접근성 '비공개'로 변경하기 + + Change to 'class' and add '[TestClass]' + 'class'로 변경하고 '[TestClass]'를 추가합니다. + + Fix actual/expected arguments order 실제/예상 인수 순서 수정 @@ -42,6 +47,16 @@ 서명 수정 + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + 메서드 호출에 'TestContext.CancellationTokenSource.Token' 인수 전달 + + + + Replace 'DataTestMethod' with 'TestMethod' + 'DataTestMethod'를 'TestMethod'로 바꾸기 + + Replace TestInitialize method with constructor TestInitialize 메서드를 생성자로 바꾸기 @@ -67,6 +82,11 @@ 생성자를 TestInitialize 메서드로 바꾸기 + + Use 'Assert.{0}' instead of 'StringAssert' + 'StringAssert' 대신 'Assert.{0}' 사용 + + Fix test class signature 테스트 클래스 서명 수정 @@ -92,6 +112,11 @@ '[TestMethod]' 추가 + + Use 'CooperativeCancellation = true' + 'CooperativeCancellation = true'를 사용하세요. + + Use '{0}' '{0}' 사용 diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pl.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pl.xlf index d879b5a155..310742cd01 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pl.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pl.xlf @@ -27,6 +27,11 @@ Zmień dostępność metody na „private” (prywatna) + + Change to 'class' and add '[TestClass]' + Zmień na wartość „class” i dodaj element „[TestClass]” + + Fix actual/expected arguments order Napraw rzeczywistą/oczekiwaną kolejność argumentów @@ -42,6 +47,16 @@ Popraw podpis + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + Przekaż argument „TestContext.CancellationTokenSource.Token” do wywołania metody + + + + Replace 'DataTestMethod' with 'TestMethod' + Zastąp element „DataTestMethod” elementem „TestMethod” + + Replace TestInitialize method with constructor Zastąp metodę TestInitialize konstruktorem @@ -67,6 +82,11 @@ Zastąp konstruktor metodą TestInitialize + + Use 'Assert.{0}' instead of 'StringAssert' + Użyj ciągu „Assert.{0}” zamiast ciągu „StringAssert” + + Fix test class signature Napraw podpis klasy testowej @@ -92,6 +112,11 @@ Dodaj „[TestMethod]” + + Use 'CooperativeCancellation = true' + Użyj opcji „CooperativeCancellation = true” + + Use '{0}' Użyj „{0}” diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pt-BR.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pt-BR.xlf index 646745d87a..bd3d1f3de9 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pt-BR.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pt-BR.xlf @@ -27,6 +27,11 @@ Alterar a acessibilidade do método para 'privado' + + Change to 'class' and add '[TestClass]' + Alterar para 'classe' e adicionar '[TestClass]' + + Fix actual/expected arguments order Corrigir ordem de argumentos real/esperada @@ -42,6 +47,16 @@ Corrigir assinatura + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + Passe o argumento 'TestContext.CancellationTokenSource.Token' para a chamada do método + + + + Replace 'DataTestMethod' with 'TestMethod' + Substitua 'DataTestMethod' por 'TestMethod' + + Replace TestInitialize method with constructor Substituir o método TestInitialize pelo construtor. @@ -67,6 +82,11 @@ Substitua o construtor pelo método TestInitialize. + + Use 'Assert.{0}' instead of 'StringAssert' + Use 'Assert'{0}. em vez de 'StringAssert' + + Fix test class signature Correção da assinatura de classe do teste @@ -92,6 +112,11 @@ Adicionar ''[TestMethod]" + + Use 'CooperativeCancellation = true' + Usar “CooperativoCancellation = true” + + Use '{0}' Usar "{0}" diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ru.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ru.xlf index d2e9dbd136..e39f5f059c 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ru.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ru.xlf @@ -27,6 +27,11 @@ Изменить доступность метода на "private" + + Change to 'class' and add '[TestClass]' + Изменить на "class" и добавить "[TestClass]" + + Fix actual/expected arguments order Исправить порядок фактических и ожидаемых аргументов @@ -42,6 +47,16 @@ Исправить подпись + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + Передайте аргумент "TestContext.CancellationTokenSource.Token" вызов метода + + + + Replace 'DataTestMethod' with 'TestMethod' + Заменить "DataTestMethod" на "TestMethod" + + Replace TestInitialize method with constructor Заменить метод TestInitialize конструктором @@ -67,6 +82,11 @@ Заменить конструктор на метод TestInitialize + + Use 'Assert.{0}' instead of 'StringAssert' + Используйте "Assert.{0}" вместо "StringAssert" + + Fix test class signature Исправить подпись класса теста @@ -92,6 +112,11 @@ Добавить "[TestMethod]" + + Use 'CooperativeCancellation = true' + Использовать "CooperativeCancellation = true" + + Use '{0}' Использовать "{0}" diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.tr.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.tr.xlf index 48e1032eb5..1d0141b71c 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.tr.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.tr.xlf @@ -27,6 +27,11 @@ Yöntem erişilebilirliğini ‘özel’ olarak değiştir + + Change to 'class' and add '[TestClass]' + ‘class’ olarak değiştirin ve ‘[TestClass]’ ekleyin. + + Fix actual/expected arguments order Fiili/beklenen bağımsız değişken sırasını düzelt @@ -42,6 +47,16 @@ İmzayı düzelt + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + ‘TestContext.CancellationTokenSource.Token’ bağımsız değişkeni metot çağrısına geçirin + + + + Replace 'DataTestMethod' with 'TestMethod' + 'DataTestMethod' yöntemini 'TestMethod' ile değiştirin + + Replace TestInitialize method with constructor TestInitialize yöntemini oluşturucuyla değiştir @@ -67,6 +82,11 @@ Oluşturucuyu TestInitialize yöntemiyle değiştir + + Use 'Assert.{0}' instead of 'StringAssert' + ‘StringAssert’ yerine ‘Assert.{0}’ kullanın + + Fix test class signature Test sınıfı imzasını düzeltme @@ -92,6 +112,11 @@ '[TestMethod]' ekle + + Use 'CooperativeCancellation = true' + 'CooperativeCancellation = true' kullanın + + Use '{0}' '{0}' kullan diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hans.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hans.xlf index 2f4b66073d..271951cb89 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hans.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hans.xlf @@ -27,6 +27,11 @@ 将方法可访问性更改为“private” + + Change to 'class' and add '[TestClass]' + 更改为 "class" 并添加 "[TestClass]" + + Fix actual/expected arguments order 修复实际/预期参数顺序 @@ -42,6 +47,16 @@ 修复签名 + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + 将 'TestContext.CancellationTokenSource.Token' 参数传递给方法调用 + + + + Replace 'DataTestMethod' with 'TestMethod' + 将 'DataTestMethod' 替换为 'TestMethod' + + Replace TestInitialize method with constructor 将 TestInitialize 方法替换为构造函数 @@ -67,6 +82,11 @@ 将构造函数替换为 TestInitialize 方法 + + Use 'Assert.{0}' instead of 'StringAssert' + 使用 'Assert.{0}' 而不是 'StringAssert' + + Fix test class signature 修复测试类签名 @@ -92,6 +112,11 @@ 添加“[TestMethod]” + + Use 'CooperativeCancellation = true' + 使用 'CooperativeCancellation = true' + + Use '{0}' 使用“{0}” diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hant.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hant.xlf index 5c5ea7e81d..d490fcbef8 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hant.xlf +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hant.xlf @@ -27,6 +27,11 @@ 將方法協助工具變更為 'private' + + Change to 'class' and add '[TestClass]' + 變更為 'class',並新增 '[TestClass]' + + Fix actual/expected arguments order 修正實際/預期的引數順序 @@ -42,6 +47,16 @@ 修正簽章 + + Pass 'TestContext.CancellationTokenSource.Token' argument to method call + 將 'TestContext.CancellationTokenSource.Token' 引數傳遞給方法呼叫 + + + + Replace 'DataTestMethod' with 'TestMethod' + 將 'DataTestMethod' 取代為 'TestMethod' + + Replace TestInitialize method with constructor 以建構函式取代 TestInitialize 方法 @@ -67,6 +82,11 @@ 使用 TestInitialize 方法取代建構函式 + + Use 'Assert.{0}' instead of 'StringAssert' + 使用 'Assert.{0}' 而不是 'StringAssert' + + Fix test class signature 修正測試類別簽章 @@ -92,6 +112,11 @@ 新增 '[TestMethod]' + + Use 'CooperativeCancellation = true' + 使用 'CooperativeCancellation = true' + + Use '{0}' 使用 '{0}' diff --git a/src/Analyzers/MSTest.Analyzers.Package/MSTest.Analyzers.Package.csproj b/src/Analyzers/MSTest.Analyzers.Package/MSTest.Analyzers.Package.csproj index dbeb1dfb27..0631e8b43c 100644 --- a/src/Analyzers/MSTest.Analyzers.Package/MSTest.Analyzers.Package.csproj +++ b/src/Analyzers/MSTest.Analyzers.Package/MSTest.Analyzers.Package.csproj @@ -35,7 +35,7 @@ $(DotNetRoot)dotnet.exe $(DotNetRoot)dotnet - + diff --git a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Shipped.md b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Shipped.md index e3dd53f75e..d0c52ee782 100644 --- a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Shipped.md +++ b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Shipped.md @@ -1,4 +1,13 @@ -## Release 3.8.0 +## Release 3.9.0 + +### New Rules + +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +MSTEST0042 | Usage | Warning | DuplicateDataRowAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0042) +MSTEST0043 | Usage | Warning | UseRetryWithTestMethodAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0043) + +## Release 3.8.0 ### New Rules diff --git a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md index fbfaf78376..f230c697eb 100644 --- a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md +++ b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md @@ -5,5 +5,16 @@ Rule ID | Category | Severity | Notes --------|----------|----------|------- -MSTEST0042 | Usage | Warning | DuplicateDataRowAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0042) -MSTEST0043 | Usage | Warning | UseRetryWithTestMethodAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0043) +MSTEST0044 | Design | Warning | PreferTestMethodOverDataTestMethodAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0044) +MSTEST0045 | Usage | Info | UseCooperativeCancellationForTimeoutAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0045) +MSTEST0046 | Usage | Info | StringAssertToAssertAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0046) +MSTEST0048 | Usage | Warning | TestContextPropertyUsageAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0047) +MSTEST0049 | Usage | Info | FlowTestContextCancellationTokenAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0049) +MSTEST0050 | Usage | Error | GlobalTestFixtureShouldBeValidAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0050) + +### Changed Rules + +Rule ID | New Category | New Severity | Old Category | Old Severity | Notes +--------|--------------|--------------|--------------|--------------|------- +MSTEST0006 | Design | Warning | Design | Info | AvoidExpectedExceptionAttributeAnalyzer +MSTEST0039 | Usage | Warning | Usage | Info | UseNewerAssertThrowsAnalyzer diff --git a/src/Analyzers/MSTest.Analyzers/AvoidExpectedExceptionAttributeAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AvoidExpectedExceptionAttributeAnalyzer.cs index 57d24831f3..df19f7f3e5 100644 --- a/src/Analyzers/MSTest.Analyzers/AvoidExpectedExceptionAttributeAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/AvoidExpectedExceptionAttributeAnalyzer.cs @@ -30,7 +30,7 @@ public sealed class AvoidExpectedExceptionAttributeAnalyzer : DiagnosticAnalyzer MessageFormat, Description, Category.Design, - DiagnosticSeverity.Info, + DiagnosticSeverity.Warning, isEnabledByDefault: true); /// diff --git a/src/Analyzers/MSTest.Analyzers/AvoidUsingAssertsInAsyncVoidContextAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AvoidUsingAssertsInAsyncVoidContextAnalyzer.cs index 4a6c6e1a7a..76ecac2e37 100644 --- a/src/Analyzers/MSTest.Analyzers/AvoidUsingAssertsInAsyncVoidContextAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/AvoidUsingAssertsInAsyncVoidContextAnalyzer.cs @@ -46,23 +46,38 @@ public override void Initialize(AnalysisContext context) { Compilation compilation = context.Compilation; INamedTypeSymbol? assertSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssert); - if (assertSymbol is not null) + INamedTypeSymbol? stringAssertSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingStringAssert); + INamedTypeSymbol? collectionAssertSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingCollectionAssert); + + if (assertSymbol is not null || stringAssertSymbol is not null || collectionAssertSymbol is not null) { - context.RegisterOperationAction(context => AnalyzeOperation(context, assertSymbol), OperationKind.Invocation); + context.RegisterOperationAction(context => AnalyzeOperation(context, assertSymbol, stringAssertSymbol, collectionAssertSymbol), OperationKind.Invocation); } }); } - private static void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol assertSymbol) + private static void AnalyzeOperation( + OperationAnalysisContext context, + INamedTypeSymbol? assertSymbol, + INamedTypeSymbol? stringAssertSymbol, + INamedTypeSymbol? collectionAssertSymbol) { var operation = (IInvocationOperation)context.Operation; - if (!IsAsyncVoidContext(operation, context.ContainingSymbol) || - !assertSymbol.Equals(operation.TargetMethod.ContainingType, SymbolEqualityComparer.Default)) + if (!IsAsyncVoidContext(operation, context.ContainingSymbol)) { return; } - context.ReportDiagnostic(operation.CreateDiagnostic(Rule)); + INamedTypeSymbol targetType = operation.TargetMethod.ContainingType; + bool isAssertType = + targetType.Equals(assertSymbol, SymbolEqualityComparer.Default) || + targetType.Equals(stringAssertSymbol, SymbolEqualityComparer.Default) || + targetType.Equals(collectionAssertSymbol, SymbolEqualityComparer.Default); + + if (isAssertType) + { + context.ReportDiagnostic(operation.CreateDiagnostic(Rule)); + } } private static bool IsAsyncVoidContext(IInvocationOperation invocationOperation, ISymbol containingSymbol) diff --git a/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs index 1742bf29c9..44d17d7c2d 100644 --- a/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs @@ -91,7 +91,7 @@ private static void AnalyzeSymbol( var methodSymbol = (IMethodSymbol)context.Symbol; bool isTestMethod = false; - List dataRowAttributes = new(); + List dataRowAttributes = []; foreach (AttributeData methodAttribute in methodSymbol.GetAttributes()) { // Current method should be a test method or should inherit from the TestMethod attribute. @@ -184,7 +184,7 @@ private static void AnalyzeAttribute(SymbolAnalysisContext context, AttributeDat AnalyzeGenericMethod(context, dataRowSyntax, methodSymbol, constructorArguments); // Check constructor argument types match method parameter types. - List<(int ConstructorArgumentIndex, int MethodParameterIndex)> typeMismatchIndices = new(); + List<(string ParameterName, string ExpectedType, string ActualType)> typeMismatches = []; for (int currentArgumentIndex = 0; currentArgumentIndex < constructorArguments.Length; currentArgumentIndex++) { // Null is considered as default for non-nullable types. @@ -205,16 +205,34 @@ private static void AnalyzeAttribute(SymbolAnalysisContext context, AttributeDat if (argumentType is not null && !argumentType.IsAssignableTo(paramType, context.Compilation)) { - typeMismatchIndices.Add((currentArgumentIndex, Math.Min(currentArgumentIndex, methodSymbol.Parameters.Length - 1))); + int parameterIndex = Math.Min(currentArgumentIndex, methodSymbol.Parameters.Length - 1); + string parameterName = methodSymbol.Parameters[parameterIndex].Name; + string expectedType = paramType.ToDisplayString(); + string actualType = argumentType.ToDisplayString(); + typeMismatches.Add((parameterName, expectedType, actualType)); } } // Report diagnostics if there's any type mismatch. - if (typeMismatchIndices.Count > 0) + if (typeMismatches.Count > 0) { + // Format all mismatches into a single message + string mismatchMessage; + if (typeMismatches.Count == 1) + { + (string parameterName, string expectedType, string actualType) = typeMismatches[0]; + mismatchMessage = string.Format(CultureInfo.InvariantCulture, Resources.DataRowShouldBeValidMessageFormat_ParameterMismatch, parameterName, expectedType, actualType); + } + else + { + IEnumerable mismatchDescriptions = typeMismatches.Select(m => + string.Format(CultureInfo.InvariantCulture, Resources.DataRowShouldBeValidMessageFormat_ParameterMismatch, m.ParameterName, m.ExpectedType, m.ActualType)); + mismatchMessage = string.Join("; ", mismatchDescriptions); + } + context.ReportDiagnostic(dataRowSyntax.CreateDiagnostic( ArgumentTypeMismatchRule, - string.Join(", ", typeMismatchIndices))); + mismatchMessage)); } } diff --git a/src/Analyzers/MSTest.Analyzers/DoNotUseShadowingAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DoNotUseShadowingAnalyzer.cs index e326e9cff5..99f2fca090 100644 --- a/src/Analyzers/MSTest.Analyzers/DoNotUseShadowingAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/DoNotUseShadowingAnalyzer.cs @@ -64,7 +64,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo Dictionary> membersByName = GetBaseMembers(namedTypeSymbol); foreach (ISymbol member in namedTypeSymbol.GetMembers()) { - foreach (ISymbol baseMember in membersByName.GetValueOrDefault(member.Name, new List())) + foreach (ISymbol baseMember in membersByName.GetValueOrDefault(member.Name, [])) { // Check if the member is shadowing a base class member if (IsMemberShadowing(member, baseMember)) @@ -77,7 +77,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo private static Dictionary> GetBaseMembers(INamedTypeSymbol namedTypeSymbol) { - Dictionary> membersByName = new(); + Dictionary> membersByName = []; INamedTypeSymbol? currentType = namedTypeSymbol.BaseType; while (currentType is not null) { @@ -91,7 +91,7 @@ private static Dictionary> GetBaseMembers(INamedTypeSymbol if (!membersByName.TryGetValue(member.Name, out List? members)) { - members = new List(); + members = []; membersByName[member.Name] = members; } diff --git a/src/Analyzers/MSTest.Analyzers/DuplicateDataRowAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DuplicateDataRowAnalyzer.cs index b4c2596fe9..6d560c76c1 100644 --- a/src/Analyzers/MSTest.Analyzers/DuplicateDataRowAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/DuplicateDataRowAnalyzer.cs @@ -126,6 +126,22 @@ private static bool AreTypedConstantEquals(TypedConstant typedConstant1, TypedCo return TypedConstantArrayComparer.Instance.Equals(typedConstant1.Values, typedConstant2.Values); } + if (typedConstant1.Kind == TypedConstantKind.Primitive) + { + // object.Equals(float.NegativeZero, 0.0f) will return true. + // But we don't want to consider it as "equal" as the test case can yield different results. + // Behavior difference between zero and negative zero can be observed via BitConverter or ToString. + if (typedConstant1.Value is float float1 && typedConstant2.Value is float float2) + { + // BitConverter.SingleToInt32Bits isn't available on netstandard2.0, so we use BitConverter.GetBytes instead. + return BitConverter.GetBytes(float1).SequenceEqual(BitConverter.GetBytes(float2)); + } + else if (typedConstant1.Value is double double1 && typedConstant2.Value is double double2) + { + return BitConverter.DoubleToInt64Bits(double1) == BitConverter.DoubleToInt64Bits(double2); + } + } + // At this point, the type is matching and the kind is matching and is not array. return object.Equals(typedConstant1.Value, typedConstant2.Value); } diff --git a/src/Analyzers/MSTest.Analyzers/DynamicDataShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DynamicDataShouldBeValidAnalyzer.cs index d5af2d294f..2a91cf33eb 100644 --- a/src/Analyzers/MSTest.Analyzers/DynamicDataShouldBeValidAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/DynamicDataShouldBeValidAnalyzer.cs @@ -184,6 +184,7 @@ private static void AnalyzeDataSource(SymbolAnalysisContext context, AttributeDa { string? memberName = null; int dataSourceType = DynamicDataSourceTypeAutoDetect; + int argumentsCount = 0; INamedTypeSymbol declaringType = methodSymbol.ContainingType; foreach (TypedConstant argument in attributeData.ConstructorArguments) { @@ -202,10 +203,15 @@ private static void AnalyzeDataSource(SymbolAnalysisContext context, AttributeDa { dataSourceType = dataType; } - else if (argument.Value is INamedTypeSymbol type) + else if (argument.Kind != TypedConstantKind.Array && + argument.Value is INamedTypeSymbol type) { declaringType = type; } + else if (argument.Kind == TypedConstantKind.Array) + { + argumentsCount = argument.Values.Length; + } } // If the member name is not available, bail out. @@ -264,7 +270,7 @@ private static void AnalyzeDataSource(SymbolAnalysisContext context, AttributeDa if (member.Kind == SymbolKind.Method && member is IMethodSymbol method - && (method.IsGenericMethod || method.Parameters.Length != 0)) + && (method.IsGenericMethod || method.Parameters.Length != argumentsCount)) { context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(DataMemberSignatureRule, declaringType.Name, memberName)); return; @@ -272,7 +278,7 @@ private static void AnalyzeDataSource(SymbolAnalysisContext context, AttributeDa // Validate member return type. ITypeSymbol? memberTypeSymbol = member.GetMemberType(); - if (memberTypeSymbol is IArrayTypeSymbol arrayType) + if (memberTypeSymbol is IArrayTypeSymbol) { return; } diff --git a/src/Analyzers/MSTest.Analyzers/FlowTestContextCancellationTokenAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/FlowTestContextCancellationTokenAnalyzer.cs new file mode 100644 index 0000000000..cf38e10478 --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers/FlowTestContextCancellationTokenAnalyzer.cs @@ -0,0 +1,231 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +using Analyzer.Utilities.Extensions; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// MSTEST0049: . +/// +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class FlowTestContextCancellationTokenAnalyzer : DiagnosticAnalyzer +{ + private static readonly LocalizableResourceString Title = new(nameof(Resources.FlowTestContextCancellationTokenTitle), Resources.ResourceManager, typeof(Resources)); + private static readonly LocalizableResourceString Description = new(nameof(Resources.FlowTestContextCancellationTokenDescription), Resources.ResourceManager, typeof(Resources)); + private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.FlowTestContextCancellationTokenMessageFormat), Resources.ResourceManager, typeof(Resources)); + + internal const string TestContextMemberNamePropertyKey = nameof(TestContextMemberNamePropertyKey); + + internal static readonly DiagnosticDescriptor FlowTestContextCancellationTokenRule = DiagnosticDescriptorHelper.Create( + DiagnosticIds.FlowTestContextCancellationTokenRuleId, + Title, + MessageFormat, + Description, + Category.Usage, + DiagnosticSeverity.Info, + isEnabledByDefault: true); + + /// + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(FlowTestContextCancellationTokenRule); + + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(context => + { + // Get the required symbols + if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingCancellationToken, out INamedTypeSymbol? cancellationTokenSymbol) || + !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestContext, out INamedTypeSymbol? testContextSymbol) || + !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassCleanupAttribute, out INamedTypeSymbol? classCleanupAttributeSymbol) || + !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyCleanupAttribute, out INamedTypeSymbol? assemblyCleanupAttributeSymbol) || + !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestMethodAttribute, out INamedTypeSymbol? testMethodAttributeSymbol)) + { + return; + } + + context.RegisterOperationAction( + context => AnalyzeInvocation(context, cancellationTokenSymbol, testContextSymbol, classCleanupAttributeSymbol, assemblyCleanupAttributeSymbol, testMethodAttributeSymbol), + OperationKind.Invocation); + }); + } + + private static void AnalyzeInvocation( + OperationAnalysisContext context, + INamedTypeSymbol cancellationTokenSymbol, + INamedTypeSymbol testContextSymbol, + INamedTypeSymbol classCleanupAttributeSymbol, + INamedTypeSymbol assemblyCleanupAttributeSymbol, + INamedTypeSymbol testMethodAttributeSymbol) + { + var invocationOperation = (IInvocationOperation)context.Operation; + IMethodSymbol method = invocationOperation.TargetMethod; + + // Check if we're in a context where a TestContext is already available or could be made available. + if (!HasOrCouldHaveTestContextInScope(context.ContainingSymbol, testContextSymbol, classCleanupAttributeSymbol, assemblyCleanupAttributeSymbol, testMethodAttributeSymbol, out string? testContextMemberNameInScope)) + { + return; + } + + IParameterSymbol? cancellationTokenParameter = method.Parameters.LastOrDefault(p => SymbolEqualityComparer.Default.Equals(p.Type, cancellationTokenSymbol)); + bool parameterHasDefaultValue = cancellationTokenParameter is not null && cancellationTokenParameter.HasExplicitDefaultValue; + if (cancellationTokenParameter is not null && !parameterHasDefaultValue) + { + // The called method has a required CancellationToken parameter. + // No need to report diagnostic, even if user is explicitly passing CancellationToken.None or default(CancellationToken). + // We consider it "intentional" if the user is passing it explicitly. + return; + } + + if (parameterHasDefaultValue && + invocationOperation.Arguments.FirstOrDefault(arg => SymbolEqualityComparer.Default.Equals(arg.Parameter, cancellationTokenParameter))?.ArgumentKind != ArgumentKind.Explicit) + { + // The called method has an optional CancellationToken parameter, but it was not explicitly provided. + ImmutableDictionary properties = ImmutableDictionary.Empty; + if (testContextMemberNameInScope is not null) + { + properties = properties.Add(TestContextMemberNamePropertyKey, testContextMemberNameInScope); + } + + context.ReportDiagnostic(invocationOperation.Syntax.CreateDiagnostic(FlowTestContextCancellationTokenRule, properties: GetPropertiesBag(testContextMemberNameInScope))); + return; + } + + // At this point, we want to only continue analysis if and only if the called method didn't have a CancellationToken parameter. + // In this case, we look for other overloads that might accept a CancellationToken. + if (cancellationTokenParameter is null && + HasOverloadWithCancellationToken(method, cancellationTokenSymbol)) + { + context.ReportDiagnostic(invocationOperation.Syntax.CreateDiagnostic(FlowTestContextCancellationTokenRule, properties: GetPropertiesBag(testContextMemberNameInScope))); + } + + static ImmutableDictionary GetPropertiesBag(string? testContextMemberNameInScope) + { + ImmutableDictionary properties = ImmutableDictionary.Empty; + if (testContextMemberNameInScope is not null) + { + properties = properties.Add(TestContextMemberNamePropertyKey, testContextMemberNameInScope); + } + + return properties; + } + } + + private static bool HasOverloadWithCancellationToken(IMethodSymbol method, INamedTypeSymbol cancellationTokenSymbol) + { + // Look for overloads of the same method that accept CancellationToken + INamedTypeSymbol containingType = method.ContainingType; + + foreach (ISymbol member in containingType.GetMembers(method.Name)) + { + if (member is IMethodSymbol candidateMethod && + candidateMethod.MethodKind == method.MethodKind && + candidateMethod.IsStatic == method.IsStatic) + { + // Check if this method has the same parameters plus a CancellationToken + if (IsCompatibleOverloadWithCancellationToken(method, candidateMethod, cancellationTokenSymbol)) + { + return true; + } + } + } + + return false; + } + + private static bool HasOrCouldHaveTestContextInScope( + ISymbol containingSymbol, + INamedTypeSymbol testContextSymbol, + INamedTypeSymbol classCleanupAttributeSymbol, + INamedTypeSymbol assemblyCleanupAttributeSymbol, + INamedTypeSymbol testMethodAttributeSymbol, + out string? testContextMemberNameInScope) + { + testContextMemberNameInScope = null; + + if (containingSymbol is not IMethodSymbol method) + { + return false; + } + + // We have a TestContext in scope (as a parameter) + if (method.Parameters.FirstOrDefault(p => testContextSymbol.Equals(p.Type, SymbolEqualityComparer.Default)) is { } testContextParameter) + { + testContextMemberNameInScope = testContextParameter.Name; + return true; + } + + // We have a TestContext in scope (as a field or property) + if (!method.IsStatic && + method.ContainingType.GetMembers().FirstOrDefault( + m => !m.IsStatic && m.Kind is SymbolKind.Field or SymbolKind.Property && testContextSymbol.Equals(m.GetMemberType(), SymbolEqualityComparer.Default)) is { } testContextMember) + { + testContextMember = (testContextMember as IFieldSymbol)?.AssociatedSymbol ?? testContextMember; + // Workaround https://github.com/dotnet/roslyn/issues/70208 + // https://github.com/dotnet/roslyn/blob/f25ae8e02a91169f45060951a168b233ad588ed3/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs#L47 + testContextMemberNameInScope = testContextMember.Name.StartsWith('<') && testContextMember.Name.EndsWith(">P", StringComparison.Ordinal) + ? testContextMember.Name.Substring(1, testContextMember.Name.Length - 3) + : testContextMember.Name; + return true; + } + + // If we have AssemblyCleanup or ClassCleanup with no parameters, then we *could* have a TestContext in scope. + // Note that assembly/class cleanup method can optionally have a TestContext parameter, but it is not required. + // Also, for test methods (parameterized or not), we *could* have a TestContext in scope by adding a property to the test class (or injecting it via constructor). + ImmutableArray attributes = method.GetAttributes(); + foreach (AttributeData attribute in attributes) + { + if (method.Parameters.IsEmpty && + (classCleanupAttributeSymbol.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default) || + assemblyCleanupAttributeSymbol.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default))) + { + return true; + } + + if (attribute.AttributeClass?.Inherits(testMethodAttributeSymbol) == true) + { + return true; + } + } + + return false; + } + + private static bool IsCompatibleOverloadWithCancellationToken(IMethodSymbol originalMethod, IMethodSymbol candidateMethod, INamedTypeSymbol cancellationTokenSymbol) + { + // Check if the candidate method has all the same parameters as the original method plus a CancellationToken + ImmutableArray originalParams = originalMethod.Parameters; + ImmutableArray candidateParams = candidateMethod.Parameters; + + // The candidate should have one more parameter (the CancellationToken) + if (candidateParams.Length != originalParams.Length + 1) + { + return false; + } + + // Check if all original parameters match the first N parameters of the candidate + for (int i = 0; i < originalParams.Length; i++) + { + if (!SymbolEqualityComparer.Default.Equals(originalParams[i].Type, candidateParams[i].Type)) + { + return false; + } + } + + // Check if the last parameter is CancellationToken + IParameterSymbol lastParam = candidateParams[candidateParams.Length - 1]; + return SymbolEqualityComparer.Default.Equals(lastParam.Type, cancellationTokenSymbol); + } +} diff --git a/src/Analyzers/MSTest.Analyzers/GlobalTestFixtureShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/GlobalTestFixtureShouldBeValidAnalyzer.cs new file mode 100644 index 0000000000..f7b4a5c8a8 --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers/GlobalTestFixtureShouldBeValidAnalyzer.cs @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +using Analyzer.Utilities.Extensions; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// MSTEST0050: . +/// +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class GlobalTestFixtureShouldBeValidAnalyzer : DiagnosticAnalyzer +{ + internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create( + DiagnosticIds.GlobalTestFixtureShouldBeValidRuleId, + new LocalizableResourceString(nameof(Resources.GlobalTestFixtureShouldBeValidTitle), Resources.ResourceManager, typeof(Resources)), + new LocalizableResourceString(nameof(Resources.GlobalTestFixtureShouldBeValidMessageFormat), Resources.ResourceManager, typeof(Resources)), + new LocalizableResourceString(nameof(Resources.GlobalTestFixtureShouldBeValidDescription), Resources.ResourceManager, typeof(Resources)), + Category.Usage, + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + /// + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); + + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(context => + { + if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestContext, out INamedTypeSymbol? testContextSymbol) && + context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol) && + context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestInitializeAttribute, out INamedTypeSymbol? globalTestInitializeAttributeSymbol) && + context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestCleanupAttribute, out INamedTypeSymbol? globalTestCleanupAttributeSymbol)) + { + INamedTypeSymbol? taskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask); + INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask); + + context.RegisterSymbolAction( + context => AnalyzeSymbol(context, globalTestInitializeAttributeSymbol, globalTestCleanupAttributeSymbol, taskSymbol, valueTaskSymbol, testContextSymbol, testClassAttributeSymbol), + SymbolKind.Method); + } + }); + } + + private static void AnalyzeSymbol( + SymbolAnalysisContext context, + INamedTypeSymbol globalTestInitializeAttributeSymbol, + INamedTypeSymbol globalTestCleanupAttributeSymbol, + INamedTypeSymbol? taskSymbol, + INamedTypeSymbol? valueTaskSymbol, + INamedTypeSymbol testContextSymbol, + INamedTypeSymbol testClassAttributeSymbol) + { + var methodSymbol = (IMethodSymbol)context.Symbol; + + if ((methodSymbol.HasAttribute(globalTestInitializeAttributeSymbol) || methodSymbol.HasAttribute(globalTestCleanupAttributeSymbol)) && + !methodSymbol.HasValidFixtureMethodSignature(taskSymbol, valueTaskSymbol, canDiscoverInternals: false, shouldBeStatic: true, + allowGenericType: false, FixtureParameterMode.MustHaveTestContext, testContextSymbol, testClassAttributeSymbol, fixtureAllowInheritedTestClass: false, out _)) + { + context.ReportDiagnostic(methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name)); + } + } +} diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticDescriptorHelper.cs b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticDescriptorHelper.cs index c719ef7aae..9e09a07c97 100644 --- a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticDescriptorHelper.cs +++ b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticDescriptorHelper.cs @@ -31,7 +31,7 @@ public static DiagnosticDescriptor Create( public static DiagnosticDescriptor WithMessage(this DiagnosticDescriptor diagnosticDescriptor, LocalizableResourceString messageFormat) => new(diagnosticDescriptor.Id, diagnosticDescriptor.Title, messageFormat, diagnosticDescriptor.Category, diagnosticDescriptor.DefaultSeverity, - diagnosticDescriptor.IsEnabledByDefault, diagnosticDescriptor.Description, diagnosticDescriptor.HelpLinkUri, diagnosticDescriptor.CustomTags.ToArray()); + diagnosticDescriptor.IsEnabledByDefault, diagnosticDescriptor.Description, diagnosticDescriptor.HelpLinkUri, [.. diagnosticDescriptor.CustomTags]); private static string[] CreateCustomTags(bool isReportedAtCompilationEnd, bool escalateToErrorInRecommended, bool disableInAllMode, string[] customTags) { diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs index 66be4e9c99..5b31df82e2 100644 --- a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs +++ b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs @@ -48,4 +48,11 @@ internal static class DiagnosticIds public const string UseConditionBaseWithTestClassRuleId = "MSTEST0041"; public const string DuplicateDataRowRuleId = "MSTEST0042"; public const string UseRetryWithTestMethodRuleId = "MSTEST0043"; + public const string PreferTestMethodOverDataTestMethodRuleId = "MSTEST0044"; + public const string UseCooperativeCancellationForTimeoutRuleId = "MSTEST0045"; + public const string StringAssertToAssertRuleId = "MSTEST0046"; + public const string UnusedParameterSuppressorRuleId = "MSTEST0047"; + public const string TestContextPropertyUsageRuleId = "MSTEST0048"; + public const string FlowTestContextCancellationTokenRuleId = "MSTEST0049"; + public const string GlobalTestFixtureShouldBeValidRuleId = "MSTEST0050"; } diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs b/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs index bb71ecd3a5..8481ca81e1 100644 --- a/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs +++ b/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs @@ -18,6 +18,7 @@ internal static class WellKnownTypeNames public const string MicrosoftVisualStudioTestToolsUnitTestingCssIterationAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.CssIterationAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingCssProjectStructureAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.CssProjectStructureAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingDataRowAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.DataRowAttribute"; + public const string MicrosoftVisualStudioTestToolsUnitTestingDataTestMethodAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.DataTestMethodAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingDeploymentItemAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.DeploymentItemAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingDescriptionAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingDiscoverInternalsAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.DiscoverInternalsAttribute"; @@ -26,6 +27,8 @@ internal static class WellKnownTypeNames public const string MicrosoftVisualStudioTestToolsUnitTestingDynamicDataSourceType = "Microsoft.VisualStudio.TestTools.UnitTesting.DynamicDataSourceType"; public const string MicrosoftVisualStudioTestToolsUnitTestingExpectedExceptionAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.ExpectedExceptionAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingExpectedExceptionBaseAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.ExpectedExceptionBaseAttribute"; + public const string MicrosoftVisualStudioTestToolsUnitTestingGlobalTestCleanupAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.GlobalTestCleanupAttribute"; + public const string MicrosoftVisualStudioTestToolsUnitTestingGlobalTestInitializeAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.GlobalTestInitializeAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingIgnoreAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.IgnoreAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingInheritanceBehavior = "Microsoft.VisualStudio.TestTools.UnitTesting.InheritanceBehavior"; public const string MicrosoftVisualStudioTestToolsUnitTestingOwnerAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.OwnerAttribute"; @@ -39,6 +42,7 @@ internal static class WellKnownTypeNames public const string MicrosoftVisualStudioTestToolsUnitTestingTestInitializeAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingTestMethodAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingTestPropertyAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute"; + public const string MicrosoftVisualStudioTestToolsUnitTestingTimeoutAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.TimeoutAttribute"; public const string MicrosoftVisualStudioTestToolsUnitTestingWorkItemAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.WorkItemAttribute"; public const string System = "System"; @@ -48,6 +52,7 @@ internal static class WellKnownTypeNames public const string SystemIAsyncDisposable = "System.IAsyncDisposable"; public const string SystemIDisposable = "System.IDisposable"; public const string SystemReflectionMethodInfo = "System.Reflection.MethodInfo"; + public const string SystemThreadingCancellationToken = "System.Threading.CancellationToken"; public const string SystemThreadingTasksTask = "System.Threading.Tasks.Task"; public const string SystemThreadingTasksTask1 = "System.Threading.Tasks.Task`1"; public const string SystemThreadingTasksValueTask = "System.Threading.Tasks.ValueTask"; diff --git a/src/Analyzers/MSTest.Analyzers/NonNullableReferenceNotInitializedSuppressor.cs b/src/Analyzers/MSTest.Analyzers/NonNullableReferenceNotInitializedSuppressor.cs index ccb701e511..0b866fc77a 100644 --- a/src/Analyzers/MSTest.Analyzers/NonNullableReferenceNotInitializedSuppressor.cs +++ b/src/Analyzers/MSTest.Analyzers/NonNullableReferenceNotInitializedSuppressor.cs @@ -41,19 +41,28 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) foreach (Diagnostic diagnostic in context.ReportedDiagnostics) { - // The diagnostic is reported on the test method - if (diagnostic.Location.SourceTree is not { } tree) + // The main diagnostic location isn't always pointing to the TestContext property. + // It can point to the constructor. + // The additional locations will have the right thing. + // See https://github.com/dotnet/roslyn/issues/79188#issuecomment-3017087900. + // It was an intentional design to include the additional locations specifically for DiagnosticSuppressor scenarios. + // So it is safe to use AdditionalLocations here. We are not relying on an implementation detail here. + // However, we still fallback to diagnostic.Location just in case Roslyn regresses the AdditionalLocations behavior. + // Such regression happened in the past in Roslyn. + // See https://github.com/dotnet/roslyn/issues/66037 + Location location = diagnostic.AdditionalLocations.Count >= 1 ? diagnostic.AdditionalLocations[0] : diagnostic.Location; + if (location.SourceTree is not { } tree) { continue; } SyntaxNode root = tree.GetRoot(context.CancellationToken); - SyntaxNode node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + SyntaxNode node = root.FindNode(location.SourceSpan, getInnermostNodeForTie: true); SemanticModel semanticModel = context.GetSemanticModel(tree); ISymbol? declaredSymbol = semanticModel.GetDeclaredSymbol(node, context.CancellationToken); if (declaredSymbol is IPropertySymbol property - && string.Equals(property.Name, "TestContext", StringComparison.OrdinalIgnoreCase) + && string.Equals(property.Name, "TestContext", StringComparison.Ordinal) && SymbolEqualityComparer.Default.Equals(testContextSymbol, property.GetMethod?.ReturnType) && property.ContainingType.GetAttributes().Any(attr => attr.AttributeClass.Inherits(testClassAttributeSymbol))) { diff --git a/src/Analyzers/MSTest.Analyzers/PreferTestMethodOverDataTestMethodAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/PreferTestMethodOverDataTestMethodAnalyzer.cs new file mode 100644 index 0000000000..faf8481797 --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers/PreferTestMethodOverDataTestMethodAnalyzer.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +using Analyzer.Utilities.Extensions; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// MSTEST0044: . +/// +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class PreferTestMethodOverDataTestMethodAnalyzer : DiagnosticAnalyzer +{ + internal static readonly DiagnosticDescriptor PreferTestMethodOverDataTestMethodRule = DiagnosticDescriptorHelper.Create( + DiagnosticIds.PreferTestMethodOverDataTestMethodRuleId, + title: new LocalizableResourceString(nameof(Resources.PreferTestMethodOverDataTestMethodAnalyzerTitle), Resources.ResourceManager, typeof(Resources)), + messageFormat: new LocalizableResourceString(nameof(Resources.PreferTestMethodOverDataTestMethodAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources)), + description: new LocalizableResourceString(nameof(Resources.PreferTestMethodOverDataTestMethodAnalyzerDescription), Resources.ResourceManager, typeof(Resources)), + Category.Design, + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + /// + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(PreferTestMethodOverDataTestMethodRule); + + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(context => + { + if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingDataTestMethodAttribute, out INamedTypeSymbol? dataTestMethodAttributeSymbol)) + { + return; + } + + context.RegisterSymbolAction(context => AnalyzeMethod(context, dataTestMethodAttributeSymbol), SymbolKind.Method); + context.RegisterSymbolAction(context => AnalyzeNamedType(context, dataTestMethodAttributeSymbol), SymbolKind.NamedType); + }); + } + + private static void AnalyzeMethod(SymbolAnalysisContext context, INamedTypeSymbol dataTestMethodAttributeSymbol) + { + var methodSymbol = (IMethodSymbol)context.Symbol; + + foreach (AttributeData attribute in methodSymbol.GetAttributes()) + { + // Only report on direct application of DataTestMethodAttribute, not inherited ones + if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, dataTestMethodAttributeSymbol)) + { + if (attribute.ApplicationSyntaxReference is { } syntaxRef) + { + context.ReportDiagnostic(syntaxRef.CreateDiagnostic(PreferTestMethodOverDataTestMethodRule, context.CancellationToken)); + } + } + } + } + + private static void AnalyzeNamedType(SymbolAnalysisContext context, INamedTypeSymbol dataTestMethodAttributeSymbol) + { + var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; + + // Check if this type directly inherits from DataTestMethodAttribute + if (dataTestMethodAttributeSymbol.Equals(namedTypeSymbol.BaseType, SymbolEqualityComparer.Default)) + { + context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(PreferTestMethodOverDataTestMethodRule)); + } + } +} diff --git a/src/Analyzers/MSTest.Analyzers/PublicAPI.Shipped.txt b/src/Analyzers/MSTest.Analyzers/PublicAPI.Shipped.txt index 56544445f9..8c2dc7036b 100644 --- a/src/Analyzers/MSTest.Analyzers/PublicAPI.Shipped.txt +++ b/src/Analyzers/MSTest.Analyzers/PublicAPI.Shipped.txt @@ -27,6 +27,8 @@ MSTest.Analyzers.DoNotUseShadowingAnalyzer MSTest.Analyzers.DoNotUseShadowingAnalyzer.DoNotUseShadowingAnalyzer() -> void MSTest.Analyzers.DoNotUseSystemDescriptionAttributeAnalyzer MSTest.Analyzers.DoNotUseSystemDescriptionAttributeAnalyzer.DoNotUseSystemDescriptionAttributeAnalyzer() -> void +MSTest.Analyzers.DuplicateDataRowAnalyzer +MSTest.Analyzers.DuplicateDataRowAnalyzer.DuplicateDataRowAnalyzer() -> void MSTest.Analyzers.DynamicDataShouldBeValidAnalyzer MSTest.Analyzers.DynamicDataShouldBeValidAnalyzer.DynamicDataShouldBeValidAnalyzer() -> void MSTest.Analyzers.NonNullableReferenceNotInitializedSuppressor @@ -77,6 +79,8 @@ MSTest.Analyzers.UseDeploymentItemWithTestMethodOrTestClassAnalyzer MSTest.Analyzers.UseDeploymentItemWithTestMethodOrTestClassAnalyzer.UseDeploymentItemWithTestMethodOrTestClassAnalyzer() -> void MSTest.Analyzers.UseParallelizeAttributeAnalyzer MSTest.Analyzers.UseParallelizeAttributeAnalyzer.UseParallelizeAttributeAnalyzer() -> void +MSTest.Analyzers.UseRetryWithTestMethodAnalyzer +MSTest.Analyzers.UseRetryWithTestMethodAnalyzer.UseRetryWithTestMethodAnalyzer() -> void override MSTest.Analyzers.AssemblyCleanupShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void override MSTest.Analyzers.AssemblyCleanupShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray override MSTest.Analyzers.AssemblyInitializeShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void @@ -105,6 +109,8 @@ override MSTest.Analyzers.DoNotUseShadowingAnalyzer.Initialize(Microsoft.CodeAna override MSTest.Analyzers.DoNotUseShadowingAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray override MSTest.Analyzers.DoNotUseSystemDescriptionAttributeAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void override MSTest.Analyzers.DoNotUseSystemDescriptionAttributeAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray +override MSTest.Analyzers.DuplicateDataRowAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void +override MSTest.Analyzers.DuplicateDataRowAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray override MSTest.Analyzers.DynamicDataShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void override MSTest.Analyzers.DynamicDataShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray override MSTest.Analyzers.NonNullableReferenceNotInitializedSuppressor.ReportSuppressions(Microsoft.CodeAnalysis.Diagnostics.SuppressionAnalysisContext context) -> void @@ -155,3 +161,5 @@ override MSTest.Analyzers.UseDeploymentItemWithTestMethodOrTestClassAnalyzer.Ini override MSTest.Analyzers.UseDeploymentItemWithTestMethodOrTestClassAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray override MSTest.Analyzers.UseParallelizeAttributeAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void override MSTest.Analyzers.UseParallelizeAttributeAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray +override MSTest.Analyzers.UseRetryWithTestMethodAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void +override MSTest.Analyzers.UseRetryWithTestMethodAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray diff --git a/src/Analyzers/MSTest.Analyzers/PublicAPI.Unshipped.txt b/src/Analyzers/MSTest.Analyzers/PublicAPI.Unshipped.txt index ffbf652d09..855fc462e3 100644 --- a/src/Analyzers/MSTest.Analyzers/PublicAPI.Unshipped.txt +++ b/src/Analyzers/MSTest.Analyzers/PublicAPI.Unshipped.txt @@ -1,9 +1,25 @@ #nullable enable -MSTest.Analyzers.DuplicateDataRowAnalyzer -MSTest.Analyzers.DuplicateDataRowAnalyzer.DuplicateDataRowAnalyzer() -> void -MSTest.Analyzers.UseRetryWithTestMethodAnalyzer -MSTest.Analyzers.UseRetryWithTestMethodAnalyzer.UseRetryWithTestMethodAnalyzer() -> void -override MSTest.Analyzers.DuplicateDataRowAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void -override MSTest.Analyzers.DuplicateDataRowAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray -override MSTest.Analyzers.UseRetryWithTestMethodAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void -override MSTest.Analyzers.UseRetryWithTestMethodAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray +MSTest.Analyzers.FlowTestContextCancellationTokenAnalyzer +MSTest.Analyzers.FlowTestContextCancellationTokenAnalyzer.FlowTestContextCancellationTokenAnalyzer() -> void +MSTest.Analyzers.GlobalTestFixtureShouldBeValidAnalyzer +MSTest.Analyzers.GlobalTestFixtureShouldBeValidAnalyzer.GlobalTestFixtureShouldBeValidAnalyzer() -> void +override MSTest.Analyzers.FlowTestContextCancellationTokenAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void +override MSTest.Analyzers.FlowTestContextCancellationTokenAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray +MSTest.Analyzers.PreferTestMethodOverDataTestMethodAnalyzer +MSTest.Analyzers.PreferTestMethodOverDataTestMethodAnalyzer.PreferTestMethodOverDataTestMethodAnalyzer() -> void +override MSTest.Analyzers.GlobalTestFixtureShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void +override MSTest.Analyzers.GlobalTestFixtureShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray +override MSTest.Analyzers.PreferTestMethodOverDataTestMethodAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void +override MSTest.Analyzers.PreferTestMethodOverDataTestMethodAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray +MSTest.Analyzers.UseCooperativeCancellationForTimeoutAnalyzer +MSTest.Analyzers.UseCooperativeCancellationForTimeoutAnalyzer.UseCooperativeCancellationForTimeoutAnalyzer() -> void +override MSTest.Analyzers.UseCooperativeCancellationForTimeoutAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void +override MSTest.Analyzers.UseCooperativeCancellationForTimeoutAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray +MSTest.Analyzers.UnusedParameterSuppressor +MSTest.Analyzers.UnusedParameterSuppressor.UnusedParameterSuppressor() -> void +override MSTest.Analyzers.UnusedParameterSuppressor.ReportSuppressions(Microsoft.CodeAnalysis.Diagnostics.SuppressionAnalysisContext context) -> void +override MSTest.Analyzers.UnusedParameterSuppressor.SupportedSuppressions.get -> System.Collections.Immutable.ImmutableArray +MSTest.Analyzers.TestContextPropertyUsageAnalyzer +MSTest.Analyzers.TestContextPropertyUsageAnalyzer.TestContextPropertyUsageAnalyzer() -> void +override MSTest.Analyzers.TestContextPropertyUsageAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void +override MSTest.Analyzers.TestContextPropertyUsageAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray diff --git a/src/Analyzers/MSTest.Analyzers/PublicTypeShouldBeTestClassAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/PublicTypeShouldBeTestClassAnalyzer.cs index ae2e53ad40..4fc74ef968 100644 --- a/src/Analyzers/MSTest.Analyzers/PublicTypeShouldBeTestClassAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/PublicTypeShouldBeTestClassAnalyzer.cs @@ -63,7 +63,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo } // The type is public, ensure this is a test class. - if (!namedTypeSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testClassAttributeSymbol))) + if (!namedTypeSymbol.GetAttributes().Any(attr => attr.AttributeClass.Inherits(testClassAttributeSymbol))) { context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(Rule, namedTypeSymbol.Name)); } diff --git a/src/Analyzers/MSTest.Analyzers/Resources.Designer.cs b/src/Analyzers/MSTest.Analyzers/Resources.Designer.cs index 46445d28d4..d81903f9ed 100644 --- a/src/Analyzers/MSTest.Analyzers/Resources.Designer.cs +++ b/src/Analyzers/MSTest.Analyzers/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace MSTest.Analyzers { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -355,7 +355,7 @@ internal static string DataRowShouldBeValidMessageFormat_ArgumentCountMismatch { } /// - /// Looks up a localized string similar to DataRow argument type should match method parameter type. Mismatches occur at indices: {0}. + /// Looks up a localized string similar to DataRow argument types do not match method parameter types. {0}. /// internal static string DataRowShouldBeValidMessageFormat_ArgumentTypeMismatch { get { @@ -390,6 +390,15 @@ internal static string DataRowShouldBeValidMessageFormat_OnTestMethod { } } + /// + /// Looks up a localized string similar to Parameter '{0}' expects type '{1}', but the provided value has type '{2}'. + /// + internal static string DataRowShouldBeValidMessageFormat_ParameterMismatch { + get { + return ResourceManager.GetString("DataRowShouldBeValidMessageFormat_ParameterMismatch", resourceCulture); + } + } + /// /// Looks up a localized string similar to DataRow should be valid. /// @@ -618,6 +627,70 @@ internal static string DynamicDataShouldBeValidTitle { } } + /// + /// Looks up a localized string similar to When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts.. + /// + internal static string FlowTestContextCancellationTokenDescription { + get { + return ResourceManager.GetString("FlowTestContextCancellationTokenDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token'. + /// + internal static string FlowTestContextCancellationTokenMessageFormat { + get { + return ResourceManager.GetString("FlowTestContextCancellationTokenMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Flow TestContext.CancellationToken to async operations. + /// + internal static string FlowTestContextCancellationTokenTitle { + get { + return ResourceManager.GetString("FlowTestContextCancellationTokenTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: + ///-it can't be declared on a generic class + ///-it should be 'public' + ///-it should be 'static' + ///-it should not be 'async void' + ///-it should not be a special method (finalizer, operator...). + ///-it should not be generic + ///-it should take one parameter of type 'TestContext' + ///-return type should be 'void', 'Task' or 'ValueTask' + /// + ///The type declaring these methods should also respect the following rules: [rest of string was truncated]";. + /// + internal static string GlobalTestFixtureShouldBeValidDescription { + get { + return ResourceManager.GetString("GlobalTestFixtureShouldBeValidDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Global test fixture method '{0}' signature is invalid. + /// + internal static string GlobalTestFixtureShouldBeValidMessageFormat { + get { + return ResourceManager.GetString("GlobalTestFixtureShouldBeValidMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to GlobalTestInitialize and GlobalTestCleanup methods should have valid layout. + /// + internal static string GlobalTestFixtureShouldBeValidTitle { + get { + return ResourceManager.GetString("GlobalTestFixtureShouldBeValidTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert. /// @@ -708,6 +781,33 @@ internal static string PreferTestInitializeOverConstructorTitle { } } + /// + /// Looks up a localized string similar to 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests.. + /// + internal static string PreferTestMethodOverDataTestMethodAnalyzerDescription { + get { + return ResourceManager.GetString("PreferTestMethodOverDataTestMethodAnalyzerDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'DataTestMethod' is obsolete. Use 'TestMethod' instead.. + /// + internal static string PreferTestMethodOverDataTestMethodAnalyzerMessageFormat { + get { + return ResourceManager.GetString("PreferTestMethodOverDataTestMethodAnalyzerMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefer 'TestMethod' over 'DataTestMethod'. + /// + internal static string PreferTestMethodOverDataTestMethodAnalyzerTitle { + get { + return ResourceManager.GetString("PreferTestMethodOverDataTestMethodAnalyzerTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to Public methods should be test methods (marked with `[TestMethod]`).. /// @@ -780,6 +880,24 @@ internal static string ReviewAlwaysTrueAssertConditionAnalyzerTitle { } } + /// + /// Looks up a localized string similar to Use 'Assert.{0}' instead of 'StringAssert.{1}'. + /// + internal static string StringAssertToAssertMessageFormat { + get { + return ResourceManager.GetString("StringAssertToAssertMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'Assert' instead of 'StringAssert'. + /// + internal static string StringAssertToAssertTitle { + get { + return ResourceManager.GetString("StringAssertToAssertTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to Test classes, classes marked with the '[TestClass]' attribute, should respect the following layout to be considered valid by MSTest: ///- it should be 'public' (or 'internal' if '[assembly: DiscoverInternals]' attribute is set) @@ -876,6 +994,33 @@ internal static string TestCleanupShouldBeValidTitle { } } + /// + /// Looks up a localized string similar to Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods.. + /// + internal static string TestContextPropertyUsageDescription { + get { + return ResourceManager.GetString("TestContextPropertyUsageDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TestContext property '{0}' cannot be accessed in '{1}' method. + /// + internal static string TestContextPropertyUsageMessageFormat { + get { + return ResourceManager.GetString("TestContextPropertyUsageMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TestContext property cannot be accessed in this context. + /// + internal static string TestContextPropertyUsageTitle { + get { + return ResourceManager.GetString("TestContextPropertyUsageTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to 'TestContext' should be a non-static field or property assigned in constructor or for a property set by MSTest, it should follow the layout: ///- it should be 'public' regardless of whether '[assembly: DiscoverInternals]' attribute is set or not. @@ -1007,7 +1152,7 @@ internal static string TestMethodShouldNotBeIgnoredAnalyzerTitle { } /// - /// Looks up a localized string similar to Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored.. + /// Looks up a localized string similar to Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored.. /// internal static string TypeContainingTestMethodShouldBeATestClassDescription { get { @@ -1016,7 +1161,7 @@ internal static string TypeContainingTestMethodShouldBeATestClassDescription { } /// - /// Looks up a localized string similar to Class '{0}' contains test methods and should be marked with '[TestClass]'. + /// Looks up a localized string similar to Type '{0}' contains test methods and should be marked with '[TestClass]'. /// internal static string TypeContainingTestMethodShouldBeATestClassMessageFormat { get { @@ -1033,6 +1178,15 @@ internal static string TypeContainingTestMethodShouldBeATestClassTitle { } } + /// + /// Looks up a localized string similar to TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods. + /// + internal static string UnusedParameterSuppressorJustification { + get { + return ResourceManager.GetString("UnusedParameterSuppressorJustification", resourceCulture); + } + } + /// /// Looks up a localized string similar to Asynchronous test fixture methods do not require the 'Async' suffix. /// @@ -1114,6 +1268,33 @@ internal static string UseConditionBaseWithTestClassTitle { } } + /// + /// Looks up a localized string similar to Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes.. + /// + internal static string UseCooperativeCancellationForTimeoutDescription { + get { + return ResourceManager.GetString("UseCooperativeCancellationForTimeoutDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior. + /// + internal static string UseCooperativeCancellationForTimeoutMessageFormat { + get { + return ResourceManager.GetString("UseCooperativeCancellationForTimeoutMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'CooperativeCancellation = true' with '[Timeout]'. + /// + internal static string UseCooperativeCancellationForTimeoutTitle { + get { + return ResourceManager.GetString("UseCooperativeCancellationForTimeoutTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to '[DeploymentItem]' can be specified only on test class or test method. /// diff --git a/src/Analyzers/MSTest.Analyzers/Resources.resx b/src/Analyzers/MSTest.Analyzers/Resources.resx index 304dfec95d..45445b2d82 100644 --- a/src/Analyzers/MSTest.Analyzers/Resources.resx +++ b/src/Analyzers/MSTest.Analyzers/Resources.resx @@ -251,7 +251,10 @@ The type declaring these methods should also respect the following rules: DataRow argument count should match method parameter count (constructor arguments: {0}, method parameters: {1}) - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} + DataRow argument types do not match method parameter types. {0} + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' DataRow should only be set on a test method @@ -426,6 +429,9 @@ The type declaring these methods should also respect the following rules: Asynchronous test methods do not require the 'Async' suffix + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + [{0}] can only be set on methods marked with [TestMethod] @@ -445,10 +451,10 @@ The type declaring these methods should also respect the following rules: Type containing '[TestMethod]' should be marked with '[TestClass]' - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. - Class '{0}' contains test methods and should be marked with '[TestClass]' + Type '{0}' contains test methods and should be marked with '[TestClass]' 'System.ComponentModel.DescriptionAttribute' has no effect on test methods @@ -534,6 +540,12 @@ The type declaring these methods should also respect the following rules: Use 'Assert.{0}' instead of 'Assert.{1}' + + Use 'Assert' instead of 'StringAssert' + + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + The type of the generic parameter '{0}' could not be inferred. @@ -585,4 +597,64 @@ The type declaring these methods should also respect the following rules: An attribute that derives from 'RetryBaseAttribute' can be specified only on a test method - \ No newline at end of file + + Prefer 'TestMethod' over 'DataTestMethod' + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + + + Use 'CooperativeCancellation = true' with '[Timeout]' + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + + + TestContext property cannot be accessed in this context + + + TestContext property '{0}' cannot be accessed in '{1}' method + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + + + Flow TestContext.CancellationToken to async operations + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + + Global test fixture method '{0}' signature is invalid + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + diff --git a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ArrayBuilder.Enumerator.cs b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ArrayBuilder.Enumerator.cs index 2a2fd9a7e4..48340fbf6a 100644 --- a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ArrayBuilder.Enumerator.cs +++ b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ArrayBuilder.Enumerator.cs @@ -32,7 +32,7 @@ public readonly void Dispose() { } - readonly object? System.Collections.IEnumerator.Current => Current; + readonly object? IEnumerator.Current => Current; public void Reset() => _index = -1; } diff --git a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/BoundedCacheWithFactory.cs b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/BoundedCacheWithFactory.cs index 87250620aa..3a760e6bd9 100644 --- a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/BoundedCacheWithFactory.cs +++ b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/BoundedCacheWithFactory.cs @@ -4,7 +4,7 @@ namespace Analyzer.Utilities; /// /// Provides bounded cache for analyzers. -/// Acts as a good alternative to +/// Acts as a good alternative to /// when the cached value has a cyclic reference to the key preventing early garbage collection of entries. /// internal sealed class BoundedCacheWithFactory diff --git a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/DiagnosticExtensions.cs b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/DiagnosticExtensions.cs index 7316c3ebb5..dbed1d2ae6 100644 --- a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/DiagnosticExtensions.cs +++ b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/DiagnosticExtensions.cs @@ -169,7 +169,7 @@ public static void ReportNoLocationDiagnostic( { #pragma warning disable RS0030 // The symbol 'DiagnosticDescriptor.DiagnosticDescriptor.#ctor' is banned in this project: Use 'DiagnosticDescriptorHelper.Create' instead rule = new DiagnosticDescriptor(rule.Id, rule.Title, rule.MessageFormat, rule.Category, - effectiveSeverity.Value, rule.IsEnabledByDefault, rule.Description, rule.HelpLinkUri, rule.CustomTags.ToArray()); + effectiveSeverity.Value, rule.IsEnabledByDefault, rule.Description, rule.HelpLinkUri, [.. rule.CustomTags]); #pragma warning restore RS0030 } diff --git a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/IOperationExtensions.cs b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/IOperationExtensions.cs index b4f48fb09f..e3ec94bd4c 100644 --- a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/IOperationExtensions.cs +++ b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/IOperationExtensions.cs @@ -5,6 +5,7 @@ using Microsoft.CodeAnalysis.Operations; namespace MSTest.Analyzers.RoslynAnalyzerHelpers; + internal static class IOperationExtensions { public static ISymbol? GetReferencedMemberOrLocalOrParameter(this IOperation? operation) => operation switch diff --git a/src/Analyzers/MSTest.Analyzers/StringAssertToAssertAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/StringAssertToAssertAnalyzer.cs new file mode 100644 index 0000000000..eb0f44ffaf --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers/StringAssertToAssertAnalyzer.cs @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +using Analyzer.Utilities.Extensions; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// MSTEST0046: Use 'Assert' instead of 'StringAssert'. +/// +/// +/// The analyzer captures StringAssert method calls and suggests using equivalent Assert methods: +/// +/// +/// +/// StringAssert.Contains(value, substring)Assert.Contains(substring, value) +/// +/// +/// +/// +/// StringAssert.StartsWith(value, substring)Assert.StartsWith(substring, value) +/// +/// +/// +/// +/// StringAssert.EndsWith(value, substring)Assert.EndsWith(substring, value) +/// +/// +/// +/// +/// StringAssert.Matches(value, pattern)Assert.Matches(pattern, value) +/// +/// +/// +/// +/// StringAssert.DoesNotMatch(value, pattern)Assert.DoesNotMatch(pattern, value) +/// +/// +/// +/// +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +internal sealed class StringAssertToAssertAnalyzer : DiagnosticAnalyzer +{ + /// + /// Key to retrieve the proper assert method name from the properties bag. + /// + internal const string ProperAssertMethodNameKey = nameof(ProperAssertMethodNameKey); + + private static readonly LocalizableResourceString Title = new(nameof(Resources.StringAssertToAssertTitle), Resources.ResourceManager, typeof(Resources)); + private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.StringAssertToAssertMessageFormat), Resources.ResourceManager, typeof(Resources)); + + internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create( + DiagnosticIds.StringAssertToAssertRuleId, + Title, + MessageFormat, + null, + Category.Usage, + DiagnosticSeverity.Info, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(context => + { + if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingStringAssert, out INamedTypeSymbol? stringAssertTypeSymbol)) + { + return; + } + + context.RegisterOperationAction(context => AnalyzeInvocationOperation(context, stringAssertTypeSymbol), OperationKind.Invocation); + }); + } + + private static void AnalyzeInvocationOperation(OperationAnalysisContext context, INamedTypeSymbol stringAssertTypeSymbol) + { + var operation = (IInvocationOperation)context.Operation; + IMethodSymbol targetMethod = operation.TargetMethod; + + if (!SymbolEqualityComparer.Default.Equals(targetMethod.ContainingType, stringAssertTypeSymbol)) + { + return; + } + + // Map StringAssert methods to their equivalent Assert methods + string? assertMethodName = targetMethod.Name switch + { + "Contains" => "Contains", + "StartsWith" => "StartsWith", + "EndsWith" => "EndsWith", + "Matches" => "MatchesRegex", + "DoesNotMatch" => "DoesNotMatchRegex", + _ => null, + }; + + if (assertMethodName == null) + { + return; + } + + // StringAssert methods all have at least 2 arguments that need to be swapped + if (operation.Arguments.Length < 2) + { + return; + } + + ImmutableDictionary properties = ImmutableDictionary.Empty.Add(ProperAssertMethodNameKey, assertMethodName); + + context.ReportDiagnostic(context.Operation.CreateDiagnostic( + Rule, + properties: properties, + assertMethodName, + targetMethod.Name)); + } +} diff --git a/src/Analyzers/MSTest.Analyzers/TestClassShouldHaveTestMethodAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestClassShouldHaveTestMethodAnalyzer.cs index c8f38fac34..5ba9dde1b6 100644 --- a/src/Analyzers/MSTest.Analyzers/TestClassShouldHaveTestMethodAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/TestClassShouldHaveTestMethodAnalyzer.cs @@ -48,15 +48,17 @@ public override void Initialize(AnalysisContext context) INamedTypeSymbol? testMethodAttributeSymbol = context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestMethodAttribute); INamedTypeSymbol? assemblyInitializationAttributeSymbol = context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyInitializeAttribute); INamedTypeSymbol? assemblyCleanupAttributeSymbol = context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyCleanupAttribute); + INamedTypeSymbol? globalTestInitializeAttributeSymbol = context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestInitializeAttribute); + INamedTypeSymbol? globalTestCleanupAttributeSymbol = context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestCleanupAttribute); context.RegisterSymbolAction( - context => AnalyzeSymbol(context, testClassAttributeSymbol, testMethodAttributeSymbol, assemblyInitializationAttributeSymbol, assemblyCleanupAttributeSymbol), + context => AnalyzeSymbol(context, testClassAttributeSymbol, testMethodAttributeSymbol, assemblyInitializationAttributeSymbol, assemblyCleanupAttributeSymbol, globalTestInitializeAttributeSymbol, globalTestCleanupAttributeSymbol), SymbolKind.NamedType); } }); } private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol testClassAttributeSymbol, INamedTypeSymbol? testMethodAttributeSymbol, - INamedTypeSymbol? assemblyInitializationAttributeSymbol, INamedTypeSymbol? assemblyCleanupAttributeSymbol) + INamedTypeSymbol? assemblyInitializationAttributeSymbol, INamedTypeSymbol? assemblyCleanupAttributeSymbol, INamedTypeSymbol? globalTestInitializeAttributeSymbol, INamedTypeSymbol? globalTestCleanupAttributeSymbol) { var classSymbol = (INamedTypeSymbol)context.Symbol; @@ -91,7 +93,9 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo } if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, assemblyInitializationAttributeSymbol) - || SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, assemblyCleanupAttributeSymbol)) + || SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, assemblyCleanupAttributeSymbol) + || SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, globalTestInitializeAttributeSymbol) + || SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, globalTestCleanupAttributeSymbol)) { hasAssemblyAttribute = true; } diff --git a/src/Analyzers/MSTest.Analyzers/TestContextPropertyUsageAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestContextPropertyUsageAnalyzer.cs new file mode 100644 index 0000000000..1cedf89c78 --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers/TestContextPropertyUsageAnalyzer.cs @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +using Analyzer.Utilities.Extensions; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// MSTEST0047: . +/// +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class TestContextPropertyUsageAnalyzer : DiagnosticAnalyzer +{ + private static readonly LocalizableResourceString Title = new(nameof(Resources.TestContextPropertyUsageTitle), Resources.ResourceManager, typeof(Resources)); + private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.TestContextPropertyUsageMessageFormat), Resources.ResourceManager, typeof(Resources)); + private static readonly LocalizableResourceString Description = new(nameof(Resources.TestContextPropertyUsageDescription), Resources.ResourceManager, typeof(Resources)); + + internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create( + DiagnosticIds.TestContextPropertyUsageRuleId, + Title, + MessageFormat, + Description, + Category.Usage, + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + /// + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); + + // Properties that cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup + private static readonly ImmutableHashSet RestrictedInAllFixtureMethods = ImmutableHashSet.Create( + StringComparer.Ordinal, + "TestData", + "TestDisplayName", + "DataRow", + "DataConnection", + "TestName", + "ManagedMethod"); + + // Properties that cannot be accessed in assembly initialize or assembly cleanup + private static readonly ImmutableHashSet RestrictedInAssemblyMethods = ImmutableHashSet.Create( + StringComparer.Ordinal, + "FullyQualifiedTestClassName", + "ManagedType"); + + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(context => + { + if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestContext, out INamedTypeSymbol? testContextSymbol) + || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyInitializeAttribute, out INamedTypeSymbol? assemblyInitializeAttributeSymbol) + || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyCleanupAttribute, out INamedTypeSymbol? assemblyCleanupAttributeSymbol) + || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassInitializeAttribute, out INamedTypeSymbol? classInitializeAttributeSymbol) + || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassCleanupAttribute, out INamedTypeSymbol? classCleanupAttributeSymbol)) + { + return; + } + + context.RegisterOperationAction(context => AnalyzePropertyReference(context, testContextSymbol, assemblyInitializeAttributeSymbol, assemblyCleanupAttributeSymbol, classInitializeAttributeSymbol, classCleanupAttributeSymbol), OperationKind.PropertyReference); + }); + } + + private static void AnalyzePropertyReference( + OperationAnalysisContext context, + INamedTypeSymbol testContextSymbol, + INamedTypeSymbol assemblyInitializeAttributeSymbol, + INamedTypeSymbol assemblyCleanupAttributeSymbol, + INamedTypeSymbol classInitializeAttributeSymbol, + INamedTypeSymbol classCleanupAttributeSymbol) + { + var propertyReference = (IPropertyReferenceOperation)context.Operation; + + // Check if the property is a TestContext property + if (!SymbolEqualityComparer.Default.Equals(propertyReference.Property.ContainingType, testContextSymbol)) + { + return; + } + + string propertyName = propertyReference.Property.Name; + + // Check if we're in a forbidden context + if (context.ContainingSymbol is not IMethodSymbol containingMethod) + { + return; + } + + // Check for assembly initialize/cleanup methods + bool isAssemblyInitialize = containingMethod.HasAttribute(assemblyInitializeAttributeSymbol); + bool isAssemblyCleanup = containingMethod.HasAttribute(assemblyCleanupAttributeSymbol); + bool isClassInitialize = containingMethod.HasAttribute(classInitializeAttributeSymbol); + bool isClassCleanup = containingMethod.HasAttribute(classCleanupAttributeSymbol); + + bool isInAssemblyMethod = isAssemblyInitialize || isAssemblyCleanup; + bool isInFixtureMethod = isInAssemblyMethod || isClassInitialize || isClassCleanup; + + // Check if the property is restricted in the current context + if (isInFixtureMethod && RestrictedInAllFixtureMethods.Contains(propertyName)) + { + context.ReportDiagnostic(propertyReference.CreateDiagnostic(Rule, propertyName, GetMethodType(isAssemblyInitialize, isAssemblyCleanup, isClassInitialize, isClassCleanup))); + } + else if (isInAssemblyMethod && RestrictedInAssemblyMethods.Contains(propertyName)) + { + context.ReportDiagnostic(propertyReference.CreateDiagnostic(Rule, propertyName, GetMethodType(isAssemblyInitialize, isAssemblyCleanup, isClassInitialize, isClassCleanup))); + } + } + + private static string GetMethodType(bool isAssemblyInitialize, bool isAssemblyCleanup, bool isClassInitialize, bool isClassCleanup) + => (isAssemblyInitialize, isAssemblyCleanup, isClassInitialize, isClassCleanup) switch + { + (true, _, _, _) => "AssemblyInitialize", + (_, true, _, _) => "AssemblyCleanup", + (_, _, true, _) => "ClassInitialize", + (_, _, _, true) => "ClassCleanup", + _ => "unknown", + }; +} diff --git a/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs index 4297c944d7..6838d3bbc7 100644 --- a/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs @@ -92,11 +92,26 @@ private static bool AssignsParameterToMember(IParameterSymbol parameter, ISymbol operation = expressionStatementOperation.Operation; } - return operation is ISimpleAssignmentOperation assignmentOperation && + if (operation is ISimpleAssignmentOperation assignmentOperation && assignmentOperation.Target is IMemberReferenceOperation targetMemberReference && - SymbolEqualityComparer.Default.Equals(targetMemberReference.Member, member) && - assignmentOperation.Value is IParameterReferenceOperation parameterReference && - SymbolEqualityComparer.Default.Equals(parameterReference.Parameter, parameter); + SymbolEqualityComparer.Default.Equals(targetMemberReference.Member, member)) + { + // Extract parameter reference from the value, unwrapping from coalesce operation if necessary + IOperation effectiveValue = assignmentOperation.Value; + if (effectiveValue is ICoalesceOperation coalesceOperation) + { + effectiveValue = coalesceOperation.Value; + } + + // Check if the effective value is a parameter reference to our target parameter + if (effectiveValue is IParameterReferenceOperation parameterReference && + SymbolEqualityComparer.Default.Equals(parameterReference.Parameter, parameter)) + { + return true; + } + } + + return false; } private static void CollectTestContextFieldsAssignedInConstructor( @@ -125,11 +140,21 @@ private static void CollectTestContextFieldsAssignedInConstructor( } if (operation is ISimpleAssignmentOperation assignmentOperation && - assignmentOperation.Target is IMemberReferenceOperation { Member: IFieldSymbol { } candidateField } && - assignmentOperation.Value is IParameterReferenceOperation parameterReference && - SymbolEqualityComparer.Default.Equals(parameterReference.Parameter, testContextParameter)) + assignmentOperation.Target is IMemberReferenceOperation { Member: IFieldSymbol { } candidateField }) { - fieldsAssignedInConstructor.Add(candidateField); + // Extract parameter reference from the value, unwrapping from coalesce operation if necessary + IOperation effectiveValue = assignmentOperation.Value; + if (effectiveValue is ICoalesceOperation coalesceOperation) + { + effectiveValue = coalesceOperation.Value; + } + + // Check if the effective value is a parameter reference to our target parameter + if (effectiveValue is IParameterReferenceOperation parameterReference && + SymbolEqualityComparer.Default.Equals(parameterReference.Parameter, testContextParameter)) + { + fieldsAssignedInConstructor.Add(candidateField); + } } } @@ -187,7 +212,7 @@ public override void Initialize(AnalysisContext context) return; } - fieldsAssignedInConstructor = new(); + fieldsAssignedInConstructor = []; context.RegisterOperationBlockAction(context => { diff --git a/src/Analyzers/MSTest.Analyzers/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs index f5c4d19827..998f4f1ba5 100644 --- a/src/Analyzers/MSTest.Analyzers/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs @@ -56,7 +56,7 @@ public override void Initialize(AnalysisContext context) private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol testClassAttributeSymbol, INamedTypeSymbol testMethodAttributeSymbol) { var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; - if (namedTypeSymbol.TypeKind != TypeKind.Class + if ((namedTypeSymbol.TypeKind != TypeKind.Class && namedTypeSymbol.TypeKind != TypeKind.Struct) || namedTypeSymbol.IsAbstract) { return; diff --git a/src/Analyzers/MSTest.Analyzers/UnusedParameterSuppressor.cs b/src/Analyzers/MSTest.Analyzers/UnusedParameterSuppressor.cs new file mode 100644 index 0000000000..3bc64d707f --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers/UnusedParameterSuppressor.cs @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +using Analyzer.Utilities.Extensions; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// MSTEST0047: . +/// +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class UnusedParameterSuppressor : DiagnosticSuppressor +{ + // IDE0060: Remove unused parameter 'name' if it is not part of a shipped public API + // https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0060 + private const string SuppressedDiagnosticId = "IDE0060"; + + internal static readonly SuppressionDescriptor Rule = + new(DiagnosticIds.UnusedParameterSuppressorRuleId, SuppressedDiagnosticId, Resources.UnusedParameterSuppressorJustification); + + /// + public override ImmutableArray SupportedSuppressions { get; } = ImmutableArray.Create(Rule); + + /// + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyInitializeAttribute, out INamedTypeSymbol? assemblyInitializeAttributeSymbol) + || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassInitializeAttribute, out INamedTypeSymbol? classInitializeAttributeSymbol) + || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestContext, out INamedTypeSymbol? testContextSymbol)) + { + return; + } + + INamedTypeSymbol? globalTestInitializeAttributeSymbol = context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestInitializeAttribute); + INamedTypeSymbol? globalTestCleanupAttributeSymbol = context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestCleanupAttribute); + + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) + { + // The diagnostic is reported on the parameter + if (diagnostic.Location.SourceTree is not { } tree) + { + continue; + } + + SyntaxNode root = tree.GetRoot(context.CancellationToken); + SyntaxNode node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + + SemanticModel semanticModel = context.GetSemanticModel(tree); + ISymbol? declaredSymbol = semanticModel.GetDeclaredSymbol(node, context.CancellationToken); + + if (declaredSymbol is IParameterSymbol parameter + && SymbolEqualityComparer.Default.Equals(testContextSymbol, parameter.Type) + && parameter.ContainingSymbol is IMethodSymbol method + && method.GetAttributes().Any(attr => + SymbolEqualityComparer.Default.Equals(attr.AttributeClass, assemblyInitializeAttributeSymbol) || + SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classInitializeAttributeSymbol) || + SymbolEqualityComparer.Default.Equals(attr.AttributeClass, globalTestInitializeAttributeSymbol) || + SymbolEqualityComparer.Default.Equals(attr.AttributeClass, globalTestCleanupAttributeSymbol))) + { + context.ReportSuppression(Suppression.Create(Rule, diagnostic)); + } + } + } +} diff --git a/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestFixtureMethodSuppressor.cs b/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestFixtureMethodSuppressor.cs index 9f7995e4cf..3cd37a4c22 100644 --- a/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestFixtureMethodSuppressor.cs +++ b/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestFixtureMethodSuppressor.cs @@ -41,6 +41,9 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) return; } + INamedTypeSymbol? globalTestInitializeAttributeSymbol = context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestInitializeAttribute); + INamedTypeSymbol? globalTestCleanupAttributeSymbol = context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestCleanupAttribute); + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) { // The diagnostic is reported on the test method @@ -61,7 +64,9 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classInitializeAttributeSymbol) || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classCleanupAttributeSymbol) || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testInitializeAttributeSymbol) - || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testCleanupAttributeSymbol))) + || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testCleanupAttributeSymbol) + || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, globalTestInitializeAttributeSymbol) + || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, globalTestCleanupAttributeSymbol))) { context.ReportSuppression(Suppression.Create(Rule, diagnostic)); } diff --git a/src/Analyzers/MSTest.Analyzers/UseAttributeOnTestMethodAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/UseAttributeOnTestMethodAnalyzer.cs index 63c73fd004..f3f8b2a28f 100644 --- a/src/Analyzers/MSTest.Analyzers/UseAttributeOnTestMethodAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/UseAttributeOnTestMethodAnalyzer.cs @@ -127,13 +127,15 @@ public sealed class UseAttributeOnTestMethodAnalyzer : DiagnosticAnalyzer isEnabledByDefault: true); // IMPORTANT: Remember to add any new rule to the rule tuple. + // IMPORTANT: The order is important. For example, Owner, Priority, and Description are also TestProperty. We report the first violation and then bail-out. + // It may be a better idea to consolidate OwnerRule, PriorityRule, DescriptionRule, and TestPropertyRule into a single rule. private static readonly List<(string AttributeFullyQualifiedName, DiagnosticDescriptor Rule)> RuleTuples = [ (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingOwnerAttribute, OwnerRule), (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingPriorityAttribute, PriorityRule), + (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingDescriptionAttribute, DescriptionRule), (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestPropertyAttribute, TestPropertyRule), (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingWorkItemAttribute, WorkItemRule), - (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingDescriptionAttribute, DescriptionRule), (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingExpectedExceptionBaseAttribute, ExpectedExceptionRule), (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingCssIterationAttribute, CssIterationRule), (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingCssProjectStructureAttribute, CssProjectStructureRule), @@ -214,6 +216,7 @@ private static void AnalyzeSymbol( if (methodAttribute.AttributeClass.Inherits(attributeSymbol)) { attributes.Add((methodAttribute, rule)); + break; } } } diff --git a/src/Analyzers/MSTest.Analyzers/UseCooperativeCancellationForTimeoutAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/UseCooperativeCancellationForTimeoutAnalyzer.cs new file mode 100644 index 0000000000..d73e67d3c0 --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers/UseCooperativeCancellationForTimeoutAnalyzer.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +using Analyzer.Utilities.Extensions; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// MSTEST0045: . +/// +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class UseCooperativeCancellationForTimeoutAnalyzer : DiagnosticAnalyzer +{ + private static readonly LocalizableResourceString Title = new(nameof(Resources.UseCooperativeCancellationForTimeoutTitle), Resources.ResourceManager, typeof(Resources)); + private static readonly LocalizableResourceString Description = new(nameof(Resources.UseCooperativeCancellationForTimeoutDescription), Resources.ResourceManager, typeof(Resources)); + private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.UseCooperativeCancellationForTimeoutMessageFormat), Resources.ResourceManager, typeof(Resources)); + + internal static readonly DiagnosticDescriptor UseCooperativeCancellationForTimeoutRule = DiagnosticDescriptorHelper.Create( + DiagnosticIds.UseCooperativeCancellationForTimeoutRuleId, + Title, + MessageFormat, + Description, + Category.Design, + DiagnosticSeverity.Info, + isEnabledByDefault: true); + + /// + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(UseCooperativeCancellationForTimeoutRule); + + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(context => + { + if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTimeoutAttribute, out INamedTypeSymbol? timeoutAttributeSymbol)) + { + context.RegisterSymbolAction( + context => AnalyzeSymbol(context, timeoutAttributeSymbol), + SymbolKind.Method); + } + }); + } + + private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol timeoutAttributeSymbol) + { + var methodSymbol = (IMethodSymbol)context.Symbol; + + AttributeData? timeoutAttribute = null; + foreach (AttributeData attribute in methodSymbol.GetAttributes()) + { + if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, timeoutAttributeSymbol)) + { + timeoutAttribute = attribute; + break; + } + } + + // Report diagnostic if CooperativeCancellation is not explicitly set to true + if (timeoutAttribute is not null + && !timeoutAttribute.NamedArguments.Any(x => x.Key == "CooperativeCancellation" && x.Value.Value is bool boolValue && boolValue)) + { + if (timeoutAttribute.ApplicationSyntaxReference?.GetSyntax() is { } syntax) + { + context.ReportDiagnostic(syntax.CreateDiagnostic(UseCooperativeCancellationForTimeoutRule)); + } + } + } +} diff --git a/src/Analyzers/MSTest.Analyzers/UseNewerAssertThrowsAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/UseNewerAssertThrowsAnalyzer.cs index d28aa7890f..0888a9d72d 100644 --- a/src/Analyzers/MSTest.Analyzers/UseNewerAssertThrowsAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/UseNewerAssertThrowsAnalyzer.cs @@ -28,7 +28,7 @@ internal sealed class UseNewerAssertThrowsAnalyzer : DiagnosticAnalyzer MessageFormat, null, Category.Usage, - DiagnosticSeverity.Info, + DiagnosticSeverity.Warning, isEnabledByDefault: true); public override ImmutableArray SupportedDiagnostics { get; } diff --git a/src/Analyzers/MSTest.Analyzers/UseProperAssertMethodsAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/UseProperAssertMethodsAnalyzer.cs index ef26733c67..7b49b0bc40 100644 --- a/src/Analyzers/MSTest.Analyzers/UseProperAssertMethodsAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/UseProperAssertMethodsAnalyzer.cs @@ -41,6 +41,36 @@ namespace MSTest.Analyzers; /// Assert.[AreEqual|AreNotEqual](null, x) /// /// +/// +/// +/// Assert.IsTrue(myString.[StartsWith|EndsWith|Contains]("...")) +/// +/// +/// +/// +/// Assert.IsFalse(myString.[StartsWith|EndsWith|Contains]("...")) +/// +/// +/// +/// +/// Assert.IsTrue(myCollection.Contains(...)) +/// +/// +/// +/// +/// Assert.IsFalse(myCollection.Contains(...)) +/// +/// +/// +/// +/// Assert.[IsTrue|IsFalse](x [>|>=|<|<=] y) +/// +/// +/// +/// +/// Assert.AreEqual([0|X], myCollection.[Count|Length]) +/// +/// /// /// [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] @@ -60,6 +90,36 @@ private enum EqualityCheckStatus NotEquals, } + private enum StringMethodCheckStatus + { + Unknown, + StartsWith, + EndsWith, + Contains, + } + + private enum ComparisonCheckStatus + { + Unknown, + GreaterThan, + GreaterThanOrEqual, + LessThan, + LessThanOrEqual, + } + + private enum CollectionCheckStatus + { + Unknown, + Contains, + } + + private enum CountCheckStatus + { + Unknown, + IsEmpty, + HasCount, + } + internal const string ProperAssertMethodNameKey = nameof(ProperAssertMethodNameKey); /// @@ -120,6 +180,18 @@ private enum EqualityCheckStatus /// internal const string CodeFixModeRemoveArgument = nameof(CodeFixModeRemoveArgument); + /// + /// This mode means the codefix operation is as follows for collection count checks: + /// + /// Find the right assert method name from the properties bag using . + /// Replace the identifier syntax for the invocation with the right assert method name. + /// Transform arguments based on the count check pattern. + /// + /// Example: For Assert.AreEqual(0, list.Count), it will become Assert.IsEmpty(list). + /// Example: For Assert.AreEqual(3, list.Count), it will become Assert.HasCount(3, list). + /// + internal const string CodeFixModeCollectionCount = nameof(CodeFixModeCollectionCount); + private static readonly LocalizableResourceString Title = new(nameof(Resources.UseProperAssertMethodsTitle), Resources.ResourceManager, typeof(Resources)); private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.UseProperAssertMethodsMessageFormat), Resources.ResourceManager, typeof(Resources)); @@ -325,6 +397,97 @@ private static bool CanUseTypeAsObject(Compilation compilation, ITypeSymbol? typ => type is null || compilation.ClassifyCommonConversion(type, compilation.GetSpecialType(SpecialType.System_Object)).Exists; + private static StringMethodCheckStatus RecognizeStringMethodCheck( + IOperation operation, + out SyntaxNode? stringExpression, + out SyntaxNode? substringExpression) + { + if (operation is IInvocationOperation invocation && + invocation.TargetMethod.ContainingType?.SpecialType == SpecialType.System_String && + invocation.Arguments.Length == 1) + { + string methodName = invocation.TargetMethod.Name; + if (methodName is "StartsWith" or "EndsWith" or "Contains") + { + stringExpression = invocation.Instance?.Syntax; + substringExpression = invocation.Arguments[0].Value.Syntax; + + return methodName switch + { + "StartsWith" => StringMethodCheckStatus.StartsWith, + "EndsWith" => StringMethodCheckStatus.EndsWith, + "Contains" => StringMethodCheckStatus.Contains, + _ => StringMethodCheckStatus.Unknown, + }; + } + } + + stringExpression = null; + substringExpression = null; + return StringMethodCheckStatus.Unknown; + } + + private static CollectionCheckStatus RecognizeCollectionMethodCheck( + IOperation operation, + out SyntaxNode? collectionExpression, + out SyntaxNode? itemExpression) + { + if (operation is IInvocationOperation invocation) + { + string methodName = invocation.TargetMethod.Name; + + // Check for Collection.Contains(item) + if (methodName == "Contains" && invocation.Arguments.Length == 1) + { + // Ensure it's a collection type (implements IEnumerable) + ITypeSymbol? receiverType = invocation.Instance?.Type; + if (receiverType is not null && + IsCollectionType(receiverType)) + { + collectionExpression = invocation.Instance?.Syntax; + itemExpression = invocation.Arguments[0].Value.Syntax; + return CollectionCheckStatus.Contains; + } + } + } + + collectionExpression = null; + itemExpression = null; + return CollectionCheckStatus.Unknown; + } + + private static bool IsCollectionType(ITypeSymbol type) + // Check if the type implements IEnumerable (but is not string) + => type.SpecialType != SpecialType.System_String && type.AllInterfaces.Any(i => + i.SpecialType == SpecialType.System_Collections_IEnumerable || + (i.OriginalDefinition?.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T)); + + private static ComparisonCheckStatus RecognizeComparisonCheck( + IOperation operation, + out SyntaxNode? leftExpression, + out SyntaxNode? rightExpression) + { + if (operation is IBinaryOperation binaryOperation && + binaryOperation.OperatorMethod is not { MethodKind: MethodKind.UserDefinedOperator }) + { + leftExpression = binaryOperation.LeftOperand.Syntax; + rightExpression = binaryOperation.RightOperand.Syntax; + + return binaryOperation.OperatorKind switch + { + BinaryOperatorKind.GreaterThan => ComparisonCheckStatus.GreaterThan, + BinaryOperatorKind.GreaterThanOrEqual => ComparisonCheckStatus.GreaterThanOrEqual, + BinaryOperatorKind.LessThan => ComparisonCheckStatus.LessThan, + BinaryOperatorKind.LessThanOrEqual => ComparisonCheckStatus.LessThanOrEqual, + _ => ComparisonCheckStatus.Unknown, + }; + } + + leftExpression = null; + rightExpression = null; + return ComparisonCheckStatus.Unknown; + } + private static void AnalyzeIsTrueOrIsFalseInvocation(OperationAnalysisContext context, IOperation conditionArgument, bool isTrueInvocation) { RoslynDebug.Assert(context.Operation is IInvocationOperation, "Expected IInvocationOperation."); @@ -361,6 +524,158 @@ private static void AnalyzeIsTrueOrIsFalseInvocation(OperationAnalysisContext co return; } + // Check for string method patterns: myString.StartsWith/EndsWith/Contains(...) + StringMethodCheckStatus stringMethodStatus = RecognizeStringMethodCheck(conditionArgument, out SyntaxNode? stringExpr, out SyntaxNode? substringExpr); + if (stringMethodStatus != StringMethodCheckStatus.Unknown) + { + // Handle both IsTrue and IsFalse cases with string methods + if (isTrueInvocation) + { + string properAssertMethod = stringMethodStatus switch + { + StringMethodCheckStatus.StartsWith => "StartsWith", + StringMethodCheckStatus.EndsWith => "EndsWith", + StringMethodCheckStatus.Contains => "Contains", + _ => throw new InvalidOperationException("Unexpected StringMethodCheckStatus value."), + }; + + ImmutableDictionary.Builder properties = ImmutableDictionary.CreateBuilder(); + properties.Add(ProperAssertMethodNameKey, properAssertMethod); + properties.Add(CodeFixModeKey, CodeFixModeAddArgument); + context.ReportDiagnostic(context.Operation.CreateDiagnostic( + Rule, + additionalLocations: ImmutableArray.Create(conditionArgument.Syntax.GetLocation(), substringExpr!.GetLocation(), stringExpr!.GetLocation()), + properties: properties.ToImmutable(), + properAssertMethod, + "IsTrue")); + return; + } + else + { + // For IsFalse with string methods, suggest the negative assertions + string properAssertMethod = stringMethodStatus switch + { + StringMethodCheckStatus.StartsWith => "DoesNotStartWith", + StringMethodCheckStatus.EndsWith => "DoesNotEndWith", + StringMethodCheckStatus.Contains => "DoesNotContain", + _ => throw new InvalidOperationException("Unexpected StringMethodCheckStatus value."), + }; + + ImmutableDictionary.Builder properties = ImmutableDictionary.CreateBuilder(); + properties.Add(ProperAssertMethodNameKey, properAssertMethod); + properties.Add(CodeFixModeKey, CodeFixModeAddArgument); + context.ReportDiagnostic(context.Operation.CreateDiagnostic( + Rule, + additionalLocations: ImmutableArray.Create(conditionArgument.Syntax.GetLocation(), substringExpr!.GetLocation(), stringExpr!.GetLocation()), + properties: properties.ToImmutable(), + properAssertMethod, + "IsFalse")); + return; + } + } + + // Check for collection method patterns: myCollection.Contains(...) + CollectionCheckStatus collectionMethodStatus = RecognizeCollectionMethodCheck(conditionArgument, out SyntaxNode? collectionExpr, out SyntaxNode? itemExpr); + if (collectionMethodStatus != CollectionCheckStatus.Unknown) + { + if (collectionMethodStatus == CollectionCheckStatus.Contains) + { + if (isTrueInvocation) + { + string properAssertMethod = "Contains"; + + ImmutableDictionary.Builder properties = ImmutableDictionary.CreateBuilder(); + properties.Add(ProperAssertMethodNameKey, properAssertMethod); + properties.Add(CodeFixModeKey, CodeFixModeAddArgument); + context.ReportDiagnostic(context.Operation.CreateDiagnostic( + Rule, + additionalLocations: ImmutableArray.Create(conditionArgument.Syntax.GetLocation(), itemExpr!.GetLocation(), collectionExpr!.GetLocation()), + properties: properties.ToImmutable(), + properAssertMethod, + "IsTrue")); + return; + } + else + { + // For IsFalse with collection Contains, suggest DoesNotContain + string properAssertMethod = "DoesNotContain"; + + ImmutableDictionary.Builder properties = ImmutableDictionary.CreateBuilder(); + properties.Add(ProperAssertMethodNameKey, properAssertMethod); + properties.Add(CodeFixModeKey, CodeFixModeAddArgument); + context.ReportDiagnostic(context.Operation.CreateDiagnostic( + Rule, + additionalLocations: ImmutableArray.Create(conditionArgument.Syntax.GetLocation(), itemExpr!.GetLocation(), collectionExpr!.GetLocation()), + properties: properties.ToImmutable(), + properAssertMethod, + "IsFalse")); + return; + } + } + } + + // Check for comparison patterns: a > b, a >= b, a < b, a <= b + ComparisonCheckStatus comparisonStatus = RecognizeComparisonCheck(conditionArgument, out SyntaxNode? leftExpr, out SyntaxNode? rightExpr); + if (comparisonStatus != ComparisonCheckStatus.Unknown) + { + string properAssertMethod = (isTrueInvocation, comparisonStatus) switch + { + (true, ComparisonCheckStatus.GreaterThan) => "IsGreaterThan", + (true, ComparisonCheckStatus.GreaterThanOrEqual) => "IsGreaterThanOrEqualTo", + (true, ComparisonCheckStatus.LessThan) => "IsLessThan", + (true, ComparisonCheckStatus.LessThanOrEqual) => "IsLessThanOrEqualTo", + (false, ComparisonCheckStatus.GreaterThan) => "IsLessThanOrEqualTo", + (false, ComparisonCheckStatus.GreaterThanOrEqual) => "IsLessThan", + (false, ComparisonCheckStatus.LessThan) => "IsGreaterThanOrEqualTo", + (false, ComparisonCheckStatus.LessThanOrEqual) => "IsGreaterThan", + _ => throw new InvalidOperationException("Unexpected ComparisonCheckStatus value."), + }; + + // For Assert.IsGreaterThan, IsLessThan etc., the method signature is (lowerBound, value) or (upperBound, value) + // So for a > b -> Assert.IsGreaterThan(b, a) where b is the lower bound and a is the value + // For a < b -> Assert.IsLessThan(b, a) where b is the upper bound and a is the value + SyntaxNode? firstArg, secondArg; + switch ((isTrueInvocation, comparisonStatus)) + { + // a > b -> IsGreaterThan(b, a) + case (true, ComparisonCheckStatus.GreaterThan): + // a >= b -> IsGreaterThanOrEqualTo(b, a) + case (true, ComparisonCheckStatus.GreaterThanOrEqual): + // !(a < b) -> IsGreaterThanOrEqualTo(b, a) + case (false, ComparisonCheckStatus.LessThan): + // !(a <= b) -> IsGreaterThan(b, a) + case (false, ComparisonCheckStatus.LessThanOrEqual): + firstArg = rightExpr; // b becomes first arg (lower bound) + secondArg = leftExpr; // a becomes second arg (value) + break; + // a < b -> IsLessThan(b, a) + case (true, ComparisonCheckStatus.LessThan): + // a <= b -> IsLessThanOrEqualTo(b, a) + case (true, ComparisonCheckStatus.LessThanOrEqual): + // !(a > b) -> IsLessThanOrEqualTo(b, a) + case (false, ComparisonCheckStatus.GreaterThan): + // !(a >= b) -> IsLessThan(b, a) + case (false, ComparisonCheckStatus.GreaterThanOrEqual): + firstArg = rightExpr; // b becomes first arg (upper bound) + secondArg = leftExpr; // a becomes second arg (value) + break; + + default: + throw new InvalidOperationException("Unexpected comparison case."); + } + + ImmutableDictionary.Builder properties = ImmutableDictionary.CreateBuilder(); + properties.Add(ProperAssertMethodNameKey, properAssertMethod); + properties.Add(CodeFixModeKey, CodeFixModeAddArgument); + context.ReportDiagnostic(context.Operation.CreateDiagnostic( + Rule, + additionalLocations: ImmutableArray.Create(conditionArgument.Syntax.GetLocation(), firstArg!.GetLocation(), secondArg!.GetLocation()), + properties: properties.ToImmutable(), + properAssertMethod, + isTrueInvocation ? "IsTrue" : "IsFalse")); + return; + } + EqualityCheckStatus equalityCheckStatus = RecognizeEqualityCheck(conditionArgument, out SyntaxNode? toBecomeExpected, out SyntaxNode? toBecomeActual, out ITypeSymbol? leftType, out ITypeSymbol? rightType); if (equalityCheckStatus != EqualityCheckStatus.Unknown && CanUseTypeAsObject(context.Compilation, leftType) && @@ -392,6 +707,64 @@ private static void AnalyzeIsTrueOrIsFalseInvocation(OperationAnalysisContext co private static void AnalyzeAreEqualOrAreNotEqualInvocation(OperationAnalysisContext context, IOperation expectedArgument, bool isAreEqualInvocation) { + // Check for collection count patterns: collection.Count/Length == 0 or collection.Count/Length == X + if (isAreEqualInvocation) + { + if (TryGetSecondArgumentValue((IInvocationOperation)context.Operation, out IOperation? actualArgumentValue)) + { + // Check if we're comparing a count/length property + CountCheckStatus countStatus = RecognizeCountCheck( + expectedArgument, + actualArgumentValue, + out SyntaxNode? collectionExpr, + out _, + out _); + + if (countStatus != CountCheckStatus.Unknown) + { + string properAssertMethod = countStatus == CountCheckStatus.IsEmpty ? "IsEmpty" : "HasCount"; + + ImmutableDictionary.Builder properties = ImmutableDictionary.CreateBuilder(); + properties.Add(ProperAssertMethodNameKey, properAssertMethod); + + if (countStatus == CountCheckStatus.IsEmpty) + { + // Assert.IsEmpty(collection) + properties.Add(CodeFixModeKey, CodeFixModeCollectionCount); + context.ReportDiagnostic(context.Operation.CreateDiagnostic( + Rule, + additionalLocations: ImmutableArray.Create( + expectedArgument.Syntax.GetLocation(), // argument to remove/modify + actualArgumentValue.Syntax.GetLocation(), // argument to remove/modify + collectionExpr!.GetLocation()), // collection expression + properties: properties.ToImmutable(), + properAssertMethod, + "AreEqual")); + } + else + { + // Assert.HasCount(expectedCount, collection) + properties.Add(CodeFixModeKey, CodeFixModeCollectionCount); + SyntaxNode expectedCountExpr = expectedArgument.ConstantValue.HasValue && expectedArgument.ConstantValue.Value is int ? + expectedArgument.Syntax : actualArgumentValue.Syntax; + + context.ReportDiagnostic(context.Operation.CreateDiagnostic( + Rule, + additionalLocations: ImmutableArray.Create( + expectedArgument.Syntax.GetLocation(), // first original argument + actualArgumentValue.Syntax.GetLocation(), // second original argument + collectionExpr!.GetLocation(), // collection expression + expectedCountExpr.GetLocation()), // count value expression + properties: properties.ToImmutable(), + properAssertMethod, + "AreEqual")); + } + + return; + } + } + } + // Don't flag a warning for Assert.AreNotEqual([true|false], x). // This is not the same as Assert.IsFalse(x). if (isAreEqualInvocation && expectedArgument is ILiteralOperation { ConstantValue: { HasValue: true, Value: bool expectedLiteralBoolean } }) @@ -446,6 +819,49 @@ actualArgumentValue.Type is { } actualType && } } + private static CountCheckStatus RecognizeCountCheck( + IOperation expectedArgument, + IOperation actualArgument, + out SyntaxNode? collectionExpression, + out SyntaxNode? countExpression, + out int countValue) + { + // Check if expectedArgument is a literal and actualArgument is a count/length property + if (expectedArgument.ConstantValue.HasValue && + expectedArgument.ConstantValue.Value is int expectedValue && + expectedValue >= 0 && + actualArgument is IPropertyReferenceOperation propertyRef && + propertyRef.Property.Name is "Count" or "Length" && + propertyRef.Instance?.Type is not null && + IsCollectionType(propertyRef.Instance.Type)) + { + collectionExpression = propertyRef.Instance.Syntax; + countExpression = propertyRef.Syntax; + countValue = expectedValue; + return expectedValue == 0 ? CountCheckStatus.IsEmpty : CountCheckStatus.HasCount; + } + + // Check if actualArgument is a literal and expectedArgument is a count/length property + if (actualArgument.ConstantValue.HasValue && + actualArgument.ConstantValue.Value is int actualValue && + actualValue >= 0 && + expectedArgument is IPropertyReferenceOperation propertyRef2 && + propertyRef2.Property.Name is "Count" or "Length" && + propertyRef2.Instance?.Type is not null && + IsCollectionType(propertyRef2.Instance.Type)) + { + collectionExpression = propertyRef2.Instance.Syntax; + countExpression = propertyRef2.Syntax; + countValue = actualValue; + return actualValue == 0 ? CountCheckStatus.IsEmpty : CountCheckStatus.HasCount; + } + + collectionExpression = null; + countExpression = null; + countValue = 0; + return CountCheckStatus.Unknown; + } + private static bool TryGetFirstArgumentValue(IInvocationOperation operation, [NotNullWhen(true)] out IOperation? argumentValue) => TryGetArgumentValueForParameterOrdinal(operation, 0, out argumentValue); diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf index d40df19f9c..e80dfe879f 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf @@ -277,8 +277,13 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - Typ argumentu DataRow by měl odpovídat typu parametru metody. V indexech dochází k neshodě: {0} + DataRow argument types do not match method parameter types. {0} + Typy argumentů DataRow neodpovídají typům parametrů metody. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + Parametr '{0}' očekává typ '{1}', ale zadaná hodnota má typ '{2}' @@ -427,6 +432,66 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: Položka DynamicData by měla být platná. + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + Při volání asynchronních metod, které mají přetížení akceptující parametr CancellationToken, upřednostňujte použití přetížení s TestContext.CancellationTokenSource.Token, aby se umožnilo kooperativní rušení a dodržování časových limitů testů. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + Zvažte použití přetížení, které přijímá CancellationToken a předejte TestContext.CancellationTokenSource.Token. + + + + Flow TestContext.CancellationToken to async operations + Přenesení TestContext.CancellationToken do asynchronních operací + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert Místo trvalého neúspěšného vyhodnocovacího výrazu „Assert.{0}“ použijte „Assert.Fail“. @@ -437,6 +502,21 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: Místo trvalého neúspěšného vyhodnocovacího výrazu použijte „Assert.Fail“. + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + Možnost DataTestMethodAttribute je zastaralá a neposkytuje žádné funkce navíc oproti možnosti TestMethodAttribute. Pro všechny testovací metody, včetně parametrizovaných testů, použijte možnost TestMethodAttribute. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + Možnost DataTestMethod je zastaralá. Místo ní použijte možnost TestMethod. + + + + Prefer 'TestMethod' over 'DataTestMethod' + Preferovat TestMethod před DataTestMethod + + Review or remove the assertion as its condition is known to be always true Zkontrolujte nebo odeberte kontrolní výraz, protože jeho podmínka je vždy true. @@ -517,6 +597,16 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: Veřejné typy by měly být testovací třídy. + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + Použijte Assert.{0}' místo StringAssert.{1}' + + + + Use 'Assert' instead of 'StringAssert' + Použijte Assert místo StringAssert + + Test class '{0}' should be valid Testovací třída {0} by měla být platná. @@ -720,12 +810,12 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. - Typ obsahující [TestMethod] by měl mít označení [TestClass], jinak bude testovací metoda bez jakéhokoli upozornění ignorována. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Typ obsahující [TestMethod] by měl mít označení [TestClass], jinak se bude testovací metoda bez upozornění ignorovat. - Class '{0}' contains test methods and should be marked with '[TestClass]' + Type '{0}' contains test methods and should be marked with '[TestClass]' Třída {0} obsahuje testovací metody a měla by mít označení [TestClass]. @@ -744,6 +834,11 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: Asynchronní testovací metody nevyžadují příponu Async. + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + Parametr TestContext vyžaduje MSTest pro metody AssemblyInitialize a ClassInitialize. + + [{0}] can only be set on methods marked with [TestMethod] [{0}] lze nastavit pouze u metod označených pomocí metody [TestMethod]. @@ -764,6 +859,21 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: Použít ConditionBaseAttribute u testovacích tříd + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + Použití „[Timeout]“ bez explicitního nastavení „CooperativeCancellation = true“ se nedoporučuje. V budoucí verzi se kooperativní zrušení stane výchozím chováním. Nastavte „CooperativeCancellation = true“, abyste zapnuli doporučené chování a vyhnuli se změnám, které by mohly způsobit problémy. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + Použijte „CooperativeCancellation = true“ s „[Timeout]“, abyste povolili chování kooperativního zrušení + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + Použijte „CooperativeCancellation = true“ s „[Timeout]“ + + '[DeploymentItem]' can be specified only on test class or test method [DeploymentItem] se dá zadat jenom pro testovací třídu nebo testovací metodu. @@ -819,6 +929,21 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: Použití atributu opakování u testovací metody + + TestContext property cannot be accessed in this context + Vlastnost TestContext není v tomto kontextu přístupná + + + + TestContext property '{0}' cannot be accessed in '{1}' method + Vlastnost TestContext {0} není přístupná v metodě {1} + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + Některé vlastnosti TestContext jsou k dispozici pouze během provádění testu a nelze k nim přistupovat v metodách inicializace sestavení, inicializace třídy, vyčištění třídy nebo vyčištění sestavení. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf index ed0272a850..cda5a5f789 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf @@ -278,8 +278,13 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - Der DataRow-Argumenttyp muss mit dem Methodenparametertyp übereinstimmen. Nichtübereinstimmungen treten bei Indizes auf: {0} + DataRow argument types do not match method parameter types. {0} + DataRow-Argumenttypen stimmen nicht mit Methodenparametertypen überein. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + Der Parameter „{0}“ erwartet den Typ „{1}“, aber der übergebene Wert hat den Typ „{2}“. @@ -428,6 +433,66 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte DynamicData muss gültig sein. + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + Wenn Sie asynchrone Methoden aufrufen, die über Überladungen verfügen, die einen CancellationToken-Parameter akzeptieren, bevorzugen Sie die Verwendung der Überladung mit TestContext.CancellationTokenSource.Token, um einen kooperativen Abbruch zu ermöglichen und Testtimeouts zu berücksichtigen. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + Erwägen Sie die Verwendung der Überladung, die ein CancellationToken akzeptiert, und übergeben Sie „TestContext.CancellationTokenSource.Token“. + + + + Flow TestContext.CancellationToken to async operations + Fluss von TestContext.CancellationToken zu asynchronen Vorgängen + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert Verwenden Sie „Assert.Fail“ anstelle einer Assert-Anweisung „Assert.{0}“, bei der immer ein Fehler auftritt. @@ -438,6 +503,21 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte Verwenden Sie „Assert.Fail“ anstelle einer Assert-Anweisung, bei der immer ein Fehler auftritt. + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + „DataTestMethodAttribute“ ist veraltet und bietet keine zusätzliche Funktionalität im Vergleich zu „TestMethodAttribute“. Verwenden Sie „TestMethodAttribute“ für alle Testmethoden, einschließlich parametrisierter Tests. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + „DataTestMethod“ ist veraltet. Verwenden Sie stattdessen „TestMethod“. + + + + Prefer 'TestMethod' over 'DataTestMethod' + „TestMethod“ gegenüber „DataTestMethod“ bevorzugen + + Review or remove the assertion as its condition is known to be always true Überprüfen oder entfernen Sie die Assertion, weil ihre Bedingung bekanntermaßen immer TRUE ist. @@ -518,6 +598,16 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte Öffentliche Typen sollten Testklassen sein. + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + Verwenden Sie „Assert.{0}“ anstelle von „StringAssert.{1}“. + + + + Use 'Assert' instead of 'StringAssert' + Verwenden Sie „Assert“ anstelle von „StringAssert“. + + Test class '{0}' should be valid Die Testklasse „{0}“ muss gültig sein @@ -721,13 +811,13 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. - Der Typ, der "[TestMethod]" enthält, sollte mit "[TestClass]" gekennzeichnet werden, andernfalls wird die Testmethode im Hintergrund ignoriert. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Der Typ, der „[Testmethode]“ enthält, sollte mit „[Testklasse]“ gekennzeichnet werden, andernfalls wird die Testmethode still im Hintergrund ignoriert. - Class '{0}' contains test methods and should be marked with '[TestClass]' - Die Klasse "{0}" enthält Testmethoden und muss mit "[TestClass]" gekennzeichnet werden. + Type '{0}' contains test methods and should be marked with '[TestClass]' + Der Typ „{0}“ enthält Testmethoden und sollte mit „[TestClass]“ gekennzeichnet werden @@ -745,6 +835,11 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte Für asynchrone Testmethoden ist das Suffix "Async" nicht erforderlich. + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + Der TestContext-Parameter ist für MSTest für AssemblyInitialize- und ClassInitialize-Methoden erforderlich + + [{0}] can only be set on methods marked with [TestMethod] [{0}] kann nur für Methoden festgelegt werden, die mit [TestMethod] markiert sind. @@ -765,6 +860,21 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte "ConditionBaseAttribute" für Testklassen verwenden + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + Es wird davon abgeraten, „[Timeout]“ ohne die explizite Festlegung von „CooperativeCancellation = true“ zu verwenden. In einer zukünftigen Version wird der kooperative Abbruch das Standardverhalten sein. Legen Sie „CooperativeCancellation = true“ fest, um das empfohlene Verhalten zu aktivieren und Breaking Changes zu vermeiden. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + Verwenden Sie „CooperativeCancellation = true“ mit „[Timeout]“, um das kooperative Abbruchverhalten zu aktivieren. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + Verwenden Sie „CooperativeCancellation = true“ mit „[Timeout]“. + + '[DeploymentItem]' can be specified only on test class or test method „[DeploymentItem]“ kann nur für die Testklasse oder Testmethode angegeben werden. @@ -820,6 +930,21 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte Verwenden des Wiederholungsattributs für die Testmethode + + TestContext property cannot be accessed in this context + Auf die TestContext-Eigenschaft kann in diesem Kontext nicht zugegriffen werden + + + + TestContext property '{0}' cannot be accessed in '{1}' method + Auf die TestContext-Eigenschaft „{0}“ kann in der Methode „{1}“ nicht zugegriffen werden + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + Einige TestContext-Eigenschaften sind nur während der Testausführung verfügbar und können nicht in Assemblyinitialisierungs-, Klasseninitialisierungs-, Klassenbereinigungs- oder Assemblybereinigungsmethoden aufgerufen werden. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf index 75d54fde75..602c9c1dd8 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf @@ -277,8 +277,13 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - El tipo de argumento DataRow debe coincidir con el tipo de parámetro de método. Se producen errores de coincidencia en los índices: {0} + DataRow argument types do not match method parameter types. {0} + Los tipos de argumentos DataRow no coinciden con los tipos de parámetro de método. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + El parámetro '{0}' espera el tipo '{1}', pero el valor proporcionado tiene el tipo '{2}' @@ -427,6 +432,66 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: DynamicData debe ser válido + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + Al llamar a métodos asincrónicos que tienen sobrecargas que aceptan un parámetro CancellationToken, es preferible utilizar la sobrecarga con TestContext.CancellationTokenSource.Token para habilitar la cancelación cooperativa y respetar los tiempos de espera de las pruebas. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + Considere utilizar la sobrecarga que acepta un CancellationToken y pase 'TestContext.CancellationTokenSource.Token' + + + + Flow TestContext.CancellationToken to async operations + Flujo de TestContext.CancellationToken a operaciones asincrónicas + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert Usar "Assert.Fail" en lugar de una aserción 'Assert.{0}' que siempre tiene errores @@ -437,6 +502,21 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: Usar "Assert.Fail" en lugar de una aserción que siempre tiene errores + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + "DataTestMethodAttribute" está obsoleto y no proporciona ninguna funcionalidad adicional sobre "TestMethodAttribute". Use "TestMethodAttribute" para todos los métodos de prueba, incluidas las pruebas parametrizadas. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + "DataTestMethod" está obsoleto. Use "TestMethod" en su lugar. + + + + Prefer 'TestMethod' over 'DataTestMethod' + Preferir "TestMethod" a "DataTestMethod" + + Review or remove the assertion as its condition is known to be always true Revise o quite la aserción porque se sabe que su condición siempre es true @@ -517,6 +597,16 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: Los tipos públicos deben ser clases de prueba + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + Use 'Assert'{0}. en lugar de 'StringAssert.'{1} + + + + Use 'Assert' instead of 'StringAssert' + Usar 'Assert' en lugar de 'StringAssert' + + Test class '{0}' should be valid La clase de prueba '{0}' debe ser válida @@ -720,13 +810,13 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. El tipo que contiene '[TestMethod]' debe marcarse con '[TestClass]'; de lo contrario, el método de prueba se omitirá de forma silenciosa. - Class '{0}' contains test methods and should be marked with '[TestClass]' - La clase '{0}' contiene métodos de prueba y debe marcarse con '[TestClass]' + Type '{0}' contains test methods and should be marked with '[TestClass]' + El tipo '{0}' contiene métodos de prueba y debe marcarse con '[TestClass]' @@ -744,6 +834,11 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: Los métodos de prueba asincrónicos no requieren el sufijo "Async". + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + MSTest requiere el parámetro TestContext para los métodos AssemblyInitialize y ClassInitialize + + [{0}] can only be set on methods marked with [TestMethod] [{0}] solo se puede establecer en métodos marcados con [TestMethod] @@ -764,6 +859,21 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: Usar 'ConditionBaseAttribute' en clases de prueba + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + No se recomienda usar "[Timeout]" sin establecer explícitamente "CooperativeCancellation = true". En una versión futura, la cancelación cooperativa se convertirá en el comportamiento predeterminado. Establece "CooperativeCancellation = true" para participar en el comportamiento recomendado y evitar cambios importantes. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + Usa "CooperativeCancellation = true" con "[Timeout]" para habilitar el comportamiento de cancelación cooperativa. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + Usa "CooperativeCancellation = true" con "[Timeout]" + + '[DeploymentItem]' can be specified only on test class or test method '[DeploymentItem]' solo se puede especificar en la clase de prueba o el método de prueba @@ -819,6 +929,21 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: Usar el atributo de reintento en el método de prueba + + TestContext property cannot be accessed in this context + No se puede tener acceso a la propiedad TestContext en este contexto + + + + TestContext property '{0}' cannot be accessed in '{1}' method + No se puede tener acceso a la propiedad TestContext "{0}" en el método "{1}" + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + Algunas propiedades de TestContext solo están disponibles durante la ejecución de la prueba y no se puede acceder a ellas en los métodos assembly initialize, class initialize, class cleanup o assembly cleanup. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf index 8bdc50155d..98163c1a21 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf @@ -277,8 +277,13 @@ Le type doit être une classe - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - Le type d’argument DataRow doit correspondre au type de paramètre de la méthode. Des incompatibilités se produisent aux index :{0} + DataRow argument types do not match method parameter types. {0} + Les types d’argument DataRow ne correspondent pas aux types de paramètre de la méthode. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + Le paramètre « {0} » attend un type « {1} », mais la valeur fournie a un type « {2} » @@ -427,6 +432,66 @@ Le type doit être une classe DynamicData doit être valide + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + Lors de l’appel de méthodes asynchrones qui ont des surcharges acceptant un paramètre CancellationToken, préférez utiliser la surcharge avec TestContext.CancellationTokenSource.Token pour activer l’annulation collaborative et respecter les délais d’expiration des tests. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + Envisagez d’utiliser la surcharge qui accepte un CancellationToken et passe « TestContext.CancellationTokenSource.Token » + + + + Flow TestContext.CancellationToken to async operations + Transmettez TestContext.CancellationToken aux opérations asynchrones + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert Utilisez « Assert.Fail » à la place d’une assertion « Assert.{0} » toujours en échec @@ -437,6 +502,21 @@ Le type doit être une classe Utilisez « Assert.Fail » à la place d’une assertion toujours en échec + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + « DataTestMethodAttribute » est obsolète et ne fournit aucune fonctionnalité supplémentaire par rapport à « TestMethodAttribute ». Utiliser « TestMethodAttribute » pour toutes les méthodes de test, y compris les tests paramétrés. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + « DataTestMethod » est obsolète. Utilisez « TestMethod » à la place. + + + + Prefer 'TestMethod' over 'DataTestMethod' + Préférer « TestMethod » à « DataTestMethod » + + Review or remove the assertion as its condition is known to be always true Vérifier ou supprimer l’assertion, car sa condition est connue pour être toujours vraie @@ -517,6 +597,16 @@ Le type doit être une classe Les types publics doivent être des classes de test + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + Utilisez « Assert.{0} » au lieu de « StringAssert.{1} » + + + + Use 'Assert' instead of 'StringAssert' + Utilisez « Assert » au lieu de « StringAssert » + + Test class '{0}' should be valid La classe de test « {0} » doit être valide @@ -720,13 +810,13 @@ Le type doit être une classe - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. Le type contenant « [TestMethod] » doit être marqué avec « [TestClass] », sans quoi la méthode de test sera ignorée silencieusement. - Class '{0}' contains test methods and should be marked with '[TestClass]' - La classe « {0} » contient des méthodes de test et doit être marquée avec « [TestClass] » + Type '{0}' contains test methods and should be marked with '[TestClass]' + Le type « {0} » contient des méthodes de test et doit être marquée avec « [TestClass] » @@ -744,6 +834,11 @@ Le type doit être une classe Les méthodes de test asynchrones ne nécessitent pas le suffixe 'Async' + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + Le paramètre TestContext est requis par MSTest pour les méthodes AssemblyInitialize et ClassInitialize + + [{0}] can only be set on methods marked with [TestMethod] [{0}] ne peut être défini que sur les méthodes marquées avec [TestMethod] @@ -764,6 +859,21 @@ Le type doit être une classe Utiliser 'ConditionBaseAttribute' sur les classes de test + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + L’utilisation de '[Timeout]' sans définir explicitement 'CooperativeCancellation = true' est déconseillée. Dans une future version, l’annulation coopérative deviendra le comportement par défaut. Définissez 'CooperativeCancellation = true' pour adopter le comportement recommandé et éviter les changements incompatibles. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + Utilisez 'CooperativeCancellation = true' avec '[Timeout]' pour activer le comportement d’annulation coopératif + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + Utiliser 'CooperativeCancellation = true' avec '[Timeout]' + + '[DeploymentItem]' can be specified only on test class or test method « [DeploymentItem] » ne peut être spécifié que sur une classe de test ou une méthode de test @@ -819,6 +929,21 @@ Le type doit être une classe Utilisez l’attribut de nouvelle tentative sur la méthode de test + + TestContext property cannot be accessed in this context + Impossible d’accéder à la propriété TestContext dans ce contexte + + + + TestContext property '{0}' cannot be accessed in '{1}' method + Impossible d’accéder à la propriété TestContext « {0} » dans la méthode « {1} » + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + Certaines propriétés TestContext sont disponibles uniquement pendant l’exécution du test et ne sont pas accessibles dans les méthodes d’initialisation d’assembly, d’initialisation de classe, de nettoyage de classe ou de nettoyage d’assembly. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf index 3201a18d17..5f583a4779 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf @@ -277,8 +277,13 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - Il tipo di argomento di DataRow deve corrispondere al tipo di parametro del metodo. Errori di corrispondenza in corrispondenza degli indici: {0} + DataRow argument types do not match method parameter types. {0} + Il tipo di argomento di DataRow deve corrispondere ai tipi di parametro del metodo. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + Il parametro '{0}' prevede il tipo '{1}', ma il tipo del valore specificato è '{2}' @@ -427,6 +432,66 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: DynamicData deve essere valido + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + Quando si chiamano metodi asincroni con overload che accettano un parametro CancellationToken, preferire l'uso dell'overload con TestContext.CancellationTokenSource.Token per abilitare l'annullamento cooperativo e rispettare i timeout di test. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + Valutare la possibilità di usare l'overload che accetta un CancellationToken e a passare 'TestContext.CancellationTokenSource.Token' + + + + Flow TestContext.CancellationToken to async operations + Flusso da TestContext.CancellationToken a operazioni asincrone + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert Usare 'Assert.Fail' invece di un'asserzione 'Assert.{0}' che ha sempre esito negativo. @@ -437,6 +502,21 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: Usare 'Assert.Fail' invece di un'asserzione che ha sempre esito negativo + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + 'DataTestMethodAttribute' è obsoleto e non offre funzionalità aggiuntive rispetto a 'TestMethodAttribute'. Utilizzare 'TestMethodAttribute' per tutti i metodi di test, inclusi i test con parametri. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + 'DataTestMethod' è obsoleto. Utilizzare 'TestMethod' invece. + + + + Prefer 'TestMethod' over 'DataTestMethod' + Preferisci 'TestMethod' a 'DataTestMethod' + + Review or remove the assertion as its condition is known to be always true Rivedere o rimuovere l'asserzione perché la relativa condizione è sempre true @@ -517,6 +597,16 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: I tipi di pubblico dovrebbero essere classi di test + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + Usa 'Assert.{0}' invece di 'StringAssert.{1}' + + + + Use 'Assert' instead of 'StringAssert' + Usa 'Assert' invece di 'StringAssert' + + Test class '{0}' should be valid La classe di test '{0}' deve essere valida @@ -720,13 +810,13 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. Il tipo contenente '[TestMethod]' deve essere contrassegnato con '[TestClass]', altrimenti il metodo di test verrà ignorato automaticamente. - Class '{0}' contains test methods and should be marked with '[TestClass]' - La classe '{0}' contiene metodi di test e deve essere contrassegnata come '[TestClass]' + Type '{0}' contains test methods and should be marked with '[TestClass]' + Il tipo '{0}' contiene metodi di test e deve essere contrassegnato come '[TestClass]' @@ -744,6 +834,11 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: I metodi di test asincroni non richiedono il suffisso 'Async' + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + Il parametro TestContext è necessario a MSTest per i metodi AssemblyInitialize e ClassInitialize + + [{0}] can only be set on methods marked with [TestMethod] [{0}] può essere impostato solo su metodi contrassegnati con [TestMethod] @@ -764,6 +859,21 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: Usa 'ConditionBaseAttribute' nelle classi di test + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + L'uso di "[Timeout]" senza impostare esplicitamente "CooperativeCancellation = true" è sconsigliato. In una versione futura l'annullamento cooperativo diventerà il comportamento predefinito. Impostare "CooperativeCancellation = true" per acconsentire esplicitamente al comportamento consigliato ed evitare modifiche che causano un'interruzione. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + Usare "CooperativeCancellation = true" con "[Timeout]" per abilitare il comportamento di annullamento cooperativo + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + Usa "CooperativeCancellation = true" con "[Timeout]" + + '[DeploymentItem]' can be specified only on test class or test method '[DeploymentItem]' può essere specificato solo per la classe di test o il metodo di test @@ -819,6 +929,21 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: Utilizzare l'attributo di ripetizione nel metodo di test + + TestContext property cannot be accessed in this context + Non è possibile accedere alla proprietà TestContext in questo contesto + + + + TestContext property '{0}' cannot be accessed in '{1}' method + Non è possibile accedere alla proprietà TestContext '{0}' nel metodo '{1}' + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + Alcune proprietà TestContext sono disponibili solo durante l'esecuzione dei test e non è possibile accedervi nei metodi di inizializzazione degli assembly, inizializzazione delle classi, pulizia delle classi o pulizia degli assembly. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf index 695f062ace..36c0e5e429 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf @@ -277,8 +277,13 @@ The type declaring these methods should also respect the following rules: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - DataRow 引数の型は、メソッド パラメーターの型と一致させる必要があります。インデックスで不一致が発生しました: {0} + DataRow argument types do not match method parameter types. {0} + DataRow 引数の型がメソッド パラメーターの型と一致しません。 {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + パラメーター '{0}' の型は '{1}' が想定されていますが、指定された値の型は '{2}' です @@ -427,6 +432,66 @@ The type declaring these methods should also respect the following rules: DynamicData は有効である必要があります + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + CancellationToken パラメーターを受け入れるオーバーロードを持つ非同期メソッドを呼び出す場合は、TestContext.CancellationTokenSource.Token でオーバーロードを使用して協調的な取り消しを有効にし、テスト タイムアウトを考慮します。 + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + CancellationToken を受け取り、'TestContext.CancellationTokenSource.Token' を渡すオーバーロードの使用を検討してください + + + + Flow TestContext.CancellationToken to async operations + TestContext.CancellationToken を非同期操作にフローする + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert 常に失敗している 'Assert.{0}' アサートの代わりに 'Assert.Fail' を使用する。 @@ -437,6 +502,21 @@ The type declaring these methods should also respect the following rules: 常に失敗しているアサートの代わりに 'Assert.Fail' を使用する + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + 'DataTestMethodAttribute' は廃止されており、'TestMethodAttribute' に対して追加の機能は提供しません。パラメーター化されたテストを含むすべてのテスト メソッドには、'TestMethodAttribute' を使用してください。 + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + 'DataTestMethod' は廃止されました。代わりに 'TestMethod' を使用してください。 + + + + Prefer 'TestMethod' over 'DataTestMethod' + 'DataTestMethod' よりも 'TestMethod' を優先する + + Review or remove the assertion as its condition is known to be always true アサーションの条件が常に TRUE であることが判明しているため、アサーションを確認または削除してください @@ -517,6 +597,16 @@ The type declaring these methods should also respect the following rules: パブリック型はテスト クラスである必要があります + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + 'StringAssert.{1}' の代わりに 'Assert.{0}' を使用します + + + + Use 'Assert' instead of 'StringAssert' + 'StringAssert' の代わりに 'Assert' を使用 + + Test class '{0}' should be valid テスト クラス '{0}' は有効である必要があります @@ -720,13 +810,13 @@ The type declaring these methods should also respect the following rules: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. - 連続する型 '[TestMethod]' は '[TestClass]' でマークする必要があります。それ以外の場合、テスト メソッドは暗黙的に無視されます。 + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + '[TestMethod]' を含む型は '[TestClass]' でマークする必要があります。そうしないとテスト メソッドは暗黙的に無視されます。 - Class '{0}' contains test methods and should be marked with '[TestClass]' - クラス '{0}' にはテスト メソッドが含まれており、'[TestClass]' でマークする必要があります + Type '{0}' contains test methods and should be marked with '[TestClass]' + 型 '{0}' にはテスト メソッドが含まれており、'[TestClass]' でマークする必要があります @@ -744,6 +834,11 @@ The type declaring these methods should also respect the following rules: 非同期テスト メソッドには 'Async' サフィックスは不要です + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + AssemblyInitialize メソッドと ClassInitialize メソッドに対する MSTest には TestContext パラメーターが必要です + + [{0}] can only be set on methods marked with [TestMethod] [{0}] は、[TestMethod] でマークされたメソッドにのみ設定できます @@ -764,6 +859,21 @@ The type declaring these methods should also respect the following rules: テスト クラスで 'ConditionBaseAttribute' を使用する + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + 'CooperativeCancellation = true' を明示的にを設定せずに '[Timeout]' を使用することは推奨されません。将来のバージョンでは、協調的キャンセルが既定の動作になります。推奨される動作をオプトインし、破壊的な変更を避けるために、'CooperativeCancellation = true' を設定します。 + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + '[Timeout]' と共に 'CooperativeCancellation = true' を使用して、協調的キャンセルの動作を有効にします + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + '[Timeout]' と共に 'CooperativeCancellation = true' を使用する + + '[DeploymentItem]' can be specified only on test class or test method '[DeploymentItem]' は、テスト クラスまたはテスト メソッドでのみ指定できます @@ -819,6 +929,21 @@ The type declaring these methods should also respect the following rules: テスト メソッドで retry 属性を使用する + + TestContext property cannot be accessed in this context + このコンテキストでは TestContext プロパティにアクセスできません + + + + TestContext property '{0}' cannot be accessed in '{1}' method + TestContext プロパティ '{0}' に '{1}' メソッドでアクセスできません + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + TestContext プロパティの一部はテストの実行中にのみ使用でき、assenbly initialize、class initialize、class cleanup、または assembly cleanup メソッドではアクセスできません。 + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf index 1f862f2ac8..e7a46259d4 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf @@ -277,8 +277,13 @@ The type declaring these methods should also respect the following rules: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - DataRow 인수 형식은 메서드 매개 변수 형식과 일치해야 합니다. 인덱스에서 불일치 발생: {0} + DataRow argument types do not match method parameter types. {0} + DataRow 인수 형식이 메서드 매개 변수 형식과 일치하지 않습니다. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + '{0}' 매개 변수에는 '{1}' 형식이 필요한데 제공된 값의 형식은 '{2}'입니다. @@ -427,6 +432,66 @@ The type declaring these methods should also respect the following rules: DynamicData는 유효해야 합니다. + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + CancellationToken 매개변수를 허용하는 오버로드가 있는 비동기 메서드를 호출할 때는 협력적 취소를 활성화하고 테스트 시간 제한을 준수하기 위해 TestContext.CancellationTokenSource.Token이 있는 오버로드를 사용하는 것이 좋습니다. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + CancellationToken을 수락하고 'TestContext.CancellationTokenSource.Token'을 전달하는 오버로드를 사용하는 것이 좋습니다. + + + + Flow TestContext.CancellationToken to async operations + 비동기 작업으로 TestContext.CancellationToken 흐름 + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert 항상 실패하는 'Assert.{0}' 어설션 대신 'Assert.Fail'을 사용합니다. @@ -437,6 +502,21 @@ The type declaring these methods should also respect the following rules: 항상 실패하는 어설션 대신 'Assert.Fail' 사용 + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + 'DataTestMethodAttribute'는 더 이상 사용되지 않으며 'TestMethodAttribute'에 대한 추가 기능을 제공하지 않습니다. 매개 변수가 있는 테스트를 포함하여 모든 테스트 메서드에 'TestMethodAttribute'를 사용하세요. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + 'DataTestMethod'는 사용되지 않습니다. 대신 'TestMethod'를 사용하세요. + + + + Prefer 'TestMethod' over 'DataTestMethod' + 'DataTestMethod'보다 'TestMethod' 선호 + + Review or remove the assertion as its condition is known to be always true 조건이 항상 true인 것으로 알려진 어설션 검토 또는 제거 @@ -517,6 +597,16 @@ The type declaring these methods should also respect the following rules: 공용 형식은 테스트 클래스여야 합니다. + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + 'StringAssert.{1}' 대신 'Assert.{0}' 사용 + + + + Use 'Assert' instead of 'StringAssert' + 'StringAssert' 대신 'Assert' 사용 + + Test class '{0}' should be valid 테스트 클래스 '{0}'은(는) 유효해야 합니다. @@ -720,13 +810,13 @@ The type declaring these methods should also respect the following rules: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. '[TestMethod]'를 포함하는 유형은 '[TestClass]'로 표시되어야 합니다. 그렇지 않으면 테스트 메서드가 자동으로 무시됩니다. - Class '{0}' contains test methods and should be marked with '[TestClass]' - '{0}' 클래스에는 테스트 메서드가 포함되어 있으며 '[TestClass]'로 표시되어야 합니다. + Type '{0}' contains test methods and should be marked with '[TestClass]' + '{0}' 유형에는 테스트 메서드가 포함되어 있으며 '[TestClass]'로 표시되어야 합니다. @@ -744,6 +834,11 @@ The type declaring these methods should also respect the following rules: 비동기 테스트 메서드에는 'Async' 접미사가 필요하지 않습니다. + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + AssemblyInitialize 및 ClassInitialize 메서드에 대해 MSTest에 의한 TestContext 매개 변수가 필요합니다. + + [{0}] can only be set on methods marked with [TestMethod] [{0}]은(는) [TestMethod] 표시된 메서드에만 설정할 수 있습니다. @@ -764,6 +859,21 @@ The type declaring these methods should also respect the following rules: 테스트 클래스에 'ConditionBaseAttribute' 사용 + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + 'CooperativeCancellation = true'를 명시적으로 설정하지 않고 '[Timeout]'을 사용하는 것은 권장되지 않습니다. 향후 버전에서는 협동 취소가 기본 동작으로 설정될 것입니다. 권장 동작을 선택하고 변경 사항으로 인한 문제를 피하려면 'CooperativeCancellation = true'를 설정하세요. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + '[Timeout]'와 함께 'CooperativeCancellation = true'를 사용하여 협동 취소 동작을 활성화하세요. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + '[Timeout]'와 함께 'CooperativeCancellation = true'를 사용하세요. + + '[DeploymentItem]' can be specified only on test class or test method '[DeploymentItem]'은(는) 테스트 클래스 또는 테스트 메서드에만 지정할 수 있습니다. @@ -819,6 +929,21 @@ The type declaring these methods should also respect the following rules: 테스트 메서드에 재시도 속성 사용 + + TestContext property cannot be accessed in this context + 이 컨텍스트에서 TestContext 속성에 액세스할 수 없습니다. + + + + TestContext property '{0}' cannot be accessed in '{1}' method + '{1}' 메서드에서 TestContext 속성 '{0}'에 액세스할 수 없습니다. + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + 일부 TestContext 속성은 테스트 실행 중에만 사용할 수 있으며, 어셈블리 초기화, 클래스 초기화, 클래스 정리 또는 어셈블리 정리 메서드에서는 액세스할 수 없습니다. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf index b82fdc2980..793e4af278 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf @@ -277,8 +277,13 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - Typ argumentu DataRow powinien być zgodny z typem parametru metody. W indeksach występują niezgodności: {0} + DataRow argument types do not match method parameter types. {0} + Typy argumentów DataRow nie są zgodne z typami parametrów metody. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + Parametr „{0}” oczekuje typu „{1}”, ale podana wartość ma typ „{2}” @@ -427,6 +432,66 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu Wartość DynamicData powinna być prawidłowa + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + W przypadku wywoływania metod asynchronicznych, które mają przeciążenia akceptujące parametr CancellationToken, preferuj użycie przeciążenia z elementem TestContext.CancellationTokenSource.Token, aby umożliwić współpracujące anulowanie i uwzględnić limity czasu testu. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + Rozważ użycie przeciążenia akceptującego parametr CancellationToken i przekazanie elementu „TestContext.CancellationTokenSource.Token” + + + + Flow TestContext.CancellationToken to async operations + Przekaż TestContext.CancellationToken do operacji asynchronicznych + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert Użyj trybu „Assert.Fail” zamiast kończącej się zawsze niepowodzeniem instrukcji „Assert.{0}” @@ -437,6 +502,21 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu Użyj trybu „Assert.Fail” zamiast kończącej się zawsze niepowodzeniem instrukcji asercji + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + Atrybut „DataTestMethodAttribute” jest przestarzały i nie zapewnia dodatkowych funkcji w stosunku do atrybutu „TestMethodAttribute”. Użyj atrybutu „TestMethodAttribute” dla wszystkich metod testowych, w tym testów sparametryzowanych. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + Element „DataTestMethod” jest przestarzały. Zamiast niego użyj elementu „TestMethod”. + + + + Prefer 'TestMethod' over 'DataTestMethod' + Wybieraj element „TestMethod”, anie „DataTestMethod” + + Review or remove the assertion as its condition is known to be always true Przejrzyj lub usuń asercję, ponieważ wiadomo, że jej warunek ma zawsze wartość true @@ -517,6 +597,16 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu Typy publiczne powinny być klasami testowymi + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + Użyj ciągu „Assert.{0}” zamiast ciągu „StringAssert.{1}” + + + + Use 'Assert' instead of 'StringAssert' + Użyj ciągu „Assert” zamiast ciągu „StringAssert” + + Test class '{0}' should be valid Klasa testowa „{0}” powinna być prawidłowa @@ -720,13 +810,13 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. - Typ zwierający metodę „[TestMethod]” powinien być oznaczony klasa „[TestClass]”. W przeciwnym razie metoda testowa zostanie zignorowana w trybie dyskretnym. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Typ zawierający element „[TestMethod]” powinien być oznaczony znakiem „[TestClass]”. W przeciwnym razie metoda testowa zostanie zignorowana w trybie dyskretnym. - Class '{0}' contains test methods and should be marked with '[TestClass]' - Klasa „{0}” zawiera metody testowe i powinna być oznaczona klasą „[TestClass]” + Type '{0}' contains test methods and should be marked with '[TestClass]' + Typ „{0}” zawiera metody testowe i powinien być oznaczony znakiem „[TestClass]” @@ -744,6 +834,11 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu Asynchroniczne metody testowe nie wymagają sufiksu „Async” + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + Parametr TestContext jest wymagany przez narzędzie MSTest dla metod AssemblyInitialize i ClassInitialize + + [{0}] can only be set on methods marked with [TestMethod] [{0}] można ustawić tylko dla metod oznaczonych znakiem [TestMethod] @@ -764,6 +859,21 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu Użyj atrybutu "ConditionBaseAttribute" w klasach testu + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + Nie rekomenduje się używania elementu „[Timeout]” bez jawnego ustawiania wartości „CooperativeCancellation = true”. W przyszłej wersji anulowanie trybu współpracy będzie zachowaniem domyślnym. Ustaw opcję „CooperativeCancellation = true”, aby włączyć rekomendowane zachowanie i uniknąć zmian powodujących niezgodność. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + Użyj opcji „CooperativeCancellation = true” z limitem czasu „[Timeout]”, aby włączyć zachowanie anulowania trybu współpracy + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + Użyj opcji „CooperativeCancellation = true” w limitem czasu „[Timeout]” + + '[DeploymentItem]' can be specified only on test class or test method Element „[DeploymentItem]” można określić tylko dla klasy testowej lub metody testowej @@ -819,6 +929,21 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu Użyj atrybutu ponawiania dla metody testowej + + TestContext property cannot be accessed in this context + W tym kontekście nie można uzyskać dostępu do właściwości TestContext + + + + TestContext property '{0}' cannot be accessed in '{1}' method + Nie można uzyskać dostępu do właściwości TestContext „{0}” w metodzie „{1}” + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + Niektóre właściwości TestContext są dostępne tylko podczas wykonywania testu i nie można uzyskać do nich dostępu w metodach inicjowania, inicjowania klasy, oczyszczania klasy ani oczyszczania zestawów. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf index db27da787d..17c17381a8 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf @@ -277,8 +277,13 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - O tipo de argumento DataRow deve corresponder ao tipo de parâmetro do método. Incompatibilidades ocorrem nos índices: {0} + DataRow argument types do not match method parameter types. {0} + Os tipos de argumento do DataRow não correspondem aos tipos de parâmetro do método. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + O parâmetro "{0}" espera o tipo "{1}", mas o valor fornecido tem o tipo "{2}" @@ -427,6 +432,66 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: DynamicData deve ser válido + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + Ao chamar métodos assíncronos que tenham sobrecargas que aceitam um parâmetro CancellationToken, prefira usar a sobrecarga com TestContext.CancellationTokenSource.Token para habilitar o cancelamento cooperativo e respeitar os tempos limite do teste. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + Considere usar a sobrecarga que aceita um CancellationToken e passar "TestContext.CancellationTokenSource.Token" + + + + Flow TestContext.CancellationToken to async operations + Fluxo TestContext.CancellationToken para operações assíncronas + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert Use "Assert.Fail" em vez de uma asserção "Assert.{0}" sempre com falha @@ -437,6 +502,21 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: Usar "Assert.Fail" em vez de uma asserção sempre com falha + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + 'DataTestMethodAttribute' está obsoleto e não oferece funcionalidade adicional em relação a 'TestMethodAttribute'. Use 'TestMethodAttribute' para todos os métodos de teste, inclusive testes parametrizados. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + 'DataTestMethod' está obsoleto. Use 'TestMethod' em vez disso. + + + + Prefer 'TestMethod' over 'DataTestMethod' + Prefira 'TestMethod' a 'DataTestMethod' + + Review or remove the assertion as its condition is known to be always true Examine ou remova a asserção, pois a sua condição é conhecida por ser sempre verdadeira @@ -517,6 +597,16 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: Os tipos públicos devem ser classes de teste + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + Use "Assert.{0}" em vez de "StringAssert.{1}" + + + + Use 'Assert' instead of 'StringAssert' + Usar "Assert" em vez de "StringAssert" + + Test class '{0}' should be valid A classe de teste ''{0}'' deve ser válida @@ -720,13 +810,13 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. - O tipo contendo '[TestMethod]' deve ser marcado com '[TestClass]', caso contrário, o método de teste será ignorado silenciosamente. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + O tipo que contém '[TestMethod]' deve ser marcado com '[TestClass]', caso contrário, o método de teste será ignorado sem aviso. - Class '{0}' contains test methods and should be marked with '[TestClass]' - A classe '{0}' contém métodos de teste e deve ser marcada com '[TestClass]' + Type '{0}' contains test methods and should be marked with '[TestClass]' + O tipo '{0}' contém métodos de teste e deve ser marcado com '[TestClass]' @@ -744,6 +834,11 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: Os métodos de teste assíncronos não exigem o sufixo 'Async' + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + O parâmetro TestContext é obrigatório para métodos AssemblyInitialize e ClassInitialize do MSTest + + [{0}] can only be set on methods marked with [TestMethod] [{0}] só pode ser definido em métodos marcados com [TestMethod] @@ -764,6 +859,21 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: Usar 'ConditionBaseAttribute' em classes de teste + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + Usar '\[Timeout]' sem definir explicitamente 'CooperativeCancellation = true' não é recomendado. Em uma versão futura, o cancelamento cooperativo se tornará o comportamento padrão. Defina 'CooperativeCancellation = true' para optar pelo comportamento recomendado e evitar quebras. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + Use 'CooperativeCancellation = true' com '\[Timeout]' para habilitar o comportamento de cancelamento cooperativo + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + Use 'CooperativeCancellation = true' com '\[Timeout]' + + '[DeploymentItem]' can be specified only on test class or test method '[DeploymentItem]' pode ser especificado apenas na classe de teste ou método de teste @@ -819,6 +929,21 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: Usar o atributo de repetição no método de teste + + TestContext property cannot be accessed in this context + A propriedade TestContext não pode ser acessada neste contexto + + + + TestContext property '{0}' cannot be accessed in '{1}' method + A propriedade "{0}" de TestContext não pode ser acessada no método "{1}" + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + Algumas propriedades TestContext só estão disponíveis durante a execução do teste e não podem ser acessadas em métodos de inicialização de assembly, inicialização de classe, limpeza de classe ou limpeza de assembly. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf index f2770a865e..00e73f807d 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf @@ -283,8 +283,13 @@ The type declaring these methods should also respect the following rules: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - Тип аргумента DataRow должен соответствовать типу параметра метода. Обнаружены несовпадения в следующих индексах: {0} + DataRow argument types do not match method parameter types. {0} + Типы аргументов DataRow не соответствуют типам параметров метода. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + Параметр "{0}" ожидает тип "{1}", но предоставленное значение относится к типу "{2}" @@ -433,6 +438,66 @@ The type declaring these methods should also respect the following rules: Значение DynamicData должно быть допустимым + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + При вызове асинхронных методов с перегрузками, принимающими параметр CancellationToken, рекомендуется использовать перегрузку с TestContext.CancellationTokenSource.Token, чтобы обеспечить кооперативную отмену и учитывать времена ожидания теста. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + Рассмотрите возможность использования перегрузки, которая принимает CancellationToken, и передавайте "TestContext.CancellationTokenSource.Token" + + + + Flow TestContext.CancellationToken to async operations + Передача TestContext.CancellationToken в асинхронные операции + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert Используйте "Assert.Fail" вместо утверждения с постоянным сбоем "Assert.{0}" @@ -443,6 +508,21 @@ The type declaring these methods should also respect the following rules: Используйте "Assert.Fail" вместо утверждения с постоянным сбоем + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + Атрибут "DataTestMethodAttribute" устарел и не предоставляет дополнительных функций по сравнению с "TestMethodAttribute". Используйте '"TestMethodAttribute" для всех методов тестирования, включая параметризованные тесты. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + "DataTestMethod" устарел. Используйте вместо него "TestMethod". + + + + Prefer 'TestMethod' over 'DataTestMethod' + Следует предпочитать метод "TestMethod" методу "DataTestMethod" + + Review or remove the assertion as its condition is known to be always true Проверьте или удалите утверждение, так как известно, что его условие всегда истинно. @@ -523,6 +603,16 @@ The type declaring these methods should also respect the following rules: Общедоступные типы должны быть тестовыми классами + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + Используйте "Assert.{0}" вместо "StringAssert.{1}" + + + + Use 'Assert' instead of 'StringAssert' + Используйте "Assert" вместо "StringAssert" + + Test class '{0}' should be valid Тестовый класс "{0}" должен быть допустимым @@ -732,13 +822,13 @@ The type declaring these methods should also respect the following rules: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. У типа, содержащего "[TestMethod]", должна быть пометка "[TestClass]", иначе метод тестирования будет проигнорирован без уведомления пользователя. - Class '{0}' contains test methods and should be marked with '[TestClass]' - Класс "{0}" тестовые методы. У этого класса должна быть пометка "[TestClass]". + Type '{0}' contains test methods and should be marked with '[TestClass]' + Тип "{0}" содержит тестовые методы и должен быть помечен как "[TestClass]" @@ -756,6 +846,11 @@ The type declaring these methods should also respect the following rules: Асинхронные методы теста не требуют суффикса Async + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + Параметр TestContext необходим для MSTest в методах AssemblyInitialize и ClassInitialize + + [{0}] can only be set on methods marked with [TestMethod] [{0}] можно задать только для методов с пометкой [TestMethod] @@ -776,6 +871,21 @@ The type declaring these methods should also respect the following rules: Использовать ConditionBaseAttribute для тестовых классов + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + Использование "[Timeout]" без явной настройки "CooperativeCancellation = true" не рекомендуется. В будущей версии кооперативная отмена станет поведением по умолчанию. Настройте "CooperativeCancellation = true", чтобы согласиться с рекомендуемым поведением и избежать критических изменений. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + Используйте "CooperativeCancellation = true" с "[Timeout]", чтобы включить поведение кооперативной отмены + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + Использовать "CooperativeCancellation = true" с "[Timeout]" + + '[DeploymentItem]' can be specified only on test class or test method Указать "[DeploymentItem]" можно только для тестового класса или метода. @@ -831,6 +941,21 @@ The type declaring these methods should also respect the following rules: Использовать атрибут retry в тестовом методе + + TestContext property cannot be accessed in this context + Свойство TestContext недоступно в этом контексте + + + + TestContext property '{0}' cannot be accessed in '{1}' method + Свойство TestContext "{0}" недоступно в методе "{1}" + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + Некоторые свойства TestContext доступны только во время выполнения теста и недоступны в методах инициализации сборки, инициализации класса, очистки класса или очистки сборки. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf index 5e0f02d87f..c1cccecf1c 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf @@ -277,8 +277,13 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - DataRow bağımsız değişken türü, yöntem parametresinin türüyle eşleşmelidir. Dizinler sırasında uyuşmazlıklar oluştu: {0} + DataRow argument types do not match method parameter types. {0} + DataRow bağımsız değişken türleri, yöntem parametre türleriyle eşleşmiyor. {0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + Parametre ‘{0}’ tipi ‘{1}’ bekliyor, ancak verilen değer ‘{2}’ tipindedir @@ -427,6 +432,66 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: DynamicData geçerli olmalıdır + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + CancellationToken parametresini kabul eden aşırı yüklemeleri olan asenkron yöntemleri çağırırken, işbirliğine dayalı iptal işlemini etkinleştirmek ve test zaman aşımlarını dikkate almak için TestContext.CancellationTokenSource.Token ile aşırı yüklemeyi kullanmayı tercih edin. + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + CancellationToken'ı kabul eden aşırı yüklemeyi kullanmayı düşünün ve 'TestContext.CancellationTokenSource.Token'i geçirin. + + + + Flow TestContext.CancellationToken to async operations + TestContext.CancellationToken'ı asenkron işlemler için akışa aktarın + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert Her zaman başarısız olan 'Assert.{0}' onaylaması yerine 'Assert.Fail' seçeneğini kullanın @@ -437,6 +502,21 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: Her zaman başarısız olan onaylama yerine 'Assert.Fail' seçeneğini kullanın + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + 'DataTestMethodAttribute' artık kullanılmıyor ve 'TestMethodAttribute' üzerinde ek bir işlevsellik sunmuyor. Parametreli testler de dahil, tüm test yöntemleri için 'TestMethodAttribute' kullanın. + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + 'DataTestMethod' artık kullanılmıyor. Bunun yerine 'TestMethod' kullanın. + + + + Prefer 'TestMethod' over 'DataTestMethod' + 'DataTestMethod' yerine 'TestMethod' yöntemini tercih edin + + Review or remove the assertion as its condition is known to be always true Koşulu her zaman true olarak bilinen onaylamayı gözden geçirin veya kaldırın @@ -517,6 +597,16 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: Genel türler test sınıfları olmalıdır + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + ‘StringAssert.{1}’ yerine ‘Assert.{0}’ kullanın + + + + Use 'Assert' instead of 'StringAssert' + ‘StringAssert’ yerine ‘Assert’ kullanın + + Test class '{0}' should be valid '{0}' test sınıfı geçerli olmalıdır @@ -722,13 +812,13 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. '[TestMethod]' içeren tür '[TestClass]' ile işaretlenmeli, aksi takdirde test yöntemi sessizce yoksayılır. - Class '{0}' contains test methods and should be marked with '[TestClass]' - '{0}' sınıfı test yöntemleri içeriyor ve '[TestClass]' ile işaretlenmeli + Type '{0}' contains test methods and should be marked with '[TestClass]' + '{0}' türü test yöntemleri içeriyor ve '[TestClass]' ile işaretlenmeli @@ -746,6 +836,11 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: Asenkron test metotları için 'Async' soneki gerekmez + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + AssemblyInitialize ve ClassInitialize yöntemleri için MSTest tarafından TestContext parametresi gereklidir. + + [{0}] can only be set on methods marked with [TestMethod] [{0}] yalnızca [TestMethod] ile işaretli yöntemlerde ayarlanabilir @@ -766,6 +861,21 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: Test sınıflarda 'ConditionBaseAttribute' kullanın + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + '[Timeout]' ayarını 'CooperativeCancellation = true' olarak açıkça ayarlamadan kullanmak önerilmez. Gelecek bir sürümde, birlikte iptal etme varsayılan davranış haline gelecektir. Önerilen davranışı kabul etmek ve uyumsuzlukları önlemek için 'CooperativeCancellation = true' değerini ayarlayın. + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + '[Timeout]' ile 'CooperativeCancellation = true' kullanarak birlikte iptal etme davranışını etkinleştirin + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + '[Timeout]' ile 'CooperativeCancellation = true' kullanın + + '[DeploymentItem]' can be specified only on test class or test method '[DeploymentItem]' yalnızca test sınıfında veya test yönteminde belirtilebilir @@ -821,6 +931,21 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: Test yönteminde yeniden deneme özniteliğini kullan + + TestContext property cannot be accessed in this context + TestContext özelliğine bu bağlamda erişilemiyor + + + + TestContext property '{0}' cannot be accessed in '{1}' method + TestContext '{0}' özelliğine '{1}' yönteminde erişilemiyor + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + Bazı TestContext özellikleri yalnızca test yürütmesi sırasında kullanılabilir ve derleme başlatma, sınıf başlatma, sınıf temizleme veya derleme temizleme yöntemlerinde erişilemez. + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf index ff54e2c6e7..2afde7d45e 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf @@ -277,8 +277,13 @@ The type declaring these methods should also respect the following rules: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - DataRow 参数类型应与方法参数类型匹配。索引处出现不匹配: {0} + DataRow argument types do not match method parameter types. {0} + DataRow 参数类型与方法参数类型不匹配。{0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + 参数 ‘{0}’ 需要类型 ‘{1}’,但提供的值类型为 ‘{2}’ @@ -427,6 +432,66 @@ The type declaring these methods should also respect the following rules: DynamicData 应有效 + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + 在调用包含接受 CancellationToken 参数的重载的异步方法时,建议使用 TestContext.CancellationTokenSource.Token 的重载,以启用协作取消并遵守测试超时。 + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + 请考虑使用接受 CancellationToken 的重载,并传递 'TestContext.CancellationTokenSource.Token' + + + + Flow TestContext.CancellationToken to async operations + 将 TestContext.CancellationToken 传递给异步操作 + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert 使用 “Assert.Fail” 而不是始终失败的 “Assert.{0}” 断言 @@ -437,6 +502,21 @@ The type declaring these methods should also respect the following rules: 使用 “Assert.Fail” 而不是始终失败的断言 + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + 'DataTestMethodAttribute' 已过时,并且不再提供 'TestMethodAttribute' 之外的其他功能。对所有测试方法(包括参数化测试)使用 'TestMethodAttribute'。 + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + 'DataTestMethod' 已过时。请改用 'TestMethod'。 + + + + Prefer 'TestMethod' over 'DataTestMethod' + 首选 'TestMethod' 而不是 'DataTestMethod' + + Review or remove the assertion as its condition is known to be always true 查看或移除断言,因为已知其条件始终为 true @@ -517,6 +597,16 @@ The type declaring these methods should also respect the following rules: 公共类型应为测试类 + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + 使用 'Assert.{0}' 而不是 'StringAssert.{1}' + + + + Use 'Assert' instead of 'StringAssert' + 使用 'Assert' 而不是 'StringAssert' + + Test class '{0}' should be valid 测试类“{0}”应该有效 @@ -720,13 +810,13 @@ The type declaring these methods should also respect the following rules: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. - 应使用“[TestClass]”标记包含“[TestMethod]”的类型,否则将以静默方式忽略该测试方法。 + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + 应使用 "[TestClass]" 标记包含 "[TestMethod]" 的类型,否则将以静默方式忽略该测试方法。 - Class '{0}' contains test methods and should be marked with '[TestClass]' - 类“{0}”包含测试方法,应使用“[TestClass]”进行标记 + Type '{0}' contains test methods and should be marked with '[TestClass]' + 类型 "{0}" 包含测试方法,应使用 "[TestClass]" 进行标记 @@ -744,6 +834,11 @@ The type declaring these methods should also respect the following rules: 异步测试方法不需要 "Async" 后缀 + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + AssemblyInitialize 和 ClassInitialize 方法的 MSTest 需要 TestContext 参数 + + [{0}] can only be set on methods marked with [TestMethod] 只能对标记了 [TestMethod] 的方法设置 [{0}] @@ -764,6 +859,21 @@ The type declaring these methods should also respect the following rules: 对测试类使用 “ConditionBaseAttribute” + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + 不建议在不显式设置 'CooperativeCancellation = true' 的情况下使用 '[Timeout]'。在将来的版本中,协作取消将成为默认行为。设置 'CooperativeCancellation = true' 以选择加入建议的行为,并避免中断性变更。 + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + 将 'CooperativeCancellation = true' 与 '[Timeout]' 配合使用以启用协作取消行为 + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + 将 'CooperativeCancellation = true' 与 '[Timeout]' 配合使用 + + '[DeploymentItem]' can be specified only on test class or test method 只能对测试类或测试方法指定 "[DeploymentItem]" @@ -819,6 +929,21 @@ The type declaring these methods should also respect the following rules: 对测试方法使用重试属性 + + TestContext property cannot be accessed in this context + 无法在此上下文中访问 TestContext 属性 + + + + TestContext property '{0}' cannot be accessed in '{1}' method + 无法在 ‘{1}’ 方法中访问 TestContext 属性 ‘{0}’ + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + 一些 TestContext 属性仅在测试执行期间可用,并且无法在程序集初始化、类初始化、类清理或程序集清理方法中访问。 + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf index dca44939e7..069c97013d 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf @@ -277,8 +277,13 @@ The type declaring these methods should also respect the following rules: - DataRow argument type should match method parameter type. Mismatches occur at indices: {0} - DataRow 引數類型應符合方法參數類型。索引發生不符: {0} + DataRow argument types do not match method parameter types. {0} + DataRow 引數類型不符合方法參數類型。{0} + + + + Parameter '{0}' expects type '{1}', but the provided value has type '{2}' + 參數 '{0}' 期望類型為 '{1}',但提供的值的類型為 '{2}' @@ -427,6 +432,66 @@ The type declaring these methods should also respect the following rules: DynamicData 應該有效 + + When calling async methods that have overloads accepting a CancellationToken parameter, prefer using the overload with TestContext.CancellationTokenSource.Token to enable cooperative cancellation and respect test timeouts. + 在呼叫接受 CancellationToken 參數的多載非同步方法時,建議使用 TestContext.CancellationTokenSource.Token 的多載,以啟用共同取消並遵守測試逾時。 + + + + Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationTokenSource.Token' + 請考慮使用接受 CancellationToken 的多載,並傳遞 'TestContext.CancellationTokenSource.Token' + + + + Flow TestContext.CancellationToken to async operations + 將 TestContext.CancellationToken 傳遞給非同步作業 + + + + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + Methods marked with '[GlobalTestInitialize]' or '[GlobalTestCleanup]' should follow the following layout to be valid: +-it can't be declared on a generic class +-it should be 'public' +-it should be 'static' +-it should not be 'async void' +-it should not be a special method (finalizer, operator...). +-it should not be generic +-it should take one parameter of type 'TestContext' +-return type should be 'void', 'Task' or 'ValueTask' + +The type declaring these methods should also respect the following rules: +-The type should be a class +-The class should be 'public' +-The class shouldn't be 'static' +-The class should be marked with '[TestClass]' (or a derived attribute) +-the class should not be generic. + + + + Global test fixture method '{0}' signature is invalid + Global test fixture method '{0}' signature is invalid + + + + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + GlobalTestInitialize and GlobalTestCleanup methods should have valid layout + + Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert 使用 'Assert.Fail',而不是一直失敗的 'Assert.{0}' 聲明 @@ -437,6 +502,21 @@ The type declaring these methods should also respect the following rules: 使用 'Assert.Fail',而不是一直失敗的聲明 + + 'DataTestMethodAttribute' is obsolete and provides no additional functionality over 'TestMethodAttribute'. Use 'TestMethodAttribute' for all test methods, including parameterized tests. + 'DataTestMethodAttribute' 已過時,未提供比 'TestMethodAttribute' 更多的功能。針對所有測試方法使用 'TestMethodAttribute',包括參數化測試。 + + + + 'DataTestMethod' is obsolete. Use 'TestMethod' instead. + 'DataTestMethod' 已過時。請改用 'TestMethod'。 + + + + Prefer 'TestMethod' over 'DataTestMethod' + 優先使用 'TestMethod' 而不是 'DataTestMethod' + + Review or remove the assertion as its condition is known to be always true 檢閱或移除判斷提示,因為已知其條件一律為 True @@ -517,6 +597,16 @@ The type declaring these methods should also respect the following rules: 公用類型應為測試類別 + + Use 'Assert.{0}' instead of 'StringAssert.{1}' + 使用 'Assert.{0}' 而不是 'StringAssert.{1}' + + + + Use 'Assert' instead of 'StringAssert' + 使用 'Assert' 而不是 'StringAssert' + + Test class '{0}' should be valid 測試類別 '{0}' 應為有效 @@ -720,13 +810,13 @@ The type declaring these methods should also respect the following rules: - Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. + Type containing '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored. 包含 '[TestMethod]' 的類型應標記為 '[TestClass]',否則將以無訊息的方式忽略測試方法。 - Class '{0}' contains test methods and should be marked with '[TestClass]' - 類別 '{0}' 包含測試方法,應以 '[TestClass]' 標記 + Type '{0}' contains test methods and should be marked with '[TestClass]' + 類型 '{0}' 包含測試方法,應以 '[TestClass]' 標記 @@ -744,6 +834,11 @@ The type declaring these methods should also respect the following rules: 非同步測試方法不需要 'Async' 尾碼 + + TestContext parameter is required by MSTest for AssemblyInitialize and ClassInitialize methods + MSTest 需要 TestContext 參數,以用於 AssemblyInitialize 和 ClassInitialize 方法 + + [{0}] can only be set on methods marked with [TestMethod] [{0}] 只能在標示為 [TestMethod] 的方法上設定 @@ -764,6 +859,21 @@ The type declaring these methods should also respect the following rules: 在測試類別上使用 'ConditionBaseAttribute' + + Using '[Timeout]' without explicitly setting 'CooperativeCancellation = true' is discouraged. In a future version, cooperative cancellation will become the default behavior. Set 'CooperativeCancellation = true' to opt into the recommended behavior and avoid breaking changes. + 在未明確設定 'CooperativeCancellation = true' 的情況下,不建議使用 '[Timeout]'。在未來的版本中,合作取消將成為預設行為。請設定 'CooperativeCancellation = true' 以選擇加入推薦的行為,並避免破壞性變更。 + + + + Use 'CooperativeCancellation = true' with '[Timeout]' to enable cooperative cancellation behavior + 使用 'CooperativeCancellation = true' 搭配 '[Timeout]' 以啟用合作取消行為 + + + + Use 'CooperativeCancellation = true' with '[Timeout]' + 使用 'CellCancellation = true' 搭配 '[Timeout]' + + '[DeploymentItem]' can be specified only on test class or test method '[DeploymentItem]' 只能在測試類或測試方法上指定 @@ -819,6 +929,21 @@ The type declaring these methods should also respect the following rules: 在測試方法上使用重試屬性 + + TestContext property cannot be accessed in this context + 無法在此內容中存取 TestContext 屬性 + + + + TestContext property '{0}' cannot be accessed in '{1}' method + 無法在 '{1}' 方法中存取 TestContext 屬性 '{0}' + + + + Some TestContext properties are only available during test execution and cannot be accessed in assembly initialize, class initialize, class cleanup, or assembly cleanup methods. + 某些 TestContext 屬性僅在測試執行期間可供使用,無法在組件初始化、類別初始化、類別清理或組件清理方法中存取。 + + \ No newline at end of file diff --git a/src/Analyzers/MSTest.GlobalConfigsGenerator/AnalyzerSeverityDecider.cs b/src/Analyzers/MSTest.GlobalConfigsGenerator/AnalyzerSeverityDecider.cs index adf182083e..ac1370ab38 100644 --- a/src/Analyzers/MSTest.GlobalConfigsGenerator/AnalyzerSeverityDecider.cs +++ b/src/Analyzers/MSTest.GlobalConfigsGenerator/AnalyzerSeverityDecider.cs @@ -86,7 +86,8 @@ internal static class AnalyzerSeverityDecider if (rule.IsEnabledByDefault && rule.DefaultSeverity >= DiagnosticSeverity.Info) { // Recommended mode will elevate info to warning only if the rule is enabled by default. - return DiagnosticSeverity.Warning; + // In addition, if the rule is already error by default, we keep it as error. So, choose the max between warning and default severity. + return (DiagnosticSeverity)Math.Max((int)rule.DefaultSeverity, (int)DiagnosticSeverity.Warning); } if (rule.DefaultSeverity >= DiagnosticSeverity.Warning) @@ -117,6 +118,8 @@ internal static class AnalyzerSeverityDecider return rule.IsEnabledByDefault ? rule.DefaultSeverity : null; } - private static DiagnosticSeverity? DecideForModeNone(DiagnosticDescriptor _) - => null; + private static DiagnosticSeverity? DecideForModeNone(DiagnosticDescriptor rule) + // Even with 'None' mode, we still keep the rules that are errors by default. + // Such rules are likely to be critical and shouldn't be suppressed by MSTestAnalysisMode None. + => rule.DefaultSeverity == DiagnosticSeverity.Error ? DiagnosticSeverity.Error : null; } diff --git a/src/Analyzers/MSTest.GlobalConfigsGenerator/GlobalConfigBuilder.cs b/src/Analyzers/MSTest.GlobalConfigsGenerator/GlobalConfigBuilder.cs index d0940b34f5..9eb780c850 100644 --- a/src/Analyzers/MSTest.GlobalConfigsGenerator/GlobalConfigBuilder.cs +++ b/src/Analyzers/MSTest.GlobalConfigsGenerator/GlobalConfigBuilder.cs @@ -6,7 +6,7 @@ internal sealed class GlobalConfigBuilder { private readonly StringBuilder _builder = new(); - private readonly Dictionary _severityDictionary = new(); + private readonly Dictionary _severityDictionary = []; public GlobalConfigBuilder(MSTestAnalysisMode mode) { diff --git a/src/Analyzers/MSTest.SourceGeneration/Generators/TestNodesGenerator.cs b/src/Analyzers/MSTest.SourceGeneration/Generators/TestNodesGenerator.cs index c841f5d90d..a1ca1ed89c 100644 --- a/src/Analyzers/MSTest.SourceGeneration/Generators/TestNodesGenerator.cs +++ b/src/Analyzers/MSTest.SourceGeneration/Generators/TestNodesGenerator.cs @@ -50,10 +50,9 @@ private static void AddAssemblyTestNode(SourceProductionContext context, (string sourceStringBuilder.AppendAutoGeneratedHeader(); sourceStringBuilder.AppendLine(); - TestNamespaceInfo[] uniqueUsedNamespaces = testClasses + TestNamespaceInfo[] uniqueUsedNamespaces = [.. testClasses .Select(x => x.ContainingNamespace) - .Distinct() - .ToArray(); + .Distinct()]; string? safeAssemblyName = null; IDisposable? namespaceBlock = null; @@ -148,7 +147,7 @@ private static void AddAssemblyTestNode(SourceProductionContext context, (string private static void AppendAssemblyTestNodeBuilderContent(IndentedStringBuilder sourceStringBuilder, string assemblyName, ImmutableArray testClasses) { - Dictionary rootVariablesPerNamespace = new(); + Dictionary rootVariablesPerNamespace = []; int variableIndex = 1; IEnumerable> classesPerNamespaces = testClasses.GroupBy(x => x.ContainingNamespace); foreach (IGrouping namespaceClasses in classesPerNamespaces) @@ -159,7 +158,6 @@ private static void AppendAssemblyTestNodeBuilderContent(IndentedStringBuilder s foreach (TestTypeInfo testClassInfo in namespaceClasses) { - string escapedClassFullName = TestNodeHelpers.GenerateEscapedName(testClassInfo.FullyQualifiedName); sourceStringBuilder.AppendLine($"{namespaceTestsVariableName}.Add({testClassInfo.GeneratedTypeName}.TestNode);"); } @@ -169,7 +167,7 @@ private static void AppendAssemblyTestNodeBuilderContent(IndentedStringBuilder s sourceStringBuilder.Append("MSTF::TestNode root = "); - using (sourceStringBuilder.AppendTestNode(assemblyName, assemblyName, Array.Empty(), ';')) + using (sourceStringBuilder.AppendTestNode(assemblyName, assemblyName, [], ';')) { foreach (IGrouping group in classesPerNamespaces) { diff --git a/src/Analyzers/MSTest.SourceGeneration/Helpers/IndentedStringBuilder.cs b/src/Analyzers/MSTest.SourceGeneration/Helpers/IndentedStringBuilder.cs index 39fdb20ba0..a9b2c407f4 100644 --- a/src/Analyzers/MSTest.SourceGeneration/Helpers/IndentedStringBuilder.cs +++ b/src/Analyzers/MSTest.SourceGeneration/Helpers/IndentedStringBuilder.cs @@ -76,7 +76,7 @@ private StringBuilder MaybeAppendIndent() { if (_needsIndent) { - _builder.Append(new string(' ', IndentationLevel * 4)); + _builder.Append(' ', IndentationLevel * 4); } return _builder; diff --git a/src/Analyzers/MSTest.SourceGeneration/Helpers/SystemPolyfills.cs b/src/Analyzers/MSTest.SourceGeneration/Helpers/SystemPolyfills.cs index 7a3645233e..6a80a1ca13 100644 --- a/src/Analyzers/MSTest.SourceGeneration/Helpers/SystemPolyfills.cs +++ b/src/Analyzers/MSTest.SourceGeneration/Helpers/SystemPolyfills.cs @@ -3,62 +3,21 @@ #if !NETCOREAPP #pragma warning disable SA1403 // File may only contain a single namespace -#pragma warning disable SA1623 // Property summary documentation should match accessors #pragma warning disable SA1642 // Constructor summary documentation should begin with standard text -#pragma warning disable SA1502 // Element should not be on a single line +#pragma warning disable SA1623 // Property summary documentation should match accessors using System.ComponentModel; namespace System.Runtime.CompilerServices { [EditorBrowsable(EditorBrowsableState.Never)] - internal static class IsExternalInit { } + internal static class IsExternalInit; } // This was copied from https://github.com/dotnet/coreclr/blob/60f1e6265bd1039f023a82e0643b524d6aaf7845/src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs // and updated to have the scope of the attributes be internal. namespace System.Diagnostics.CodeAnalysis { - /// Specifies that null is allowed as an input even if the corresponding type disallows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] - internal sealed class AllowNullAttribute : Attribute { } - - /// Specifies that null is disallowed as an input even if the corresponding type allows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] - internal sealed class DisallowNullAttribute : Attribute { } - - /// Specifies that an output may be null even if the corresponding type disallows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] - internal sealed class MaybeNullAttribute : Attribute { } - - /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - internal sealed class MaybeNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter may be null. - /// - public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; - - /// Gets the return value condition. - public bool ReturnValue { get; } - } - - /// Specifies that the output will be non-null if the named parameter is non-null. - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] - internal sealed class NotNullIfNotNullAttribute : Attribute - { - /// Initializes the attribute with the associated parameter name. - /// - /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. - /// - public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; - - /// Gets the associated parameter name. - public string ParameterName { get; } - } - /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class NotNullWhenAttribute : Attribute @@ -72,127 +31,6 @@ internal sealed class NotNullWhenAttribute : Attribute /// Gets the return value condition. public bool ReturnValue { get; } } - - /// Specifies that the method or property will ensure that the listed field and property members have not-null values. - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] - internal sealed class MemberNotNullAttribute : Attribute - { - /// Initializes the attribute with a field or property member. - /// - /// The field or property member that is promised to be not-null. - /// - public MemberNotNullAttribute(string member) => Members = new[] { member }; - - /// Initializes the attribute with the list of field and property members. - /// - /// The list of field and property members that are promised to be not-null. - /// - public MemberNotNullAttribute(params string[] members) => Members = members; - - /// Gets field or property member names. - public string[] Members { get; } - } - - /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] - internal sealed class MemberNotNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition and a field or property member. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - /// - /// The field or property member that is promised to be not-null. - /// - public MemberNotNullWhenAttribute(bool returnValue, string member) - { - ReturnValue = returnValue; - Members = new[] { member }; - } - - /// Initializes the attribute with the specified return value condition and list of field and property members. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - /// - /// The list of field and property members that are promised to be not-null. - /// - public MemberNotNullWhenAttribute(bool returnValue, params string[] members) - { - ReturnValue = returnValue; - Members = members; - } - - /// Gets the return value condition. - public bool ReturnValue { get; } - - /// Gets field or property member names. - public string[] Members { get; } - } } #endif - -#if !NET7_0_OR_GREATER -namespace System.Diagnostics.CodeAnalysis -{ - /// - /// Specifies that this constructor sets all required members for the current type, - /// and callers do not need to set any required members themselves. - /// - [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] - internal sealed class SetsRequiredMembersAttribute : Attribute - { - } -} - -namespace System.Runtime.CompilerServices -{ - /// - /// Indicates that compiler support for a particular feature is required for the location where this attribute is applied. - /// - [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] - internal sealed class CompilerFeatureRequiredAttribute : Attribute - { - /// - /// Creates a new instance of the type. - /// - /// The name of the feature to indicate. - public CompilerFeatureRequiredAttribute(string featureName) => FeatureName = featureName; - - /// - /// The name of the compiler feature. - /// - public string FeatureName { get; } - - /// - /// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand . - /// - public bool IsOptional { get; set; } - - /// - /// The used for the ref structs C# feature. - /// - public const string RefStructs = nameof(RefStructs); - - /// - /// The used for the required members C# feature. - /// - public const string RequiredMembers = nameof(RequiredMembers); - } - - /// - /// Specifies that a type has required members or that a member is required. - /// - [AttributeUsage( - AttributeTargets.Class | - AttributeTargets.Struct | - AttributeTargets.Field | - AttributeTargets.Property, - AllowMultiple = false, - Inherited = false)] - internal sealed class RequiredMemberAttribute : Attribute - { - } -} -#endif diff --git a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/DataRowTestMethodArgumentsInfo.cs b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/DataRowTestMethodArgumentsInfo.cs index 5380802d1d..7bc9a24b18 100644 --- a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/DataRowTestMethodArgumentsInfo.cs +++ b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/DataRowTestMethodArgumentsInfo.cs @@ -14,7 +14,7 @@ internal sealed class DataRowTestMethodArgumentsInfo : ITestMethodArgumentsInfo private readonly ImmutableArray> _argumentsRows; private readonly TestMethodParametersInfo _parametersInfo; - public bool IsTestArgumentsEntryReturnType { get; } = true; + public bool IsTestArgumentsEntryReturnType => true; public string? GeneratorMethodFullName { get; } @@ -43,7 +43,7 @@ public void AppendArguments(IndentedStringBuilder nodeBuilder) string argumentsEntry = arguments.Length > 1 ? "(" + string.Join(", ", arguments) + ")" : arguments[0]; - string argumentsUid = GetArgumentsUid(_parametersInfo.Parameters.Select(x => x.Name).ToArray(), arguments); + string argumentsUid = GetArgumentsUid([.. _parametersInfo.Parameters.Select(x => x.Name)], arguments); nodeBuilder.AppendLine($"new {TestMethodInfo.TestArgumentsEntryTypeName}<{_parametersInfo.ParametersTuple}>({argumentsEntry}, \"{argumentsUid}\"),"); } } diff --git a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/DynamicDataTestMethodArgumentsInfo.cs b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/DynamicDataTestMethodArgumentsInfo.cs index e40db92762..1f520350ae 100644 --- a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/DynamicDataTestMethodArgumentsInfo.cs +++ b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/DynamicDataTestMethodArgumentsInfo.cs @@ -205,7 +205,7 @@ public void AppendArguments(IndentedStringBuilder nodeBuilder) nodeBuilder.Append("()"); } - nodeBuilder.AppendLine(";"); + nodeBuilder.AppendLine(';'); if (!_targetMethodReturnsCollectionOfTestArgumentsEntry) { @@ -225,6 +225,6 @@ public void AppendArguments(IndentedStringBuilder nodeBuilder) } } - nodeBuilder.AppendLine(","); + nodeBuilder.AppendLine(','); } } diff --git a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestMethodInfo.cs b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestMethodInfo.cs index 4cad071a97..708dce9b17 100644 --- a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestMethodInfo.cs +++ b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestMethodInfo.cs @@ -89,10 +89,10 @@ private TestMethodInfo(IMethodSymbol methodSymbol, INamedTypeSymbol typeUsingMet return null; } - List dataRowAttributes = new(); - List dynamicDataAttributes = new(); - List testPropertyAttributes = new(); - List<(string RuleId, string Description)> pragmas = new(); + List dataRowAttributes = []; + List dynamicDataAttributes = []; + List testPropertyAttributes = []; + List<(string RuleId, string Description)> pragmas = []; TimeSpan? testExecutionTimeout = null; foreach (AttributeData attribute in attributes) { diff --git a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestNamespaceInfo.cs b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestNamespaceInfo.cs index a17a31fc11..308a04ebea 100644 --- a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestNamespaceInfo.cs +++ b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestNamespaceInfo.cs @@ -30,8 +30,7 @@ public TestNamespaceInfo(INamespaceSymbol namespaceSymbol) public void AppendNamespaceTestNode(IndentedStringBuilder nodeStringBuilder, string testsVariableName) { - using (nodeStringBuilder.AppendTestNode(_containingAssembly + "." + _nameOrGlobalNamespace, _nameOrGlobalNamespace, - Array.Empty(), testsVariableName)) + using (nodeStringBuilder.AppendTestNode(_containingAssembly + "." + _nameOrGlobalNamespace, _nameOrGlobalNamespace, [], testsVariableName)) { } } diff --git a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestTypeInfo.cs b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestTypeInfo.cs index 60d46150ed..c1ec3a610e 100644 --- a/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestTypeInfo.cs +++ b/src/Analyzers/MSTest.SourceGeneration/ObjectModels/TestTypeInfo.cs @@ -156,7 +156,7 @@ public void AppendTestNode(IndentedStringBuilder sourceStringBuilder) private void AppendTestNodeCreation(IndentedStringBuilder sourceStringBuilder) { - List properties = new(); + List properties = []; foreach ((string filePath, int startLine, int endLine) in _declarationReferences) { properties.Add($"new Msg::TestFileLocationProperty(@\"{filePath}\", new(new({startLine}, -1), new({endLine}, -1))),"); diff --git a/src/Package/MSTest.Sdk/Sdk/Runner/Common.targets b/src/Package/MSTest.Sdk/Sdk/Runner/Common.targets index af047cbf0c..78d6d93755 100644 --- a/src/Package/MSTest.Sdk/Sdk/Runner/Common.targets +++ b/src/Package/MSTest.Sdk/Sdk/Runner/Common.targets @@ -33,13 +33,4 @@ - - - - - diff --git a/src/Package/MSTest.Sdk/Sdk/Sdk.props.template b/src/Package/MSTest.Sdk/Sdk/Sdk.props.template index 2c6fe5ca7d..73530c9e0d 100644 --- a/src/Package/MSTest.Sdk/Sdk/Sdk.props.template +++ b/src/Package/MSTest.Sdk/Sdk/Sdk.props.template @@ -12,6 +12,8 @@ + + false true diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsReporter.cs b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsReporter.cs index 9e7093ba63..5d9c0f65b3 100644 --- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsReporter.cs +++ b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsReporter.cs @@ -11,6 +11,7 @@ using Microsoft.Testing.Platform.Helpers; using Microsoft.Testing.Platform.Logging; using Microsoft.Testing.Platform.OutputDevice; +using Microsoft.Testing.TestInfrastructure; namespace Microsoft.Testing.Extensions.AzureDevOpsReport; @@ -23,7 +24,7 @@ internal sealed class AzureDevOpsReporter : private readonly IOutputDevice _outputDisplay; private readonly ILogger _logger; - private static readonly char[] NewlineCharacters = new char[] { '\r', '\n' }; + private static readonly char[] NewlineCharacters = ['\r', '\n']; private readonly ICommandLineOptions _commandLine; private readonly IEnvironment _environment; private readonly IFileSystem _fileSystem; @@ -51,10 +52,10 @@ public AzureDevOpsReporter( public Type[] DataTypesProduced { get; } = [typeof(SessionFileArtifact)]; /// - public string Uid { get; } = nameof(AzureDevOpsReporter); + public string Uid => nameof(AzureDevOpsReporter); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// public string DisplayName { get; } = AzureDevOpsResources.DisplayName; @@ -124,16 +125,16 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella switch (nodeState) { case FailedTestNodeStateProperty failed: - await WriteExceptionAsync(failed.Explanation, failed.Exception); + await WriteExceptionAsync(failed.Explanation, failed.Exception).ConfigureAwait(false); break; case ErrorTestNodeStateProperty error: - await WriteExceptionAsync(error.Explanation, error.Exception); + await WriteExceptionAsync(error.Explanation, error.Exception).ConfigureAwait(false); break; case CancelledTestNodeStateProperty cancelled: - await WriteExceptionAsync(cancelled.Explanation, cancelled.Exception); + await WriteExceptionAsync(cancelled.Explanation, cancelled.Exception).ConfigureAwait(false); break; case TimeoutTestNodeStateProperty timeout: - await WriteExceptionAsync(timeout.Explanation, timeout.Exception); + await WriteExceptionAsync(timeout.Explanation, timeout.Exception).ConfigureAwait(false); break; } } @@ -161,7 +162,7 @@ private async Task WriteExceptionAsync(string? explanation, Exception? exception _logger.LogTrace($"Showing failure message '{line}'."); } - await _outputDisplay.DisplayAsync(this, new FormattedTextOutputDeviceData(line)); + await _outputDisplay.DisplayAsync(this, new FormattedTextOutputDeviceData(line)).ConfigureAwait(false); } internal static /* for testing */ string? GetErrorText(string? explanation, Exception? exception, string severity, IFileSystem fileSystem, ILogger logger) @@ -263,7 +264,7 @@ private async Task WriteExceptionAsync(string? explanation, Exception? exception // Combine with repo root, to be able to resolve deterministic build paths. string fullPath = Path.Combine(repoRoot, relativePath); - if (!fileSystem.Exists(fullPath)) + if (!fileSystem.ExistFile(fullPath)) { // Path does not belong to current repository or does not exist, no need to report it because it will not show up in the PR error, we will only see it details of the run, which is the same // as not reporting it this way. Maybe there can be 2 modes, but right now we want this to be usable for GitHub + AzDo, not for pure AzDo. diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/BannedSymbols.txt index ea8617fcb0..09d715c49c 100644 --- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/BannedSymbols.txt @@ -6,5 +6,5 @@ M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask M:System.Threading.Tasks.Task.WhenAll(System.Collections.Generic.IEnumerable{System.Threading.Tasks.Task}); Use 'ITask' instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Microsoft.Testing.Extensions.AzureDevOpsReport.csproj b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Microsoft.Testing.Extensions.AzureDevOpsReport.csproj index c509126613..cf9962e410 100644 --- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Microsoft.Testing.Extensions.AzureDevOpsReport.csproj +++ b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Microsoft.Testing.Extensions.AzureDevOpsReport.csproj @@ -6,6 +6,7 @@ 1.0.0 alpha + true @@ -38,6 +39,10 @@ This package extends Microsoft Testing Platform to provide a Azure DevOps report + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/PublicAPI/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/PublicAPI/PublicAPI.Shipped.txt index 7dc5c58110..3b7a744721 100644 --- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/PublicAPI/PublicAPI.Shipped.txt +++ b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/PublicAPI/PublicAPI.Shipped.txt @@ -1 +1,5 @@ #nullable enable +Microsoft.Testing.Extensions.AzureDevOpsExtensions +Microsoft.Testing.Extensions.AzureDevOpsReport.TestingPlatformBuilderHook +static Microsoft.Testing.Extensions.AzureDevOpsExtensions.AddAzureDevOpsProvider(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder) -> void +static Microsoft.Testing.Extensions.AzureDevOpsReport.TestingPlatformBuilderHook.AddExtensions(Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! testApplicationBuilder, string![]! _) -> void diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/PublicAPI/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/PublicAPI/PublicAPI.Unshipped.txt index 2ad77b868e..7dc5c58110 100644 --- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/PublicAPI/PublicAPI.Unshipped.txt @@ -1,5 +1 @@ #nullable enable -Microsoft.Testing.Extensions.AzureDevOpsReport.TestingPlatformBuilderHook -Microsoft.Testing.Extensions.AzureDevOpsExtensions -static Microsoft.Testing.Extensions.AzureDevOpsReport.TestingPlatformBuilderHook.AddExtensions(Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! testApplicationBuilder, string![]! _) -> void -static Microsoft.Testing.Extensions.AzureDevOpsExtensions.AddAzureDevOpsProvider(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder) -> void diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/RootFinder.cs b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/RootFinder.cs deleted file mode 100644 index aa4cf86d09..0000000000 --- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/RootFinder.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.Testing.Extensions.AzureDevOpsReport; - -internal static class RootFinder -{ - private static string? s_root; - - public static string Find() - { - if (s_root != null) - { - return s_root; - } - - string path = AppContext.BaseDirectory; - string dir = path; - while (Directory.GetDirectoryRoot(dir) != dir) - { - if (Directory.Exists(Path.Combine(dir, ".git"))) - { - s_root = dir + Path.DirectorySeparatorChar; - return dir + Path.DirectorySeparatorChar; - } - else - { - dir = Directory.GetParent(dir)!.ToString(); - } - } - - throw new InvalidOperationException($"Could not find solution root, .git not found in {path} or any parent directory."); - } -} diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt index ea8617fcb0..09d715c49c 100644 --- a/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt @@ -6,5 +6,5 @@ M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask M:System.Threading.Tasks.Task.WhenAll(System.Collections.Generic.IEnumerable{System.Threading.Tasks.Task}); Use 'ITask' instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpEnvironmentVariableProvider.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpEnvironmentVariableProvider.cs index e23f9491ca..8ca9a523cb 100644 --- a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpEnvironmentVariableProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpEnvironmentVariableProvider.cs @@ -21,7 +21,7 @@ internal sealed class CrashDumpEnvironmentVariableProvider : ITestHostEnvironmen private const string CreateDumpVerboseDiagnosticsVariable = "CreateDumpVerboseDiagnostics"; private const string EnableMiniDumpValue = "1"; - private readonly string[] _prefixes = ["DOTNET_", "COMPlus_"]; + private static readonly string[] Prefixes = ["DOTNET_", "COMPlus_"]; private readonly IConfiguration _configuration; private readonly ICommandLineOptions _commandLineOptions; private readonly ITestApplicationModuleInfo _testApplicationModuleInfo; @@ -62,7 +62,7 @@ public Task IsEnabledAsync() public Task UpdateAsync(IEnvironmentVariables environmentVariables) { - foreach (string prefix in _prefixes) + foreach (string prefix in Prefixes) { environmentVariables.SetVariable(new($"{prefix}{EnableMiniDumpVariable}", EnableMiniDumpValue, false, true)); environmentVariables.SetVariable(new($"{prefix}{CreateDumpDiagnosticsVariable}", EnableMiniDumpValue, false, true)); @@ -107,7 +107,7 @@ public Task UpdateAsync(IEnvironmentVariables environmentVariables) } } - foreach (string prefix in _prefixes) + foreach (string prefix in Prefixes) { environmentVariables.SetVariable(new($"{prefix}{MiniDumpTypeVariable}", miniDumpTypeValue, false, true)); } @@ -116,7 +116,7 @@ public Task UpdateAsync(IEnvironmentVariables environmentVariables) ? Path.Combine(_configuration.GetTestResultDirectory(), dumpFileName[0]) : Path.Combine(_configuration.GetTestResultDirectory(), $"{Path.GetFileNameWithoutExtension(_testApplicationModuleInfo.GetCurrentTestApplicationFullPath())}_%p_crash.dmp"); _crashDumpGeneratorConfiguration.DumpFileNamePattern = _miniDumpNameValue; - foreach (string prefix in _prefixes) + foreach (string prefix in Prefixes) { environmentVariables.SetVariable(new($"{prefix}{MiniDumpNameVariable}", _miniDumpNameValue, false, true)); } @@ -132,12 +132,11 @@ public Task UpdateAsync(IEnvironmentVariables environmentVariables) public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnlyEnvironmentVariables environmentVariables) { - StringBuilder errors = new(); - #if !NETCOREAPP return ValidationResult.InvalidTask(CrashDumpResources.CrashDumpNotSupportedInNonNetCoreErrorMessage); #else - foreach (string prefix in _prefixes) + StringBuilder errors = new(); + foreach (string prefix in Prefixes) { if (!environmentVariables.TryGetVariable($"{prefix}{EnableMiniDumpVariable}", out OwnedEnvironmentVariable? enableMiniDump) || enableMiniDump.Value != EnableMiniDumpValue) @@ -146,7 +145,7 @@ public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnl } } - foreach (string prefix in _prefixes) + foreach (string prefix in Prefixes) { if (!environmentVariables.TryGetVariable($"{prefix}{CreateDumpDiagnosticsVariable}", out OwnedEnvironmentVariable? enableMiniDump) || enableMiniDump.Value != EnableMiniDumpValue) @@ -155,7 +154,7 @@ public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnl } } - foreach (string prefix in _prefixes) + foreach (string prefix in Prefixes) { if (!environmentVariables.TryGetVariable($"{prefix}{CreateDumpVerboseDiagnosticsVariable}", out OwnedEnvironmentVariable? enableMiniDump) || enableMiniDump.Value != EnableMiniDumpValue) @@ -164,7 +163,7 @@ public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnl } } - foreach (string prefix in _prefixes) + foreach (string prefix in Prefixes) { if (!environmentVariables.TryGetVariable($"{prefix}{MiniDumpTypeVariable}", out OwnedEnvironmentVariable? miniDumpType)) { @@ -187,7 +186,7 @@ public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnl } } - foreach (string prefix in _prefixes) + foreach (string prefix in Prefixes) { if (!environmentVariables.TryGetVariable($"{prefix}{MiniDumpNameVariable}", out OwnedEnvironmentVariable? miniDumpName) || miniDumpName.Value != _miniDumpNameValue) diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpProcessLifetimeHandler.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpProcessLifetimeHandler.cs index ecec7a268e..005ccc1580 100644 --- a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpProcessLifetimeHandler.cs +++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpProcessLifetimeHandler.cs @@ -63,19 +63,19 @@ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testH } ApplicationStateGuard.Ensure(_netCoreCrashDumpGeneratorConfiguration.DumpFileNamePattern is not null); - await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, CrashDumpResources.CrashDumpProcessCrashedDumpFileCreated, testHostProcessInformation.PID))); + await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, CrashDumpResources.CrashDumpProcessCrashedDumpFileCreated, testHostProcessInformation.PID))).ConfigureAwait(false); string expectedDumpFile = _netCoreCrashDumpGeneratorConfiguration.DumpFileNamePattern.Replace("%p", testHostProcessInformation.PID.ToString(CultureInfo.InvariantCulture)); if (File.Exists(expectedDumpFile)) { - await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(expectedDumpFile), CrashDumpResources.CrashDumpArtifactDisplayName, CrashDumpResources.CrashDumpArtifactDescription)); + await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(expectedDumpFile), CrashDumpResources.CrashDumpArtifactDisplayName, CrashDumpResources.CrashDumpArtifactDescription)).ConfigureAwait(false); } else { - await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, CrashDumpResources.CannotFindExpectedCrashDumpFile, expectedDumpFile))); + await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, CrashDumpResources.CannotFindExpectedCrashDumpFile, expectedDumpFile))).ConfigureAwait(false); foreach (string dumpFile in Directory.GetFiles(Path.GetDirectoryName(expectedDumpFile)!, "*.dmp")) { - await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(dumpFile), CrashDumpResources.CrashDumpDisplayName, CrashDumpResources.CrashDumpArtifactDescription)); + await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(dumpFile), CrashDumpResources.CrashDumpDisplayName, CrashDumpResources.CrashDumpArtifactDescription)).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt index ea8617fcb0..09d715c49c 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt @@ -6,5 +6,5 @@ M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask M:System.Threading.Tasks.Task.WhenAll(System.Collections.Generic.IEnumerable{System.Threading.Tasks.Task}); Use 'ITask' instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpActivityIndicator.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpActivityIndicator.cs index 9469725e51..ed6a65341d 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpActivityIndicator.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpActivityIndicator.cs @@ -90,7 +90,7 @@ public async Task OnTestSessionStartingAsync(SessionUid sessionUid, Cancellation { ApplicationStateGuard.Ensure(_namedPipeClient is not null); - if (!await IsEnabledAsync() || cancellationToken.IsCancellationRequested) + if (!await IsEnabledAsync().ConfigureAwait(false) || cancellationToken.IsCancellationRequested) { return; } @@ -98,36 +98,36 @@ public async Task OnTestSessionStartingAsync(SessionUid sessionUid, Cancellation try { // Connect to the named pipe server - await _logger.LogTraceAsync($"Connecting to the process lifetime handler {_namedPipeClient.PipeName}"); - await _namedPipeClient.ConnectAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); - await _logger.LogTraceAsync("Connected to the process lifetime handler"); + await _logger.LogTraceAsync($"Connecting to the process lifetime handler {_namedPipeClient.PipeName}").ConfigureAwait(false); + await _namedPipeClient.ConnectAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); + await _logger.LogTraceAsync("Connected to the process lifetime handler").ConfigureAwait(false); _activityIndicatorMutex = new Mutex(true); _mutexName = $"{HangDumpConfiguration.MutexName}_{Guid.NewGuid():N}"; // Keep the custom thread to avoid to waste one from thread pool. _signalActivityIndicatorTask = _task.RunLongRunning(SignalActivityIndicatorAsync, "[HangDump] SignalActivityIndicatorAsync", cancellationToken); - await _logger.LogTraceAsync($"Wait for mutex '{_mutexName}' creation"); + await _logger.LogTraceAsync($"Wait for mutex '{_mutexName}' creation").ConfigureAwait(false); _mutexCreated.Wait(cancellationToken); - await _logger.LogTraceAsync($"Mutex '{_mutexName}' created"); + await _logger.LogTraceAsync($"Mutex '{_mutexName}' created").ConfigureAwait(false); await _namedPipeClient.RequestReplyAsync(new ActivityIndicatorMutexNameRequest(_mutexName), cancellationToken) - .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); - await _logger.LogTraceAsync($"Mutex '{_mutexName}' sent to the process lifetime handler"); + .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); + await _logger.LogTraceAsync($"Mutex '{_mutexName}' sent to the process lifetime handler").ConfigureAwait(false); // Setup the server channel with the testhost controller - _pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N")); + _pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"), _environment); _logger.LogTrace($"Hang dump pipe name: '{_pipeNameDescription.Name}'"); _singleConnectionNamedPipeServer = new(_pipeNameDescription, CallbackAsync, _environment, _logger, _task, cancellationToken); _singleConnectionNamedPipeServer.RegisterSerializer(new GetInProgressTestsResponseSerializer(), typeof(GetInProgressTestsResponse)); _singleConnectionNamedPipeServer.RegisterSerializer(new GetInProgressTestsRequestSerializer(), typeof(GetInProgressTestsRequest)); _singleConnectionNamedPipeServer.RegisterSerializer(new ExitSignalActivityIndicatorTaskRequestSerializer(), typeof(ExitSignalActivityIndicatorTaskRequest)); _singleConnectionNamedPipeServer.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse)); - await _logger.LogTraceAsync($"Send consumer pipe name to the test controller '{_pipeNameDescription.Name}'"); + await _logger.LogTraceAsync($"Send consumer pipe name to the test controller '{_pipeNameDescription.Name}'").ConfigureAwait(false); await _namedPipeClient.RequestReplyAsync(new ConsumerPipeNameRequest(_pipeNameDescription.Name), cancellationToken) - .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); + .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); // Wait the connection from the testhost controller - await _singleConnectionNamedPipeServer.WaitConnectionAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); - await _logger.LogTraceAsync("Test host controller connected"); + await _singleConnectionNamedPipeServer.WaitConnectionAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); + await _logger.LogTraceAsync("Test host controller connected").ConfigureAwait(false); } catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken) { @@ -139,13 +139,13 @@ private async Task CallbackAsync(IRequest request) { if (request is GetInProgressTestsRequest) { - await _logger.LogDebugAsync($"Received '{nameof(GetInProgressTestsRequest)}'"); - return new GetInProgressTestsResponse(_testsCurrentExecutionState.Select(x => (x.Value.Name, (int)_clock.UtcNow.Subtract(x.Value.StartTime).TotalSeconds)).ToArray()); + await _logger.LogDebugAsync($"Received '{nameof(GetInProgressTestsRequest)}'").ConfigureAwait(false); + return new GetInProgressTestsResponse([.. _testsCurrentExecutionState.Select(x => (x.Value.Name, (int)_clock.UtcNow.Subtract(x.Value.StartTime).TotalSeconds))]); } else if (request is ExitSignalActivityIndicatorTaskRequest) { - await _logger.LogDebugAsync($"Received '{nameof(ExitSignalActivityIndicatorTaskRequest)}'"); - await ExitSignalActivityIndicatorTaskAsync(); + await _logger.LogDebugAsync($"Received '{nameof(ExitSignalActivityIndicatorTaskRequest)}'").ConfigureAwait(false); + await ExitSignalActivityIndicatorTaskAsync().ConfigureAwait(false); return VoidResponse.CachedInstance; } else @@ -167,7 +167,7 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella { if (_traceLevelEnabled) { - await _logger.LogTraceAsync($"New in-progress test '{nodeChangedMessage.TestNode.DisplayName}'"); + await _logger.LogTraceAsync($"New in-progress test '{nodeChangedMessage.TestNode.DisplayName}'").ConfigureAwait(false); } _testsCurrentExecutionState.TryAdd(nodeChangedMessage.TestNode.Uid, (nodeChangedMessage.TestNode.DisplayName, typeof(InProgressTestNodeStateProperty), _clock.UtcNow)); @@ -177,7 +177,7 @@ or FailedTestNodeStateProperty or TimeoutTestNodeStateProperty or SkippedTestNod && _testsCurrentExecutionState.TryRemove(nodeChangedMessage.TestNode.Uid, out (string Name, Type Type, DateTimeOffset StartTime) record) && _traceLevelEnabled) { - await _logger.LogTraceAsync($"Test removed from in-progress list '{record.Name}' after '{_clock.UtcNow.Subtract(record.StartTime)}', total in-progress '{_testsCurrentExecutionState.Count}'"); + await _logger.LogTraceAsync($"Test removed from in-progress list '{record.Name}' after '{_clock.UtcNow.Subtract(record.StartTime)}', total in-progress '{_testsCurrentExecutionState.Count}'").ConfigureAwait(false); } // Optimization, we're interested in test progression and eventually in the discovery progression @@ -185,7 +185,7 @@ or FailedTestNodeStateProperty or TimeoutTestNodeStateProperty or SkippedTestNod { if (_traceLevelEnabled) { - await _logger.LogTraceAsync($"Signal for action node {nodeChangedMessage.TestNode.DisplayName} - '{state}'"); + await _logger.LogTraceAsync($"Signal for action node {nodeChangedMessage.TestNode.DisplayName} - '{state}'").ConfigureAwait(false); } // Signal the activity if it's not set @@ -234,18 +234,18 @@ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, Cancellatio ApplicationStateGuard.Ensure(_namedPipeClient is not null); ApplicationStateGuard.Ensure(_activityIndicatorMutex is not null); - if (!await IsEnabledAsync()) + if (!await IsEnabledAsync().ConfigureAwait(false)) { return; } await _namedPipeClient.RequestReplyAsync(new SessionEndSerializerRequest(), cancellationToken) - .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); + .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); - await _logger.LogDebugAsync("Signal for test session end'"); - await ExitSignalActivityIndicatorTaskAsync(); + await _logger.LogDebugAsync("Signal for test session end'").ConfigureAwait(false); + await ExitSignalActivityIndicatorTaskAsync().ConfigureAwait(false); - await _logger.LogTraceAsync("Signaled by process for it's exit"); + await _logger.LogTraceAsync("Signaled by process for it's exit").ConfigureAwait(false); _sessionEndCalled = true; } @@ -259,20 +259,20 @@ private async Task ExitSignalActivityIndicatorTaskAsync() ApplicationStateGuard.Ensure(_signalActivityIndicatorTask is not null); _exitSignalActivityIndicatorAsync = true; _signalActivity.Set(); - await _signalActivityIndicatorTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout); + await _signalActivityIndicatorTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false); } #if NETCOREAPP public async ValueTask DisposeAsync() { - await DisposeHelper.DisposeAsync(_namedPipeClient); + await DisposeHelper.DisposeAsync(_namedPipeClient).ConfigureAwait(false); // If the OnTestSessionFinishingAsync is not called means that something unhandled happened // and we didn't correctly coordinate the shutdown with the HangDumpProcessLifetimeHandler. // If we go do wait for the server we will hang. if (_sessionEndCalled) { - await DisposeHelper.DisposeAsync(_singleConnectionNamedPipeServer); + await DisposeHelper.DisposeAsync(_singleConnectionNamedPipeServer).ConfigureAwait(false); } _pipeNameDescription?.Dispose(); diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs index 1ecc644a4e..f226b68da5 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs @@ -21,9 +21,10 @@ public static class HangDumpExtensions /// The test application builder. public static void AddHangDumpProvider(this ITestApplicationBuilder builder) { - CurrentTestApplicationModuleInfo testApplicationModuleInfo = new(new SystemEnvironment(), new SystemProcessHandler()); + var environment = new SystemEnvironment(); + CurrentTestApplicationModuleInfo testApplicationModuleInfo = new(environment, new SystemProcessHandler()); string mutexSuffix = Guid.NewGuid().ToString("N"); - PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N")); + PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"), environment); HangDumpConfiguration hangDumpConfiguration = new(testApplicationModuleInfo, pipeNameDescription, mutexSuffix); builder.TestHostControllers.AddProcessLifetimeHandler(serviceProvider diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpProcessLifetimeHandler.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpProcessLifetimeHandler.cs index 06f1fa1044..2f41e6fa6e 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpProcessLifetimeHandler.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpProcessLifetimeHandler.cs @@ -118,7 +118,7 @@ public async Task BeforeTestHostProcessStartAsync(CancellationToken cancellation _dumpFileNamePattern = fileName[0]; } - await _logger.LogInformationAsync($"Hang dump timeout setup {_activityTimerValue}."); + await _logger.LogInformationAsync($"Hang dump timeout setup {_activityTimerValue}.").ConfigureAwait(false); _waitConnectionTask = _task.Run( async () => @@ -128,8 +128,8 @@ public async Task BeforeTestHostProcessStartAsync(CancellationToken cancellation _singleConnectionNamedPipeServer.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse)); _singleConnectionNamedPipeServer.RegisterSerializer(new SessionEndSerializerRequestSerializer(), typeof(SessionEndSerializerRequest)); _singleConnectionNamedPipeServer.RegisterSerializer(new ConsumerPipeNameRequestSerializer(), typeof(ConsumerPipeNameRequest)); - await _logger.LogDebugAsync($"Waiting for connection to {_singleConnectionNamedPipeServer.PipeName.Name}"); - await _singleConnectionNamedPipeServer.WaitConnectionAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); + await _logger.LogDebugAsync($"Waiting for connection to {_singleConnectionNamedPipeServer.PipeName.Name}").ConfigureAwait(false); + await _singleConnectionNamedPipeServer.WaitConnectionAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); }, cancellationToken); } @@ -137,19 +137,19 @@ private async Task CallbackAsync(IRequest request) { if (request is ActivityIndicatorMutexNameRequest activityIndicatorMutexNameRequest) { - await _logger.LogDebugAsync($"Mutex name received by the test host, '{activityIndicatorMutexNameRequest.MutexName}'"); + await _logger.LogDebugAsync($"Mutex name received by the test host, '{activityIndicatorMutexNameRequest.MutexName}'").ConfigureAwait(false); _activityTimerMutexName = activityIndicatorMutexNameRequest.MutexName; _mutexNameReceived.Set(); return VoidResponse.CachedInstance; } else if (request is SessionEndSerializerRequest) { - await _logger.LogDebugAsync("Session end received by the test host"); + await _logger.LogDebugAsync("Session end received by the test host").ConfigureAwait(false); _exitActivityIndicatorTask = true; #if NET if (_namedPipeClient is not null) { - await _namedPipeClient.DisposeAsync(); + await _namedPipeClient.DisposeAsync().ConfigureAwait(false); } #else _namedPipeClient?.Dispose(); @@ -158,7 +158,7 @@ private async Task CallbackAsync(IRequest request) } else if (request is ConsumerPipeNameRequest consumerPipeNameRequest) { - await _logger.LogDebugAsync($"Consumer pipe name received '{consumerPipeNameRequest.PipeName}'"); + await _logger.LogDebugAsync($"Consumer pipe name received '{consumerPipeNameRequest.PipeName}'").ConfigureAwait(false); _namedPipeClient = new NamedPipeClient(consumerPipeNameRequest.PipeName); _namedPipeClient.RegisterSerializer(new GetInProgressTestsResponseSerializer(), typeof(GetInProgressTestsResponse)); _namedPipeClient.RegisterSerializer(new GetInProgressTestsRequestSerializer(), typeof(GetInProgressTestsRequest)); @@ -181,14 +181,14 @@ public async Task OnTestHostProcessStartedAsync(ITestHostProcessInformation test { _testHostProcessInformation = testHostProcessInformation; - await _logger.LogDebugAsync($"Wait for test host connection to the server pipe '{_singleConnectionNamedPipeServer.PipeName.Name}'"); - await _waitConnectionTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout); + await _logger.LogDebugAsync($"Wait for test host connection to the server pipe '{_singleConnectionNamedPipeServer.PipeName.Name}'").ConfigureAwait(false); + await _waitConnectionTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false); using CancellationTokenSource timeout = new(TimeoutHelper.DefaultHangTimeSpanTimeout); using var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellation, timeout.Token); _waitConsumerPipeName.Wait(linkedCancellationToken.Token); ApplicationStateGuard.Ensure(_namedPipeClient is not null); - await _namedPipeClient.ConnectAsync(cancellation).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout); - await _logger.LogDebugAsync($"Connected to the test host server pipe '{_namedPipeClient.PipeName}'"); + await _namedPipeClient.ConnectAsync(cancellation).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false); + await _logger.LogDebugAsync($"Connected to the test host server pipe '{_namedPipeClient.PipeName}'").ConfigureAwait(false); // Keep the custom thread to avoid to waste one from thread pool. _activityIndicatorTask = _task.RunLongRunning( @@ -196,11 +196,11 @@ public async Task OnTestHostProcessStartedAsync(ITestHostProcessInformation test { try { - await ActivityTimerAsync(); + await ActivityTimerAsync().ConfigureAwait(false); } catch (Exception e) { - await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpFailed, e.ToString(), GetDiskInfo()))); + await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpFailed, e.ToString(), GetDiskInfo()))).ConfigureAwait(false); throw; } }, "[HangDump] ActivityTimerAsync", cancellation); @@ -244,7 +244,7 @@ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testH if (!RoslynString.IsNullOrEmpty(_dumpFileTaken)) { - await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(_dumpFileTaken), ExtensionResources.HangDumpArtifactDisplayName, ExtensionResources.HangDumpArtifactDescription)); + await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(_dumpFileTaken), ExtensionResources.HangDumpArtifactDisplayName, ExtensionResources.HangDumpArtifactDescription)).ConfigureAwait(false); } } @@ -340,7 +340,7 @@ private async Task ActivityTimerAsync() if (timeoutFired) { - await TakeDumpAsync(); + await TakeDumpAsync().ConfigureAwait(false); } } @@ -349,35 +349,35 @@ private async Task TakeDumpAsync() ApplicationStateGuard.Ensure(_testHostProcessInformation is not null); ApplicationStateGuard.Ensure(_dumpType is not null); - await _logger.LogInformationAsync($"Hang dump timeout({_activityTimerValue}) expired."); - await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpTimeoutExpired, _activityTimerValue))); + await _logger.LogInformationAsync($"Hang dump timeout({_activityTimerValue}) expired.").ConfigureAwait(false); + await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpTimeoutExpired, _activityTimerValue))).ConfigureAwait(false); string finalDumpFileName = _dumpFileNamePattern.Replace("%p", _testHostProcessInformation.PID.ToString(CultureInfo.InvariantCulture)); finalDumpFileName = Path.Combine(_configuration.GetTestResultDirectory(), finalDumpFileName); ApplicationStateGuard.Ensure(_namedPipeClient is not null); - GetInProgressTestsResponse tests = await _namedPipeClient.RequestReplyAsync(new GetInProgressTestsRequest(), _testApplicationCancellationTokenSource.CancellationToken); - await _namedPipeClient.RequestReplyAsync(new ExitSignalActivityIndicatorTaskRequest(), _testApplicationCancellationTokenSource.CancellationToken); + GetInProgressTestsResponse tests = await _namedPipeClient.RequestReplyAsync(new GetInProgressTestsRequest(), _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); + await _namedPipeClient.RequestReplyAsync(new ExitSignalActivityIndicatorTaskRequest(), _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); if (tests.Tests.Length > 0) { string hangTestsFileName = Path.Combine(_configuration.GetTestResultDirectory(), Path.ChangeExtension(Path.GetFileName(finalDumpFileName), ".log")); using (FileStream fs = File.OpenWrite(hangTestsFileName)) using (StreamWriter sw = new(fs)) { - await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(ExtensionResources.RunningTestsWhileDumping)); + await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(ExtensionResources.RunningTestsWhileDumping)).ConfigureAwait(false); foreach ((string testName, int seconds) in tests.Tests) { - await sw.WriteLineAsync($"[{TimeSpan.FromSeconds(seconds)}] {testName}"); - await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData($"[{TimeSpan.FromSeconds(seconds)}] {testName}")); + await sw.WriteLineAsync($"[{TimeSpan.FromSeconds(seconds)}] {testName}").ConfigureAwait(false); + await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData($"[{TimeSpan.FromSeconds(seconds)}] {testName}")).ConfigureAwait(false); } } - await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(hangTestsFileName), ExtensionResources.HangTestListArtifactDisplayName, ExtensionResources.HangTestListArtifactDescription)); + await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(hangTestsFileName), ExtensionResources.HangTestListArtifactDisplayName, ExtensionResources.HangTestListArtifactDescription)).ConfigureAwait(false); } - await _logger.LogInformationAsync($"Creating dump filename {finalDumpFileName}"); + await _logger.LogInformationAsync($"Creating dump filename {finalDumpFileName}").ConfigureAwait(false); - await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.CreatingDumpFile, finalDumpFileName))); + await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.CreatingDumpFile, finalDumpFileName))).ConfigureAwait(false); try { @@ -419,7 +419,7 @@ private async Task TakeDumpAsync() NotifyCrashDumpServiceIfEnabled(); using IProcess process = _processHandler.GetProcessById(_testHostProcessInformation.PID); process.Kill(); - await process.WaitForExitAsync(); + await process.WaitForExitAsync().ConfigureAwait(false); } } @@ -448,7 +448,7 @@ public async ValueTask DisposeAsync() { if (_activityIndicatorTask is not null) { - await _activityIndicatorTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout); + await _activityIndicatorTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false); } _namedPipeClient?.Dispose(); diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ExitSignalActivityIndicatorTaskRequest.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ExitSignalActivityIndicatorTaskRequest.cs index a1f76cf3b9..72ab5a9bd0 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ExitSignalActivityIndicatorTaskRequest.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ExitSignalActivityIndicatorTaskRequest.cs @@ -6,7 +6,7 @@ namespace Microsoft.Testing.Extensions.HangDump.Serializers; -internal sealed class ExitSignalActivityIndicatorTaskRequest() : IRequest; +internal sealed class ExitSignalActivityIndicatorTaskRequest : IRequest; internal sealed class ExitSignalActivityIndicatorTaskRequestSerializer : BaseSerializer, INamedPipeSerializer { diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsRequest.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsRequest.cs index 2a68a98905..05cbf08b45 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsRequest.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsRequest.cs @@ -6,7 +6,7 @@ namespace Microsoft.Testing.Extensions.HangDump.Serializers; -internal sealed class GetInProgressTestsRequest() : IRequest; +internal sealed class GetInProgressTestsRequest : IRequest; internal sealed class GetInProgressTestsRequestSerializer : BaseSerializer, INamedPipeSerializer { diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsResponse.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsResponse.cs index da92375d71..04344f941c 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsResponse.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsResponse.cs @@ -26,7 +26,7 @@ public object Deserialize(Stream stream) tests.Add((testName, unixTimeSeconds)); } - return new GetInProgressTestsResponse(tests.ToArray()); + return new GetInProgressTestsResponse([.. tests]); } public void Serialize(object objectToSerialize, Stream stream) diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/SessionEndSerializer.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/SessionEndSerializer.cs index 23cd132c19..8e547f6974 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/SessionEndSerializer.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/SessionEndSerializer.cs @@ -6,7 +6,7 @@ namespace Microsoft.Testing.Extensions.HangDump.Serializers; -internal sealed class SessionEndSerializerRequest() : IRequest; +internal sealed class SessionEndSerializerRequest : IRequest; internal sealed class SessionEndSerializerRequestSerializer : BaseSerializer, INamedPipeSerializer { diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs index 41f2c6586d..d069d6e9f1 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs @@ -9,7 +9,7 @@ internal static class MiniDumpWriteDump { public static void CollectDumpUsingMiniDumpWriteDump(int pid, string outputFile, MiniDumpTypeOption type) { - var process = Process.GetProcessById(pid); + using var process = Process.GetProcessById(pid); // Open the file for writing using var stream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None); diff --git a/src/Platform/Microsoft.Testing.Extensions.HotReload/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.HotReload/BannedSymbols.txt index 5bc5c2fb96..6b0c437d6e 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HotReload/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Extensions.HotReload/BannedSymbols.txt @@ -6,5 +6,5 @@ M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask M:System.Threading.Tasks.Task.WhenAll(System.Collections.Generic.IEnumerable{System.Threading.Tasks.Task}); Use 'ITask' instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadHandler.cs b/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadHandler.cs index 281048572a..812d925074 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadHandler.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadHandler.cs @@ -84,13 +84,13 @@ public async Task ShouldRunAsync(Task? waitExecutionCompletion, Cancellati if (waitExecutionCompletion is not null) { - await waitExecutionCompletion; - await _outputDevice!.DisplayAsync(_outputDeviceDataProducer, new TextOutputDeviceData(ExtensionResources.HotReloadSessionCompleted)); + await waitExecutionCompletion.ConfigureAwait(false); + await _outputDevice!.DisplayAsync(_outputDeviceDataProducer, new TextOutputDeviceData(ExtensionResources.HotReloadSessionCompleted)).ConfigureAwait(false); } try { - await SemaphoreSlim.WaitAsync(cancellationToken); + await SemaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { @@ -102,7 +102,7 @@ public async Task ShouldRunAsync(Task? waitExecutionCompletion, Cancellati _console!.Clear(); } - await _outputDevice.DisplayAsync(_outputDeviceDataProducer, new TextOutputDeviceData(ExtensionResources.HotReloadSessionStarted)); + await _outputDevice.DisplayAsync(_outputDeviceDataProducer, new TextOutputDeviceData(ExtensionResources.HotReloadSessionStarted)).ConfigureAwait(false); return !s_shutdownProcess; } diff --git a/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadTestHostTestFrameworkInvoker.cs b/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadTestHostTestFrameworkInvoker.cs index df6c08a9d4..f28b457c82 100644 --- a/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadTestHostTestFrameworkInvoker.cs +++ b/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadTestHostTestFrameworkInvoker.cs @@ -33,7 +33,7 @@ public override async Task ExecuteRequestAsync(ITestFramework testFrameworkAdapt { if (!_isHotReloadEnabled) { - await base.ExecuteRequestAsync(testFrameworkAdapter, request, messageBus, cancellationToken); + await base.ExecuteRequestAsync(testFrameworkAdapter, request, messageBus, cancellationToken).ConfigureAwait(false); return; } @@ -41,25 +41,23 @@ public override async Task ExecuteRequestAsync(ITestFramework testFrameworkAdapt IOutputDevice outputDevice = ServiceProvider.GetOutputDevice(); var hotReloadHandler = new HotReloadHandler(ServiceProvider.GetConsole(), outputDevice, this); TaskCompletionSource? executionCompleted = null; - while (await hotReloadHandler.ShouldRunAsync(executionCompleted?.Task, ServiceProvider.GetTestApplicationCancellationTokenSource().CancellationToken)) + while (await hotReloadHandler.ShouldRunAsync(executionCompleted?.Task, ServiceProvider.GetTestApplicationCancellationTokenSource().CancellationToken).ConfigureAwait(false)) { executionCompleted = new(); using SemaphoreSlim requestSemaphore = new(1); var hotReloadOutputDevice = ServiceProvider.GetPlatformOutputDevice() as IHotReloadPlatformOutputDevice; if (hotReloadOutputDevice is not null) { - await hotReloadOutputDevice.DisplayBeforeHotReloadSessionStartAsync(); + await hotReloadOutputDevice.DisplayBeforeHotReloadSessionStartAsync().ConfigureAwait(false); } -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - await testFrameworkAdapter.ExecuteRequestAsync(new(request, messageBus, new SemaphoreSlimRequestCompleteNotifier(requestSemaphore), cancellationToken)); -#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + await testFrameworkAdapter.ExecuteRequestAsync(new(request, messageBus, new SemaphoreSlimRequestCompleteNotifier(requestSemaphore), cancellationToken)).ConfigureAwait(false); - await requestSemaphore.WaitAsync(cancellationToken); - await ServiceProvider.GetBaseMessageBus().DrainDataAsync(); + await requestSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + await ServiceProvider.GetBaseMessageBus().DrainDataAsync().ConfigureAwait(false); if (hotReloadOutputDevice is not null) { - await hotReloadOutputDevice.DisplayAfterHotReloadSessionEndAsync(); + await hotReloadOutputDevice.DisplayAfterHotReloadSessionEndAsync().ConfigureAwait(false); } executionCompleted.SetResult(0); diff --git a/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildConsumer.cs b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildConsumer.cs index 124be7cbb5..9ce87925d1 100644 --- a/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildConsumer.cs +++ b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildConsumer.cs @@ -94,7 +94,7 @@ await HandleFailuresAsync( actual: null, testFileLocationProperty?.FilePath, testFileLocationProperty?.LineSpan.Start.Line ?? 0, - cancellationToken); + cancellationToken).ConfigureAwait(false); break; case FailedTestNodeStateProperty failedState: @@ -108,7 +108,7 @@ await HandleFailuresAsync( actual: failedState.Exception?.Data["assert.actual"] as string, testFileLocationProperty?.FilePath, testFileLocationProperty?.LineSpan.Start.Line ?? 0, - cancellationToken); + cancellationToken).ConfigureAwait(false); break; case TimeoutTestNodeStateProperty timeoutState: @@ -122,7 +122,7 @@ await HandleFailuresAsync( actual: null, testFileLocationProperty?.FilePath, testFileLocationProperty?.LineSpan.Start.Line ?? 0, - cancellationToken); + cancellationToken).ConfigureAwait(false); break; case CancelledTestNodeStateProperty canceledState: @@ -136,7 +136,7 @@ await HandleFailuresAsync( actual: null, testFileLocationProperty?.FilePath, testFileLocationProperty?.LineSpan.Start.Line ?? 0, - cancellationToken); + cancellationToken).ConfigureAwait(false); break; case PassedTestNodeStateProperty: @@ -153,7 +153,7 @@ await HandleFailuresAsync( break; case TestRequestExecutionTimeInfo testRequestExecutionTimeInfo: - await HandleSummaryAsync(testRequestExecutionTimeInfo, cancellationToken); + await HandleSummaryAsync(testRequestExecutionTimeInfo, cancellationToken).ConfigureAwait(false); break; } @@ -166,7 +166,7 @@ private async Task HandleFailuresAsync(string testDisplayName, bool isCanceled, ApplicationStateGuard.Ensure(_msBuildTestApplicationLifecycleCallbacks != null); ApplicationStateGuard.Ensure(_msBuildTestApplicationLifecycleCallbacks.PipeClient != null); var failedTestInfoRequest = new FailedTestInfoRequest(testDisplayName, isCanceled, duration, errorMessage, errorStackTrace, expected, actual, codeFilePath, lineNumber); - await _msBuildTestApplicationLifecycleCallbacks.PipeClient.RequestReplyAsync(failedTestInfoRequest, cancellationToken); + await _msBuildTestApplicationLifecycleCallbacks.PipeClient.RequestReplyAsync(failedTestInfoRequest, cancellationToken).ConfigureAwait(false); } private async Task HandleSummaryAsync(TestRequestExecutionTimeInfo timeInfo, CancellationToken cancellationToken) @@ -176,7 +176,7 @@ private async Task HandleSummaryAsync(TestRequestExecutionTimeInfo timeInfo, Can ApplicationStateGuard.Ensure(_msBuildTestApplicationLifecycleCallbacks != null); ApplicationStateGuard.Ensure(_msBuildTestApplicationLifecycleCallbacks.PipeClient != null); var runSummaryInfoRequest = new RunSummaryInfoRequest(_totalTests, _totalFailedTests, _totalPassedTests, _totalSkippedTests, duration); - await _msBuildTestApplicationLifecycleCallbacks.PipeClient.RequestReplyAsync(runSummaryInfoRequest, cancellationToken); + await _msBuildTestApplicationLifecycleCallbacks.PipeClient.RequestReplyAsync(runSummaryInfoRequest, cancellationToken).ConfigureAwait(false); } private static string? ToHumanReadableDuration(double? durationInMs) diff --git a/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildExtensions.cs index cbd3d784be..5f9509761c 100644 --- a/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildExtensions.cs +++ b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildExtensions.cs @@ -20,12 +20,18 @@ public static class MSBuildExtensions public static void AddMSBuild(this ITestApplicationBuilder builder) { builder.CommandLine.AddProvider(() => new MSBuildCommandLineProvider()); - builder.TestHost.AddTestApplicationLifecycleCallbacks( + builder.TestHost.AddTestHostApplicationLifetime( serviceProvider => new MSBuildTestApplicationLifecycleCallbacks( serviceProvider.GetConfiguration(), serviceProvider.GetCommandLineOptions(), serviceProvider.GetTestApplicationCancellationTokenSource())); + ((TestApplicationBuilder)builder).TestHostOrchestrator.AddTestHostOrchestratorApplicationLifetime( + serviceProvider => new MSBuildOrchestratorLifetime( + serviceProvider.GetConfiguration(), + serviceProvider.GetCommandLineOptions(), + serviceProvider.GetTestApplicationCancellationTokenSource())); + CompositeExtensionFactory compositeExtensionFactory = new(serviceProvider => new MSBuildConsumer( serviceProvider, diff --git a/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildOrchestratorLifecycleCallbacks.cs b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildOrchestratorLifecycleCallbacks.cs new file mode 100644 index 0000000000..b74ba02f2f --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildOrchestratorLifecycleCallbacks.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Extensions.MSBuild.Serializers; +using Microsoft.Testing.Platform.CommandLine; +using Microsoft.Testing.Platform.Configurations; +using Microsoft.Testing.Platform.Extensions.TestHostOrchestrator; +using Microsoft.Testing.Platform.Helpers; +using Microsoft.Testing.Platform.IPC; +using Microsoft.Testing.Platform.IPC.Models; +using Microsoft.Testing.Platform.IPC.Serializers; +using Microsoft.Testing.Platform.Services; + +namespace Microsoft.Testing.Extensions.MSBuild; + +internal sealed class MSBuildOrchestratorLifetime : ITestHostOrchestratorApplicationLifetime +{ + private readonly IConfiguration _configuration; + private readonly ICommandLineOptions _commandLineOptions; + private readonly ITestApplicationCancellationTokenSource _testApplicationCancellationTokenSource; + + public MSBuildOrchestratorLifetime( + IConfiguration configuration, + ICommandLineOptions commandLineOptions, + ITestApplicationCancellationTokenSource testApplicationCancellationTokenSource) + { + _configuration = configuration; + _commandLineOptions = commandLineOptions; + _testApplicationCancellationTokenSource = testApplicationCancellationTokenSource; + } + + public string Uid => nameof(MSBuildOrchestratorLifetime); + + public string Version => AppVersion.DefaultSemVer; + + public string DisplayName => nameof(MSBuildOrchestratorLifetime); + + public string Description => Resources.ExtensionResources.MSBuildExtensionsDescription; + + public Task IsEnabledAsync() + => Task.FromResult(_commandLineOptions.IsOptionSet(MSBuildConstants.MSBuildNodeOptionKey)); + + public async Task BeforeRunAsync(CancellationToken cancellationToken) + { + if (!_commandLineOptions.TryGetOptionArgumentList(MSBuildConstants.MSBuildNodeOptionKey, out string[]? msbuildInfo)) + { + throw new InvalidOperationException($"MSBuild pipe name not found in the command line, missing {MSBuildConstants.MSBuildNodeOptionKey}"); + } + + if (msbuildInfo is null || msbuildInfo.Length != 1 || string.IsNullOrEmpty(msbuildInfo[0])) + { + throw new InvalidOperationException($"MSBuild pipe name not found in the command line, missing argument for {MSBuildConstants.MSBuildNodeOptionKey}"); + } + + using var pipeClient = new NamedPipeClient(msbuildInfo[0]); + pipeClient.RegisterSerializer(new ModuleInfoRequestSerializer(), typeof(ModuleInfoRequest)); + pipeClient.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse)); + using var cancellationTokenSource = new CancellationTokenSource(TimeoutHelper.DefaultHangTimeSpanTimeout); + using var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, _testApplicationCancellationTokenSource.CancellationToken); + await pipeClient.ConnectAsync(linkedCancellationToken.Token).ConfigureAwait(false); + await pipeClient.RequestReplyAsync( + new ModuleInfoRequest( + RuntimeInformation.FrameworkDescription, + RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(), + _configuration.GetTestResultDirectory()), + _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); + } + + public Task AfterRunAsync(int exitCode, CancellationToken cancellation) => Task.CompletedTask; +} diff --git a/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildTestApplicationLifecycleCallbacks.cs b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildTestApplicationLifecycleCallbacks.cs index 7e830ab2b7..b8b91ecb4f 100644 --- a/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildTestApplicationLifecycleCallbacks.cs +++ b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildTestApplicationLifecycleCallbacks.cs @@ -13,7 +13,7 @@ namespace Microsoft.Testing.Extensions.MSBuild; -internal sealed class MSBuildTestApplicationLifecycleCallbacks : ITestApplicationLifecycleCallbacks, IDisposable +internal sealed class MSBuildTestApplicationLifecycleCallbacks : ITestHostApplicationLifetime, IDisposable { private readonly IConfiguration _configuration; private readonly ICommandLineOptions _commandLineOptions; @@ -61,13 +61,13 @@ public async Task BeforeRunAsync(CancellationToken cancellationToken) PipeClient.RegisterSerializer(new RunSummaryInfoRequestSerializer(), typeof(RunSummaryInfoRequest)); using var cancellationTokenSource = new CancellationTokenSource(TimeoutHelper.DefaultHangTimeSpanTimeout); using var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, _testApplicationCancellationTokenSource.CancellationToken); - await PipeClient.ConnectAsync(linkedCancellationToken.Token); + await PipeClient.ConnectAsync(linkedCancellationToken.Token).ConfigureAwait(false); await PipeClient.RequestReplyAsync( new ModuleInfoRequest( RuntimeInformation.FrameworkDescription, RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(), _configuration.GetTestResultDirectory()), - _testApplicationCancellationTokenSource.CancellationToken); + _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); } public void Dispose() diff --git a/src/Platform/Microsoft.Testing.Extensions.MSBuild/Microsoft.Testing.Extensions.MSBuild.csproj b/src/Platform/Microsoft.Testing.Extensions.MSBuild/Microsoft.Testing.Extensions.MSBuild.csproj index ba0721a0bd..b830523061 100644 --- a/src/Platform/Microsoft.Testing.Extensions.MSBuild/Microsoft.Testing.Extensions.MSBuild.csproj +++ b/src/Platform/Microsoft.Testing.Extensions.MSBuild/Microsoft.Testing.Extensions.MSBuild.csproj @@ -6,6 +6,11 @@ false + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.MSBuild/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.MSBuild/PublicAPI.Shipped.txt new file mode 100644 index 0000000000..a82cec2234 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.MSBuild/PublicAPI.Shipped.txt @@ -0,0 +1,5 @@ +#nullable enable +Microsoft.Testing.Platform.MSBuild.MSBuildExtensions +Microsoft.Testing.Platform.MSBuild.TestingPlatformBuilderHook +static Microsoft.Testing.Platform.MSBuild.MSBuildExtensions.AddMSBuild(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder) -> void +static Microsoft.Testing.Platform.MSBuild.TestingPlatformBuilderHook.AddExtensions(Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! testApplicationBuilder, string![]! _) -> void diff --git a/src/Platform/Microsoft.Testing.Extensions.MSBuild/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.MSBuild/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000..7dc5c58110 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.MSBuild/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.Retry/BannedSymbols.txt index 5bc5c2fb96..7be39f73d1 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Retry/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Extensions.Retry/BannedSymbols.txt @@ -6,5 +6,7 @@ M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask M:System.Threading.Tasks.Task.WhenAll(System.Collections.Generic.IEnumerable{System.Threading.Tasks.Task}); Use 'ITask' instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead +T:System.File; Use 'IFileSystem' instead +T:System.Directory; Use 'IFileSystem' instead diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryCommandLineOptionsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryCommandLineOptionsProvider.cs index 954fb4dfe9..5a5e521ca2 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryCommandLineOptionsProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryCommandLineOptionsProvider.cs @@ -24,9 +24,8 @@ internal sealed class RetryCommandLineOptionsProvider : ICommandLineOptionsProvi public string Description => ExtensionResources.RetryFailedTestsExtensionDescription; - public IReadOnlyCollection GetCommandLineOptions() - => new CommandLineOption[] - { + public IReadOnlyCollection GetCommandLineOptions() => + [ // Hide the extension for now, we will add tests and we will re-enable when will be good. // We'd like to have some iteration in prod with our dogfooders before. new(RetryFailedTestsOptionName, ExtensionResources.RetryFailedTestsOptionDescription, ArgumentArity.ExactlyOne, false, isBuiltIn: true), @@ -34,8 +33,8 @@ public IReadOnlyCollection GetCommandLineOptions() new(RetryFailedTestsMaxTestsOptionName, ExtensionResources.RetryFailedTestsMaxTestsOptionDescription, ArgumentArity.ExactlyOne, false, isBuiltIn: true), // Hidden internal args - new(RetryFailedTestsPipeNameOptionName, "Communication between the test host and the retry infra.", ArgumentArity.ExactlyOne, isHidden: true, isBuiltIn: true), - }; + new(RetryFailedTestsPipeNameOptionName, "Communication between the test host and the retry infra.", ArgumentArity.ExactlyOne, isHidden: true, isBuiltIn: true) + ]; public Task IsEnabledAsync() => Task.FromResult(true); diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryDataConsumer.cs b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryDataConsumer.cs index 8b92f00072..2c1b46b798 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryDataConsumer.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryDataConsumer.cs @@ -28,7 +28,7 @@ public RetryDataConsumer(IServiceProvider serviceProvider) _commandLineOptions = _serviceProvider.GetCommandLineOptions(); } - public Type[] DataTypesConsumed => new[] { typeof(TestNodeUpdateMessage) }; + public Type[] DataTypesConsumed => [typeof(TestNodeUpdateMessage)]; public string Uid => nameof(RetryDataConsumer); @@ -51,7 +51,7 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella { ApplicationStateGuard.Ensure(_retryFailedTestsLifecycleCallbacks is not null); ApplicationStateGuard.Ensure(_retryFailedTestsLifecycleCallbacks.Client is not null); - await _retryFailedTestsLifecycleCallbacks.Client.RequestReplyAsync(new FailedTestRequest(testNodeUpdateMessage.TestNode.Uid), cancellationToken); + await _retryFailedTestsLifecycleCallbacks.Client.RequestReplyAsync(new FailedTestRequest(testNodeUpdateMessage.TestNode.Uid), cancellationToken).ConfigureAwait(false); } if (Array.IndexOf(TestNodePropertiesCategories.WellKnownTestNodeTestRunOutcomeProperties, nodeState.GetType()) != -1) @@ -64,7 +64,7 @@ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, Cancellatio { ApplicationStateGuard.Ensure(_retryFailedTestsLifecycleCallbacks is not null); ApplicationStateGuard.Ensure(_retryFailedTestsLifecycleCallbacks.Client is not null); - await _retryFailedTestsLifecycleCallbacks.Client.RequestReplyAsync(new TotalTestsRunRequest(_totalTests), cancellationToken); + await _retryFailedTestsLifecycleCallbacks.Client.RequestReplyAsync(new TotalTestsRunRequest(_totalTests), cancellationToken).ConfigureAwait(false); } public Task OnTestSessionStartingAsync(SessionUid sessionUid, CancellationToken cancellationToken) @@ -76,7 +76,7 @@ public Task IsEnabledAsync() public async Task InitializeAsync() { - if (await IsEnabledAsync()) + if (await IsEnabledAsync().ConfigureAwait(false)) { _retryFailedTestsLifecycleCallbacks = _serviceProvider.GetRequiredService(); } diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExecutionFilterFactory.cs b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExecutionFilterFactory.cs index 1beb0961e0..c2b9b8c13a 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExecutionFilterFactory.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExecutionFilterFactory.cs @@ -38,13 +38,12 @@ public Task IsEnabledAsync() _retryFailedTestsLifecycleCallbacks = _serviceProvider.GetRequiredService(); if (_retryFailedTestsLifecycleCallbacks.FailedTestsIDToRetry?.Length > 0) { - return (true, new TestNodeUidListFilter(_retryFailedTestsLifecycleCallbacks.FailedTestsIDToRetry - .Select(x => new TestNodeUid(x)).ToArray())); + return (true, new TestNodeUidListFilter([.. _retryFailedTestsLifecycleCallbacks.FailedTestsIDToRetry.Select(x => new TestNodeUid(x))])); } else { ConsoleTestExecutionFilterFactory consoleTestExecutionFilterFactory = new(_commandLineOptions); - return await consoleTestExecutionFilterFactory.TryCreateAsync(); + return await consoleTestExecutionFilterFactory.TryCreateAsync().ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExtensions.cs index 0a048a39c9..544672fc03 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExtensions.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExtensions.cs @@ -23,7 +23,7 @@ public static void AddRetryProvider(this ITestApplicationBuilder builder) { builder.CommandLine.AddProvider(() => new RetryCommandLineOptionsProvider()); - builder.TestHost.AddTestApplicationLifecycleCallbacks(serviceProvider + builder.TestHost.AddTestHostApplicationLifetime(serviceProvider => new RetryLifecycleCallbacks(serviceProvider)); CompositeExtensionFactory compositeExtensionFactory diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryFailedTestsPipeServer.cs b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryFailedTestsPipeServer.cs index 21032e0497..0702dba543 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryFailedTestsPipeServer.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryFailedTestsPipeServer.cs @@ -19,7 +19,7 @@ internal sealed class RetryFailedTestsPipeServer : IDisposable public RetryFailedTestsPipeServer(IServiceProvider serviceProvider, string[] failedTests, ILogger logger) { - _pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N")); + _pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"), serviceProvider.GetEnvironment()); logger.LogTrace($"Retry server pipe name: '{_pipeNameDescription.Name}'"); _singleConnectionNamedPipeServer = new NamedPipeServer(_pipeNameDescription, CallbackAsync, serviceProvider.GetEnvironment(), @@ -54,7 +54,7 @@ private Task CallbackAsync(IRequest request) { if (request is FailedTestRequest failed) { - FailedUID ??= new(); + FailedUID ??= []; FailedUID.Add(failed.Uid); return Task.FromResult((IResponse)VoidResponse.CachedInstance); } diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryLifecycleCallbacks.cs b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryLifecycleCallbacks.cs index 6d019d9fd1..91c7fda0a1 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryLifecycleCallbacks.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryLifecycleCallbacks.cs @@ -16,7 +16,7 @@ namespace Microsoft.Testing.Extensions.Policy; -internal sealed class RetryLifecycleCallbacks : ITestApplicationLifecycleCallbacks, +internal sealed class RetryLifecycleCallbacks : ITestHostApplicationLifetime, #if NETCOREAPP IAsyncDisposable #else @@ -63,9 +63,9 @@ public async Task BeforeRunAsync(CancellationToken cancellationToken) Client.RegisterSerializer(new GetListOfFailedTestsRequestSerializer(), typeof(GetListOfFailedTestsRequest)); Client.RegisterSerializer(new GetListOfFailedTestsResponseSerializer(), typeof(GetListOfFailedTestsResponse)); Client.RegisterSerializer(new TotalTestsRunRequestSerializer(), typeof(TotalTestsRunRequest)); - await Client.ConnectAsync(cancellationToken); + await Client.ConnectAsync(cancellationToken).ConfigureAwait(false); - GetListOfFailedTestsResponse result = await Client.RequestReplyAsync(new GetListOfFailedTestsRequest(), cancellationToken); + GetListOfFailedTestsResponse result = await Client.RequestReplyAsync(new GetListOfFailedTestsRequest(), cancellationToken).ConfigureAwait(false); FailedTestsIDToRetry = result.FailedTestIds; } @@ -80,7 +80,7 @@ public async ValueTask DisposeAsync() { if (Client is not null) { - await Client.DisposeAsync(); + await Client.DisposeAsync().ConfigureAwait(false); } } #else diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryOrchestrator.cs b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryOrchestrator.cs index 59df6004f2..e06210513d 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryOrchestrator.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryOrchestrator.cs @@ -17,11 +17,13 @@ internal sealed class RetryOrchestrator : ITestHostOrchestrator, IOutputDeviceDa { private readonly IServiceProvider _serviceProvider; private readonly ICommandLineOptions _commandLineOptions; + private readonly IFileSystem _fileSystem; public RetryOrchestrator(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; _commandLineOptions = _serviceProvider.GetCommandLineOptions(); + _fileSystem = _serviceProvider.GetFileSystem(); } public string Uid => nameof(RetryOrchestrator); @@ -35,21 +37,21 @@ public RetryOrchestrator(IServiceProvider serviceProvider) public Task IsEnabledAsync() => Task.FromResult(_commandLineOptions.IsOptionSet(RetryCommandLineOptionsProvider.RetryFailedTestsOptionName)); - private static string CreateRetriesDirectory(string resultDirectory) + private string CreateRetriesDirectory(string resultDirectory) { Exception? lastException = null; // Quite arbitrary. Keep trying to create the directory for 10 times. for (int i = 0; i < 10; i++) { string retryRootFolder = Path.Combine(resultDirectory, "Retries", RandomId.Next()); - if (Directory.Exists(retryRootFolder)) + if (_fileSystem.ExistDirectory(retryRootFolder)) { continue; } try { - Directory.CreateDirectory(retryRootFolder); + _fileSystem.CreateDirectory(retryRootFolder); return retryRootFolder; } catch (IOException ex) @@ -73,11 +75,14 @@ public async Task OrchestrateTestHostExecutionAsync() throw new InvalidOperationException(ExtensionResources.RetryFailedTestsNotSupportedInServerModeErrorMessage); } - if (IsHotReloadEnabled(_serviceProvider.GetEnvironment())) + IEnvironment environment = _serviceProvider.GetEnvironment(); + if (IsHotReloadEnabled(environment)) { throw new InvalidOperationException(ExtensionResources.RetryFailedTestsNotSupportedInHotReloadErrorMessage); } + environment.SetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_TRX_TESTRUN_ID, Guid.NewGuid().ToString("N")); + ILogger logger = _serviceProvider.GetLoggerFactory().CreateLogger(); IConfiguration configuration = _serviceProvider.GetConfiguration(); @@ -93,8 +98,8 @@ public async Task OrchestrateTestHostExecutionAsync() int userMaxRetryCount = int.Parse(cmdRetries[0], CultureInfo.InvariantCulture); // Find out the retry args index inside the arguments to after cleanup the command line when we restart - List indexToCleanup = new(); - string[] executableArguments = executableInfo.Arguments.ToArray(); + List indexToCleanup = []; + string[] executableArguments = [.. executableInfo.Arguments]; int argIndex = GetOptionArgumentIndex(RetryCommandLineOptionsProvider.RetryFailedTestsOptionName, executableArguments); if (argIndex < 0) { @@ -128,12 +133,12 @@ public async Task OrchestrateTestHostExecutionAsync() // Override the result directory with the attempt one string resultDirectory = configuration.GetTestResultDirectory(); - List exitCodes = new(); + List exitCodes = []; IOutputDevice outputDevice = _serviceProvider.GetOutputDevice(); IFileSystem fileSystem = _serviceProvider.GetFileSystem(); int attemptCount = 0; - List finalArguments = new(); + List finalArguments = []; string[]? lastListOfFailedId = null; string? currentTryResultFolder = null; bool thresholdPolicyKickedIn = false; @@ -160,7 +165,7 @@ public async Task OrchestrateTestHostExecutionAsync() finalArguments.Add(currentTryResultFolder); // Prepare the pipeserver - using RetryFailedTestsPipeServer retryFailedTestsPipeServer = new(_serviceProvider, lastListOfFailedId ?? Array.Empty(), logger); + using RetryFailedTestsPipeServer retryFailedTestsPipeServer = new(_serviceProvider, lastListOfFailedId ?? [], logger); finalArguments.Add($"--{RetryCommandLineOptionsProvider.RetryFailedTestsPipeNameOptionName}"); finalArguments.Add(retryFailedTestsPipeServer.PipeName); @@ -182,7 +187,7 @@ public async Task OrchestrateTestHostExecutionAsync() #endif } - await logger.LogDebugAsync($"Starting test host process, attempt {attemptCount}/{userMaxRetryCount}"); + await logger.LogDebugAsync($"Starting test host process, attempt {attemptCount}/{userMaxRetryCount}").ConfigureAwait(false); IProcess testHostProcess = _serviceProvider.GetProcessHandler().Start(processStartInfo) ?? throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ExtensionResources.RetryFailedTestsCannotStartProcessErrorMessage, processStartInfo.FileName)); @@ -198,39 +203,39 @@ public async Task OrchestrateTestHostExecutionAsync() using (var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, _serviceProvider.GetTestApplicationCancellationTokenSource().CancellationToken)) using (var linkedToken2 = CancellationTokenSource.CreateLinkedTokenSource(linkedToken.Token, processExitedCancellationToken.Token)) { - await logger.LogDebugAsync("Wait connection from the test host process"); + await logger.LogDebugAsync("Wait connection from the test host process").ConfigureAwait(false); try { #if NETCOREAPP - await retryFailedTestsPipeServer.WaitForConnectionAsync(linkedToken2.Token); + await retryFailedTestsPipeServer.WaitForConnectionAsync(linkedToken2.Token).ConfigureAwait(false); #else // We don't know why but if the cancellation is called quickly in line 171 for netfx we stuck sometime here, like if // the token we pass to the named pipe is not "correctly" verified inside the pipe implementation self. // We fallback with our custom agnostic cancellation mechanism in that case. // We see it happen only in .NET FX and not in .NET Core so for now we don't do it for core. - await retryFailedTestsPipeServer.WaitForConnectionAsync(linkedToken2.Token).WithCancellationAsync(linkedToken2.Token); + await retryFailedTestsPipeServer.WaitForConnectionAsync(linkedToken2.Token).WithCancellationAsync(linkedToken2.Token).ConfigureAwait(false); #endif } catch (OperationCanceledException) when (processExitedCancellationToken.IsCancellationRequested) { - await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestHostProcessExitedBeforeRetryCouldConnect, testHostProcess.ExitCode))); + await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestHostProcessExitedBeforeRetryCouldConnect, testHostProcess.ExitCode))).ConfigureAwait(false); return ExitCodes.GenericFailure; } } - await testHostProcess.WaitForExitAsync(); + await testHostProcess.WaitForExitAsync().ConfigureAwait(false); exitCodes.Add(testHostProcess.ExitCode); if (testHostProcess.ExitCode != ExitCodes.Success) { if (testHostProcess.ExitCode != ExitCodes.AtLeastOneTestFailed) { - await outputDevice.DisplayAsync(this, new WarningMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestSuiteFailedWithWrongExitCode, testHostProcess.ExitCode))); + await outputDevice.DisplayAsync(this, new WarningMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestSuiteFailedWithWrongExitCode, testHostProcess.ExitCode))).ConfigureAwait(false); retryInterrupted = true; break; } - await outputDevice.DisplayAsync(this, new WarningMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestSuiteFailed, retryFailedTestsPipeServer.FailedUID?.Count ?? 0, testHostProcess.ExitCode, attemptCount, userMaxRetryCount + 1))); + await outputDevice.DisplayAsync(this, new WarningMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestSuiteFailed, retryFailedTestsPipeServer.FailedUID?.Count ?? 0, testHostProcess.ExitCode, attemptCount, userMaxRetryCount + 1))).ConfigureAwait(false); // Check thresholds if (attemptCount == 1) @@ -269,7 +274,7 @@ public async Task OrchestrateTestHostExecutionAsync() explanation.AppendLine(string.Format(CultureInfo.InvariantCulture, ExtensionResources.FailureThresholdPolicyMaxCount, maxCount, retryFailedTestsPipeServer.FailedUID!.Count)); } - await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(explanation.ToString())); + await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(explanation.ToString())).ConfigureAwait(false); break; } } @@ -288,20 +293,20 @@ public async Task OrchestrateTestHostExecutionAsync() { if (exitCodes[^1] != ExitCodes.Success) { - await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestSuiteFailedInAllAttempts, userMaxRetryCount + 1))); + await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestSuiteFailedInAllAttempts, userMaxRetryCount + 1))).ConfigureAwait(false); } else { - await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestSuiteCompletedSuccessfully, attemptCount)) { ForegroundColor = new SystemConsoleColor { ConsoleColor = ConsoleColor.Green } }); + await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TestSuiteCompletedSuccessfully, attemptCount)) { ForegroundColor = new SystemConsoleColor { ConsoleColor = ConsoleColor.DarkGreen } }).ConfigureAwait(false); } } ApplicationStateGuard.Ensure(currentTryResultFolder is not null); - string[] filesToMove = Directory.GetFiles(currentTryResultFolder, "*.*", SearchOption.AllDirectories); + string[] filesToMove = _fileSystem.GetFiles(currentTryResultFolder, "*.*", SearchOption.AllDirectories); if (filesToMove.Length > 0) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(ExtensionResources.MoveFiles)); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(ExtensionResources.MoveFiles)).ConfigureAwait(false); // Move last attempt assets foreach (string file in filesToMove) @@ -309,14 +314,14 @@ public async Task OrchestrateTestHostExecutionAsync() string finalFileLocation = file.Replace(currentTryResultFolder, resultDirectory); // Create the directory if missing - Directory.CreateDirectory(Path.GetDirectoryName(finalFileLocation)!); + fileSystem.CreateDirectory(Path.GetDirectoryName(finalFileLocation)!); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.MovingFileToLocation, file, finalFileLocation))); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.MovingFileToLocation, file, finalFileLocation))).ConfigureAwait(false); #if NETCOREAPP - File.Move(file, finalFileLocation, overwrite: true); + fileSystem.MoveFile(file, finalFileLocation, overwrite: true); #else - File.Copy(file, finalFileLocation, overwrite: true); - File.Delete(file); + fileSystem.CopyFile(file, finalFileLocation, overwrite: true); + fileSystem.DeleteFile(file); #endif } } diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClient.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClient.cs index fe27fd2eb2..33d9a0ba3c 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClient.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClient.cs @@ -12,14 +12,13 @@ internal sealed class AppInsightTelemetryClient : ITelemetryClient private const string InstrumentationKey = "74cc1c9e-3e6e-4d05-b3fc-dde9101d0254"; private const string TelemetryServiceEndpoint = "https://dc.services.visualstudio.com/"; - private readonly TelemetryConfiguration _config; private readonly TelemetryClient _telemetryClient; public AppInsightTelemetryClient(string? currentSessionId, string osVersion) { - _config = TelemetryConfiguration.CreateDefault(); - _config.ConnectionString = $"InstrumentationKey={InstrumentationKey};IngestionEndpoint={TelemetryServiceEndpoint}"; - _telemetryClient = new TelemetryClient(_config); + var config = TelemetryConfiguration.CreateDefault(); + config.ConnectionString = $"InstrumentationKey={InstrumentationKey};IngestionEndpoint={TelemetryServiceEndpoint}"; + _telemetryClient = new TelemetryClient(config); _telemetryClient.Context.Session.Id = currentSessionId; _telemetryClient.Context.Device.OperatingSystem = osVersion; } diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs index 959180a64a..fd9926502d 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs @@ -108,7 +108,7 @@ public AppInsightsProvider( #else // Keep the custom thread to avoid to waste one from thread pool. // We have some await but we should stay on the custom thread if not for special cases like trace log or exception. - _payloads = new(); + _payloads = []; _telemetryTask = _task.RunLongRunning(IngestLoopAsync, "Telemetry AppInsightsProvider", _testApplicationCancellationTokenSource.CancellationToken); #endif @@ -131,7 +131,7 @@ private async Task IngestLoopAsync() { _client = null; - await _logger.LogErrorAsync("Failed to initialize telemetry client", e); + await _logger.LogErrorAsync("Failed to initialize telemetry client", e).ConfigureAwait(false); return; } @@ -140,9 +140,9 @@ private async Task IngestLoopAsync() try { #if NETCOREAPP - while (await _payloads.Reader.WaitToReadAsync(_flushTimeoutOrStop.Token)) + while (await _payloads.Reader.WaitToReadAsync(_flushTimeoutOrStop.Token).ConfigureAwait(false)) { - (string eventName, IDictionary paramsMap) = await _payloads.Reader.ReadAsync(); + (string eventName, IDictionary paramsMap) = await _payloads.Reader.ReadAsync().ConfigureAwait(false); #else foreach ((string eventName, IDictionary paramsMap) in _payloads.GetConsumingEnumerable(_flushTimeoutOrStop.Token)) { @@ -205,7 +205,7 @@ private async Task IngestLoopAsync() builder.AppendLine(CultureInfo.InvariantCulture, $" {key}: {value.ToString("f", CultureInfo.InvariantCulture)}"); } - await _logger.LogTraceAsync(builder.ToString()); + await _logger.LogTraceAsync(builder.ToString()).ConfigureAwait(false); } try @@ -219,7 +219,7 @@ private async Task IngestLoopAsync() // We could do better back-pressure. if (_logger.IsEnabled(LogLevel.Error) && (!lastLoggedError.HasValue || (lastLoggedError.Value - _clock.UtcNow).TotalSeconds > 3)) { - await _logger.LogErrorAsync("Error during telemetry report.", ex); + await _logger.LogErrorAsync("Error during telemetry report.", ex).ConfigureAwait(false); lastLoggedError = _clock.UtcNow; } } @@ -260,10 +260,10 @@ private static void AssertHashed(string key, string value) } #if NET7_0_OR_GREATER - [System.Text.RegularExpressions.GeneratedRegex("[a-f0-9]{64}")] - private static partial System.Text.RegularExpressions.Regex GetValidHashPattern(); + [GeneratedRegex("[a-f0-9]{64}")] + private static partial Regex GetValidHashPattern(); #else - private static System.Text.RegularExpressions.Regex GetValidHashPattern() + private static Regex GetValidHashPattern() => new("[a-f0-9]{64}"); #endif #endif @@ -275,7 +275,7 @@ private static System.Text.RegularExpressions.Regex GetValidHashPattern() Task LogEventAsync(string eventName, IDictionary paramsMap) { #if NETCOREAPP - await _payloads.Writer.WriteAsync((eventName, paramsMap)); + await _payloads.Writer.WriteAsync((eventName, paramsMap)).ConfigureAwait(false); #else _payloads.Add((eventName, paramsMap)); return Task.CompletedTask; @@ -320,12 +320,12 @@ public async ValueTask DisposeAsync() int flushForSeconds = 3; try { - await _telemetryTask.TimeoutAfterAsync(TimeSpan.FromSeconds(flushForSeconds)); + await _telemetryTask.TimeoutAfterAsync(TimeSpan.FromSeconds(flushForSeconds)).ConfigureAwait(false); } catch (TimeoutException) { - await _flushTimeoutOrStop.CancelAsync(); - await _logger.LogWarningAsync($"Telemetry task didn't flush after '{flushForSeconds}', some payload could be lost"); + await _flushTimeoutOrStop.CancelAsync().ConfigureAwait(false); + await _logger.LogWarningAsync($"Telemetry task didn't flush after '{flushForSeconds}', some payload could be lost").ConfigureAwait(false); } _isDisposed = true; diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.Telemetry/BannedSymbols.txt index 469bd16cf9..0fcaeeec4b 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/BannedSymbols.txt @@ -1,4 +1,4 @@ M:System.String.IsNullOrEmpty(System.String); Use 'TAString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'TAString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/CIEnvironmentDetectorForTelemetry.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/CIEnvironmentDetectorForTelemetry.cs index b90059537b..0ac25bde4a 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/CIEnvironmentDetectorForTelemetry.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/CIEnvironmentDetectorForTelemetry.cs @@ -33,8 +33,8 @@ internal sealed class CIEnvironmentDetectorForTelemetry ]; // Systems where every variable must be present and not-null before returning true - private static readonly string[][] AllNotNullVariables = new string[][] - { + private static readonly string[][] AllNotNullVariables = + [ // AWS CodeBuild - https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html ["CODEBUILD_BUILD_ID", "AWS_REGION"], @@ -43,7 +43,7 @@ internal sealed class CIEnvironmentDetectorForTelemetry // Google Cloud Build - https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values#using_default_substitutions ["BUILD_ID", "PROJECT_ID"], - }; + ]; // Systems where the variable must be present and not-null private static readonly string[] IfNonNullVariables = diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt index ea8617fcb0..09d715c49c 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt @@ -6,5 +6,5 @@ M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask M:System.Threading.Tasks.Task.WhenAll(System.Collections.Generic.IEnumerable{System.Threading.Tasks.Task}); Use 'ITask' instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt index ea8617fcb0..09d715c49c 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt @@ -6,5 +6,5 @@ M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask M:System.Threading.Tasks.Task.WhenAll(System.Collections.Generic.IEnumerable{System.Threading.Tasks.Task}); Use 'ITask' instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/ToolTrxCompareFactory.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/ToolTrxCompareFactory.cs index e88cb5b300..8cd1723dbb 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/ToolTrxCompareFactory.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/ToolTrxCompareFactory.cs @@ -12,10 +12,10 @@ namespace Microsoft.Testing.Extensions.TrxReport.Abstractions; internal sealed class ToolTrxCompareFactory : IExtension { /// - public string Uid { get; } = nameof(TrxCompareTool); + public string Uid => nameof(TrxCompareTool); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// public string DisplayName { get; } = ExtensionResources.TrxComparerToolDisplayName; diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCommandLine.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCommandLine.cs index 51f36f19dc..db827e0d45 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCommandLine.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCommandLine.cs @@ -16,10 +16,10 @@ internal sealed class TrxReportGeneratorCommandLine : ICommandLineOptionsProvide public const string TrxReportFileNameOptionName = "report-trx-filename"; /// - public string Uid { get; } = nameof(TrxReportGeneratorCommandLine); + public string Uid => nameof(TrxReportGeneratorCommandLine); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// public string DisplayName { get; } = ExtensionResources.TrxReportGeneratorDisplayName; diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.CommandLine.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.CommandLine.cs index bc131ffc4f..294e61c76a 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.CommandLine.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.CommandLine.cs @@ -31,7 +31,7 @@ public TrxCompareToolCommandLine(IExtension extension) public string Description => _extension.Description; /// - public string ToolName { get; } = TrxCompareTool.ToolName; + public string ToolName => TrxCompareTool.ToolName; /// public Task IsEnabledAsync() => Task.FromResult(true); diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs index c79cb5c062..43e967f035 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs @@ -12,6 +12,8 @@ namespace Microsoft.Testing.Extensions.TrxReport.Abstractions; internal sealed class TrxCompareTool : ITool, IOutputDeviceDataProducer { + private record struct Trx(string TestName, string Outcome, string Storage); + public const string ToolName = "ms-trxcompare"; private readonly ICommandLineOptions _commandLineOptions; private readonly IExtension _extension; @@ -28,7 +30,7 @@ public TrxCompareTool(ICommandLineOptions commandLineOptions, IExtension extensi } /// - public string Name { get; } = ToolName; + public string Name => ToolName; /// public string Uid => _extension.Uid; @@ -55,13 +57,14 @@ public async Task RunAsync() XNamespace trxNamespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010"; - List<(string TestName, string Outcome, string Storage)> baseLineResults = new(); - List baseLineIssues = new(); - List<(string TestName, string Outcome, string Storage)> comparedResults = new(); - List comparedIssues = new(); + List baseLineResults = []; + List baseLineIssues = []; + List comparedResults = []; + List comparedIssues = []; await _task.WhenAll( - _task.Run(() => CollectEntriesAndErrors(baselineFilePaths[0], trxNamespace, baseLineResults, baseLineIssues)), - _task.Run(() => CollectEntriesAndErrors(comparedFilePaths[0], trxNamespace, comparedResults, comparedIssues))); + CollectEntriesAndErrorsAsync(baselineFilePaths[0], trxNamespace, baseLineResults, baseLineIssues), + CollectEntriesAndErrorsAsync(comparedFilePaths[0], trxNamespace, comparedResults, comparedIssues)) + .ConfigureAwait(false); StringBuilder outputBuilder = new(); AppendResultsAndIssues("Baseline", baselineFilePaths[0], baseLineResults, baseLineIssues, outputBuilder); @@ -69,33 +72,33 @@ await _task.WhenAll( if (AreMatchingTrxFiles(baseLineResults, comparedResults, outputBuilder)) { - await _outputDisplay.DisplayAsync(this, new TextOutputDeviceData(outputBuilder.ToString())); + await _outputDisplay.DisplayAsync(this, new TextOutputDeviceData(outputBuilder.ToString())).ConfigureAwait(false); return ExitCodes.Success; } else { - await _outputDisplay.DisplayAsync(this, new TextOutputDeviceData(outputBuilder.ToString())); + await _outputDisplay.DisplayAsync(this, new TextOutputDeviceData(outputBuilder.ToString())).ConfigureAwait(false); return ExitCodes.GenericFailure; } } private static bool AreMatchingTrxFiles( - List<(string TestName, string Outcome, string Storage)> baseLineResults, - List<(string TestName, string Outcome, string Storage)> comparedResults, + List baseLineResults, + List comparedResults, StringBuilder outputBuilder) { bool checkFailed = false; outputBuilder.AppendLine("--- Comparing TRX files ---"); - IEnumerable<((string TestName, string Outcome, string Storage), string Source)> trxEntries = + IEnumerable<(Trx, string Source)> trxEntries = baseLineResults.Select(tuple => (tuple, "baseline")) .Concat(comparedResults.Select(tuple => (tuple, "other"))) .OrderBy(x => x.tuple.TestName); - foreach (((string TestName, string Outcome, string Storage) sourceTrx, string entrySource) in trxEntries) + foreach ((Trx sourceTrx, string entrySource) in trxEntries) { string otherSource = entrySource == "baseline" ? "other" : "baseline"; - IEnumerable<(string MatchingTestName, string MatchingOutcome, string MatchingStorage)> matchingEntries = + IEnumerable matchingEntries = entrySource == "baseline" ? comparedResults.Where(x => x.TestName == sourceTrx.TestName) : baseLineResults.Where(x => x.TestName == sourceTrx.TestName); @@ -117,13 +120,13 @@ private static bool AreMatchingTrxFiles( continue; } - (string otherTestName, string otherOutcome, string otherStorage) = matchingEntries.First(); - if (sourceTrx.Outcome != otherOutcome) + Trx otherTrx = matchingEntries.First(); + if (sourceTrx.Outcome != otherTrx.Outcome) { checkFailed = true; outputBuilder.AppendLine( CultureInfo.InvariantCulture, - $" - Test '{sourceTrx.TestName}' has a different outcome. Got '{otherOutcome}', expected '{sourceTrx.Outcome}'"); + $" - Test '{sourceTrx.TestName}' has a different outcome. Got '{otherTrx.Outcome}', expected '{sourceTrx.Outcome}'"); } } @@ -141,7 +144,7 @@ private static bool AreMatchingTrxFiles( } private static void AppendResultsAndIssues(string category, string filePath, - List<(string TestName, string Outcome, string Storage)> results, List issues, StringBuilder outputBuilder) + List results, List issues, StringBuilder outputBuilder) { outputBuilder.AppendLine(CultureInfo.InvariantCulture, $"--- {category} ---"); outputBuilder.AppendLine(CultureInfo.InvariantCulture, $"File '{filePath}'"); @@ -174,9 +177,10 @@ private static void AppendResultsAndIssues(string category, string filePath, outputBuilder.AppendLine(); } - private static void CollectEntriesAndErrors(string trxFile, XNamespace ns, List<(string TestName, string Outcome, string Storage)> results, List issues) + private static async Task CollectEntriesAndErrorsAsync(string trxFile, XNamespace ns, List results, List issues) { - var trxTestRun = XElement.Parse(File.ReadAllText(trxFile)); + using FileStream stream = File.OpenRead(trxFile); + XElement trxTestRun = await XElement.LoadAsync(stream, LoadOptions.None, CancellationToken.None).ConfigureAwait(false); int testResultIndex = 0; foreach (XElement testResult in trxTestRun.Elements(ns + "Results").Elements(ns + "UnitTestResult")) { @@ -202,11 +206,10 @@ private static void CollectEntriesAndErrors(string trxFile, XNamespace ns, List< continue; } - XElement[] matchingUnitTestDefinitions = trxTestRun + XElement[] matchingUnitTestDefinitions = [.. trxTestRun .Elements(ns + "TestDefinitions") .Elements(ns + "UnitTest") - .Where(x => x.Attribute("id")?.Value == testId) - .ToArray(); + .Where(x => x.Attribute("id")?.Value == testId)]; if (matchingUnitTestDefinitions.Length > 1) { issues.Add($"Found more than one entry in 'TestDefinitions.UnitTest' matching the test ID '{testId}'."); @@ -238,7 +241,7 @@ private static void CollectEntriesAndErrors(string trxFile, XNamespace ns, List< continue; } - results.Add((testDefinitionClassName + "." + testResultTestName, testResultOutcome, testDefinitionStorage)); + results.Add(new(testDefinitionClassName + "." + testResultTestName, testResultOutcome, testDefinitionStorage)); } } } diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs index 7999b00d47..7bca22a1ce 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs @@ -40,7 +40,7 @@ internal sealed class TrxReportGenerator : private readonly TrxTestApplicationLifecycleCallbacks? _trxTestApplicationLifecycleCallbacks; private readonly ILogger _logger; private readonly List _tests = []; - private readonly Dictionary> _artifactsByExtension = new(); + private readonly Dictionary> _artifactsByExtension = []; private readonly bool _isEnabled; private DateTimeOffset? _testStartTime; @@ -89,10 +89,10 @@ public TrxReportGenerator( public Type[] DataTypesProduced { get; } = [typeof(SessionFileArtifact)]; /// - public string Uid { get; } = nameof(TrxReportGenerator); + public string Uid => nameof(TrxReportGenerator); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// public string DisplayName { get; } = ExtensionResources.TrxReportGeneratorDisplayName; @@ -179,7 +179,7 @@ await _logger.LogDebugAsync($""" PlatformCommandLineProvider.ServerOption: {_commandLineOptionsService.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey)} CrashDumpCommandLineOptions.CrashDumpOptionName: {_commandLineOptionsService.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName)} TrxReportGeneratorCommandLine.IsTrxReportEnabled: {_commandLineOptionsService.IsOptionSet(TrxReportGeneratorCommandLine.TrxReportOptionName)} -"""); +""").ConfigureAwait(false); } if (!_commandLineOptionsService.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey) && @@ -191,7 +191,7 @@ await _logger.LogDebugAsync($""" try { await _trxTestApplicationLifecycleCallbacks.NamedPipeClient.RequestReplyAsync(new TestAdapterInformationRequest(_testFramework.Uid, _testFramework.Version), cancellationToken) - .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); + .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken) { @@ -220,19 +220,19 @@ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, Cancellatio { if (!_adapterSupportTrxCapability) { - await _outputDisplay.DisplayAsync(this, new WarningMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxReportFrameworkDoesNotSupportTrxReportCapability, _testFramework.DisplayName, _testFramework.Uid))); + await _outputDisplay.DisplayAsync(this, new WarningMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxReportFrameworkDoesNotSupportTrxReportCapability, _testFramework.DisplayName, _testFramework.Uid))).ConfigureAwait(false); } ApplicationStateGuard.Ensure(_testStartTime is not null); int exitCode = _testApplicationProcessExitCode.GetProcessExitCode(); TrxReportEngine trxReportGeneratorEngine = new(_testApplicationModuleInfo, _environment, _commandLineOptionsService, _configuration, - _clock, _tests.ToArray(), _failedTestsCount, _passedTestsCount, _notExecutedTestsCount, _timeoutTestsCount, _artifactsByExtension, - _adapterSupportTrxCapability, _testFramework, _testStartTime.Value, exitCode, cancellationToken); - (string reportFileName, string? warning) = await trxReportGeneratorEngine.GenerateReportAsync(); + _clock, [.. _tests], _failedTestsCount, _passedTestsCount, _notExecutedTestsCount, _timeoutTestsCount, _artifactsByExtension, + _adapterSupportTrxCapability, _testFramework, _testStartTime.Value, exitCode, cancellationToken); + (string reportFileName, string? warning) = await trxReportGeneratorEngine.GenerateReportAsync().ConfigureAwait(false); if (warning is not null) { - await _outputDisplay.DisplayAsync(this, new WarningMessageOutputDeviceData(warning)); + await _outputDisplay.DisplayAsync(this, new WarningMessageOutputDeviceData(warning)).ConfigureAwait(false); } if ( @@ -242,13 +242,13 @@ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, Cancellatio !_commandLineOptionsService.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName)) { // In server mode we report the trx in-process - await _messageBus.PublishAsync(this, new SessionFileArtifact(sessionUid, new FileInfo(reportFileName), ExtensionResources.TrxReportArtifactDisplayName, ExtensionResources.TrxReportArtifactDescription)); + await _messageBus.PublishAsync(this, new SessionFileArtifact(sessionUid, new FileInfo(reportFileName), ExtensionResources.TrxReportArtifactDisplayName, ExtensionResources.TrxReportArtifactDescription)).ConfigureAwait(false); } else { ApplicationStateGuard.Ensure(_trxTestApplicationLifecycleCallbacks is not null); ApplicationStateGuard.Ensure(_trxTestApplicationLifecycleCallbacks.NamedPipeClient is not null); - await _trxTestApplicationLifecycleCallbacks.NamedPipeClient.RequestReplyAsync(new ReportFileNameRequest(reportFileName), cancellationToken); + await _trxTestApplicationLifecycleCallbacks.NamedPipeClient.RequestReplyAsync(new ReportFileNameRequest(reportFileName), cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken) diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs index 903579a21a..ae3a26358a 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs @@ -44,7 +44,7 @@ internal sealed class TrxProcessLifetimeHandler : private readonly IOutputDevice _outputDevice; private readonly ILogger _logger; private readonly PipeNameDescription _pipeNameDescription; - private readonly Dictionary> _fileArtifacts = new(); + private readonly Dictionary> _fileArtifacts = []; private readonly DateTimeOffset _startTime; private NamedPipeServer? _singleConnectionNamedPipeServer; @@ -109,7 +109,7 @@ public Task BeforeTestHostProcessStartAsync(CancellationToken cancellation) _singleConnectionNamedPipeServer.RegisterSerializer(new ReportFileNameRequestSerializer(), typeof(ReportFileNameRequest)); _singleConnectionNamedPipeServer.RegisterSerializer(new TestAdapterInformationRequestSerializer(), typeof(TestAdapterInformationRequest)); _singleConnectionNamedPipeServer.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse)); - await _singleConnectionNamedPipeServer.WaitConnectionAsync(cancellation).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellation); + await _singleConnectionNamedPipeServer.WaitConnectionAsync(cancellation).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellation).ConfigureAwait(false); }, cancellation); return Task.CompletedTask; @@ -122,7 +122,7 @@ public async Task OnTestHostProcessStartedAsync(ITestHostProcessInformation test throw new InvalidOperationException(ExtensionResources.TrxReportGeneratorBeforeTestHostProcessStartAsyncNotCalled); } - await _waitConnectionTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellation); + await _waitConnectionTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellation).ConfigureAwait(false); } public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationToken cancellationToken) @@ -144,7 +144,7 @@ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testH return; } - Dictionary> artifacts = new(); + Dictionary> artifacts = []; foreach (KeyValuePair> prodArtifacts in _fileArtifacts) { @@ -172,10 +172,10 @@ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testH (string fileName, string? warning) = await trxReportGeneratorEngine.GenerateReportAsync( isTestHostCrashed: true, - testHostCrashInfo: $"Test host process pid: {testHostProcessInformation.PID} crashed."); + testHostCrashInfo: $"Test host process pid: {testHostProcessInformation.PID} crashed.").ConfigureAwait(false); if (warning is not null) { - await _outputDevice.DisplayAsync(this, new WarningMessageOutputDeviceData(warning)); + await _outputDevice.DisplayAsync(this, new WarningMessageOutputDeviceData(warning)).ConfigureAwait(false); } await _messageBus.PublishAsync( @@ -183,7 +183,7 @@ await _messageBus.PublishAsync( new FileArtifact( new FileInfo(fileName), ExtensionResources.TrxReportArtifactDisplayName, - ExtensionResources.TrxReportArtifactDescription)); + ExtensionResources.TrxReportArtifactDescription)).ConfigureAwait(false); return; } @@ -206,10 +206,10 @@ await _messageBus.PublishAsync( testHostProcessInformation.ExitCode, cancellation); - await trxReportGeneratorEngine.AddArtifactsAsync(trxFile, artifacts); + await trxReportGeneratorEngine.AddArtifactsAsync(trxFile, artifacts).ConfigureAwait(false); } - await _messageBus.PublishAsync(this, new FileArtifact(trxFile, ExtensionResources.TrxReportArtifactDisplayName, ExtensionResources.TrxReportArtifactDescription)); + await _messageBus.PublishAsync(this, new FileArtifact(trxFile, ExtensionResources.TrxReportArtifactDisplayName, ExtensionResources.TrxReportArtifactDescription)).ConfigureAwait(false); } private Task CallbackAsync(IRequest request) @@ -233,10 +233,10 @@ private Task CallbackAsync(IRequest request) #if NETCOREAPP public async ValueTask DisposeAsync() { - await DisposeHelper.DisposeAsync(_singleConnectionNamedPipeServer); + await DisposeHelper.DisposeAsync(_singleConnectionNamedPipeServer).ConfigureAwait(false); // Dispose the pipe descriptor after the server to ensure the pipe is closed. - _pipeNameDescription?.Dispose(); + _pipeNameDescription.Dispose(); } #else public void Dispose() @@ -244,7 +244,7 @@ public void Dispose() _singleConnectionNamedPipeServer?.Dispose(); // Dispose the pipe descriptor after the server to ensure the pipe is closed. - _pipeNameDescription?.Dispose(); + _pipeNameDescription.Dispose(); } #endif diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs index e58b34329c..c9e81e9b13 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs @@ -148,7 +148,12 @@ public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testAp // create the xml doc var document = new XDocument(new XDeclaration("1.0", "UTF-8", null)); var testRun = new XElement(_namespaceUri + "TestRun"); - testRun.SetAttributeValue("id", Guid.NewGuid()); + if (!Guid.TryParse(_environment.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_TRX_TESTRUN_ID), out Guid testRunId)) + { + testRunId = Guid.NewGuid(); + } + + testRun.SetAttributeValue("id", testRunId); string testRunName = $"{_environment.GetEnvironmentVariable("UserName")}@{_environment.MachineName} {FormatDateTimeForRunName(_clock.UtcNow)}"; testRun.SetAttributeValue("name", testRunName); @@ -177,7 +182,7 @@ public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testAp // NotExecuted is the status for the skipped test. resultSummaryOutcome = isTestHostCrashed || _exitCode != ExitCodes.Success ? "Failed" : resultSummaryOutcome is "Passed" or "NotExecuted" ? "Completed" : resultSummaryOutcome; - await AddResultSummaryAsync(testRun, resultSummaryOutcome, runDeploymentRoot, testHostCrashInfo, _exitCode, isTestHostCrashed); + await AddResultSummaryAsync(testRun, resultSummaryOutcome, runDeploymentRoot, testHostCrashInfo, _exitCode, isTestHostCrashed).ConfigureAwait(false); // will need catch Unauthorized access document.Add(testRun); @@ -198,16 +203,16 @@ public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testAp string outputDirectory = _configuration.GetTestResultDirectory(); // add var for this string finalFileName = Path.Combine(outputDirectory, trxFileName); - bool isFileNameExplicitlyProvidedAndFileExists = isFileNameExplicitlyProvided && _fileSystem.Exists(finalFileName); + bool isFileNameExplicitlyProvidedAndFileExists = isFileNameExplicitlyProvided && _fileSystem.ExistFile(finalFileName); // Note that we need to dispose the IFileStream, not the inner stream. // IFileStream implementations will be responsible to dispose their inner stream. using IFileStream stream = _fileSystem.NewFileStream(finalFileName, isFileNameExplicitlyProvided ? FileMode.Create : FileMode.CreateNew); - await document.SaveAsync(stream.Stream, SaveOptions.None, _cancellationToken); + await document.SaveAsync(stream.Stream, SaveOptions.None, _cancellationToken).ConfigureAwait(false); return isFileNameExplicitlyProvidedAndFileExists ? (finalFileName, string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxFileExistsAndWillBeOverwritten, finalFileName)) : (finalFileName, null); - }); + }).ConfigureAwait(false); private async Task<(string FileName, string? Warning)> RetryWhenIOExceptionAsync(Func> func) { @@ -217,7 +222,7 @@ public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testAp { try { - return await func(); + return await func().ConfigureAwait(false); } catch (IOException) { @@ -254,10 +259,10 @@ public async Task AddArtifactsAsync(FileInfo trxFile, Dictionary> artifacts, XElement collectorDataEntries, string runDeploymentRoot) @@ -276,7 +281,7 @@ private async Task AddArtifactsToCollectionAsync(Dictionary CopyArtifactIntoTrxDirectoryAndReturnHrefValueAsync(FileInfo artifact, string runDeploymentRoot) @@ -368,7 +373,7 @@ private async Task CopyArtifactIntoTrxDirectoryAndReturnHrefValueAsync(F break; } - await CopyFileAsync(artifact, new FileInfo(destination)); + await CopyFileAsync(artifact, new FileInfo(destination)).ConfigureAwait(false); return Path.Combine(_environment.MachineName, Path.GetFileName(destination)); } @@ -393,7 +398,7 @@ private async Task CopyFileAsync(FileInfo origin, FileInfo destination) using FileStream fileStream = File.OpenRead(origin.FullName); using var destinationStream = new FileStream(destination.FullName, FileMode.Create); - await fileStream.CopyToAsync(destinationStream, _cancellationToken); + await fileStream.CopyToAsync(destinationStream, _cancellationToken).ConfigureAwait(false); } private static void AddTestLists(XElement testRun, string uncategorizedTestId) @@ -518,8 +523,7 @@ private void AddResults(string testAppModule, XElement testRun, out XElement tes output.Add(errorInfoElement); } - // add collectorDataEntries details - if (output.HasElements && outcome != "NotExecuted") + if (output.HasElements) { unitTestResult.Add(output); } @@ -555,6 +559,66 @@ private void AddResults(string testAppModule, XElement testRun, out XElement tes unitTest.Add(new XElement("Execution", new XAttribute("id", executionId))); + XElement? properties = null; + XElement? owners = null; + foreach (TestMetadataProperty property in testNode.Properties.OfType()) + { + switch (property.Key) + { + case "Owner": + owners ??= new XElement("Owners", new XElement("Owner", new XAttribute("name", property.Value))); + break; + + case "Priority": + if (int.TryParse(property.Value, out _)) + { + unitTest.SetAttributeValue("priority", property.Value); + } + + break; + + default: + // NOTE: VSTest doesn't produce Properties as of writing this. + // It was historically fixed, but the fix wasn't correct and the fix was reverted and never revisited to be properly fixed. + // Revert PR: https://github.com/microsoft/vstest/pull/15080 + // The original implementation (buggy) was setting "Key" and "Value" as attributes on "Property" element. + // However, Visual Studio will validate the TRX file against vstst.xsd file in + // C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Xml\Schemas\vstst.xsd + // In xsd, "Properties" element is defined as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // So, Key and Value are **elements**, not attributes. + // In MTP, we do the right thing and follow the XSD definition. + properties ??= new XElement("Properties"); + properties.Add(new XElement( + "Property", + new XElement("Key", property.Key), new XElement("Value", property.Value))); + break; + } + } + + if (owners is not null) + { + unitTest.Add(owners); + } + + if (properties is not null) + { + unitTest.Add(properties); + } + var testMethod = new XElement( "TestMethod", new XAttribute("codeBase", testAppModule), @@ -619,7 +683,7 @@ private static string FormatDateTimeForRunName(DateTimeOffset date) => // We use custom format string to make sure that runs are sorted in the same way on all intl machines. // This is both for directory names and for Data Warehouse. - date.ToString("yyyy-MM-dd HH:mm:ss.fff", DateTimeFormatInfo.InvariantInfo); + date.ToString("yyyy-MM-dd HH:mm:ss.fffffff", DateTimeFormatInfo.InvariantInfo); private static string ReplaceInvalidFileNameChars(string fileName) { @@ -653,7 +717,7 @@ private static bool IsReservedFileName(string fileName) => // LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. // Also avoid these names followed by an extension, for example, NUL.tx7. // Windows NT: CLOCK$ is also a reserved device name. - ReservedFileNamesRegex.Match(fileName).Success; + ReservedFileNamesRegex.IsMatch(fileName); private static Guid GuidFromString(string data) { @@ -672,8 +736,7 @@ private static Guid GuidFromString(string data) ArrayPool.Shared.Return(dataBytes); } #else - var sha256 = SHA256.Create(); - byte[] hash = sha256.ComputeHash(Encoding.Unicode.GetBytes(data)); + byte[] hash = SHA256.HashData(Encoding.Unicode.GetBytes(data)); byte[] bytes = new byte[16]; Array.Copy(hash, bytes, 16); return new Guid(bytes); diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs index eb769731a0..7962b07e30 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs @@ -47,7 +47,7 @@ public static void AddTrxReportProvider(this ITestApplicationBuilder builder) serviceProvider.GetService(), serviceProvider.GetLoggerFactory().CreateLogger())); - builder.TestHost.AddTestApplicationLifecycleCallbacks(serviceProvider => + builder.TestHost.AddTestHostApplicationLifetime(serviceProvider => new TrxTestApplicationLifecycleCallbacks( serviceProvider.GetCommandLineOptions(), serviceProvider.GetEnvironment())); @@ -56,7 +56,7 @@ public static void AddTrxReportProvider(this ITestApplicationBuilder builder) builder.CommandLine.AddProvider(() => commandLine); - PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N")); + PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"), new SystemEnvironment()); var compositeLifeTimeHandler = new CompositeExtensionFactory(serviceProvider => { diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs index 33e0e73cff..d1057fcef1 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs @@ -12,7 +12,7 @@ namespace Microsoft.Testing.Extensions.TrxReport.Abstractions; -internal sealed class TrxTestApplicationLifecycleCallbacks : ITestApplicationLifecycleCallbacks, IDisposable +internal sealed class TrxTestApplicationLifecycleCallbacks : ITestHostApplicationLifetime, IDisposable { private readonly bool _isEnabled; private readonly IEnvironment _environment; @@ -34,10 +34,10 @@ public TrxTestApplicationLifecycleCallbacks( public NamedPipeClient? NamedPipeClient { get; private set; } - public string Uid { get; } = nameof(TrxTestApplicationLifecycleCallbacks); + public string Uid => nameof(TrxTestApplicationLifecycleCallbacks); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// public string DisplayName { get; } = ExtensionResources.TrxReportGeneratorDisplayName; @@ -69,7 +69,7 @@ public async Task BeforeRunAsync(CancellationToken cancellationToken) NamedPipeClient.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse)); // Connect to the named pipe server - await NamedPipeClient.ConnectAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); + await NamedPipeClient.ConnectAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken) diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/BannedSymbols.txt index 13daece7e1..6c52641180 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/BannedSymbols.txt @@ -1,5 +1,5 @@ T:System.ArgumentNullException; Use 'ArgumentGuard' class instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs index 4c17f77738..23558ea6ea 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs @@ -18,7 +18,7 @@ public sealed class VSTestBridgeExtensionBaseCapabilities : ITrxReportCapability private const string VSTestProviderSupport = "vstestProvider"; /// - bool ITrxReportCapability.IsSupported { get; } = true; + bool ITrxReportCapability.IsSupported => true; /// /// Gets a value indicating whether a flag indicating whether the trx report capability is enabled. diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs index 261f1e58d5..8affc8e609 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs @@ -57,7 +57,7 @@ public Task ValidateOptionArgumentsAsync(CommandLineOption com RoslynDebug.Assert(commandOption.Name == RunSettingsOptionName); string filePath = arguments[0]; - if (!_fileSystem.Exists(filePath)) + if (!_fileSystem.ExistFile(filePath)) { return ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, ExtensionResources.RunsettingsFileDoesNotExist, filePath)); } diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Configurations/RunSettingsConfigurationProvider.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Configurations/RunSettingsConfigurationProvider.cs index da7ff8d85c..d61233e864 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Configurations/RunSettingsConfigurationProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Configurations/RunSettingsConfigurationProvider.cs @@ -15,16 +15,16 @@ internal sealed class RunSettingsConfigurationProvider(IFileSystem fileSystem) : private string? _runSettingsFileContent; /// - public string Uid { get; } = nameof(RunSettingsConfigurationProvider); + public string Uid => nameof(RunSettingsConfigurationProvider); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// - public string DisplayName { get; } = "VSTest Helpers: runsettings configuration"; + public string DisplayName => "VSTest Helpers: runsettings configuration"; /// - public string Description { get; } = "Configuration source to bridge VSTest xml runsettings configuration into Microsoft Testing Platform configuration model."; + public string Description => "Configuration source to bridge VSTest xml runsettings configuration into Microsoft Testing Platform configuration model."; public int Order => 2; @@ -62,9 +62,9 @@ public async Task BuildAsync(CommandLineParseResult comm { if (commandLineParseResult.TryGetOptionArgumentList(RunSettingsCommandLineOptionsProvider.RunSettingsOptionName, out string[]? runSettingsFilePath)) { - if (_fileSystem.Exists(runSettingsFilePath[0])) + if (_fileSystem.ExistFile(runSettingsFilePath[0])) { - _runSettingsFileContent = await _fileSystem.ReadAllTextAsync(runSettingsFilePath[0]); + _runSettingsFileContent = await _fileSystem.ReadAllTextAsync(runSettingsFilePath[0]).ConfigureAwait(false); } } diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/Condition.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/Condition.cs index 90d9101af0..9c072cdb0f 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/Condition.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/Condition.cs @@ -164,7 +164,7 @@ internal static Condition Parse(string? conditionString) ThrownFormatExceptionForInvalidCondition(conditionString); } - string[] parts = TokenizeFilterConditionString(conditionString).ToArray(); + string[] parts = [.. TokenizeFilterConditionString(conditionString)]; if (parts.Length == 1) { // If only parameter values is passed, create condition with default property name, @@ -193,9 +193,9 @@ internal static Condition Parse(string? conditionString) } [DoesNotReturn] - private static void ThrownFormatExceptionForInvalidCondition(string? conditionString) => throw new FormatException( - string.Format(CultureInfo.CurrentCulture, "Incorrect format for TestCaseFilter {0}. Specify the correct format and try again. Note that the incorrect format can lead to no test getting executed..", - string.Format(CultureInfo.CurrentCulture, "Error: Invalid Condition '{0}'", conditionString))); + private static void ThrownFormatExceptionForInvalidCondition(string? conditionString) => + throw new FormatException( + $"Incorrect format for TestCaseFilter Error: Invalid Condition '{conditionString}'. Specify the correct format and try again. Note that the incorrect format can lead to no test getting executed.."); /// /// Check if condition validates any property in properties. @@ -247,8 +247,7 @@ private bool ValidForContainsOperation(Func? propertyProv "~" => Operation.Contains, "!~" => Operation.NotContains, _ => throw new FormatException( - string.Format(CultureInfo.CurrentCulture, "Incorrect format for TestCaseFilter {0}. Specify the correct format and try again. Note that the incorrect format can lead to no test getting executed..", - string.Format(CultureInfo.CurrentCulture, "Error: Invalid operator '{0}'", operationString))), + $"Incorrect format for TestCaseFilter Error: Invalid operator '{operationString}'. Specify the correct format and try again. Note that the incorrect format can lead to no test getting executed.."), }; /// diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.cs index 7121115b98..49579940eb 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.cs @@ -61,14 +61,9 @@ protected ContextAdapterBase(ICommandLineOptions commandLineOptions, IRunSetting string validPropertiesString = supportedProperties == null ? string.Empty : string.Join(", ", supportedProperties); - string errorMessage = string.Format( - CultureInfo.CurrentCulture, - "No tests matched the filter because it contains one or more properties that are not valid ({0}). Specify filter expression containing valid properties ({1}).", - string.Join(", ", invalidProperties), - validPropertiesString); // For unsupported property don’t throw exception, just log the message. Later it is going to handle properly with TestCaseFilterExpression.MatchTestCase(). - EqtTrace.Info(errorMessage); + EqtTrace.Info($"No tests matched the filter because it contains one or more properties that are not valid ({string.Join(", ", invalidProperties)}). Specify filter expression containing valid properties ({validPropertiesString})."); } return adapterSpecificTestCaseFilter; diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FastFilter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FastFilter.cs index 456384b72c..1a8c3ebdb1 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FastFilter.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FastFilter.cs @@ -21,7 +21,7 @@ internal FastFilter(ImmutableDictionary> filterProperties, (filterOperation != Operation.Equal || (filterOperator != Operator.Or && filterOperator != Operator.None)) && (filterOperation == Operation.NotEqual && (filterOperator == Operator.And || filterOperator == Operator.None) ? true - : throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "An error occurred while creating Fast filter."))); + : throw new ArgumentException("An error occurred while creating Fast filter.")); } internal ImmutableDictionary> FilterProperties { get; } @@ -37,7 +37,7 @@ internal FastFilter(ImmutableDictionary> filterProperties, ? null : FilterProperties.Keys.All(name => properties.Contains(name)) ? null - : FilterProperties.Keys.Where(name => !properties.Contains(name)).ToArray(); + : [.. FilterProperties.Keys.Where(name => !properties.Contains(name))]; internal bool Evaluate(Func propertyValueProvider) { diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpression.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpression.cs index 4f771bfc0f..be6f23da2b 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpression.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpression.cs @@ -136,7 +136,7 @@ private static void ProcessOperator(Stack filterStack, Operato } else if (invalidRight != null) { - invalidProperties = invalidProperties.Concat(invalidRight).ToArray(); + invalidProperties = [.. invalidProperties, .. invalidRight]; } return invalidProperties; diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs index 865ba66023..c0c58665a8 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - using Microsoft.Testing.Extensions.VSTestBridge.Helpers; using Microsoft.Testing.Platform.Capabilities.TestFramework; using Microsoft.Testing.Platform.CommandLine; @@ -140,7 +138,7 @@ public void RecordResult(TestResult testResult) _frameworkHandle?.RecordResult(testResult); // Publish node state change to Microsoft Testing Platform - var testNode = testResult.ToTestNode(_isTrxEnabled, _namedFeatureCapability, _commandLineOptions, _clientInfo); + var testNode = testResult.ToTestNode(_isTrxEnabled, _adapterExtensionBase.UseFullyQualifiedNameAsTestNodeUid, _namedFeatureCapability, _commandLineOptions, _clientInfo); var testNodeChange = new TestNodeUpdateMessage(_session.SessionUid, testNode); _messageBus.PublishAsync(_adapterExtensionBase, testNodeChange).Await(); @@ -159,7 +157,7 @@ public void RecordStart(TestCase testCase) _frameworkHandle?.RecordStart(testCase); // Publish node state change to Microsoft Testing Platform - var testNode = testCase.ToTestNode(_isTrxEnabled, _namedFeatureCapability, _commandLineOptions, _clientInfo); + var testNode = testCase.ToTestNode(_isTrxEnabled, _adapterExtensionBase.UseFullyQualifiedNameAsTestNodeUid, _namedFeatureCapability, _commandLineOptions, _clientInfo); testNode.Properties.Add(InProgressTestNodeStateProperty.CachedInstance); var testNodeChange = new TestNodeUpdateMessage(_session.SessionUid, testNode); @@ -182,7 +180,7 @@ private async Task PublishTestSessionAttachmentsAsync(IEnumerable } var fileArtifact = new SessionFileArtifact(_session.SessionUid, new(attachment.Uri.LocalPath), attachmentSet.DisplayName, attachment.Description); - await _messageBus.PublishAsync(_adapterExtensionBase, fileArtifact); + await _messageBus.PublishAsync(_adapterExtensionBase, fileArtifact).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs index 4a801d1c4d..46a63890ef 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs @@ -34,24 +34,21 @@ internal static class ObjectModelConverters valueType: typeof(string), owner: typeof(TestCase)); - private static readonly TestProperty TestCategoryProperty = TestProperty.Register( - id: "MSTestDiscoverer.TestCategory", - label: "TestCategory", - valueType: typeof(string[]), - owner: typeof(TestCase)); - - private static readonly TestProperty TraitsProperty = TestProperty.Register( - id: "TestObject.Traits", - label: "Traits", - valueType: typeof(KeyValuePair[]), - owner: typeof(TestObject)); + private static readonly Uri ExecutorUri = new(Constants.ExecutorUri); /// /// Converts a VSTest to a Microsoft Testing Platform . /// - public static TestNode ToTestNode(this TestCase testCase, bool isTrxEnabled, INamedFeatureCapability? namedFeatureCapability, ICommandLineOptions commandLineOptions, IClientInfo clientInfo, string? displayNameFromTestResult = null) + public static TestNode ToTestNode( + this TestCase testCase, + bool isTrxEnabled, + bool useFullyQualifiedNameAsUid, + INamedFeatureCapability? namedFeatureCapability, + ICommandLineOptions commandLineOptions, + IClientInfo clientInfo, + string? displayNameFromTestResult = null) { - string testNodeUid = testCase.Id.ToString(); + string testNodeUid = useFullyQualifiedNameAsUid ? testCase.FullyQualifiedName : testCase.Id.ToString(); TestNode testNode = new() { @@ -82,27 +79,33 @@ public static TestNode ToTestNode(this TestCase testCase, bool isTrxEnabled, INa private static void CopyCategoryAndTraits(TestObject testCaseOrResult, TestNode testNode, bool isTrxEnabled) { - // TPv2 is doing some special handling for MSTest... we should probably do the same. - // See https://github.com/microsoft/vstest/blob/main/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs#L66-L70 - if (testCaseOrResult.GetPropertyValue(TestCategoryProperty, defaultValue: null) is string[] mstestCategories) + foreach (KeyValuePair property in testCaseOrResult.GetProperties()) { - if (isTrxEnabled) +#pragma warning disable CS0618 // Type or member is obsolete + if ((property.Key.Attributes & TestPropertyAttributes.Trait) == 0) +#pragma warning restore CS0618 // Type or member is obsolete { - testNode.Properties.Add(new TrxCategoriesProperty(mstestCategories)); + continue; } - foreach (string category in mstestCategories) + if (property.Value is string[] categories) { - testNode.Properties.Add(new TestMetadataProperty(category, string.Empty)); - } - } + if (isTrxEnabled) + { + testNode.Properties.Add(new TrxCategoriesProperty(categories)); + } - if (testCaseOrResult.GetPropertyValue[]>(TraitsProperty, defaultValue: null) is KeyValuePair[] traits && - traits.Length > 0) - { - foreach (KeyValuePair trait in traits) + foreach (string category in categories) + { + testNode.Properties.Add(new TestMetadataProperty(category, string.Empty)); + } + } + else if (property.Value is KeyValuePair[] traits) { - testNode.Properties.Add(new TestMetadataProperty(trait.Key, trait.Value)); + foreach (KeyValuePair trait in traits) + { + testNode.Properties.Add(new TestMetadataProperty(trait.Key, trait.Value)); + } } } } @@ -135,9 +138,15 @@ private static void CopyVSTestProviderProperties(TestNode testNode, TestCase tes /// /// Converts a VSTest to a Microsoft Testing Platform . /// - public static TestNode ToTestNode(this TestResult testResult, bool isTrxEnabled, INamedFeatureCapability? namedFeatureCapability, ICommandLineOptions commandLineOptions, IClientInfo clientInfo) + public static TestNode ToTestNode( + this TestResult testResult, + bool isTrxEnabled, + bool useFullyQualifiedNameAsUid, + INamedFeatureCapability? namedFeatureCapability, + ICommandLineOptions commandLineOptions, + IClientInfo clientInfo) { - var testNode = testResult.TestCase.ToTestNode(isTrxEnabled, namedFeatureCapability, commandLineOptions, clientInfo, testResult.DisplayName); + var testNode = testResult.TestCase.ToTestNode(isTrxEnabled, useFullyQualifiedNameAsUid, namedFeatureCapability, commandLineOptions, clientInfo, testResult.DisplayName); CopyCategoryAndTraits(testResult, testNode, isTrxEnabled); @@ -145,7 +154,10 @@ public static TestNode ToTestNode(this TestResult testResult, bool isTrxEnabled, if (isTrxEnabled) { - testNode.Properties.Add(new TrxExceptionProperty(testResult.ErrorMessage, testResult.ErrorStackTrace)); + if (!RoslynString.IsNullOrEmpty(testResult.ErrorMessage) || !RoslynString.IsNullOrEmpty(testResult.ErrorStackTrace)) + { + testNode.Properties.Add(new TrxExceptionProperty(testResult.ErrorMessage, testResult.ErrorStackTrace)); + } if (TryParseFullyQualifiedType(testResult.TestCase.FullyQualifiedName, out string? fullyQualifiedType)) { @@ -156,7 +168,7 @@ public static TestNode ToTestNode(this TestResult testResult, bool isTrxEnabled, throw new InvalidOperationException("Unable to parse fully qualified type name from test case: " + testResult.TestCase.FullyQualifiedName); } - testNode.Properties.Add(new TrxMessagesProperty(testResult.Messages + testNode.Properties.Add(new TrxMessagesProperty([.. testResult.Messages .Select(msg => msg.Category switch { @@ -164,8 +176,7 @@ public static TestNode ToTestNode(this TestResult testResult, bool isTrxEnabled, string x when x == TestResultMessage.StandardOutCategory => new StandardOutputTrxMessage(msg.Text), string x when x == TestResultMessage.DebugTraceCategory => new DebugOrTraceTrxMessage(msg.Text), _ => new TrxMessage(msg.Text), - }) - .ToArray())); + })])); } testNode.Properties.Add(new TimingProperty(new(testResult.StartTime, testResult.EndTime, testResult.Duration), [])); @@ -264,7 +275,7 @@ internal static void FixUpTestCase(this TestCase testCase, string? testAssemblyP testCase.SetPropertyValue(OriginalExecutorUriProperty, testCase.ExecutorUri); } - testCase.ExecutorUri = new(Constants.ExecutorUri); + testCase.ExecutorUri = ExecutorUri; } private static bool TryGetMethodIdentifierProperty(TestCase testCase, [NotNullWhen(true)] out TestMethodIdentifierProperty? methodIdentifierProperty) diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsAdapter.cs index 912eaa084a..76dc6dc0ab 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsAdapter.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsAdapter.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - using Microsoft.Testing.Extensions.VSTestBridge.CommandLine; using Microsoft.Testing.Extensions.VSTestBridge.Resources; using Microsoft.Testing.Platform; @@ -45,7 +43,7 @@ public RunSettingsAdapter( if (commandLineOptions.TryGetOptionArgumentList(RunSettingsCommandLineOptionsProvider.RunSettingsOptionName, out string[]? fileNames) && fileNames is not null && fileNames.Length == 1 - && fileSystem.Exists(fileNames[0])) + && fileSystem.ExistFile(fileNames[0])) { runSettingsXml = fileSystem.ReadAllText(fileNames[0]); } diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsPatcher.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsPatcher.cs index 85cc81e2e2..7a7dceecd5 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsPatcher.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsPatcher.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - using Microsoft.Testing.Extensions.VSTestBridge.CommandLine; using Microsoft.Testing.Extensions.VSTestBridge.Resources; using Microsoft.Testing.Platform; @@ -49,12 +47,6 @@ private static XDocument PatchSettingsWithDefaults(string? runSettingsXml, bool runSettingsElement.AddFirst(runConfigurationElement); } - if (runConfigurationElement.Element("DisableAppDomain") is null) - { - AddPatchingCommentIfNeeded(runConfigurationElement, ref isPatchingCommentAdded); - runConfigurationElement.Add(new XElement("DisableAppDomain", false)); - } - if (runConfigurationElement.Element("DesignMode") is null) { AddPatchingCommentIfNeeded(runConfigurationElement, ref isPatchingCommentAdded); @@ -107,7 +99,7 @@ private static void PatchTestRunParameters(XDocument runSettingsDocument, IComma runSettingsElement.Add(testRunParametersElement); } - XElement[] testRunParametersNodes = testRunParametersElement.Nodes().OfType().ToArray(); + XElement[] testRunParametersNodes = [.. testRunParametersElement.Nodes().OfType()]; foreach (string testRunParameter in testRunParameters) { string[] parts = testRunParameter.Split(TestRunParameterSeparator, 2); diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs index 2fda4f9620..f3d7226158 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - using Microsoft.Testing.Extensions.VSTestBridge.Helpers; using Microsoft.Testing.Platform.Capabilities.TestFramework; using Microsoft.Testing.Platform.CommandLine; @@ -94,7 +92,7 @@ public void SendTestCase(TestCase discoveredTest) _testCaseDiscoverySink?.SendTestCase(discoveredTest); // Publish node state change to Microsoft Testing Platform - var testNode = discoveredTest.ToTestNode(_isTrxEnabled, _namedFeatureCapability, _commandLineOptions, _clientInfo); + var testNode = discoveredTest.ToTestNode(_isTrxEnabled, _adapterExtension.UseFullyQualifiedNameAsTestNodeUid, _namedFeatureCapability, _commandLineOptions, _clientInfo); testNode.Properties.Add(DiscoveredTestNodeStateProperty.CachedInstance); var testNodeChange = new TestNodeUpdateMessage(_session.SessionUid, testNode); diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Unshipped.txt index 7dc5c58110..a0e14e5ed0 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Unshipped.txt +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Unshipped.txt @@ -1 +1,2 @@ #nullable enable +virtual Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.UseFullyQualifiedNameAsTestNodeUid.get -> bool diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs index 57ae617299..0789698909 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs @@ -52,7 +52,7 @@ protected SynchronizedSingleSessionVSTestBridgedTestFramework(IExtension extensi public sealed override string Version => _extension.Version; /// - public override async Task IsEnabledAsync() => await _extension.IsEnabledAsync(); + public override async Task IsEnabledAsync() => await _extension.IsEnabledAsync().ConfigureAwait(false); /// public sealed override Task CreateTestSessionAsync(CreateTestSessionContext context) @@ -75,7 +75,7 @@ public sealed override async Task CloseTestSessionAsync( _incomingRequestCounter.Signal(); // Wait for remaining request processing - await _incomingRequestCounter.WaitAsync(context.CancellationToken); + await _incomingRequestCounter.WaitAsync(context.CancellationToken).ConfigureAwait(false); _sessionUid = null; return new CloseTestSessionResult { IsSuccess = true }; } @@ -108,7 +108,7 @@ protected virtual void Dispose(bool disposing) /// The cancellation token. protected sealed override Task DiscoverTestsAsync(VSTestDiscoverTestExecutionRequest request, IMessageBus messageBus, CancellationToken cancellationToken) - => ExecuteRequestWithRequestCountGuardAsync(async () => await SynchronizedDiscoverTestsAsync(request, messageBus, cancellationToken)); + => ExecuteRequestWithRequestCountGuardAsync(async () => await SynchronizedDiscoverTestsAsync(request, messageBus, cancellationToken).ConfigureAwait(false)); /// /// Discovers tests asynchronously with handling of concurrency. @@ -127,7 +127,7 @@ protected abstract Task SynchronizedDiscoverTestsAsync(VSTestDiscoverTestExecuti /// The cancellation token. protected sealed override Task RunTestsAsync(VSTestRunTestExecutionRequest request, IMessageBus messageBus, CancellationToken cancellationToken) - => ExecuteRequestWithRequestCountGuardAsync(async () => await SynchronizedRunTestsAsync(request, messageBus, cancellationToken)); + => ExecuteRequestWithRequestCountGuardAsync(async () => await SynchronizedRunTestsAsync(request, messageBus, cancellationToken).ConfigureAwait(false)); /// /// Runs tests asynchronously with handling of concurrency. @@ -150,20 +150,20 @@ protected sealed override Task ExecuteRequestAsync(TestExecutionRequest request, => ExecuteRequestWithRequestCountGuardAsync(async () => { #pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file - string[] testAssemblyPaths = _getTestAssemblies().Select(x => x.Location).ToArray(); + string[] testAssemblyPaths = [.. _getTestAssemblies().Select(x => x.Location)]; #pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file switch (request) { case DiscoverTestExecutionRequest discoverRequest: VSTestDiscoverTestExecutionRequest vstestDiscoverRequest = VSTestDiscoverTestExecutionRequestFactory.CreateRequest(discoverRequest, this, testAssemblyPaths, cancellationToken); - await SynchronizedDiscoverTestsAsync(vstestDiscoverRequest, messageBus, cancellationToken); + await SynchronizedDiscoverTestsAsync(vstestDiscoverRequest, messageBus, cancellationToken).ConfigureAwait(false); break; case RunTestExecutionRequest runRequest: VSTestRunTestExecutionRequest vstestRunRequest = VSTestRunTestExecutionRequestFactory.CreateRequest(runRequest, this, testAssemblyPaths, cancellationToken); - await SynchronizedRunTestsAsync(vstestRunRequest, messageBus, cancellationToken); + await SynchronizedRunTestsAsync(vstestRunRequest, messageBus, cancellationToken).ConfigureAwait(false); break; default: @@ -185,7 +185,7 @@ private async Task ExecuteRequestWithRequestCountGuardAsync(Func asyncFunc try { - await asyncFunc(); + await asyncFunc().ConfigureAwait(false); } finally { diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider .cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider.cs similarity index 94% rename from src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider .cs rename to src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider.cs index b1e9e21a15..72a5fd8152 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider .cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider.cs @@ -38,17 +38,17 @@ public async Task IsEnabledAsync() return false; } - if (!_fileSystem.Exists(runsettings[0])) + if (!_fileSystem.ExistFile(runsettings[0])) { return false; } using IFileStream fileStream = _fileSystem.NewFileStream(runsettings[0], FileMode.Open, FileAccess.Read); #if NETCOREAPP - _runSettings = await XDocument.LoadAsync(fileStream.Stream, LoadOptions.None, CancellationToken.None); + _runSettings = await XDocument.LoadAsync(fileStream.Stream, LoadOptions.None, CancellationToken.None).ConfigureAwait(false); #else using StreamReader streamReader = new(fileStream.Stream); - _runSettings = XDocument.Parse(await streamReader.ReadToEndAsync()); + _runSettings = XDocument.Parse(await streamReader.ReadToEndAsync().ConfigureAwait(false)); #endif return _runSettings.Element("RunSettings")?.Element("RunConfiguration")?.Element("EnvironmentVariables") is not null; } diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs index 28481349d3..b52022ecd0 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - using Microsoft.Testing.Extensions.TrxReport.Abstractions; using Microsoft.Testing.Extensions.VSTestBridge.Helpers; using Microsoft.Testing.Extensions.VSTestBridge.ObjectModel; @@ -14,6 +12,7 @@ using Microsoft.Testing.Platform.Messages; using Microsoft.Testing.Platform.Requests; using Microsoft.Testing.Platform.Services; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; namespace Microsoft.Testing.Extensions.VSTestBridge; @@ -58,6 +57,11 @@ protected VSTestBridgedTestFrameworkBase(IServiceProvider serviceProvider, ITest /// protected internal IServiceProvider ServiceProvider { get; } + /// + /// Gets a value indicating whether the should use instead of . + /// + protected internal virtual bool UseFullyQualifiedNameAsTestNodeUid { get; } + /// /// Gets a value indicating whether the TRX report is enabled. /// @@ -86,7 +90,7 @@ public async Task ExecuteRequestAsync(ExecuteRequestContext context) _ => Task.CompletedTask, }; - await convertedRequest; + await convertedRequest.ConfigureAwait(false); } finally { diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/Microsoft.Testing.Platform.MSBuild.csproj b/src/Platform/Microsoft.Testing.Platform.MSBuild/Microsoft.Testing.Platform.MSBuild.csproj index 3d9603f9a6..57274bc055 100644 --- a/src/Platform/Microsoft.Testing.Platform.MSBuild/Microsoft.Testing.Platform.MSBuild.csproj +++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/Microsoft.Testing.Platform.MSBuild.csproj @@ -1,7 +1,7 @@  $(MicrosoftTestingTargetFrameworks);netstandard2.0 - PLATFORM_MSBUILD + $(DefineConstants);PLATFORM_MSBUILD $(NoWarn);NU5100 @@ -45,9 +45,9 @@ This package provides MSBuild integration of the platform, its extensions and co - - - + + + diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/DotnetMuxerLocator.cs b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/DotnetMuxerLocator.cs index 0b3beddffd..11f1c6910c 100644 --- a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/DotnetMuxerLocator.cs +++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/DotnetMuxerLocator.cs @@ -8,14 +8,22 @@ namespace Microsoft.Testing.Platform.MSBuild.Tasks; internal sealed class DotnetMuxerLocator { + // Mach-O magic numbers from https://en.wikipedia.org/wiki/Mach-O + private const uint MachOMagic32BigEndian = 0xfeedface; // 32-bit big-endian + private const uint MachOMagic64BigEndian = 0xfeedfacf; // 64-bit big-endian + private const uint MachOMagic32LittleEndian = 0xcefaedfe; // 32-bit little-endian + private const uint MachOMagic64LittleEndian = 0xcffaedfe; // 64-bit little-endian + private const uint MachOMagicFatBigEndian = 0xcafebabe; // Multi-architecture big-endian + private readonly string _muxerName; - private readonly Process _currentProcess; private readonly Action _resolutionLog; + private readonly string _currentProcessFileName; internal DotnetMuxerLocator(Action resolutionLog) { _muxerName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet"; - _currentProcess = Process.GetCurrentProcess(); + using var currentProcess = Process.GetCurrentProcess(); + _currentProcessFileName = currentProcess.MainModule!.FileName!; _resolutionLog = resolutionLog; } @@ -52,15 +60,14 @@ public bool TryGetDotnetPathByArchitecture( // If current process is the same as the target architecture we return the current process filename. if (GetCurrentProcessArchitecture() == targetArchitecture) { - string currentProcessFileName = _currentProcess.MainModule!.FileName!; - if (Path.GetFileName(currentProcessFileName) == _muxerName) + if (Path.GetFileName(_currentProcessFileName) == _muxerName) { - muxerPath = currentProcessFileName; + muxerPath = _currentProcessFileName; _resolutionLog($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Target architecture is the same as the current process architecture '{targetArchitecture}', and the current process is a muxer, using that: '{muxerPath}'"); return true; } - _resolutionLog($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Target architecture is the same as the current process architecture '{targetArchitecture}', but the current process is not a muxer: '{currentProcessFileName}'"); + _resolutionLog($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Target architecture is the same as the current process architecture '{targetArchitecture}', but the current process is not a muxer: '{_currentProcessFileName}'"); } // We used similar approach as the runtime resolver. @@ -287,9 +294,7 @@ public bool TryGetDotnetPathByArchitecture( try { - using Stream stream = new FileStream(installLocation, FileMode.Open, FileAccess.Read); - using StreamReader streamReader = new(stream); - string content = streamReader.ReadToEnd().Trim(); + string content = File.ReadAllText(installLocation).Trim(); _resolutionLog($"DotnetHostHelper: '{installLocation}' content '{content}'"); string path = Path.Combine(content, _muxerName); _resolutionLog($"DotnetHostHelper: Muxer resolved using '{installLocation}' in '{path}'"); @@ -411,6 +416,14 @@ public bool TryGetDotnetPathByArchitecture( #pragma warning restore CA2022 // Avoid inexact read with 'Stream.Read' uint magic = BitConverter.ToUInt32(magicBytes, 0); + + // Validate magic bytes to ensure this is a valid Mach-O binary + if (magic is not (MachOMagic32BigEndian or MachOMagic64BigEndian or MachOMagic32LittleEndian or MachOMagic64LittleEndian or MachOMagicFatBigEndian)) + { + _resolutionLog($"DotnetHostHelper.GetMuxerArchitectureByMachoOnMac: Invalid Mach-O magic bytes: 0x{magic:X8}"); + return null; + } + uint cpuInfo = BitConverter.ToUInt32(cpuInfoBytes, 0); PlatformArchitecture? architecture = (MacOsCpuType)cpuInfo switch { diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/FailedTestHelper.cs b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/FailedTestHelper.cs index 0c6e51a65f..138f407108 100644 --- a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/FailedTestHelper.cs +++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/FailedTestHelper.cs @@ -71,17 +71,16 @@ internal static void FromFailedTest(this FailedTestInfoRequest failedTestInfoReq string nameAndPlace = place == null ? $"{failedTestInfoRequest.DisplayName} ({failedTestInfoRequest.Duration})" : $"{failedTestInfoRequest.DisplayName} ({failedTestInfoRequest.Duration}): {place}"; - string? singleLineError = JoinSingleLineAndShorten(nameAndPlace, failedTestInfoRequest.ErrorMessage); - message = singleLineError!; + message = JoinSingleLineAndShorten(nameAndPlace, failedTestInfoRequest.ErrorMessage); } } - private static string? JoinSingleLineAndShorten(string first, string? second) + private static string JoinSingleLineAndShorten(string first, string? second) => second == null ? SingleLineAndShorten(first) : SingleLineAndShorten(first) + " " + SingleLineAndShorten(second); - private static string? SingleLineAndShorten(string? text) - => text == null ? null : (text.Length <= 1000 ? text : text[..1000]).Replace('\r', ' ').Replace('\n', ' '); + private static string SingleLineAndShorten(string text) => + (text.Length <= 1000 ? text : text[..1000]).Replace('\r', ' ').Replace('\n', ' '); } diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs index ed0cbe17ec..7f75710fe4 100644 --- a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs +++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs @@ -32,7 +32,7 @@ public class InvokeTestingPlatformTask : Build.Utilities.ToolTask, IDisposable private readonly IFileSystem _fileSystem; private readonly PipeNameDescription _pipeNameDescription; private readonly CancellationTokenSource _waitForConnections = new(); - private readonly List _connections = new(); + private readonly List _connections = []; private readonly StringBuilder _output = new(); private readonly Lock _initLock = new(); private readonly Architecture _currentProcessArchitecture = RuntimeInformation.ProcessArchitecture; @@ -54,7 +54,7 @@ public InvokeTestingPlatformTask() Debugger.Launch(); } - _pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N")); + _pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"), new SystemEnvironment()); } internal InvokeTestingPlatformTask(IFileSystem fileSystem) => _fileSystem = fileSystem; @@ -207,7 +207,7 @@ protected override string ToolName } Log.LogMessage(MessageImportance.Low, $"Current process architecture '{_currentProcessArchitecture}'. Requested test architecture '{TestArchitecture.ItemSpec}'"); - PlatformArchitecture targetArchitecture = EnumPolyfill.Parse(TestArchitecture.ItemSpec, ignoreCase: true); + PlatformArchitecture targetArchitecture = Enum.Parse(TestArchitecture.ItemSpec, ignoreCase: true); StringBuilder resolutionLog = new(); DotnetMuxerLocator dotnetMuxerLocator = new(log => resolutionLog.AppendLine(log)); if (dotnetMuxerLocator.TryGetDotnetPathByArchitecture(targetArchitecture, out string? dotnetPath)) @@ -241,7 +241,7 @@ protected override string ToolName } private bool IsCurrentProcessArchitectureCompatible() => - _currentProcessArchitecture == EnumPolyfill.Parse(TestArchitecture.ItemSpec, ignoreCase: true); + _currentProcessArchitecture == Enum.Parse(TestArchitecture.ItemSpec, ignoreCase: true); private string? TryGetRunCommand() { @@ -352,7 +352,7 @@ protected override void ProcessStarted() pipeServer.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse)); pipeServer.RegisterSerializer(new FailedTestInfoRequestSerializer(), typeof(FailedTestInfoRequest)); pipeServer.RegisterSerializer(new RunSummaryInfoRequestSerializer(), typeof(RunSummaryInfoRequest)); - await pipeServer.WaitConnectionAsync(_waitForConnections.Token); + await pipeServer.WaitConnectionAsync(_waitForConnections.Token).ConfigureAwait(false); _connections.Add(pipeServer); Log.LogMessage(MessageImportance.Low, $"Client connected to '{_pipeNameDescription.Name}'"); } @@ -433,6 +433,10 @@ protected override bool HandleTaskExecutionErrors() private Task HandleRequestAsync(IRequest request) { + // For the case, of orchestrator (e.g, Retry), we can get ModuleInfoRequest from the orchestrator itself. + // If there is no orchestrator or the orchestrator didn't send ModuleInfoRequest, we will get it from the first test host. + // For the case of retry, the request is different between the orchestrator and the test host. + // More specifically, the results directory is different (orchestrator points to original, while test host points to the specific retry results directory). if (request is ModuleInfoRequest moduleInfo) { if (_moduleInfo is null) diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/TestingPlatformAutoRegisteredExtensions.cs b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/TestingPlatformAutoRegisteredExtensions.cs index 818749ffad..f1d1018d35 100644 --- a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/TestingPlatformAutoRegisteredExtensions.cs +++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/TestingPlatformAutoRegisteredExtensions.cs @@ -156,7 +156,7 @@ private static ITaskItem[] Reorder(ITaskItem[] items) result.Add(items[wellKnownBuilderHook_MicrosoftTestingPlatformExtensions_index]); } - return result.ToArray(); + return [.. result]; } private static void GenerateCode(string language, string? rootNamespace, ITaskItem[] taskItems, ITaskItem testingPlatformEntryPointSourcePath, IFileSystem fileSystem, TaskLoggingHelper taskLoggingHelper) diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/buildMultiTargeting/Microsoft.Testing.Platform.MSBuild.targets b/src/Platform/Microsoft.Testing.Platform.MSBuild/buildMultiTargeting/Microsoft.Testing.Platform.MSBuild.targets index 882b0396c6..04b28bc764 100644 --- a/src/Platform/Microsoft.Testing.Platform.MSBuild/buildMultiTargeting/Microsoft.Testing.Platform.MSBuild.targets +++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/buildMultiTargeting/Microsoft.Testing.Platform.MSBuild.targets @@ -4,7 +4,7 @@ - $(MSBuildThisFileDirectory)..\_MSBuildTasks\netstandard2.0\ + $(MSBuildThisFileDirectory)..\_MSBuildTasks\netstandard2.0\ diff --git a/src/Platform/Microsoft.Testing.Platform/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Platform/BannedSymbols.txt index dde632bded..96906f3552 100644 --- a/src/Platform/Microsoft.Testing.Platform/BannedSymbols.txt +++ b/src/Platform/Microsoft.Testing.Platform/BannedSymbols.txt @@ -7,5 +7,5 @@ M:System.Diagnostics.Process.GetCurrentProcess(); Use 'IProcess' instead M:System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo); Use 'IProcess' instead M:System.String.IsNullOrEmpty(System.String); Use 'RoslynString.IsNullOrEmpty' instead M:System.String.IsNullOrWhiteSpace(System.String); Use 'RoslynString.IsNullOrWhiteSpace' instead -M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead +M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'RoslynDebug.Assert' instead M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'RoslynDebug.Assert' instead diff --git a/src/Platform/Microsoft.Testing.Platform/Builder/ITestApplicationBuilder.cs b/src/Platform/Microsoft.Testing.Platform/Builder/ITestApplicationBuilder.cs index 7309a14589..d17fca33e1 100644 --- a/src/Platform/Microsoft.Testing.Platform/Builder/ITestApplicationBuilder.cs +++ b/src/Platform/Microsoft.Testing.Platform/Builder/ITestApplicationBuilder.cs @@ -47,11 +47,11 @@ public interface ITestApplicationBuilder /// Registers a test framework with the application builder. /// /// The factory method for creating test framework capabilities. - /// The factory method for creating a test framework adapter. + /// The factory method for creating a test framework adapter. /// The updated test application builder. ITestApplicationBuilder RegisterTestFramework( Func capabilitiesFactory, - Func adapterFactory); + Func frameworkFactory); /// /// Builds the test application asynchronously. diff --git a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs index b1cd776b62..fc8c2870ef 100644 --- a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs +++ b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs @@ -21,8 +21,7 @@ public sealed class TestApplication : ITestApplication #pragma warning restore SA1001 // Commas should be spaced correctly #endif { - private readonly ITestHost _testHost; - private static int s_numberOfBuilders; + private readonly IHost _host; private static UnhandledExceptionHandler? s_unhandledExceptionHandler; static TestApplication() => @@ -30,11 +29,11 @@ static TestApplication() => // This is important for the console display system to work properly. _ = new SystemConsole(); - internal TestApplication(ITestHost testHost) => _testHost = testHost; + internal TestApplication(IHost host) => _host = host; - internal IServiceProvider ServiceProvider => ((CommonTestHost)_testHost).ServiceProvider; - - internal static int MaxNumberOfBuilders { get; set; } = int.MaxValue; + // This cast looks like incorrect assumption. + // This property is currently accessed in unit tests only. + internal IServiceProvider ServiceProvider => ((CommonHost)_host).ServiceProvider; /// /// Creates a server mode builder asynchronously. @@ -47,10 +46,10 @@ public static Task CreateServerModeBuilderAsync(string[ if (args.Contains($"--{PlatformCommandLineProvider.ServerOptionKey}") || args.Contains($"-{PlatformCommandLineProvider.ServerOptionKey}")) { // Remove the --server option from the args so that the builder can be created. - args = args.Where(arg => arg.Trim('-') != PlatformCommandLineProvider.ServerOptionKey).ToArray(); + args = [.. args.Where(arg => arg.Trim('-') != PlatformCommandLineProvider.ServerOptionKey)]; } - return CreateBuilderAsync(args.Append($"--{PlatformCommandLineProvider.ServerOptionKey}").ToArray(), testApplicationOptions); + return CreateBuilderAsync([.. args, $"--{PlatformCommandLineProvider.ServerOptionKey}"], testApplicationOptions); } /// @@ -93,7 +92,7 @@ public static async Task CreateBuilderAsync(string[] ar { ILogger logger = loggingState.FileLoggerProvider.CreateLogger(typeof(TestApplication).ToString()); s_unhandledExceptionHandler.SetLogger(logger); - await LogInformationAsync(logger, testApplicationModuleInfo, testHostControllerInfo, systemProcess, systemEnvironment, createBuilderEntryTime, loggingState.IsSynchronousWrite, loggingState.LogLevel, args); + await LogInformationAsync(logger, testApplicationModuleInfo, testHostControllerInfo, systemEnvironment, createBuilderEntryTime, loggingState.IsSynchronousWrite, loggingState.LogLevel, args).ConfigureAwait(false); } // All checks are fine, create the TestApplication. @@ -104,7 +103,6 @@ private static async Task LogInformationAsync( ILogger logger, CurrentTestApplicationModuleInfo testApplicationModuleInfo, TestHostControllerInfo testHostControllerInfo, - SystemProcessHandler processHandler, SystemEnvironment environment, string createBuilderEntryTime, bool syncWrite, @@ -115,25 +113,24 @@ private static async Task LogInformationAsync( AssemblyInformationalVersionAttribute? version = Assembly.GetExecutingAssembly().GetCustomAttribute(); if (version is not null) { - await logger.LogInformationAsync($"Version: {version.InformationalVersion}"); + await logger.LogInformationAsync($"Version: {version.InformationalVersion}").ConfigureAwait(false); } else { - await logger.LogInformationAsync("Version attribute not found"); + await logger.LogInformationAsync("Version attribute not found").ConfigureAwait(false); } - await logger.LogInformationAsync("Logging mode: " + (syncWrite ? "synchronous" : "asynchronous")); - await logger.LogInformationAsync($"Logging level: {loggerLevel}"); - await logger.LogInformationAsync($"CreateBuilderAsync entry time: {createBuilderEntryTime}"); - using IProcess currentProcess = processHandler.GetCurrentProcess(); - await logger.LogInformationAsync($"PID: {currentProcess.Id}"); + await logger.LogInformationAsync("Logging mode: " + (syncWrite ? "synchronous" : "asynchronous")).ConfigureAwait(false); + await logger.LogInformationAsync($"Logging level: {loggerLevel}").ConfigureAwait(false); + await logger.LogInformationAsync($"CreateBuilderAsync entry time: {createBuilderEntryTime}").ConfigureAwait(false); + await logger.LogInformationAsync($"PID: {environment.ProcessId}").ConfigureAwait(false); #if NETCOREAPP string runtimeInformation = $"{RuntimeInformation.RuntimeIdentifier} - {RuntimeInformation.FrameworkDescription}"; #else string runtimeInformation = $"{RuntimeInformation.ProcessArchitecture} - {RuntimeInformation.FrameworkDescription}"; #endif - await logger.LogInformationAsync($"Runtime information: {runtimeInformation}"); + await logger.LogInformationAsync($"Runtime information: {runtimeInformation}").ConfigureAwait(false); #if NETCOREAPP if (RuntimeFeature.IsDynamicCodeSupported) @@ -143,11 +140,11 @@ private static async Task LogInformationAsync( #pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file if (runtimeLocation is not null) { - await logger.LogInformationAsync($"Runtime location: {runtimeLocation}"); + await logger.LogInformationAsync($"Runtime location: {runtimeLocation}").ConfigureAwait(false); } else { - await logger.LogInformationAsync("Runtime location not found."); + await logger.LogInformationAsync("Runtime location not found.").ConfigureAwait(false); } } #else @@ -156,11 +153,11 @@ private static async Task LogInformationAsync( #pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file if (runtimeLocation is not null) { - await logger.LogInformationAsync($"Runtime location: {runtimeLocation}"); + await logger.LogInformationAsync($"Runtime location: {runtimeLocation}").ConfigureAwait(false); } else { - await logger.LogInformationAsync($"Runtime location not found."); + await logger.LogInformationAsync($"Runtime location not found.").ConfigureAwait(false); } #endif @@ -168,11 +165,11 @@ private static async Task LogInformationAsync( #if NETCOREAPP isDynamicCodeSupported = RuntimeFeature.IsDynamicCodeSupported; #endif - await logger.LogInformationAsync($"IsDynamicCodeSupported: {isDynamicCodeSupported}"); + await logger.LogInformationAsync($"IsDynamicCodeSupported: {isDynamicCodeSupported}").ConfigureAwait(false); string moduleName = testApplicationModuleInfo.GetDisplayName(); - await logger.LogInformationAsync($"Test module: {moduleName}"); - await logger.LogInformationAsync($"Command line arguments: '{(args.Length == 0 ? string.Empty : args.Aggregate((a, b) => $"{a} {b}"))}'"); + await logger.LogInformationAsync($"Test module: {moduleName}").ConfigureAwait(false); + await logger.LogInformationAsync($"Command line arguments: '{(args.Length == 0 ? string.Empty : args.Aggregate((a, b) => $"{a} {b}"))}'").ConfigureAwait(false); StringBuilder machineInfo = new(); #pragma warning disable RS0030 // Do not use banned APIs @@ -184,15 +181,15 @@ private static async Task LogInformationAsync( #if NETCOREAPP machineInfo.AppendLine(CultureInfo.InvariantCulture, $"TotalAvailableMemoryBytes(GB): {GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 1_000_000_000}"); #endif - await logger.LogDebugAsync($"Machine info:\n{machineInfo}"); + await logger.LogDebugAsync($"Machine info:\n{machineInfo}").ConfigureAwait(false); if (testHostControllerInfo.HasTestHostController) { int? testHostControllerPID = testHostControllerInfo.GetTestHostControllerPID(); - await LogVariableAsync(EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_CORRELATIONID); - await LogVariableAsync(EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_PARENTPID); - await LogVariableAsync(EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_TESTHOSTPROCESSSTARTTIME); + await LogVariableAsync(EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_CORRELATIONID).ConfigureAwait(false); + await LogVariableAsync(EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_PARENTPID).ConfigureAwait(false); + await LogVariableAsync(EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_TESTHOSTPROCESSSTARTTIME).ConfigureAwait(false); async Task LogVariableAsync(string key) { @@ -200,32 +197,29 @@ async Task LogVariableAsync(string key) key = $"{key}_{testHostControllerPID}"; if ((value = environment.GetEnvironmentVariable(key)) is not null) { - await logger.LogDebugAsync($"{key} '{value}'"); + await logger.LogDebugAsync($"{key} '{value}'").ConfigureAwait(false); } } } - await logger.LogInformationAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_DEFAULT_HANG_TIMEOUT}: '{environment.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_DEFAULT_HANG_TIMEOUT)}'"); + await logger.LogInformationAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_DEFAULT_HANG_TIMEOUT}: '{environment.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_DEFAULT_HANG_TIMEOUT)}'").ConfigureAwait(false); } - internal static void ReleaseBuilder() - => Interlocked.Decrement(ref s_numberOfBuilders); - /// public void Dispose() - => (_testHost as IDisposable)?.Dispose(); + => (_host as IDisposable)?.Dispose(); #if NETCOREAPP /// public ValueTask DisposeAsync() - => _testHost is IAsyncDisposable asyncDisposable + => _host is IAsyncDisposable asyncDisposable ? asyncDisposable.DisposeAsync() : ValueTask.CompletedTask; #endif /// public async Task RunAsync() - => await _testHost.RunAsync(); + => await _host.RunAsync().ConfigureAwait(false); private static void AttachDebuggerIfNeeded(SystemEnvironment environment, SystemConsole console, SystemProcessHandler systemProcess) { @@ -236,8 +230,8 @@ private static void AttachDebuggerIfNeeded(SystemEnvironment environment, System if (environment.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_WAIT_ATTACH_DEBUGGER) == "1") { - IProcess currentProcess = systemProcess.GetCurrentProcess(); - console.WriteLine($"Waiting for debugger to attach... Process Id: {currentProcess.Id}, Name: {currentProcess.Name}"); + using IProcess currentProcess = systemProcess.GetCurrentProcess(); + console.WriteLine($"Waiting for debugger to attach... Process Id: {environment.ProcessId}, Name: {currentProcess.Name}"); while (!Debugger.IsAttached) { @@ -286,7 +280,7 @@ private static ApplicationLoggingState CreateFileLoggerIfDiagnosticIsEnabled( if (result.TryGetOptionArgumentList(PlatformCommandLineProvider.DiagnosticVerbosityOptionKey, out string[]? verbosity)) { - logLevel = EnumPolyfill.Parse(verbosity[0], true); + logLevel = Enum.Parse(verbosity[0], true); } // Override the log level if the environment variable is set diff --git a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs index ee07ce0ba1..1a5214b4ea 100644 --- a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs +++ b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs @@ -11,7 +11,6 @@ using Microsoft.Testing.Platform.Hosts; using Microsoft.Testing.Platform.Logging; using Microsoft.Testing.Platform.Resources; -using Microsoft.Testing.Platform.ServerMode; using Microsoft.Testing.Platform.Services; using Microsoft.Testing.Platform.Telemetry; using Microsoft.Testing.Platform.TestHost; @@ -30,7 +29,7 @@ internal sealed class TestApplicationBuilder : ITestApplicationBuilder private readonly TestApplicationOptions _testApplicationOptions; private readonly IUnhandledExceptionsHandler _unhandledExceptionsHandler; private readonly TestHostBuilder _testHostBuilder; - private ITestHost? _testHost; + private IHost? _host; private Func? _testFrameworkFactory; private Func? _testFrameworkCapabilitiesFactory; @@ -53,8 +52,6 @@ internal TestApplicationBuilder( public ICommandLineManager CommandLine => _testHostBuilder.CommandLine; - internal IServerModeManager ServerMode => _testHostBuilder.ServerMode; - internal ITestHostOrchestratorManager TestHostOrchestrator => _testHostBuilder.TestHostOrchestratorManager; [Obsolete("Remove in v2. Avoid breaking change with the rename of the property. See https://github.com/microsoft/testfx/issues/5015", error: true)] @@ -75,9 +72,9 @@ internal TestApplicationBuilder( public ITestApplicationBuilder RegisterTestFramework( Func capabilitiesFactory, - Func adapterFactory) + Func frameworkFactory) { - Guard.NotNull(adapterFactory); + Guard.NotNull(frameworkFactory); Guard.NotNull(capabilitiesFactory); if (_testFrameworkFactory is not null) @@ -85,7 +82,7 @@ public ITestApplicationBuilder RegisterTestFramework( throw new InvalidOperationException(PlatformResources.TestApplicationBuilderFrameworkAdapterFactoryAlreadyRegisteredErrorMessage); } - _testFrameworkFactory = adapterFactory; + _testFrameworkFactory = frameworkFactory; if (_testFrameworkCapabilitiesFactory is not null) { @@ -107,13 +104,13 @@ public async Task BuildAsync() throw new InvalidOperationException(PlatformResources.TestApplicationBuilderTestFrameworkNotRegistered); } - if (_testHost is not null) + if (_host is not null) { throw new InvalidOperationException(PlatformResources.TestApplicationBuilderApplicationAlreadyRegistered); } - _testHost = await _testHostBuilder.BuildAsync(_loggingState, _testApplicationOptions, _unhandledExceptionsHandler, _createBuilderStart); + _host = await _testHostBuilder.BuildAsync(_loggingState, _testApplicationOptions, _unhandledExceptionsHandler, _createBuilderStart).ConfigureAwait(false); - return new TestApplication(_testHost); + return new TestApplication(_host); } } diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineHandler.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineHandler.cs index 1f6a1e0365..c8a9f3c128 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineHandler.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineHandler.cs @@ -49,10 +49,10 @@ public CommandLineHandler(CommandLineParseResult parseResult, IReadOnlyCollectio public async Task PrintInfoAsync(IOutputDevice outputDevice, IReadOnlyList? availableTools = null) { // /!\ Info should not be localized as it serves debugging purposes. - await DisplayPlatformInfoAsync(); - await outputDevice.DisplayAsync(this, EmptyText); - await DisplayBuiltInExtensionsInfoAsync(outputDevice); - await outputDevice.DisplayAsync(this, EmptyText); + await DisplayPlatformInfoAsync().ConfigureAwait(false); + await outputDevice.DisplayAsync(this, EmptyText).ConfigureAwait(false); + await DisplayBuiltInExtensionsInfoAsync(outputDevice).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, EmptyText).ConfigureAwait(false); List toolExtensions = []; List nonToolExtensions = []; @@ -68,24 +68,24 @@ public async Task PrintInfoAsync(IOutputDevice outputDevice, IReadOnlyList(); string versionInfo = version?.InformationalVersion ?? "Not Available"; - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Version: {versionInfo}")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Version: {versionInfo}")).ConfigureAwait(false); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Dynamic Code Supported: {_runtimeFeature.IsDynamicCodeSupported}")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Dynamic Code Supported: {_runtimeFeature.IsDynamicCodeSupported}")).ConfigureAwait(false); // TODO: Replace RuntimeInformation with IRuntimeInformation #if NETCOREAPP @@ -93,17 +93,17 @@ async Task DisplayPlatformInfoAsync() #else string runtimeInformation = $"{RuntimeInformation.FrameworkDescription}"; #endif - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Runtime information: {runtimeInformation}")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Runtime information: {runtimeInformation}")).ConfigureAwait(false); #if !NETCOREAPP #pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file, this branch run only in .NET Framework string runtimeLocation = typeof(object).Assembly?.Location ?? "Not Found"; #pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Runtime location: {runtimeLocation}")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Runtime location: {runtimeLocation}")).ConfigureAwait(false); #endif string moduleName = _testApplicationModuleInfo.GetDisplayName(); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Test module: {moduleName}")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Test module: {moduleName}")).ConfigureAwait(false); } async Task DisplayOptionsAsync(IOutputDevice outputDevice, IEnumerable options, int indentLevel) @@ -112,19 +112,19 @@ async Task DisplayOptionsAsync(IOutputDevice outputDevice, IEnumerable x.Name)) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($"{optionNameIndent}--{option.Name}")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($"{optionNameIndent}--{option.Name}")).ConfigureAwait(false); if (option.Arity.Min == option.Arity.Max) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($"{optionInfoIndent}Arity: {option.Arity.Min}")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($"{optionInfoIndent}Arity: {option.Arity.Min}")).ConfigureAwait(false); } else { string maxArityValue = option.Arity.Max == int.MaxValue ? "N" : $"{option.Arity.Max}"; - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($"{optionInfoIndent}Arity: {option.Arity.Min}..{maxArityValue}")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($"{optionInfoIndent}Arity: {option.Arity.Min}..{maxArityValue}")).ConfigureAwait(false); } - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($"{optionInfoIndent}Hidden: {option.IsHidden}")); - await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"Description: {option.Description}") { Padding = optionInfoIndent.Length }); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($"{optionInfoIndent}Hidden: {option.IsHidden}")).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"Description: {option.Description}") { Padding = optionInfoIndent.Length }).ConfigureAwait(false); } } @@ -140,69 +140,69 @@ async Task DisplayProvidersAsync(IOutputDevice outputDevice, IEnumerable nonToolExtensions) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData("Registered command line providers:")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData("Registered command line providers:")).ConfigureAwait(false); if (nonToolExtensions.Count == 0) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(" There are no registered command line providers.")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(" There are no registered command line providers.")).ConfigureAwait(false); } else { - await DisplayProvidersAsync(outputDevice, nonToolExtensions, 1); + await DisplayProvidersAsync(outputDevice, nonToolExtensions, 1).ConfigureAwait(false); } } async Task DisplayRegisteredToolsInfoAsync(IOutputDevice outputDevice, IReadOnlyList? availableTools, List toolExtensions) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData("Registered tools:")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData("Registered tools:")).ConfigureAwait(false); if (availableTools is null || availableTools.Count == 0) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(" There are no registered tools.")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(" There are no registered tools.")).ConfigureAwait(false); } else { var groupedToolExtensions = toolExtensions.GroupBy(x => x.ToolName).ToDictionary(x => x.Key, x => x.ToList()); foreach (ITool tool in availableTools.OrderBy(x => x.Uid)) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" {tool.Uid}")); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Command: {tool.Name}")); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Name: {tool.DisplayName}")); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Version: {tool.Version}")); - await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"Description: {tool.Description}") { Padding = 4 }); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(" Tool command line providers:")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" {tool.Uid}")).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Command: {tool.Name}")).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Name: {tool.DisplayName}")).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData($" Version: {tool.Version}")).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"Description: {tool.Description}") { Padding = 4 }).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(" Tool command line providers:")).ConfigureAwait(false); if (groupedToolExtensions.TryGetValue(tool.Name, out List? providers)) { - await DisplayProvidersAsync(outputDevice, providers, 3); + await DisplayProvidersAsync(outputDevice, providers, 3).ConfigureAwait(false); } else { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(" There are no registered command line providers.")); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(" There are no registered command line providers.")).ConfigureAwait(false); } } } @@ -212,11 +212,8 @@ async Task DisplayRegisteredToolsInfoAsync(IOutputDevice outputDevice, IReadOnly public bool IsOptionSet(string optionName) => ParseResult.IsOptionSet(optionName); - public bool TryGetOptionArgumentList(string optionName, [NotNullWhen(true)] out string[]? arguments) - { - arguments = null; - return ParseResult is not null && ParseResult.TryGetOptionArgumentList(optionName, out arguments); - } + public bool TryGetOptionArgumentList(string optionName, [NotNullWhen(true)] out string[]? arguments) => + ParseResult.TryGetOptionArgumentList(optionName, out arguments); public Task IsEnabledAsync() => Task.FromResult(false); @@ -231,11 +228,11 @@ public async Task PrintHelpAsync(IOutputDevice outputDevice, IReadOnlyList PrintOptionsAsync(IEnumerable optionProviders, bool builtInOnly = false) { CommandLineOption[] options = - optionProviders + [.. optionProviders .SelectMany(provider => provider.GetCommandLineOptions()) .Where(option => !option.IsHidden && option.IsBuiltIn == builtInOnly) - .OrderBy(option => option.Name) - .ToArray(); + .OrderBy(option => option.Name)]; if (options.Length == 0) { @@ -261,9 +257,9 @@ async Task PrintOptionsAsync(IEnumerable opti foreach (CommandLineOption? option in options) { - await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"--{option.Name}") { Padding = 4 }); - await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData(option.Description) { Padding = 8 }); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(string.Empty)); + await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"--{option.Name}") { Padding = 4 }).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData(option.Description) { Padding = 8 }).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(string.Empty)).ConfigureAwait(false); } return options.Length != 0; @@ -271,31 +267,29 @@ async Task PrintOptionsAsync(IEnumerable opti async Task PrintApplicationUsageAsync(string applicationName) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.HelpApplicationUsage, applicationName))); - await outputDevice.DisplayAsync(this, EmptyText); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.HelpExecuteTestApplication)); - await outputDevice.DisplayAsync(this, EmptyText); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.HelpApplicationUsage, applicationName))).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, EmptyText).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.HelpExecuteTestApplication)).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, EmptyText).ConfigureAwait(false); RoslynDebug.Assert( !SystemCommandLineOptionsProviders.OfType().Any(), "System command line options should not have any tool option registered."); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.HelpOptions)); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.HelpOptions)).ConfigureAwait(false); ICommandLineOptionsProvider[] nonToolsExtensionProviders = - ExtensionsCommandLineOptionsProviders - .Where(provider => provider is not IToolCommandLineOptionsProvider) - .ToArray(); + [.. ExtensionsCommandLineOptionsProviders.Where(provider => provider is not IToolCommandLineOptionsProvider)]; // By default, only system options are built-in but some extensions (e.g. retry) are considered as built-in too, // so we need to union the 2 collections before printing the options. - await PrintOptionsAsync(SystemCommandLineOptionsProviders.Union(nonToolsExtensionProviders), builtInOnly: true); - await outputDevice.DisplayAsync(this, EmptyText); + await PrintOptionsAsync(SystemCommandLineOptionsProviders.Union(nonToolsExtensionProviders), builtInOnly: true).ConfigureAwait(false); + await outputDevice.DisplayAsync(this, EmptyText).ConfigureAwait(false); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.HelpExtensionOptions)); - if (!await PrintOptionsAsync(nonToolsExtensionProviders)) + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.HelpExtensionOptions)).ConfigureAwait(false); + if (!await PrintOptionsAsync(nonToolsExtensionProviders).ConfigureAwait(false)) { - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.HelpNoExtensionRegistered)); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.HelpNoExtensionRegistered)).ConfigureAwait(false); } - await outputDevice.DisplayAsync(this, EmptyText); + await outputDevice.DisplayAsync(this, EmptyText).ConfigureAwait(false); } // Temporary disabled, we don't remove the code because could be useful in future. diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineManager.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineManager.cs index 796a345413..d737a0ad5a 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineManager.cs @@ -33,12 +33,12 @@ internal async Task BuildAsync(CommandLineParseResult parseR foreach (Func commandLineProviderFactory in _commandLineProviderFactory) { ICommandLineOptionsProvider commandLineOptionsProvider = commandLineProviderFactory(serviceProvider); - if (!await commandLineOptionsProvider.IsEnabledAsync()) + if (!await commandLineOptionsProvider.IsEnabledAsync().ConfigureAwait(false)) { continue; } - await commandLineOptionsProvider.TryInitializeAsync(); + await commandLineOptionsProvider.TryInitializeAsync().ConfigureAwait(false); commandLineOptionsProviders.Add( commandLineOptionsProvider is IToolCommandLineOptionsProvider toolCommandLineOptionsProvider diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionsValidator.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionsValidator.cs index 9becb9e8c5..9ea02b9a03 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionsValidator.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionsValidator.cs @@ -59,13 +59,13 @@ public static async Task ValidateAsync( return result5; } - if (await ValidateOptionsArgumentsAsync(commandLineParseResult, providerAndOptionByOptionName) is { IsValid: false } result6) + if (await ValidateOptionsArgumentsAsync(commandLineParseResult, providerAndOptionByOptionName).ConfigureAwait(false) is { IsValid: false } result6) { return result6; } // Last validation step - return await ValidateConfigurationAsync(extensionOptionsByProvider.Keys, systemOptionsByProvider.Keys, commandLineOptions); + return await ValidateConfigurationAsync(extensionOptionsByProvider.Keys, systemOptionsByProvider.Keys, commandLineOptions).ConfigureAwait(false); } private static ValidationResult ValidateExtensionOptionsDoNotContainReservedPrefix( @@ -208,7 +208,7 @@ private static async Task ValidateOptionsArgumentsAsync( foreach (CommandLineParseOption optionRecord in parseResult.Options) { (ICommandLineOptionsProvider provider, CommandLineOption option) = providerAndOptionByOptionName[optionRecord.Name]; - ValidationResult result = await provider.ValidateOptionArgumentsAsync(option, optionRecord.Arguments); + ValidationResult result = await provider.ValidateOptionArgumentsAsync(option, optionRecord.Arguments).ConfigureAwait(false); if (!result.IsValid) { stringBuilder ??= new(); @@ -226,8 +226,8 @@ private static async Task ValidateConfigurationAsync( Dictionary>.KeyCollection systemProviders, ICommandLineOptions commandLineOptions) { - StringBuilder? stringBuilder = await ValidateConfigurationAsync(systemProviders, commandLineOptions, null); - stringBuilder = await ValidateConfigurationAsync(extensionsProviders, commandLineOptions, stringBuilder); + StringBuilder? stringBuilder = await ValidateConfigurationAsync(systemProviders, commandLineOptions, null).ConfigureAwait(false); + stringBuilder = await ValidateConfigurationAsync(extensionsProviders, commandLineOptions, stringBuilder).ConfigureAwait(false); return stringBuilder?.Length > 0 ? ValidationResult.Invalid(stringBuilder.ToTrimmedString()) @@ -241,7 +241,7 @@ private static async Task ValidateConfigurationAsync( { foreach (ICommandLineOptionsProvider commandLineOptionsProvider in providers) { - ValidationResult result = await commandLineOptionsProvider.ValidateCommandLineOptionsAsync(commandLineOptions); + ValidationResult result = await commandLineOptionsProvider.ValidateCommandLineOptionsAsync(commandLineOptions).ConfigureAwait(false); if (!result.IsValid) { stringBuilder ??= new(); diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/InformativeCommandLineTestHost.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/InformativeCommandLineTestHost.cs index 05c78fc571..f832a1aa03 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/InformativeCommandLineTestHost.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/InformativeCommandLineTestHost.cs @@ -7,7 +7,7 @@ namespace Microsoft.Testing.Platform.CommandLine; -internal sealed class InformativeCommandLineTestHost(int returnValue, IServiceProvider serviceProvider) : ITestHost, IDisposable +internal sealed class InformativeCommandLineHost(int returnValue, IServiceProvider serviceProvider) : IHost, IDisposable #if NETCOREAPP #pragma warning disable SA1001 // Commas should be spaced correctly , IAsyncDisposable @@ -27,7 +27,7 @@ public async ValueTask DisposeAsync() { if (PushOnlyProtocol is not null) { - await PushOnlyProtocol.DisposeAsync(); + await PushOnlyProtocol.DisposeAsync().ConfigureAwait(false); } } #endif diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/ParseResult.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/ParseResult.cs index 6e3de38051..1a39282dc7 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/ParseResult.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/ParseResult.cs @@ -129,7 +129,7 @@ public bool TryGetOptionArgumentList(string optionName, [NotNullWhen(true)] out IEnumerable result = Options.Where(x => x.Name == optionName); if (result.Any()) { - arguments = result.SelectMany(x => x.Arguments).ToArray(); + arguments = [.. result.SelectMany(x => x.Arguments)]; return true; } diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/Parser.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/Parser.cs index 61551e2c83..f8f6306d22 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/Parser.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/Parser.cs @@ -72,7 +72,7 @@ private static CommandLineParseResult Parse(List args, IEnvironment envi } else { - options.Add(new(currentOption, currentOptionArguments.ToArray())); + options.Add(new(currentOption, [.. currentOptionArguments])); currentOptionArguments.Clear(); ParseOptionAndSeparators(args[i], out currentOption, out currentArg); argumentHandled = true; @@ -93,11 +93,11 @@ private static CommandLineParseResult Parse(List args, IEnvironment envi { if (TryUnescape(currentArg.Trim(), currentOption, environment, out string? unescapedArg, out string? error)) { - currentOptionArguments.Add(unescapedArg!); + currentOptionArguments.Add(unescapedArg); } else { - errors.Add(error!); + errors.Add(error); } currentArg = null; @@ -114,15 +114,15 @@ private static CommandLineParseResult Parse(List args, IEnvironment envi { if (TryUnescape(currentArg.Trim(), currentOption, environment, out string? unescapedArg, out string? error)) { - currentOptionArguments.Add(unescapedArg!); + currentOptionArguments.Add(unescapedArg); } else { - errors.Add(error!); + errors.Add(error); } } - options.Add(new(currentOption, currentOptionArguments.ToArray())); + options.Add(new(currentOption, [.. currentOptionArguments])); } return new CommandLineParseResult(toolName, options, errors); @@ -138,14 +138,14 @@ static void ParseOptionAndSeparators(string arg, out string? currentOption, out currentOption = currentOption.TrimStart('-'); } - static bool TryUnescape(string input, string? option, IEnvironment environment, out string? unescapedArg, out string? error) + static bool TryUnescape(string input, string? option, IEnvironment environment, [NotNullWhen(true)] out string? unescapedArg, [NotNullWhen(false)] out string? error) { unescapedArg = input; error = null; // Enclosing characters in single-quotes ( '' ) shall preserve the literal value of each character within the single-quotes. // A single-quote cannot occur within single-quotes. - if (input.StartsWith(@"'", StringComparison.OrdinalIgnoreCase) && input.EndsWith(@"'", StringComparison.OrdinalIgnoreCase)) + if (input.StartsWith('\'') && input.EndsWith('\'')) { if (input.IndexOf('\'', 1, input.Length - 2) != -1) { @@ -165,7 +165,7 @@ static bool TryUnescape(string input, string? option, IEnvironment environment, // * The shall retain its special meaning introducing parameter expansion. [NOT SUPPORTED] // * The backslash shall retain its special meaning as an escape character only when followed by one of the following characters when considered special: // $ ` " \ - if (input.StartsWith("\"", StringComparison.OrdinalIgnoreCase) && input.EndsWith("\"", StringComparison.OrdinalIgnoreCase)) + if (input.StartsWith('"') && input.EndsWith('"')) { unescapedArg = input[1..^1].Replace(@"\\", "\\") .Replace(@"\""", "\"") diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/PlatformCommandLineProvider.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/PlatformCommandLineProvider.cs index c448fa0bf4..5f1b3f192b 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/PlatformCommandLineProvider.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/PlatformCommandLineProvider.cs @@ -28,6 +28,7 @@ internal sealed class PlatformCommandLineProvider : ICommandLineOptionsProvider public const string TestHostControllerPIDOptionKey = "internal-testhostcontroller-pid"; public const string ExitOnProcessExitOptionKey = "exit-on-process-exit"; public const string ConfigFileOptionKey = "config-file"; + public const string FilterUidOptionKey = "filter-uid"; public const string ServerOptionKey = "server"; public const string ClientPortOptionKey = "client-port"; @@ -57,6 +58,7 @@ internal sealed class PlatformCommandLineProvider : ICommandLineOptionsProvider new(IgnoreExitCodeOptionKey, PlatformResources.PlatformCommandLineIgnoreExitCodeOptionDescription, ArgumentArity.ExactlyOne, false, isBuiltIn: true), new(ExitOnProcessExitOptionKey, PlatformResources.PlatformCommandLineExitOnProcessExitOptionDescription, ArgumentArity.ExactlyOne, false, isBuiltIn: true), new(ConfigFileOptionKey, PlatformResources.PlatformCommandLineConfigFileOptionDescription, ArgumentArity.ExactlyOne, false, isBuiltIn: true), + new(FilterUidOptionKey, PlatformResources.PlatformCommandLineFilterUidOptionDescription, ArgumentArity.OneOrMore, false, isBuiltIn: true), // Hidden options new(HelpOptionQuestionMark, PlatformResources.PlatformCommandLineHelpOptionDescription, ArgumentArity.Zero, true, isBuiltIn: true), @@ -70,10 +72,10 @@ internal sealed class PlatformCommandLineProvider : ICommandLineOptionsProvider ]; /// - public string Uid { get; } = nameof(PlatformCommandLineProvider); + public string Uid => nameof(PlatformCommandLineProvider); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// public string DisplayName { get; } = PlatformResources.PlatformCommandLineProviderDisplayName; @@ -111,7 +113,7 @@ public Task ValidateOptionArgumentsAsync(CommandLineOption com { string arg = arguments[0]; int size = arg.Length; - if ((char.ToLowerInvariant(arg[size - 1]) != 'h' && char.ToLowerInvariant(arg[size - 1]) != 'm' && char.ToLowerInvariant(arg[size - 1]) != 's') || !float.TryParse(arg[..(size - 1)], out float _)) + if ((char.ToLowerInvariant(arg[size - 1]) != 'h' && char.ToLowerInvariant(arg[size - 1]) != 'm' && char.ToLowerInvariant(arg[size - 1]) != 's') || !float.TryParse(arg[..(size - 1)], NumberStyles.Float, CultureInfo.InvariantCulture, out float _)) { return ValidationResult.InvalidTask(PlatformResources.PlatformCommandLineTimeoutArgumentErrorMessage); } @@ -143,7 +145,7 @@ public Task ValidateOptionArgumentsAsync(CommandLineOption com public static int GetMinimumExpectedTests(ICommandLineOptions commandLineOptions) { bool hasMinimumExpectedTestsOptionKey = commandLineOptions.TryGetOptionArgumentList(MinimumExpectedTestsOptionKey, out string[]? minimumExpectedTests); - if (!hasMinimumExpectedTestsOptionKey || !IsMinimumExpectedTestsOptionValidAsync(MinimumExpectedTests, minimumExpectedTests ?? Array.Empty()).Result.IsValid) + if (!hasMinimumExpectedTestsOptionKey || !IsMinimumExpectedTestsOptionValidAsync(MinimumExpectedTests, minimumExpectedTests ?? []).Result.IsValid) { return 0; } diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/ResponseFileHelper.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/ResponseFileHelper.cs index 1b9d4c057b..a0d5965447 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/ResponseFileHelper.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/ResponseFileHelper.cs @@ -12,7 +12,7 @@ internal static bool TryReadResponseFile(string rspFilePath, ICollection { try { - newArguments = ExpandResponseFile(rspFilePath).ToArray(); + newArguments = [.. ExpandResponseFile(rspFilePath)]; return true; } catch (FileNotFoundException) diff --git a/src/Platform/Microsoft.Testing.Platform/Configurations/AggregatedConfiguration.cs b/src/Platform/Microsoft.Testing.Platform/Configurations/AggregatedConfiguration.cs index 878a690d58..18ffa830a1 100644 --- a/src/Platform/Microsoft.Testing.Platform/Configurations/AggregatedConfiguration.cs +++ b/src/Platform/Microsoft.Testing.Platform/Configurations/AggregatedConfiguration.cs @@ -68,7 +68,7 @@ public async Task CheckTestResultsDirectoryOverrideAndCreateItAsync(IFileLoggerP // This behavior is non documented and we reserve the right to change it in the future. if (fileLoggerProvider is not null) { - await fileLoggerProvider.CheckLogFolderAndMoveToTheNewIfNeededAsync(_resultsDirectory); + await fileLoggerProvider.CheckLogFolderAndMoveToTheNewIfNeededAsync(_resultsDirectory).ConfigureAwait(false); } } diff --git a/src/Platform/Microsoft.Testing.Platform/Configurations/ConfigurationManager.cs b/src/Platform/Microsoft.Testing.Platform/Configurations/ConfigurationManager.cs index 5a4861b9b0..bf9b7a51e6 100644 --- a/src/Platform/Microsoft.Testing.Platform/Configurations/ConfigurationManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/Configurations/ConfigurationManager.cs @@ -27,15 +27,15 @@ internal async Task BuildAsync(IFileLoggerProvider? syncFileLogg foreach (Func configurationSource in _configurationSources) { IConfigurationSource serviceInstance = configurationSource(); - if (!await serviceInstance.IsEnabledAsync()) + if (!await serviceInstance.IsEnabledAsync().ConfigureAwait(false)) { continue; } - await serviceInstance.TryInitializeAsync(); + await serviceInstance.TryInitializeAsync().ConfigureAwait(false); - IConfigurationProvider configurationProvider = await serviceInstance.BuildAsync(commandLineParseResult); - await configurationProvider.LoadAsync(); + IConfigurationProvider configurationProvider = await serviceInstance.BuildAsync(commandLineParseResult).ConfigureAwait(false); + await configurationProvider.LoadAsync().ConfigureAwait(false); if (configurationProvider is JsonConfigurationProvider configuration) { defaultJsonConfiguration = configuration; @@ -52,12 +52,12 @@ internal async Task BuildAsync(IFileLoggerProvider? syncFileLogg { using IFileStream configFileStream = _fileSystem.NewFileStream(defaultJsonConfiguration.ConfigurationFile, FileMode.Open, FileAccess.Read); StreamReader streamReader = new(configFileStream.Stream); - await logger.LogTraceAsync($"Configuration file ('{defaultJsonConfiguration.ConfigurationFile}') content:\n{await streamReader.ReadToEndAsync()}"); + await logger.LogTraceAsync($"Configuration file ('{defaultJsonConfiguration.ConfigurationFile}') content:\n{await streamReader.ReadToEndAsync().ConfigureAwait(false)}").ConfigureAwait(false); } } return defaultJsonConfiguration is null ? throw new InvalidOperationException(PlatformResources.ConfigurationManagerCannotFindDefaultJsonConfigurationErrorMessage) - : new AggregatedConfiguration(configurationProviders.OrderBy(x => x.Order).Select(x => x.ConfigurationProvider).ToArray(), _testApplicationModuleInfo, _fileSystem, commandLineParseResult); + : new AggregatedConfiguration([.. configurationProviders.OrderBy(x => x.Order).Select(x => x.ConfigurationProvider)], _testApplicationModuleInfo, _fileSystem, commandLineParseResult); } } diff --git a/src/Platform/Microsoft.Testing.Platform/Configurations/EnvironmentVariablesConfigurationProvider.cs b/src/Platform/Microsoft.Testing.Platform/Configurations/EnvironmentVariablesConfigurationProvider.cs index 1807b234dc..c5f4046058 100644 --- a/src/Platform/Microsoft.Testing.Platform/Configurations/EnvironmentVariablesConfigurationProvider.cs +++ b/src/Platform/Microsoft.Testing.Platform/Configurations/EnvironmentVariablesConfigurationProvider.cs @@ -15,7 +15,6 @@ internal sealed class EnvironmentVariablesConfigurationProvider : IConfiguration private const string SqlServerPrefix = "SQLCONNSTR_"; private const string CustomConnectionStringPrefix = "CUSTOMCONNSTR_"; - private readonly string _prefix; private readonly string _normalizedPrefix; private readonly Dictionary _data = new(StringComparer.OrdinalIgnoreCase); @@ -29,8 +28,7 @@ public EnvironmentVariablesConfigurationProvider(IEnvironment environmentVariabl public EnvironmentVariablesConfigurationProvider(IEnvironment environmentVariables, string prefix) { - _prefix = prefix; - _normalizedPrefix = Normalize(_prefix); + _normalizedPrefix = Normalize(prefix); _environmentVariables = environmentVariables; } diff --git a/src/Platform/Microsoft.Testing.Platform/Configurations/JsonConfigurationProvider.cs b/src/Platform/Microsoft.Testing.Platform/Configurations/JsonConfigurationProvider.cs index e2f33baa04..a4227726e0 100644 --- a/src/Platform/Microsoft.Testing.Platform/Configurations/JsonConfigurationProvider.cs +++ b/src/Platform/Microsoft.Testing.Platform/Configurations/JsonConfigurationProvider.cs @@ -30,7 +30,7 @@ private async Task LogInformationAsync(string message) { if (_logger is not null) { - await _logger.LogInformationAsync(message); + await _logger.LogInformationAsync(message).ConfigureAwait(false); } } @@ -40,7 +40,7 @@ public async Task LoadAsync() if (_commandLineParseResult.TryGetOptionArgumentList(PlatformCommandLineProvider.ConfigFileOptionKey, out string[]? configOptions)) { configFileName = configOptions[0]; - if (!_fileSystem.Exists(configFileName)) + if (!_fileSystem.ExistFile(configFileName)) { try { @@ -63,13 +63,13 @@ public async Task LoadAsync() Path.GetFileNameWithoutExtension(fullPath))}{PlatformConfigurationConstants.PlatformConfigSuffixFileName}" : $"{_testApplicationModuleInfo.TryGetAssemblyName()}{PlatformConfigurationConstants.PlatformConfigSuffixFileName}"; - if (!_fileSystem.Exists(configFileName)) + if (!_fileSystem.ExistFile(configFileName)) { return; } } - await LogInformationAsync($"Config file '{configFileName}' loaded."); + await LogInformationAsync($"Config file '{configFileName}' loaded.").ConfigureAwait(false); ConfigurationFile = configFileName; diff --git a/src/Platform/Microsoft.Testing.Platform/Configurations/JsonConfigurationSource.cs b/src/Platform/Microsoft.Testing.Platform/Configurations/JsonConfigurationSource.cs index 3855c806e8..405d58af87 100644 --- a/src/Platform/Microsoft.Testing.Platform/Configurations/JsonConfigurationSource.cs +++ b/src/Platform/Microsoft.Testing.Platform/Configurations/JsonConfigurationSource.cs @@ -15,18 +15,18 @@ internal sealed partial class JsonConfigurationSource(ITestApplicationModuleInfo private readonly FileLoggerProvider? _fileLoggerProvider = fileLoggerProvider; /// - public string Uid { get; } = nameof(JsonConfigurationSource); + public string Uid => nameof(JsonConfigurationSource); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// // Can be empty string because it's not used in the UI - public string DisplayName { get; } = string.Empty; + public string DisplayName => string.Empty; /// // Can be empty string because it's not used in the UI - public string Description { get; } = string.Empty; + public string Description => string.Empty; public int Order => 3; diff --git a/src/Platform/Microsoft.Testing.Platform/Extensions/AbortForMaxFailedTestsExtension.cs b/src/Platform/Microsoft.Testing.Platform/Extensions/AbortForMaxFailedTestsExtension.cs index c35ed10c03..878f3e8dcc 100644 --- a/src/Platform/Microsoft.Testing.Platform/Extensions/AbortForMaxFailedTestsExtension.cs +++ b/src/Platform/Microsoft.Testing.Platform/Extensions/AbortForMaxFailedTestsExtension.cs @@ -41,13 +41,13 @@ public AbortForMaxFailedTestsExtension( public Type[] DataTypesConsumed { get; } = [typeof(TestNodeUpdateMessage)]; /// - public string Uid { get; } = nameof(AbortForMaxFailedTestsExtension); + public string Uid => nameof(AbortForMaxFailedTestsExtension); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// - public string DisplayName { get; } = nameof(AbortForMaxFailedTestsExtension); + public string DisplayName => nameof(AbortForMaxFailedTestsExtension); /// public string Description { get; } = PlatformResources.AbortForMaxFailedTestsDescription; @@ -74,8 +74,8 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella // If already triggered, don't do it again. !_policiesService.IsMaxFailedTestsTriggered) { - await _capability.StopTestExecutionAsync(_testApplicationCancellationTokenSource.CancellationToken); - await _policiesService.ExecuteMaxFailedTestsCallbacksAsync(_maxFailedTests.Value, _testApplicationCancellationTokenSource.CancellationToken); + await _capability.StopTestExecutionAsync(_testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); + await _policiesService.ExecuteMaxFailedTestsCallbacksAsync(_maxFailedTests.Value, _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/Extensions/IAsyncInitializableExtension.cs b/src/Platform/Microsoft.Testing.Platform/Extensions/IAsyncInitializableExtension.cs index 8b79a2560d..87c0e8ad90 100644 --- a/src/Platform/Microsoft.Testing.Platform/Extensions/IAsyncInitializableExtension.cs +++ b/src/Platform/Microsoft.Testing.Platform/Extensions/IAsyncInitializableExtension.cs @@ -20,7 +20,7 @@ public static async Task TryInitializeAsync(this object target) { if (target is IAsyncInitializableExtension initializable) { - await initializable.InitializeAsync(); + await initializable.InitializeAsync().ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/ActionResult.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/ActionResult.cs index 694daf1ddc..33a26c8c31 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/ActionResult.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/ActionResult.cs @@ -3,19 +3,8 @@ namespace Microsoft.Testing.Platform.Helpers; -internal class ActionResult +internal static class ActionResult { - protected ActionResult(bool isSuccess, object? result) - { - IsSuccess = isSuccess; - Result = result; - } - - [MemberNotNullWhen(true, nameof(Result))] - public bool IsSuccess { get; } - - public object? Result { get; } - public static ActionResult Ok(TResult result) => new(true, result); @@ -23,16 +12,19 @@ public static ActionResult Fail() => new(false, default); } -internal sealed class ActionResult : ActionResult +internal sealed class ActionResult { internal ActionResult(bool isSuccess, TResult? result) - : base(isSuccess, result) => Result = result; + { + IsSuccess = isSuccess; + Result = result; + } [MemberNotNullWhen(true, nameof(Result))] - public new bool IsSuccess => base.IsSuccess; + public bool IsSuccess { get; } - public new TResult? Result { get; } + public TResult? Result { get; } public static implicit operator ActionResult(TResult result) - => Ok(result); + => new(true, result); } diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/CountDownEventExtensions.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/CountDownEventExtensions.cs index ccf927e17e..5093cbe04e 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/CountDownEventExtensions.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/CountDownEventExtensions.cs @@ -6,10 +6,10 @@ namespace Microsoft.Testing.Platform.Helpers; internal static class CountDownEventExtensions { public static async Task WaitAsync(this CountdownEvent countdownEvent, CancellationToken cancellationToken) - => await countdownEvent.WaitAsync(uint.MaxValue, cancellationToken); + => await countdownEvent.WaitAsync(uint.MaxValue, cancellationToken).ConfigureAwait(false); public static async Task WaitAsync(this CountdownEvent countdownEvent, TimeSpan timeout, CancellationToken cancellationToken) - => await countdownEvent.WaitAsync((uint)timeout.TotalMilliseconds, cancellationToken); + => await countdownEvent.WaitAsync((uint)timeout.TotalMilliseconds, cancellationToken).ConfigureAwait(false); internal static async Task WaitAsync(this CountdownEvent countdownEvent, uint millisecondsTimeOutInterval, CancellationToken cancellationToken) { @@ -39,7 +39,7 @@ internal static async Task WaitAsync(this CountdownEvent countdownEvent, u // Register the cancellation callback tokenRegistration = cancellationToken.Register(state => ((TaskCompletionSource)state!).TrySetCanceled(), tcs); - return await tcs.Task; + return await tcs.Task.ConfigureAwait(false); } finally { @@ -50,7 +50,7 @@ internal static async Task WaitAsync(this CountdownEvent countdownEvent, u #pragma warning disable CA1416 // Validate platform compatibility registeredHandle?.Unregister(null); #pragma warning restore CA1416 - await DisposeHelper.DisposeAsync(tokenRegistration); + await DisposeHelper.DisposeAsync(tokenRegistration).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/DisposeHelper.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/DisposeHelper.cs index 5ff940fa0b..97f5e1ad40 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/DisposeHelper.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/DisposeHelper.cs @@ -16,13 +16,13 @@ public static async Task DisposeAsync(object? obj) if (obj is IAsyncCleanableExtension async) { - await async.CleanupAsync(); + await async.CleanupAsync().ConfigureAwait(false); } #if NETCOREAPP if (obj is IAsyncDisposable dcAsyncDisposable) { - await dcAsyncDisposable.DisposeAsync(); + await dcAsyncDisposable.DisposeAsync().ConfigureAwait(false); } else { diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/EnvironmentVariableConstants.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/EnvironmentVariableConstants.cs index ad3c5291d3..e496cbc3af 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/EnvironmentVariableConstants.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/EnvironmentVariableConstants.cs @@ -39,4 +39,7 @@ internal static class EnvironmentVariableConstants // Unhandled Exception public const string TESTINGPLATFORM_EXIT_PROCESS_ON_UNHANDLED_EXCEPTION = nameof(TESTINGPLATFORM_EXIT_PROCESS_ON_UNHANDLED_EXCEPTION); + + // Trx + public const string TESTINGPLATFORM_TRX_TESTRUN_ID = nameof(TESTINGPLATFORM_TRX_TESTRUN_ID); } diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/ExtensionValidationHelper.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/ExtensionValidationHelper.cs new file mode 100644 index 0000000000..45266b509b --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/ExtensionValidationHelper.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Extensions; +using Microsoft.Testing.Platform.Resources; + +namespace Microsoft.Testing.Platform.Helpers; + +internal static class ExtensionValidationHelper +{ + /// + /// Validates that an extension with the same UID is not already registered in the collection. + /// Throws an InvalidOperationException with a detailed error message if duplicates are found. + /// + /// The type of extension being validated. + /// Collection of existing extensions to check against. + /// The new extension being registered. + /// Function to extract the IExtension from the collection item. + public static void ValidateUniqueExtension(this IEnumerable existingExtensions, IExtension newExtension, Func extensionSelector) + { + Guard.NotNull(existingExtensions); + Guard.NotNull(newExtension); + Guard.NotNull(extensionSelector); + + T[] duplicates = [.. existingExtensions.Where(x => extensionSelector(x).Uid == newExtension.Uid)]; + if (duplicates.Length > 0) + { + IExtension[] allDuplicates = [.. duplicates.Select(extensionSelector), newExtension]; + string typesList = string.Join(", ", allDuplicates.Select(x => $"'{x.GetType()}'")); + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, newExtension.Uid, typesList)); + } + } + + /// + /// Validates that an extension with the same UID is not already registered in the collection. + /// This overload is for simple collections where the items are extensions themselves. + /// + /// Collection of existing extensions to check against. + /// The new extension being registered. + public static void ValidateUniqueExtension(this IEnumerable existingExtensions, IExtension newExtension) + => existingExtensions.ValidateUniqueExtension(newExtension, x => x); +} diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs index 99f5c70729..51df458a4c 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs @@ -9,23 +9,10 @@ namespace Microsoft.Testing.Platform.Helpers; [ExcludeFromCodeCoverage] internal static class Sha256Hasher { - private static string Hash(string text) + public static string HashWithNormalizedCasing(string text) { - byte[] bytes = Encoding.UTF8.GetBytes(text); -#if NETCOREAPP + byte[] bytes = Encoding.UTF8.GetBytes(text.ToUpperInvariant()); byte[] hash = SHA256.HashData(bytes); -#else - using var hasher = SHA256.Create(); - byte[] hash = hasher.ComputeHash(bytes); -#endif - -#if NETCOREAPP - return Convert.ToHexString(hash).ToLowerInvariant(); -#else - return BitConverter.ToString(hash).Replace("-", string.Empty).ToLowerInvariant(); -#endif + return Convert.ToHexStringLower(hash); } - - public static string HashWithNormalizedCasing(string text) - => Hash(text.ToUpperInvariant()); } diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/IEnvironment.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/IEnvironment.cs index b44afb7377..dfcab15fbb 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/IEnvironment.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/IEnvironment.cs @@ -11,6 +11,8 @@ internal interface IEnvironment string NewLine { get; } + int ProcessId { get; } + string OsVersion { get; } #if NETCOREAPP diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/IFileSystem.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/IFileSystem.cs index a191266c3b..ca8e8fd431 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/IFileSystem.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/IFileSystem.cs @@ -5,11 +5,13 @@ namespace Microsoft.Testing.Platform.Helpers; internal interface IFileSystem { - bool Exists(string path); + bool ExistFile(string path); + + bool ExistDirectory(string? path); string CreateDirectory(string path); - void Move(string sourceFileName, string destFileName); + void MoveFile(string sourceFileName, string destFileName, bool overwrite = false); IFileStream NewFileStream(string path, FileMode mode); @@ -18,4 +20,10 @@ internal interface IFileSystem string ReadAllText(string path); Task ReadAllTextAsync(string path); + + void CopyFile(string sourceFileName, string destFileName, bool overwrite = false); + + void DeleteFile(string path); + + string[] GetFiles(string path, string searchPattern, SearchOption searchOption); } diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/IProcess.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/IProcess.cs index c64b4bbd97..49f677afd2 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/IProcess.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/IProcess.cs @@ -7,34 +7,29 @@ internal interface IProcess : IDisposable { event EventHandler Exited; - /// + /// int Id { get; } - /// + /// string Name { get; } - /// + /// int ExitCode { get; } - /// + /// bool HasExited { get; } -#if NETCOREAPP - /// + /// IMainModule? MainModule { get; } -#else - /// - IMainModule MainModule { get; } -#endif /// /// Instructs the Process component to wait for the associated process to exit, or for the cancellationToken to be canceled. /// Task WaitForExitAsync(); - /// + /// void WaitForExit(); - /// + /// void Kill(); } diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemAsyncMonitor.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemAsyncMonitor.cs index 4d563c4cd8..3e43741968 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemAsyncMonitor.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemAsyncMonitor.cs @@ -10,14 +10,14 @@ internal sealed class SystemAsyncMonitor : IAsyncMonitor, IDisposable public async Task LockAsync(TimeSpan timeout) { AsyncDisposableMonitor asyncDisposableMonitor = new(_semaphoreSlim); - await asyncDisposableMonitor.WaitAsync(timeout); + await asyncDisposableMonitor.WaitAsync(timeout).ConfigureAwait(false); return asyncDisposableMonitor; } public async Task LockAsync(CancellationToken cancellationToken) { AsyncDisposableMonitor asyncDisposableMonitor = new(_semaphoreSlim); - await asyncDisposableMonitor.WaitAsync(cancellationToken); + await asyncDisposableMonitor.WaitAsync(cancellationToken).ConfigureAwait(false); return asyncDisposableMonitor; } @@ -30,13 +30,13 @@ private readonly struct AsyncDisposableMonitor(SemaphoreSlim semaphoreSlim) : ID public async Task WaitAsync(TimeSpan timeout) { - if (!await _semaphoreSlim.WaitAsync(timeout)) + if (!await _semaphoreSlim.WaitAsync(timeout).ConfigureAwait(false)) { throw new InvalidOperationException($"Timeout of '{timeout}' while waiting for the semaphore"); } } - public async Task WaitAsync(CancellationToken cancellationToken) => await _semaphoreSlim.WaitAsync(cancellationToken); + public async Task WaitAsync(CancellationToken cancellationToken) => await _semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); public void Dispose() => _semaphoreSlim.Release(); diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs index a7ea4efe62..5723b9cfa5 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs @@ -12,6 +12,8 @@ internal sealed class SystemEnvironment : IEnvironment public string NewLine => Environment.NewLine; + public int ProcessId => Environment.ProcessId; + public string OsVersion => Environment.OSVersion.ToString(); #if NETCOREAPP diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs index c87970a522..d88cbf742a 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs @@ -5,11 +5,11 @@ namespace Microsoft.Testing.Platform.Helpers; internal sealed class SystemFileSystem : IFileSystem { - public bool Exists(string path) => File.Exists(path); + public bool ExistFile(string path) => File.Exists(path); public string CreateDirectory(string path) => Directory.CreateDirectory(path).FullName; - public void Move(string sourceFileName, string destFileName) => File.Move(sourceFileName, destFileName); + public void MoveFile(string sourceFileName, string destFileName, bool overwrite = false) => File.Move(sourceFileName, destFileName, overwrite); public IFileStream NewFileStream(string path, FileMode mode) => new SystemFileStream(path, mode); @@ -17,14 +17,13 @@ internal sealed class SystemFileSystem : IFileSystem public string ReadAllText(string path) => File.ReadAllText(path); -#if NETCOREAPP public Task ReadAllTextAsync(string path) => File.ReadAllTextAsync(path); -#else - public async Task ReadAllTextAsync(string path) - { - using FileStream stream = new(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan); - using StreamReader reader = new(stream); - return await reader.ReadToEndAsync(); - } -#endif + + public void CopyFile(string sourceFileName, string destFileName, bool overwrite = false) => File.Copy(sourceFileName, destFileName, overwrite); + + public void DeleteFile(string path) => File.Delete(path); + + public bool ExistDirectory(string? path) => Directory.Exists(path); + + public string[] GetFiles(string path, string searchPattern, SearchOption searchOption) => Directory.GetFiles(path, searchPattern, searchOption); } diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemProcess.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemProcess.cs index d38a5e75a9..17f6caa6bc 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemProcess.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemProcess.cs @@ -24,15 +24,10 @@ public SystemProcess(Process process) public int ExitCode => _process.ExitCode; -#if NETCOREAPP public IMainModule? MainModule => _process.MainModule is null ? null - : (IMainModule)new SystemMainModule(_process.MainModule); -#else - public IMainModule MainModule - => new SystemMainModule(_process.MainModule); -#endif + : new SystemMainModule(_process.MainModule); private void OnProcessExited(object? sender, EventArgs e) => Exited?.Invoke(sender, e); @@ -43,13 +38,8 @@ public void WaitForExit() public Task WaitForExitAsync() => _process.WaitForExitAsync(); -#if NETCOREAPP public void Kill() => _process.Kill(true); -#else - public void Kill() - => _process.Kill(); -#endif public void Dispose() => _process.Dispose(); #pragma warning restore CA1416 diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/TaskExtensions.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/TaskExtensions.cs index e482f7ab42..ae1ac1c92c 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/TaskExtensions.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/TaskExtensions.cs @@ -16,7 +16,7 @@ public static async Task WithCancellationAsync(this Task task, Cancella { try { - await task; + await task.ConfigureAwait(false); } catch (Exception) { @@ -55,7 +55,7 @@ public static async Task WithCancellationAsync(this Task task, CancellationToken { try { - await task; + await task.ConfigureAwait(false); } catch (Exception) { @@ -86,7 +86,7 @@ public static async Task TimeoutAfterAsync(this Task task, TimeSpan timeout, boo { try { - await task; + await task.ConfigureAwait(false); } catch (Exception) { @@ -124,7 +124,7 @@ public static async Task TimeoutAfterAsync(this Task task, TimeSpan timeout, Can { try { - await task; + await task.ConfigureAwait(false); } catch (Exception) { diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs index 0e146d7e9c..e11599ddff 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs @@ -14,7 +14,11 @@ namespace Microsoft.Testing.Platform.Hosts; -internal abstract class CommonTestHost(ServiceProvider serviceProvider) : ITestHost +/// +/// This represents either a test host (console or server), or a test host controller. +/// This doesn't represent an orchestrator host. +/// +internal abstract class CommonHost(ServiceProvider serviceProvider) : IHost { public ServiceProvider ServiceProvider => serviceProvider; @@ -31,7 +35,7 @@ public async Task RunAsync() { if (PushOnlyProtocol is null || PushOnlyProtocol?.IsServerMode == false) { - exitCode = await RunTestAppAsync(testApplicationCancellationToken); + exitCode = await RunTestAppAsync(testApplicationCancellationToken).ConfigureAwait(false); if (testApplicationCancellationToken.IsCancellationRequested) { @@ -45,18 +49,17 @@ public async Task RunAsync() { RoslynDebug.Assert(PushOnlyProtocol is not null); - ITestApplicationModuleInfo testApplicationModuleInfo = serviceProvider.GetTestApplicationModuleInfo(); - bool isValidProtocol = await PushOnlyProtocol.IsCompatibleProtocolAsync(GetHostType()); + bool isValidProtocol = await PushOnlyProtocol.IsCompatibleProtocolAsync(GetHostType()).ConfigureAwait(false); exitCode = isValidProtocol - ? await RunTestAppAsync(testApplicationCancellationToken) + ? await RunTestAppAsync(testApplicationCancellationToken).ConfigureAwait(false) : ExitCodes.IncompatibleProtocolVersion; } finally { if (PushOnlyProtocol is not null) { - await PushOnlyProtocol.OnExitAsync(); + await PushOnlyProtocol.OnExitAsync().ConfigureAwait(false); } } } @@ -66,9 +69,9 @@ public async Task RunAsync() } finally { - await DisposeServiceProviderAsync(ServiceProvider, isProcessShutdown: true); - await DisposeHelper.DisposeAsync(ServiceProvider.GetService()); - await DisposeHelper.DisposeAsync(PushOnlyProtocol); + await DisposeServiceProviderAsync(ServiceProvider, isProcessShutdown: true).ConfigureAwait(false); + await DisposeHelper.DisposeAsync(ServiceProvider.GetService()).ConfigureAwait(false); + await DisposeHelper.DisposeAsync(PushOnlyProtocol).ConfigureAwait(false); // This is intentional that we are not disposing the CTS. // An unobserved task exception could be raised after the dispose, and we want to use OutputDevice there @@ -86,7 +89,7 @@ public async Task RunAsync() private string GetHostType() { - // For now, we don't inherit TestHostOrchestratorHost from CommonTestHost one so we don't connect when we orchestrate + // For now, we don't inherit TestHostOrchestratorHost from CommonHost one so we don't connect when we orchestrate string hostType = this switch { ConsoleTestHost => "TestHost", @@ -101,21 +104,25 @@ private async Task RunTestAppAsync(CancellationToken testApplicationCancell if (RunTestApplicationLifeCycleCallbacks) { // Get the test application lifecycle callbacks to be able to call the before run +#pragma warning disable CS0618 // Type or member is obsolete foreach (ITestApplicationLifecycleCallbacks testApplicationLifecycleCallbacks in ServiceProvider.GetServicesInternal()) { - await testApplicationLifecycleCallbacks.BeforeRunAsync(testApplicationCancellationToken); + await testApplicationLifecycleCallbacks.BeforeRunAsync(testApplicationCancellationToken).ConfigureAwait(false); } +#pragma warning restore CS0618 // Type or member is obsolete } - int exitCode = await InternalRunAsync(); + int exitCode = await InternalRunAsync().ConfigureAwait(false); if (RunTestApplicationLifeCycleCallbacks) { +#pragma warning disable CS0618 // Type or member is obsolete foreach (ITestApplicationLifecycleCallbacks testApplicationLifecycleCallbacks in ServiceProvider.GetServicesInternal()) { - await testApplicationLifecycleCallbacks.AfterRunAsync(exitCode, testApplicationCancellationToken); - await DisposeHelper.DisposeAsync(testApplicationLifecycleCallbacks); + await testApplicationLifecycleCallbacks.AfterRunAsync(exitCode, testApplicationCancellationToken).ConfigureAwait(false); + await DisposeHelper.DisposeAsync(testApplicationLifecycleCallbacks).ConfigureAwait(false); } +#pragma warning restore CS0618 // Type or member is obsolete } return exitCode; @@ -128,13 +135,13 @@ protected static async Task ExecuteRequestAsync(ProxyOutputDevice outputDevice, { CancellationToken testSessionCancellationToken = serviceProvider.GetTestSessionContext().CancellationToken; - await DisplayBeforeSessionStartAsync(outputDevice, testSessionInfo, testSessionCancellationToken); + await DisplayBeforeSessionStartAsync(outputDevice, testSessionInfo, testSessionCancellationToken).ConfigureAwait(false); try { - await NotifyTestSessionStartAsync(testSessionInfo.SessionId, baseMessageBus, serviceProvider, testSessionCancellationToken); - await serviceProvider.GetTestAdapterInvoker().ExecuteAsync(testFramework, client, testSessionCancellationToken); - await NotifyTestSessionEndAsync(testSessionInfo.SessionId, baseMessageBus, serviceProvider, testSessionCancellationToken); + await NotifyTestSessionStartAsync(testSessionInfo.SessionId, baseMessageBus, serviceProvider, testSessionCancellationToken).ConfigureAwait(false); + await serviceProvider.GetTestAdapterInvoker().ExecuteAsync(testFramework, client, testSessionCancellationToken).ConfigureAwait(false); + await NotifyTestSessionEndAsync(testSessionInfo.SessionId, baseMessageBus, serviceProvider, testSessionCancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) when (testSessionCancellationToken.IsCancellationRequested) { @@ -143,33 +150,33 @@ protected static async Task ExecuteRequestAsync(ProxyOutputDevice outputDevice, // We keep the display after session out of the OperationCanceledException catch because we want to notify the IPlatformOutputDevice // also in case of cancellation. Most likely it needs to notify users that the session was canceled. - await DisplayAfterSessionEndRunAsync(outputDevice, testSessionInfo, testSessionCancellationToken); + await DisplayAfterSessionEndRunAsync(outputDevice, testSessionInfo, testSessionCancellationToken).ConfigureAwait(false); } private static async Task DisplayBeforeSessionStartAsync(ProxyOutputDevice outputDevice, ITestSessionContext sessionInfo, CancellationToken cancellationToken) { // Display before session start - await outputDevice.DisplayBeforeSessionStartAsync(); + await outputDevice.DisplayBeforeSessionStartAsync().ConfigureAwait(false); if (outputDevice.OriginalOutputDevice is ITestSessionLifetimeHandler testSessionLifetimeHandler) { await testSessionLifetimeHandler.OnTestSessionStartingAsync( sessionInfo.SessionId, - cancellationToken); + cancellationToken).ConfigureAwait(false); } } private static async Task DisplayAfterSessionEndRunAsync(ProxyOutputDevice outputDevice, ITestSessionContext sessionInfo, CancellationToken cancellationToken) { // Display after session end - await outputDevice.DisplayAfterSessionEndRunAsync(); + await outputDevice.DisplayAfterSessionEndRunAsync().ConfigureAwait(false); // We want to ensure that the output service is the last one to run if (outputDevice.OriginalOutputDevice is ITestSessionLifetimeHandler testSessionLifetimeHandlerFinishing) { await testSessionLifetimeHandlerFinishing.OnTestSessionFinishingAsync( sessionInfo.SessionId, - cancellationToken); + cancellationToken).ConfigureAwait(false); } } @@ -183,17 +190,17 @@ private static async Task NotifyTestSessionStartAsync(SessionUid sessionUid, Bas foreach (ITestSessionLifetimeHandler testSessionLifetimeHandler in testSessionLifetimeHandlersContainer.TestSessionLifetimeHandlers) { - await testSessionLifetimeHandler.OnTestSessionStartingAsync(sessionUid, cancellationToken); + await testSessionLifetimeHandler.OnTestSessionStartingAsync(sessionUid, cancellationToken).ConfigureAwait(false); } // Drain messages generated by the session start notification before to start test execution. - await baseMessageBus.DrainDataAsync(); + await baseMessageBus.DrainDataAsync().ConfigureAwait(false); } private static async Task NotifyTestSessionEndAsync(SessionUid sessionUid, BaseMessageBus baseMessageBus, ServiceProvider serviceProvider, CancellationToken cancellationToken) { // Drain messages generated by the test session execution before to process the session end notification. - await baseMessageBus.DrainDataAsync(); + await baseMessageBus.DrainDataAsync().ConfigureAwait(false); TestSessionLifetimeHandlersContainer? testSessionLifetimeHandlersContainer = serviceProvider.GetService(); if (testSessionLifetimeHandlersContainer is null) @@ -203,15 +210,15 @@ private static async Task NotifyTestSessionEndAsync(SessionUid sessionUid, BaseM foreach (ITestSessionLifetimeHandler testSessionLifetimeHandler in serviceProvider.GetRequiredService().TestSessionLifetimeHandlers) { - await testSessionLifetimeHandler.OnTestSessionFinishingAsync(sessionUid, cancellationToken); + await testSessionLifetimeHandler.OnTestSessionFinishingAsync(sessionUid, cancellationToken).ConfigureAwait(false); // OnTestSessionFinishingAsync could produce information that needs to be handled by others. - await baseMessageBus.DrainDataAsync(); + await baseMessageBus.DrainDataAsync().ConfigureAwait(false); } // We disable after the drain because it's possible that the drain will produce more messages - await baseMessageBus.DrainDataAsync(); - await baseMessageBus.DisableAsync(); + await baseMessageBus.DrainDataAsync().ConfigureAwait(false); + await baseMessageBus.DisableAsync().ConfigureAwait(false); } protected static async Task DisposeServiceProviderAsync(ServiceProvider serviceProvider, Func? filter = null, List? alreadyDisposed = null, bool isProcessShutdown = false) @@ -239,17 +246,20 @@ protected static async Task DisposeServiceProviderAsync(ServiceProvider serviceP } // We need to ensure that we won't dispose special services till the shutdown +#pragma warning disable CS0618 // Type or member is obsolete if (!isProcessShutdown && service is ITelemetryCollector or ITestApplicationLifecycleCallbacks or + ITestHostApplicationLifetime or IPushOnlyProtocol) { continue; } +#pragma warning restore CS0618 // Type or member is obsolete if (!alreadyDisposed.Contains(service)) { - await DisposeHelper.DisposeAsync(service); + await DisposeHelper.DisposeAsync(service).ConfigureAwait(false); alreadyDisposed.Add(service); } @@ -264,7 +274,7 @@ ITestApplicationLifecycleCallbacks or if (!alreadyDisposed.Contains(dataConsumer)) { - await DisposeHelper.DisposeAsync(dataConsumer); + await DisposeHelper.DisposeAsync(dataConsumer).ConfigureAwait(false); alreadyDisposed.Add(service); } } diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs index 026b1365d8..ddf96dcc17 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs @@ -20,7 +20,7 @@ internal sealed class ConsoleTestHost( Func> buildTestFrameworkAsync, TestFrameworkManager testFrameworkManager, TestHostManager testHostManager) - : CommonTestHost(serviceProvider) + : CommonHost(serviceProvider) { private static readonly ClientInfo ClientInfoHost = new("testingplatform-console", AppVersion.DefaultSemVer); private static readonly IClientInfo ClientInfoService = new ClientInfoService("testingplatform-console", AppVersion.DefaultSemVer); @@ -65,13 +65,13 @@ protected override async Task InternalRunAsync() _testHostManager, new MessageBusProxy(), ServiceProvider.GetCommandLineOptions().IsOptionSet(PlatformCommandLineProvider.DiscoverTestsOptionKey), - false)); + false)).ConfigureAwait(false); ITelemetryCollector telemetry = ServiceProvider.GetTelemetryCollector(); ITelemetryInformation telemetryInformation = ServiceProvider.GetTelemetryInformation(); Statistics? statistics = null; string? extensionInformation = null; - await _logger.LogInformationAsync($"Starting test session '{ServiceProvider.GetTestSessionContext().SessionId}'"); + await _logger.LogInformationAsync($"Starting test session '{ServiceProvider.GetTestSessionContext().SessionId}'").ConfigureAwait(false); int exitCode; DateTimeOffset adapterLoadStop = _clock.UtcNow; DateTimeOffset requestExecuteStart = _clock.UtcNow; @@ -86,7 +86,7 @@ await ExecuteRequestAsync( ServiceProvider, ServiceProvider.GetBaseMessageBus(), testFramework, - ClientInfoHost); + ClientInfoHost).ConfigureAwait(false); requestExecuteStop = _clock.UtcNow; // Get the exit code service to be able to set the exit code @@ -94,12 +94,12 @@ await ExecuteRequestAsync( statistics = testApplicationResult.GetStatistics(); exitCode = testApplicationResult.GetProcessExitCode(); - await _logger.LogInformationAsync($"Test session '{ServiceProvider.GetTestSessionContext().SessionId}' ended with exit code '{exitCode}' in {consoleRunStarted.Elapsed}"); + await _logger.LogInformationAsync($"Test session '{ServiceProvider.GetTestSessionContext().SessionId}' ended with exit code '{exitCode}' in {consoleRunStarted.Elapsed}").ConfigureAwait(false); // We collect info about the extensions before the dispose to avoid possible issue with cleanup. if (telemetryInformation.IsEnabled) { - extensionInformation = await ExtensionInformationCollector.CollectAndSerializeToJsonAsync(ServiceProvider); + extensionInformation = await ExtensionInformationCollector.CollectAndSerializeToJsonAsync(ServiceProvider).ConfigureAwait(false); } } catch (OperationCanceledException oc) when (oc.CancellationToken == abortRun) @@ -107,12 +107,12 @@ await ExecuteRequestAsync( requestExecuteStop ??= _clock.UtcNow; exitCode = ExitCodes.TestSessionAborted; - await _logger.LogInformationAsync("Test session canceled."); + await _logger.LogInformationAsync("Test session canceled.").ConfigureAwait(false); } finally { // Cleanup all services - await DisposeServiceProviderAsync(ServiceProvider); + await DisposeServiceProviderAsync(ServiceProvider).ConfigureAwait(false); } if (telemetryInformation.IsEnabled) @@ -140,7 +140,7 @@ await ExecuteRequestAsync( metrics.Add(TelemetryProperties.HostProperties.ExtensionsPropertyName, extensionInformation); } - await telemetry.LogEventAsync(TelemetryEvents.ConsoleTestHostExitEventName, metrics); + await telemetry.LogEventAsync(TelemetryEvents.ConsoleTestHostExitEventName, metrics).ConfigureAwait(false); } return exitCode; diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/IHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/IHost.cs new file mode 100644 index 0000000000..08fcda2bf8 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/IHost.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Testing.Platform.Hosts; + +/// +/// This represents a host (i.e, a process). It could be a "test host" (the process that actually runs the tests), +/// a "test host controller" (runs out-of-process extensions like dump extensions which observes the test host), or +/// a "test host orchestrator" (like Retry extension, which coordinates how test hosts should be run). +/// +internal interface IHost +{ + Task RunAsync(); +} diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/ITestHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/ITestHost.cs deleted file mode 100644 index 7f8bf987bd..0000000000 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/ITestHost.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.Testing.Platform.Hosts; - -internal interface ITestHost -{ - Task RunAsync(); -} diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/ITestHostBuilder.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/ITestHostBuilder.cs index dfe44cd17b..12cc02f5a6 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/ITestHostBuilder.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/ITestHostBuilder.cs @@ -8,7 +8,6 @@ using Microsoft.Testing.Platform.Extensions.TestHostOrchestrator; using Microsoft.Testing.Platform.Helpers; using Microsoft.Testing.Platform.Logging; -using Microsoft.Testing.Platform.ServerMode; using Microsoft.Testing.Platform.Telemetry; using Microsoft.Testing.Platform.TestHost; using Microsoft.Testing.Platform.TestHostControllers; @@ -34,9 +33,7 @@ internal interface ITestHostBuilder ITelemetryManager Telemetry { get; } - IServerModeManager ServerMode { get; } - IToolsManager Tools { get; } - Task BuildAsync(ApplicationLoggingState loggingState, TestApplicationOptions testApplicationOptions, IUnhandledExceptionsHandler unhandledExceptionsHandler, DateTimeOffset createBuilderStart); + Task BuildAsync(ApplicationLoggingState loggingState, TestApplicationOptions testApplicationOptions, IUnhandledExceptionsHandler unhandledExceptionsHandler, DateTimeOffset createBuilderStart); } diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs index be8ff2dd95..cdc2774be8 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs @@ -21,7 +21,7 @@ namespace Microsoft.Testing.Platform.Hosts; -internal sealed partial class ServerTestHost : CommonTestHost, IServerTestHost, IDisposable, IOutputDeviceDataProducer +internal sealed partial class ServerTestHost : CommonHost, IServerTestHost, IDisposable, IOutputDeviceDataProducer { public const string ProtocolVersion = PlatformVersion.Version; private readonly Func> _buildTestFrameworkAsync; @@ -137,10 +137,10 @@ protected override async Task InternalRunAsync() { try { - await _logger.LogDebugAsync("Starting server mode"); - _messageHandler = await _messageHandlerFactory.CreateMessageHandlerAsync(_testApplicationCancellationTokenSource.CancellationToken); + await _logger.LogDebugAsync("Starting server mode").ConfigureAwait(false); + _messageHandler = await _messageHandlerFactory.CreateMessageHandlerAsync(_testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); - await HandleMessagesAsync(); + await HandleMessagesAsync().ConfigureAwait(false); (_messageHandler as IDisposable)?.Dispose(); } @@ -156,7 +156,7 @@ protected override async Task InternalRunAsync() finally { // Cleanup all services but special one because in the per-call mode we needed to keep them alive for reuse - await DisposeServiceProviderAsync(ServiceProvider); + await DisposeServiceProviderAsync(ServiceProvider).ConfigureAwait(false); } // If the global cancellation is called together with the server closing one the server exited gracefully. @@ -178,7 +178,7 @@ private async Task HandleMessagesAsync() { try { - RpcMessage? message = await _messageHandler.ReadAsync(messageHandlerStopPlusGlobalToken); + RpcMessage? message = await _messageHandler.ReadAsync(messageHandlerStopPlusGlobalToken).ConfigureAwait(false); // In case of issue on underneath handler we expect a null rpc message to signal that we should close // because we're no more able to process things. @@ -195,8 +195,8 @@ private async Task HandleMessagesAsync() // Signal only one time if (!_serverClosingTokenSource.IsCancellationRequested) { - await _logger.LogDebugAsync("Server requested to shutdown"); - await _serverClosingTokenSource.CancelAsync(); + await _logger.LogDebugAsync("Server requested to shutdown").ConfigureAwait(false); + await _serverClosingTokenSource.CancelAsync().ConfigureAwait(false); } // Signal the exit call @@ -205,7 +205,7 @@ private async Task HandleMessagesAsync() // If there're no in-flight request we can close the server if (_clientToServerRequests.IsEmpty) { - await _stopMessageHandler.CancelAsync(); + await _stopMessageHandler.CancelAsync().ConfigureAwait(false); } continue; @@ -248,7 +248,7 @@ private async Task HandleMessagesAsync() _requestCounter.Signal(); // Wait to drain all in-flight requests HandleRequestCoreAsync/CompleteRequest - await _requestCounter.WaitAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, CancellationToken.None); + await _requestCounter.WaitAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, CancellationToken.None).ConfigureAwait(false); } private async Task HandleNotificationAsync(NotificationMessage message, CancellationToken serverClosing) @@ -285,11 +285,11 @@ private async Task HandleNotificationAsync(NotificationMessage message, Cancella // This is intentionally not using PlatformResources.ExceptionDuringCancellationWarningMessage // It's meant for troubleshooting and shouldn't be localized. // The localized message that is user-facing will be displayed in the DisplayAsync call next line. - await _logger.LogWarningAsync($"Exception during the cancellation of request id '{args.CancelRequestId}'"); + await _logger.LogWarningAsync($"Exception during the cancellation of request id '{args.CancelRequestId}'").ConfigureAwait(false); await ServiceProvider.GetOutputDevice().DisplayAsync( this, - new WarningMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExceptionDuringCancellationWarningMessage, args.CancelRequestId))); + new WarningMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExceptionDuringCancellationWarningMessage, args.CancelRequestId))).ConfigureAwait(false); } } @@ -310,7 +310,7 @@ private async Task HandleRequestAsync(RequestMessage request, CancellationToken { try { - await SendErrorAsync(reqId: request.Id, errorCode: ErrorCodes.InvalidRequest, message: "Server is closing", data: null, _testApplicationCancellationTokenSource.CancellationToken); + await SendErrorAsync(reqId: request.Id, errorCode: ErrorCodes.InvalidRequest, message: "Server is closing", data: null, _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); } finally { @@ -330,8 +330,8 @@ private async Task HandleRequestAsync(RequestMessage request, CancellationToken try { - object response = await HandleRequestCoreAsync(request, rpcState); - await SendResponseAsync(reqId: request.Id, result: response, _testApplicationCancellationTokenSource.CancellationToken); + object response = await HandleRequestCoreAsync(request, rpcState).ConfigureAwait(false); + await SendResponseAsync(reqId: request.Id, result: response, _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); CompleteRequest(ref _clientToServerRequests, request.Id, completion => completion.TrySetResult(response)); } catch (OperationCanceledException e) @@ -342,12 +342,12 @@ private async Task HandleRequestAsync(RequestMessage request, CancellationToken ? (string.Empty, ErrorCodes.RequestCanceled) : (e.ToString(), ErrorCodes.RequestCanceled); - await SendErrorAsync(reqId: request.Id, errorCode: errorCode, message: errorMessage, data: null, _testApplicationCancellationTokenSource.CancellationToken); + await SendErrorAsync(reqId: request.Id, errorCode: errorCode, message: errorMessage, data: null, _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); CompleteRequest(ref _clientToServerRequests, request.Id, completion => completion.TrySetCanceled()); } catch (Exception e) { - await SendErrorAsync(reqId: request.Id, errorCode: 0, message: e.ToString(), data: null, _testApplicationCancellationTokenSource.CancellationToken); + await SendErrorAsync(reqId: request.Id, errorCode: 0, message: e.ToString(), data: null, _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); CompleteRequest(ref _clientToServerRequests, request.Id, completion => completion.SetException(e)); } } @@ -393,7 +393,7 @@ private async Task HandleRequestCoreAsync(RequestMessage message, RpcInv AssertInitialized(); - await _logger.LogDebugAsync($"Received {message.Method} request"); + await _logger.LogDebugAsync($"Received {message.Method} request").ConfigureAwait(false); switch (message.Method, message.Params) { @@ -401,11 +401,11 @@ private async Task HandleRequestCoreAsync(RequestMessage message, RpcInv { _client = new(args.ClientInfo.Name, args.ClientInfo.Version); _clientInfoService = new ClientInfoService(args.ClientInfo.Name, args.ClientInfo.Version); - await _logger.LogDebugAsync($"Connection established with '{_client.Id}', protocol version {_client.Version}"); + await _logger.LogDebugAsync($"Connection established with '{_client.Id}', protocol version {_client.Version}").ConfigureAwait(false); INamedFeatureCapability? namedFeatureCapability = ServiceProvider.GetTestFrameworkCapabilities().GetCapability(); return new InitializeResponseArgs( - ProcessId: ServiceProvider.GetProcessHandler().GetCurrentProcess().Id, + ProcessId: ServiceProvider.GetEnvironment().ProcessId, ServerInfo: new ServerInfo("test-anywhere", Version: ProtocolVersion), Capabilities: new ServerCapabilities( new ServerTestingCapabilities( @@ -419,12 +419,12 @@ private async Task HandleRequestCoreAsync(RequestMessage message, RpcInv case (JsonRpcMethods.TestingDiscoverTests, DiscoverRequestArgs args): { - return await ExecuteRequestAsync(args, JsonRpcMethods.TestingDiscoverTests, perRequestServiceProvider); + return await ExecuteRequestAsync(args, JsonRpcMethods.TestingDiscoverTests, perRequestServiceProvider).ConfigureAwait(false); } case (JsonRpcMethods.TestingRunTests, RunRequestArgs args): { - return await ExecuteRequestAsync(args, JsonRpcMethods.TestingRunTests, perRequestServiceProvider); + return await ExecuteRequestAsync(args, JsonRpcMethods.TestingRunTests, perRequestServiceProvider).ConfigureAwait(false); } default: @@ -472,7 +472,7 @@ private async Task ExecuteRequestAsync(RequestArgsBase args, s DateTimeOffset adapterLoadStart = _clock.UtcNow; ProxyOutputDevice outputDevice = ServiceProvider.GetRequiredService(); - await outputDevice.InitializeAsync(this); + await outputDevice.InitializeAsync(this).ConfigureAwait(false); // Build the per request adapter ITestFramework perRequestTestFramework = await _buildTestFrameworkAsync(new TestFrameworkBuilderData( @@ -486,7 +486,7 @@ private async Task ExecuteRequestAsync(RequestArgsBase args, s _testSessionManager, new MessageBusProxy(), method == JsonRpcMethods.TestingDiscoverTests, - true)); + true)).ConfigureAwait(false); DateTimeOffset adapterLoadStop = _clock.UtcNow; @@ -504,7 +504,7 @@ await ExecuteRequestAsync( perRequestServiceProvider, perRequestServiceProvider.GetBaseMessageBus(), perRequestTestFramework, - _client); + _client).ConfigureAwait(false); // Check if there was a test adapter testSession failure ITestApplicationProcessExitCode testApplicationResult = perRequestServiceProvider.GetTestApplicationProcessExitCode(); @@ -516,7 +516,7 @@ await ExecuteRequestAsync( // Verify request cancellation, above the chain the exception will be // catch and propagated as correct json rpc error perRequestTestSessionContext.CancellationToken.ThrowIfCancellationRequested(); - await SendTestUpdateCompleteAsync(args.RunId); + await SendTestUpdateCompleteAsync(args.RunId).ConfigureAwait(false); requestExecuteStop = _clock.UtcNow; } finally @@ -525,7 +525,7 @@ await ExecuteRequestAsync( // Cleanup all services // We skip all services that are "cloned" per call because are reused and will be disposed on shutdown. - await DisposeServiceProviderAsync(perRequestServiceProvider, obj => !ServiceProvider.Services.Contains(obj)); + await DisposeServiceProviderAsync(perRequestServiceProvider, obj => !ServiceProvider.Services.Contains(obj)).ConfigureAwait(false); // We need to dispose this service manually because the shared DisposeServiceProviderAsync skip some special service like the ITestApplicationCooperativeLifetimeService // that needs to be disposed at process exits. @@ -553,10 +553,10 @@ await ExecuteRequestAsync( testNodeUpdateProcessor.GetTestNodeStatistics().TotalDiscoveredTests) : throw new NotImplementedException($"Request not implemented '{method}'"); - await _telemetryService.LogEventAsync(TelemetryEvents.TestsRunEventName, metadata); + await _telemetryService.LogEventAsync(TelemetryEvents.TestsRunEventName, metadata).ConfigureAwait(false); return method == JsonRpcMethods.TestingRunTests - ? new RunResponseArgs(testNodeUpdateProcessor.Artifacts.ToArray()) + ? new RunResponseArgs([.. testNodeUpdateProcessor.Artifacts]) : method == JsonRpcMethods.TestingDiscoverTests ? (ResponseArgsBase)new DiscoverResponseArgs() : throw new NotImplementedException($"Request not implemented '{method}'"); @@ -604,9 +604,9 @@ private async Task SendErrorAsync(int reqId, int errorCode, string message, obje AssertInitialized(); ErrorMessage error = new(reqId, errorCode, message, data); - using (await _messageMonitor.LockAsync(cancellationToken)) + using (await _messageMonitor.LockAsync(cancellationToken).ConfigureAwait(false)) { - await _messageHandler.WriteRequestAsync(error, cancellationToken); + await _messageHandler.WriteRequestAsync(error, cancellationToken).ConfigureAwait(false); } } @@ -615,9 +615,9 @@ private async Task SendResponseAsync(int reqId, object result, CancellationToken AssertInitialized(); ResponseMessage response = new(reqId, result); - using (await _messageMonitor.LockAsync(cancellationToken)) + using (await _messageMonitor.LockAsync(cancellationToken).ConfigureAwait(false)) { - await _messageHandler.WriteRequestAsync(response, cancellationToken); + await _messageHandler.WriteRequestAsync(response, cancellationToken).ConfigureAwait(false); } } @@ -633,10 +633,10 @@ private async Task SendMessageAsync(string method, object? @params, Cancellation { NotificationMessage notification = new(method, @params); - using (await _messageMonitor.LockAsync(cancellationToken)) + using (await _messageMonitor.LockAsync(cancellationToken).ConfigureAwait(false)) { AssertInitialized(); - await _messageHandler.WriteRequestAsync(notification, cancellationToken); + await _messageHandler.WriteRequestAsync(notification, cancellationToken).ConfigureAwait(false); } } catch @@ -664,31 +664,31 @@ public void Dispose() } internal async Task SendTestUpdateCompleteAsync(Guid runId) - => await SendTestUpdateAsync(new TestNodeStateChangedEventArgs(runId, Changes: null)); + => await SendTestUpdateAsync(new TestNodeStateChangedEventArgs(runId, Changes: null)).ConfigureAwait(false); public async Task SendTestUpdateAsync(TestNodeStateChangedEventArgs update) => await SendMessageAsync( method: JsonRpcMethods.TestingTestUpdatesTests, @params: update, - _testApplicationCancellationTokenSource.CancellationToken); + _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); public async Task SendTelemetryEventUpdateAsync(TelemetryEventArgs args) => await SendMessageAsync( method: JsonRpcMethods.TelemetryUpdate, @params: args, - _testApplicationCancellationTokenSource.CancellationToken); + _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); public async Task SendClientLaunchDebuggerAsync(ProcessInfoArgs args) => await SendRequestAsync( method: JsonRpcMethods.ClientLaunchDebugger, @params: args, - _testApplicationCancellationTokenSource.CancellationToken); + _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); public async Task SendClientAttachDebuggerAsync(AttachDebuggerInfoArgs args) => await SendRequestAsync( method: JsonRpcMethods.ClientAttachDebugger, @params: args, - _testApplicationCancellationTokenSource.CancellationToken); + _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); private async Task SendRequestAsync(string method, object @params, CancellationToken cancellationToken) { @@ -701,14 +701,14 @@ private async Task SendRequestAsync(string method, object @params, CancellationT // Add the request to the counter _requestCounter.AddCount(); - await _messageHandler.WriteRequestAsync(request, cancellationToken); + await _messageHandler.WriteRequestAsync(request, cancellationToken).ConfigureAwait(false); using (cancellationToken.Register(() => _ = SendMessageAsync( JsonRpcMethods.CancelRequest, new CancelRequestArgs(requestId), cancellationToken))) { - await invocationState.CompletionSource.Task; + await invocationState.CompletionSource.Task.ConfigureAwait(false); } } @@ -724,7 +724,7 @@ await SendMessageAsync( // We could receive some log messages after the exit, a real sample is if telemetry provider is too slow and we log a warning. checkServerExit: true, - rethrowException: false); + rethrowException: false).ConfigureAwait(false); break; } } diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs index 4f11f189c8..b51e0dc081 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs @@ -46,15 +46,13 @@ internal sealed class TestHostBuilder(IFileSystem fileSystem, IRuntimeFeature ru public ITelemetryManager Telemetry { get; } = new TelemetryManager(); - public IServerModeManager ServerMode { get; } = new ServerModeManager(); - public ITestHostControllersManager TestHostControllers { get; } = new TestHostControllersManager(); public IToolsManager Tools { get; } = new ToolsManager(); public ITestHostOrchestratorManager TestHostOrchestratorManager { get; } = new TestHostOrchestratorManager(); - public async Task BuildAsync( + public async Task BuildAsync( ApplicationLoggingState loggingState, TestApplicationOptions testApplicationOptions, IUnhandledExceptionsHandler unhandledExceptionsHandler, @@ -117,7 +115,7 @@ public async Task BuildAsync( if (logger is not null) { - await logger.LogInformationAsync($"Setting RegisterEnvironmentVariablesConfigurationSource: '{testApplicationOptions.Configuration.ConfigurationSources.RegisterEnvironmentVariablesConfigurationSource}'"); + await logger.LogInformationAsync($"Setting RegisterEnvironmentVariablesConfigurationSource: '{testApplicationOptions.Configuration.ConfigurationSources.RegisterEnvironmentVariablesConfigurationSource}'").ConfigureAwait(false); } // By default the env var configuration source is enabled, check if we have to disable it. @@ -130,13 +128,12 @@ public async Task BuildAsync( Configuration.AddConfigurationSource(() => new JsonConfigurationSource(_testApplicationModuleInfo, _fileSystem, loggingState.FileLoggerProvider)); // Build the IConfiguration - we need special treatment because the configuration is needed by extensions. - var configuration = (AggregatedConfiguration)await ((ConfigurationManager)Configuration).BuildAsync(loggingState.FileLoggerProvider, loggingState.CommandLineParseResult); + var configuration = (AggregatedConfiguration)await ((ConfigurationManager)Configuration).BuildAsync(loggingState.FileLoggerProvider, loggingState.CommandLineParseResult).ConfigureAwait(false); serviceProvider.TryAddService(configuration); // Current test platform is picky on unhandled exception, we will tear down the process in that case. // This mode can be too aggressive especially compared to the old framework, so we allow the user to disable it if their suite // relies on unhandled exception. - IEnvironment environment = serviceProvider.GetEnvironment(); // Check the config file, by default is not specified the policy is false. _ = bool.TryParse(configuration[PlatformConfigurationConstants.PlatformExitProcessOnUnhandledException]!, out bool isFileConfiguredToFailFast); @@ -155,7 +152,7 @@ public async Task BuildAsync( if (logger is not null) { - await logger.LogInformationAsync($"Setting PlatformExitProcessOnUnhandledException: '{exitProcessOnUnhandledException}', config file: {isFileConfiguredToFailFast} environment variable: {isEnvConfiguredToFailFast}"); + await logger.LogInformationAsync($"Setting PlatformExitProcessOnUnhandledException: '{exitProcessOnUnhandledException}', config file: {isFileConfiguredToFailFast} environment variable: {isEnvConfiguredToFailFast}").ConfigureAwait(false); } if (exitProcessOnUnhandledException) @@ -185,7 +182,7 @@ public async Task BuildAsync( // Build the command line service - we need special treatment because is possible that an extension query it during the creation. // Add Retry default argument commandlines - CommandLineHandler commandLineHandler = await ((CommandLineManager)CommandLine).BuildAsync(loggingState.CommandLineParseResult, serviceProvider); + CommandLineHandler commandLineHandler = await ((CommandLineManager)CommandLine).BuildAsync(loggingState.CommandLineParseResult, serviceProvider).ConfigureAwait(false); // Set the concrete command line options to the proxy. commandLineOptionsProxy.SetCommandLineOptions(commandLineHandler); @@ -197,7 +194,7 @@ public async Task BuildAsync( bool hasServerFlag = commandLineHandler.TryGetOptionArgumentList(PlatformCommandLineProvider.ServerOptionKey, out string[]? protocolName); bool isJsonRpcProtocol = protocolName is null || protocolName.Length == 0 || protocolName[0].Equals(PlatformCommandLineProvider.JsonRpcProtocolName, StringComparison.OrdinalIgnoreCase); - ProxyOutputDevice proxyOutputDevice = await _outputDisplay.BuildAsync(serviceProvider, hasServerFlag && isJsonRpcProtocol); + ProxyOutputDevice proxyOutputDevice = await _outputDisplay.BuildAsync(serviceProvider, hasServerFlag && isJsonRpcProtocol).ConfigureAwait(false); // Add FileLoggerProvider if needed if (loggingState.FileLoggerProvider is not null) @@ -209,15 +206,15 @@ public async Task BuildAsync( ICommandLineOptions commandLineOptions = serviceProvider.GetCommandLineOptions(); // Build the logger factory. - ILoggerFactory loggerFactory = await ((LoggingManager)Logging).BuildAsync(serviceProvider, loggingState.LogLevel, systemMonitor); + ILoggerFactory loggerFactory = await ((LoggingManager)Logging).BuildAsync(serviceProvider, loggingState.LogLevel, systemMonitor).ConfigureAwait(false); // Set the concrete logger factory loggerFactoryProxy.SetLoggerFactory(loggerFactory); // Initialize the output device if needed. - if (await proxyOutputDevice.OriginalOutputDevice.IsEnabledAsync()) + if (await proxyOutputDevice.OriginalOutputDevice.IsEnabledAsync().ConfigureAwait(false)) { - await proxyOutputDevice.OriginalOutputDevice.TryInitializeAsync(); + await proxyOutputDevice.OriginalOutputDevice.TryInitializeAsync().ConfigureAwait(false); } // Add the platform output device to the service provider for both modes. @@ -228,7 +225,7 @@ public async Task BuildAsync( ITestFrameworkCapabilities testFrameworkCapabilities = TestFramework.TestFrameworkCapabilitiesFactory(serviceProvider); if (testFrameworkCapabilities is IAsyncInitializableExtension testFrameworkCapabilitiesAsyncInitializable) { - await testFrameworkCapabilitiesAsyncInitializable.InitializeAsync(); + await testFrameworkCapabilitiesAsyncInitializable.InitializeAsync().ConfigureAwait(false); } // Register the test framework capabilities to be used by services @@ -239,14 +236,14 @@ public async Task BuildAsync( loggingState.CommandLineParseResult, commandLineHandler.SystemCommandLineOptionsProviders, commandLineHandler.ExtensionsCommandLineOptionsProviders, - commandLineHandler); + commandLineHandler).ConfigureAwait(false); if (!loggingState.CommandLineParseResult.HasTool && !commandLineValidationResult.IsValid) { - await DisplayBannerIfEnabledAsync(loggingState, proxyOutputDevice, testFrameworkCapabilities); - await proxyOutputDevice.DisplayAsync(commandLineHandler, new ErrorMessageOutputDeviceData(commandLineValidationResult.ErrorMessage)); - await commandLineHandler.PrintHelpAsync(proxyOutputDevice); - return new InformativeCommandLineTestHost(ExitCodes.InvalidCommandLine, serviceProvider); + await DisplayBannerIfEnabledAsync(loggingState, proxyOutputDevice, testFrameworkCapabilities).ConfigureAwait(false); + await proxyOutputDevice.DisplayAsync(commandLineHandler, new ErrorMessageOutputDeviceData(commandLineValidationResult.ErrorMessage)).ConfigureAwait(false); + await commandLineHandler.PrintHelpAsync(proxyOutputDevice).ConfigureAwait(false); + return new InformativeCommandLineHost(ExitCodes.InvalidCommandLine, serviceProvider); } // Register as ICommandLineOptions. @@ -257,7 +254,7 @@ public async Task BuildAsync( { string arg = args[0]; int size = arg.Length; - if (!float.TryParse(arg[..(size - 1)], out float value)) + if (!float.TryParse(arg[..(size - 1)], NumberStyles.Float, CultureInfo.InvariantCulture, out float value)) { throw ApplicationStateGuard.Unreachable(); } @@ -273,19 +270,26 @@ public async Task BuildAsync( testApplicationCancellationTokenSource.CancelAfter(timeout); } - // At this point we start to build extensions so we need to have all the information complete for the usage, - // here we ensure to override the result directory if user passed the argument --results-directory in command line. - // After this check users can get the result directory using IConfiguration["platformOptions:resultDirectory"] or the - // extension method helper serviceProvider.GetConfiguration() - await configuration.CheckTestResultsDirectoryOverrideAndCreateItAsync(loggingState.FileLoggerProvider); + bool isHelpCommand = commandLineHandler.IsHelpInvoked(); + bool isInfoCommand = commandLineHandler.IsInfoInvoked(); + + // Do not create the result directory if the user invoked --help or --info command. + if (!isHelpCommand && !isInfoCommand) + { + // At this point we start to build extensions so we need to have all the information complete for the usage, + // here we ensure to override the result directory if user passed the argument --results-directory in command line. + // After this check users can get the result directory using IConfiguration["platformOptions:resultDirectory"] or the + // extension method helper serviceProvider.GetConfiguration() + await configuration.CheckTestResultsDirectoryOverrideAndCreateItAsync(loggingState.FileLoggerProvider).ConfigureAwait(false); + } // Display banner now because we need capture the output in case of MSBuild integration and we want to forward // to file disc also the banner, so at this point we need to have all services and configuration(result directory) built. - await DisplayBannerIfEnabledAsync(loggingState, proxyOutputDevice, testFrameworkCapabilities); + await DisplayBannerIfEnabledAsync(loggingState, proxyOutputDevice, testFrameworkCapabilities).ConfigureAwait(false); // Add global telemetry service. // Add at this point or the telemetry banner appearance order will be wrong, we want the testing app banner before the telemetry banner. - ITelemetryCollector telemetryService = await ((TelemetryManager)Telemetry).BuildAsync(serviceProvider, loggerFactory, testApplicationOptions); + ITelemetryCollector telemetryService = await ((TelemetryManager)Telemetry).BuildAsync(serviceProvider, loggerFactory, testApplicationOptions).ConfigureAwait(false); serviceProvider.TryAddService(telemetryService); AddApplicationMetadata(serviceProvider, builderMetrics); @@ -314,58 +318,64 @@ public async Task BuildAsync( // Add the platform output device to the service provider. var toolsServiceProvider = (ServiceProvider)serviceProvider.Clone(); toolsServiceProvider.TryAddService(proxyOutputDevice); - IReadOnlyList toolsInformation = await ((ToolsManager)Tools).BuildAsync(toolsServiceProvider); + IReadOnlyList toolsInformation = await ((ToolsManager)Tools).BuildAsync(toolsServiceProvider).ConfigureAwait(false); if (loggingState.CommandLineParseResult.HasTool) { // Add the platform output device to the service provider. serviceProvider.TryAddService(proxyOutputDevice); - ToolsTestHost toolsTestHost = new(toolsInformation, serviceProvider, commandLineHandler, proxyOutputDevice); + ToolsHost toolsTestHost = new(toolsInformation, serviceProvider, commandLineHandler, proxyOutputDevice); await LogTestHostCreatedAsync( serviceProvider, mode: TelemetryProperties.ApplicationMode.Tool, metrics: builderMetrics, - stop: systemClock.UtcNow); + stop: systemClock.UtcNow).ConfigureAwait(false); return toolsTestHost; } - var pushOnlyProtocol = new DotnetTestConnection(commandLineHandler, processHandler, environment, _testApplicationModuleInfo, testApplicationCancellationTokenSource); - await pushOnlyProtocol.AfterCommonServiceSetupAsync(); + var pushOnlyProtocol = new DotnetTestConnection(commandLineHandler, environment, _testApplicationModuleInfo, testApplicationCancellationTokenSource); + await pushOnlyProtocol.AfterCommonServiceSetupAsync().ConfigureAwait(false); if (pushOnlyProtocol.IsServerMode) { serviceProvider.AddService(pushOnlyProtocol); } // If --help is invoked we return - if (commandLineHandler.IsHelpInvoked()) + if (isHelpCommand) { if (pushOnlyProtocol.IsServerMode) { - await pushOnlyProtocol.HelpInvokedAsync(); + await pushOnlyProtocol.HelpInvokedAsync().ConfigureAwait(false); } else { - await commandLineHandler.PrintHelpAsync(proxyOutputDevice, toolsInformation); + await commandLineHandler.PrintHelpAsync(proxyOutputDevice, toolsInformation).ConfigureAwait(false); } - return new InformativeCommandLineTestHost(0, serviceProvider); + return new InformativeCommandLineHost(0, serviceProvider); } // If --info is invoked we return - if (commandLineHandler.IsInfoInvoked()) + if (isInfoCommand) { - await commandLineHandler.PrintInfoAsync(proxyOutputDevice, toolsInformation); - return new InformativeCommandLineTestHost(0, serviceProvider); + await commandLineHandler.PrintInfoAsync(proxyOutputDevice, toolsInformation).ConfigureAwait(false); + return new InformativeCommandLineHost(0, serviceProvider); } // ======= TEST HOST ORCHESTRATOR ======== // - TestHostOrchestratorConfiguration testHostOrchestratorConfiguration = await TestHostOrchestratorManager.BuildAsync(serviceProvider); + TestHostOrchestratorConfiguration testHostOrchestratorConfiguration = await TestHostOrchestratorManager.BuildAsync(serviceProvider).ConfigureAwait(false); if (testHostOrchestratorConfiguration.TestHostOrchestrators.Length > 0 && !commandLineHandler.IsOptionSet(PlatformCommandLineProvider.DiscoverTestsOptionKey)) { policiesService.ProcessRole = TestProcessRole.TestHostOrchestrator; - await proxyOutputDevice.HandleProcessRoleAsync(TestProcessRole.TestHostOrchestrator); + await proxyOutputDevice.HandleProcessRoleAsync(TestProcessRole.TestHostOrchestrator).ConfigureAwait(false); + + // Build and register the test application lifecycle callbacks. + ITestHostOrchestratorApplicationLifetime[] orchestratorLifetimes = + await ((TestHostOrchestratorManager)TestHostOrchestratorManager).BuildTestHostOrchestratorApplicationLifetimesAsync(serviceProvider).ConfigureAwait(false); + serviceProvider.AddServices(orchestratorLifetimes); + return new TestHostOrchestratorHost(testHostOrchestratorConfiguration, serviceProvider); } @@ -380,11 +390,11 @@ await LogTestHostCreatedAsync( if (hasServerFlag && isJsonRpcProtocol) { // Build the IMessageHandlerFactory for the PassiveNode - IMessageHandlerFactory messageHandlerFactory = ((ServerModeManager)ServerMode).Build(serviceProvider); + IMessageHandlerFactory messageHandlerFactory = ServerModeManager.Build(serviceProvider); passiveNode = new PassiveNode( messageHandlerFactory, testApplicationCancellationTokenSource, - processHandler, + systemEnvironment, systemMonitorAsyncFactory, loggerFactory.CreateLogger()); } @@ -397,19 +407,19 @@ await LogTestHostCreatedAsync( // Add the message bus proxy specific for the launchers. testHostControllersServiceProvider.TryAddService(new MessageBusProxy()); - TestHostControllerConfiguration testHostControllers = await ((TestHostControllersManager)TestHostControllers).BuildAsync(testHostControllersServiceProvider); + TestHostControllerConfiguration testHostControllers = await ((TestHostControllersManager)TestHostControllers).BuildAsync(testHostControllersServiceProvider).ConfigureAwait(false); if (testHostControllers.RequireProcessRestart) { testHostControllerInfo.IsCurrentProcessTestHostController = true; policiesService.ProcessRole = TestProcessRole.TestHostController; - await proxyOutputDevice.HandleProcessRoleAsync(TestProcessRole.TestHostController); + await proxyOutputDevice.HandleProcessRoleAsync(TestProcessRole.TestHostController).ConfigureAwait(false); TestHostControllersTestHost testHostControllersTestHost = new(testHostControllers, testHostControllersServiceProvider, passiveNode, systemEnvironment, loggerFactory, systemClock); await LogTestHostCreatedAsync( serviceProvider, mode: TelemetryProperties.ApplicationMode.TestHostControllers, metrics: builderMetrics, - stop: systemClock.UtcNow); + stop: systemClock.UtcNow).ConfigureAwait(false); return testHostControllersTestHost; } @@ -417,7 +427,7 @@ await LogTestHostCreatedAsync( // ======= TEST HOST MODE ======== // policiesService.ProcessRole = TestProcessRole.TestHost; - await proxyOutputDevice.HandleProcessRoleAsync(TestProcessRole.TestHost); + await proxyOutputDevice.HandleProcessRoleAsync(TestProcessRole.TestHost).ConfigureAwait(false); // Setup the test host working folder. // Out of the test host controller extension the current working directory is the test host working directory. @@ -429,23 +439,24 @@ await LogTestHostCreatedAsync( // If we're under test controllers and currently we're inside the started test host we connect to the out of process // test controller manager. NamedPipeClient? testControllerConnection = await ConnectToTestHostProcessMonitorIfAvailableAsync( - processHandler, testApplicationCancellationTokenSource, loggerFactory.CreateLogger(nameof(ConnectToTestHostProcessMonitorIfAvailableAsync)), testHostControllerInfo, configuration, - systemEnvironment); + systemEnvironment).ConfigureAwait(false); // Build and register the test application lifecycle callbacks. +#pragma warning disable CS0618 // Type or member is obsolete ITestApplicationLifecycleCallbacks[] testApplicationLifecycleCallback = - await ((TestHostManager)TestHost).BuildTestApplicationLifecycleCallbackAsync(serviceProvider); + await ((TestHostManager)TestHost).BuildTestApplicationLifecycleCallbackAsync(serviceProvider).ConfigureAwait(false); +#pragma warning restore CS0618 // Type or member is obsolete serviceProvider.AddServices(testApplicationLifecycleCallback); // ServerMode and Console mode uses different host if (hasServerFlag && isJsonRpcProtocol) { // Build the server mode with the user preferences - IMessageHandlerFactory messageHandlerFactory = ((ServerModeManager)ServerMode).Build(serviceProvider); + IMessageHandlerFactory messageHandlerFactory = ServerModeManager.Build(serviceProvider); // Build the test host // note that we pass the BuildTestFrameworkAsync as callback because server mode will call it per-request @@ -454,7 +465,7 @@ await LogTestHostCreatedAsync( new(serviceProvider, BuildTestFrameworkAsync, messageHandlerFactory, (TestFrameworkManager)TestFramework, (TestHostManager)TestHost); // If needed we wrap the host inside the TestHostControlledHost to automatically handle the shutdown of the connected pipe. - ITestHost actualTestHost = testControllerConnection is not null + IHost actualTestHost = testControllerConnection is not null ? new TestHostControlledHost(testControllerConnection, serverTestHost, testApplicationCancellationTokenSource.CancellationToken) : serverTestHost; @@ -463,21 +474,21 @@ await LogTestHostCreatedAsync( serviceProvider, mode: TelemetryProperties.ApplicationMode.Server, metrics: builderMetrics, - stop: systemClock.UtcNow); + stop: systemClock.UtcNow).ConfigureAwait(false); return actualTestHost; } else { // Add custom ITestExecutionFilterFactory to the service list if available - ActionResult testExecutionFilterFactoryResult = await ((TestHostManager)TestHost).TryBuildTestExecutionFilterFactoryAsync(serviceProvider); + ActionResult testExecutionFilterFactoryResult = await ((TestHostManager)TestHost).TryBuildTestExecutionFilterFactoryAsync(serviceProvider).ConfigureAwait(false); if (testExecutionFilterFactoryResult.IsSuccess) { serviceProvider.TryAddService(testExecutionFilterFactoryResult.Result); } // Add custom ITestExecutionFilterFactory to the service list if available - ActionResult testAdapterInvokerBuilderResult = await ((TestHostManager)TestHost).TryBuildTestAdapterInvokerAsync(serviceProvider); + ActionResult testAdapterInvokerBuilderResult = await ((TestHostManager)TestHost).TryBuildTestAdapterInvokerAsync(serviceProvider).ConfigureAwait(false); if (testAdapterInvokerBuilderResult.IsSuccess) { serviceProvider.TryAddService(testAdapterInvokerBuilderResult.Result); @@ -498,7 +509,7 @@ await LogTestHostCreatedAsync( (TestHostManager)TestHost); // If needed we wrap the host inside the TestHostControlledHost to automatically handle the shutdown of the connected pipe. - ITestHost actualTestHost = testControllerConnection is not null + IHost actualTestHost = testControllerConnection is not null ? new TestHostControlledHost(testControllerConnection, consoleHost, testApplicationCancellationTokenSource.CancellationToken) : consoleHost; @@ -508,7 +519,7 @@ await LogTestHostCreatedAsync( serviceProvider, mode: TelemetryProperties.ApplicationMode.Console, metrics: builderMetrics, - stop: systemClock.UtcNow); + stop: systemClock.UtcNow).ConfigureAwait(false); #pragma warning restore SA1118 // Parameter should not span multiple lines return actualTestHost; @@ -516,7 +527,6 @@ await LogTestHostCreatedAsync( } private static async Task ConnectToTestHostProcessMonitorIfAvailableAsync( - IProcessHandler processHandler, CTRLPlusCCancellationTokenSource testApplicationCancellationTokenSource, ILogger logger, TestHostControllerInfo testHostControllerInfo, @@ -539,21 +549,20 @@ await LogTestHostCreatedAsync( client.RegisterAllSerializers(); // Connect to the monitor - await logger.LogDebugAsync($"Connecting to named pipe '{pipeName}'"); + await logger.LogDebugAsync($"Connecting to named pipe '{pipeName}'").ConfigureAwait(false); string? seconds = configuration[PlatformConfigurationConstants.PlatformTestHostControllersManagerNamedPipeClientConnectTimeoutSeconds]; // Default timeout is 30 seconds int timeoutSeconds = seconds is null ? TimeoutHelper.DefaultHangTimeoutSeconds : int.Parse(seconds, CultureInfo.InvariantCulture); - await logger.LogDebugAsync($"Setting PlatformTestHostControllersManagerNamedPipeClientConnectTimeoutSeconds '{timeoutSeconds}'"); + await logger.LogDebugAsync($"Setting PlatformTestHostControllersManagerNamedPipeClientConnectTimeoutSeconds '{timeoutSeconds}'").ConfigureAwait(false); using CancellationTokenSource timeout = new(TimeSpan.FromSeconds(timeoutSeconds)); - await client.ConnectAsync(timeout.Token); - await logger.LogDebugAsync($"Connected to named pipe '{pipeName}'"); + await client.ConnectAsync(timeout.Token).ConfigureAwait(false); + await logger.LogDebugAsync($"Connected to named pipe '{pipeName}'").ConfigureAwait(false); // Send the PID - using IProcess currentProcess = processHandler.GetCurrentProcess(); await client.RequestReplyAsync( - new TestHostProcessPIDRequest(currentProcess.Id), - testApplicationCancellationTokenSource.CancellationToken); + new TestHostProcessPIDRequest(environment.ProcessId), + testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); return client; } @@ -614,7 +623,7 @@ private static async Task LogTestHostCreatedAsync( [TelemetryProperties.HostProperties.BuildBuilderStop] = stop, [TelemetryProperties.HostProperties.CreateBuilderStop] = stop, }; - await telemetryService.LogEventAsync(TelemetryEvents.TestHostBuiltEventName, metricsObj); + await telemetryService.LogEventAsync(TelemetryEvents.TestHostBuiltEventName, metricsObj).ConfigureAwait(false); } } @@ -630,27 +639,27 @@ private static async Task BuildTestFrameworkAsync(TestFrameworkB if (pushOnlyProtocol?.IsServerMode == true) { - pushOnlyProtocolDataConsumer = await pushOnlyProtocol.GetDataConsumerAsync(); + pushOnlyProtocolDataConsumer = await pushOnlyProtocol.GetDataConsumerAsync().ConfigureAwait(false); } // Build and register "common non special" services - we need special treatment because extensions can start to log during the // creations and we could lose interesting diagnostic information. List dataConsumersBuilder = []; - await RegisterAsServiceOrConsumerOrBothAsync(testFrameworkBuilderData.PlatformOutputDisplayService, serviceProvider, dataConsumersBuilder); - await RegisterAsServiceOrConsumerOrBothAsync(testFrameworkBuilderData.TestExecutionRequestFactory, serviceProvider, dataConsumersBuilder); - await RegisterAsServiceOrConsumerOrBothAsync(testFrameworkBuilderData.TestExecutionRequestInvoker, serviceProvider, dataConsumersBuilder); - await RegisterAsServiceOrConsumerOrBothAsync(testFrameworkBuilderData.TestExecutionFilterFactory, serviceProvider, dataConsumersBuilder); + await RegisterAsServiceOrConsumerOrBothAsync(testFrameworkBuilderData.PlatformOutputDisplayService, serviceProvider, dataConsumersBuilder).ConfigureAwait(false); + await RegisterAsServiceOrConsumerOrBothAsync(testFrameworkBuilderData.TestExecutionRequestFactory, serviceProvider, dataConsumersBuilder).ConfigureAwait(false); + await RegisterAsServiceOrConsumerOrBothAsync(testFrameworkBuilderData.TestExecutionRequestInvoker, serviceProvider, dataConsumersBuilder).ConfigureAwait(false); + await RegisterAsServiceOrConsumerOrBothAsync(testFrameworkBuilderData.TestExecutionFilterFactory, serviceProvider, dataConsumersBuilder).ConfigureAwait(false); // Create the test framework adapter ITestFrameworkCapabilities testFrameworkCapabilities = serviceProvider.GetTestFrameworkCapabilities(); ITestFramework testFramework = testFrameworkBuilderData.TestFrameworkManager.TestFrameworkFactory(testFrameworkCapabilities, serviceProvider); - await testFramework.TryInitializeAsync(); + await testFramework.TryInitializeAsync().ConfigureAwait(false); serviceProvider.AllowTestAdapterFrameworkRegistration = true; try { - await RegisterAsServiceOrConsumerOrBothAsync(new TestFrameworkProxy(testFramework), serviceProvider, dataConsumersBuilder); + await RegisterAsServiceOrConsumerOrBothAsync(new TestFrameworkProxy(testFramework), serviceProvider, dataConsumersBuilder).ConfigureAwait(false); } finally { @@ -665,8 +674,8 @@ private static async Task BuildTestFrameworkAsync(TestFrameworkB { // We keep the bag of the already created composite service factory to reuse the instance. List newBuiltCompositeServices = []; - (IExtension Consumer, int RegistrationOrder)[] consumers = await testFrameworkBuilderData.TestSessionManager.BuildDataConsumersAsync(serviceProvider, newBuiltCompositeServices); - (IExtension TestSessionLifetimeHandler, int RegistrationOrder)[] sessionLifeTimeHandlers = await testFrameworkBuilderData.TestSessionManager.BuildTestSessionLifetimeHandleAsync(serviceProvider, newBuiltCompositeServices); + (IExtension Consumer, int RegistrationOrder)[] consumers = await testFrameworkBuilderData.TestSessionManager.BuildDataConsumersAsync(serviceProvider, newBuiltCompositeServices).ConfigureAwait(false); + (IExtension TestSessionLifetimeHandler, int RegistrationOrder)[] sessionLifeTimeHandlers = await testFrameworkBuilderData.TestSessionManager.BuildTestSessionLifetimeHandleAsync(serviceProvider, newBuiltCompositeServices).ConfigureAwait(false); // Register the test session lifetime handlers for the notifications testSessionLifetimeHandlers.AddRange(sessionLifeTimeHandlers.OrderBy(x => x.RegistrationOrder).Select(x => (ITestSessionLifetimeHandler)x.TestSessionLifetimeHandler)); @@ -676,11 +685,11 @@ private static async Task BuildTestFrameworkAsync(TestFrameworkB { if (testhostExtension.Extension is IDataConsumer) { - await RegisterAsServiceOrConsumerOrBothAsync(testhostExtension.Extension, serviceProvider, dataConsumersBuilder); + await RegisterAsServiceOrConsumerOrBothAsync(testhostExtension.Extension, serviceProvider, dataConsumersBuilder).ConfigureAwait(false); } else { - await AddServiceIfNotSkippedAsync(testhostExtension.Extension, serviceProvider); + await AddServiceIfNotSkippedAsync(testhostExtension.Extension, serviceProvider).ConfigureAwait(false); } } } @@ -694,7 +703,7 @@ private static async Task BuildTestFrameworkAsync(TestFrameworkB testSessionLifetimeHandlers.Add(handler); } - await RegisterAsServiceOrConsumerOrBothAsync(consumerService, serviceProvider, dataConsumersBuilder); + await RegisterAsServiceOrConsumerOrBothAsync(consumerService, serviceProvider, dataConsumersBuilder).ConfigureAwait(false); } // Register the test session lifetime handlers container @@ -710,7 +719,7 @@ private static async Task BuildTestFrameworkAsync(TestFrameworkB // Allow the ITestApplicationProcessExitCode to subscribe as IDataConsumer ITestApplicationProcessExitCode testApplicationResult = serviceProvider.GetRequiredService(); - await RegisterAsServiceOrConsumerOrBothAsync(testApplicationResult, serviceProvider, dataConsumersBuilder); + await RegisterAsServiceOrConsumerOrBothAsync(testApplicationResult, serviceProvider, dataConsumersBuilder).ConfigureAwait(false); // We register the data consumer handler if we're connected to the dotnet test pipe if (pushOnlyProtocolDataConsumer is not null) @@ -724,12 +733,12 @@ private static async Task BuildTestFrameworkAsync(TestFrameworkB serviceProvider.GetRequiredService(), serviceProvider.GetTestApplicationCancellationTokenSource()); - if (await abortForMaxFailedTestsExtension.IsEnabledAsync()) + if (await abortForMaxFailedTestsExtension.IsEnabledAsync().ConfigureAwait(false)) { dataConsumersBuilder.Add(abortForMaxFailedTestsExtension); } - IDataConsumer[] dataConsumerServices = dataConsumersBuilder.ToArray(); + IDataConsumer[] dataConsumerServices = [.. dataConsumersBuilder]; AsynchronousMessageBus concreteMessageBusService = new( dataConsumerServices, @@ -737,7 +746,7 @@ private static async Task BuildTestFrameworkAsync(TestFrameworkB serviceProvider.GetTask(), serviceProvider.GetLoggerFactory(), serviceProvider.GetEnvironment()); - await concreteMessageBusService.InitAsync(); + await concreteMessageBusService.InitAsync().ConfigureAwait(false); testFrameworkBuilderData.MessageBusProxy.SetBuiltMessageBus(concreteMessageBusService); return testFramework; @@ -754,7 +763,7 @@ private static async Task AddServiceIfNotSkippedAsync(object service, ServicePro { if (service is IExtension extension) { - if (await extension.IsEnabledAsync()) + if (await extension.IsEnabledAsync().ConfigureAwait(false)) { serviceProvider.TryAddService(service); } @@ -770,7 +779,7 @@ private static async Task RegisterAsServiceOrConsumerOrBothAsync(object service, { if (service is IDataConsumer dataConsumer) { - if (!await dataConsumer.IsEnabledAsync()) + if (!await dataConsumer.IsEnabledAsync().ConfigureAwait(false)) { return; } @@ -783,7 +792,7 @@ private static async Task RegisterAsServiceOrConsumerOrBothAsync(object service, return; } - await AddServiceIfNotSkippedAsync(service, serviceProvider); + await AddServiceIfNotSkippedAsync(service, serviceProvider).ConfigureAwait(false); } private async Task DisplayBannerIfEnabledAsync(ApplicationLoggingState loggingState, ProxyOutputDevice outputDevice, @@ -796,10 +805,10 @@ private async Task DisplayBannerIfEnabledAsync(ApplicationLoggingState loggingSt { IBannerMessageOwnerCapability? bannerMessageOwnerCapability = testFrameworkCapabilities.GetCapability(); string? bannerMessage = bannerMessageOwnerCapability is not null - ? await bannerMessageOwnerCapability.GetBannerMessageAsync() + ? await bannerMessageOwnerCapability.GetBannerMessageAsync().ConfigureAwait(false) : null; - await outputDevice.DisplayBannerAsync(bannerMessage); + await outputDevice.DisplayBannerAsync(bannerMessage).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControlledHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControlledHost.cs index 47aa9ec5ce..e3ba508abf 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControlledHost.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControlledHost.cs @@ -7,7 +7,7 @@ namespace Microsoft.Testing.Platform.Hosts; -internal sealed class TestHostControlledHost(NamedPipeClient testHostControllerPipeClient, ITestHost innerTestHost, CancellationToken cancellationToken) : ITestHost, IDisposable +internal sealed class TestHostControlledHost(NamedPipeClient testHostControllerPipeClient, IHost innerHost, CancellationToken cancellationToken) : IHost, IDisposable #if NETCOREAPP #pragma warning disable SA1001 // Commas should be spaced correctly , IAsyncDisposable @@ -15,15 +15,15 @@ internal sealed class TestHostControlledHost(NamedPipeClient testHostControllerP #endif { private readonly NamedPipeClient _namedPipeClient = testHostControllerPipeClient; - private readonly ITestHost _innerTestHost = innerTestHost; + private readonly IHost _innerHost = innerHost; private readonly CancellationToken _cancellationToken = cancellationToken; public async Task RunAsync() { - int exitCode = await _innerTestHost.RunAsync(); + int exitCode = await _innerHost.RunAsync().ConfigureAwait(false); try { - await _namedPipeClient.RequestReplyAsync(new TestHostProcessExitRequest(exitCode), _cancellationToken); + await _namedPipeClient.RequestReplyAsync(new TestHostProcessExitRequest(exitCode), _cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException oc) when (oc.CancellationToken == _cancellationToken) { @@ -31,7 +31,7 @@ public async Task RunAsync() } finally { - await DisposeHelper.DisposeAsync(_namedPipeClient); + await DisposeHelper.DisposeAsync(_namedPipeClient).ConfigureAwait(false); } return exitCode; @@ -39,15 +39,15 @@ public async Task RunAsync() public void Dispose() { - (_innerTestHost as IDisposable)?.Dispose(); + (_innerHost as IDisposable)?.Dispose(); _namedPipeClient.Dispose(); } #if NETCOREAPP public async ValueTask DisposeAsync() { - await DisposeHelper.DisposeAsync(_innerTestHost); - await _namedPipeClient.DisposeAsync(); + await DisposeHelper.DisposeAsync(_innerHost).ConfigureAwait(false); + await _namedPipeClient.DisposeAsync().ConfigureAwait(false); } #endif } diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControllersTestHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControllersTestHost.cs index 601ea403d2..25bfabac0b 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControllersTestHost.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControllersTestHost.cs @@ -22,7 +22,7 @@ namespace Microsoft.Testing.Platform.Hosts; -internal sealed class TestHostControllersTestHost : CommonTestHost, ITestHost, IDisposable, IOutputDeviceDataProducer +internal sealed class TestHostControllersTestHost : CommonHost, IHost, IDisposable, IOutputDeviceDataProducer { private readonly TestHostControllerConfiguration _testHostsInformation; private readonly PassiveNode? _passiveNode; @@ -76,12 +76,11 @@ protected override async Task InternalRunAsync() IConfiguration configuration = ServiceProvider.GetConfiguration(); try { - using IProcess currentProcess = process.GetCurrentProcess(); - int currentPID = currentProcess.Id; - string processIdString = currentPID.ToString(CultureInfo.InvariantCulture); + int currentPid = environment.ProcessId; + string processIdString = currentPid.ToString(CultureInfo.InvariantCulture); ExecutableInfo executableInfo = testApplicationModuleInfo.GetCurrentExecutableInfo(); - await _logger.LogDebugAsync($"Test host controller process info: {executableInfo}"); + await _logger.LogDebugAsync($"Test host controller process info: {executableInfo}").ConfigureAwait(false); List partialCommandLine = [ @@ -92,7 +91,7 @@ protected override async Task InternalRunAsync() // Prepare the environment variables used by the test host string processCorrelationId = Guid.NewGuid().ToString("N"); - await _logger.LogDebugAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_CORRELATIONID}_{currentPID} '{processCorrelationId}'"); + await _logger.LogDebugAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_CORRELATIONID}_{currentPid} '{processCorrelationId}'").ConfigureAwait(false); NamedPipeServer testHostControllerIpc = new( $"MONITORTOHOST_{Guid.NewGuid():N}", @@ -105,7 +104,7 @@ protected override async Task InternalRunAsync() #if NET8_0_OR_GREATER IEnumerable arguments = partialCommandLine; #else - string arguments = string.Join(" ", partialCommandLine); + string arguments = string.Join(' ', partialCommandLine); #endif #pragma warning disable CA1416 // Validate platform compatibility @@ -115,10 +114,10 @@ protected override async Task InternalRunAsync() { EnvironmentVariables = { - { $"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_CORRELATIONID}_{currentPID}", processCorrelationId }, - { $"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_PARENTPID}_{currentPID}", processIdString }, - { $"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_SKIPEXTENSION}_{currentPID}", "1" }, - { $"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_PIPENAME}_{currentPID}", testHostControllerIpc.PipeName.Name }, + { $"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_CORRELATIONID}_{currentPid}", processCorrelationId }, + { $"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_PARENTPID}_{currentPid}", processIdString }, + { $"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_SKIPEXTENSION}_{currentPid}", "1" }, + { $"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_PIPENAME}_{currentPid}", testHostControllerIpc.PipeName.Name }, }, #if !NETCOREAPP UseShellExecute = false, @@ -139,30 +138,30 @@ protected override async Task InternalRunAsync() IPushOnlyProtocol? pushOnlyProtocol = ServiceProvider.GetService(); if (pushOnlyProtocol?.IsServerMode == true) { - dataConsumersBuilder.Add(await pushOnlyProtocol.GetDataConsumerAsync()); + dataConsumersBuilder.Add(await pushOnlyProtocol.GetDataConsumerAsync().ConfigureAwait(false)); } // If we're in server mode jsonrpc we add as last consumer the PassiveNodeDataConsumer for the attachments. // Connect the passive node if it's available if (_passiveNode is not null) { - if (await _passiveNode.ConnectAsync()) + if (await _passiveNode.ConnectAsync().ConfigureAwait(false)) { dataConsumersBuilder.Add(new PassiveNodeDataConsumer(_passiveNode)); } else { - await _logger.LogWarningAsync("PassiveNode was expected to connect but failed"); + await _logger.LogWarningAsync("PassiveNode was expected to connect but failed").ConfigureAwait(false); } } AsynchronousMessageBus concreteMessageBusService = new( - dataConsumersBuilder.ToArray(), + [.. dataConsumersBuilder], ServiceProvider.GetTestApplicationCancellationTokenSource(), ServiceProvider.GetTask(), ServiceProvider.GetLoggerFactory(), ServiceProvider.GetEnvironment()); - await concreteMessageBusService.InitAsync(); + await concreteMessageBusService.InitAsync().ConfigureAwait(false); ((MessageBusProxy)ServiceProvider.GetMessageBus()).SetBuiltMessageBus(concreteMessageBusService); // Apply the ITestHostEnvironmentVariableProvider @@ -173,12 +172,12 @@ protected override async Task InternalRunAsync() { CurrentProvider = systemEnvironmentVariableProvider, }; - await systemEnvironmentVariableProvider.UpdateAsync(environmentVariables); + await systemEnvironmentVariableProvider.UpdateAsync(environmentVariables).ConfigureAwait(false); foreach (ITestHostEnvironmentVariableProvider environmentVariableProvider in _testHostsInformation.EnvironmentVariableProviders) { environmentVariables.CurrentProvider = environmentVariableProvider; - await environmentVariableProvider.UpdateAsync(environmentVariables); + await environmentVariableProvider.UpdateAsync(environmentVariables).ConfigureAwait(false); } environmentVariables.CurrentProvider = null; @@ -186,7 +185,7 @@ protected override async Task InternalRunAsync() List<(IExtension, string)> failedValidations = []; foreach (ITestHostEnvironmentVariableProvider hostEnvironmentVariableProvider in _testHostsInformation.EnvironmentVariableProviders) { - ValidationResult variableResult = await hostEnvironmentVariableProvider.ValidateTestHostEnvironmentVariablesAsync(environmentVariables); + ValidationResult variableResult = await hostEnvironmentVariableProvider.ValidateTestHostEnvironmentVariablesAsync(environmentVariables).ConfigureAwait(false); if (!variableResult.IsValid) { failedValidations.Add((hostEnvironmentVariableProvider, variableResult.ErrorMessage)); @@ -205,8 +204,8 @@ protected override async Task InternalRunAsync() displayErrorMessageBuilder.AppendLine(CultureInfo.InvariantCulture, $"Provider '{extension.DisplayName}' (UID: {extension.Uid}) failed with error: {errorMessage}"); } - await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(displayErrorMessageBuilder.ToString())); - await _logger.LogErrorAsync(logErrorMessageBuilder.ToString()); + await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(displayErrorMessageBuilder.ToString())).ConfigureAwait(false); + await _logger.LogErrorAsync(logErrorMessageBuilder.ToString()).ConfigureAwait(false); return ExitCodes.InvalidPlatformSetup; } @@ -223,18 +222,18 @@ protected override async Task InternalRunAsync() { foreach (ITestHostProcessLifetimeHandler lifetimeHandler in _testHostsInformation.LifetimeHandlers) { - await lifetimeHandler.BeforeTestHostProcessStartAsync(abortRun); + await lifetimeHandler.BeforeTestHostProcessStartAsync(abortRun).ConfigureAwait(false); } } // Launch the test host process string testHostProcessStartupTime = _clock.UtcNow.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture); #pragma warning disable CA1416 // Validate platform compatibility - processStartInfo.EnvironmentVariables.Add($"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_TESTHOSTPROCESSSTARTTIME}_{currentPID}", testHostProcessStartupTime); + processStartInfo.EnvironmentVariables.Add($"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_TESTHOSTPROCESSSTARTTIME}_{currentPid}", testHostProcessStartupTime); #pragma warning restore CA1416 - await _logger.LogDebugAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_TESTHOSTPROCESSSTARTTIME}_{currentPID} '{testHostProcessStartupTime}'"); + await _logger.LogDebugAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_TESTHOSTPROCESSSTARTTIME}_{currentPid} '{testHostProcessStartupTime}'").ConfigureAwait(false); #pragma warning disable CA1416 // Validate platform compatibility - await _logger.LogDebugAsync($"Starting test host process '{processStartInfo.FileName}' with args '{processStartInfo.Arguments}'"); + await _logger.LogDebugAsync($"Starting test host process '{processStartInfo.FileName}' with args '{processStartInfo.Arguments}'").ConfigureAwait(false); #pragma warning restore CA1416 using IProcess testHostProcess = process.Start(processStartInfo); @@ -252,24 +251,24 @@ protected override async Task InternalRunAsync() testHostProcess.Exited += (_, _) => _logger.LogDebug($"Test host process exited, PID: '{testHostProcessId}'"); - await _logger.LogDebugAsync($"Started test host process '{testHostProcessId}' HasExited: {testHostProcess.HasExited}"); + await _logger.LogDebugAsync($"Started test host process '{testHostProcessId}' HasExited: {testHostProcess.HasExited}").ConfigureAwait(false); if (testHostProcess.HasExited || testHostProcessId is null) { - await _logger.LogDebugAsync("Test host process exited prematurely"); + await _logger.LogDebugAsync("Test host process exited prematurely").ConfigureAwait(false); } else { string? seconds = configuration[PlatformConfigurationConstants.PlatformTestHostControllersManagerSingleConnectionNamedPipeServerWaitConnectionTimeoutSeconds]; int timeoutSeconds = seconds is null ? TimeoutHelper.DefaultHangTimeoutSeconds : int.Parse(seconds, CultureInfo.InvariantCulture); - await _logger.LogDebugAsync($"Setting PlatformTestHostControllersManagerSingleConnectionNamedPipeServerWaitConnectionTimeoutSeconds '{timeoutSeconds}'"); + await _logger.LogDebugAsync($"Setting PlatformTestHostControllersManagerSingleConnectionNamedPipeServerWaitConnectionTimeoutSeconds '{timeoutSeconds}'").ConfigureAwait(false); // Wait for the test host controller to connect using (CancellationTokenSource timeout = new(TimeSpan.FromSeconds(timeoutSeconds))) using (var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, abortRun)) { - await _logger.LogDebugAsync("Wait connection from the test host process"); - await testHostControllerIpc.WaitConnectionAsync(linkedToken.Token); + await _logger.LogDebugAsync("Wait connection from the test host process").ConfigureAwait(false); + await testHostControllerIpc.WaitConnectionAsync(linkedToken.Token).ConfigureAwait(false); } // Wait for the test host controller to send the PID of the test host process @@ -280,7 +279,7 @@ protected override async Task InternalRunAsync() #pragma warning restore CA1416 } - await _logger.LogDebugAsync("Fire OnTestHostProcessStartedAsync"); + await _logger.LogDebugAsync("Fire OnTestHostProcessStartedAsync").ConfigureAwait(false); if (_testHostPID is null) { @@ -290,22 +289,22 @@ protected override async Task InternalRunAsync() if (_testHostsInformation.LifetimeHandlers.Length > 0) { // We don't block the host during the 'OnTestHostProcessStartedAsync' by-design, if 'ITestHostProcessLifetimeHandler' extensions needs - // to block the execution of the test host should add an in-process extension like an 'ITestApplicationLifecycleCallbacks' and + // to block the execution of the test host should add an in-process extension like an 'ITestHostApplicationLifetime' and // wait for a connection/signal to return. TestHostProcessInformation testHostProcessInformation = new(_testHostPID.Value); foreach (ITestHostProcessLifetimeHandler lifetimeHandler in _testHostsInformation.LifetimeHandlers) { - await lifetimeHandler.OnTestHostProcessStartedAsync(testHostProcessInformation, abortRun); + await lifetimeHandler.OnTestHostProcessStartedAsync(testHostProcessInformation, abortRun).ConfigureAwait(false); } } - await _logger.LogDebugAsync("Wait for test host process exit"); - await testHostProcess.WaitForExitAsync(); + await _logger.LogDebugAsync("Wait for test host process exit").ConfigureAwait(false); + await testHostProcess.WaitForExitAsync().ConfigureAwait(false); } if (_testHostsInformation.LifetimeHandlers.Length > 0) { - await _logger.LogDebugAsync($"Fire OnTestHostProcessExitedAsync testHostGracefullyClosed: {_testHostGracefullyClosed}"); + await _logger.LogDebugAsync($"Fire OnTestHostProcessExitedAsync testHostGracefullyClosed: {_testHostGracefullyClosed}").ConfigureAwait(false); var messageBusProxy = (MessageBusProxy)ServiceProvider.GetMessageBus(); if (_testHostPID is not null) @@ -313,24 +312,24 @@ protected override async Task InternalRunAsync() TestHostProcessInformation testHostProcessInformation = new(_testHostPID.Value, testHostProcess.ExitCode, _testHostGracefullyClosed); foreach (ITestHostProcessLifetimeHandler lifetimeHandler in _testHostsInformation.LifetimeHandlers) { - await lifetimeHandler.OnTestHostProcessExitedAsync(testHostProcessInformation, abortRun); + await lifetimeHandler.OnTestHostProcessExitedAsync(testHostProcessInformation, abortRun).ConfigureAwait(false); // OnTestHostProcess could produce information that needs to be handled by others. - await messageBusProxy.DrainDataAsync(); + await messageBusProxy.DrainDataAsync().ConfigureAwait(false); } } // We disable after the drain because it's possible that the drain will produce more messages - await messageBusProxy.DrainDataAsync(); - await messageBusProxy.DisableAsync(); + await messageBusProxy.DrainDataAsync().ConfigureAwait(false); + await messageBusProxy.DisableAsync().ConfigureAwait(false); } - await outputDevice.DisplayAfterSessionEndRunAsync(); + await outputDevice.DisplayAfterSessionEndRunAsync().ConfigureAwait(false); // We collect info about the extensions before the dispose to avoid possible issue with cleanup. if (telemetryInformation.IsEnabled) { - extensionInformation = await ExtensionInformationCollector.CollectAndSerializeToJsonAsync(ServiceProvider); + extensionInformation = await ExtensionInformationCollector.CollectAndSerializeToJsonAsync(ServiceProvider).ConfigureAwait(false); } // If we have a process in the middle between the test host controller and the test host process we need to keep it into account. @@ -341,15 +340,15 @@ protected override async Task InternalRunAsync() if (!_testHostGracefullyClosed && !abortRun.IsCancellationRequested) { - await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.TestProcessDidNotExitGracefullyErrorMessage, exitCode))); + await outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.TestProcessDidNotExitGracefullyErrorMessage, exitCode))).ConfigureAwait(false); } - await _logger.LogInformationAsync($"TestHostControllersTestHost ended with exit code '{exitCode}' (real test host exit code '{testHostProcess.ExitCode}')' in '{consoleRunStarted.Elapsed}'"); - await DisposeHelper.DisposeAsync(testHostControllerIpc); + await _logger.LogInformationAsync($"TestHostControllersTestHost ended with exit code '{exitCode}' (real test host exit code '{testHostProcess.ExitCode}')' in '{consoleRunStarted.Elapsed}'").ConfigureAwait(false); + await DisposeHelper.DisposeAsync(testHostControllerIpc).ConfigureAwait(false); } finally { - await DisposeServicesAsync(); + await DisposeServicesAsync().ConfigureAwait(false); } if (telemetryInformation.IsEnabled) @@ -363,7 +362,7 @@ protected override async Task InternalRunAsync() [TelemetryProperties.HostProperties.ExitCodePropertyName] = exitCode.ToString(CultureInfo.InvariantCulture), [TelemetryProperties.HostProperties.HasExitedGracefullyPropertyName] = _testHostGracefullyClosed.AsTelemetryBool(), [TelemetryProperties.HostProperties.ExtensionsPropertyName] = extensionInformation, - }); + }).ConfigureAwait(false); } return exitCode; @@ -378,17 +377,17 @@ private async Task DisposeServicesAsync() foreach (ITestHostProcessLifetimeHandler service in lifetimeHandlers) { - await DisposeHelper.DisposeAsync(service); + await DisposeHelper.DisposeAsync(service).ConfigureAwait(false); alreadyDisposed.Add(service); } foreach (ITestHostEnvironmentVariableProvider service in variableProviders) { - await DisposeHelper.DisposeAsync(service); + await DisposeHelper.DisposeAsync(service).ConfigureAwait(false); alreadyDisposed.Add(service); } - await DisposeServiceProviderAsync(ServiceProvider, alreadyDisposed: alreadyDisposed); + await DisposeServiceProviderAsync(ServiceProvider, alreadyDisposed: alreadyDisposed).ConfigureAwait(false); } private Task HandleRequestAsync(IRequest request) diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostOchestratorHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostOchestratorHost.cs index 6eca7b889f..d6bbc13c86 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostOchestratorHost.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostOchestratorHost.cs @@ -8,7 +8,7 @@ namespace Microsoft.Testing.Platform.Hosts; -internal sealed class TestHostOrchestratorHost(TestHostOrchestratorConfiguration testHostOrchestratorConfiguration, ServiceProvider serviceProvider) : ITestHost +internal sealed class TestHostOrchestratorHost(TestHostOrchestratorConfiguration testHostOrchestratorConfiguration, ServiceProvider serviceProvider) : IHost { private readonly TestHostOrchestratorConfiguration _testHostOrchestratorConfiguration = testHostOrchestratorConfiguration; private readonly ServiceProvider _serviceProvider = serviceProvider; @@ -24,10 +24,21 @@ public async Task RunAsync() ITestHostOrchestrator testHostOrchestrator = _testHostOrchestratorConfiguration.TestHostOrchestrators[0]; ITestApplicationCancellationTokenSource applicationCancellationToken = _serviceProvider.GetTestApplicationCancellationTokenSource(); int exitCode; - await logger.LogInformationAsync($"Running test orchestrator '{testHostOrchestrator.Uid}'"); + await logger.LogInformationAsync($"Running test orchestrator '{testHostOrchestrator.Uid}'").ConfigureAwait(false); try { - exitCode = await testHostOrchestrator.OrchestrateTestHostExecutionAsync(); + foreach (ITestHostOrchestratorApplicationLifetime orchestratorLifetime in _serviceProvider.GetServicesInternal()) + { + await orchestratorLifetime.BeforeRunAsync(applicationCancellationToken.CancellationToken).ConfigureAwait(false); + } + + exitCode = await testHostOrchestrator.OrchestrateTestHostExecutionAsync().ConfigureAwait(false); + + foreach (ITestHostOrchestratorApplicationLifetime orchestratorLifetime in _serviceProvider.GetServicesInternal()) + { + await orchestratorLifetime.AfterRunAsync(exitCode, applicationCancellationToken.CancellationToken).ConfigureAwait(false); + await DisposeHelper.DisposeAsync(orchestratorLifetime).ConfigureAwait(false); + } } catch (OperationCanceledException) when (applicationCancellationToken.CancellationToken.IsCancellationRequested) { diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/ToolsTestHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/ToolsTestHost.cs index c4eb8aabb5..a8420a1ee8 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/ToolsTestHost.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/ToolsTestHost.cs @@ -12,11 +12,11 @@ namespace Microsoft.Testing.Platform.Hosts; -internal sealed class ToolsTestHost( +internal sealed class ToolsHost( IReadOnlyList toolsInformation, ServiceProvider serviceProvider, CommandLineHandler commandLineHandler, - IOutputDevice outputDevice) : ITestHost, IOutputDeviceDataProducer + IOutputDevice outputDevice) : IHost, IOutputDeviceDataProducer { private readonly IReadOnlyList _toolsInformation = toolsInformation; private readonly ServiceProvider _serviceProvider = serviceProvider; @@ -24,7 +24,7 @@ internal sealed class ToolsTestHost( private readonly IOutputDevice _outputDevice = outputDevice; /// - public string Uid => nameof(ToolsTestHost); + public string Uid => nameof(ToolsHost); /// public string Version => AppVersion.DefaultSemVer; @@ -60,30 +60,30 @@ public async Task RunAsync() { if (UnknownOptions(out string? unknownOptionsError, tool)) { - await _outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(unknownOptionsError)); + await _outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(unknownOptionsError)).ConfigureAwait(false); console.WriteLine(); return ExitCodes.InvalidCommandLine; } if (ExtensionArgumentArityAreInvalid(out string? arityErrors, tool)) { - await _outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(arityErrors)); + await _outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(arityErrors)).ConfigureAwait(false); return ExitCodes.InvalidCommandLine; } - ValidationResult optionsArgumentsValidationResult = await ValidateOptionsArgumentsAsync(tool); + ValidationResult optionsArgumentsValidationResult = await ValidateOptionsArgumentsAsync(tool).ConfigureAwait(false); if (!optionsArgumentsValidationResult.IsValid) { - await _outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(optionsArgumentsValidationResult.ErrorMessage)); + await _outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData(optionsArgumentsValidationResult.ErrorMessage)).ConfigureAwait(false); return ExitCodes.InvalidCommandLine; } - return await tool.RunAsync(); + return await tool.RunAsync().ConfigureAwait(false); } } - await _outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData($"Tool '{toolNameToRun}' not found in the list of registered tools.")); - await _commandLineHandler.PrintHelpAsync(_outputDevice); + await _outputDevice.DisplayAsync(this, new ErrorMessageOutputDeviceData($"Tool '{toolNameToRun}' not found in the list of registered tools.")).ConfigureAwait(false); + await _commandLineHandler.PrintHelpAsync(_outputDevice).ConfigureAwait(false); return ExitCodes.InvalidCommandLine; } @@ -164,7 +164,7 @@ private async Task ValidateOptionsArgumentsAsync(ITool tool) foreach (CommandLineParseOption optionRecord in _commandLineHandler.ParseResult.Options) { ICommandLineOptionsProvider extension = GetAllCommandLineOptionsProviderByOptionName(optionRecord.Name).Single(); - ValidationResult result = await extension.ValidateOptionArgumentsAsync(extension.GetCommandLineOptions().Single(x => x.Name == optionRecord.Name), optionRecord.Arguments); + ValidationResult result = await extension.ValidateOptionArgumentsAsync(extension.GetCommandLineOptions().Single(x => x.Name == optionRecord.Name), optionRecord.Arguments).ConfigureAwait(false); if (!result.IsValid) { stringBuilder.AppendLine(CultureInfo.InvariantCulture, $"Invalid arguments for option '--{optionRecord.Name}': {result.ErrorMessage}, tool {tool.DisplayName}"); diff --git a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeBase.cs b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeBase.cs index 4a12606676..c511303584 100644 --- a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeBase.cs +++ b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeBase.cs @@ -9,8 +9,8 @@ namespace Microsoft.Testing.Platform.IPC; internal abstract class NamedPipeBase { - private readonly Dictionary _typeSerializer = []; - private readonly Dictionary _idSerializer = []; + private readonly Dictionary _typeSerializer = []; + private readonly Dictionary _idSerializer = []; public void RegisterSerializer(INamedPipeSerializer namedPipeSerializer, Type type) { @@ -19,16 +19,16 @@ public void RegisterSerializer(INamedPipeSerializer namedPipeSerializer, Type ty } protected INamedPipeSerializer GetSerializer(int id) - => _idSerializer.TryGetValue(id, out object? serializer) - ? (INamedPipeSerializer)serializer + => _idSerializer.TryGetValue(id, out INamedPipeSerializer? serializer) + ? serializer : throw new ArgumentException(string.Format( CultureInfo.InvariantCulture, PlatformResources.NoSerializerRegisteredWithIdErrorMessage, id)); protected INamedPipeSerializer GetSerializer(Type type) - => _typeSerializer.TryGetValue(type, out object? serializer) - ? (INamedPipeSerializer)serializer + => _typeSerializer.TryGetValue(type, out INamedPipeSerializer? serializer) + ? serializer : throw new ArgumentException(string.Format( CultureInfo.InvariantCulture, PlatformResources.NoSerializerRegisteredWithTypeErrorMessage, diff --git a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeClient.cs b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeClient.cs index 39613088cd..1ea5418212 100644 --- a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeClient.cs +++ b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeClient.cs @@ -39,13 +39,13 @@ public NamedPipeClient(string name) public bool IsConnected => _namedPipeClientStream.IsConnected; public async Task ConnectAsync(CancellationToken cancellationToken) - => await _namedPipeClientStream.ConnectAsync(cancellationToken); + => await _namedPipeClientStream.ConnectAsync(cancellationToken).ConfigureAwait(false); public async Task RequestReplyAsync(TRequest request, CancellationToken cancellationToken) where TRequest : IRequest where TResponse : IResponse { - await _lock.WaitAsync(cancellationToken); + await _lock.WaitAsync(cancellationToken).ConfigureAwait(false); try { INamedPipeSerializer requestNamedPipeSerializer = GetSerializer(typeof(TRequest)); @@ -70,14 +70,14 @@ public async Task RequestReplyAsync(TRequest req try { ApplicationStateGuard.Ensure(BitConverter.TryWriteBytes(bytes, sizeOfTheWholeMessage), PlatformResources.UnexpectedExceptionDuringByteConversionErrorMessage); - await _messageBuffer.WriteAsync(bytes.AsMemory(0, sizeof(int)), cancellationToken); + await _messageBuffer.WriteAsync(bytes.AsMemory(0, sizeof(int)), cancellationToken).ConfigureAwait(false); } finally { ArrayPool.Shared.Return(bytes); } #else - await _messageBuffer.WriteAsync(BitConverter.GetBytes(sizeOfTheWholeMessage), 0, sizeof(int), cancellationToken); + await _messageBuffer.WriteAsync(BitConverter.GetBytes(sizeOfTheWholeMessage), 0, sizeof(int), cancellationToken).ConfigureAwait(false); #endif // Write the serializer id @@ -86,23 +86,23 @@ public async Task RequestReplyAsync(TRequest req try { ApplicationStateGuard.Ensure(BitConverter.TryWriteBytes(bytes, requestNamedPipeSerializer.Id), PlatformResources.UnexpectedExceptionDuringByteConversionErrorMessage); - await _messageBuffer.WriteAsync(bytes.AsMemory(0, sizeof(int)), cancellationToken); + await _messageBuffer.WriteAsync(bytes.AsMemory(0, sizeof(int)), cancellationToken).ConfigureAwait(false); } finally { ArrayPool.Shared.Return(bytes); } #else - await _messageBuffer.WriteAsync(BitConverter.GetBytes(requestNamedPipeSerializer.Id), 0, sizeof(int), cancellationToken); + await _messageBuffer.WriteAsync(BitConverter.GetBytes(requestNamedPipeSerializer.Id), 0, sizeof(int), cancellationToken).ConfigureAwait(false); #endif try { // Write the message #if NETCOREAPP - await _messageBuffer.WriteAsync(_serializationBuffer.GetBuffer().AsMemory(0, (int)_serializationBuffer.Position), cancellationToken); + await _messageBuffer.WriteAsync(_serializationBuffer.GetBuffer().AsMemory(0, (int)_serializationBuffer.Position), cancellationToken).ConfigureAwait(false); #else - await _messageBuffer.WriteAsync(_serializationBuffer.GetBuffer(), 0, (int)_serializationBuffer.Position, cancellationToken); + await _messageBuffer.WriteAsync(_serializationBuffer.GetBuffer(), 0, (int)_serializationBuffer.Position, cancellationToken).ConfigureAwait(false); #endif } finally @@ -115,11 +115,11 @@ public async Task RequestReplyAsync(TRequest req try { #if NETCOREAPP - await _namedPipeClientStream.WriteAsync(_messageBuffer.GetBuffer().AsMemory(0, (int)_messageBuffer.Position), cancellationToken); + await _namedPipeClientStream.WriteAsync(_messageBuffer.GetBuffer().AsMemory(0, (int)_messageBuffer.Position), cancellationToken).ConfigureAwait(false); #else - await _namedPipeClientStream.WriteAsync(_messageBuffer.GetBuffer(), 0, (int)_messageBuffer.Position, cancellationToken); + await _namedPipeClientStream.WriteAsync(_messageBuffer.GetBuffer(), 0, (int)_messageBuffer.Position, cancellationToken).ConfigureAwait(false); #endif - await _namedPipeClientStream.FlushAsync(cancellationToken); + await _namedPipeClientStream.FlushAsync(cancellationToken).ConfigureAwait(false); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { _namedPipeClientStream.WaitForPipeDrain(); @@ -139,9 +139,9 @@ public async Task RequestReplyAsync(TRequest req { int currentReadIndex = 0; #if NETCOREAPP - int currentReadBytes = await _namedPipeClientStream.ReadAsync(_readBuffer.AsMemory(currentReadIndex, _readBuffer.Length), cancellationToken); + int currentReadBytes = await _namedPipeClientStream.ReadAsync(_readBuffer.AsMemory(currentReadIndex, _readBuffer.Length), cancellationToken).ConfigureAwait(false); #else - int currentReadBytes = await _namedPipeClientStream.ReadAsync(_readBuffer, currentReadIndex, _readBuffer.Length, cancellationToken); + int currentReadBytes = await _namedPipeClientStream.ReadAsync(_readBuffer, currentReadIndex, _readBuffer.Length, cancellationToken).ConfigureAwait(false); #endif // Reset the current chunk size @@ -161,9 +161,9 @@ public async Task RequestReplyAsync(TRequest req { // We need to read the rest of the message #if NETCOREAPP - await _messageBuffer.WriteAsync(_readBuffer.AsMemory(currentReadIndex, missingBytesToReadOfCurrentChunk), cancellationToken); + await _messageBuffer.WriteAsync(_readBuffer.AsMemory(currentReadIndex, missingBytesToReadOfCurrentChunk), cancellationToken).ConfigureAwait(false); #else - await _messageBuffer.WriteAsync(_readBuffer, currentReadIndex, missingBytesToReadOfCurrentChunk, cancellationToken); + await _messageBuffer.WriteAsync(_readBuffer, currentReadIndex, missingBytesToReadOfCurrentChunk, cancellationToken).ConfigureAwait(false); #endif missingBytesToReadOfWholeMessage -= missingBytesToReadOfCurrentChunk; } @@ -223,9 +223,9 @@ public async ValueTask DisposeAsync() } _lock.Dispose(); - await _serializationBuffer.DisposeAsync(); - await _messageBuffer.DisposeAsync(); - await _namedPipeClientStream.DisposeAsync(); + await _serializationBuffer.DisposeAsync().ConfigureAwait(false); + await _messageBuffer.DisposeAsync().ConfigureAwait(false); + await _namedPipeClientStream.DisposeAsync().ConfigureAwait(false); _disposed = true; } #endif diff --git a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs index 8f59b1f817..0fb0d3a1f4 100644 --- a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs +++ b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs @@ -36,7 +36,7 @@ public NamedPipeServer( ILogger logger, ITask task, CancellationToken cancellationToken) - : this(GetPipeName(name), callback, environment, logger, task, cancellationToken) + : this(GetPipeName(name, environment), callback, environment, logger, task, cancellationToken) { } @@ -77,18 +77,25 @@ public NamedPipeServer( public async Task WaitConnectionAsync(CancellationToken cancellationToken) { - await _logger.LogDebugAsync($"Waiting for connection for the pipe name {PipeName.Name}"); + // NOTE: _cancellationToken field is usually the "test session" cancellation token. + // And cancellationToken parameter may have hang mitigating timeout. + // The parameter should only be used for the call of WaitForConnectionAsync and Task.Run call. + // NOTE: The cancellation token passed to Task.Run will only have effect before the task is started by runtime. + // Once it starts, it won't be considered. + // Then, for the internal loop, we should use _cancellationToken, because we don't know for how long the loop will run. + // So what we pass to InternalLoopAsync shouldn't have any timeout (it's usually linked to Ctrl+C). + await _logger.LogDebugAsync($"Waiting for connection for the pipe name {PipeName.Name}").ConfigureAwait(false); #pragma warning disable CA1416 // Validate platform compatibility - await _namedPipeServerStream.WaitForConnectionAsync(cancellationToken); + await _namedPipeServerStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); #pragma warning restore CA1416 WasConnected = true; - await _logger.LogDebugAsync($"Client connected to {PipeName.Name}"); + await _logger.LogDebugAsync($"Client connected to {PipeName.Name}").ConfigureAwait(false); _loopTask = _task.Run( async () => { try { - await InternalLoopAsync(_cancellationToken); + await InternalLoopAsync(_cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException ex) when (ex.CancellationToken == _cancellationToken) { @@ -96,7 +103,7 @@ public async Task WaitConnectionAsync(CancellationToken cancellationToken) } catch (Exception ex) { - await _logger.LogErrorAsync($"Exception on pipe: {PipeName.Name}", ex); + await _logger.LogErrorAsync($"Exception on pipe: {PipeName.Name}", ex).ConfigureAwait(false); _environment.FailFast($"[NamedPipeServer] Unhandled exception:{_environment.NewLine}{ex}", ex); } }, cancellationToken); @@ -117,10 +124,10 @@ private async Task InternalLoopAsync(CancellationToken cancellationToken) int currentReadIndex = 0; #if NET #pragma warning disable CA1416 // Validate platform compatibility - int currentReadBytes = await _namedPipeServerStream.ReadAsync(_readBuffer.AsMemory(currentReadIndex, _readBuffer.Length), cancellationToken); + int currentReadBytes = await _namedPipeServerStream.ReadAsync(_readBuffer.AsMemory(currentReadIndex, _readBuffer.Length), cancellationToken).ConfigureAwait(false); #pragma warning restore CA1416 #else - int currentReadBytes = await _namedPipeServerStream.ReadAsync(_readBuffer, currentReadIndex, _readBuffer.Length, cancellationToken); + int currentReadBytes = await _namedPipeServerStream.ReadAsync(_readBuffer, currentReadIndex, _readBuffer.Length, cancellationToken).ConfigureAwait(false); #endif if (currentReadBytes == 0) { @@ -145,9 +152,9 @@ private async Task InternalLoopAsync(CancellationToken cancellationToken) { // We need to read the rest of the message #if NET - await _messageBuffer.WriteAsync(_readBuffer.AsMemory(currentReadIndex, missingBytesToReadOfCurrentChunk), cancellationToken); + await _messageBuffer.WriteAsync(_readBuffer.AsMemory(currentReadIndex, missingBytesToReadOfCurrentChunk), cancellationToken).ConfigureAwait(false); #else - await _messageBuffer.WriteAsync(_readBuffer, currentReadIndex, missingBytesToReadOfCurrentChunk, cancellationToken); + await _messageBuffer.WriteAsync(_readBuffer, currentReadIndex, missingBytesToReadOfCurrentChunk, cancellationToken).ConfigureAwait(false); #endif missingBytesToReadOfWholeMessage -= missingBytesToReadOfCurrentChunk; } @@ -169,7 +176,7 @@ private async Task InternalLoopAsync(CancellationToken cancellationToken) var deserializedObject = (IRequest)requestNamedPipeSerializer.Deserialize(_messageBuffer); // Call the callback - IResponse response = await _callback(deserializedObject); + IResponse response = await _callback(deserializedObject).ConfigureAwait(false); // Write the message size _messageBuffer.Position = 0; @@ -194,14 +201,14 @@ private async Task InternalLoopAsync(CancellationToken cancellationToken) { ApplicationStateGuard.Ensure(BitConverter.TryWriteBytes(bytes, sizeOfTheWholeMessage), PlatformResources.UnexpectedExceptionDuringByteConversionErrorMessage); - await _messageBuffer.WriteAsync(bytes.AsMemory(0, sizeof(int)), cancellationToken); + await _messageBuffer.WriteAsync(bytes.AsMemory(0, sizeof(int)), cancellationToken).ConfigureAwait(false); } finally { ArrayPool.Shared.Return(bytes); } #else - await _messageBuffer.WriteAsync(BitConverter.GetBytes(sizeOfTheWholeMessage), 0, sizeof(int), cancellationToken); + await _messageBuffer.WriteAsync(BitConverter.GetBytes(sizeOfTheWholeMessage), 0, sizeof(int), cancellationToken).ConfigureAwait(false); #endif // Write the serializer id @@ -211,21 +218,21 @@ private async Task InternalLoopAsync(CancellationToken cancellationToken) { ApplicationStateGuard.Ensure(BitConverter.TryWriteBytes(bytes, responseNamedPipeSerializer.Id), PlatformResources.UnexpectedExceptionDuringByteConversionErrorMessage); - await _messageBuffer.WriteAsync(bytes.AsMemory(0, sizeof(int)), cancellationToken); + await _messageBuffer.WriteAsync(bytes.AsMemory(0, sizeof(int)), cancellationToken).ConfigureAwait(false); } finally { ArrayPool.Shared.Return(bytes); } #else - await _messageBuffer.WriteAsync(BitConverter.GetBytes(responseNamedPipeSerializer.Id), 0, sizeof(int), cancellationToken); + await _messageBuffer.WriteAsync(BitConverter.GetBytes(responseNamedPipeSerializer.Id), 0, sizeof(int), cancellationToken).ConfigureAwait(false); #endif // Write the message #if NET - await _messageBuffer.WriteAsync(_serializationBuffer.GetBuffer().AsMemory(0, (int)_serializationBuffer.Position), cancellationToken); + await _messageBuffer.WriteAsync(_serializationBuffer.GetBuffer().AsMemory(0, (int)_serializationBuffer.Position), cancellationToken).ConfigureAwait(false); #else - await _messageBuffer.WriteAsync(_serializationBuffer.GetBuffer(), 0, (int)_serializationBuffer.Position, cancellationToken); + await _messageBuffer.WriteAsync(_serializationBuffer.GetBuffer(), 0, (int)_serializationBuffer.Position, cancellationToken).ConfigureAwait(false); #endif // Send the message @@ -233,13 +240,13 @@ private async Task InternalLoopAsync(CancellationToken cancellationToken) { #if NET #pragma warning disable CA1416 // Validate platform compatibility - await _namedPipeServerStream.WriteAsync(_messageBuffer.GetBuffer().AsMemory(0, (int)_messageBuffer.Position), cancellationToken); + await _namedPipeServerStream.WriteAsync(_messageBuffer.GetBuffer().AsMemory(0, (int)_messageBuffer.Position), cancellationToken).ConfigureAwait(false); #pragma warning restore CA1416 #else - await _namedPipeServerStream.WriteAsync(_messageBuffer.GetBuffer(), 0, (int)_messageBuffer.Position, cancellationToken); + await _namedPipeServerStream.WriteAsync(_messageBuffer.GetBuffer(), 0, (int)_messageBuffer.Position, cancellationToken).ConfigureAwait(false); #endif #pragma warning disable CA1416 // Validate platform compatibility - await _namedPipeServerStream.FlushAsync(cancellationToken); + await _namedPipeServerStream.FlushAsync(cancellationToken).ConfigureAwait(false); #pragma warning restore CA1416 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -260,14 +267,16 @@ private async Task InternalLoopAsync(CancellationToken cancellationToken) } } - public static PipeNameDescription GetPipeName(string name) + public static PipeNameDescription GetPipeName(string name, IEnvironment environment) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return new PipeNameDescription($"testingplatform.pipe.{name.Replace('\\', '.')}", false); } - string directoryId = Path.Combine(Path.GetTempPath(), name); +#pragma warning disable RS0030 // Do not use banned APIs - We are using IEnvironment, but we still need the enum from the Environment class in BCL. This is safe. + string directoryId = Path.Combine(environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.None), name); +#pragma warning disable RS0030 // Do not use banned APIs Directory.CreateDirectory(directoryId); return new PipeNameDescription( !Directory.Exists(directoryId) @@ -332,7 +341,7 @@ public async ValueTask DisposeAsync() try { // To close gracefully we need to ensure that the client closed the stream line 103. - await _loopTask.WaitAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, _cancellationToken); + await _loopTask.WaitAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, _cancellationToken).ConfigureAwait(false); } catch (TimeoutException) { diff --git a/src/Platform/Microsoft.Testing.Platform/IPC/PipeNameDescription.cs b/src/Platform/Microsoft.Testing.Platform/IPC/PipeNameDescription.cs index d272b7f8ce..b8b6214612 100644 --- a/src/Platform/Microsoft.Testing.Platform/IPC/PipeNameDescription.cs +++ b/src/Platform/Microsoft.Testing.Platform/IPC/PipeNameDescription.cs @@ -10,20 +10,13 @@ internal sealed class PipeNameDescription(string name, bool isDirectory) : IDisp public string Name { get; } = name; - public void Dispose() => Dispose(true); - - public void Dispose(bool disposing) + public void Dispose() { if (_disposed) { return; } - if (disposing) - { - // TODO: dispose managed state (managed objects). - } - if (_isDirectory) { try diff --git a/src/Platform/Microsoft.Testing.Platform/IPC/Serializers/BaseSerializer.cs b/src/Platform/Microsoft.Testing.Platform/IPC/Serializers/BaseSerializer.cs index ee10295eae..5847336210 100644 --- a/src/Platform/Microsoft.Testing.Platform/IPC/Serializers/BaseSerializer.cs +++ b/src/Platform/Microsoft.Testing.Platform/IPC/Serializers/BaseSerializer.cs @@ -18,20 +18,12 @@ internal abstract class BaseSerializer protected static string ReadString(Stream stream) { Span len = stackalloc byte[sizeof(int)]; -#if NET7_0_OR_GREATER stream.ReadExactly(len); -#else - _ = stream.Read(len); -#endif int stringLen = BitConverter.ToInt32(len); byte[] bytes = ArrayPool.Shared.Rent(stringLen); try { -#if NET7_0_OR_GREATER stream.ReadExactly(bytes, 0, stringLen); -#else - _ = stream.Read(bytes, 0, stringLen); -#endif return Encoding.UTF8.GetString(bytes, 0, stringLen); } finally @@ -45,11 +37,7 @@ protected static string ReadStringValue(Stream stream, int size) byte[] bytes = ArrayPool.Shared.Rent(size); try { -#if NET7_0_OR_GREATER stream.ReadExactly(bytes, 0, size); -#else - _ = stream.Read(bytes, 0, size); -#endif return Encoding.UTF8.GetString(bytes, 0, size); } finally @@ -148,44 +136,28 @@ protected static void WriteBool(Stream stream, bool value) protected static int ReadInt(Stream stream) { Span bytes = stackalloc byte[sizeof(int)]; -#if NET7_0_OR_GREATER stream.ReadExactly(bytes); -#else - _ = stream.Read(bytes); -#endif return BitConverter.ToInt32(bytes); } protected static long ReadLong(Stream stream) { Span bytes = stackalloc byte[sizeof(long)]; -#if NET7_0_OR_GREATER stream.ReadExactly(bytes); -#else - _ = stream.Read(bytes); -#endif return BitConverter.ToInt64(bytes); } protected static ushort ReadShort(Stream stream) { Span bytes = stackalloc byte[sizeof(ushort)]; -#if NET7_0_OR_GREATER stream.ReadExactly(bytes); -#else - _ = stream.Read(bytes); -#endif return BitConverter.ToUInt16(bytes); } protected static bool ReadBool(Stream stream) { Span bytes = stackalloc byte[sizeof(bool)]; -#if NET7_0_OR_GREATER stream.ReadExactly(bytes); -#else - _ = stream.Read(bytes); -#endif return BitConverter.ToBoolean(bytes); } diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/FileLogger.cs b/src/Platform/Microsoft.Testing.Platform/Logging/FileLogger.cs index eeec19e5f5..bd824d507f 100644 --- a/src/Platform/Microsoft.Testing.Platform/Logging/FileLogger.cs +++ b/src/Platform/Microsoft.Testing.Platform/Logging/FileLogger.cs @@ -71,7 +71,7 @@ public FileLogger( if (_options.FileName is not null) { string fileNameFullPath = Path.Combine(_options.LogFolder, _options.FileName); - _fileStream = fileSystem.Exists(fileNameFullPath) + _fileStream = fileSystem.ExistFile(fileNameFullPath) ? OpenFileStreamForAppend(fileStreamFactory, fileNameFullPath) : CreateFileStream(fileStreamFactory, fileNameFullPath); } @@ -165,7 +165,7 @@ public async Task LogAsync(LogLevel logLevel, TState state, Exception? e { if (_options.SyncFlush) { - await InternalAsyncLogAsync(logLevel, state, exception, formatter, category); + await InternalAsyncLogAsync(logLevel, state, exception, formatter, category).ConfigureAwait(false); } else { @@ -180,14 +180,14 @@ private async Task InternalAsyncLogAsync(LogLevel logLevel, TState state return; } - if (!await _semaphore.WaitAsync(TimeoutHelper.DefaultHangTimeSpanTimeout)) + if (!await _semaphore.WaitAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false)) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.TimeoutAcquiringSemaphoreErrorMessage, TimeoutHelper.DefaultHangTimeoutSeconds)); } try { - await _writer.WriteLineAsync(BuildLogEntry(logLevel, state, exception, formatter, category)); + await _writer.WriteLineAsync(BuildLogEntry(logLevel, state, exception, formatter, category)).ConfigureAwait(false); } finally { @@ -232,16 +232,16 @@ private async Task WriteLogToFileAsync() { #if NETCOREAPP // We don't need cancellation token because the task will be stopped when the Channel is completed thanks to the call to Complete() inside the Dispose method. - while (await _channel.Reader.WaitToReadAsync()) + while (await _channel.Reader.WaitToReadAsync().ConfigureAwait(false)) { - await _writer.WriteLineAsync(await _channel.Reader.ReadAsync()); + await _writer.WriteLineAsync(await _channel.Reader.ReadAsync().ConfigureAwait(false)).ConfigureAwait(false); } #else // We don't need cancellation token because the task will be stopped when the BlockingCollection is completed thanks to the call to CompleteAdding() // inside the Dispose method. foreach (string message in _asyncLogs.GetConsumingEnumerable()) { - await _writer.WriteLineAsync(message); + await _writer.WriteLineAsync(message).ConfigureAwait(false); } #endif } @@ -312,13 +312,13 @@ public async ValueTask DisposeAsync() // Wait for all logs to be written _channel.Writer.TryComplete(); - await _logLoop.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout); + await _logLoop.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false); } _semaphore.Dispose(); - await _writer.FlushAsync(); - await _writer.DisposeAsync(); - await _fileStream.DisposeAsync(); + await _writer.FlushAsync().ConfigureAwait(false); + await _writer.DisposeAsync().ConfigureAwait(false); + await _fileStream.DisposeAsync().ConfigureAwait(false); _disposed = true; } #endif diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerCategory.cs b/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerCategory.cs index ea2c8f32b8..21b55b35b4 100644 --- a/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerCategory.cs +++ b/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerCategory.cs @@ -14,5 +14,5 @@ public void Log(LogLevel logLevel, TState state, Exception? exception, F => _fileLogger.Log(logLevel, state, exception, formatter, _category); public async Task LogAsync(LogLevel logLevel, TState state, Exception? exception, Func formatter) - => await _fileLogger.LogAsync(logLevel, state, exception, formatter, _category); + => await _fileLogger.LogAsync(logLevel, state, exception, formatter, _category).ConfigureAwait(false); } diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerInformation.cs b/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerInformation.cs index 2237492e9b..3651bc24b5 100644 --- a/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerInformation.cs +++ b/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerInformation.cs @@ -3,9 +3,9 @@ namespace Microsoft.Testing.Platform.Logging; -internal sealed record FileLoggerInformation(bool SyncronousWrite, FileInfo LogFile, LogLevel LogLevel) : IFileLoggerInformation +internal sealed record FileLoggerInformation(bool SynchronousWrite, FileInfo LogFile, LogLevel LogLevel) : IFileLoggerInformation { - public bool SyncronousWrite { get; init; } = SyncronousWrite; + public bool SynchronousWrite { get; init; } = SynchronousWrite; public FileInfo LogFile { get; init; } = LogFile; diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerProvider.cs b/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerProvider.cs index cbb4477319..b59a9bce0a 100644 --- a/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerProvider.cs +++ b/src/Platform/Microsoft.Testing.Platform/Logging/FileLoggerProvider.cs @@ -53,10 +53,10 @@ public async Task CheckLogFolderAndMoveToTheNewIfNeededAsync(string testResultDi } string fileName = Path.GetFileName(FileLogger.FileName); - await DisposeHelper.DisposeAsync(FileLogger); + await DisposeHelper.DisposeAsync(FileLogger).ConfigureAwait(false); // Move the log file to the new directory - _fileSystem.Move(FileLogger.FileName, Path.Combine(testResultDirectory, fileName)); + _fileSystem.MoveFile(FileLogger.FileName, Path.Combine(testResultDirectory, fileName)); FileLogger = new FileLogger( new FileLoggerOptions(testResultDirectory, _options.LogPrefixName, fileName, _options.SyncFlush), @@ -76,6 +76,6 @@ public void Dispose() #if NETCOREAPP public async ValueTask DisposeAsync() - => await FileLogger.DisposeAsync(); + => await FileLogger.DisposeAsync().ConfigureAwait(false); #endif } diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/IFIleLoggerInformation.cs b/src/Platform/Microsoft.Testing.Platform/Logging/IFIleLoggerInformation.cs index 1a77067d53..6f8867e8f4 100644 --- a/src/Platform/Microsoft.Testing.Platform/Logging/IFIleLoggerInformation.cs +++ b/src/Platform/Microsoft.Testing.Platform/Logging/IFIleLoggerInformation.cs @@ -5,7 +5,7 @@ namespace Microsoft.Testing.Platform.Logging; internal interface IFileLoggerInformation { - bool SyncronousWrite { get; } + bool SynchronousWrite { get; } FileInfo LogFile { get; } diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/Logger.cs b/src/Platform/Microsoft.Testing.Platform/Logging/Logger.cs index 539dc9dfb9..f63efc4eaf 100644 --- a/src/Platform/Microsoft.Testing.Platform/Logging/Logger.cs +++ b/src/Platform/Microsoft.Testing.Platform/Logging/Logger.cs @@ -28,7 +28,7 @@ public async Task LogAsync(LogLevel logLevel, TState state, Exception? e { if (logger.IsEnabled(logLevel)) { - await logger.LogAsync(logLevel, state, exception, formatter); + await logger.LogAsync(logLevel, state, exception, formatter).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactory.cs b/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactory.cs index 951e264d23..c431ec4921 100644 --- a/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactory.cs +++ b/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactory.cs @@ -41,7 +41,7 @@ private ILogger[] CreateLoggers(string categoryName) loggers.Add(loggerProvider.CreateLogger(categoryName)); } - return loggers.ToArray(); + return [.. loggers]; } public void Dispose() @@ -69,7 +69,7 @@ public async ValueTask DisposeAsync() continue; } - await asyncDisposable.DisposeAsync(); + await asyncDisposable.DisposeAsync().ConfigureAwait(false); } } #endif diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/LoggingManager.cs b/src/Platform/Microsoft.Testing.Platform/Logging/LoggingManager.cs index 5ce732043a..390d1fd698 100644 --- a/src/Platform/Microsoft.Testing.Platform/Logging/LoggingManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/Logging/LoggingManager.cs @@ -23,16 +23,16 @@ internal async Task BuildAsync(IServiceProvider serviceProvider, foreach (Func factory in _loggerProviderFullFactories) { ILoggerProvider serviceInstance = factory(logLevel, serviceProvider); - if (serviceInstance is IExtension extension && !await extension.IsEnabledAsync()) + if (serviceInstance is IExtension extension && !await extension.IsEnabledAsync().ConfigureAwait(false)) { continue; } - await serviceInstance.TryInitializeAsync(); + await serviceInstance.TryInitializeAsync().ConfigureAwait(false); loggerProviders.Add(serviceInstance); } - return new LoggerFactory(loggerProviders.ToArray(), logLevel, monitor); + return new LoggerFactory([.. loggerProviders], logLevel, monitor); } } diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/AsynchronousMessageBus.cs b/src/Platform/Microsoft.Testing.Platform/Messages/AsynchronousMessageBus.cs index b473a41956..973fc74926 100644 --- a/src/Platform/Microsoft.Testing.Platform/Messages/AsynchronousMessageBus.cs +++ b/src/Platform/Microsoft.Testing.Platform/Messages/AsynchronousMessageBus.cs @@ -42,13 +42,11 @@ public AsynchronousMessageBus( public override IDataConsumer[] DataConsumerServices => _dataConsumers; - public override async Task InitAsync() => await BuildConsumerProducersAsync(); - - private async Task BuildConsumerProducersAsync() + public override async Task InitAsync() { foreach (IDataConsumer consumer in _dataConsumers) { - if (!await consumer.IsEnabledAsync()) + if (!await consumer.IsEnabledAsync().ConfigureAwait(false)) { throw new InvalidOperationException($"Unexpected disabled IDataConsumer '{consumer}'"); } @@ -96,7 +94,7 @@ public override async Task PublishAsync(IDataProducer dataProducer, IData data) if (_isTraceLoggingEnabled) { - await LogDataAsync(dataProducer, data); + await LogDataAsync(dataProducer, data).ConfigureAwait(false); } Type dataType = data.GetType(); @@ -112,7 +110,7 @@ public override async Task PublishAsync(IDataProducer dataProducer, IData data) for (int i = 0; i < values.Count; i++) { - await values[i].PublishAsync(dataProducer, data); + await values[i].PublishAsync(dataProducer, data).ConfigureAwait(false); } } @@ -124,7 +122,7 @@ private async Task LogDataAsync(IDataProducer dataProducer, IData data) $"The producer '{dataProducer.DisplayName}' (ID: {dataProducer.Uid}) pushed data:"); messageBuilder.AppendLine(data.ToString()); - await _logger.LogTraceAsync(messageBuilder.ToString()); + await _logger.LogTraceAsync(messageBuilder.ToString()).ConfigureAwait(false); } public override async Task DrainDataAsync() @@ -165,12 +163,9 @@ public override async Task DrainDataAsync() { foreach (AsyncConsumerDataProcessor asyncMultiProducerMultiConsumerDataProcessor in dataProcessors) { - if (!consumerToDrain.TryGetValue(asyncMultiProducerMultiConsumerDataProcessor, out long _)) - { - consumerToDrain.Add(asyncMultiProducerMultiConsumerDataProcessor, 0); - } + consumerToDrain.TryAdd(asyncMultiProducerMultiConsumerDataProcessor, 0); - long totalPayloadReceived = await asyncMultiProducerMultiConsumerDataProcessor.DrainDataAsync(); + long totalPayloadReceived = await asyncMultiProducerMultiConsumerDataProcessor.DrainDataAsync().ConfigureAwait(false); if (consumerToDrain[asyncMultiProducerMultiConsumerDataProcessor] != totalPayloadReceived) { consumerToDrain[asyncMultiProducerMultiConsumerDataProcessor] = totalPayloadReceived; @@ -194,7 +189,7 @@ public override async Task DisableAsync() { foreach (AsyncConsumerDataProcessor asyncMultiProducerMultiConsumerDataProcessor in dataProcessors) { - await asyncMultiProducerMultiConsumerDataProcessor.CompleteAddingAsync(); + await asyncMultiProducerMultiConsumerDataProcessor.CompleteAddingAsync().ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/ChannelConsumerDataProcessor.cs b/src/Platform/Microsoft.Testing.Platform/Messages/ChannelConsumerDataProcessor.cs index 2982aeed35..1c568abd55 100644 --- a/src/Platform/Microsoft.Testing.Platform/Messages/ChannelConsumerDataProcessor.cs +++ b/src/Platform/Microsoft.Testing.Platform/Messages/ChannelConsumerDataProcessor.cs @@ -47,16 +47,16 @@ public AsyncConsumerDataProcessor(IDataConsumer consumer, ITask task, Cancellati public async Task PublishAsync(IDataProducer dataProducer, IData data) { Interlocked.Increment(ref _totalPayloadReceived); - await _channel.Writer.WriteAsync((dataProducer, data), _cancellationToken); + await _channel.Writer.WriteAsync((dataProducer, data), _cancellationToken).ConfigureAwait(false); } private async Task ConsumeAsync() { try { - while (await _channel.Reader.WaitToReadAsync(_cancellationToken)) + while (await _channel.Reader.WaitToReadAsync(_cancellationToken).ConfigureAwait(false)) { - (IDataProducer dataProducer, IData data) = await _channel.Reader.ReadAsync(_cancellationToken); + (IDataProducer dataProducer, IData data) = await _channel.Reader.ReadAsync(_cancellationToken).ConfigureAwait(false); try { @@ -70,7 +70,7 @@ private async Task ConsumeAsync() try { - await DataConsumer.ConsumeAsync(dataProducer, data, _cancellationToken); + await DataConsumer.ConsumeAsync(dataProducer, data, _cancellationToken).ConfigureAwait(false); } // We let the catch below to handle the graceful cancellation of the process @@ -118,7 +118,7 @@ public async Task CompleteAddingAsync() _channel.Writer.TryComplete(); // Wait for the consumer to complete - await _consumeTask; + await _consumeTask.ConfigureAwait(false); } public async Task DrainDataAsync() @@ -136,13 +136,13 @@ public async Task DrainDataAsync() break; } - await _task.Delay(currentDelayTimeMs); + await _task.Delay(currentDelayTimeMs).ConfigureAwait(false); currentDelayTimeMs = Math.Min(currentDelayTimeMs + minDelayTimeMs, 200); if (_consumerState.Task.IsFaulted) { // Rethrow the exception - await _consumerState.Task; + await _consumerState.Task.ConfigureAwait(false); } // Wait for the consumer to complete the current enqueued items @@ -154,7 +154,7 @@ public async Task DrainDataAsync() if (_consumerState.Task.IsFaulted) { // Rethrow the exception - await _consumerState.Task; + await _consumerState.Task.ConfigureAwait(false); } return _totalPayloadReceived; diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/ConsumingEnumerableConsumerDataProcessor.cs b/src/Platform/Microsoft.Testing.Platform/Messages/ConsumingEnumerableConsumerDataProcessor.cs index fd0cf91171..f2cc853b00 100644 --- a/src/Platform/Microsoft.Testing.Platform/Messages/ConsumingEnumerableConsumerDataProcessor.cs +++ b/src/Platform/Microsoft.Testing.Platform/Messages/ConsumingEnumerableConsumerDataProcessor.cs @@ -59,7 +59,7 @@ private async Task ConsumeAsync() try { - await DataConsumer.ConsumeAsync(dataProducer, data, _cancellationToken); + await DataConsumer.ConsumeAsync(dataProducer, data, _cancellationToken).ConfigureAwait(false); } // We let the catch below to handle the graceful cancellation of the process @@ -125,13 +125,13 @@ public async Task DrainDataAsync() break; } - await _task.Delay(currentDelayTimeMs); + await _task.Delay(currentDelayTimeMs).ConfigureAwait(false); currentDelayTimeMs = Math.Min(currentDelayTimeMs + minDelayTimeMs, 200); if (_consumerState.Task.IsFaulted) { // Rethrow the exception - await _consumerState.Task; + await _consumerState.Task.ConfigureAwait(false); } // Wait for the consumer to complete the current enqueued items @@ -143,7 +143,7 @@ public async Task DrainDataAsync() if (_consumerState.Task.IsFaulted) { // Rethrow the exception - await _consumerState.Task; + await _consumerState.Task.ConfigureAwait(false); } return _totalPayloadReceived; @@ -155,7 +155,7 @@ public async Task CompleteAddingAsync() _payloads.CompleteAdding(); // Wait for the consumer to complete - await _consumeTask; + await _consumeTask.ConfigureAwait(false); } public void Dispose() diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/MessageBusProxy.cs b/src/Platform/Microsoft.Testing.Platform/Messages/MessageBusProxy.cs index 20f550e813..bf1e01743f 100644 --- a/src/Platform/Microsoft.Testing.Platform/Messages/MessageBusProxy.cs +++ b/src/Platform/Microsoft.Testing.Platform/Messages/MessageBusProxy.cs @@ -16,7 +16,7 @@ public override IDataConsumer[] DataConsumerServices public override async Task InitAsync() { EnsureMessageBusAvailable(); - await _messageBus.InitAsync(); + await _messageBus.InitAsync().ConfigureAwait(false); } public void SetBuiltMessageBus(BaseMessageBus messageBus) @@ -28,19 +28,19 @@ public void SetBuiltMessageBus(BaseMessageBus messageBus) public override async Task PublishAsync(IDataProducer dataProducer, IData data) { EnsureMessageBusAvailable(); - await _messageBus.PublishAsync(dataProducer, data); + await _messageBus.PublishAsync(dataProducer, data).ConfigureAwait(false); } public override async Task DrainDataAsync() { EnsureMessageBusAvailable(); - await _messageBus.DrainDataAsync(); + await _messageBus.DrainDataAsync().ConfigureAwait(false); } public override async Task DisableAsync() { EnsureMessageBusAvailable(); - await _messageBus.DisableAsync(); + await _messageBus.DisableAsync().ConfigureAwait(false); } [MemberNotNull(nameof(_messageBus))] diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.Property.cs b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.Property.cs index 0594ffa307..c0401e55a1 100644 --- a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.Property.cs +++ b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.Property.cs @@ -147,6 +147,6 @@ public PropertyDebugView(Property property) } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public IProperty[] Items => _property.AsEnumerable().ToArray(); + public IProperty[] Items => [.. _property.AsEnumerable()]; } } diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs index c3d1e03d24..b8c0905ce1 100644 --- a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs +++ b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs @@ -230,7 +230,7 @@ public TProperty Single() throw new InvalidOperationException($"Could not find a property of type '{typeof(TProperty)}'."); } - IEnumerable matchingValues = _property is null ? Array.Empty() : _property.OfType(); + IEnumerable matchingValues = _property is null ? [] : _property.OfType(); return !matchingValues.Any() ? throw new InvalidOperationException($"Could not find a property of type '{typeof(TProperty)}'.") @@ -255,7 +255,7 @@ public TProperty[] OfType() // We don't want to allocate an array if we know that we're looking for a TestNodeStateProperty return typeof(TestNodeStateProperty).IsAssignableFrom(typeof(TProperty)) ? [] - : _property is null ? [] : _property.OfType().ToArray(); + : _property is null ? [] : [.. _property.OfType()]; } /// diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs b/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs index 858f1b53a0..0a0de9b2b3 100644 --- a/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs +++ b/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs @@ -13,6 +13,7 @@ public interface IProperty; /// /// Key name. /// Key value. +[Obsolete("Use TestMetadataProperty instead. This will be removed in a future version.")] public record KeyValuePairStringProperty(string Key, string Value) : IProperty; /// @@ -415,4 +416,6 @@ public record StandardErrorProperty(string StandardError) : IProperty; /// The description. public record FileArtifactProperty(FileInfo FileInfo, string DisplayName, string? Description = null) : IProperty; +#pragma warning disable CS0618 // Type or member is obsolete internal sealed record SerializableKeyValuePairStringProperty(string Key, string Value) : KeyValuePairStringProperty(Key, Value); +#pragma warning restore CS0618 // Type or member is obsolete diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/BrowserOutputDevice.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/BrowserOutputDevice.cs index e215879c04..603c8dc38d 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/BrowserOutputDevice.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/BrowserOutputDevice.cs @@ -93,7 +93,7 @@ public async Task InitializeAsync() { ConsoleLog(PlatformResources.CancellingTestSession); return Task.CompletedTask; - }); + }).ConfigureAwait(false); public Type[] DataTypesConsumed { get; } = [ @@ -103,23 +103,23 @@ public async Task InitializeAsync() ]; /// - public string Uid { get; } = nameof(BrowserOutputDevice); + public string Uid => nameof(BrowserOutputDevice); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// - public string DisplayName { get; } = "Test Platform Browser Console Service"; + public string DisplayName => "Test Platform Browser Console Service"; /// - public string Description { get; } = "Test Platform default browser console service"; + public string Description => "Test Platform default browser console service"; /// public Task IsEnabledAsync() => Task.FromResult(true); public async Task DisplayBannerAsync(string? bannerMessage) { - using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout)) + using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false)) { if (_bannerDisplayed) { @@ -202,7 +202,7 @@ private static void AppendAssemblyLinkTargetFrameworkAndArchitecture(IConsole co public async Task DisplayAfterSessionEndRunAsync() { - using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout)) + using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false)) { if (_firstCallTo_OnSessionStartingAsync) { @@ -257,7 +257,7 @@ public Task OnTestSessionStartingAsync(SessionUid sessionUid, CancellationToken /// The data to be displayed. public async Task DisplayAsync(IOutputDeviceDataProducer producer, IOutputDeviceData data) { - using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout)) + using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false)) { switch (data) { @@ -398,7 +398,7 @@ public async Task HandleProcessRoleAsync(TestProcessRole processRole) { await _policiesService.RegisterOnMaxFailedTestsCallbackAsync( async (maxFailedTests, _) => await DisplayAsync( - this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ReachedMaxFailedTestsMessage, maxFailedTests)))); + this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ReachedMaxFailedTestsMessage, maxFailedTests))).ConfigureAwait(false)).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceManager.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceManager.cs index 87ae5097ea..bd791add93 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceManager.cs @@ -26,7 +26,7 @@ internal async Task BuildAsync(ServiceProvider serviceProvide : _platformOutputDeviceFactory(serviceProvider); // If the externally provided output device is not enabled, we opt-in the default terminal output device. - if (_platformOutputDeviceFactory is not null && !await nonServerOutputDevice.IsEnabledAsync()) + if (_platformOutputDeviceFactory is not null && !await nonServerOutputDevice.IsEnabledAsync().ConfigureAwait(false)) { nonServerOutputDevice = GetDefaultTerminalOutputDevice(serviceProvider); } @@ -62,5 +62,6 @@ public static IPlatformOutputDevice GetDefaultTerminalOutputDevice(ServiceProvid serviceProvider.GetFileLoggerInformation(), serviceProvider.GetLoggerFactory(), serviceProvider.GetClock(), - serviceProvider.GetRequiredService()); + serviceProvider.GetRequiredService(), + serviceProvider.GetTestApplicationCancellationTokenSource()); } diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/ProxyOutputDevice.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/ProxyOutputDevice.cs index b2d0b2ed4c..4987ac93a8 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/ProxyOutputDevice.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/ProxyOutputDevice.cs @@ -21,37 +21,37 @@ public ProxyOutputDevice(IPlatformOutputDevice originalOutputDevice, ServerModeP public async Task DisplayAsync(IOutputDeviceDataProducer producer, IOutputDeviceData data) { - await OriginalOutputDevice.DisplayAsync(producer, data); + await OriginalOutputDevice.DisplayAsync(producer, data).ConfigureAwait(false); if (_serverModeOutputDevice is not null) { - await _serverModeOutputDevice.DisplayAsync(producer, data); + await _serverModeOutputDevice.DisplayAsync(producer, data).ConfigureAwait(false); } } internal async Task DisplayBannerAsync(string? bannerMessage) { - await OriginalOutputDevice.DisplayBannerAsync(bannerMessage); + await OriginalOutputDevice.DisplayBannerAsync(bannerMessage).ConfigureAwait(false); if (_serverModeOutputDevice is not null) { - await _serverModeOutputDevice.DisplayBannerAsync(bannerMessage); + await _serverModeOutputDevice.DisplayBannerAsync(bannerMessage).ConfigureAwait(false); } } internal async Task DisplayBeforeSessionStartAsync() { - await OriginalOutputDevice.DisplayBeforeSessionStartAsync(); + await OriginalOutputDevice.DisplayBeforeSessionStartAsync().ConfigureAwait(false); if (_serverModeOutputDevice is not null) { - await _serverModeOutputDevice.DisplayBeforeSessionStartAsync(); + await _serverModeOutputDevice.DisplayBeforeSessionStartAsync().ConfigureAwait(false); } } internal async Task DisplayAfterSessionEndRunAsync() { - await OriginalOutputDevice.DisplayAfterSessionEndRunAsync(); + await OriginalOutputDevice.DisplayAfterSessionEndRunAsync().ConfigureAwait(false); if (_serverModeOutputDevice is not null) { - await _serverModeOutputDevice.DisplayAfterSessionEndRunAsync(); + await _serverModeOutputDevice.DisplayAfterSessionEndRunAsync().ConfigureAwait(false); } } @@ -59,16 +59,16 @@ internal async Task InitializeAsync(ServerTestHost serverTestHost) { if (_serverModeOutputDevice is not null) { - await _serverModeOutputDevice.InitializeAsync(serverTestHost); + await _serverModeOutputDevice.InitializeAsync(serverTestHost).ConfigureAwait(false); } } internal async Task HandleProcessRoleAsync(TestProcessRole processRole) { - await OriginalOutputDevice.HandleProcessRoleAsync(processRole); + await OriginalOutputDevice.HandleProcessRoleAsync(processRole).ConfigureAwait(false); if (_serverModeOutputDevice is not null) { - await _serverModeOutputDevice.HandleProcessRoleAsync(processRole); + await _serverModeOutputDevice.HandleProcessRoleAsync(processRole).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiDetector.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiDetector.cs index 5dd4b3e884..9c1b06e283 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiDetector.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiDetector.cs @@ -13,7 +13,7 @@ namespace Microsoft.Testing.Platform.OutputDevice.Terminal; internal static class AnsiDetector { private static readonly Regex[] TerminalsRegexes = - { + [ new("^xterm"), // xterm, PuTTY, Mintty new("^rxvt"), // RXVT new("^(?!eterm-color).*eterm.*"), // Accepts eterm, but not eterm-color, which does not support moving the cursor, see #9950. @@ -30,8 +30,8 @@ internal static class AnsiDetector new("konsole"), // Konsole new("bvterm"), // Bitvise SSH Client new("^st-256color"), // Suckless Simple Terminal, st - new("alacritty"), // Alacritty - }; + new("alacritty") // Alacritty + ]; public static bool IsAnsiSupported(string? termType) => !RoslynString.IsNullOrEmpty(termType) && TerminalsRegexes.Any(regex => regex.IsMatch(termType)); diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminal.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminal.cs index 4e8e511e22..20ffd4af20 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminal.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminal.cs @@ -16,8 +16,8 @@ internal sealed class AnsiTerminal : ITerminal /// File extensions that we will link to directly, all other files /// are linked to their directory, to avoid opening dlls, or executables. /// - private static readonly string[] KnownFileExtensions = new string[] - { + private static readonly string[] KnownFileExtensions = + [ // code files ".cs", ".vb", @@ -33,8 +33,8 @@ internal sealed class AnsiTerminal : ITerminal ".nunit", ".trx", ".xml", - ".xunit", - }; + ".xunit" + ]; private readonly IConsole _console; private readonly string? _baseDirectory; @@ -43,10 +43,10 @@ internal sealed class AnsiTerminal : ITerminal private bool _isBatching; private AnsiTerminalTestProgressFrame _currentFrame = new(0, 0); - public AnsiTerminal(IConsole console, string? baseDirectory) + public AnsiTerminal(IConsole console) { _console = console; - _baseDirectory = baseDirectory ?? Directory.GetCurrentDirectory(); + _baseDirectory = Directory.GetCurrentDirectory(); // Output ansi code to get spinner on top of a terminal, to indicate in-progress task. // https://github.com/dotnet/msbuild/issues/8958: iTerm2 treats ;9 code to post a notification instead, so disable progress reporting on Mac. diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs index 6489512a6b..272e73c412 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs @@ -37,7 +37,7 @@ public void AppendTestWorkerProgress(TestProgressState progress, RenderedProgres terminal.Append('['); charsTaken++; - terminal.SetColor(TerminalColor.Green); + terminal.SetColor(TerminalColor.DarkGreen); terminal.Append('✓'); charsTaken++; string passedText = passed.ToString(CultureInfo.CurrentCulture); @@ -48,7 +48,7 @@ public void AppendTestWorkerProgress(TestProgressState progress, RenderedProgres terminal.Append('/'); charsTaken++; - terminal.SetColor(TerminalColor.Red); + terminal.SetColor(TerminalColor.DarkRed); terminal.Append('x'); charsTaken++; string failedText = failed.ToString(CultureInfo.CurrentCulture); @@ -59,7 +59,7 @@ public void AppendTestWorkerProgress(TestProgressState progress, RenderedProgres terminal.Append('/'); charsTaken++; - terminal.SetColor(TerminalColor.Yellow); + terminal.SetColor(TerminalColor.DarkYellow); terminal.Append('↓'); charsTaken++; string skippedText = skipped.ToString(CultureInfo.CurrentCulture); @@ -308,7 +308,7 @@ private List GenerateLinesToRender(TestProgressState?[] progress) // Note: We want to render the list of active tests, but this can easily fill up the full screen. // As such, we should balance the number of active tests shown per project. // We do this by distributing the remaining lines for each projects. - TestProgressState[] progressItems = progress.OfType().ToArray(); + TestProgressState[] progressItems = [.. progress.OfType()]; int linesToDistribute = (int)(Height * 0.7) - 1 - progressItems.Length; var detailItems = new IEnumerable[progressItems.Length]; IEnumerable sortedItemsIndices = Enumerable.Range(0, progressItems.Length).OrderBy(i => progressItems[i].TestNodeResultsState?.Count ?? 0); @@ -317,7 +317,7 @@ private List GenerateLinesToRender(TestProgressState?[] progress) { detailItems[sortedItemIndex] = progressItems[sortedItemIndex].TestNodeResultsState?.GetRunningTasks( linesToDistribute / progressItems.Length) - ?? Array.Empty(); + ?? []; } for (int progressI = 0; progressI < progressItems.Length; progressI++) diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/ExceptionFlattener.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/ExceptionFlattener.cs index 5e0a406ab8..929a2d6ed4 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/ExceptionFlattener.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/ExceptionFlattener.cs @@ -9,7 +9,7 @@ internal static FlatException[] Flatten(string? errorMessage, Exception? excepti { if (errorMessage is null && exception is null) { - return Array.Empty(); + return []; } string? message = !RoslynString.IsNullOrWhiteSpace(errorMessage) ? errorMessage : exception?.Message; @@ -17,10 +17,7 @@ internal static FlatException[] Flatten(string? errorMessage, Exception? excepti string? stackTrace = exception?.StackTrace; var flatException = new FlatException(message, type, stackTrace); - List flatExceptions = new() - { - flatException, - }; + List flatExceptions = [flatException]; // Add all inner exceptions. This will flatten top level AggregateExceptions, // and all AggregateExceptions that are directly in AggregateExceptions, but won't expand @@ -45,7 +42,7 @@ internal static FlatException[] Flatten(string? errorMessage, Exception? excepti } } - return flatExceptions.ToArray(); + return [.. flatExceptions]; } } diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/NonAnsiTerminal.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/NonAnsiTerminal.cs index 11af53dc1e..78b26ac13d 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/NonAnsiTerminal.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/NonAnsiTerminal.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Testing.Platform.Helpers; -using Microsoft.Testing.Platform.Resources; namespace Microsoft.Testing.Platform.OutputDevice.Terminal; @@ -10,143 +9,48 @@ namespace Microsoft.Testing.Platform.OutputDevice.Terminal; /// Non-ANSI terminal that writes text using the standard Console.Foreground color capabilities to stay compatible with /// standard Windows command line, and other command lines that are not capable of ANSI, or when output is redirected. /// -internal sealed class NonAnsiTerminal : ITerminal +internal sealed class NonAnsiTerminal : SimpleTerminal { - private readonly IConsole _console; private readonly ConsoleColor _defaultForegroundColor; - private bool _isBatching; - private object? _batchingLock; + private bool? _colorNotSupported; public NonAnsiTerminal(IConsole console) - { - _console = console; - _defaultForegroundColor = IsForegroundColorNotSupported() ? ConsoleColor.Black : _console.GetForegroundColor(); - } - -#pragma warning disable CA1416 // Validate platform compatibility - public int Width => _console.IsOutputRedirected ? int.MaxValue : _console.BufferWidth; - - public int Height => _console.IsOutputRedirected ? int.MaxValue : _console.BufferHeight; -#pragma warning restore CA1416 // Validate platform compatibility - - public void Append(char value) - => _console.Write(value); - - public void Append(string value) - => _console.Write(value); - - public void AppendLine() - => _console.WriteLine(); - - public void AppendLine(string value) - => _console.WriteLine(value); - - public void AppendLink(string path, int? lineNumber) - { - Append(path); - if (lineNumber.HasValue) - { - Append($":{lineNumber}"); - } - } + : base(console) + => _defaultForegroundColor = IsForegroundColorNotSupported() ? ConsoleColor.Black : console.GetForegroundColor(); - public void SetColor(TerminalColor color) + public override void SetColor(TerminalColor color) { if (IsForegroundColorNotSupported()) { return; } - _console.SetForegroundColor(ToConsoleColor(color)); + Console.SetForegroundColor(ToConsoleColor(color)); } - public void ResetColor() + public override void ResetColor() { if (IsForegroundColorNotSupported()) { return; } - _console.SetForegroundColor(_defaultForegroundColor); - } - - public void ShowCursor() - { - // nop + Console.SetForegroundColor(_defaultForegroundColor); } - public void HideCursor() - { - // nop - } - - // TODO: Refactor NonAnsiTerminal and AnsiTerminal such that we don't need StartUpdate/StopUpdate. - // It's much better if we use lock C# keyword instead of manually calling Monitor.Enter/Exit - // Using lock also ensures we don't accidentally have `await`s in between that could cause Exit to be on a different thread. - public void StartUpdate() + [SupportedOSPlatformGuard("android")] + [SupportedOSPlatformGuard("ios")] + [SupportedOSPlatformGuard("tvos")] + [SupportedOSPlatformGuard("browser")] + private bool IsForegroundColorNotSupported() { - if (_isBatching) - { - throw new InvalidOperationException(PlatformResources.ConsoleIsAlreadyInBatchingMode); - } - - bool lockTaken = false; - - // We store Console.Out in a field to make sure we will be doing - // the Monitor.Exit call on the same instance. - _batchingLock = Console.Out; - - // Note that we need to lock on System.Out for batching to work correctly. - // Consider the following scenario: - // 1. We call StartUpdate - // 2. We call a Write("A") - // 3. User calls Console.Write("B") from another thread. - // 4. We call a Write("C"). - // 5. We call StopUpdate. - // The expectation is that we see either ACB, or BAC, but not ABC. - // Basically, when doing batching, we want to ensure that everything we write is - // written continuously, without anything in-between. - // One option (and we used to do it), is that we append to a StringBuilder while batching - // Then at StopUpdate, we write the whole string at once. - // This works to some extent, but we cannot get it to work when SetColor kicks in. - // Console methods will internally lock on Console.Out, so we are locking on the same thing. - // This locking is the easiest way to get coloring to work correctly while preventing - // interleaving with user's calls to Console.Write methods. - // One extra note: - // It's very important to lock on Console.Out (the current Console.Out). - // Consider the following scenario: - // 1. SystemConsole captures the original Console.Out set by runtime. - // 2. Framework author sets his own Console.Out which wraps the original Console.Out. - // 3. Two threads are writing concurrently: - // - One thread is writing using Console.Write* APIs, which will use the Console.Out set by framework author. - // - The other thread is writing using NonAnsiTerminal. - // 4. **If** we lock the original Console.Out. The following may happen (subject to race) [NOT THE CURRENT CASE - imaginary situation if we lock on the original Console.Out]: - // - First thread enters the Console.Write, which will acquire the lock for the current Console.Out (set by framework author). - // - Second thread executes StartUpdate, and acquires the lock for the original Console.Out. - // - First thread continues in the Write implementation of the framework author, which tries to run Console.Write on the original Console.Out. - // - First thread can't make any progress, because the second thread is holding the lock already. - // - Second thread continues execution, and reaches into runtime code (ConsolePal.WriteFromConsoleStream - on Unix) which tries to acquire the lock for the current Console.Out (set by framework author). - // - (see https://github.com/dotnet/runtime/blob/8a9d492444f06df20fcc5dfdcf7a6395af18361f/src/libraries/System.Console/src/System/ConsolePal.Unix.cs#L963) - // - No thread can progress. - // - Basically, what happened is that the first thread acquires the lock for current Console.Out, then for the original Console.Out. - // - while the second thread acquires the lock for the original Console.Out, then for the current Console.Out. - // - That's a typical deadlock where two threads are acquiring two locks in reverse order. - // 5. By locking the *current* Console.Out, we avoid the situation described in 4. - Monitor.Enter(_batchingLock, ref lockTaken); - if (!lockTaken) - { - // Can this happen? :/ - throw new InvalidOperationException(); - } - - _isBatching = true; - } + _colorNotSupported ??= RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID")) || + RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS")) || + RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS")) || + RuntimeInformation.IsOSPlatform(OSPlatform.Create("WASI")) || + RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")); - public void StopUpdate() - { - Monitor.Exit(_batchingLock!); - _batchingLock = null; - _isBatching = false; + return _colorNotSupported.Value; } private ConsoleColor ToConsoleColor(TerminalColor color) => color switch @@ -170,111 +74,4 @@ public void StopUpdate() TerminalColor.White => ConsoleColor.White, _ => _defaultForegroundColor, }; - - public void EraseProgress() - { - // nop - } - - public void RenderProgress(TestProgressState?[] progress) - { - int count = 0; - foreach (TestProgressState? p in progress) - { - if (p == null) - { - continue; - } - - count++; - - string durationString = HumanReadableDurationFormatter.Render(p.Stopwatch.Elapsed); - - int passed = p.PassedTests; - int failed = p.FailedTests; - int skipped = p.SkippedTests; - - // Use just ascii here, so we don't put too many restrictions on fonts needing to - // properly show unicode, or logs being saved in particular encoding. - Append('['); - SetColor(TerminalColor.DarkGreen); - Append('+'); - Append(passed.ToString(CultureInfo.CurrentCulture)); - ResetColor(); - - Append('/'); - - SetColor(TerminalColor.DarkRed); - Append('x'); - Append(failed.ToString(CultureInfo.CurrentCulture)); - ResetColor(); - - Append('/'); - - SetColor(TerminalColor.DarkYellow); - Append('?'); - Append(skipped.ToString(CultureInfo.CurrentCulture)); - ResetColor(); - Append(']'); - - Append(' '); - Append(p.AssemblyName); - - if (p.TargetFramework != null || p.Architecture != null) - { - Append(" ("); - if (p.TargetFramework != null) - { - Append(p.TargetFramework); - Append('|'); - } - - if (p.Architecture != null) - { - Append(p.Architecture); - } - - Append(')'); - } - - TestDetailState? activeTest = p.TestNodeResultsState?.GetRunningTasks(1).FirstOrDefault(); - if (!RoslynString.IsNullOrWhiteSpace(activeTest?.Text)) - { - Append(" - "); - Append(activeTest.Text); - Append(' '); - } - - Append(durationString); - - AppendLine(); - } - - // Do not render empty lines when there is nothing to show. - if (count > 0) - { - AppendLine(); - } - } - - public void StartBusyIndicator() - { - // nop - } - - public void StopBusyIndicator() - { - // nop - } - - [SupportedOSPlatformGuard("android")] - [SupportedOSPlatformGuard("ios")] - [SupportedOSPlatformGuard("tvos")] - [SupportedOSPlatformGuard("browser")] - private static bool IsForegroundColorNotSupported() - => RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID")) || - RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS")) || - RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS")) || - RuntimeInformation.IsOSPlatform(OSPlatform.Create("WASI")) || - RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")); } diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleAnsiTerminal.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleAnsiTerminal.cs new file mode 100644 index 0000000000..12b4f4eee0 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleAnsiTerminal.cs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Helpers; + +namespace Microsoft.Testing.Platform.OutputDevice.Terminal; + +/// +/// Simple terminal that uses 4-bit ANSI for colors but does not move cursor and does not do other fancy stuff to stay compatible with CI systems like AzDO. +/// The colors are set on start of every line to properly color multiline strings in AzDO output. +/// +internal sealed class SimpleAnsiTerminal : SimpleTerminal +{ + private string? _foregroundColor; + private bool _prependColor; + + public SimpleAnsiTerminal(IConsole console) + : base(console) + { + } + + public override void Append(string value) + { + // Previous write appended line, so we need to prepend color. + if (_prependColor) + { + Console.Write(_foregroundColor); + // This line is not adding new line at the end, so we don't need to prepend color on next line. + _prependColor = false; + } + + Console.Write(SetColorPerLine(value)); + } + + public override void AppendLine(string value) + { + // Previous write appended line, so we need to prepend color. + if (_prependColor) + { + Console.Write(_foregroundColor); + } + + Console.WriteLine(SetColorPerLine(value)); + // This call appended new line so the next write to console needs to prepend color. + _prependColor = true; + } + + public override void SetColor(TerminalColor color) + { + string setColor = $"{AnsiCodes.CSI}{(int)color}{AnsiCodes.SetColor}"; + _foregroundColor = setColor; + Console.Write(setColor); + // This call set the color for current line, no need to prepend on next write. + _prependColor = false; + } + + public override void ResetColor() + { + _foregroundColor = null; + _prependColor = false; + Console.Write(AnsiCodes.SetDefaultColor); + } + + private string? SetColorPerLine(string value) + => _foregroundColor == null ? value : value.Replace("\n", $"\n{_foregroundColor}"); +} diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleTerminalBase.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleTerminalBase.cs new file mode 100644 index 0000000000..aefad9bc28 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleTerminalBase.cs @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Helpers; +using Microsoft.Testing.Platform.Resources; + +namespace Microsoft.Testing.Platform.OutputDevice.Terminal; + +internal abstract class SimpleTerminal : ITerminal +{ + private object? _batchingLock; + private bool _isBatching; + + public SimpleTerminal(IConsole console) + => Console = console; + +#pragma warning disable CA1416 // Validate platform compatibility + public int Width => Console.IsOutputRedirected ? int.MaxValue : Console.BufferWidth; + + public int Height => Console.IsOutputRedirected ? int.MaxValue : Console.BufferHeight; + + protected IConsole Console { get; } + + public void Append(char value) + => Console.Write(value); + + public virtual void Append(string value) + => Console.Write(value); + + public void AppendLine() + => Console.WriteLine(); + + public virtual void AppendLine(string value) + => Console.WriteLine(value); + + public void AppendLink(string path, int? lineNumber) + { + Append(path); + if (lineNumber.HasValue) + { + Append($":{lineNumber}"); + } + } + + public void EraseProgress() + { + // nop + } + + public void HideCursor() + { + // nop + } + + public void RenderProgress(TestProgressState?[] progress) + { + int count = 0; + foreach (TestProgressState? p in progress) + { + if (p == null) + { + continue; + } + + count++; + + string durationString = HumanReadableDurationFormatter.Render(p.Stopwatch.Elapsed); + + int passed = p.PassedTests; + int failed = p.FailedTests; + int skipped = p.SkippedTests; + + // Use just ascii here, so we don't put too many restrictions on fonts needing to + // properly show unicode, or logs being saved in particular encoding. + Append('['); + SetColor(TerminalColor.DarkGreen); + Append('+'); + Append(passed.ToString(CultureInfo.CurrentCulture)); + ResetColor(); + + Append('/'); + + SetColor(TerminalColor.DarkRed); + Append('x'); + Append(failed.ToString(CultureInfo.CurrentCulture)); + ResetColor(); + + Append('/'); + + SetColor(TerminalColor.DarkYellow); + Append('?'); + Append(skipped.ToString(CultureInfo.CurrentCulture)); + ResetColor(); + Append(']'); + + Append(' '); + Append(p.AssemblyName); + + if (p.TargetFramework != null || p.Architecture != null) + { + Append(" ("); + if (p.TargetFramework != null) + { + Append(p.TargetFramework); + Append('|'); + } + + if (p.Architecture != null) + { + Append(p.Architecture); + } + + Append(')'); + } + + TestDetailState? activeTest = p.TestNodeResultsState?.GetRunningTasks(1).FirstOrDefault(); + if (!RoslynString.IsNullOrWhiteSpace(activeTest?.Text)) + { + Append(" - "); + Append(activeTest.Text); + Append(' '); + } + + Append(durationString); + + AppendLine(); + } + + // Do not render empty lines when there is nothing to show. + if (count > 0) + { + AppendLine(); + } + } + + public void ShowCursor() + { + // nop + } + + public void StartBusyIndicator() + { + // nop + } + + // TODO: Refactor NonAnsiTerminal and AnsiTerminal such that we don't need StartUpdate/StopUpdate. + // It's much better if we use lock C# keyword instead of manually calling Monitor.Enter/Exit + // Using lock also ensures we don't accidentally have `await`s in between that could cause Exit to be on a different thread. + public void StartUpdate() + { + if (_isBatching) + { + throw new InvalidOperationException(PlatformResources.ConsoleIsAlreadyInBatchingMode); + } + + bool lockTaken = false; + + // We store Console.Out in a field to make sure we will be doing + // the Monitor.Exit call on the same instance. + _batchingLock = System.Console.Out; + + // Note that we need to lock on System.Out for batching to work correctly. + // Consider the following scenario: + // 1. We call StartUpdate + // 2. We call a Write("A") + // 3. User calls Console.Write("B") from another thread. + // 4. We call a Write("C"). + // 5. We call StopUpdate. + // The expectation is that we see either ACB, or BAC, but not ABC. + // Basically, when doing batching, we want to ensure that everything we write is + // written continuously, without anything in-between. + // One option (and we used to do it), is that we append to a StringBuilder while batching + // Then at StopUpdate, we write the whole string at once. + // This works to some extent, but we cannot get it to work when SetColor kicks in. + // Console methods will internally lock on Console.Out, so we are locking on the same thing. + // This locking is the easiest way to get coloring to work correctly while preventing + // interleaving with user's calls to Console.Write methods. + // One extra note: + // It's very important to lock on Console.Out (the current Console.Out). + // Consider the following scenario: + // 1. SystemConsole captures the original Console.Out set by runtime. + // 2. Framework author sets his own Console.Out which wraps the original Console.Out. + // 3. Two threads are writing concurrently: + // - One thread is writing using Console.Write* APIs, which will use the Console.Out set by framework author. + // - The other thread is writing using NonAnsiTerminal. + // 4. **If** we lock the original Console.Out. The following may happen (subject to race) [NOT THE CURRENT CASE - imaginary situation if we lock on the original Console.Out]: + // - First thread enters the Console.Write, which will acquire the lock for the current Console.Out (set by framework author). + // - Second thread executes StartUpdate, and acquires the lock for the original Console.Out. + // - First thread continues in the Write implementation of the framework author, which tries to run Console.Write on the original Console.Out. + // - First thread can't make any progress, because the second thread is holding the lock already. + // - Second thread continues execution, and reaches into runtime code (ConsolePal.WriteFromConsoleStream - on Unix) which tries to acquire the lock for the current Console.Out (set by framework author). + // - (see https://github.com/dotnet/runtime/blob/8a9d492444f06df20fcc5dfdcf7a6395af18361f/src/libraries/System.Console/src/System/ConsolePal.Unix.cs#L963) + // - No thread can progress. + // - Basically, what happened is that the first thread acquires the lock for current Console.Out, then for the original Console.Out. + // - while the second thread acquires the lock for the original Console.Out, then for the current Console.Out. + // - That's a typical deadlock where two threads are acquiring two locks in reverse order. + // 5. By locking the *current* Console.Out, we avoid the situation described in 4. + Monitor.Enter(_batchingLock, ref lockTaken); + if (!lockTaken) + { + // Can this happen? :/ + throw new InvalidOperationException(); + } + + _isBatching = true; + } + + public void StopBusyIndicator() + { + // nop + } + + public void StopUpdate() + { + Monitor.Exit(_batchingLock!); + _batchingLock = null; + _isBatching = false; + } + + public abstract void SetColor(TerminalColor color); + + public abstract void ResetColor(); +} diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporter.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporter.cs index 905fc50137..576117e89e 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporter.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporter.cs @@ -3,6 +3,7 @@ using Microsoft.Testing.Platform.Helpers; using Microsoft.Testing.Platform.Resources; +using Microsoft.Testing.Platform.Services; namespace Microsoft.Testing.Platform.OutputDevice.Terminal; @@ -15,7 +16,7 @@ internal sealed partial class TerminalTestReporter : IDisposable /// /// The two directory separator characters to be passed to methods like . /// - private static readonly string[] NewLineStrings = { "\r\n", "\n" }; + private static readonly string[] NewLineStrings = ["\r\n", "\n"]; internal const string SingleIndentation = " "; @@ -35,15 +36,22 @@ internal event EventHandler OnProgressStopUpdate remove => _terminalWithProgress.OnProgressStopUpdate -= value; } - private readonly ConcurrentDictionary _assemblies = new(); + private readonly string _assembly; + private readonly string? _targetFramework; + private readonly string? _architecture; + private readonly ITestApplicationCancellationTokenSource _testApplicationCancellationTokenSource; - private readonly List _artifacts = new(); + private readonly List _artifacts = []; private readonly TerminalTestReporterOptions _options; private readonly TestProgressStateAwareTerminal _terminalWithProgress; + private readonly Lock _lock = new(); private readonly uint? _originalConsoleMode; + + private TestProgressState? _testProgressState; + private bool _isDiscovery; private DateTimeOffset? _testExecutionStartTime; @@ -51,7 +59,11 @@ internal event EventHandler OnProgressStopUpdate private int _buildErrorsCount; - private bool _wasCancelled; + private bool WasCancelled + { + get => field || _testApplicationCancellationTokenSource.CancellationToken.IsCancellationRequested; + set => field = value; + } private bool? _shouldShowPassedTests; @@ -60,8 +72,18 @@ internal event EventHandler OnProgressStopUpdate /// /// Initializes a new instance of the class with custom terminal and manual refresh for testing. /// - public TerminalTestReporter(IConsole console, TerminalTestReporterOptions options) - { + public TerminalTestReporter( + string assembly, + string? targetFramework, + string? architecture, + IConsole console, + ITestApplicationCancellationTokenSource testApplicationCancellationTokenSource, + TerminalTestReporterOptions options) + { + _assembly = assembly; + _targetFramework = targetFramework; + _architecture = architecture; + _testApplicationCancellationTokenSource = testApplicationCancellationTokenSource; _options = options; Func showProgress = _options.ShowProgress; @@ -77,12 +99,20 @@ public TerminalTestReporter(IConsole console, TerminalTestReporterOptions option } else { - // Autodetect. - (bool consoleAcceptsAnsiCodes, bool _, uint? originalConsoleMode) = NativeMethods.QueryIsScreenAndTryEnableAnsiColorCodes(); - _originalConsoleMode = originalConsoleMode; - terminalWithProgress = consoleAcceptsAnsiCodes || _options.ForceAnsi is true - ? new TestProgressStateAwareTerminal(new AnsiTerminal(console, _options.BaseDirectory), showProgress, writeProgressImmediatelyAfterOutput: true, updateEvery: ansiUpdateCadenceInMs) - : new TestProgressStateAwareTerminal(new NonAnsiTerminal(console), showProgress, writeProgressImmediatelyAfterOutput: false, updateEvery: nonAnsiUpdateCadenceInMs); + if (_options.UseCIAnsi) + { + // We are told externally that we are in CI, use simplified ANSI mode. + terminalWithProgress = new TestProgressStateAwareTerminal(new SimpleAnsiTerminal(console), showProgress, writeProgressImmediatelyAfterOutput: true, updateEvery: nonAnsiUpdateCadenceInMs); + } + else + { + // We are not in CI, or in CI non-compatible with simple ANSI, autodetect terminal capabilities + (bool consoleAcceptsAnsiCodes, bool _, uint? originalConsoleMode) = NativeMethods.QueryIsScreenAndTryEnableAnsiColorCodes(); + _originalConsoleMode = originalConsoleMode; + terminalWithProgress = consoleAcceptsAnsiCodes || _options.ForceAnsi is true + ? new TestProgressStateAwareTerminal(new AnsiTerminal(console), showProgress, writeProgressImmediatelyAfterOutput: true, updateEvery: ansiUpdateCadenceInMs) + : new TestProgressStateAwareTerminal(new NonAnsiTerminal(console), showProgress, writeProgressImmediatelyAfterOutput: false, updateEvery: nonAnsiUpdateCadenceInMs); + } } _terminalWithProgress = terminalWithProgress; @@ -95,34 +125,30 @@ public void TestExecutionStarted(DateTimeOffset testStartTime, int workerCount, _terminalWithProgress.StartShowingProgress(workerCount); } - public void AssemblyRunStarted(string assembly, string? targetFramework, string? architecture) + public void AssemblyRunStarted() + => GetOrAddAssemblyRun(); + + private TestProgressState GetOrAddAssemblyRun() { - if (_options.ShowAssembly && _options.ShowAssemblyStartAndComplete) + if (_testProgressState is not null) { - _terminalWithProgress.WriteToTerminal(terminal => - { - terminal.Append(_isDiscovery ? PlatformResources.DiscoveringTestsFrom : PlatformResources.RunningTestsFrom); - terminal.Append(' '); - AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal, assembly, targetFramework, architecture); - terminal.AppendLine(); - }); + return _testProgressState; } - GetOrAddAssemblyRun(assembly, targetFramework, architecture); - } - - private TestProgressState GetOrAddAssemblyRun(string assembly, string? targetFramework, string? architecture) - { - string key = $"{assembly}|{targetFramework}|{architecture}"; - return _assemblies.GetOrAdd(key, _ => + lock (_lock) { + if (_testProgressState is not null) + { + return _testProgressState; + } + IStopwatch sw = CreateStopwatch(); - var assemblyRun = new TestProgressState(Interlocked.Increment(ref _counter), assembly, targetFramework, architecture, sw); + var assemblyRun = new TestProgressState(Interlocked.Increment(ref _counter), _assembly, _targetFramework, _architecture, sw); int slotIndex = _terminalWithProgress.AddWorker(assemblyRun); assemblyRun.SlotIndex = slotIndex; - + _testProgressState = assemblyRun; return assemblyRun; - }); + } } public void TestExecutionCompleted(DateTimeOffset endTime) @@ -133,7 +159,6 @@ public void TestExecutionCompleted(DateTimeOffset endTime) _terminalWithProgress.WriteToTerminal(_isDiscovery ? AppendTestDiscoverySummary : AppendTestRunSummary); NativeMethods.RestoreConsoleMode(_originalConsoleMode); - _assemblies.Clear(); _buildErrorsCount = 0; _testExecutionStartTime = null; _testExecutionEndTime = null; @@ -171,20 +196,20 @@ private void AppendTestRunSummary(ITerminal terminal) terminal.AppendLine(); - int totalTests = _assemblies.Values.Sum(a => a.TotalTests); - int totalFailedTests = _assemblies.Values.Sum(a => a.FailedTests); - int totalSkippedTests = _assemblies.Values.Sum(a => a.SkippedTests); + int totalTests = _testProgressState?.TotalTests ?? 0; + int totalFailedTests = _testProgressState?.FailedTests ?? 0; + int totalSkippedTests = _testProgressState?.SkippedTests ?? 0; bool notEnoughTests = totalTests < _options.MinimumExpectedTests; bool allTestsWereSkipped = totalTests == 0 || totalTests == totalSkippedTests; bool anyTestFailed = totalFailedTests > 0; - bool runFailed = anyTestFailed || notEnoughTests || allTestsWereSkipped || _wasCancelled; - terminal.SetColor(runFailed ? TerminalColor.Red : TerminalColor.Green); + bool runFailed = anyTestFailed || notEnoughTests || allTestsWereSkipped || WasCancelled; + terminal.SetColor(runFailed ? TerminalColor.DarkRed : TerminalColor.DarkGreen); terminal.Append(PlatformResources.TestRunSummary); terminal.Append(' '); - if (_wasCancelled) + if (WasCancelled) { terminal.Append(PlatformResources.Aborted); } @@ -198,40 +223,24 @@ private void AppendTestRunSummary(ITerminal terminal) } else if (anyTestFailed) { - terminal.Append(string.Format(CultureInfo.CurrentCulture, "{0}!", PlatformResources.Failed)); + terminal.Append($"{PlatformResources.Failed}!"); } else { - terminal.Append(string.Format(CultureInfo.CurrentCulture, "{0}!", PlatformResources.Passed)); + terminal.Append($"{PlatformResources.Passed}!"); } - if (!_options.ShowAssembly && _assemblies.Count == 1) - { - TestProgressState testProgressState = _assemblies.Values.Single(); - terminal.SetColor(TerminalColor.DarkGray); - terminal.Append(" - "); - terminal.ResetColor(); - AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal, testProgressState.Assembly, testProgressState.TargetFramework, testProgressState.Architecture); - } + terminal.SetColor(TerminalColor.DarkGray); + terminal.Append(" - "); + terminal.ResetColor(); + AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal); terminal.AppendLine(); - if (_options.ShowAssembly && _assemblies.Count > 1) - { - foreach (TestProgressState assemblyRun in _assemblies.Values) - { - terminal.Append(SingleIndentation); - AppendAssemblySummary(assemblyRun, terminal); - terminal.AppendLine(); - } - - terminal.AppendLine(); - } - - int total = _assemblies.Values.Sum(t => t.TotalTests); - int failed = _assemblies.Values.Sum(t => t.FailedTests); - int passed = _assemblies.Values.Sum(t => t.PassedTests); - int skipped = _assemblies.Values.Sum(t => t.SkippedTests); + int total = _testProgressState?.TotalTests ?? 0; + int failed = _testProgressState?.FailedTests ?? 0; + int passed = _testProgressState?.PassedTests ?? 0; + int skipped = _testProgressState?.SkippedTests ?? 0; TimeSpan runDuration = _testExecutionStartTime != null && _testExecutionEndTime != null ? (_testExecutionEndTime - _testExecutionStartTime).Value : TimeSpan.Zero; bool colorizeFailed = failed > 0; @@ -248,7 +257,7 @@ private void AppendTestRunSummary(ITerminal terminal) terminal.AppendLine(totalText); if (colorizeFailed) { - terminal.SetColor(TerminalColor.Red); + terminal.SetColor(TerminalColor.DarkRed); } terminal.AppendLine(failedText); @@ -260,7 +269,7 @@ private void AppendTestRunSummary(ITerminal terminal) if (colorizePassed) { - terminal.SetColor(TerminalColor.Green); + terminal.SetColor(TerminalColor.DarkGreen); } terminal.AppendLine(passedText); @@ -272,7 +281,7 @@ private void AppendTestRunSummary(ITerminal terminal) if (colorizeSkipped) { - terminal.SetColor(TerminalColor.Yellow); + terminal.SetColor(TerminalColor.DarkYellow); } terminal.AppendLine(skippedText); @@ -287,43 +296,7 @@ private void AppendTestRunSummary(ITerminal terminal) terminal.AppendLine(); } - /// - /// Print a build result summary to the output. - /// - private static void AppendAssemblyResult(ITerminal terminal, bool succeeded, int countErrors, int countWarnings) - { - if (!succeeded) - { - terminal.SetColor(TerminalColor.Red); - // If the build failed, we print one of three red strings. - string text = (countErrors > 0, countWarnings > 0) switch - { - (true, true) => string.Format(CultureInfo.CurrentCulture, PlatformResources.FailedWithErrorsAndWarnings, countErrors, countWarnings), - (true, _) => string.Format(CultureInfo.CurrentCulture, PlatformResources.FailedWithErrors, countErrors), - (false, true) => string.Format(CultureInfo.CurrentCulture, PlatformResources.FailedWithWarnings, countWarnings), - _ => PlatformResources.FailedLowercase, - }; - terminal.Append(text); - terminal.ResetColor(); - } - else if (countWarnings > 0) - { - terminal.SetColor(TerminalColor.Yellow); - terminal.Append($"succeeded with {countWarnings} warning(s)"); - terminal.ResetColor(); - } - else - { - terminal.SetColor(TerminalColor.Green); - terminal.Append(PlatformResources.PassedLowercase); - terminal.ResetColor(); - } - } - internal void TestCompleted( - string assembly, - string? targetFramework, - string? architecture, string testNodeUid, string displayName, TestOutcome outcome, @@ -338,9 +311,6 @@ internal void TestCompleted( { FlatException[] flatExceptions = ExceptionFlattener.Flatten(errorMessage, exception); TestCompleted( - assembly, - targetFramework, - architecture, testNodeUid, displayName, outcome, @@ -354,9 +324,6 @@ internal void TestCompleted( } private void TestCompleted( - string assembly, - string? targetFramework, - string? architecture, string testNodeUid, string displayName, TestOutcome outcome, @@ -368,7 +335,12 @@ private void TestCompleted( string? standardOutput, string? errorOutput) { - TestProgressState asm = _assemblies[$"{assembly}|{targetFramework}|{architecture}"]; + if (_testProgressState is null) + { + throw ApplicationStateGuard.Unreachable(); + } + + TestProgressState asm = _testProgressState; if (_options.ShowActiveTests) { @@ -399,9 +371,6 @@ private void TestCompleted( { _terminalWithProgress.WriteToTerminal(terminal => RenderTestCompleted( terminal, - assembly, - targetFramework, - architecture, displayName, outcome, duration, @@ -422,9 +391,6 @@ private bool GetShowPassedTests() private void RenderTestCompleted( ITerminal terminal, - string assembly, - string? targetFramework, - string? architecture, string displayName, TestOutcome outcome, TimeSpan duration, @@ -442,9 +408,9 @@ private void RenderTestCompleted( TerminalColor color = outcome switch { - TestOutcome.Error or TestOutcome.Fail or TestOutcome.Canceled or TestOutcome.Timeout => TerminalColor.Red, - TestOutcome.Skipped => TerminalColor.Yellow, - TestOutcome.Passed => TerminalColor.Green, + TestOutcome.Error or TestOutcome.Fail or TestOutcome.Canceled or TestOutcome.Timeout => TerminalColor.DarkRed, + TestOutcome.Skipped => TerminalColor.DarkYellow, + TestOutcome.Passed => TerminalColor.DarkGreen, _ => throw new NotSupportedException(), }; string outcomeText = outcome switch @@ -464,14 +430,6 @@ private void RenderTestCompleted( terminal.SetColor(TerminalColor.DarkGray); terminal.Append(' '); AppendLongDuration(terminal, duration); - if (_options.ShowAssembly) - { - terminal.AppendLine(); - terminal.Append(SingleIndentation); - terminal.Append(PlatformResources.FromFile); - terminal.Append(' '); - AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal, assembly, targetFramework, architecture); - } terminal.AppendLine(); @@ -492,7 +450,7 @@ private static void FormatInnerExceptions(ITerminal terminal, FlatException[] ex for (int i = 1; i < exceptions.Length; i++) { - terminal.SetColor(TerminalColor.Red); + terminal.SetColor(TerminalColor.DarkRed); terminal.Append(SingleIndentation); terminal.Append("--->"); FormatErrorMessage(terminal, exceptions, TestOutcome.Error, i); @@ -510,7 +468,7 @@ private static void FormatErrorMessage(ITerminal terminal, FlatException[] excep return; } - terminal.SetColor(TerminalColor.Red); + terminal.SetColor(TerminalColor.DarkRed); if (firstStackTrace is null) { @@ -539,7 +497,7 @@ private static void FormatExpectedAndActual(ITerminal terminal, string? expected return; } - terminal.SetColor(TerminalColor.Red); + terminal.SetColor(TerminalColor.DarkRed); terminal.Append(SingleIndentation); terminal.AppendLine(PlatformResources.Expected); AppendIndentedLine(terminal, expected, DoubleIndentation); @@ -587,21 +545,21 @@ private static void FormatStandardAndErrorOutput(ITerminal terminal, string? sta terminal.ResetColor(); } - private static void AppendAssemblyLinkTargetFrameworkAndArchitecture(ITerminal terminal, string assembly, string? targetFramework, string? architecture) + private void AppendAssemblyLinkTargetFrameworkAndArchitecture(ITerminal terminal) { - terminal.AppendLink(assembly, lineNumber: null); - if (targetFramework != null || architecture != null) + terminal.AppendLink(_assembly, lineNumber: null); + if (_targetFramework != null || _architecture != null) { terminal.Append(" ("); - if (targetFramework != null) + if (_targetFramework != null) { - terminal.Append(targetFramework); + terminal.Append(_targetFramework); terminal.Append('|'); } - if (architecture != null) + if (_architecture != null) { - terminal.Append(architecture); + terminal.Append(_architecture); } terminal.Append(')'); @@ -678,46 +636,12 @@ private static void AppendIndentedLine(ITerminal terminal, string? message, stri } } - internal void AssemblyRunCompleted(string assembly, string? targetFramework, string? architecture, - // These parameters are useful only for "remote" runs in dotnet test, where we are reporting on multiple processes. - // In single process run, like with testing platform .exe we report these via messages, and run exit. - int? exitCode, string? outputData, string? errorData) + internal void AssemblyRunCompleted() { - TestProgressState assemblyRun = GetOrAddAssemblyRun(assembly, targetFramework, architecture); + TestProgressState assemblyRun = GetOrAddAssemblyRun(); assemblyRun.Stopwatch.Stop(); _terminalWithProgress.RemoveWorker(assemblyRun.SlotIndex); - - if (!_isDiscovery && _options.ShowAssembly && _options.ShowAssemblyStartAndComplete) - { - _terminalWithProgress.WriteToTerminal(terminal => AppendAssemblySummary(assemblyRun, terminal)); - } - - if (exitCode is null or 0) - { - // Report nothing, we don't want to report on success, because then we will also report on test-discovery etc. - return; - } - - _terminalWithProgress.WriteToTerminal(terminal => - { - AppendExecutableSummary(terminal, exitCode, outputData, errorData); - terminal.AppendLine(); - }); - } - - private static void AppendExecutableSummary(ITerminal terminal, int? exitCode, string? outputData, string? errorData) - { - terminal.AppendLine(); - terminal.Append(PlatformResources.ExitCode); - terminal.Append(": "); - terminal.AppendLine(exitCode?.ToString(CultureInfo.CurrentCulture) ?? ""); - terminal.Append(PlatformResources.StandardOutput); - terminal.AppendLine(":"); - terminal.AppendLine(RoslynString.IsNullOrWhiteSpace(outputData) ? string.Empty : outputData); - terminal.Append(PlatformResources.StandardError); - terminal.AppendLine(":"); - terminal.AppendLine(RoslynString.IsNullOrWhiteSpace(errorData) ? string.Empty : errorData); } private static string? NormalizeSpecialCharacters(string? text) @@ -725,18 +649,6 @@ private static void AppendExecutableSummary(ITerminal terminal, int? exitCode, s // escape char .Replace('\x001b', '\x241b'); - private static void AppendAssemblySummary(TestProgressState assemblyRun, ITerminal terminal) - { - int failedTests = assemblyRun.FailedTests; - int warnings = 0; - - AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal, assemblyRun.Assembly, assemblyRun.TargetFramework, assemblyRun.Architecture); - terminal.Append(' '); - AppendAssemblyResult(terminal, assemblyRun.FailedTests == 0, failedTests, warnings); - terminal.Append(' '); - AppendLongDuration(terminal, assemblyRun.Stopwatch.Elapsed); - } - /// /// Appends a long duration in human readable format such as 1h 23m 500ms. /// @@ -757,15 +669,15 @@ private static void AppendLongDuration(ITerminal terminal, TimeSpan duration, bo public void Dispose() => _terminalWithProgress.Dispose(); - public void ArtifactAdded(bool outOfProcess, string? assembly, string? targetFramework, string? architecture, string? testName, string path) - => _artifacts.Add(new TestRunArtifact(outOfProcess, assembly, targetFramework, architecture, testName, path)); + public void ArtifactAdded(bool outOfProcess, string? testName, string path) + => _artifacts.Add(new TestRunArtifact(outOfProcess, testName, path)); /// /// Let the user know that cancellation was triggered. /// public void StartCancelling() { - _wasCancelled = true; + WasCancelled = true; _terminalWithProgress.WriteToTerminal(terminal => { terminal.AppendLine(); @@ -774,14 +686,14 @@ public void StartCancelling() }); } - internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, string text, int? padding) + internal void WriteErrorMessage(string text, int? padding) { - TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture); + TestProgressState asm = GetOrAddAssemblyRun(); asm.AddError(text); _terminalWithProgress.WriteToTerminal(terminal => { - terminal.SetColor(TerminalColor.Red); + terminal.SetColor(TerminalColor.DarkRed); if (padding == null) { terminal.AppendLine(text); @@ -795,13 +707,13 @@ internal void WriteErrorMessage(string assembly, string? targetFramework, string }); } - internal void WriteWarningMessage(string assembly, string? targetFramework, string? architecture, string text, int? padding) + internal void WriteWarningMessage(string text, int? padding) { - TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture); + TestProgressState asm = GetOrAddAssemblyRun(); asm.AddWarning(text); _terminalWithProgress.WriteToTerminal(terminal => { - terminal.SetColor(TerminalColor.Yellow); + terminal.SetColor(TerminalColor.DarkYellow); if (padding == null) { terminal.AppendLine(text); @@ -815,8 +727,8 @@ internal void WriteWarningMessage(string assembly, string? targetFramework, stri }); } - internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, Exception exception) - => WriteErrorMessage(assembly, targetFramework, architecture, exception.ToString(), padding: null); + internal void WriteErrorMessage(Exception exception) + => WriteErrorMessage(exception.ToString(), padding: null); public void WriteMessage(string text, SystemConsoleColor? color = null, int? padding = null) { @@ -853,15 +765,14 @@ public void WriteMessage(string text, SystemConsoleColor? color = null, int? pad } } - internal void TestDiscovered( - string assembly, - string? targetFramework, - string? architecture, - string? displayName, - string? uid) + internal void TestDiscovered(string displayName) { - TestProgressState asm = _assemblies[$"{assembly}|{targetFramework}|{architecture}"]; + if (_testProgressState is null) + { + throw ApplicationStateGuard.Unreachable(); + } + TestProgressState asm = _testProgressState; if (_isDiscovery) { // TODO: add mode for discovered tests to the progress bar, to get rid of the hack here that allows updating the @@ -870,65 +781,42 @@ internal void TestDiscovered( asm.TotalTests++; } - asm.DiscoveredTests.Add(new(displayName, uid)); + asm.DiscoveredTestDisplayNames.Add(displayName); _terminalWithProgress.UpdateWorker(asm.SlotIndex); } public void AppendTestDiscoverySummary(ITerminal terminal) { + TestProgressState? assembly = _testProgressState; terminal.AppendLine(); - var assemblies = _assemblies.Select(asm => asm.Value).OrderBy(a => a.Assembly).Where(a => a is not null).ToList(); + int totalTests = assembly?.TotalTests ?? 0; + bool runFailed = WasCancelled; - int totalTests = _assemblies.Values.Sum(a => a.TotalTests); - bool runFailed = _wasCancelled; - - foreach (TestProgressState assembly in assemblies) + if (assembly is not null) { - if (_options.ShowAssembly) - { - terminal.Append(string.Format(CultureInfo.CurrentCulture, PlatformResources.DiscoveredTestsInAssembly, assembly.DiscoveredTests.Count)); - terminal.Append(" - "); - AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal, assembly.Assembly, assembly.TargetFramework, assembly.Architecture); - terminal.AppendLine(); - } - - foreach ((string? displayName, string? uid) in assembly.DiscoveredTests) + foreach (string displayName in assembly.DiscoveredTestDisplayNames) { - if (displayName is not null) - { - terminal.Append(SingleIndentation); - terminal.AppendLine(displayName); - } + terminal.Append(SingleIndentation); + terminal.AppendLine(displayName); } - - terminal.AppendLine(); } - terminal.SetColor(runFailed ? TerminalColor.Red : TerminalColor.Green); - if (assemblies.Count <= 1) - { - terminal.Append(string.Format(CultureInfo.CurrentCulture, PlatformResources.TestDiscoverySummarySingular, totalTests)); + terminal.AppendLine(); - if (!_options.ShowAssembly && _assemblies.Count == 1) - { - TestProgressState testProgressState = _assemblies.Values.Single(); - terminal.SetColor(TerminalColor.DarkGray); - terminal.Append(" - "); - terminal.ResetColor(); - AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal, testProgressState.Assembly, testProgressState.TargetFramework, testProgressState.Architecture); - } - } - else - { - terminal.Append(string.Format(CultureInfo.CurrentCulture, PlatformResources.TestDiscoverySummary, totalTests, assemblies.Count)); - } + terminal.SetColor(runFailed ? TerminalColor.DarkRed : TerminalColor.DarkGreen); + terminal.Append(string.Format(CultureInfo.CurrentCulture, PlatformResources.TestDiscoverySummarySingular, totalTests)); + + terminal.SetColor(TerminalColor.DarkGray); + terminal.Append(" - "); + terminal.ResetColor(); + AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal); terminal.ResetColor(); terminal.AppendLine(); - if (_wasCancelled) + if (WasCancelled) { terminal.Append(PlatformResources.Aborted); terminal.AppendLine(); @@ -964,14 +852,15 @@ private static TerminalColor ToTerminalColor(ConsoleColor consoleColor) }; public void TestInProgress( - string assembly, - string? targetFramework, - string? architecture, string testNodeUid, string displayName) { - TestProgressState asm = _assemblies[$"{assembly}|{targetFramework}|{architecture}"]; + if (_testProgressState is null) + { + throw ApplicationStateGuard.Unreachable(); + } + TestProgressState asm = _testProgressState; if (_options.ShowActiveTests) { asm.TestNodeResultsState ??= new(Interlocked.Increment(ref _counter)); diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.cs index 97e965b324..5de9570121 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.cs @@ -18,10 +18,10 @@ internal sealed class TerminalTestReporterCommandLineOptionsProvider : ICommandL public const string OutputOptionDetailedArgument = "detailed"; /// - public string Uid { get; } = nameof(TerminalTestReporterCommandLineOptionsProvider); + public string Uid => nameof(TerminalTestReporterCommandLineOptionsProvider); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// public string DisplayName { get; } = PlatformResources.TerminalTestReporterDisplayName; diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterOptions.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterOptions.cs index 478453758d..b738158389 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterOptions.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterOptions.cs @@ -5,26 +5,11 @@ namespace Microsoft.Testing.Platform.OutputDevice.Terminal; internal sealed class TerminalTestReporterOptions { - /// - /// Gets path to which all other paths in output should be relative. - /// - public string? BaseDirectory { get; init; } - /// /// Gets a value indicating whether we should show passed tests. /// public Func ShowPassedTests { get; init; } = () => true; - /// - /// Gets a value indicating whether we should show information about which assembly is the source of the data on screen. Turn this off when running directly from an exe to reduce noise, because the path will always be the same. - /// - public bool ShowAssembly { get; init; } - - /// - /// Gets a value indicating whether we should show information about which assembly started or completed. Turn this off when running directly from an exe to reduce noise, because the path will always be the same. - /// - public bool ShowAssemblyStartAndComplete { get; init; } - /// /// Gets minimum amount of tests to run. /// @@ -47,6 +32,12 @@ internal sealed class TerminalTestReporterOptions /// public bool UseAnsi { get; init; } + /// + /// Gets a value indicating whether we are running in compatible CI, and should use simplified ANSI renderer, which colors output, but does not move cursor. + /// Setting to false will disable this option. + /// + public bool UseCIAnsi { get; init; } + /// /// Gets a value indicating whether we should force ANSI escape codes. When true the ANSI is used without auto-detecting capabilities of the console. This is needed only for testing. /// diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestNodeResultsState.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestNodeResultsState.cs index db574dfa97..f14fecc7aa 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestNodeResultsState.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestNodeResultsState.cs @@ -45,7 +45,7 @@ public IEnumerable GetRunningTasks(int maxCount) ? string.Format(CultureInfo.CurrentCulture, PlatformResources.ActiveTestsRunning_FullTestsCount, sortedDetails.Count) // If itemsToTake is larger, then we show the project summary, active tests, and the number of active tests that are not shown. : $"... {string.Format(CultureInfo.CurrentCulture, PlatformResources.ActiveTestsRunning_MoreTestsCount, sortedDetails.Count - itemsToTake)}"; - sortedDetails = sortedDetails.Take(itemsToTake).ToList(); + sortedDetails = [.. sortedDetails.Take(itemsToTake)]; } foreach (TestDetailState? detail in sortedDetails) diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestProgressState.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestProgressState.cs index afc5d8d7cf..5cccaafa99 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestProgressState.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestProgressState.cs @@ -27,7 +27,7 @@ public TestProgressState(long id, string assembly, string? targetFramework, stri public IStopwatch Stopwatch { get; } - public List Messages { get; } = new(); + public List Messages { get; } = []; public int FailedTests { get; internal set; } @@ -45,7 +45,7 @@ public TestProgressState(long id, string assembly, string? targetFramework, stri public long Version { get; internal set; } - public List<(string? DisplayName, string? UID)> DiscoveredTests { get; internal set; } = new(); + public List DiscoveredTestDisplayNames { get; internal set; } = []; internal void AddError(string text) => Messages.Add(new ErrorMessage(text)); diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestRunArtifact.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestRunArtifact.cs index 5ab5c2172d..936a213f70 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestRunArtifact.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestRunArtifact.cs @@ -6,4 +6,4 @@ namespace Microsoft.Testing.Platform.OutputDevice.Terminal; /// /// An artifact / attachment that was reported during run. /// -internal sealed record TestRunArtifact(bool OutOfProcess, string? Assembly, string? TargetFramework, string? Architecture, string? TestName, string Path); +internal sealed record TestRunArtifact(bool OutOfProcess, string? TestName, string Path); diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs index ac46b81654..2fd1bbb28f 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs @@ -31,6 +31,8 @@ internal sealed partial class TerminalOutputDevice : IHotReloadPlatformOutputDev private const string TESTINGPLATFORM_CONSOLEOUTPUTDEVICE_SKIP_BANNER = nameof(TESTINGPLATFORM_CONSOLEOUTPUTDEVICE_SKIP_BANNER); #pragma warning restore SA1310 // Field names should not contain underscore + private const char Dash = '-'; + private readonly IConsole _console; private readonly ITestHostControllerInfo _testHostControllerInfo; private readonly IAsyncMonitor _asyncMonitor; @@ -42,6 +44,7 @@ internal sealed partial class TerminalOutputDevice : IHotReloadPlatformOutputDev private readonly ILoggerFactory _loggerFactory; private readonly IClock _clock; private readonly IStopPoliciesService _policiesService; + private readonly ITestApplicationCancellationTokenSource _testApplicationCancellationTokenSource; private readonly string? _longArchitecture; private readonly string? _shortArchitecture; @@ -51,7 +54,6 @@ internal sealed partial class TerminalOutputDevice : IHotReloadPlatformOutputDev // The targeted framework, .NET 8 when application specifies net8.0 private readonly string? _targetFramework; private readonly string _assemblyName; - private readonly char[] _dash = new char[] { '-' }; private TerminalTestReporter? _terminalTestReporter; private bool _firstCallTo_OnSessionStartingAsync = true; @@ -65,7 +67,7 @@ public TerminalOutputDevice( ITestApplicationModuleInfo testApplicationModuleInfo, ITestHostControllerInfo testHostControllerInfo, IAsyncMonitor asyncMonitor, IRuntimeFeature runtimeFeature, IEnvironment environment, IPlatformInformation platformInformation, ICommandLineOptions commandLineOptions, IFileLoggerInformation? fileLoggerInformation, ILoggerFactory loggerFactory, IClock clock, - IStopPoliciesService policiesService) + IStopPoliciesService policiesService, ITestApplicationCancellationTokenSource testApplicationCancellationTokenSource) { _console = console; _testHostControllerInfo = testHostControllerInfo; @@ -78,6 +80,7 @@ public TerminalOutputDevice( _loggerFactory = loggerFactory; _clock = clock; _policiesService = policiesService; + _testApplicationCancellationTokenSource = testApplicationCancellationTokenSource; if (_runtimeFeature.IsDynamicCodeSupported) { @@ -87,7 +90,7 @@ public TerminalOutputDevice( #else // RID has the operating system, we want to see that in the banner, but not next to every dll. _longArchitecture = RuntimeInformation.RuntimeIdentifier; - _shortArchitecture = GetShortArchitecture(RuntimeInformation.RuntimeIdentifier); + _shortArchitecture = TerminalOutputDevice.GetShortArchitecture(RuntimeInformation.RuntimeIdentifier); #endif _runtimeFramework = TargetFrameworkParser.GetShortTargetFramework(RuntimeInformation.FrameworkDescription); _targetFramework = TargetFrameworkParser.GetShortTargetFramework(Assembly.GetEntryAssembly()?.GetCustomAttribute()?.FrameworkDisplayName) ?? _runtimeFramework; @@ -99,6 +102,8 @@ public TerminalOutputDevice( { _bannerDisplayed = true; } + + _testApplicationCancellationTokenSource = testApplicationCancellationTokenSource; } public async Task InitializeAsync() @@ -108,7 +113,7 @@ await _policiesService.RegisterOnAbortCallbackAsync( { _terminalTestReporter?.StartCancelling(); return Task.CompletedTask; - }); + }).ConfigureAwait(false); if (_fileLoggerInformation is not null) { @@ -118,6 +123,9 @@ await _policiesService.RegisterOnAbortCallbackAsync( _isListTests = _commandLineOptions.IsOptionSet(PlatformCommandLineProvider.DiscoverTestsOptionKey); _isServerMode = _commandLineOptions.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey); bool noAnsi = _commandLineOptions.IsOptionSet(TerminalTestReporterCommandLineOptionsProvider.NoAnsiOption); + + // TODO: Replace this with proper CI detection that we already have in telemetry. https://github.com/microsoft/testfx/issues/5533#issuecomment-2838893327 + bool inCI = string.Equals(_environment.GetEnvironmentVariable("TF_BUILD"), "true", StringComparison.OrdinalIgnoreCase) || string.Equals(_environment.GetEnvironmentVariable("GITHUB_ACTIONS"), "true", StringComparison.OrdinalIgnoreCase); bool noProgress = _commandLineOptions.IsOptionSet(TerminalTestReporterCommandLineOptionsProvider.NoProgressOption); // _runtimeFeature.IsHotReloadEnabled is not set to true here, even if the session will be HotReload, @@ -147,22 +155,20 @@ await _policiesService.RegisterOnAbortCallbackAsync( : !_testHostControllerInfo.IsCurrentProcessTestHostController; // This is single exe run, don't show all the details of assemblies and their summaries. - _terminalTestReporter = new TerminalTestReporter(_console, new() + _terminalTestReporter = new TerminalTestReporter(_assemblyName, _targetFramework, _shortArchitecture, _console, _testApplicationCancellationTokenSource, new() { - BaseDirectory = null, - ShowAssembly = false, - ShowAssemblyStartAndComplete = false, ShowPassedTests = showPassed, MinimumExpectedTests = PlatformCommandLineProvider.GetMinimumExpectedTests(_commandLineOptions), UseAnsi = !noAnsi, + UseCIAnsi = inCI, ShowActiveTests = true, ShowProgress = shouldShowProgress, }); } - private string GetShortArchitecture(string runtimeIdentifier) - => runtimeIdentifier.Contains('-') - ? runtimeIdentifier.Split(_dash, 2)[1] + private static string GetShortArchitecture(string runtimeIdentifier) + => runtimeIdentifier.Contains(Dash) + ? runtimeIdentifier.Split(Dash, 2)[1] : runtimeIdentifier; public Type[] DataTypesConsumed { get; } = @@ -173,16 +179,16 @@ private string GetShortArchitecture(string runtimeIdentifier) ]; /// - public string Uid { get; } = nameof(TerminalOutputDevice); + public string Uid => nameof(TerminalOutputDevice); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// - public string DisplayName { get; } = "Test Platform Console Service"; + public string DisplayName => "Test Platform Console Service"; /// - public string Description { get; } = "Test Platform default console service"; + public string Description => "Test Platform default console service"; /// public Task IsEnabledAsync() => Task.FromResult(true); @@ -191,7 +197,7 @@ private async Task LogDebugAsync(string message) { if (_logger is not null) { - await _logger.LogDebugAsync(message); + await _logger.LogDebugAsync(message).ConfigureAwait(false); } } @@ -199,7 +205,7 @@ public async Task DisplayBannerAsync(string? bannerMessage) { RoslynDebug.Assert(_terminalTestReporter is not null); - using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout)) + using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false)) { if (!_bannerDisplayed) { @@ -246,20 +252,20 @@ public async Task DisplayBannerAsync(string? bannerMessage) if (_fileLoggerInformation is not null) { - if (_fileLoggerInformation.SyncronousWrite) + if (_fileLoggerInformation.SynchronousWrite) { - _terminalTestReporter.WriteWarningMessage(_assemblyName, _targetFramework, _shortArchitecture, string.Format(CultureInfo.CurrentCulture, PlatformResources.DiagnosticFileLevelWithFlush, _fileLoggerInformation.LogLevel, _fileLoggerInformation.LogFile.FullName), padding: null); + _terminalTestReporter.WriteWarningMessage(string.Format(CultureInfo.CurrentCulture, PlatformResources.DiagnosticFileLevelWithFlush, _fileLoggerInformation.LogLevel, _fileLoggerInformation.LogFile.FullName), padding: null); } else { - _terminalTestReporter.WriteWarningMessage(_assemblyName, _targetFramework, _shortArchitecture, string.Format(CultureInfo.CurrentCulture, PlatformResources.DiagnosticFileLevelWithAsyncFlush, _fileLoggerInformation.LogLevel, _fileLoggerInformation.LogFile.FullName), padding: null); + _terminalTestReporter.WriteWarningMessage(string.Format(CultureInfo.CurrentCulture, PlatformResources.DiagnosticFileLevelWithAsyncFlush, _fileLoggerInformation.LogLevel, _fileLoggerInformation.LogFile.FullName), padding: null); } } } } public async Task DisplayBeforeHotReloadSessionStartAsync() - => await DisplayBeforeSessionStartAsync(); + => await DisplayBeforeSessionStartAsync().ConfigureAwait(false); public async Task DisplayBeforeSessionStartAsync() { @@ -273,15 +279,15 @@ public async Task DisplayBeforeSessionStartAsync() // Start test execution here, rather than in ShowBanner, because then we know // if we are a testHost controller or not, and if we should show progress bar. _terminalTestReporter.TestExecutionStarted(_clock.UtcNow, workerCount: 1, isDiscovery: _isListTests); - _terminalTestReporter.AssemblyRunStarted(_assemblyName, _targetFramework, _shortArchitecture); + _terminalTestReporter.AssemblyRunStarted(); if (_logger is not null && _logger.IsEnabled(LogLevel.Trace)) { - await _logger.LogTraceAsync("DisplayBeforeSessionStartAsync"); + await _logger.LogTraceAsync("DisplayBeforeSessionStartAsync").ConfigureAwait(false); } } public async Task DisplayAfterHotReloadSessionEndAsync() - => await DisplayAfterSessionEndRunInternalAsync(); + => await DisplayAfterSessionEndRunInternalAsync().ConfigureAwait(false); public async Task DisplayAfterSessionEndRunAsync() { @@ -297,18 +303,18 @@ public async Task DisplayAfterSessionEndRunAsync() return; } - await DisplayAfterSessionEndRunInternalAsync(); + await DisplayAfterSessionEndRunInternalAsync().ConfigureAwait(false); } private async Task DisplayAfterSessionEndRunInternalAsync() { RoslynDebug.Assert(_terminalTestReporter is not null); - using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout)) + using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false)) { if (!_firstCallTo_OnSessionStartingAsync) { - _terminalTestReporter.AssemblyRunCompleted(_assemblyName, _targetFramework, _shortArchitecture, exitCode: null, outputData: null, errorData: null); + _terminalTestReporter.AssemblyRunCompleted(); _terminalTestReporter.TestExecutionCompleted(_clock.UtcNow); } } @@ -343,33 +349,33 @@ public async Task DisplayAsync(IOutputDeviceDataProducer producer, IOutputDevice { RoslynDebug.Assert(_terminalTestReporter is not null); - using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout)) + using (await _asyncMonitor.LockAsync(TimeoutHelper.DefaultHangTimeSpanTimeout).ConfigureAwait(false)) { switch (data) { case FormattedTextOutputDeviceData formattedTextData: - await LogDebugAsync(formattedTextData.Text); + await LogDebugAsync(formattedTextData.Text).ConfigureAwait(false); _terminalTestReporter.WriteMessage(formattedTextData.Text, formattedTextData.ForegroundColor as SystemConsoleColor, formattedTextData.Padding); break; case TextOutputDeviceData textData: - await LogDebugAsync(textData.Text); + await LogDebugAsync(textData.Text).ConfigureAwait(false); _terminalTestReporter.WriteMessage(textData.Text); break; case WarningMessageOutputDeviceData warningData: - await LogDebugAsync(warningData.Message); - _terminalTestReporter.WriteWarningMessage(_assemblyName, _targetFramework, _shortArchitecture, warningData.Message, null); + await LogDebugAsync(warningData.Message).ConfigureAwait(false); + _terminalTestReporter.WriteWarningMessage(warningData.Message, null); break; case ErrorMessageOutputDeviceData errorData: - await LogDebugAsync(errorData.Message); - _terminalTestReporter.WriteErrorMessage(_assemblyName, _targetFramework, _shortArchitecture, errorData.Message, null); + await LogDebugAsync(errorData.Message).ConfigureAwait(false); + _terminalTestReporter.WriteErrorMessage(errorData.Message, null); break; case ExceptionOutputDeviceData exceptionOutputDeviceData: - await LogDebugAsync(exceptionOutputDeviceData.Exception.ToString()); - _terminalTestReporter.WriteErrorMessage(_assemblyName, _targetFramework, _shortArchitecture, exceptionOutputDeviceData.Exception); + await LogDebugAsync(exceptionOutputDeviceData.Exception.ToString()).ConfigureAwait(false); + _terminalTestReporter.WriteErrorMessage(exceptionOutputDeviceData.Exception); break; } } @@ -397,9 +403,6 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo bool isOutOfProcessArtifact = _firstCallTo_OnSessionStartingAsync; _terminalTestReporter.ArtifactAdded( isOutOfProcessArtifact, - _assemblyName, - _targetFramework, - _shortArchitecture, testNodeStateChanged.TestNode.DisplayName, artifact.FileInfo.FullName); } @@ -408,18 +411,12 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo { case InProgressTestNodeStateProperty: _terminalTestReporter.TestInProgress( - _assemblyName, - _targetFramework, - _shortArchitecture, testNodeStateChanged.TestNode.Uid.Value, testNodeStateChanged.TestNode.DisplayName); break; case ErrorTestNodeStateProperty errorState: _terminalTestReporter.TestCompleted( - _assemblyName, - _targetFramework, - _shortArchitecture, testNodeStateChanged.TestNode.Uid.Value, testNodeStateChanged.TestNode.DisplayName, TestOutcome.Error, @@ -435,9 +432,6 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo case FailedTestNodeStateProperty failedState: _terminalTestReporter.TestCompleted( - _assemblyName, - _targetFramework, - _shortArchitecture, testNodeStateChanged.TestNode.Uid.Value, testNodeStateChanged.TestNode.DisplayName, TestOutcome.Fail, @@ -453,9 +447,6 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo case TimeoutTestNodeStateProperty timeoutState: _terminalTestReporter.TestCompleted( - _assemblyName, - _targetFramework, - _shortArchitecture, testNodeStateChanged.TestNode.Uid.Value, testNodeStateChanged.TestNode.DisplayName, TestOutcome.Timeout, @@ -471,9 +462,6 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo case CancelledTestNodeStateProperty cancelledState: _terminalTestReporter.TestCompleted( - _assemblyName, - _targetFramework, - _shortArchitecture, testNodeStateChanged.TestNode.Uid.Value, testNodeStateChanged.TestNode.DisplayName, TestOutcome.Canceled, @@ -489,9 +477,6 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo case PassedTestNodeStateProperty: _terminalTestReporter.TestCompleted( - _assemblyName, - _targetFramework, - _shortArchitecture, testNodeStateChanged.TestNode.Uid.Value, testNodeStateChanged.TestNode.DisplayName, outcome: TestOutcome.Passed, @@ -507,9 +492,6 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo case SkippedTestNodeStateProperty skippedState: _terminalTestReporter.TestCompleted( - _assemblyName, - _targetFramework, - _shortArchitecture, testNodeStateChanged.TestNode.Uid.Value, testNodeStateChanged.TestNode.DisplayName, TestOutcome.Skipped, @@ -524,12 +506,7 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo break; case DiscoveredTestNodeStateProperty: - _terminalTestReporter.TestDiscovered( - _assemblyName, - _targetFramework, - _shortArchitecture, - testNodeStateChanged.TestNode.DisplayName, - testNodeStateChanged.TestNode.Uid); + _terminalTestReporter.TestDiscovered(testNodeStateChanged.TestNode.DisplayName); break; } @@ -540,9 +517,6 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo bool isOutOfProcessArtifact = _firstCallTo_OnSessionStartingAsync; _terminalTestReporter.ArtifactAdded( isOutOfProcessArtifact, - _assemblyName, - _targetFramework, - _shortArchitecture, testName: null, artifact.FileInfo.FullName); } @@ -553,9 +527,6 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo bool isOutOfProcessArtifact = _firstCallTo_OnSessionStartingAsync; _terminalTestReporter.ArtifactAdded( isOutOfProcessArtifact, - _assemblyName, - _targetFramework, - _shortArchitecture, testName: null, artifact.FileInfo.FullName); } @@ -575,7 +546,7 @@ public async Task HandleProcessRoleAsync(TestProcessRole processRole) { await _policiesService.RegisterOnMaxFailedTestsCallbackAsync( async (maxFailedTests, _) => await DisplayAsync( - this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ReachedMaxFailedTestsMessage, maxFailedTests)))); + this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ReachedMaxFailedTestsMessage, maxFailedTests))).ConfigureAwait(false)).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Shipped.txt index 88740559f6..a3663087b9 100644 --- a/src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Shipped.txt +++ b/src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Shipped.txt @@ -174,6 +174,16 @@ Microsoft.Testing.Platform.Extensions.Messages.FailedTestNodeStateProperty.Faile Microsoft.Testing.Platform.Extensions.Messages.FileArtifact Microsoft.Testing.Platform.Extensions.Messages.FileArtifact.FileArtifact(System.IO.FileInfo! fileInfo, string! displayName, string? description = null) -> void Microsoft.Testing.Platform.Extensions.Messages.FileArtifact.FileInfo.get -> System.IO.FileInfo! +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Deconstruct(out System.IO.FileInfo! FileInfo, out string! DisplayName, out string? Description) -> void +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Description.get -> string? +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Description.init -> void +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.DisplayName.get -> string! +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.DisplayName.init -> void +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.FileArtifactProperty(Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty! original) -> void +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.FileArtifactProperty(System.IO.FileInfo! FileInfo, string! DisplayName, string? Description = null) -> void +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.FileInfo.get -> System.IO.FileInfo! +Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.FileInfo.init -> void Microsoft.Testing.Platform.Extensions.Messages.FileLocationProperty Microsoft.Testing.Platform.Extensions.Messages.FileLocationProperty.FileLocationProperty(string! FilePath, Microsoft.Testing.Platform.Extensions.Messages.LinePositionSpan LineSpan) -> void Microsoft.Testing.Platform.Extensions.Messages.FileLocationProperty.FilePath.get -> string! @@ -252,6 +262,9 @@ Microsoft.Testing.Platform.Extensions.Messages.TestMetadataProperty.Value.init - Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.AssemblyFullName.get -> string! Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.AssemblyFullName.init -> void +Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.Deconstruct(out string! AssemblyFullName, out string! Namespace, out string! TypeName, out string! MethodName, out int MethodArity, out string![]! ParameterTypeFullNames, out string! ReturnTypeFullName) -> void +Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.MethodArity.get -> int +Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.MethodArity.init -> void Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.MethodName.get -> string! Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.MethodName.init -> void Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.Namespace.get -> string! @@ -260,6 +273,7 @@ Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.Para Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.ParameterTypeFullNames.init -> void Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.ReturnTypeFullName.get -> string! Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.ReturnTypeFullName.init -> void +Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.TestMethodIdentifierProperty(string! AssemblyFullName, string! Namespace, string! TypeName, string! MethodName, int MethodArity, string![]! ParameterTypeFullNames, string! ReturnTypeFullName) -> void Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.TestMethodIdentifierProperty(string! AssemblyFullName, string! Namespace, string! TypeName, string! MethodName, string![]! ParameterTypeFullNames, string! ReturnTypeFullName) -> void Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.TypeName.get -> string! Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.TypeName.init -> void @@ -470,6 +484,9 @@ override Microsoft.Testing.Platform.Extensions.CommandLine.CommandLineOption.Equ override Microsoft.Testing.Platform.Extensions.CommandLine.CommandLineOption.GetHashCode() -> int override Microsoft.Testing.Platform.Extensions.Messages.DataWithSessionUid.ToString() -> string! override Microsoft.Testing.Platform.Extensions.Messages.FileArtifact.ToString() -> string! +override Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Equals(object? obj) -> bool +override Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.GetHashCode() -> int +override Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.ToString() -> string! override Microsoft.Testing.Platform.Extensions.Messages.PropertyBagData.ToString() -> string! override Microsoft.Testing.Platform.Extensions.Messages.SessionFileArtifact.ToString() -> string! override Microsoft.Testing.Platform.Extensions.Messages.TestNode.ToString() -> string! @@ -487,6 +504,8 @@ static Microsoft.Testing.Platform.Configurations.ConfigurationExtensions.GetTest static Microsoft.Testing.Platform.Extensions.CommandLine.ArgumentArity.operator !=(Microsoft.Testing.Platform.Extensions.CommandLine.ArgumentArity left, Microsoft.Testing.Platform.Extensions.CommandLine.ArgumentArity right) -> bool static Microsoft.Testing.Platform.Extensions.CommandLine.ArgumentArity.operator ==(Microsoft.Testing.Platform.Extensions.CommandLine.ArgumentArity left, Microsoft.Testing.Platform.Extensions.CommandLine.ArgumentArity right) -> bool static Microsoft.Testing.Platform.Extensions.Messages.DiscoveredTestNodeStateProperty.CachedInstance.get -> Microsoft.Testing.Platform.Extensions.Messages.DiscoveredTestNodeStateProperty! +static Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.operator !=(Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? left, Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? right) -> bool +static Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.operator ==(Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? left, Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? right) -> bool static Microsoft.Testing.Platform.Extensions.Messages.InProgressTestNodeStateProperty.CachedInstance.get -> Microsoft.Testing.Platform.Extensions.Messages.InProgressTestNodeStateProperty! static Microsoft.Testing.Platform.Extensions.Messages.PassedTestNodeStateProperty.CachedInstance.get -> Microsoft.Testing.Platform.Extensions.Messages.PassedTestNodeStateProperty! static Microsoft.Testing.Platform.Extensions.Messages.SkippedTestNodeStateProperty.CachedInstance.get -> Microsoft.Testing.Platform.Extensions.Messages.SkippedTestNodeStateProperty! @@ -529,3 +548,7 @@ static readonly Microsoft.Testing.Platform.Extensions.CommandLine.ArgumentArity. static readonly Microsoft.Testing.Platform.Extensions.CommandLine.ArgumentArity.ZeroOrOne -> Microsoft.Testing.Platform.Extensions.CommandLine.ArgumentArity static readonly Microsoft.Testing.Platform.TestHost.WellKnownClients.TestingPlatformConsole -> string! static readonly Microsoft.Testing.Platform.TestHost.WellKnownClients.VisualStudio -> string! +virtual Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.$() -> Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty! +virtual Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.EqualityContract.get -> System.Type! +virtual Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Equals(Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? other) -> bool +virtual Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.PrintMembers(System.Text.StringBuilder! builder) -> bool diff --git a/src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txt index 27ec037846..200755b523 100644 --- a/src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txt @@ -1,24 +1,5 @@ #nullable enable -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Deconstruct(out System.IO.FileInfo! FileInfo, out string! DisplayName, out string? Description) -> void -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Description.get -> string? -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Description.init -> void -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.DisplayName.get -> string! -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.DisplayName.init -> void -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.FileArtifactProperty(Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty! original) -> void -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.FileArtifactProperty(System.IO.FileInfo! FileInfo, string! DisplayName, string? Description = null) -> void -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.FileInfo.get -> System.IO.FileInfo! -Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.FileInfo.init -> void -Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.Deconstruct(out string! AssemblyFullName, out string! Namespace, out string! TypeName, out string! MethodName, out int MethodArity, out string![]! ParameterTypeFullNames, out string! ReturnTypeFullName) -> void -Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.MethodArity.get -> int -Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.MethodArity.init -> void -Microsoft.Testing.Platform.Extensions.Messages.TestMethodIdentifierProperty.TestMethodIdentifierProperty(string! AssemblyFullName, string! Namespace, string! TypeName, string! MethodName, int MethodArity, string![]! ParameterTypeFullNames, string! ReturnTypeFullName) -> void -override Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Equals(object? obj) -> bool -override Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.GetHashCode() -> int -override Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.ToString() -> string! -static Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.operator !=(Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? left, Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? right) -> bool -static Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.operator ==(Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? left, Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? right) -> bool -virtual Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.$() -> Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty! -virtual Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.EqualityContract.get -> System.Type! -virtual Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.Equals(Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty? other) -> bool -virtual Microsoft.Testing.Platform.Extensions.Messages.FileArtifactProperty.PrintMembers(System.Text.StringBuilder! builder) -> bool +Microsoft.Testing.Platform.Builder.ITestApplicationBuilder.RegisterTestFramework(System.Func! capabilitiesFactory, System.Func! frameworkFactory) -> Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! +*REMOVED*Microsoft.Testing.Platform.Builder.ITestApplicationBuilder.RegisterTestFramework(System.Func! capabilitiesFactory, System.Func! adapterFactory) -> Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! +Microsoft.Testing.Platform.Extensions.TestHost.ITestHostApplicationLifetime +Microsoft.Testing.Platform.TestHost.ITestHostManager.AddTestHostApplicationLifetime(System.Func! testHostApplicationLifetimeFactory) -> void diff --git a/src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionFilterFactory.cs b/src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionFilterFactory.cs index 14f7305ec4..5e7ef78150 100644 --- a/src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionFilterFactory.cs +++ b/src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionFilterFactory.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Testing.Platform.CommandLine; +using Microsoft.Testing.Platform.Extensions.Messages; using Microsoft.Testing.Platform.Helpers; using Microsoft.Testing.Platform.Resources; @@ -21,8 +22,18 @@ internal sealed class ConsoleTestExecutionFilterFactory(ICommandLineOptions comm public Task IsEnabledAsync() => Task.FromResult(true); - public Task<(bool Success, ITestExecutionFilter? TestExecutionFilter)> TryCreateAsync() => - _commandLineService.TryGetOptionArgumentList(TreeNodeFilterCommandLineOptionsProvider.TreenodeFilter, out string[]? filter) - ? Task.FromResult((true, (ITestExecutionFilter?)new TreeNodeFilter(filter[0]))) - : Task.FromResult((true, (ITestExecutionFilter?)new NopFilter())); + public Task<(bool Success, ITestExecutionFilter? TestExecutionFilter)> TryCreateAsync() + { + bool hasTreenodeFilter = _commandLineService.TryGetOptionArgumentList(TreeNodeFilterCommandLineOptionsProvider.TreenodeFilter, out string[]? treenodeFilter); + bool hasTestNodeUidFilter = _commandLineService.TryGetOptionArgumentList(PlatformCommandLineProvider.FilterUidOptionKey, out string[]? uidFilter); + ITestExecutionFilter filter = (hasTreenodeFilter, hasTestNodeUidFilter) switch + { + (true, true) => throw new NotSupportedException(PlatformResources.OnlyOneFilterSupported), + (true, false) => new TreeNodeFilter(treenodeFilter![0]), + (false, true) => new TestNodeUidListFilter([.. uidFilter!.Select(x => new TestNodeUid(x))]), + (false, false) => new NopFilter(), + }; + + return Task.FromResult<(bool, ITestExecutionFilter?)>((true, filter)); + } } diff --git a/src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.cs b/src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.cs index e4da6701f6..b31feb6d14 100644 --- a/src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.cs +++ b/src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.cs @@ -15,7 +15,7 @@ internal sealed class ConsoleTestExecutionRequestFactory(ICommandLineOptions com public async Task CreateRequestAsync(TestSessionContext session) { - (bool created, ITestExecutionFilter? testExecutionFilter) = await _testExecutionFilterFactory.TryCreateAsync(); + (bool created, ITestExecutionFilter? testExecutionFilter) = await _testExecutionFilterFactory.TryCreateAsync().ConfigureAwait(false); if (!created) { throw new InvalidOperationException(PlatformResources.CannotCreateTestExecutionFilterErrorMessage); diff --git a/src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterFactory.cs b/src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterFactory.cs index cc80518805..37b51a3d82 100644 --- a/src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterFactory.cs +++ b/src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterFactory.cs @@ -7,5 +7,5 @@ namespace Microsoft.Testing.Platform.Requests; internal interface ITestExecutionFilterFactory : IExtension { - public Task<(bool Success, ITestExecutionFilter? TestExecutionFilter)> TryCreateAsync(); + Task<(bool Success, ITestExecutionFilter? TestExecutionFilter)> TryCreateAsync(); } diff --git a/src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.cs b/src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.cs index f44eb1e82b..0ba1974901 100644 --- a/src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.cs +++ b/src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.cs @@ -37,40 +37,40 @@ public async Task ExecuteAsync(ITestFramework testFramework, ClientInfo client, { ILogger logger = ServiceProvider.GetLoggerFactory().CreateLogger(); - await logger.LogInformationAsync($"Test framework UID: '{testFramework.Uid}' Version: '{testFramework.Version}' DisplayName: '{testFramework.DisplayName}' Description: '{testFramework.Description}'"); + await logger.LogInformationAsync($"Test framework UID: '{testFramework.Uid}' Version: '{testFramework.Version}' DisplayName: '{testFramework.DisplayName}' Description: '{testFramework.Description}'").ConfigureAwait(false); foreach (ICapability capability in ServiceProvider.GetTestFrameworkCapabilities().Capabilities) { if (capability is ITestNodesTreeFilterTestFrameworkCapability testNodesTreeFilterCapability) { - await logger.LogInformationAsync($"ITestNodesTreeFilterCapability.IsSupported: {testNodesTreeFilterCapability.IsSupported}"); + await logger.LogInformationAsync($"ITestNodesTreeFilterCapability.IsSupported: {testNodesTreeFilterCapability.IsSupported}").ConfigureAwait(false); } } DateTimeOffset startTime = DateTimeOffset.UtcNow; var stopwatch = Stopwatch.StartNew(); SessionUid sessionId = ServiceProvider.GetTestSessionContext().SessionId; - CreateTestSessionResult createTestSessionResult = await testFramework.CreateTestSessionAsync(new(sessionId, client, cancellationToken)); - await HandleTestSessionResultAsync(createTestSessionResult.IsSuccess, createTestSessionResult.WarningMessage, createTestSessionResult.ErrorMessage); + CreateTestSessionResult createTestSessionResult = await testFramework.CreateTestSessionAsync(new(sessionId, client, cancellationToken)).ConfigureAwait(false); + await HandleTestSessionResultAsync(createTestSessionResult.IsSuccess, createTestSessionResult.WarningMessage, createTestSessionResult.ErrorMessage).ConfigureAwait(false); ITestExecutionRequestFactory testExecutionRequestFactory = ServiceProvider.GetTestExecutionRequestFactory(); - TestExecutionRequest request = await testExecutionRequestFactory.CreateRequestAsync(new(sessionId, client)); + TestExecutionRequest request = await testExecutionRequestFactory.CreateRequestAsync(new(sessionId, client)).ConfigureAwait(false); IMessageBus messageBus = ServiceProvider.GetMessageBus(); // Execute the test request - await ExecuteRequestAsync(testFramework, request, messageBus, cancellationToken); + await ExecuteRequestAsync(testFramework, request, messageBus, cancellationToken).ConfigureAwait(false); - CloseTestSessionResult closeTestSessionResult = await testFramework.CloseTestSessionAsync(new(sessionId, client, cancellationToken)); - await HandleTestSessionResultAsync(closeTestSessionResult.IsSuccess, closeTestSessionResult.WarningMessage, closeTestSessionResult.ErrorMessage); + CloseTestSessionResult closeTestSessionResult = await testFramework.CloseTestSessionAsync(new(sessionId, client, cancellationToken)).ConfigureAwait(false); + await HandleTestSessionResultAsync(closeTestSessionResult.IsSuccess, closeTestSessionResult.WarningMessage, closeTestSessionResult.ErrorMessage).ConfigureAwait(false); DateTimeOffset endTime = DateTimeOffset.UtcNow; - await messageBus.PublishAsync(this, new TestRequestExecutionTimeInfo(new TimingInfo(startTime, endTime, stopwatch.Elapsed))); + await messageBus.PublishAsync(this, new TestRequestExecutionTimeInfo(new TimingInfo(startTime, endTime, stopwatch.Elapsed))).ConfigureAwait(false); } public virtual async Task ExecuteRequestAsync(ITestFramework testFramework, TestExecutionRequest request, IMessageBus messageBus, CancellationToken cancellationToken) { using SemaphoreSlim requestSemaphore = new(0, 1); - await testFramework.ExecuteRequestAsync(new(request, messageBus, new SemaphoreSlimRequestCompleteNotifier(requestSemaphore), cancellationToken)); - await requestSemaphore.WaitAsync(cancellationToken); + await testFramework.ExecuteRequestAsync(new(request, messageBus, new SemaphoreSlimRequestCompleteNotifier(requestSemaphore), cancellationToken)).ConfigureAwait(false); + await requestSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); } private async Task HandleTestSessionResultAsync(bool isSuccess, string? warningMessage, string? errorMessage) @@ -78,14 +78,14 @@ private async Task HandleTestSessionResultAsync(bool isSuccess, string? warningM if (warningMessage is not null) { IOutputDevice outputDisplay = ServiceProvider.GetOutputDevice(); - await outputDisplay.DisplayAsync(this, new WarningMessageOutputDeviceData(warningMessage)); + await outputDisplay.DisplayAsync(this, new WarningMessageOutputDeviceData(warningMessage)).ConfigureAwait(false); } if (!isSuccess) { ITestApplicationProcessExitCode testApplicationProcessExitCode = ServiceProvider.GetTestApplicationProcessExitCode(); await testApplicationProcessExitCode.SetTestAdapterTestSessionFailureAsync(errorMessage - ?? PlatformResources.TestHostAdapterInvokerFailedTestSessionErrorMessage); + ?? PlatformResources.TestHostAdapterInvokerFailedTestSessionErrorMessage).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/OperatorKind.cs b/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/OperatorKind.cs index b9c7da2819..68de3b9293 100644 --- a/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/OperatorKind.cs +++ b/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/OperatorKind.cs @@ -55,4 +55,9 @@ internal enum OperatorKind /// Operator used for combining multiple filters with a logical AND. /// And, + + /// + /// Operator used to negate an expression. + /// + UnaryNot, } diff --git a/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs b/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs index 7cb4ff2a9e..e7d3eaff93 100644 --- a/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs +++ b/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs @@ -77,7 +77,7 @@ private static List ParseFilter(string filter) // of an expression operators are not allowed. bool isOperatorAllowed = false; bool isPropAllowed = false; - + bool lastWasOpenParen = false; OperatorKind topStackOperator; foreach (string token in TokenizeFilter(filter)) @@ -225,6 +225,10 @@ private static List ParseFilter(string filter) isPropAllowed = false; break; + case "!" when lastWasOpenParen: + operatorStack.Push(OperatorKind.UnaryNot); + break; + default: expressionStack.Push(new ValueExpression(token)); @@ -232,6 +236,8 @@ private static List ParseFilter(string filter) isPropAllowed = true; break; } + + lastWasOpenParen = token == "("; } // Note: What we should end with (as long as the expression is a valid filter) @@ -262,11 +268,9 @@ static void ProcessHigherPrecedenceOperators( Stack operatorStack, OperatorKind currentOp) { - OperatorKind topStackOperator; - while (operatorStack.Count != 0 && operatorStack.Peek() > currentOp) { - topStackOperator = operatorStack.Pop(); + OperatorKind topStackOperator = operatorStack.Pop(); ProcessStackOperator(topStackOperator, expressionStack, operatorStack); break; } @@ -352,6 +356,11 @@ private static void ProcessStackOperator(OperatorKind op, Stack TokenizeFilter(string filter) yield return "!="; i++; } + else if (i - 1 >= 0 && filter[i - 1] == '(') + { + // Note: If we have a ! at the start of an expression, we should + // treat it as a NOT operator. + yield return "!"; + } else { goto default; @@ -550,7 +565,7 @@ private static bool MatchProperties( => propertyExpr switch { PropertyExpression { PropertyName: var propExpr, Value: var valueExpr } - => properties.AsEnumerable().Any(prop => prop is KeyValuePairStringProperty kvpProperty && propExpr.Regex.IsMatch(kvpProperty.Key) && valueExpr.Regex.IsMatch(kvpProperty.Value)), + => properties.AsEnumerable().Any(prop => IsMatchingProperty(prop, propExpr, valueExpr)), OperatorExpression { Op: FilterOperator.Or, SubExpressions: var subExprs } => subExprs.Any(expr => MatchProperties(expr, properties)), OperatorExpression { Op: FilterOperator.And, SubExpressions: var subExprs } @@ -559,4 +574,14 @@ private static bool MatchProperties( => !MatchProperties(subExprs.Single(), properties), _ => throw ApplicationStateGuard.Unreachable(), }; + + private static bool IsMatchingProperty(IProperty prop, ValueExpression propExpr, ValueExpression valueExpr) => + prop switch + { +#pragma warning disable CS0618 // Type or member is obsolete + KeyValuePairStringProperty kvpProperty => propExpr.Regex.IsMatch(kvpProperty.Key) && valueExpr.Regex.IsMatch(kvpProperty.Value), +#pragma warning restore CS0618 // Type or member is obsolete + TestMetadataProperty testMetadataProperty => propExpr.Regex.IsMatch(testMetadataProperty.Key) && valueExpr.Regex.IsMatch(testMetadataProperty.Value), + _ => false, + }; } diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx b/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx index b894e8fe79..9ca55934cd 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx +++ b/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx @@ -136,7 +136,7 @@ Extension of type '{0}' is not implementing the required '{1}' interface - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} A duplicate key '{0}' was found @@ -444,12 +444,6 @@ The default is TestResults in the directory that contains the test application.< JsonRpc server to client handshake, implementation based on the test platform protocol specification. - - Starting server. Listening on port '{0}' - - - The communication protocol '{0}' is not supported - Telemetry --------- @@ -713,4 +707,10 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is The current test framework does not implement 'IGracefulStopTestExecutionCapability' which is required for '--maximum-failed-tests' feature. + + Provides a list of test node UIDs to filter by. + + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf index 850364800b..2dd7c37384 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - Už je zaregistrované jiné rozšíření se stejným UID {0}. Zaregistrované rozšíření je typu {1}. + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + Rozšíření se stejným UID {0} již byla zaregistrována. Registrovaná rozšíření jsou těchto typů: {1} @@ -431,6 +431,11 @@ Nenalezeno + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + Předávání možností --treenode-filter a --filter-uid není podporováno. + + Out of process file artifacts produced: Vytvořené artefakty souboru mimo proces: @@ -533,6 +538,11 @@ Dostupné hodnoty jsou Trace, Debug, Information, Warning, Error a Critical.„ --{0}“ očekává jeden argument int PID. + + Provides a list of test node UIDs to filter by. + Poskytuje seznam identifikátorů UID testovacích uzlů, podle kterých lze filtrovat. + + Show the command line help. Umožňuje zobrazit nápovědu příkazového řádku. @@ -733,11 +743,6 @@ Může mít jenom jeden argument jako řetězec ve formátu <value>[h|m|s] Standardní výstup - - Starting server. Listening on port '{0}' - Spouští se server. Naslouchání na portu {0} - - Starting test session. Spouští se testovací relace. @@ -952,11 +957,6 @@ Platné hodnoty jsou Normal a Detailed. Výchozí hodnota je Normal. Neočekávaný stav v souboru {0} na řádku {1} - - The communication protocol '{0}' is not supported - Komunikační protokol {0} není podporován. - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Neošetřená výjimka: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf index f945fff2db..2901eea04a 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - Eine andere Erweiterung mit derselben UID "{0}" wurde bereits registriert. Die registrierte Erweiterung ist vom Typ "{1}" + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + Erweiterungen mit derselben UID „{0}“ wurden bereits registriert. Registrierte Erweiterungen haben die Typen: {1} @@ -431,6 +431,11 @@ Nicht gefunden + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + Das gleichzeitige Übergeben von „--treenode-filter“ und „--filter-uid“ wird nicht unterstützt. + + Out of process file artifacts produced: Nicht verarbeitete Dateiartefakte erstellt: @@ -533,6 +538,11 @@ Die verfügbaren Werte sind "Trace", "Debug", "Information", "Warning", "Error" "--{0}" erwartet ein einzelnes int-PID-Argument. + + Provides a list of test node UIDs to filter by. + Stellt eine Liste der UIDs von Testknoten bereit, nach denen gefiltert werden kann. + + Show the command line help. Zeigen Sie die Hilfe zur Befehlszeile an. @@ -733,11 +743,6 @@ Nimmt ein Argument als Zeichenfolge im Format <value>[h|m|s], wobei "value Standardausgabe - - Starting server. Listening on port '{0}' - Server wird gestartet. An Port "{0}" lauschen - - Starting test session. Die Testsitzung wird gestartet. @@ -952,11 +957,6 @@ Gültige Werte sind „Normal“, „Detailed“. Der Standardwert ist „Normal Unerwarteter Status in Datei "{0}" in Zeile "{1}" - - The communication protocol '{0}' is not supported - Das Kommunikationsprotokoll "{0}" wird nicht unterstützt - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Ausnahmefehler: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf index a264892a13..613ea681c3 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - Ya se registró otra extensión con el mismo UID "{0}". La extensión registrada es de tipo "{1}" + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + Ya se han registrado extensiones con el mismo UID ''{0}". Las extensiones registradas son de los siguientes tipos: {1} @@ -431,6 +431,11 @@ No se encontró + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + No se admite el paso de "--treenode-filter" y "--filter-uid". + + Out of process file artifacts produced: Artefactos de archivo fuera de proceso producidos: @@ -533,6 +538,11 @@ Los valores disponibles son 'Seguimiento', 'Depurar', 'Información', 'Advertenc '--{0}' espera un único argumento PID entero + + Provides a list of test node UIDs to filter by. + Proporciona una lista de UID de nodo de prueba por los que filtrar. + + Show the command line help. Muestre la ayuda de la línea de comandos. @@ -733,11 +743,6 @@ Toma un argumento como cadena con el formato <value>[h|m|s] donde 'value' Salida estándar - - Starting server. Listening on port '{0}' - Iniciando el servidor. Escuchando en el puerto '{0}' - - Starting test session. Iniciando sesión de prueba. @@ -952,11 +957,6 @@ Los valores válidos son 'Normal', 'Detallado'. El valor predeterminado es 'Norm Estado inesperado en el archivo “{0}” en la línea “{1}” - - The communication protocol '{0}' is not supported - No se admite el protocolo de comunicación '{0}' - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] excepción no controlada: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf index 6c08b3f8dc..6ac9dfb271 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - Désolé, une autre extension avec le même UID « {0} » a déjà été inscrite. Désolé, l’extension inscrite est de type « {1} » + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + Les extensions ayant le même UID « {0} » ont déjà été enregistrées. Les extensions enregistrées sont de types : {1} @@ -431,6 +431,11 @@ Introuvable + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + Vous ne pouvez pas passer à la fois « --treenode-filter » et « --filter-uid ». Cette action n’est pas prise en charge. + + Out of process file artifacts produced: Artefacts de fichier hors processus produits : @@ -533,6 +538,11 @@ Les valeurs disponibles sont « Trace », « Debug », « Information », « --{0} » attend un seul argument PID int + + Provides a list of test node UIDs to filter by. + Fournit la liste des IUD de nœud de test à filtrer. + + Show the command line help. Afficher l’aide de la ligne de commande. @@ -733,11 +743,6 @@ Prend un argument sous forme de chaîne au format <value>[h|m|s] où « v Sortie standard - - Starting server. Listening on port '{0}' - Démarrage du serveur. Écoute sur le port « {0} » - - Starting test session. Démarrage de la session de test. @@ -952,11 +957,6 @@ Les valeurs valides sont « Normal » et « Détaillé ». La valeur par dé État inattendu dans le fichier « {0} » à la ligne « {1} » - - The communication protocol '{0}' is not supported - Le protocole de communication « {0} » n’est pas pris en charge - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] exception non prise en charge : {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf index bb1706795d..e2b61cae0c 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - È già stata registrata un'altra estensione con lo stesso UID '{0}'. L'estensione registrata è di tipo '{1}' + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + Le estensioni con lo stesso UID '{0}' sono già state registrate. Le estensioni registrate sono di tipo: {1} @@ -431,6 +431,11 @@ Non trovato + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + Il passaggio di '--treenode-filter' e '--filter-uid' non è supportato. + + Out of process file artifacts produced: Artefatti file non in elaborazione prodotti: @@ -533,6 +538,11 @@ I valori disponibili sono 'Trace', 'Debug', 'Information', 'Warning', 'Error' e '--{0}' prevede un singolo argomento PID int + + Provides a list of test node UIDs to filter by. + Fornisce un elenco di UID dei nodi di prova per il filtraggio. + + Show the command line help. Mostra la Guida della riga di comando. @@ -733,11 +743,6 @@ Acquisisce un argomento come stringa nel formato <value>[h|m|s] dove 'valu Output standard - - Starting server. Listening on port '{0}' - Avvio del server. In ascolto sulla porta '{0}' - - Starting test session. Avvio della sessione di test. @@ -952,11 +957,6 @@ I valori validi sono 'Normal', 'Detailed'. L'impostazione predefinita è 'Normal Stato imprevisto nel file '{0}' alla riga '{1}' - - The communication protocol '{0}' is not supported - Il protocollo di comunicazione '{0}' non è supportato - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] eccezione non gestita: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf index 825b4cc593..1998a73c03 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - 同じ UID '{0}' を持つ別の拡張機能が既に登録されています。登録されている拡張機能の種類は '{1}' です + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + 同じ UID '{0}' の拡張機能は既に登録されています。登録済みの拡張機能の種類: {1} @@ -431,6 +431,11 @@ 見つかりません + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + '--treenode-filter' と '--filter-uid' の両方を渡すことはサポートされていません。 + + Out of process file artifacts produced: アウトプロセスのファイル成果物が生成されました: @@ -534,6 +539,11 @@ The available values are 'Trace', 'Debug', 'Information', 'Warning', 'Error', an '--{0}' には 1 つの int PID 引数が必要です + + Provides a list of test node UIDs to filter by. + フィルター対象のテスト ノード UID のリストを提供します。 + + Show the command line help. コマンド ラインヘルプを表示します。 @@ -734,11 +744,6 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is 標準出力 - - Starting server. Listening on port '{0}' - サーバーを起動しています。ポート '{0}' で聞いています - - Starting test session. テスト セッションを開始しています。 @@ -953,11 +958,6 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. ファイル '{0}' の行 '{1}' の予期しない状態 - - The communication protocol '{0}' is not supported - 通信プロトコル '{0}' はサポートされていません - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} ハンドルされない例外 [ServerTestHost.OnTaskSchedulerUnobservedTaskException]: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf index 5b3fd3add9..e2d0097ada 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - UID '{0}'과(와) 동일한 다른 확장이 이미 등록되었습니다. 등록된 확장은 '{1}' 형식임 + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + UID가 '{0}’인 확장이 이미 등록되었습니다. 등록된 확장은 다음과 같은 형식입니다. {1} @@ -431,6 +431,11 @@ 찾을 수 없음 + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + '--treenode-filter'와 '--filter-uid'를 동시에 전달하는 것은 지원되지 않습니다. + + Out of process file artifacts produced: 생성된 Out of process 파일 아티팩트: @@ -533,6 +538,11 @@ The available values are 'Trace', 'Debug', 'Information', 'Warning', 'Error', an '--{0}'에는 단일 int PID 인수가 필요합니다. + + Provides a list of test node UIDs to filter by. + 필터링에 사용할 테스트 노드 UID 목록을 제공합니다. + + Show the command line help. 명령줄 도움말을 표시합니다. @@ -733,11 +743,6 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is 표준 출력 - - Starting server. Listening on port '{0}' - 서버를 시작하는 중입니다. 포트 '{0}'에서 수신 대기 중 - - Starting test session. 테스트 세션을 시작하는 중입니다. @@ -952,11 +957,6 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. '{1}' 줄의 '{0}' 파일에 예기치 않은 상태가 있습니다. - - The communication protocol '{0}' is not supported - 통신 프로토콜 '{0}'은(는) 지원되지 않습니다. - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} 처리되지 않은 예외 [ServerTestHost.OnTaskSchedulerUnobservedTaskException]: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf index 4f723bdd74..9f96ada5b5 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - Inne rozszerzenie o tym samym identyfikatorze UID „{0}” zostało już zarejestrowane. Zarejestrowane rozszerzenie jest typu „{1}” + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + Rozszerzenia o tym samym identyfikatorze UID „{0}” zostały już zarejestrowane. Zarejestrowane rozszerzenia są typu: {1} @@ -431,6 +431,11 @@ Nie znaleziono + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + Przekazywanie obu parametrów „--treenode-filter” i „--filter-uid” jest nieobsługiwane. + + Out of process file artifacts produced: Wygenerowane artefakty pliku poza procesem: @@ -533,6 +538,11 @@ Dostępne wartości to „Trace”, „Debug”, „Information”, „Warning „--{0}” oczekuje pojedynczego argumentu int identyfikatora PID + + Provides a list of test node UIDs to filter by. + Zawiera listę identyfikatorów UID węzła testowego do filtrowania. + + Show the command line help. Pokaż pomoc wiersza polecenia. @@ -733,11 +743,6 @@ Pobiera jeden argument jako ciąg w formacie <value>[h|m|s], gdzie element Standardowe dane wyjściowe - - Starting server. Listening on port '{0}' - Uruchamianie serwera. Nasłuchiwanie na porcie „{0}” - - Starting test session. Rozpoczynanie sesji testowej. @@ -952,11 +957,6 @@ Prawidłowe wartości to „Normalne”, „Szczegółowe”. Wartość domyśln Nieoczekiwany stan w pliku „{0}” w wierszu „{1}” - - The communication protocol '{0}' is not supported - Protokół komunikacyjny „{0}” nie jest obsługiwany - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Nieobsługiwany wyjątek: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf index df330a27f2..a0884e336d 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - Outra extensão com o mesmo UID “{0}” já foi registrada. A extensão registrada é do tipo “{1}” + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + Extensões com o mesmo UID '{0}' já foram registradas. As extensões registradas são dos tipos: {1} @@ -431,6 +431,11 @@ Não encontrado + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + Não há suporte para a passagem de "--treenode-filter" e "--filter-uid". + + Out of process file artifacts produced: Artefatos de arquivo fora do processo produzidos: @@ -533,6 +538,11 @@ Os valores disponíveis são 'Rastreamento', 'Depuração', 'Informação', 'Avi "--{0}" espera um único argumento int PID + + Provides a list of test node UIDs to filter by. + Fornece uma lista de UIDs de nó de teste para filtrar. + + Show the command line help. Mostrar a ajuda da linha de comando. @@ -733,11 +743,6 @@ Recebe um argumento como cadeia de caracteres no formato <valor>[h|m|s] em Saída padrão - - Starting server. Listening on port '{0}' - Iniciando servidor. Escutando na porta “{0}” - - Starting test session. Iniciando sessão de teste. @@ -952,11 +957,6 @@ Os valores válidos são “Normal”, “Detalhado”. O padrão é “Normal Estado inesperado no arquivo '{0}' na linha '{1}' - - The communication protocol '{0}' is not supported - O protocolo de comunicação “{0}” não tem suporte - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] exceção sem tratamento: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf index 85478d870f..e57b6d1544 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - Уже зарегистрировано другое расширение с таким же ИД пользователя "{0}". Зарегистрированное расширение относится к типу "{1}" + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + Расширения с тем же UID "{0}" уже зарегистрированы. Зарегистрированные расширения относятся к следующим типам: {1} @@ -431,6 +431,11 @@ Не найдено + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + Передача одновременно "--treenode-filter" и "--filter-uid" не поддерживается. + + Out of process file artifacts produced: Созданные вне процесса артефакты файлов: @@ -533,6 +538,11 @@ The available values are 'Trace', 'Debug', 'Information', 'Warning', 'Error', an "--{0}" ожидает один аргумент int PID + + Provides a list of test node UIDs to filter by. + Предоставляет список UID тестовых узлов для фильтрации. + + Show the command line help. Показать справку по командной строке. @@ -733,11 +743,6 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is Стандартный вывод - - Starting server. Listening on port '{0}' - Выполняется запуск сервера. Прослушивание порта "{0}" - - Starting test session. Запуск тестового сеанса. @@ -952,11 +957,6 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. Непредвиденное состояние в файле "{0}" в строке "{1}" - - The communication protocol '{0}' is not supported - Протокол коммуникации "{0}" не поддерживается - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] необработанное исключение: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf index 4c7c2fbd6c..4008f64005 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - Aynı UID '{0}' olan başka bir uzantı zaten kayıtlı. Kayıtlı uzantı '{1}' türünde + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + Aynı UID ‘{0}’ ile uzantılar zaten kayıtlıdır. Kayıtlı uzantılar şu türlerde olabilir: {1} @@ -431,6 +431,11 @@ Bulunamadı + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + Hem ‘--treenode-filter’ hem de ‘--filter-uid’ parametrelerinin birlikte kullanılması desteklenmemektedir. + + Out of process file artifacts produced: Üretilen işlem dışı dosya yapıtları: @@ -533,6 +538,11 @@ Kullanılabilir değerler: 'Trace', 'Debug', 'Information', 'Warning', 'Error' v '--{0}', tek bir int PID bağımsız değişkeni bekliyor + + Provides a list of test node UIDs to filter by. + Filtrelemek için test düğümü UID'lerinin bir listesini sağlar. + + Show the command line help. Komut satırı yardımını gösterir. @@ -733,11 +743,6 @@ Bir bağımsız değişkeni, 'value' değerinin kayan olduğu <value>[h|m| Standart çıkış - - Starting server. Listening on port '{0}' - Sunucu başlatılıyor. '{0}' bağlantı noktasında dinleme işlemi yapılıyor - - Starting test session. Test oturumu başlatılıyor. @@ -952,11 +957,6 @@ Geçerli değerler: ‘Normal’, ‘Ayrıntılı’. Varsayılan değer: ‘Nor '{0}' dosyasında '{1}' satırındaki durum beklenmiyordu - - The communication protocol '{0}' is not supported - '{0}' iletişim protokolü desteklenmiyor - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] özel durum: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf index 15741f97e4..5fdcc9180a 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - 已注册另一个具有相同 UID“{0}”的扩展。已注册的扩展属于“{1}”类型 + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + 已注册具有相同 UID“{0}”的扩展。已注册的扩展类型如下: {1} @@ -431,6 +431,11 @@ 未找到 + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + 不支持同时传递“--treenode-filter”和“--filter-uid”。 + + Out of process file artifacts produced: 生成的进程外文件项目: @@ -533,6 +538,11 @@ The available values are 'Trace', 'Debug', 'Information', 'Warning', 'Error', an “--{0}”需要单个 int PID 参数 + + Provides a list of test node UIDs to filter by. + 提供用作筛选依据的测试节点 UID 列表。 + + Show the command line help. 显示命令行帮助。 @@ -733,11 +743,6 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is 标准输出 - - Starting server. Listening on port '{0}' - 正在启动服务器。正在侦听端口“{0}” - - Starting test session. 正在启动测试会话。 @@ -952,11 +957,6 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. 文件“{0}”中第“{1}”行出现意外状态 - - The communication protocol '{0}' is not supported - 不支持通信协议“{0}” - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] 未经处理的异常: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf index a788e45f92..60fd30786c 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf @@ -250,8 +250,8 @@ - Another extension with same the same UID '{0}' has already been registered. Registered extension is of type '{1}' - 已註冊另一個具有相同 UID '{0}' 的延伸模組。已註冊的延伸模組屬於 '{1}' 類型 + Extensions with the same UID '{0}' have already been registered. Registered extensions are of types: {1} + 具有相同 UID '{0}' 的延伸模組已經註冊。已註冊的延伸模組類型為: {1} @@ -431,6 +431,11 @@ 找不到 + + Passing both '--treenode-filter' and '--filter-uid' is unsupported. + 不支援同時傳遞 '--treenode-filter' 和 '--filter-uid'。 + + Out of process file artifacts produced: 產生的流程外檔案成品: @@ -533,6 +538,11 @@ The available values are 'Trace', 'Debug', 'Information', 'Warning', 'Error', an '--{0}' 需要單一 int PID 引數 + + Provides a list of test node UIDs to filter by. + 提供要篩選的測試節點 UID 清單。 + + Show the command line help. 顯示命令列說明。 @@ -733,11 +743,6 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is 標準輸出 - - Starting server. Listening on port '{0}' - 正在啟動伺服器。正在連接埠 '{0}' 上聆聽 - - Starting test session. 正在啟動測試會話。 @@ -952,11 +957,6 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. 檔案 '{0}' 的第 '{1}' 行出現未預期的狀態 - - The communication protocol '{0}' is not supported - 通訊協定 '{0}' 不受支援 - - [ServerTestHost.OnTaskSchedulerUnobservedTaskException] Unhandled exception: {0} [ServerTestHost.OnTaskSchedulerUnobservedTaskException] 未處理的例外狀況: {0} diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestConnection.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestConnection.cs index 8b1d908167..faeea63c18 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestConnection.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestConnection.cs @@ -20,7 +20,6 @@ internal sealed class DotnetTestConnection : IPushOnlyProtocol, IDisposable { private readonly CommandLineHandler _commandLineHandler; - private readonly IProcessHandler _processHandler; private readonly IEnvironment _environment; private readonly ITestApplicationModuleInfo _testApplicationModuleInfo; private readonly ITestApplicationCancellationTokenSource _cancellationTokenSource; @@ -29,10 +28,9 @@ internal sealed class DotnetTestConnection : IPushOnlyProtocol, public static string InstanceId { get; } = Guid.NewGuid().ToString("N"); - public DotnetTestConnection(CommandLineHandler commandLineHandler, IProcessHandler processHandler, IEnvironment environment, ITestApplicationModuleInfo testApplicationModuleInfo, ITestApplicationCancellationTokenSource cancellationTokenSource) + public DotnetTestConnection(CommandLineHandler commandLineHandler, IEnvironment environment, ITestApplicationModuleInfo testApplicationModuleInfo, ITestApplicationCancellationTokenSource cancellationTokenSource) { _commandLineHandler = commandLineHandler; - _processHandler = processHandler; _environment = environment; _testApplicationModuleInfo = testApplicationModuleInfo; _cancellationTokenSource = cancellationTokenSource; @@ -61,7 +59,7 @@ public async Task AfterCommonServiceSetupAsync() _dotnetTestPipeClient = new(arguments[0]); _dotnetTestPipeClient.RegisterAllSerializers(); - await _dotnetTestPipeClient.ConnectAsync(_cancellationTokenSource.CancellationToken); + await _dotnetTestPipeClient.ConnectAsync(_cancellationTokenSource.CancellationToken).ConfigureAwait(false); } } @@ -69,7 +67,7 @@ public async Task HelpInvokedAsync() { RoslynDebug.Assert(_dotnetTestPipeClient is not null); - List commandLineHelpOptions = new(); + List commandLineHelpOptions = []; foreach (ICommandLineOptionsProvider commandLineOptionProvider in _commandLineHandler.CommandLineOptionsProviders) { if (commandLineOptionProvider is IToolCommandLineOptionsProvider) @@ -87,7 +85,7 @@ public async Task HelpInvokedAsync() } } - await _dotnetTestPipeClient.RequestReplyAsync(new CommandLineOptionMessages(_testApplicationModuleInfo.GetCurrentTestApplicationFullPath(), commandLineHelpOptions.OrderBy(option => option.Name).ToArray()), _cancellationTokenSource.CancellationToken); + await _dotnetTestPipeClient.RequestReplyAsync(new CommandLineOptionMessages(_testApplicationModuleInfo.GetCurrentTestApplicationFullPath(), [.. commandLineHelpOptions.OrderBy(option => option.Name)]), _cancellationTokenSource.CancellationToken).ConfigureAwait(false); } public async Task IsCompatibleProtocolAsync(string hostType) @@ -97,7 +95,7 @@ public async Task IsCompatibleProtocolAsync(string hostType) string supportedProtocolVersions = ProtocolConstants.Version; HandshakeMessage handshakeMessage = new(new Dictionary { - { HandshakeMessagePropertyNames.PID, _processHandler.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture) }, + { HandshakeMessagePropertyNames.PID, _environment.ProcessId.ToString(CultureInfo.InvariantCulture) }, { HandshakeMessagePropertyNames.Architecture, RuntimeInformation.ProcessArchitecture.ToString() }, { HandshakeMessagePropertyNames.Framework, RuntimeInformation.FrameworkDescription }, { HandshakeMessagePropertyNames.OS, RuntimeInformation.OSDescription }, @@ -108,7 +106,7 @@ public async Task IsCompatibleProtocolAsync(string hostType) { HandshakeMessagePropertyNames.InstanceId, InstanceId }, }); - HandshakeMessage response = await _dotnetTestPipeClient.RequestReplyAsync(handshakeMessage, _cancellationTokenSource.CancellationToken); + HandshakeMessage response = await _dotnetTestPipeClient.RequestReplyAsync(handshakeMessage, _cancellationTokenSource.CancellationToken).ConfigureAwait(false); return response.Properties?.TryGetValue(HandshakeMessagePropertyNames.SupportedProtocolVersions, out string? protocolVersion) == true && IsVersionCompatible(protocolVersion, supportedProtocolVersions); @@ -123,19 +121,19 @@ public async Task SendMessageAsync(IRequest message) switch (message) { case DiscoveredTestMessages discoveredTestMessages: - await _dotnetTestPipeClient.RequestReplyAsync(discoveredTestMessages, _cancellationTokenSource.CancellationToken); + await _dotnetTestPipeClient.RequestReplyAsync(discoveredTestMessages, _cancellationTokenSource.CancellationToken).ConfigureAwait(false); break; case TestResultMessages testResultMessages: - await _dotnetTestPipeClient.RequestReplyAsync(testResultMessages, _cancellationTokenSource.CancellationToken); + await _dotnetTestPipeClient.RequestReplyAsync(testResultMessages, _cancellationTokenSource.CancellationToken).ConfigureAwait(false); break; case FileArtifactMessages fileArtifactMessages: - await _dotnetTestPipeClient.RequestReplyAsync(fileArtifactMessages, _cancellationTokenSource.CancellationToken); + await _dotnetTestPipeClient.RequestReplyAsync(fileArtifactMessages, _cancellationTokenSource.CancellationToken).ConfigureAwait(false); break; case TestSessionEvent testSessionEvent: - await _dotnetTestPipeClient.RequestReplyAsync(testSessionEvent, _cancellationTokenSource.CancellationToken); + await _dotnetTestPipeClient.RequestReplyAsync(testSessionEvent, _cancellationTokenSource.CancellationToken).ConfigureAwait(false); break; } } @@ -149,7 +147,7 @@ public async ValueTask DisposeAsync() { if (_dotnetTestPipeClient is not null) { - await _dotnetTestPipeClient.DisposeAsync(); + await _dotnetTestPipeClient.DisposeAsync().ConfigureAwait(false); } } #endif diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/DotnetTestDataConsumer.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/DotnetTestDataConsumer.cs index 702a3bd9be..f15c188df0 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/DotnetTestDataConsumer.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/DotnetTestDataConsumer.cs @@ -21,13 +21,13 @@ public DotnetTestDataConsumer(DotnetTestConnection dotnetTestConnection, IEnviro _environment = environment; } - public Type[] DataTypesConsumed => new[] - { + public Type[] DataTypesConsumed => + [ typeof(TestNodeUpdateMessage), typeof(SessionFileArtifact), typeof(FileArtifact), - typeof(TestRequestExecutionTimeInfo), - }; + typeof(TestRequestExecutionTimeInfo) + ]; public string Uid => nameof(DotnetTestDataConsumer); @@ -59,14 +59,13 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella DiscoveredTestMessages discoveredTestMessages = new( ExecutionId, DotnetTestConnection.InstanceId, - new[] - { + [ new DiscoveredTestMessage( testNodeUpdateMessage.TestNode.Uid.Value, - testNodeUpdateMessage.TestNode.DisplayName), - }); + testNodeUpdateMessage.TestNode.DisplayName) + ]); - await _dotnetTestConnection.SendMessageAsync(discoveredTestMessages); + await _dotnetTestConnection.SendMessageAsync(discoveredTestMessages).ConfigureAwait(false); break; case TestStates.Passed: @@ -74,8 +73,7 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella TestResultMessages testResultMessages = new( ExecutionId, DotnetTestConnection.InstanceId, - new[] - { + [ new SuccessfulTestResultMessage( testNodeUpdateMessage.TestNode.Uid.Value, testNodeUpdateMessage.TestNode.DisplayName, @@ -84,11 +82,11 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella testNodeDetails.Reason ?? string.Empty, testNodeDetails.StandardOutput ?? string.Empty, testNodeDetails.StandardError ?? string.Empty, - testNodeUpdateMessage.SessionUid.Value), - }, - Array.Empty()); + testNodeUpdateMessage.SessionUid.Value) + ], + []); - await _dotnetTestConnection.SendMessageAsync(testResultMessages); + await _dotnetTestConnection.SendMessageAsync(testResultMessages).ConfigureAwait(false); break; case TestStates.Failed: @@ -98,9 +96,8 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella testResultMessages = new( ExecutionId, DotnetTestConnection.InstanceId, - Array.Empty(), - new[] - { + [], + [ new FailedTestResultMessage( testNodeUpdateMessage.TestNode.Uid.Value, testNodeUpdateMessage.TestNode.DisplayName, @@ -110,10 +107,10 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella testNodeDetails.Exceptions, testNodeDetails.StandardOutput ?? string.Empty, testNodeDetails.StandardError ?? string.Empty, - testNodeUpdateMessage.SessionUid.Value), - }); + testNodeUpdateMessage.SessionUid.Value) + ]); - await _dotnetTestConnection.SendMessageAsync(testResultMessages); + await _dotnetTestConnection.SendMessageAsync(testResultMessages).ConfigureAwait(false); break; } @@ -122,18 +119,17 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella FileArtifactMessages testFileArtifactMessages = new( ExecutionId, DotnetTestConnection.InstanceId, - new[] - { - new FileArtifactMessage( - artifact.FileInfo.FullName, - artifact.DisplayName, - artifact.Description ?? string.Empty, - testNodeUpdateMessage.TestNode.Uid.Value, - testNodeUpdateMessage.TestNode.DisplayName, - testNodeUpdateMessage.SessionUid.Value), - }); - - await _dotnetTestConnection.SendMessageAsync(testFileArtifactMessages); + [ + new FileArtifactMessage( + artifact.FileInfo.FullName, + artifact.DisplayName, + artifact.Description ?? string.Empty, + testNodeUpdateMessage.TestNode.Uid.Value, + testNodeUpdateMessage.TestNode.DisplayName, + testNodeUpdateMessage.SessionUid.Value) + ]); + + await _dotnetTestConnection.SendMessageAsync(testFileArtifactMessages).ConfigureAwait(false); } break; @@ -142,36 +138,34 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella var fileArtifactMessages = new FileArtifactMessages( ExecutionId, DotnetTestConnection.InstanceId, - new[] - { + [ new FileArtifactMessage( sessionFileArtifact.FileInfo.FullName, sessionFileArtifact.DisplayName, sessionFileArtifact.Description ?? string.Empty, string.Empty, string.Empty, - sessionFileArtifact.SessionUid.Value), - }); + sessionFileArtifact.SessionUid.Value) + ]); - await _dotnetTestConnection.SendMessageAsync(fileArtifactMessages); + await _dotnetTestConnection.SendMessageAsync(fileArtifactMessages).ConfigureAwait(false); break; case FileArtifact fileArtifact: fileArtifactMessages = new( ExecutionId, DotnetTestConnection.InstanceId, - new[] - { + [ new FileArtifactMessage( fileArtifact.FileInfo.FullName, fileArtifact.DisplayName, fileArtifact.Description ?? string.Empty, string.Empty, string.Empty, - string.Empty), - }); + string.Empty) + ]); - await _dotnetTestConnection.SendMessageAsync(fileArtifactMessages); + await _dotnetTestConnection.SendMessageAsync(fileArtifactMessages).ConfigureAwait(false); break; } } @@ -271,7 +265,7 @@ public async Task OnTestSessionStartingAsync(SessionUid sessionUid, Cancellation sessionUid.Value, ExecutionId); - await _dotnetTestConnection.SendMessageAsync(sessionStartEvent); + await _dotnetTestConnection.SendMessageAsync(sessionStartEvent).ConfigureAwait(false); } public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, CancellationToken cancellationToken) @@ -283,6 +277,6 @@ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, Cancellatio sessionUid.Value, ExecutionId); - await _dotnetTestConnection.SendMessageAsync(sessionEndEvent); + await _dotnetTestConnection.SendMessageAsync(sessionEndEvent).ConfigureAwait(false); } } diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/HandshakeMessageSerializer.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/HandshakeMessageSerializer.cs index 9940477af9..9571f8f7a4 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/HandshakeMessageSerializer.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/HandshakeMessageSerializer.cs @@ -11,7 +11,7 @@ internal sealed class HandshakeMessageSerializer : BaseSerializer, INamedPipeSer public object Deserialize(Stream stream) { - Dictionary properties = new(); + Dictionary properties = []; ushort fieldCount = ReadShort(stream); diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/TestResultMessagesSerializer.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/TestResultMessagesSerializer.cs index 4472ddbaea..3bc7cc8965 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/TestResultMessagesSerializer.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/TestResultMessagesSerializer.cs @@ -323,7 +323,7 @@ private static ExceptionMessage[] ReadExceptionMessagesPayload(Stream stream) exceptionMessages.Add(new ExceptionMessage(errorMessage, errorType, stackTrace)); } - return exceptionMessages.ToArray(); + return [.. exceptionMessages]; } public void Serialize(object objectToSerialize, Stream stream) diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/FormatterUtilities.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/FormatterUtilities.cs index 0e540ef32e..f5a40ec03f 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/FormatterUtilities.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/FormatterUtilities.cs @@ -34,13 +34,13 @@ internal sealed class MessageFormatter : IMessageFormatter public MessageFormatter() { - Dictionary serializers = new(); - Dictionary deserializers = new(); + Dictionary serializers = []; + Dictionary deserializers = []; foreach (Type serializableType in SerializerUtilities.SerializerTypes) { serializers[serializableType] = new JsonObjectSerializer( - o => SerializerUtilities.Serialize(serializableType, o).Select(kvp => (kvp.Key, kvp.Value)).ToArray()); + o => [.. SerializerUtilities.Serialize(serializableType, o).Select(kvp => (kvp.Key, kvp.Value))]); } foreach (Type deserializableType in SerializerUtilities.DeserializerTypes) diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/IServerModeManager.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/IServerModeManager.cs deleted file mode 100644 index dde41a1521..0000000000 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/IServerModeManager.cs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.Testing.Platform.ServerMode; - -internal interface IServerModeManager; diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs index d7b1b73607..0b8952079c 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs @@ -19,28 +19,27 @@ public Json(Dictionary? serializers = null, Dictionary(request => new[] - { - (JsonRpcStrings.JsonRpc, "2.0"), + _serializers[typeof(RequestMessage)] = new JsonObjectSerializer(request => + [ + (JsonRpcStrings.JsonRpc, "2.0"), (JsonRpcStrings.Id, request.Id), (JsonRpcStrings.Method, request.Method), - (JsonRpcStrings.Params, request.Params), - }); + (JsonRpcStrings.Params, request.Params) + ]); - _serializers[typeof(ResponseMessage)] = new JsonObjectSerializer(response => new[] - { - (JsonRpcStrings.JsonRpc, "2.0"), + _serializers[typeof(ResponseMessage)] = new JsonObjectSerializer(response => + [ + (JsonRpcStrings.JsonRpc, "2.0"), (JsonRpcStrings.Id, response.Id), - (JsonRpcStrings.Result, response.Result), - }); + (JsonRpcStrings.Result, response.Result) + ]); _serializers[typeof(NotificationMessage)] = new JsonObjectSerializer(notification => - new[] - { - (JsonRpcStrings.JsonRpc, "2.0"), + [ + (JsonRpcStrings.JsonRpc, "2.0"), (JsonRpcStrings.Method, notification.Method), - (JsonRpcStrings.Params, notification.Params), - }); + (JsonRpcStrings.Params, notification.Params) + ]); _serializers[typeof(ErrorMessage)] = new JsonObjectSerializer(error => { @@ -51,76 +50,69 @@ public Json(Dictionary? serializers = null, Dictionary(response => - new (string, object?)[] - { - (JsonRpcStrings.ProcessId, response.ProcessId), + [ + (JsonRpcStrings.ProcessId, response.ProcessId), (JsonRpcStrings.ServerInfo, response.ServerInfo), - (JsonRpcStrings.Capabilities, response.Capabilities), - }); + (JsonRpcStrings.Capabilities, response.Capabilities) + ]); - _serializers[typeof(ServerInfo)] = new JsonObjectSerializer(info => new (string, object?)[] - { - (JsonRpcStrings.Name, info.Name), - (JsonRpcStrings.Version, info.Version), - }); + _serializers[typeof(ServerInfo)] = new JsonObjectSerializer(info => + [ + (JsonRpcStrings.Name, info.Name), + (JsonRpcStrings.Version, info.Version) + ]); _serializers[typeof(ServerCapabilities)] = new JsonObjectSerializer(capabilities => - new (string, object?)[] - { - (JsonRpcStrings.Testing, capabilities.TestingCapabilities), - }); + [ + (JsonRpcStrings.Testing, capabilities.TestingCapabilities) + ]); _serializers[typeof(ServerTestingCapabilities)] = new JsonObjectSerializer(capabilities => - new (string, object?)[] - { - (JsonRpcStrings.SupportsDiscovery, capabilities.SupportsDiscovery), + [ + (JsonRpcStrings.SupportsDiscovery, capabilities.SupportsDiscovery), (JsonRpcStrings.MultiRequestSupport, capabilities.MultiRequestSupport), (JsonRpcStrings.VSTestProviderSupport, capabilities.VSTestProviderSupport), (JsonRpcStrings.AttachmentsSupport, capabilities.SupportsAttachments), - (JsonRpcStrings.MultiConnectionProvider, capabilities.MultiConnectionProvider), - }); + (JsonRpcStrings.MultiConnectionProvider, capabilities.MultiConnectionProvider) + ]); _serializers[typeof(Artifact)] = new JsonObjectSerializer(artifact => - new (string, object?)[] - { - (JsonRpcStrings.Uri, artifact.Uri), + [ + (JsonRpcStrings.Uri, artifact.Uri), (JsonRpcStrings.Producer, artifact.Producer), (JsonRpcStrings.Type, artifact.Type), (JsonRpcStrings.DisplayName, artifact.DisplayName), - (JsonRpcStrings.Description, artifact.Description), - }); + (JsonRpcStrings.Description, artifact.Description) + ]); _serializers[typeof(DiscoverResponseArgs)] = new JsonObjectSerializer(response => []); _serializers[typeof(RunResponseArgs)] = new JsonObjectSerializer(response => - new (string, object?)[] - { - (JsonRpcStrings.Attachments, response.Artifacts), - }); + [ + (JsonRpcStrings.Attachments, response.Artifacts) + ]); _serializers[typeof(TestNodeUpdateMessage)] = new JsonObjectSerializer(message => - new (string, object?)[] - { - (JsonRpcStrings.Node, message.TestNode), - (JsonRpcStrings.Parent, message.ParentTestNodeUid?.Value), - }); + [ + (JsonRpcStrings.Node, message.TestNode), + (JsonRpcStrings.Parent, message.ParentTestNodeUid?.Value) + ]); _serializers[typeof(TestNodeStateChangedEventArgs)] = new JsonObjectSerializer(message => - new (string, object?)[] - { - (JsonRpcStrings.RunId, message.RunId), - (JsonRpcStrings.Changes, message.Changes), - }); + [ + (JsonRpcStrings.RunId, message.RunId), + (JsonRpcStrings.Changes, message.Changes) + ]); _serializers[typeof(TestNode)] = new JsonObjectSerializer(message => { @@ -162,7 +154,7 @@ public Json(Dictionary? serializers = null, Dictionary 0 - ? $"{testMethodIdentifierProperty.MethodName}({string.Join(",", testMethodIdentifierProperty.ParameterTypeFullNames)})" + ? $"{testMethodIdentifierProperty.MethodName}({string.Join(',', testMethodIdentifierProperty.ParameterTypeFullNames)})" : testMethodIdentifierProperty.MethodName)); properties.Add(("location.method-arity", testMethodIdentifierProperty.MethodArity)); @@ -299,59 +291,52 @@ public Json(Dictionary? serializers = null, Dictionary(message => - new (string, object?)[] - { - (JsonRpcStrings.Level, message.LogMessage.Level.ToString()), - (JsonRpcStrings.Message, message.LogMessage.Message), - }); + [ + (JsonRpcStrings.Level, message.LogMessage.Level.ToString()), + (JsonRpcStrings.Message, message.LogMessage.Message) + ]); _serializers[typeof(CancelRequestArgs)] = new JsonObjectSerializer(request => - new (string, object?)[] - { - (JsonRpcStrings.Id, request.CancelRequestId), - }); + [ + (JsonRpcStrings.Id, request.CancelRequestId) + ]); _serializers[typeof(TelemetryEventArgs)] = new JsonObjectSerializer(ev => - new (string, object?)[] - { - (JsonRpcStrings.EventName, ev.EventName), - (JsonRpcStrings.Metrics, ev.Metrics), - }); + [ + (JsonRpcStrings.EventName, ev.EventName), + (JsonRpcStrings.Metrics, ev.Metrics) + ]); _serializers[typeof(ProcessInfoArgs)] = new JsonObjectSerializer(info => - new (string, object?)[] - { - (JsonRpcStrings.Program, info.Program), + [ + (JsonRpcStrings.Program, info.Program), (JsonRpcStrings.Args, info.Args), (JsonRpcStrings.WorkingDirectory, info.WorkingDirectory), - (JsonRpcStrings.EnvironmentVariables, info.EnvironmentVariables), - }); + (JsonRpcStrings.EnvironmentVariables, info.EnvironmentVariables) + ]); _serializers[typeof(AttachDebuggerInfoArgs)] = new JsonObjectSerializer(info => - new (string, object?)[] - { - (JsonRpcStrings.ProcessId, info.ProcessId), - }); + [ + (JsonRpcStrings.ProcessId, info.ProcessId) + ]); _serializers[typeof(TestsAttachments)] = new JsonObjectSerializer(info => - new (string, object?)[] - { - (JsonRpcStrings.Attachments, info.Attachments), - }); + [ + (JsonRpcStrings.Attachments, info.Attachments) + ]); _serializers[typeof(RunTestAttachment)] = new JsonObjectSerializer(info => - new (string, object?)[] - { - (JsonRpcStrings.Uri, info.Uri), + [ + (JsonRpcStrings.Uri, info.Uri), (JsonRpcStrings.Producer, info.Producer), (JsonRpcStrings.Type, info.Type), (JsonRpcStrings.DisplayName, info.DisplayName), - (JsonRpcStrings.Description, info.Description), - }); + (JsonRpcStrings.Description, info.Description) + ]); // Serializers _serializers[typeof(string)] = new JsonValueSerializer((w, v) => w.WriteStringValue(v)); @@ -368,7 +353,7 @@ public Json(Dictionary? serializers = null, Dictionary((w, v) => w.WriteStringValue(v.ToString())); // Remove for now _serializers[typeof((string, object?)[])] = new JsonObjectSerializer<(string, object?)[]>(n => n); - _serializers[typeof(Dictionary)] = new JsonObjectSerializer>(d => d.Select(kvp => (kvp.Key, (object?)kvp.Value)).ToArray()); + _serializers[typeof(Dictionary)] = new JsonObjectSerializer>(d => [.. d.Select(kvp => (kvp.Key, (object?)kvp.Value))]); // Deserializers _deserializers[typeof(string)] = new JsonElementDeserializer((json, jsonDocument) => jsonDocument.GetString()!); @@ -379,7 +364,7 @@ public Json(Dictionary? serializers = null, Dictionary)] = new JsonElementDeserializer>((json, jsonDocument) => { - Dictionary items = new(); + Dictionary items = []; foreach (JsonProperty kvp in jsonDocument.EnumerateObject()) { switch (kvp.Value.ValueKind) @@ -618,14 +603,12 @@ public async Task SerializeAsync(object obj) try { stream.Position = 0; +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await using Utf8JsonWriter writer = new(stream); - await SerializeAsync(obj, writer); - await writer.FlushAsync(); -#if NETCOREAPP +#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task + await SerializeAsync(obj, writer).ConfigureAwait(false); + await writer.FlushAsync().ConfigureAwait(false); return Encoding.UTF8.GetString(stream.GetBuffer().AsMemory().Span[..(int)stream.Position]); -#else - return Encoding.UTF8.GetString(stream.ToArray()); -#endif } finally { @@ -639,13 +622,6 @@ public T Deserialize(ReadOnlyMemory utf8Json) return Bind(document.RootElement, null); } - internal T Bind(IEnumerable properties) - => !_deserializers.TryGetValue(typeof(T), out JsonDeserializer? deserializer) - ? throw new InvalidOperationException($"Cannot find deserializer for {typeof(T)}.") - : deserializer is not JsonPropertyCollectionDeserializer propertyBagDeserializer - ? throw new InvalidOperationException("we need property bag deserializer") - : propertyBagDeserializer.CreateObject(this, properties); - internal T Bind(JsonElement element, string? property = null) { if (property is not null) @@ -683,7 +659,7 @@ internal bool TryArrayBind(JsonElement element, out T[]? value, string? prope return false; } - value = element.EnumerateArray().Select(Deserialize).ToArray(); + value = [.. element.EnumerateArray().Select(Deserialize)]; return true; } @@ -733,12 +709,10 @@ private async Task SerializeAsync(object? obj, Utf8JsonWriter writer) (string Key, object? Value)[]? properties = objectConverter.Properties(obj); if (properties is not null) { - int count = 1; foreach ((string property, object? value) in properties) { writer.WritePropertyName(property); - await SerializeAsync(value, writer); - count++; + await SerializeAsync(value, writer).ConfigureAwait(false); } } @@ -765,7 +739,7 @@ private async Task SerializeAsync(object? obj, Utf8JsonWriter writer) } else { - await SerializeAsync(o, writer); + await SerializeAsync(o, writer).ConfigureAwait(false); } } diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/JsonCollectionDeserializer.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/JsonCollectionDeserializer.cs index b22ae843f5..53570dcbcf 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/JsonCollectionDeserializer.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/JsonCollectionDeserializer.cs @@ -9,32 +9,3 @@ internal abstract class JsonCollectionDeserializer : JsonDeserializ { internal abstract TCollection CreateObject(Json json, JsonElement element); } - -internal sealed class JsonCollectionDeserializer(Func createCollection, Action addItem) : JsonCollectionDeserializer - where TCollection : ICollection -{ - private readonly Func _createCollection = createCollection; - private readonly Action _addItem = addItem; - - public TCollection CreateCollection(JsonElement jsonElement) - => _createCollection(jsonElement); - - public void AddItem(TCollection collection, TItem item) - => _addItem(collection, item); - - internal override TCollection CreateObject(Json json, JsonElement element) - { - if (element.ValueKind == JsonValueKind.Null) - { - return default!; - } - - TCollection collection = CreateCollection(element); - foreach (JsonElement item in element.EnumerateArray()) - { - AddItem(collection, json.Bind(item)); - } - - return collection; - } -} diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/JsonPropertyBagDeserializer.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/JsonPropertyBagDeserializer.cs deleted file mode 100644 index 08e5e8c4c9..0000000000 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/JsonPropertyBagDeserializer.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Text.Json; - -namespace Microsoft.Testing.Platform.ServerMode.Json; - -internal sealed class JsonPropertyCollectionDeserializer(Func, T> creator) : JsonDeserializer -{ - private readonly Func, T> _creator = creator; - - internal T CreateObject(Json json, IEnumerable properties) - => _creator(json, properties); -} diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/JsonRpcTcpServerToSingleClient.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/JsonRpcTcpServerToSingleClient.cs deleted file mode 100644 index 93865858e6..0000000000 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/JsonRpcTcpServerToSingleClient.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Microsoft.Testing.Platform.Helpers; -using Microsoft.Testing.Platform.Resources; - -namespace Microsoft.Testing.Platform.ServerMode; - -internal sealed class JsonRpcTcpServerToSingleClient(string clientHostName, int clientPort) : ICommunicationProtocol -{ - public string ClientHostName { get; } = clientHostName; - - public int ClientPort { get; } = clientPort; - - public string Name => nameof(JsonRpcTcpServerToSingleClient); - - public string Version => AppVersion.DefaultSemVer; - - public string Description => PlatformResources.JsonRpcTcpServerToSingleClientDescription; -} diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/MessageHandlerFactory.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/MessageHandlerFactory.cs index 6c578c2197..3deba13219 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/MessageHandlerFactory.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/MessageHandlerFactory.cs @@ -15,7 +15,7 @@ internal sealed partial class ServerModeManager { internal sealed class MessageHandlerFactory : IMessageHandlerFactory, IOutputDeviceDataProducer { - private readonly string? _host; + private readonly string _host; private readonly int _port; private readonly IOutputDevice _outputDevice; @@ -39,52 +39,21 @@ public MessageHandlerFactory( public string Description => nameof(MessageHandlerFactory); - public Task CreateMessageHandlerAsync(CancellationToken cancellationToken) - => _host is not null - ? ConnectToTestPlatformClientAsync(_host, _port, cancellationToken) - : StartTestPlatformServerAsync(port: _port, cancellationToken); - #pragma warning disable CA1416 // Validate platform compatibility - private async Task ConnectToTestPlatformClientAsync(string clientHost, int clientPort, CancellationToken cancellationToken) + public async Task CreateMessageHandlerAsync(CancellationToken cancellationToken) { - await _outputDevice.DisplayAsync(this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ConnectingToClientHost, clientHost, clientPort))); + await _outputDevice.DisplayAsync(this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ConnectingToClientHost, _host, _port))).ConfigureAwait(false); TcpClient client = new(); #if NETCOREAPP - await client.ConnectAsync(host: clientHost, port: clientPort, cancellationToken); + await client.ConnectAsync(host: _host, port: _port, cancellationToken).ConfigureAwait(false); #else - await client.ConnectAsync(host: clientHost, port: clientPort).WithCancellationAsync(cancellationToken, observeException: true); + await client.ConnectAsync(host: _host, port: _port).WithCancellationAsync(cancellationToken, observeException: true).ConfigureAwait(false); #endif NetworkStream stream = client.GetStream(); return new TcpMessageHandler(client, clientToServerStream: stream, serverToClientStream: stream, FormatterUtilities.CreateFormatter()); } - - private async Task StartTestPlatformServerAsync(int? port, CancellationToken cancellationToken) - { - port ??= 0; - IPEndPoint endPoint = new(IPAddress.Loopback, port.Value); - TcpListener listener = new(endPoint); - - listener.Start(); - try - { - await _outputDevice.DisplayAsync(this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.StartingServer, ((IPEndPoint)listener.LocalEndpoint).Port))); - -#if NETCOREAPP - TcpClient client = await listener.AcceptTcpClientAsync(cancellationToken); -#else - TcpClient client = await listener.AcceptTcpClientAsync().WithCancellationAsync(cancellationToken); -#endif - NetworkStream stream = client.GetStream(); - return new TcpMessageHandler(client, clientToServerStream: stream, serverToClientStream: stream, FormatterUtilities.CreateFormatter()); - } - catch (OperationCanceledException oc) when (oc.CancellationToken == cancellationToken) - { - listener.Stop(); - throw; - } - } #pragma warning restore CA1416 public Task IsEnabledAsync() => Task.FromResult(false); diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PassiveNode.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PassiveNode.cs index 9ab9878ce0..931755233f 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PassiveNode.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PassiveNode.cs @@ -11,7 +11,7 @@ internal sealed class PassiveNode : IDisposable { private readonly IMessageHandlerFactory _messageHandlerFactory; private readonly ITestApplicationCancellationTokenSource _testApplicationCancellationTokenSource; - private readonly IProcessHandler _processHandler; + private readonly IEnvironment _environment; private readonly ILogger _logger; private readonly IAsyncMonitor _messageMonitor; private IMessageHandler? _messageHandler; @@ -19,13 +19,13 @@ internal sealed class PassiveNode : IDisposable public PassiveNode( IMessageHandlerFactory messageHandlerFactory, ITestApplicationCancellationTokenSource testApplicationCancellationTokenSource, - IProcessHandler processHandler, + IEnvironment environment, IAsyncMonitorFactory asyncMonitorFactory, ILogger logger) { _messageHandlerFactory = messageHandlerFactory; _testApplicationCancellationTokenSource = testApplicationCancellationTokenSource; - _processHandler = processHandler; + _environment = environment; _messageMonitor = asyncMonitorFactory.Create(); _logger = logger; } @@ -42,12 +42,12 @@ public void AssertInitialized() public async Task ConnectAsync() { // Create message handler - await _logger.LogDebugAsync("Create message handler"); - _messageHandler = await _messageHandlerFactory.CreateMessageHandlerAsync(_testApplicationCancellationTokenSource.CancellationToken); + await _logger.LogDebugAsync("Create message handler").ConfigureAwait(false); + _messageHandler = await _messageHandlerFactory.CreateMessageHandlerAsync(_testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); // Wait the initial message - await _logger.LogDebugAsync("Wait the initial message"); - RpcMessage? message = await _messageHandler.ReadAsync(_testApplicationCancellationTokenSource.CancellationToken); + await _logger.LogDebugAsync("Wait the initial message").ConfigureAwait(false); + RpcMessage? message = await _messageHandler.ReadAsync(_testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); if (message is null) { return false; @@ -56,12 +56,12 @@ public async Task ConnectAsync() // Log the message if (_logger.IsEnabled(LogLevel.Trace)) { - await _logger.LogTraceAsync(message!.ToString()); + await _logger.LogTraceAsync(message!.ToString()).ConfigureAwait(false); } var requestMessage = (RequestMessage)message; var responseObject = new InitializeResponseArgs( - ProcessId: _processHandler.GetCurrentProcess().Id, + ProcessId: _environment.ProcessId, ServerInfo: new ServerInfo("test-anywhere", Version: PlatformVersion.Version), Capabilities: new ServerCapabilities( new ServerTestingCapabilities( @@ -73,7 +73,7 @@ public async Task ConnectAsync() // This means we're a push node MultiConnectionProvider: true))); - await SendResponseAsync(requestMessage.Id, responseObject, _testApplicationCancellationTokenSource.CancellationToken); + await SendResponseAsync(requestMessage.Id, responseObject, _testApplicationCancellationTokenSource.CancellationToken).ConfigureAwait(false); return true; } @@ -82,9 +82,9 @@ private async Task SendResponseAsync(int reqId, object result, CancellationToken AssertInitialized(); ResponseMessage response = new(reqId, result); - using (await _messageMonitor.LockAsync(cancellationToken)) + using (await _messageMonitor.LockAsync(cancellationToken).ConfigureAwait(false)) { - await _messageHandler.WriteRequestAsync(response, cancellationToken); + await _messageHandler.WriteRequestAsync(response, cancellationToken).ConfigureAwait(false); } } @@ -93,9 +93,9 @@ public async Task SendAttachmentsAsync(TestsAttachments testsAttachments, Cancel AssertInitialized(); NotificationMessage notification = new(JsonRpcMethods.TestingTestUpdatesAttachments, testsAttachments); - using (await _messageMonitor.LockAsync(cancellationToken)) + using (await _messageMonitor.LockAsync(cancellationToken).ConfigureAwait(false)) { - await _messageHandler.WriteRequestAsync(notification, cancellationToken); + await _messageHandler.WriteRequestAsync(notification, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PerRequestServerDataConsumerService.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PerRequestServerDataConsumerService.cs index 30b26041f2..f61fad28a0 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PerRequestServerDataConsumerService.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PerRequestServerDataConsumerService.cs @@ -92,7 +92,7 @@ private async Task ProcessTestNodeUpdateAsync(TestNodeUpdateMessage update, Canc try { - await _nodeAggregatorSemaphore.WaitAsync(cancellationToken); + await _nodeAggregatorSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { // Note: If there's no changes to aggregate kick off a background task, @@ -108,7 +108,7 @@ private async Task ProcessTestNodeUpdateAsync(TestNodeUpdateMessage update, Canc // Observe possible exceptions try { - await _idleUpdateTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); + await _idleUpdateTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -144,14 +144,14 @@ private async Task SendTestNodeUpdatesOnIdleAsync(Guid runId) // When batch timer expire or we're at the end of the session we can unblock the message drain Guard.NotNull(_task); - await Task.WhenAny(_task.Delay(TimeSpan.FromMilliseconds(TestNodeUpdateDelayInMs), cancellationToken), _testSessionEnd.Task); + await Task.WhenAny(_task.Delay(TimeSpan.FromMilliseconds(TestNodeUpdateDelayInMs), cancellationToken), _testSessionEnd.Task).ConfigureAwait(false); if (cancellationToken.IsCancellationRequested) { return; } - await SendTestNodeUpdatesIfNecessaryAsync(runId, cancellationToken); + await SendTestNodeUpdatesIfNecessaryAsync(runId, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { @@ -165,11 +165,11 @@ private async Task SendTestNodeUpdatesIfNecessaryAsync(Guid runId, CancellationT // and the Task completes, all of the pending updates have been sent. // We synchronize the aggregator access with a separate lock, so that sending // the update message will not block the producers. - await _nodeUpdateSemaphore.WaitAsync(cancellationToken); + await _nodeUpdateSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { TestNodeStateChangedEventArgs? change = null; - await _nodeAggregatorSemaphore.WaitAsync(cancellationToken); + await _nodeAggregatorSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { if (_nodeUpdatesAggregator.HasChanges) @@ -185,7 +185,7 @@ private async Task SendTestNodeUpdatesIfNecessaryAsync(Guid runId, CancellationT if (change is not null) { - await _serverTestHost.SendTestUpdateAsync(change); + await _serverTestHost.SendTestUpdateAsync(change).ConfigureAwait(false); } } finally @@ -200,7 +200,7 @@ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, Cancellatio { // We signal the test session end so we can complete the flush. _testSessionEnd.SetResult(true); - await GetIdleUpdateTaskAsync().TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken); + await GetIdleUpdateTaskAsync().TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { @@ -218,7 +218,7 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella switch (value) { case TestNodeUpdateMessage update: - await ProcessTestNodeUpdateAsync(update, cancellationToken); + await ProcessTestNodeUpdateAsync(update, cancellationToken).ConfigureAwait(false); PopulateTestNodeStatistics(update); break; diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/RpcMessages.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/RpcMessages.cs index 941f900ed7..e975f8f469 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/RpcMessages.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/RpcMessages.cs @@ -6,7 +6,7 @@ namespace Microsoft.Testing.Platform.ServerMode; -internal abstract record RpcMessage(); +internal abstract record RpcMessage; /// /// A request is a message for which the server should return a corresponding @@ -63,8 +63,6 @@ internal sealed record ClientInfo(string Name, string Version); internal sealed record ClientCapabilities(bool DebuggerProvider); -internal sealed record ClientTestingCapabilities(bool DebuggerProvider); - internal sealed record ServerInfo(string Name, string Version); internal sealed record ServerCapabilities(ServerTestingCapabilities TestingCapabilities); diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs index 97b5733507..1a47c209e4 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs @@ -224,7 +224,7 @@ static SerializerUtilities() : $"{testMethodIdentifierProperty.Namespace}.{testMethodIdentifierProperty.TypeName}"; properties["location.method"] = testMethodIdentifierProperty.ParameterTypeFullNames.Length > 0 - ? $"{testMethodIdentifierProperty.MethodName}({string.Join(",", testMethodIdentifierProperty.ParameterTypeFullNames)})" + ? $"{testMethodIdentifierProperty.MethodName}({string.Join(',', testMethodIdentifierProperty.ParameterTypeFullNames)})" : testMethodIdentifierProperty.MethodName; properties["location.method-arity"] = testMethodIdentifierProperty.MethodArity; @@ -354,10 +354,7 @@ static SerializerUtilities() } } - if (!properties.ContainsKey("node-type")) - { - properties["node-type"] = "group"; - } + properties.TryAdd("node-type", "group"); return properties; }); diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModeManager.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModeManager.cs index c0bc80727b..b9ee389873 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModeManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModeManager.cs @@ -7,11 +7,9 @@ namespace Microsoft.Testing.Platform.ServerMode; -internal sealed partial class ServerModeManager : IServerModeManager +internal sealed partial class ServerModeManager { - internal ICommunicationProtocol? CommunicationProtocol { get; set; } - - internal IMessageHandlerFactory Build(IServiceProvider serviceProvider) + internal static IMessageHandlerFactory Build(IServiceProvider serviceProvider) { ICommandLineOptions commandLineService = serviceProvider.GetCommandLineOptions(); @@ -20,34 +18,10 @@ internal IMessageHandlerFactory Build(IServiceProvider serviceProvider) ? int.Parse(clientPortArgs[0], CultureInfo.InvariantCulture) : throw new InvalidOperationException(PlatformResources.MissingClientPortFoJsonRpc); - string? clientHostName; - clientHostName = commandLineService.TryGetOptionArgumentList(PlatformCommandLineProvider.ClientHostOptionKey, out string[]? clientHostArgs) + string clientHostName = commandLineService.TryGetOptionArgumentList(PlatformCommandLineProvider.ClientHostOptionKey, out string[]? clientHostArgs) ? clientHostArgs[0] : "localhost"; - if (CommunicationProtocol is not null) - { - switch (CommunicationProtocol) - { - case JsonRpcTcpServerToSingleClient tcpServerToSingleClientCommunicationProtocol: - { - clientPort ??= tcpServerToSingleClientCommunicationProtocol.ClientPort; - - if (RoslynString.IsNullOrEmpty(clientHostName)) - { - clientHostName = tcpServerToSingleClientCommunicationProtocol.ClientHostName; - } - - break; - } - - default: - { - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.UnknownCommunicationProtocolErrorMessage, CommunicationProtocol.GetType())); - } - } - } - return new MessageHandlerFactory(clientHostName, clientPort.Value, serviceProvider.GetOutputDevice()); } } diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs index 1ae054fcbd..406f7419a4 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs @@ -15,11 +15,11 @@ internal sealed class ServerModePerCallOutputDevice : IPlatformOutputDevice, IOu { private readonly FileLoggerProvider? _fileLoggerProvider; private readonly IStopPoliciesService _policiesService; - private readonly ConcurrentBag _messages = new(); + private readonly ConcurrentBag _messages = []; private IServerTestHost? _serverTestHost; - private static readonly string[] NewLineStrings = { "\r\n", "\n" }; + private static readonly string[] NewLineStrings = ["\r\n", "\n"]; public ServerModePerCallOutputDevice(FileLoggerProvider? fileLoggerProvider, IStopPoliciesService policiesService) { @@ -41,7 +41,7 @@ internal async Task InitializeAsync(IServerTestHost serverTestHost) foreach (ServerLogMessage message in _messages) { - await LogAsync(message); + await LogAsync(message).ConfigureAwait(false); } _messages.Clear(); @@ -56,30 +56,30 @@ internal async Task InitializeAsync(IServerTestHost serverTestHost) public string Description => nameof(ServerModePerCallOutputDevice); public async Task DisplayAfterSessionEndRunAsync() - => await LogAsync(LogLevel.Trace, PlatformResources.FinishedTestSession, padding: null); + => await LogAsync(LogLevel.Trace, PlatformResources.FinishedTestSession, padding: null).ConfigureAwait(false); public async Task DisplayAsync(IOutputDeviceDataProducer producer, IOutputDeviceData data) { switch (data) { case FormattedTextOutputDeviceData formattedTextOutputDeviceData: - await LogAsync(LogLevel.Information, formattedTextOutputDeviceData.Text, formattedTextOutputDeviceData.Padding); + await LogAsync(LogLevel.Information, formattedTextOutputDeviceData.Text, formattedTextOutputDeviceData.Padding).ConfigureAwait(false); break; case TextOutputDeviceData textOutputDeviceData: - await LogAsync(LogLevel.Information, textOutputDeviceData.Text, padding: null); + await LogAsync(LogLevel.Information, textOutputDeviceData.Text, padding: null).ConfigureAwait(false); break; case WarningMessageOutputDeviceData warningData: - await LogAsync(LogLevel.Warning, warningData.Message, padding: null); + await LogAsync(LogLevel.Warning, warningData.Message, padding: null).ConfigureAwait(false); break; case ErrorMessageOutputDeviceData errorData: - await LogAsync(LogLevel.Error, errorData.Message, padding: null); + await LogAsync(LogLevel.Error, errorData.Message, padding: null).ConfigureAwait(false); break; case ExceptionOutputDeviceData exceptionOutputDeviceData: - await LogAsync(LogLevel.Error, exceptionOutputDeviceData.Exception.ToString(), padding: null); + await LogAsync(LogLevel.Error, exceptionOutputDeviceData.Exception.ToString(), padding: null).ConfigureAwait(false); break; } } @@ -88,7 +88,7 @@ public async Task DisplayBannerAsync(string? bannerMessage) { if (bannerMessage is not null) { - await LogAsync(LogLevel.Debug, bannerMessage, padding: null); + await LogAsync(LogLevel.Debug, bannerMessage, padding: null).ConfigureAwait(false); } } @@ -96,18 +96,18 @@ public async Task DisplayBeforeSessionStartAsync() { if (_fileLoggerProvider is { FileLogger.FileName: { } logFileName }) { - await LogAsync(LogLevel.Trace, string.Format(CultureInfo.InvariantCulture, PlatformResources.StartingTestSessionWithLogFilePath, logFileName), padding: null); + await LogAsync(LogLevel.Trace, string.Format(CultureInfo.InvariantCulture, PlatformResources.StartingTestSessionWithLogFilePath, logFileName), padding: null).ConfigureAwait(false); } else { - await LogAsync(LogLevel.Trace, PlatformResources.StartingTestSession, padding: null); + await LogAsync(LogLevel.Trace, PlatformResources.StartingTestSession, padding: null).ConfigureAwait(false); } } public Task IsEnabledAsync() => Task.FromResult(true); private async Task LogAsync(LogLevel logLevel, string message, int? padding) - => await LogAsync(GetServerLogMessage(logLevel, message, padding)); + => await LogAsync(GetServerLogMessage(logLevel, message, padding)).ConfigureAwait(false); private async Task LogAsync(ServerLogMessage message) { @@ -117,7 +117,7 @@ private async Task LogAsync(ServerLogMessage message) } else { - await _serverTestHost.PushDataAsync(message); + await _serverTestHost.PushDataAsync(message).ConfigureAwait(false); } } @@ -156,7 +156,7 @@ public async Task HandleProcessRoleAsync(TestProcessRole processRole) { await _policiesService.RegisterOnMaxFailedTestsCallbackAsync( async (maxFailedTests, _) => await DisplayAsync( - this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ReachedMaxFailedTestsMessage, maxFailedTests)))); + this, new TextOutputDeviceData(string.Format(CultureInfo.InvariantCulture, PlatformResources.ReachedMaxFailedTestsMessage, maxFailedTests))).ConfigureAwait(false)).ConfigureAwait(false); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/StreamMessageHandler.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/StreamMessageHandler.cs deleted file mode 100644 index c93aabf846..0000000000 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/StreamMessageHandler.cs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#if NETCOREAPP -using System.Buffers; -#else -using Microsoft.Testing.Platform.Helpers; -#endif - -namespace Microsoft.Testing.Platform.ServerMode; - -internal class StreamMessageHandler : IMessageHandler, IDisposable -{ - private readonly Stream _clientToServerStream; - private readonly Stream _serverToClientStream; - private readonly StreamReader _reader; - private readonly StreamWriter _writer; - private readonly IMessageFormatter _formatter; - private bool _isDisposed; - - public StreamMessageHandler( - Stream clientToServerStream, - Stream serverToClientStream, - IMessageFormatter formatter) - { - _clientToServerStream = clientToServerStream; - _serverToClientStream = serverToClientStream; - _reader = new StreamReader(_clientToServerStream); - _writer = new StreamWriter(_serverToClientStream) - { - // We need to force the NewLine because in Windows and nix different char sequence are used - // https://learn.microsoft.com/dotnet/api/system.io.textwriter.newline?view=net-7.0 - NewLine = "\r\n", - }; - _formatter = formatter; - } - - public virtual async Task ReadAsync(CancellationToken cancellationToken) - { - // Reads an RPC message. - // The message is currently encoded by writing a list of headers - // and then passing a byte stream with the message. - // The headers include the size of the byte stream. - // Content-Length: [content-length]\r\n - // Content-Type: [mime-type]\r\n - // \r\n - // [content]\r\n - while (true) - { - // Content type is not mandatory, and we don't use it. - (int commandSize, string _) = await ReadHeadersAsync(cancellationToken); - - // Most probably connection lost - if (commandSize is -1) - { - return null; - } - -#if NETCOREAPP - char[] commandCharsBuffer = ArrayPool.Shared.Rent(commandSize); - try - { - Memory memoryBuffer = new(commandCharsBuffer, 0, commandSize); - await _reader.ReadBlockAsync(memoryBuffer, cancellationToken); - return _formatter.Deserialize(memoryBuffer); - } - finally - { - ArrayPool.Shared.Return(commandCharsBuffer); - } -#else - char[] commandChars = new char[commandSize]; - await _reader.ReadBlockAsync(commandChars, 0, commandSize).WithCancellationAsync(cancellationToken); - return _formatter.Deserialize(new string(commandChars, 0, commandSize)); -#endif - } - } - - private async Task<(int ContentSize, string ContentType)> ReadHeadersAsync(CancellationToken cancellationToken) - { - int contentSize = -1; - string contentType = string.Empty; - - while (true) - { -#if NET7_0_OR_GREATER - string? line = await _reader.ReadLineAsync(cancellationToken); -#elif NET6_0_OR_GREATER - string? line = await _reader.ReadLineAsync().WaitAsync(cancellationToken); -#else - string? line = await _reader.ReadLineAsync().WithCancellationAsync(cancellationToken); -#endif - if (line is null || (line.Length == 0 && contentSize != -1)) - { - break; - } - - string contentSizeStr = "Content-Length:"; - string contentTypeStr = "Content-Type:"; - if (line.StartsWith(contentSizeStr, StringComparison.OrdinalIgnoreCase)) - { -#if NETCOREAPP - _ = int.TryParse(line.AsSpan()[contentSizeStr.Length..].Trim(), out contentSize); -#else - _ = int.TryParse(line[contentSizeStr.Length..].Trim(), out contentSize); -#endif - } - else if (line.StartsWith(contentTypeStr, StringComparison.OrdinalIgnoreCase)) - { -#if NETCOREAPP - contentType = new(line.AsSpan()[contentTypeStr.Length..].Trim()); -#else - contentType = line[contentTypeStr.Length..].Trim(); -#endif - } - } - - return (contentSize, contentType); - } - - public async Task WriteRequestAsync(RpcMessage message, CancellationToken cancellationToken) - { - string messageStr = await _formatter.SerializeAsync(message); - await _writer.WriteLineAsync($"Content-Length: {Encoding.UTF8.GetByteCount(messageStr)}"); - await _writer.WriteLineAsync("Content-Type: application/testingplatform"); - await _writer.WriteLineAsync(); - await _writer.WriteAsync(messageStr); - await _writer.FlushAsync(cancellationToken); - } - - protected virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - _reader.Dispose(); - try - { - _writer.Dispose(); - } - catch (InvalidOperationException) - { - // We can exit the server without wait that the streaming activity is completed. - // In that case we can get an InvalidOperationException - // (https://learn.microsoft.com/dotnet/api/system.io.streamwriter.writelineasync?view=net-7.0#system-io-streamwriter-writelineasync(system-string)): - // The stream writer is currently in use by a previous write operation. - } - } - - _isDisposed = true; - } - } - - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } -} diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs index 1ea27abcde..30b690cbd2 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs @@ -1,44 +1,150 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#if NETCOREAPP +using System.Buffers; +#endif using System.Net.Sockets; +#if !NETCOREAPP +using Microsoft.Testing.Platform.Helpers; +#endif + namespace Microsoft.Testing.Platform.ServerMode; internal sealed class TcpMessageHandler( TcpClient client, Stream clientToServerStream, Stream serverToClientStream, - IMessageFormatter formatter) : StreamMessageHandler(clientToServerStream, serverToClientStream, formatter) + IMessageFormatter formatter) : IMessageHandler, IDisposable { private readonly TcpClient _client = client; + private readonly StreamReader _reader = new(clientToServerStream); + private readonly StreamWriter _writer = new(serverToClientStream) + { + // We need to force the NewLine because in Windows and nix different char sequence are used + // https://learn.microsoft.com/dotnet/api/system.io.textwriter.newline?view=net-7.0 + NewLine = "\r\n", + }; - public override async Task ReadAsync(CancellationToken cancellationToken) + private readonly IMessageFormatter _formatter = formatter; + + public async Task ReadAsync(CancellationToken cancellationToken) { try { - return await base.ReadAsync(cancellationToken); + // Reads an RPC message. + // The message is currently encoded by writing a list of headers + // and then passing a byte stream with the message. + // The headers include the size of the byte stream. + // Content-Length: [content-length]\r\n + // Content-Type: [mime-type]\r\n + // \r\n + // [content]\r\n + while (true) + { + int commandSize = await ReadHeadersAsync(cancellationToken).ConfigureAwait(false); + + // Most probably connection lost + if (commandSize is -1) + { + return null; + } + +#if NETCOREAPP + char[] commandCharsBuffer = ArrayPool.Shared.Rent(commandSize); + try + { + Memory memoryBuffer = new(commandCharsBuffer, 0, commandSize); + await _reader.ReadBlockAsync(memoryBuffer, cancellationToken).ConfigureAwait(false); + return _formatter.Deserialize(memoryBuffer); + } + finally + { + ArrayPool.Shared.Return(commandCharsBuffer); + } +#else + char[] commandChars = new char[commandSize]; + await _reader.ReadBlockAsync(commandChars, 0, commandSize).WithCancellationAsync(cancellationToken).ConfigureAwait(false); + return _formatter.Deserialize(new string(commandChars, 0, commandSize)); +#endif + } } // Client close the connection in an unexpected way - catch (Exception ex) + catch (Exception ex) when + (ex is + SocketException { SocketErrorCode: SocketError.ConnectionReset } or + IOException + { + InnerException: SocketException { SocketErrorCode: SocketError.ConnectionReset } + }) { - switch (ex) + return null; + } + } + + private async Task ReadHeadersAsync(CancellationToken cancellationToken) + { + int contentSize = -1; + + while (true) + { +#if NET7_0_OR_GREATER + string? line = await _reader.ReadLineAsync(cancellationToken).ConfigureAwait(false); +#elif NET6_0_OR_GREATER + string? line = await _reader.ReadLineAsync().WaitAsync(cancellationToken).ConfigureAwait(false); +#else + string? line = await _reader.ReadLineAsync().WithCancellationAsync(cancellationToken).ConfigureAwait(false); +#endif + if (line is null || (line.Length == 0 && contentSize != -1)) { - case SocketException { SocketErrorCode: SocketError.ConnectionReset }: - case IOException { InnerException: SocketException { SocketErrorCode: SocketError.ConnectionReset } }: - return null; - default: - throw; + break; + } + + const string ContentLengthHeaderName = "Content-Length:"; + // Content type is not mandatory, and we don't use it. + if (line.StartsWith(ContentLengthHeaderName, StringComparison.OrdinalIgnoreCase)) + { +#if NETCOREAPP + _ = int.TryParse(line.AsSpan()[ContentLengthHeaderName.Length..].Trim(), out contentSize); +#else + _ = int.TryParse(line[ContentLengthHeaderName.Length..].Trim(), out contentSize); +#endif } } + + return contentSize; + } + + public async Task WriteRequestAsync(RpcMessage message, CancellationToken cancellationToken) + { + string messageStr = await _formatter.SerializeAsync(message).ConfigureAwait(false); + await _writer.WriteLineAsync($"Content-Length: {Encoding.UTF8.GetByteCount(messageStr)}").ConfigureAwait(false); + await _writer.WriteLineAsync("Content-Type: application/testingplatform").ConfigureAwait(false); + await _writer.WriteLineAsync().ConfigureAwait(false); + await _writer.WriteAsync(messageStr).ConfigureAwait(false); + await _writer.FlushAsync(cancellationToken).ConfigureAwait(false); } - protected override void Dispose(bool disposing) + public void Dispose() { - base.Dispose(disposing); + _reader.Dispose(); + + try + { + _writer.Dispose(); + } + catch (InvalidOperationException) + { + // We can exit the server without wait that the streaming activity is completed. + // In that case we can get an InvalidOperationException + // (https://learn.microsoft.com/dotnet/api/system.io.streamwriter.writelineasync?view=net-7.0#system-io-streamwriter-writelineasync(system-string)): + // The stream writer is currently in use by a previous write operation. + } + #pragma warning disable CA1416 // Validate platform compatibility - _client.Close(); + _client.Dispose(); #pragma warning restore CA1416 } } diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TestNodeStateChangeAggregator.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TestNodeStateChangeAggregator.cs index 0c26a1c096..91a23ad4f7 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TestNodeStateChangeAggregator.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TestNodeStateChangeAggregator.cs @@ -29,6 +29,6 @@ public void OnStateChange(TestNodeUpdateMessage stateChangedMessage) => _stateChanges.Add(stateChangedMessage); public TestNodeStateChangedEventArgs BuildAggregatedChange() - => new(RunId, _stateChanges.ToArray()); + => new(RunId, [.. _stateChanges]); } } diff --git a/src/Platform/Microsoft.Testing.Platform/Services/CurrentTestApplicationModuleInfo.cs b/src/Platform/Microsoft.Testing.Platform/Services/CurrentTestApplicationModuleInfo.cs index 8af8270867..8f8fffd0ed 100644 --- a/src/Platform/Microsoft.Testing.Platform/Services/CurrentTestApplicationModuleInfo.cs +++ b/src/Platform/Microsoft.Testing.Platform/Services/CurrentTestApplicationModuleInfo.cs @@ -85,20 +85,18 @@ public string GetProcessPath() => GetProcessPath(_environment, _process, throwOnNull: true)!; private static string? GetProcessPath(IEnvironment environment, IProcessHandler process, bool throwOnNull = false) -#if NETCOREAPP { +#if NETCOREAPP string? processPath = environment.ProcessPath; - ApplicationStateGuard.Ensure(processPath is not null || !throwOnNull); - - return processPath; - } #else - { using IProcess currentProcess = process.GetCurrentProcess(); - return currentProcess.MainModule.FileName; - } + string? processPath = currentProcess.MainModule?.FileName; #endif + ApplicationStateGuard.Ensure(processPath is not null || !throwOnNull); + return processPath; + } + public ExecutableInfo GetCurrentExecutableInfo() { bool isDotnetMuxer = IsCurrentTestApplicationHostDotnetMuxer; diff --git a/src/Platform/Microsoft.Testing.Platform/Services/ExecutableInfo.cs b/src/Platform/Microsoft.Testing.Platform/Services/ExecutableInfo.cs index 80b35d1441..17b6023e2b 100644 --- a/src/Platform/Microsoft.Testing.Platform/Services/ExecutableInfo.cs +++ b/src/Platform/Microsoft.Testing.Platform/Services/ExecutableInfo.cs @@ -12,5 +12,5 @@ internal sealed class ExecutableInfo(string filePath, IEnumerable argume public string Workspace { get; } = workspace; public override string ToString() - => $"Process: {FilePath}, Arguments: {string.Join(" ", Arguments)}, Workspace: {Workspace}"; + => $"Process: {FilePath}, Arguments: {string.Join(' ', Arguments)}, Workspace: {Workspace}"; } diff --git a/src/Platform/Microsoft.Testing.Platform/Services/IPlatformInformation.cs b/src/Platform/Microsoft.Testing.Platform/Services/IPlatformInformation.cs index 8c8f1302fa..98959a6647 100644 --- a/src/Platform/Microsoft.Testing.Platform/Services/IPlatformInformation.cs +++ b/src/Platform/Microsoft.Testing.Platform/Services/IPlatformInformation.cs @@ -64,7 +64,7 @@ public PlatformInformation() } } - public string Name { get; } = "Microsoft.Testing.Platform"; + public string Name => "Microsoft.Testing.Platform"; public DateTimeOffset? BuildDate { get; } diff --git a/src/Platform/Microsoft.Testing.Platform/Services/ServiceProvider.cs b/src/Platform/Microsoft.Testing.Platform/Services/ServiceProvider.cs index 556e89cc09..c85d18a92b 100644 --- a/src/Platform/Microsoft.Testing.Platform/Services/ServiceProvider.cs +++ b/src/Platform/Microsoft.Testing.Platform/Services/ServiceProvider.cs @@ -17,10 +17,12 @@ internal sealed class ServiceProvider : IServiceProvider, ICloneable public bool AllowTestAdapterFrameworkRegistration { get; set; } +#pragma warning disable CS0618 // Type or member is obsolete private static Type[] InternalOnlyExtensions => [ // TestHost typeof(ITestApplicationLifecycleCallbacks), + typeof(ITestHostApplicationLifetime), typeof(IDataConsumer), typeof(ITestSessionLifetimeHandler), @@ -28,6 +30,7 @@ internal sealed class ServiceProvider : IServiceProvider, ICloneable typeof(ITestHostEnvironmentVariableProvider), typeof(ITestHostProcessLifetimeHandler) ]; +#pragma warning restore CS0618 // Type or member is obsolete public void AddService(object service, bool throwIfSameInstanceExit = true) { diff --git a/src/Platform/Microsoft.Testing.Platform/Services/StopPoliciesService.cs b/src/Platform/Microsoft.Testing.Platform/Services/StopPoliciesService.cs index c69e617b8a..b9b2aed89b 100644 --- a/src/Platform/Microsoft.Testing.Platform/Services/StopPoliciesService.cs +++ b/src/Platform/Microsoft.Testing.Platform/Services/StopPoliciesService.cs @@ -19,7 +19,7 @@ public StopPoliciesService(ITestApplicationCancellationTokenSource testApplicati #pragma warning disable VSTHRD101 // Avoid unsupported async delegates // Note: If cancellation already requested, Register will still invoke the callback. - testApplicationCancellationTokenSource.CancellationToken.Register(async () => await ExecuteAbortCallbacksAsync()); + testApplicationCancellationTokenSource.CancellationToken.Register(async () => await ExecuteAbortCallbacksAsync().ConfigureAwait(false)); #pragma warning restore VSTHRD101 // Avoid unsupported async delegates } @@ -31,7 +31,7 @@ public StopPoliciesService(ITestApplicationCancellationTokenSource testApplicati private static void RegisterCallback(ref BlockingCollection? callbacks, T callback) #pragma warning disable CA1416 // Validate platform compatibility - => (callbacks ??= new()).Add(callback); + => (callbacks ??= []).Add(callback); #pragma warning restore CA1416 public async Task ExecuteMaxFailedTestsCallbacksAsync(int maxFailedTests, CancellationToken cancellationToken) @@ -47,7 +47,7 @@ public async Task ExecuteMaxFailedTestsCallbacksAsync(int maxFailedTests, Cancel { // For now, we are fine if the callback crashed us. It shouldn't happen for our // current usage anyway and the APIs around this are all internal for now. - await callback.Invoke(maxFailedTests, cancellationToken); + await callback.Invoke(maxFailedTests, cancellationToken).ConfigureAwait(false); } } @@ -64,7 +64,7 @@ public async Task ExecuteAbortCallbacksAsync() { // For now, we are fine if the callback crashed us. It shouldn't happen for our // current usage anyway and the APIs around this are all internal for now. - await callback.Invoke(); + await callback.Invoke().ConfigureAwait(false); } } @@ -77,7 +77,7 @@ public async Task RegisterOnMaxFailedTestsCallbackAsync(Func callback) { if (IsAbortTriggered) { - await callback(); + await callback().ConfigureAwait(false); } RegisterCallback(ref _abortCallbacks, callback); diff --git a/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResult.cs b/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResult.cs index 6539fae697..cf3835cee0 100644 --- a/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResult.cs +++ b/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResult.cs @@ -17,7 +17,8 @@ internal sealed class TestApplicationResult : ITestApplicationProcessExitCode, I private readonly ICommandLineOptions _commandLineOptions; private readonly IEnvironment _environment; private readonly IStopPoliciesService _policiesService; - private readonly List _failedTests = []; + private readonly bool _isDiscovery; + private int _failedTestsCount; private int _totalRanTests; private bool _testAdapterTestSessionFailure; @@ -31,13 +32,14 @@ public TestApplicationResult( _commandLineOptions = commandLineOptions; _environment = environment; _policiesService = policiesService; + _isDiscovery = _commandLineOptions.IsOptionSet(PlatformCommandLineProvider.DiscoverTestsOptionKey); } /// - public string Uid { get; } = nameof(TestApplicationResult); + public string Uid => nameof(TestApplicationResult); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// public string DisplayName { get; } = PlatformResources.TestApplicationResultDisplayName; @@ -68,10 +70,10 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo if (Array.IndexOf(TestNodePropertiesCategories.WellKnownTestNodeTestRunOutcomeFailedProperties, executionState.GetType()) != -1) { - _failedTests.Add(message.TestNode); + _failedTestsCount++; } - if (_commandLineOptions.IsOptionSet(PlatformCommandLineProvider.DiscoverTestsOptionKey) + if (_isDiscovery && Array.IndexOf(TestNodePropertiesCategories.WellKnownTestNodeDiscoveredProperties, executionState.GetType()) != -1) { _totalRanTests++; @@ -89,7 +91,7 @@ public int GetProcessExitCode() int exitCode = ExitCodes.Success; exitCode = exitCode == ExitCodes.Success && _policiesService.IsMaxFailedTestsTriggered ? ExitCodes.TestExecutionStoppedForMaxFailedTests : exitCode; exitCode = exitCode == ExitCodes.Success && _testAdapterTestSessionFailure ? ExitCodes.TestAdapterTestSessionFailure : exitCode; - exitCode = exitCode == ExitCodes.Success && _failedTests.Count > 0 ? ExitCodes.AtLeastOneTestFailed : exitCode; + exitCode = exitCode == ExitCodes.Success && _failedTestsCount > 0 ? ExitCodes.AtLeastOneTestFailed : exitCode; exitCode = exitCode == ExitCodes.Success && _policiesService.IsAbortTriggered ? ExitCodes.TestSessionAborted : exitCode; exitCode = exitCode == ExitCodes.Success && _totalRanTests == 0 ? ExitCodes.ZeroTests : exitCode; @@ -123,9 +125,9 @@ public async Task SetTestAdapterTestSessionFailureAsync(string errorMessage) { TestAdapterTestSessionFailureErrorMessage = errorMessage; _testAdapterTestSessionFailure = true; - await _outputService.DisplayAsync(this, new ErrorMessageOutputDeviceData(errorMessage)); + await _outputService.DisplayAsync(this, new ErrorMessageOutputDeviceData(errorMessage)).ConfigureAwait(false); } public Statistics GetStatistics() - => new() { TotalRanTests = _totalRanTests, TotalFailedTests = _failedTests.Count }; + => new() { TotalRanTests = _totalRanTests, TotalFailedTests = _failedTestsCount }; } diff --git a/src/Platform/Microsoft.Testing.Platform/Telemetry/ExtensionInformationCollector.cs b/src/Platform/Microsoft.Testing.Platform/Telemetry/ExtensionInformationCollector.cs index ff91fab992..dbff0964d6 100644 --- a/src/Platform/Microsoft.Testing.Platform/Telemetry/ExtensionInformationCollector.cs +++ b/src/Platform/Microsoft.Testing.Platform/Telemetry/ExtensionInformationCollector.cs @@ -25,7 +25,7 @@ public static async Task CollectAndSerializeToJsonAsync(ServiceProvider { if (service is IExtension extension) { - extensionsInformation.Add(new ExtensionInformation(Sha256Hasher.HashWithNormalizedCasing(extension.Uid), extension.Version, await extension.IsEnabledAsync())); + extensionsInformation.Add(new ExtensionInformation(Sha256Hasher.HashWithNormalizedCasing(extension.Uid), extension.Version, await extension.IsEnabledAsync().ConfigureAwait(false))); } if (service is MessageBusProxy messageBus) @@ -34,7 +34,7 @@ public static async Task CollectAndSerializeToJsonAsync(ServiceProvider { if (dataConsumer is IExtension extension1) { - extensionsInformation.Add(new ExtensionInformation(Sha256Hasher.HashWithNormalizedCasing(extension1.Uid), extension1.Version, await extension1.IsEnabledAsync())); + extensionsInformation.Add(new ExtensionInformation(Sha256Hasher.HashWithNormalizedCasing(extension1.Uid), extension1.Version, await extension1.IsEnabledAsync().ConfigureAwait(false))); } } } diff --git a/src/Platform/Microsoft.Testing.Platform/Telemetry/ServerTelemetry.cs b/src/Platform/Microsoft.Testing.Platform/Telemetry/ServerTelemetry.cs index 01646f0f4e..27a2b92a74 100644 --- a/src/Platform/Microsoft.Testing.Platform/Telemetry/ServerTelemetry.cs +++ b/src/Platform/Microsoft.Testing.Platform/Telemetry/ServerTelemetry.cs @@ -13,9 +13,9 @@ internal sealed class ServerTelemetry(IServerTestHost serverTestHost) : ITelemet public async Task LogEventAsync(string eventName, IDictionary paramsMap) { TelemetryEventArgs logMessage = new(eventName, paramsMap); - await PushTelemetryToServerTestHostAsync(logMessage); + await PushTelemetryToServerTestHostAsync(logMessage).ConfigureAwait(false); } private async Task PushTelemetryToServerTestHostAsync(TelemetryEventArgs telemetryEvent) - => await _serverTestHost.SendTelemetryEventUpdateAsync(telemetryEvent); + => await _serverTestHost.SendTelemetryEventUpdateAsync(telemetryEvent).ConfigureAwait(false); } diff --git a/src/Platform/Microsoft.Testing.Platform/Telemetry/TelemetryManager.cs b/src/Platform/Microsoft.Testing.Platform/Telemetry/TelemetryManager.cs index c96926d870..eeaeb0fa56 100644 --- a/src/Platform/Microsoft.Testing.Platform/Telemetry/TelemetryManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/Telemetry/TelemetryManager.cs @@ -35,23 +35,23 @@ public async Task BuildAsync(ServiceProvider serviceProvide bool isTelemetryOptedOut = !testApplicationOptions.EnableTelemetry; ILogger logger = loggerFactory.CreateLogger(); - await logger.LogDebugAsync($"TestApplicationOptions.EnableTelemetry: {testApplicationOptions.EnableTelemetry}"); + await logger.LogDebugAsync($"TestApplicationOptions.EnableTelemetry: {testApplicationOptions.EnableTelemetry}").ConfigureAwait(false); // If the environment variable is not set or is set to 0, telemetry is opted in. IEnvironment environment = serviceProvider.GetEnvironment(); string? telemetryOptOut = environment.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_TELEMETRY_OPTOUT); - await logger.LogDebugAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_TELEMETRY_OPTOUT} environment variable: '{telemetryOptOut}'"); + await logger.LogDebugAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_TELEMETRY_OPTOUT} environment variable: '{telemetryOptOut}'").ConfigureAwait(false); isTelemetryOptedOut = (telemetryOptOut is "1" or "true") || isTelemetryOptedOut; string? cli_telemetryOptOut = environment.GetEnvironmentVariable(EnvironmentVariableConstants.DOTNET_CLI_TELEMETRY_OPTOUT); - await logger.LogDebugAsync($"{EnvironmentVariableConstants.DOTNET_CLI_TELEMETRY_OPTOUT} environment variable: '{cli_telemetryOptOut}'"); + await logger.LogDebugAsync($"{EnvironmentVariableConstants.DOTNET_CLI_TELEMETRY_OPTOUT} environment variable: '{cli_telemetryOptOut}'").ConfigureAwait(false); isTelemetryOptedOut = (cli_telemetryOptOut is "1" or "true") || isTelemetryOptedOut; - await logger.LogDebugAsync($"Telemetry is '{(!isTelemetryOptedOut ? "ENABLED" : "DISABLED")}'"); + await logger.LogDebugAsync($"Telemetry is '{(!isTelemetryOptedOut ? "ENABLED" : "DISABLED")}'").ConfigureAwait(false); if (!isTelemetryOptedOut && _telemetryFactory is not null) { - await ShowTelemetryBannerFirstNoticeAsync(serviceProvider, logger, environment); + await ShowTelemetryBannerFirstNoticeAsync(serviceProvider, logger, environment).ConfigureAwait(false); } serviceProvider.TryAddService(new TelemetryInformation(!isTelemetryOptedOut, TelemetryProperties.VersionValue)); @@ -62,7 +62,7 @@ public async Task BuildAsync(ServiceProvider serviceProvide if (!isTelemetryOptedOut) { - await logger.LogDebugAsync($"Telemetry collector provider: '{telemetryCollector.GetType()}'"); + await logger.LogDebugAsync($"Telemetry collector provider: '{telemetryCollector.GetType()}'").ConfigureAwait(false); } return telemetryCollector; @@ -75,11 +75,11 @@ private async Task ShowTelemetryBannerFirstNoticeAsync(ServiceProvider servicePr bool doNotShowLogo = commandLineOptions.IsOptionSet(PlatformCommandLineProvider.NoBannerOptionKey); string? noBannerEnvVar = environment.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_NOBANNER); - await logger.LogDebugAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_NOBANNER} environment variable: '{noBannerEnvVar}'"); + await logger.LogDebugAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_NOBANNER} environment variable: '{noBannerEnvVar}'").ConfigureAwait(false); doNotShowLogo = (noBannerEnvVar is "1" or "true") || doNotShowLogo; string? dotnetNoLogoEnvVar = environment.GetEnvironmentVariable(EnvironmentVariableConstants.DOTNET_NOLOGO); - await logger.LogDebugAsync($"{EnvironmentVariableConstants.DOTNET_NOLOGO} environment variable: '{dotnetNoLogoEnvVar}'"); + await logger.LogDebugAsync($"{EnvironmentVariableConstants.DOTNET_NOLOGO} environment variable: '{dotnetNoLogoEnvVar}'").ConfigureAwait(false); doNotShowLogo = (dotnetNoLogoEnvVar is "1" or "true") || doNotShowLogo; if (doNotShowLogo) @@ -103,7 +103,7 @@ private async Task ShowTelemetryBannerFirstNoticeAsync(ServiceProvider servicePr bool sentinelIsNotPresent = RoslynString.IsNullOrWhiteSpace(directory) - || !fileSystem.Exists(Path.Combine(directory, fileName)); + || !fileSystem.ExistFile(Path.Combine(directory, fileName)); if (!sentinelIsNotPresent) { @@ -111,7 +111,7 @@ private async Task ShowTelemetryBannerFirstNoticeAsync(ServiceProvider servicePr } IOutputDevice outputDevice = serviceProvider.GetOutputDevice(); - await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.TelemetryNotice)); + await outputDevice.DisplayAsync(this, new TextOutputDeviceData(PlatformResources.TelemetryNotice)).ConfigureAwait(false); string? path = null; try @@ -130,7 +130,7 @@ private async Task ShowTelemetryBannerFirstNoticeAsync(ServiceProvider servicePr } catch (Exception exception) when (exception is IOException or SystemException) { - await logger.LogErrorAsync($"Could not write sentinel file for telemetry to path,'{path ?? ""}'.", exception); + await logger.LogErrorAsync($"Could not write sentinel file for telemetry to path,'{path ?? ""}'.", exception).ConfigureAwait(false); } } diff --git a/src/Platform/Microsoft.Testing.Platform/TestHost/ITestApplicationLifecycleCallbacks.cs b/src/Platform/Microsoft.Testing.Platform/TestHost/ITestHostApplicationLifetime.cs similarity index 66% rename from src/Platform/Microsoft.Testing.Platform/TestHost/ITestApplicationLifecycleCallbacks.cs rename to src/Platform/Microsoft.Testing.Platform/TestHost/ITestHostApplicationLifetime.cs index e81a4b7128..e21bb9ee44 100644 --- a/src/Platform/Microsoft.Testing.Platform/TestHost/ITestApplicationLifecycleCallbacks.cs +++ b/src/Platform/Microsoft.Testing.Platform/TestHost/ITestHostApplicationLifetime.cs @@ -6,6 +6,7 @@ namespace Microsoft.Testing.Platform.Extensions.TestHost; /// /// Represents the interface for test application lifecycle callbacks. /// +[Obsolete("Use ITestHostApplicationLifetime instead. This interface will be removed in v2.")] public interface ITestApplicationLifecycleCallbacks : ITestHostExtension { /// @@ -23,3 +24,13 @@ public interface ITestApplicationLifecycleCallbacks : ITestHostExtension /// A task representing the asynchronous operation. Task AfterRunAsync(int exitCode, CancellationToken cancellation); } + +/// +/// Represents the interface for test application lifecycle callbacks. +/// +#pragma warning disable CS0618 // Type or member is obsolete +public interface ITestHostApplicationLifetime : ITestHostExtension, ITestApplicationLifecycleCallbacks +#pragma warning restore CS0618 // Type or member is obsolete +{ + // In v2, move BeforeRunAsync and AfterRunAsync to ITestHostApplicationLifetime directly +} diff --git a/src/Platform/Microsoft.Testing.Platform/TestHost/ITestHostManager.cs b/src/Platform/Microsoft.Testing.Platform/TestHost/ITestHostManager.cs index 4be1bccb84..4fd70a7844 100644 --- a/src/Platform/Microsoft.Testing.Platform/TestHost/ITestHostManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/TestHost/ITestHostManager.cs @@ -15,8 +15,15 @@ public interface ITestHostManager /// Adds a test application lifecycle callbacks. /// /// The factory method for creating the test application lifecycle callbacks. + [Obsolete("Use 'AddTestHostApplicationLifetime' instead.")] void AddTestApplicationLifecycleCallbacks(Func testApplicationLifecycleCallbacks); + /// + /// Adds a test application lifecycle callbacks. + /// + /// The factory method for creating the test host application lifetime callbacks. + void AddTestHostApplicationLifetime(Func testHostApplicationLifetimeFactory); + /// /// Adds a data consumer. /// diff --git a/src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.cs b/src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.cs index 684e3cfeec..ff714a33e0 100644 --- a/src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.cs @@ -16,7 +16,9 @@ internal sealed class TestHostManager : ITestHostManager private readonly List _factoryOrdering = []; // Exposed extension points +#pragma warning disable CS0618 // Type or member is obsolete private readonly List> _testApplicationLifecycleCallbacksFactories = []; +#pragma warning restore CS0618 // Type or member is obsolete private readonly List> _dataConsumerFactories = []; private readonly List> _testSessionLifetimeHandlerFactories = []; private readonly List _dataConsumersCompositeServiceFactories = []; @@ -47,9 +49,9 @@ internal async Task> TryBuildTestAdapterInvo ITestFrameworkInvoker testAdapterInvoke = _testFrameworkInvokerFactory(serviceProvider); // We initialize only if enabled - if (await testAdapterInvoke.IsEnabledAsync()) + if (await testAdapterInvoke.IsEnabledAsync().ConfigureAwait(false)) { - await testAdapterInvoke.TryInitializeAsync(); + await testAdapterInvoke.TryInitializeAsync().ConfigureAwait(false); return ActionResult.Ok(testAdapterInvoke); } @@ -78,9 +80,9 @@ internal async Task> TryBuildTestExecu ITestExecutionFilterFactory testExecutionFilterFactory = _testExecutionFilterFactory(serviceProvider); // We initialize only if enabled - if (await testExecutionFilterFactory.IsEnabledAsync()) + if (await testExecutionFilterFactory.IsEnabledAsync().ConfigureAwait(false)) { - await testExecutionFilterFactory.TryInitializeAsync(); + await testExecutionFilterFactory.TryInitializeAsync().ConfigureAwait(false); return ActionResult.Ok(testExecutionFilterFactory); } @@ -88,12 +90,22 @@ internal async Task> TryBuildTestExecu return ActionResult.Fail(); } + [Obsolete] public void AddTestApplicationLifecycleCallbacks(Func testApplicationLifecycleCallbacks) { Guard.NotNull(testApplicationLifecycleCallbacks); _testApplicationLifecycleCallbacksFactories.Add(testApplicationLifecycleCallbacks); } + public void AddTestHostApplicationLifetime(Func testHostApplicationLifetime) + { + Guard.NotNull(testHostApplicationLifetime); +#pragma warning disable CS0612 // Type or member is obsolete + _testApplicationLifecycleCallbacksFactories.Add(testHostApplicationLifetime); +#pragma warning restore CS0612 // Type or member is obsolete + } + +#pragma warning disable CS0618 // Type or member is obsolete internal async Task BuildTestApplicationLifecycleCallbackAsync(ServiceProvider serviceProvider) { List testApplicationLifecycleCallbacks = []; @@ -102,24 +114,21 @@ internal async Task BuildTestApplicationLi ITestApplicationLifecycleCallbacks service = testApplicationLifecycleCallbacksFactory(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (testApplicationLifecycleCallbacks.Any(x => x.Uid == service.Uid)) - { - ITestApplicationLifecycleCallbacks currentRegisteredExtension = testApplicationLifecycleCallbacks.Single(x => x.Uid == service.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, service.Uid, currentRegisteredExtension.GetType())); - } + testApplicationLifecycleCallbacks.ValidateUniqueExtension(service); // We initialize only if enabled - if (await service.IsEnabledAsync()) + if (await service.IsEnabledAsync().ConfigureAwait(false)) { - await service.TryInitializeAsync(); + await service.TryInitializeAsync().ConfigureAwait(false); // Register the extension for usage testApplicationLifecycleCallbacks.Add(service); } } - return testApplicationLifecycleCallbacks.ToArray(); + return [.. testApplicationLifecycleCallbacks]; } +#pragma warning restore CS0618 // Type or member is obsolete public void AddDataConsumer(Func dataConsumerFactory) { @@ -149,16 +158,12 @@ public void AddDataConsumer(CompositeExtensionFactory compositeServiceFact IDataConsumer service = dataConsumerFactory(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (dataConsumers.Any(x => x.Consumer.Uid == service.Uid)) - { - (IExtension consumer, int order) = dataConsumers.Single(x => x.Consumer.Uid == service.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, service.Uid, consumer.GetType())); - } + dataConsumers.ValidateUniqueExtension(service, x => x.Consumer); // We initialize only if enabled - if (await service.IsEnabledAsync()) + if (await service.IsEnabledAsync().ConfigureAwait(false)) { - await service.TryInitializeAsync(); + await service.TryInitializeAsync().ConfigureAwait(false); // Register the extension for usage dataConsumers.Add((service, _factoryOrdering.IndexOf(dataConsumerFactory))); @@ -179,16 +184,12 @@ public void AddDataConsumer(CompositeExtensionFactory compositeServiceFact var instance = (IExtension)compositeFactoryInstance.GetInstance(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (dataConsumers.Any(x => x.Consumer.Uid == instance.Uid)) - { - (IExtension consumer, int _) = dataConsumers.Single(x => x.Consumer.Uid == instance.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, instance.Uid, consumer.GetType())); - } + dataConsumers.ValidateUniqueExtension(instance, x => x.Consumer); // We initialize only if enabled - if (await instance.IsEnabledAsync()) + if (await instance.IsEnabledAsync().ConfigureAwait(false)) { - await instance.TryInitializeAsync(); + await instance.TryInitializeAsync().ConfigureAwait(false); } // Add to the list of shared singletons @@ -199,7 +200,7 @@ public void AddDataConsumer(CompositeExtensionFactory compositeServiceFact var extension = (IExtension)compositeFactoryInstance.GetInstance(); // We register the extension only if enabled - if (await extension.IsEnabledAsync()) + if (await extension.IsEnabledAsync().ConfigureAwait(false)) { if (extension is IDataConsumer consumer) { @@ -212,7 +213,7 @@ public void AddDataConsumer(CompositeExtensionFactory compositeServiceFact } } - return dataConsumers.ToArray(); + return [.. dataConsumers]; } public void AddTestSessionLifetimeHandle(Func testSessionLifetimeHandleFactory) @@ -243,16 +244,12 @@ public void AddTestSessionLifetimeHandle(CompositeExtensionFactory composi ITestSessionLifetimeHandler service = testSessionLifetimeHandlerFactory(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (testSessionLifetimeHandlers.Any(x => x.TestSessionLifetimeHandler.Uid == service.Uid)) - { - (IExtension testSessionLifetimeHandler, int _) = testSessionLifetimeHandlers.Single(x => x.TestSessionLifetimeHandler.Uid == service.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, service.Uid, testSessionLifetimeHandler.GetType())); - } + testSessionLifetimeHandlers.ValidateUniqueExtension(service, x => x.TestSessionLifetimeHandler); // We initialize only if enabled - if (await service.IsEnabledAsync()) + if (await service.IsEnabledAsync().ConfigureAwait(false)) { - await service.TryInitializeAsync(); + await service.TryInitializeAsync().ConfigureAwait(false); // Register the extension for usage testSessionLifetimeHandlers.Add((service, _factoryOrdering.IndexOf(testSessionLifetimeHandlerFactory))); @@ -273,16 +270,12 @@ public void AddTestSessionLifetimeHandle(CompositeExtensionFactory composi var instance = (IExtension)compositeFactoryInstance.GetInstance(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (testSessionLifetimeHandlers.Any(x => x.TestSessionLifetimeHandler.Uid == instance.Uid)) - { - (IExtension testSessionLifetimeHandler, int _) = testSessionLifetimeHandlers.Single(x => x.TestSessionLifetimeHandler.Uid == instance.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, instance.Uid, testSessionLifetimeHandler.GetType())); - } + testSessionLifetimeHandlers.ValidateUniqueExtension(instance, x => x.TestSessionLifetimeHandler); // We initialize only if enabled - if (await instance.IsEnabledAsync()) + if (await instance.IsEnabledAsync().ConfigureAwait(false)) { - await instance.TryInitializeAsync(); + await instance.TryInitializeAsync().ConfigureAwait(false); } // Add to the list of shared singletons @@ -293,7 +286,7 @@ public void AddTestSessionLifetimeHandle(CompositeExtensionFactory composi var extension = (IExtension)compositeFactoryInstance.GetInstance(); // We register the extension only if enabled - if (await extension.IsEnabledAsync()) + if (await extension.IsEnabledAsync().ConfigureAwait(false)) { if (extension is ITestSessionLifetimeHandler testSessionLifetimeHandler) { @@ -307,6 +300,6 @@ public void AddTestSessionLifetimeHandle(CompositeExtensionFactory composi } } - return testSessionLifetimeHandlers.ToArray(); + return [.. testSessionLifetimeHandlers]; } } diff --git a/src/Platform/Microsoft.Testing.Platform/TestHostControllers/PassiveNodeDataConsumer.cs b/src/Platform/Microsoft.Testing.Platform/TestHostControllers/PassiveNodeDataConsumer.cs index 9e4c2e5be8..31001ace26 100644 --- a/src/Platform/Microsoft.Testing.Platform/TestHostControllers/PassiveNodeDataConsumer.cs +++ b/src/Platform/Microsoft.Testing.Platform/TestHostControllers/PassiveNodeDataConsumer.cs @@ -46,14 +46,14 @@ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, Cancella case SessionFileArtifact sessionFileArtifact: { RunTestAttachment runTestAttachment = new(sessionFileArtifact.FileInfo.FullName, dataProducer.Uid, FileType, sessionFileArtifact.DisplayName, sessionFileArtifact.Description); - await _passiveNode.SendAttachmentsAsync(new TestsAttachments([runTestAttachment]), cancellationToken); + await _passiveNode.SendAttachmentsAsync(new TestsAttachments([runTestAttachment]), cancellationToken).ConfigureAwait(false); break; } case FileArtifact fileArtifact: { RunTestAttachment runTestAttachment = new(fileArtifact.FileInfo.FullName, dataProducer.Uid, FileType, fileArtifact.DisplayName, fileArtifact.Description); - await _passiveNode.SendAttachmentsAsync(new TestsAttachments([runTestAttachment]), cancellationToken); + await _passiveNode.SendAttachmentsAsync(new TestsAttachments([runTestAttachment]), cancellationToken).ConfigureAwait(false); break; } diff --git a/src/Platform/Microsoft.Testing.Platform/TestHostControllers/SystemEnvironmentVariableProvider.cs b/src/Platform/Microsoft.Testing.Platform/TestHostControllers/SystemEnvironmentVariableProvider.cs index 6e4e6bac6e..00bed2b5a6 100644 --- a/src/Platform/Microsoft.Testing.Platform/TestHostControllers/SystemEnvironmentVariableProvider.cs +++ b/src/Platform/Microsoft.Testing.Platform/TestHostControllers/SystemEnvironmentVariableProvider.cs @@ -20,7 +20,7 @@ internal sealed class SystemEnvironmentVariableProvider(IEnvironment environment public string Description => _systemExtension.Description; - public async Task IsEnabledAsync() => await _systemExtension.IsEnabledAsync(); + public async Task IsEnabledAsync() => await _systemExtension.IsEnabledAsync().ConfigureAwait(false); public Task UpdateAsync(IEnvironmentVariables environmentVariables) { diff --git a/src/Platform/Microsoft.Testing.Platform/TestHostControllers/TestHostControllersManager.cs b/src/Platform/Microsoft.Testing.Platform/TestHostControllers/TestHostControllersManager.cs index f04985b9db..cc0b74e43e 100644 --- a/src/Platform/Microsoft.Testing.Platform/TestHostControllers/TestHostControllersManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/TestHostControllers/TestHostControllersManager.cs @@ -92,16 +92,12 @@ internal async Task BuildAsync(ServiceProvider ITestHostEnvironmentVariableProvider envVarProvider = environmentVariableProviderFactory(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (environmentVariableProviders.Any(x => x.TestHostEnvironmentVariableProvider.Uid == envVarProvider.Uid)) - { - (ITestHostEnvironmentVariableProvider testHostEnvironmentVariableProvider, int _) = environmentVariableProviders.Single(x => x.TestHostEnvironmentVariableProvider.Uid == envVarProvider.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, envVarProvider.Uid, testHostEnvironmentVariableProvider.GetType())); - } + environmentVariableProviders.ValidateUniqueExtension(envVarProvider, x => x.TestHostEnvironmentVariableProvider); // We initialize only if enabled - if (await envVarProvider.IsEnabledAsync()) + if (await envVarProvider.IsEnabledAsync().ConfigureAwait(false)) { - await envVarProvider.TryInitializeAsync(); + await envVarProvider.TryInitializeAsync().ConfigureAwait(false); // Register the extension for usage environmentVariableProviders.Add((envVarProvider, _factoryOrdering.IndexOf(environmentVariableProviderFactory))); @@ -113,22 +109,18 @@ internal async Task BuildAsync(ServiceProvider { // Get the singleton var extension = (IExtension)compositeServiceFactory.GetInstance(serviceProvider); - bool isEnabledAsync = await extension.IsEnabledAsync(); + bool isEnabledAsync = await extension.IsEnabledAsync().ConfigureAwait(false); // Check if we have already built the singleton for this composite factory if (!_alreadyBuiltServices.Contains(compositeServiceFactory)) { // Check if we have already extensions of the same type with same id registered - if (environmentVariableProviders.Any(x => x.TestHostEnvironmentVariableProvider.Uid == extension.Uid)) - { - (ITestHostEnvironmentVariableProvider testHostEnvironmentVariableProvider, int _) = environmentVariableProviders.Single(x => x.TestHostEnvironmentVariableProvider.Uid == extension.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, extension.Uid, testHostEnvironmentVariableProvider.GetType())); - } + environmentVariableProviders.ValidateUniqueExtension(extension, x => x.TestHostEnvironmentVariableProvider); // We initialize only if enabled if (isEnabledAsync) { - await extension.TryInitializeAsync(); + await extension.TryInitializeAsync().ConfigureAwait(false); } // Add to the list of shared singletons @@ -157,16 +149,12 @@ internal async Task BuildAsync(ServiceProvider ITestHostProcessLifetimeHandler lifetimeHandler = lifetimeHandlerFactory(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (lifetimeHandlers.Any(x => x.TestHostProcessLifetimeHandler.Uid == lifetimeHandler.Uid)) - { - (ITestHostProcessLifetimeHandler testHostProcessLifetimeHandler, int _) = lifetimeHandlers.Single(x => x.TestHostProcessLifetimeHandler.Uid == lifetimeHandler.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, lifetimeHandler.Uid, testHostProcessLifetimeHandler.GetType())); - } + lifetimeHandlers.ValidateUniqueExtension(lifetimeHandler, x => x.TestHostProcessLifetimeHandler); // We initialize only if enabled - if (await lifetimeHandler.IsEnabledAsync()) + if (await lifetimeHandler.IsEnabledAsync().ConfigureAwait(false)) { - await lifetimeHandler.TryInitializeAsync(); + await lifetimeHandler.TryInitializeAsync().ConfigureAwait(false); // Register the extension for usage lifetimeHandlers.Add((lifetimeHandler, _factoryOrdering.IndexOf(lifetimeHandlerFactory))); @@ -178,21 +166,17 @@ internal async Task BuildAsync(ServiceProvider { // Get the singleton var extension = (IExtension)compositeServiceFactory.GetInstance(serviceProvider); - bool isEnabledAsync = await extension.IsEnabledAsync(); + bool isEnabledAsync = await extension.IsEnabledAsync().ConfigureAwait(false); // Check if we have already built the singleton for this composite factory if (!_alreadyBuiltServices.Contains(compositeServiceFactory)) { - if (lifetimeHandlers.Any(x => x.TestHostProcessLifetimeHandler.Uid == extension.Uid)) - { - (ITestHostProcessLifetimeHandler testHostProcessLifetimeHandler, int _) = lifetimeHandlers.Single(x => x.TestHostProcessLifetimeHandler.Uid == extension.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, extension.Uid, testHostProcessLifetimeHandler.GetType())); - } + lifetimeHandlers.ValidateUniqueExtension(extension, x => x.TestHostProcessLifetimeHandler); // We initialize only if enabled if (isEnabledAsync) { - await extension.TryInitializeAsync(); + await extension.TryInitializeAsync().ConfigureAwait(false); } // Add to the list of shared singletons @@ -221,16 +205,12 @@ internal async Task BuildAsync(ServiceProvider IDataConsumer service = dataConsumerFactory(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (dataConsumers.Any(x => x.Consumer.Uid == service.Uid)) - { - (IExtension consumer, int order) = dataConsumers.Single(x => x.Consumer.Uid == service.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, service.Uid, consumer.GetType())); - } + dataConsumers.ValidateUniqueExtension(service, x => x.Consumer); // We initialize only if enabled - if (await service.IsEnabledAsync()) + if (await service.IsEnabledAsync().ConfigureAwait(false)) { - await service.TryInitializeAsync(); + await service.TryInitializeAsync().ConfigureAwait(false); // Register the extension for usage dataConsumers.Add((service, _factoryOrdering.IndexOf(dataConsumerFactory))); @@ -251,16 +231,12 @@ internal async Task BuildAsync(ServiceProvider var instance = (IExtension)compositeFactoryInstance.GetInstance(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (dataConsumers.Any(x => x.Consumer.Uid == instance.Uid)) - { - (IExtension consumer, int _) = dataConsumers.Single(x => x.Consumer.Uid == instance.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, instance.Uid, consumer.GetType())); - } + dataConsumers.ValidateUniqueExtension(instance, x => x.Consumer); // We initialize only if enabled - if (await instance.IsEnabledAsync()) + if (await instance.IsEnabledAsync().ConfigureAwait(false)) { - await instance.TryInitializeAsync(); + await instance.TryInitializeAsync().ConfigureAwait(false); } // Add to the list of shared singletons @@ -271,7 +247,7 @@ internal async Task BuildAsync(ServiceProvider var extension = (IExtension)compositeFactoryInstance.GetInstance(); // We register the extension only if enabled - if (await extension.IsEnabledAsync()) + if (await extension.IsEnabledAsync().ConfigureAwait(false)) { if (extension is IDataConsumer consumer) { @@ -286,9 +262,9 @@ internal async Task BuildAsync(ServiceProvider bool requireProcessRestart = environmentVariableProviders.Count > 0 || lifetimeHandlers.Count > 0 || dataConsumers.Count > 0; return new TestHostControllerConfiguration( - environmentVariableProviders.OrderBy(x => x.RegistrationOrder).Select(x => x.TestHostEnvironmentVariableProvider).ToArray(), - lifetimeHandlers.OrderBy(x => x.RegistrationOrder).Select(x => x.TestHostProcessLifetimeHandler).ToArray(), - dataConsumers.OrderBy(x => x.RegistrationOrder).Select(x => x.Consumer).ToArray(), + [.. environmentVariableProviders.OrderBy(x => x.RegistrationOrder).Select(x => x.TestHostEnvironmentVariableProvider)], + [.. lifetimeHandlers.OrderBy(x => x.RegistrationOrder).Select(x => x.TestHostProcessLifetimeHandler)], + [.. dataConsumers.OrderBy(x => x.RegistrationOrder).Select(x => x.Consumer)], requireProcessRestart); } } diff --git a/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostControllersExtension.cs b/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostControllersExtension.cs new file mode 100644 index 0000000000..02c81a5fee --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostControllersExtension.cs @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Testing.Platform.Extensions.TestHostOrchestrator; + +/// +/// Represents an extension for test host orchestrators. +/// +internal interface ITestHostOrchestratorExtension : IExtension; diff --git a/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostOrchestratorApplicationLifetime.cs b/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostOrchestratorApplicationLifetime.cs new file mode 100644 index 0000000000..93cb179eb8 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostOrchestratorApplicationLifetime.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Testing.Platform.Extensions.TestHostOrchestrator; + +// NOTE: The equivalent of this for "test host" is ITestApplicationLifecycleCallbacks, which is an unfortunate naming. +// If we ever open orchestration before MTP v2 (https://github.com/microsoft/testfx/issues/5733), we should +// consider if we are okay with this kinda inconsistent naming between test host and test host orchestrator. +internal interface ITestHostOrchestratorApplicationLifetime : ITestHostOrchestratorExtension +{ + /// + /// Executes before the orchestrator runs. + /// + /// The cancellation token. + /// A task representing the asynchronous operation. + Task BeforeRunAsync(CancellationToken cancellationToken); + + /// + /// Executes after the orchestrator runs. + /// + /// The exit code of the orchestrator. + /// The cancellation token. + /// A task representing the asynchronous operation. + Task AfterRunAsync(int exitCode, CancellationToken cancellation); +} diff --git a/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostOrchestratorManager.cs b/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostOrchestratorManager.cs index 3ad59955fb..7f4d5c0827 100644 --- a/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostOrchestratorManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/ITestHostOrchestratorManager.cs @@ -9,5 +9,10 @@ internal interface ITestHostOrchestratorManager { void AddTestHostOrchestrator(Func factory); + // NOTE: In ITestHostManager, we have AddTestApplicationLifecycleCallbacks, which is an unfortunate naming. + // If we ever open orchestration before MTP v2 (https://github.com/microsoft/testfx/issues/5733), we should + // consider if we are okay with this kinda inconsistent naming between test host and test host orchestrator. + void AddTestHostOrchestratorApplicationLifetime(Func testHostOrchestratorApplicationLifetimeFactory); + Task BuildAsync(ServiceProvider serviceProvider); } diff --git a/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/TestHostOrchestratorManager.cs b/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/TestHostOrchestratorManager.cs index d6f7a628bf..e7678fba7e 100644 --- a/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/TestHostOrchestratorManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/TestHostOrcherstrator/TestHostOrchestratorManager.cs @@ -1,13 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Microsoft.Testing.Platform.Resources; +using Microsoft.Testing.Platform.Helpers; using Microsoft.Testing.Platform.Services; namespace Microsoft.Testing.Platform.Extensions.TestHostOrchestrator; internal sealed class TestHostOrchestratorManager : ITestHostOrchestratorManager { + private readonly List> _testHostOrchestratorApplicationLifetimeFactories = []; private List>? _factories; public void AddTestHostOrchestrator(Func factory) @@ -30,22 +31,47 @@ public async Task BuildAsync(ServiceProvider ITestHostOrchestrator orchestrator = factory(serviceProvider); // Check if we have already extensions of the same type with same id registered - if (orchestrators.Any(x => x.Uid == orchestrator.Uid)) + orchestrators.ValidateUniqueExtension(orchestrator); + + // We initialize only if enabled + if (await orchestrator.IsEnabledAsync().ConfigureAwait(false)) { - ITestHostOrchestrator currentRegisteredExtension = orchestrators.Single(x => x.Uid == orchestrator.Uid); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, PlatformResources.ExtensionWithSameUidAlreadyRegisteredErrorMessage, orchestrator.Uid, currentRegisteredExtension.GetType())); + await orchestrator.TryInitializeAsync().ConfigureAwait(false); + + // Register the extension for usage + orchestrators.Add(orchestrator); } + } + + return new TestHostOrchestratorConfiguration([.. orchestrators]); + } + + public void AddTestHostOrchestratorApplicationLifetime(Func testHostOrchestratorApplicationLifetimeFactory) + { + Guard.NotNull(testHostOrchestratorApplicationLifetimeFactory); + _testHostOrchestratorApplicationLifetimeFactories.Add(testHostOrchestratorApplicationLifetimeFactory); + } + + internal async Task BuildTestHostOrchestratorApplicationLifetimesAsync(ServiceProvider serviceProvider) + { + List lifetimes = []; + foreach (Func testHostOrchestratorApplicationLifetimeFactory in _testHostOrchestratorApplicationLifetimeFactories) + { + ITestHostOrchestratorApplicationLifetime service = testHostOrchestratorApplicationLifetimeFactory(serviceProvider); + + // Check if we have already extensions of the same type with same id registered + lifetimes.ValidateUniqueExtension(service); // We initialize only if enabled - if (await orchestrator.IsEnabledAsync()) + if (await service.IsEnabledAsync().ConfigureAwait(false)) { - await orchestrator.TryInitializeAsync(); + await service.TryInitializeAsync().ConfigureAwait(false); // Register the extension for usage - orchestrators.Add(orchestrator); + lifetimes.Add(service); } } - return new TestHostOrchestratorConfiguration(orchestrators.ToArray()); + return [.. lifetimes]; } } diff --git a/src/Platform/Microsoft.Testing.Platform/Tools/ToolsManager.cs b/src/Platform/Microsoft.Testing.Platform/Tools/ToolsManager.cs index 869c60d440..69f2b595cf 100644 --- a/src/Platform/Microsoft.Testing.Platform/Tools/ToolsManager.cs +++ b/src/Platform/Microsoft.Testing.Platform/Tools/ToolsManager.cs @@ -21,12 +21,12 @@ internal async Task> BuildAsync(IServiceProvider servicePro foreach (Func toolFactory in _toolsFactories) { ITool tool = toolFactory(serviceProvider); - if (!await tool.IsEnabledAsync()) + if (!await tool.IsEnabledAsync().ConfigureAwait(false)) { continue; } - await tool.TryInitializeAsync(); + await tool.TryInitializeAsync().ConfigureAwait(false); tools.Add(tool); } diff --git a/src/TestFramework/TestFramework.Extensions/Attributes/UWP_UITestMethodAttribute.cs b/src/TestFramework/TestFramework.Extensions/Attributes/UWP_UITestMethodAttribute.cs index 6be0c1acea..59e96e8f1c 100644 --- a/src/TestFramework/TestFramework.Extensions/Attributes/UWP_UITestMethodAttribute.cs +++ b/src/TestFramework/TestFramework.Extensions/Attributes/UWP_UITestMethodAttribute.cs @@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer; /// public class UITestMethodAttribute : TestMethodAttribute { - private protected override bool UseAsync => true; + private protected override bool UseAsync => GetType() == typeof(UITestMethodAttribute); /// public override TestResult[] Execute(ITestMethod testMethod) => base.Execute(testMethod); @@ -34,7 +34,7 @@ await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatch { try { - tcs.SetResult(await testMethod.InvokeAsync(null)); + tcs.SetResult(await testMethod.InvokeAsync(null).ConfigureAwait(false)); } catch (Exception ex) { @@ -43,7 +43,7 @@ await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatch }); #pragma warning restore VSTHRD101 // Avoid unsupported async delegates - return [await tcs.Task]; + return [await tcs.Task.ConfigureAwait(false)]; } } #endif diff --git a/src/TestFramework/TestFramework.Extensions/Attributes/WinUITestTargetAttribute.cs b/src/TestFramework/TestFramework.Extensions/Attributes/WinUITestTargetAttribute.cs index e440b2f31d..d3cd4dd81c 100644 --- a/src/TestFramework/TestFramework.Extensions/Attributes/WinUITestTargetAttribute.cs +++ b/src/TestFramework/TestFramework.Extensions/Attributes/WinUITestTargetAttribute.cs @@ -23,7 +23,7 @@ public WinUITestTargetAttribute(Type applicationType) if (!typeof(UI.Xaml.Application).IsAssignableFrom(applicationType)) { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, FrameworkMessages.ArgumentXMustDeriveFromClassY, nameof(applicationType), "Microsoft.UI.Xaml.Application"), nameof(applicationType)); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, FrameworkExtensionsMessages.ArgumentXMustDeriveFromClassY, nameof(applicationType), "Microsoft.UI.Xaml.Application"), nameof(applicationType)); } ApplicationType = applicationType; diff --git a/src/TestFramework/TestFramework.Extensions/Attributes/WinUI_UITestMethodAttribute.cs b/src/TestFramework/TestFramework.Extensions/Attributes/WinUI_UITestMethodAttribute.cs index 37f81c56dc..e059339d3a 100644 --- a/src/TestFramework/TestFramework.Extensions/Attributes/WinUI_UITestMethodAttribute.cs +++ b/src/TestFramework/TestFramework.Extensions/Attributes/WinUI_UITestMethodAttribute.cs @@ -34,7 +34,7 @@ public UITestMethodAttribute(string displayName) { } - private protected override bool UseAsync => true; + private protected override bool UseAsync => GetType() == typeof(UITestMethodAttribute); /// /// Gets or sets the that should be used to invoke the UITestMethodAttribute. @@ -62,12 +62,12 @@ internal override async Task ExecuteAsync(ITestMethod testMethod) { // TODO: Code seems to be assuming DeclaringType is never null, but it can be null. // Using 'bang' notation for now to ensure same behavior. - DispatcherQueue dispatcher = GetDispatcherQueue(testMethod.MethodInfo.DeclaringType!.Assembly) ?? throw new InvalidOperationException(FrameworkMessages.AsyncUITestMethodWithNoDispatcherQueue); + DispatcherQueue dispatcher = GetDispatcherQueue(testMethod.MethodInfo.DeclaringType!.Assembly) ?? throw new InvalidOperationException(FrameworkExtensionsMessages.AsyncUITestMethodWithNoDispatcherQueue); if (dispatcher.HasThreadAccess) { try { - return [await testMethod.InvokeAsync(null)]; + return [await testMethod.InvokeAsync(null).ConfigureAwait(false)]; } catch (Exception e) { @@ -82,7 +82,7 @@ internal override async Task ExecuteAsync(ITestMethod testMethod) { try { - tcs.SetResult(await testMethod.InvokeAsync(null)); + tcs.SetResult(await testMethod.InvokeAsync(null).ConfigureAwait(false)); } catch (Exception e) { @@ -94,7 +94,7 @@ internal override async Task ExecuteAsync(ITestMethod testMethod) } #pragma warning restore VSTHRD101 // Avoid unsupported async delegates - return [await tcs.Task]; + return [await tcs.Task.ConfigureAwait(false)]; } private static Type? GetApplicationType(Assembly assembly) diff --git a/src/TestFramework/TestFramework.Extensions/Friends.cs b/src/TestFramework/TestFramework.Extensions/Friends.cs deleted file mode 100644 index 57566ec3fd..0000000000 --- a/src/TestFramework/TestFramework.Extensions/Friends.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -// Friend assemblies -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("MSTestAdapter.PlatformServices.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] - -#if WINDOWS_UWP || WIN_UI -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -#endif diff --git a/src/TestFramework/TestFramework.Extensions/MSTest.TestFramework.NonWindows.nuspec b/src/TestFramework/TestFramework.Extensions/MSTest.TestFramework.NonWindows.nuspec index af5c322364..d214368c74 100644 --- a/src/TestFramework/TestFramework.Extensions/MSTest.TestFramework.NonWindows.nuspec +++ b/src/TestFramework/TestFramework.Extensions/MSTest.TestFramework.NonWindows.nuspec @@ -34,21 +34,25 @@ $CommonFileElements$ + + + + - + @@ -57,7 +61,7 @@ - + @@ -66,7 +70,7 @@ - + @@ -75,7 +79,7 @@ - + diff --git a/src/TestFramework/TestFramework.Extensions/MSTest.TestFramework.nuspec b/src/TestFramework/TestFramework.Extensions/MSTest.TestFramework.nuspec index 67a4e010a2..deeb4715bd 100644 --- a/src/TestFramework/TestFramework.Extensions/MSTest.TestFramework.nuspec +++ b/src/TestFramework/TestFramework.Extensions/MSTest.TestFramework.nuspec @@ -47,35 +47,43 @@ $CommonFileElements$ + + + + + + + + - + @@ -86,7 +94,7 @@ - + @@ -95,7 +103,7 @@ - + @@ -104,7 +112,7 @@ - + diff --git a/src/TestFramework/TestFramework.Extensions/MessageLevel.cs b/src/TestFramework/TestFramework.Extensions/MessageLevel.cs index 064b617131..4d6fecd6f7 100644 --- a/src/TestFramework/TestFramework.Extensions/MessageLevel.cs +++ b/src/TestFramework/TestFramework.Extensions/MessageLevel.cs @@ -4,7 +4,7 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; /// -/// Specifies the severity level of messages displayed using the API. +/// Specifies the severity level of messages displayed using the API. /// public enum MessageLevel { diff --git a/src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Shipped.txt b/src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Shipped.txt index 1e3ad80187..b50cde008f 100644 --- a/src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Shipped.txt +++ b/src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Shipped.txt @@ -18,6 +18,7 @@ Microsoft.VisualStudio.TestTools.UnitTesting.TestContext.TestDisplayName.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestContext.TestDisplayName.set -> void Microsoft.VisualStudio.TestTools.UnitTesting.TestContext.TestException.get -> System.Exception? Microsoft.VisualStudio.TestTools.UnitTesting.TestContext.TestException.set -> void +Microsoft.VisualStudio.TestTools.UnitTesting.TestContext.TestRunCount.get -> int virtual Microsoft.VisualStudio.TestTools.UnitTesting.TestContext.CancellationTokenSource.get -> System.Threading.CancellationTokenSource! virtual Microsoft.VisualStudio.TestTools.UnitTesting.TestContext.CancellationTokenSource.set -> void virtual Microsoft.VisualStudio.TestTools.UnitTesting.TestContext.CurrentTestOutcome.get -> Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome diff --git a/src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txt b/src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txt index 3fbc1ee8a4..7dc5c58110 100644 --- a/src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txt @@ -1,2 +1 @@ #nullable enable -Microsoft.VisualStudio.TestTools.UnitTesting.TestContext.TestRunCount.get -> int diff --git a/src/TestFramework/TestFramework.Extensions/Resources/FrameworkExtensionsMessages.Designer.cs b/src/TestFramework/TestFramework.Extensions/Resources/FrameworkExtensionsMessages.Designer.cs new file mode 100644 index 0000000000..8591c426b3 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/FrameworkExtensionsMessages.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.VisualStudio.TestTools.UnitTesting { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class FrameworkExtensionsMessages { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal FrameworkExtensionsMessages() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.VisualStudio.TestTools.UnitTesting.Resources.FrameworkExtensionsMessages", typeof(FrameworkExtensionsMessages).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Type '{0}' is not assignable to '{1}'.. + /// + internal static string ArgumentXMustDeriveFromClassY { + get { + return ResourceManager.GetString("ArgumentXMustDeriveFromClassY", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization.. + /// + internal static string AsyncUITestMethodWithNoDispatcherQueue { + get { + return ResourceManager.GetString("AsyncUITestMethodWithNoDispatcherQueue", resourceCulture); + } + } + } +} diff --git a/src/TestFramework/TestFramework.Extensions/Resources/FrameworkExtensionsMessages.resx b/src/TestFramework/TestFramework.Extensions/Resources/FrameworkExtensionsMessages.resx new file mode 100644 index 0000000000..7e55257e77 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/FrameworkExtensionsMessages.resx @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Type '{0}' is not assignable to '{1}'. + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.cs.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.cs.xlf new file mode 100644 index 0000000000..df112b7c30 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.cs.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + Typ „{0}“ nelze přiřadit k „{1}“. + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue nesmí mít hodnotu null. Pokud chcete použít UITestMethodAttribute v desktopové aplikaci WinUI, nezapomeňte během inicializace testu nastavit statický UITestMethodAttribute.DispatcherQueue. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.de.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.de.xlf new file mode 100644 index 0000000000..a764dda7b3 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.de.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + Der Typ "{0}" kann nicht "{1}" zugewiesen werden. + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue darf nicht NULL sein. Um UITestMethodAttribute in einer WinUI-Desktop-App zu verwenden, denken Sie daran, die statische UITestMethodAttribute.DispatcherQueue während der Testinitialisierung festzulegen. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.es.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.es.xlf new file mode 100644 index 0000000000..17912d03f1 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.es.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + Tipo "{0}" no se puede asignar a "{1}". + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue no debe ser null. Para usar UITestMethodAttribute en una aplicación de escritorio WinUI, recuerde establecer el UITestMethodAttribute.DispatcherQueue estático durante la inicialización de la prueba. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.fr.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.fr.xlf new file mode 100644 index 0000000000..6a4b6f969e --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.fr.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + Impossible d'assigner le type '{0}' à '{1}'. + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue ne doit pas avoir la valeur nul. Pour utiliser UITestMethodAttribute dans une application de bureau WinUI, n’oubliez pas de définir l’UITestMethodAttribute.DispatcherQueue statique pendant l’initialisation du test. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.it.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.it.xlf new file mode 100644 index 0000000000..5cd8d9568a --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.it.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + Il tipo '{0}' non è assegnabile a '{1}'. + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue non deve essere Null. Per usare UITestMethodAttribute all'interno di un'app desktop WinUI, ricordarsi di impostare il parametro statico uiTestMethodAttribute.DispatcherQueue durante l'inizializzazione del test. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.ja.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.ja.xlf new file mode 100644 index 0000000000..4d3d045657 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.ja.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + 型 '{0}' を '{1}' に割り当てることはできません。 + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue を null にすることはできません。WinUI デスクトップ アプリ内で UITestMethodAttribute を使用するには、テストの初期化中に静的な UITestMethodAttribute.DispatcherQueue を設定してください。 + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.ko.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.ko.xlf new file mode 100644 index 0000000000..7749a50ad7 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.ko.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + '{0}' 형식은 '{1}'에 할당할 수 없습니다. + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue는 null이 아니어야 합니다. WinUI 데스크톱 앱 내에서 UITestMethodAttribute를 사용하려면 테스트 초기화 중에 정적 UITestMethodAttribute.DispatcherQueue를 설정해야 합니다. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.pl.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.pl.xlf new file mode 100644 index 0000000000..cacee965b7 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.pl.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + Typu „{0}” nie można przypisać do typu „{1}”. + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + Element UITestMethodAttribute.DispatcherQueue nie powinien mieć wartości null. Aby użyć atrybutu UITestMethodAttribute w aplikacji klasycznej WinUI, pamiętaj o ustawieniu statycznego atrybutu UITestMethodAttribute.DispatcherQueue podczas inicjowania testu. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.pt-BR.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.pt-BR.xlf new file mode 100644 index 0000000000..abd65e40f5 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.pt-BR.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + Tipo '{0}' não é atribuível a '{1}'. + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue não deve ser nulo. Para usar UITestMethodAttribute em um aplicativo WinUI Desktop, lembre-se de definir o UITestMethodAttribute.DispatcherQueue estático durante a inicialização do teste. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.ru.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.ru.xlf new file mode 100644 index 0000000000..36e3e0934c --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.ru.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + Тип "{0}" не может быть назначен "{1}". + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + Параметр UITestMethodAttribute.DispatcherQueue не должен иметь значение NULL. Чтобы использовать параметр UITestMethodAttribute в классических приложениях WinUI, не забудьте задать статический параметр UITestMethodAttribute.DispatcherQueue во время инициализации теста. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.tr.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.tr.xlf new file mode 100644 index 0000000000..60c31e4c21 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.tr.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + '{0}' tipi '{1}'ye atanamaz. + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue boş olmamalıdır. UITestMethodAttribute'ı bir WinUI Masaüstü Uygulamasında kullanmak için, test başlatma sırasında statik UITestMethodAttribute.DispatcherQueue'yu ayarlamayı unutmayın. + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.zh-Hans.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.zh-Hans.xlf new file mode 100644 index 0000000000..0d2a247a4d --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.zh-Hans.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + 类型“{0}”不能分配给“{1}”。 + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue 不应为 null。若要在 WinUI 桌面应用中使用 UITestMethodAttribute,请在测试初始化期间设置静态 UITestMethodAttribute.DispatcherQueue。 + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.zh-Hant.xlf b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.zh-Hant.xlf new file mode 100644 index 0000000000..90f4e3bb61 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/Resources/xlf/FrameworkExtensionsMessages.zh-Hant.xlf @@ -0,0 +1,20 @@ + + + + + + Type '{0}' is not assignable to '{1}'. + 無法將類型 '{0}' {0} 指派給 '{1}。 + + - {0} argument name like "applicationType" + - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" + + + + UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. + UITestMethodAttribute.DispatcherQueue 不應為 Null。若要在 WinUI 傳統型應用程式內使用 UITestMethodAttribute,請記得在測試初始化期間設定靜態 UITestMethodAttribute.DispatcherQueue。 + + + + + \ No newline at end of file diff --git a/src/TestFramework/TestFramework.Extensions/TestContext.cs b/src/TestFramework/TestFramework.Extensions/TestContext.cs index ccbb8a68ea..ce78b1a0c1 100644 --- a/src/TestFramework/TestFramework.Extensions/TestContext.cs +++ b/src/TestFramework/TestFramework.Extensions/TestContext.cs @@ -48,6 +48,7 @@ public abstract class TestContext /// /// Gets or sets the cancellation token source. This token source is canceled when test times out. Also when explicitly canceled the test will be aborted. /// + // Disposing isn't important per https://github.com/dotnet/runtime/issues/29970#issuecomment-717840778 public virtual CancellationTokenSource CancellationTokenSource { get; protected internal set; } = new(); /// diff --git a/src/TestFramework/TestFramework.Extensions/TestFramework.Extensions.csproj b/src/TestFramework/TestFramework.Extensions/TestFramework.Extensions.csproj index 134b272c10..3a751c24b1 100644 --- a/src/TestFramework/TestFramework.Extensions/TestFramework.Extensions.csproj +++ b/src/TestFramework/TestFramework.Extensions/TestFramework.Extensions.csproj @@ -36,7 +36,7 @@ Microsoft.VisualStudio.TestTools.UnitTesting Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions - TRACE + $(DefineConstants);TRACE @@ -92,12 +92,22 @@ + + - - PreserveNewest - + + True + True + FrameworkExtensionsMessages.resx + + + ResXFileCodeGenerator + FrameworkExtensionsMessages.Designer.cs + Microsoft.VisualStudio.TestTools.UnitTesting + Designer + diff --git a/src/TestFramework/TestFramework.Extensions/build/net462/MSTest.TestFramework.targets b/src/TestFramework/TestFramework.Extensions/build/net462/MSTest.TestFramework.targets new file mode 100644 index 0000000000..f80fd5bb22 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/build/net462/MSTest.TestFramework.targets @@ -0,0 +1,3 @@ + + + diff --git a/src/TestFramework/TestFramework.Extensions/build/netcoreapp3.1/MSTest.TestFramework.targets b/src/TestFramework/TestFramework.Extensions/build/netcoreapp3.1/MSTest.TestFramework.targets new file mode 100644 index 0000000000..a9e20a1c40 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/build/netcoreapp3.1/MSTest.TestFramework.targets @@ -0,0 +1,3 @@ + + + diff --git a/src/TestFramework/TestFramework.Extensions/build/netstandard2.0/MSTest.TestFramework.targets b/src/TestFramework/TestFramework.Extensions/build/netstandard2.0/MSTest.TestFramework.targets new file mode 100644 index 0000000000..d4afeaee4a --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/build/netstandard2.0/MSTest.TestFramework.targets @@ -0,0 +1,3 @@ + + + diff --git a/src/TestFramework/TestFramework.Extensions/build/uap10.0/MSTest.TestFramework.targets b/src/TestFramework/TestFramework.Extensions/build/uap10.0/MSTest.TestFramework.targets new file mode 100644 index 0000000000..9b248fe99e --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/build/uap10.0/MSTest.TestFramework.targets @@ -0,0 +1,3 @@ + + + diff --git a/src/TestFramework/TestFramework.Extensions/buildTransitive/winui+uwp/MSTest.TestFramework.targets b/src/TestFramework/TestFramework.Extensions/buildTransitive/net6.0AndLater/MSTest.TestFramework.targets similarity index 68% rename from src/TestFramework/TestFramework.Extensions/buildTransitive/winui+uwp/MSTest.TestFramework.targets rename to src/TestFramework/TestFramework.Extensions/buildTransitive/net6.0AndLater/MSTest.TestFramework.targets index 4fa711c2c7..5d2ec50262 100644 --- a/src/TestFramework/TestFramework.Extensions/buildTransitive/winui+uwp/MSTest.TestFramework.targets +++ b/src/TestFramework/TestFramework.Extensions/buildTransitive/net6.0AndLater/MSTest.TestFramework.targets @@ -20,4 +20,12 @@ + + + + diff --git a/src/TestFramework/TestFramework.Extensions/buildTransitive/others/MSTest.TestFramework.targets b/src/TestFramework/TestFramework.Extensions/buildTransitive/others/MSTest.TestFramework.targets new file mode 100644 index 0000000000..7ab2dd1dd4 --- /dev/null +++ b/src/TestFramework/TestFramework.Extensions/buildTransitive/others/MSTest.TestFramework.targets @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreSame.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreSame.cs index 5a80a9b523..61d0a6700d 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreSame.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreSame.cs @@ -220,7 +220,7 @@ public static void AreSame(T? expected, T? actual, [StringSyntax(StringSyntax } private static bool IsAreSameFailing(T? expected, T? actual) - => !ReferenceEquals(expected, actual); + => !object.ReferenceEquals(expected, actual); [DoesNotReturn] private static void ThrowAssertAreSameFailed(T? expected, T? actual, string userMessage) @@ -325,7 +325,7 @@ public static void AreNotSame(T? notExpected, T? actual, [StringSyntax(String } private static bool IsAreNotSameFailing(T? notExpected, T? actual) - => ReferenceEquals(notExpected, actual); + => object.ReferenceEquals(notExpected, actual); [DoesNotReturn] private static void ThrowAssertAreNotSameFailed(string userMessage) diff --git a/src/TestFramework/TestFramework/Assertions/Assert.Contains.cs b/src/TestFramework/TestFramework/Assertions/Assert.Contains.cs index 74abfeb3cd..849d9a4bac 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.Contains.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.Contains.cs @@ -5,6 +5,8 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; +#pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads + /// /// A collection of helper classes to test various conditions within /// unit tests. If the condition being tested is not met, an exception @@ -35,11 +37,11 @@ public AssertSingleInterpolatedStringHandler(int literalLength, int formattedCou } } - internal TItem ComputeAssertion(string assertionName) + internal TItem ComputeAssertion() { if (_builder is not null) { - ThrowAssertCountFailed(assertionName, 1, _actualCount, _builder.ToString()); + ThrowAssertContainsSingleFailed(_actualCount, _builder.ToString()); } return _item!; @@ -55,10 +57,8 @@ public void AppendFormatted(T value) public void AppendFormatted(ReadOnlySpan value) => _builder!.Append(value); -#pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads public void AppendFormatted(ReadOnlySpan value, int alignment = 0, string? format = null) => AppendFormatted(value.ToString(), alignment, format); -#pragma warning restore RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads #endif // NOTE: All the overloads involving format and/or alignment are not super efficient. @@ -79,14 +79,12 @@ public void AppendFormatted(string? value) => _builder!.Append(value); #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters -#pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads public void AppendFormatted(string? value, int alignment = 0, string? format = null) => _builder!.AppendFormat(null, $"{{0,{alignment}:{format}}}", value); public void AppendFormatted(object? value, int alignment = 0, string? format = null) => _builder!.AppendFormat(null, $"{{0,{alignment}:{format}}}", value); #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters -#pragma warning restore RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member @@ -119,7 +117,7 @@ public static T ContainsSingle(IEnumerable collection, string? message) #pragma warning disable IDE0060 // Remove unused parameter public static T ContainsSingle(IEnumerable collection, [InterpolatedStringHandlerArgument(nameof(collection))] ref AssertSingleInterpolatedStringHandler message) #pragma warning restore IDE0060 // Remove unused parameter - => message.ComputeAssertion("ContainsSingle"); + => message.ComputeAssertion(); /// /// Tests whether the specified collection contains exactly one element. @@ -138,7 +136,32 @@ public static T ContainsSingle(IEnumerable collection, [StringSyntax(Strin } string userMessage = BuildUserMessage(message, parameters); - ThrowAssertCountFailed("ContainsSingle", 1, actualCount, userMessage); + ThrowAssertContainsSingleFailed(actualCount, userMessage); + + // Unreachable code but compiler cannot work it out + return default; + } + + /// + /// Tests whether the specified collection contains exactly one element that matches the given predicate. + /// + /// The type of the collection items. + /// A function to test each element for a condition. + /// The collection. + /// The message format to display when the assertion fails. + /// The item that matches the predicate. + public static T ContainsSingle(Func predicate, IEnumerable collection, string message = "") + { + var matchingElements = collection.Where(predicate).ToList(); + int actualCount = matchingElements.Count; + + if (actualCount == 1) + { + return matchingElements[0]; + } + + string userMessage = BuildUserMessage(message); + ThrowAssertSingleMatchFailed(actualCount, userMessage); // Unreachable code but compiler cannot work it out return default; @@ -178,7 +201,7 @@ public static void Contains(T expected, IEnumerable collection, string? me if (!collection.Contains(expected)) { string userMessage = BuildUserMessage(message, parameters); - ThrowAssertFailed("Contains", userMessage); + ThrowAssertContainsItemFailed(userMessage); } } @@ -217,7 +240,7 @@ public static void Contains(T expected, IEnumerable collection, IEqualityC if (!collection.Contains(expected, comparer)) { string userMessage = BuildUserMessage(message, parameters); - ThrowAssertFailed("Contains", userMessage); + ThrowAssertContainsItemFailed(userMessage); } } @@ -234,10 +257,10 @@ public static void Contains(Func predicate, IEnumerable collectio /// Tests whether the specified collection contains the given element. /// /// The type of the collection items. - /// The collection. /// A function to test each element for a condition. + /// The collection. /// The message to display when the assertion fails. - public static void Contains(IEnumerable collection, Func predicate, string? message) + public static void Contains(Func predicate, IEnumerable collection, string? message) => Contains(predicate, collection, message, null); /// @@ -253,7 +276,7 @@ public static void Contains(Func predicate, IEnumerable collectio if (!collection.Any(predicate)) { string userMessage = BuildUserMessage(message, parameters); - ThrowAssertFailed("Contains", userMessage); + ThrowAssertContainsPredicateFailed(userMessage); } } @@ -409,7 +432,7 @@ public static void Contains(string substring, string value, StringComparison com { string userMessage = BuildUserMessage(message, parameters); string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.ContainsFail, value, substring, userMessage); - ThrowAssertFailed("StringAssert.Contains", finalMessage); + ThrowAssertFailed("Assert.Contains", finalMessage); } } @@ -449,7 +472,7 @@ public static void DoesNotContain(T expected, IEnumerable collection, stri if (collection.Contains(expected)) { string userMessage = BuildUserMessage(message, parameters); - ThrowAssertFailed("DoesNotContain", userMessage); + ThrowAssertDoesNotContainItemFailed(userMessage); } } @@ -488,7 +511,7 @@ public static void DoesNotContain(T expected, IEnumerable collection, IEqu if (collection.Contains(expected, comparer)) { string userMessage = BuildUserMessage(message, parameters); - ThrowAssertFailed("DoesNotContain", userMessage); + ThrowAssertDoesNotContainItemFailed(userMessage); } } @@ -524,65 +547,65 @@ public static void DoesNotContain(Func predicate, IEnumerable col if (collection.Any(predicate)) { string userMessage = BuildUserMessage(message, parameters); - ThrowAssertFailed("DoesNotContain", userMessage); + ThrowAssertDoesNotContainPredicateFailed(userMessage); } } /// - /// Tests whether the specified string contains the specified substring - /// and throws an exception if the substring does not occur within the + /// Tests whether the specified string does not contain the specified substring + /// and throws an exception if the substring occurs within the /// test string. /// /// - /// The string expected to occur within . + /// The string expected to not occur within . /// /// - /// The string that is expected to contain . + /// The string that is expected to not contain . /// /// /// is null, or is null, - /// or does not contain . + /// or contains . /// public static void DoesNotContain(string substring, string value) => DoesNotContain(substring, value, StringComparison.Ordinal, string.Empty); /// - /// Tests whether the specified string contains the specified substring - /// and throws an exception if the substring does not occur within the + /// Tests whether the specified string does not contain the specified substring + /// and throws an exception if the substring occurs within the /// test string. /// /// - /// The string expected to occur within . + /// The string expected to not occur within . /// /// - /// The string that is expected to contain . + /// The string that is expected to not contain . /// /// /// The message to include in the exception when - /// is not in . The message is shown in + /// is in . The message is shown in /// test results. /// /// /// is null, or is null, - /// or does not contain . + /// or contains . /// public static void DoesNotContain(string substring, string value, string? message) => DoesNotContain(substring, value, StringComparison.Ordinal, message); /// - /// Tests whether the specified string contains the specified substring - /// and throws an exception if the substring does not occur within the + /// Tests whether the specified string does not contain the specified substring + /// and throws an exception if the substring occurs within the /// test string. /// /// - /// The string expected to occur within . + /// The string expected to not occur within . /// /// - /// The string that is expected to contain . + /// The string that is expected to not contain . /// /// /// The message to include in the exception when - /// is not in . The message is shown in + /// is in . The message is shown in /// test results. /// /// @@ -590,76 +613,76 @@ public static void DoesNotContain(string substring, string value, string? messag /// /// /// is null, or is null, - /// or does not contain . + /// or contains . /// public static void DoesNotContain(string substring, string value, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string? message, params object?[]? parameters) => DoesNotContain(substring, value, StringComparison.Ordinal, message, parameters); /// - /// Tests whether the specified string contains the specified substring - /// and throws an exception if the substring does not occur within the + /// Tests whether the specified string does not contain the specified substring + /// and throws an exception if the substring occurs within the /// test string. /// /// - /// The string expected to occur within . + /// The string expected to not occur within . /// /// - /// The string that is expected to contain . + /// The string that is expected to not contain . /// /// /// The comparison method to compare strings . /// /// /// is null, or is null, - /// or does not contain . + /// or contains . /// public static void DoesNotContain(string substring, string value, StringComparison comparisonType) => DoesNotContain(substring, value, comparisonType, string.Empty); /// - /// Tests whether the specified string contains the specified substring - /// and throws an exception if the substring does not occur within the + /// Tests whether the specified string does not contain the specified substring + /// and throws an exception if the substring occurs within the /// test string. /// /// - /// The string expected to occur within . + /// The string expected to not occur within . /// /// - /// The string that is expected to contain . + /// The string that is expected to not contain . /// /// /// The comparison method to compare strings . /// /// /// The message to include in the exception when - /// is not in . The message is shown in + /// is in . The message is shown in /// test results. /// /// /// is null, or is null, - /// or does not contain . + /// or contains . /// public static void DoesNotContain(string substring, string value, StringComparison comparisonType, string? message) => DoesNotContain(substring, value, comparisonType, message, null); /// - /// Tests whether the specified string contains the specified substring - /// and throws an exception if the substring does not occur within the + /// Tests whether the specified string does not contain the specified substring + /// and throws an exception if the substring occurs within the /// test string. /// /// - /// The string expected to occur within . + /// The string expected to not occur within . /// /// - /// The string that is expected to contain . + /// The string that is expected to not contain . /// /// /// The comparison method to compare strings . /// /// /// The message to include in the exception when - /// is not in . The message is shown in + /// is in . The message is shown in /// test results. /// /// @@ -667,7 +690,7 @@ public static void DoesNotContain(string substring, string value, StringComparis /// /// /// is null, or is null, - /// or does not contain . + /// or contains . /// public static void DoesNotContain(string substring, string value, StringComparison comparisonType, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string? message, params object?[]? parameters) @@ -680,9 +703,100 @@ public static void DoesNotContain(string substring, string value, StringComparis { string userMessage = BuildUserMessage(message, parameters); string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DoesNotContainFail, value, substring, userMessage); - ThrowAssertFailed("StringAssert.DoesNotContain", finalMessage); + ThrowAssertFailed("Assert.DoesNotContain", finalMessage); } } #endregion // DoesNotContain + + #region IsInRange + + /// + /// Tests whether the specified value is within the expected range (inclusive). + /// The range includes both the minimum and maximum values. + /// + /// The type of the values to compare. + /// The minimum value of the expected range (inclusive). + /// The maximum value of the expected range (inclusive). + /// The value to test. + /// The message format to display when the assertion fails. + public static void IsInRange(T minValue, T maxValue, T value, string message = "") + where T : struct, IComparable + { + if (maxValue.CompareTo(minValue) <= 0) + { + throw new ArgumentOutOfRangeException(nameof(maxValue), "The maximum value must be greater than the minimum value."); + } + + if (value.CompareTo(minValue) < 0 || value.CompareTo(maxValue) > 0) + { + string userMessage = BuildUserMessage(message); + string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.IsInRangeFail, value, minValue, maxValue, userMessage); + ThrowAssertFailed("IsInRange", finalMessage); + } + } + + #endregion // IsInRange + + [DoesNotReturn] + private static void ThrowAssertSingleMatchFailed(int actualCount, string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.ContainsSingleMatchFailMsg, + userMessage, + actualCount); + ThrowAssertFailed("Assert.ContainsSingle", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertContainsSingleFailed(int actualCount, string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.ContainsSingleFailMsg, + userMessage, + actualCount); + ThrowAssertFailed("Assert.ContainsSingle", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertContainsItemFailed(string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.ContainsItemFailMsg, + userMessage); + ThrowAssertFailed("Assert.Contains", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertContainsPredicateFailed(string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.ContainsPredicateFailMsg, + userMessage); + ThrowAssertFailed("Assert.Contains", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertDoesNotContainItemFailed(string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.DoesNotContainItemFailMsg, + userMessage); + ThrowAssertFailed("Assert.DoesNotContain", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertDoesNotContainPredicateFailed(string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.DoesNotContainPredicateFailMsg, + userMessage); + ThrowAssertFailed("Assert.DoesNotContain", finalMessage); + } } diff --git a/src/TestFramework/TestFramework/Assertions/Assert.Count.cs b/src/TestFramework/TestFramework/Assertions/Assert.Count.cs index 5c01a9e767..d86e37f5a3 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.Count.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.Count.cs @@ -320,6 +320,6 @@ private static void ThrowAssertIsNotEmptyFailed(string userMessage) CultureInfo.CurrentCulture, FrameworkMessages.IsNotEmptyFailMsg, userMessage); - ThrowAssertFailed($"Assert.IsNotEmpty", finalMessage); + ThrowAssertFailed("Assert.IsNotEmpty", finalMessage); } } diff --git a/src/TestFramework/TestFramework/Assertions/Assert.EndsWith.cs b/src/TestFramework/TestFramework/Assertions/Assert.EndsWith.cs new file mode 100644 index 0000000000..43a93fe0c9 --- /dev/null +++ b/src/TestFramework/TestFramework/Assertions/Assert.EndsWith.cs @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + +public sealed partial class Assert +{ + #region EndsWith + + /// + /// Tests whether the specified string ends with the specified substring + /// and throws an exception if the test string does not end with the + /// substring. + /// + /// + /// The string expected to be a suffix of . + /// + /// + /// The string that is expected to end with . + /// + /// + /// The message to include in the exception when + /// does not end with . The message is + /// shown in test results. + /// + /// + /// is null, or is null, + /// or does not end with . + /// + public static void EndsWith([NotNull] string? substring, [NotNull] string? value, string message = "") + => EndsWith(substring, value, StringComparison.Ordinal, message); + + /// + /// Tests whether the specified string ends with the specified substring + /// and throws an exception if the test string does not end with the + /// substring. + /// + /// + /// The string expected to be a suffix of . + /// + /// + /// The string that is expected to end with . + /// + /// + /// The comparison method to compare strings . + /// + /// + /// The message to include in the exception when + /// does not end with . The message is + /// shown in test results. + /// + /// + /// is null, or is null, + /// or does not start with . + /// + public static void EndsWith([NotNull] string? substring, [NotNull] string? value, StringComparison comparisonType, string message = "") + { + CheckParameterNotNull(value, "Assert.EndsWith", "value", string.Empty); + CheckParameterNotNull(substring, "Assert.EndsWith", "substring", string.Empty); + if (!value.EndsWith(substring, comparisonType)) + { + string userMessage = BuildUserMessage(message); + string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.EndsWithFail, value, substring, userMessage); + ThrowAssertFailed("Assert.EndsWith", finalMessage); + } + } + + #endregion // EndsWith + + #region DoesNotEndWith + + /// + /// Tests whether the specified string does not end with the specified substring + /// and throws an exception if the test string does not end with the + /// substring. + /// + /// + /// The string expected not to be a suffix of . + /// + /// + /// The string that is expected not to end with . + /// + /// + /// The message to include in the exception when + /// ends with . The message is + /// shown in test results. + /// + /// + /// is null, or is null, + /// or ends with . + /// + public static void DoesNotEndWith([NotNull] string? substring, [NotNull] string? value, string message = "") + => DoesNotEndWith(substring, value, StringComparison.Ordinal, message); + + /// + /// Tests whether the specified string does not end with the specified substring + /// and throws an exception if the test string does not end with the + /// substring. + /// + /// + /// The string expected not to be a suffix of . + /// + /// + /// The string that is expected not to end with . + /// + /// + /// The comparison method to compare strings . + /// + /// + /// The message to include in the exception when + /// ends with . The message is + /// shown in test results. + /// + /// + /// is null, or is null, + /// or ends with . + /// + public static void DoesNotEndWith([NotNull] string? substring, [NotNull] string? value, StringComparison comparisonType, string message = "") + { + CheckParameterNotNull(value, "Assert.DoesNotEndWith", "value", string.Empty); + CheckParameterNotNull(substring, "Assert.DoesNotEndWith", "substring", string.Empty); + if (value.EndsWith(substring, comparisonType)) + { + string userMessage = BuildUserMessage(message); + string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DoesNotEndWithFail, value, substring, userMessage); + ThrowAssertFailed("Assert.DoesNotEndWith", finalMessage); + } + } + + #endregion // DoesNotEndWith +} diff --git a/src/TestFramework/TestFramework/Assertions/Assert.IComparable.cs b/src/TestFramework/TestFramework/Assertions/Assert.IComparable.cs new file mode 100644 index 0000000000..3e27a0f99d --- /dev/null +++ b/src/TestFramework/TestFramework/Assertions/Assert.IComparable.cs @@ -0,0 +1,330 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +/// +/// A collection of helper classes to test various conditions within +/// unit tests. If the condition being tested is not met, an exception +/// is thrown. +/// +public sealed partial class Assert +{ + #region IsGreaterThan + + /// + /// Tests whether the value is greater than the lower bound and throws an exception + /// if it is not. + /// + /// + /// The type of values to compare. + /// + /// + /// The lower bound value that the value should exceed. + /// + /// + /// The value to compare. This is the value produced by the code under test. + /// + /// + /// The message to include in the exception when + /// is not greater than . The message is shown in + /// test results. + /// + /// + /// Thrown if is not greater than . + /// + public static void IsGreaterThan(T lowerBound, T value, string message = "") + where T : IComparable + { + if (value.CompareTo(lowerBound) > 0) + { + return; + } + + string userMessage = BuildUserMessage(message); + ThrowAssertIsGreaterThanFailed(lowerBound, value, userMessage); + } + + #endregion // IsGreaterThan + + #region IsGreaterThanOrEqualTo + + /// + /// Tests whether the value is greater than or equal to the lower bound and throws an exception + /// if it is not. + /// + /// + /// The type of values to compare. + /// + /// + /// The lower bound value that the value should meet or exceed. + /// + /// + /// The value to compare. This is the value produced by the code under test. + /// + /// + /// The message to include in the exception when + /// is not greater than or equal to . The message is shown in + /// test results. + /// + /// + /// Thrown if is not greater than or equal to . + /// + public static void IsGreaterThanOrEqualTo(T lowerBound, T value, string message = "") + where T : IComparable + { + if (value.CompareTo(lowerBound) >= 0) + { + return; + } + + string userMessage = BuildUserMessage(message); + ThrowAssertIsGreaterThanOrEqualToFailed(lowerBound, value, userMessage); + } + + #endregion // IsGreaterThanOrEqualTo + + #region IsLessThan + + /// + /// Tests whether the value is less than the upper bound and throws an exception + /// if it is not. + /// + /// + /// The type of values to compare. + /// + /// + /// The upper bound value that the value should be less than. + /// + /// + /// The value to compare. This is the value produced by the code under test. + /// + /// + /// The message to include in the exception when + /// is not less than . The message is shown in + /// test results. + /// + /// + /// Thrown if is not less than . + /// + public static void IsLessThan(T upperBound, T value, string message = "") + where T : IComparable + { + if (value.CompareTo(upperBound) < 0) + { + return; + } + + string userMessage = BuildUserMessage(message); + ThrowAssertIsLessThanFailed(upperBound, value, userMessage); + } + + #endregion // IsLessThan + + #region IsLessThanOrEqualTo + + /// + /// Tests whether the value is less than or equal to the upper bound and throws an exception + /// if it is not. + /// + /// + /// The type of values to compare. + /// + /// + /// The upper bound value that the value should not exceed. + /// + /// + /// The value to compare. This is the value produced by the code under test. + /// + /// + /// The message to include in the exception when + /// is not less than or equal to . The message is shown in + /// test results. + /// + /// + /// Thrown if is not less than or equal to . + /// + public static void IsLessThanOrEqualTo(T upperBound, T value, string message = "") + where T : IComparable + { + if (value.CompareTo(upperBound) <= 0) + { + return; + } + + string userMessage = BuildUserMessage(message); + ThrowAssertIsLessThanOrEqualToFailed(upperBound, value, userMessage); + } + + #endregion // IsLessThanOrEqualTo + + #region IsPositive + + /// + /// Tests whether the specified value is positive and throws an exception + /// if it is not. + /// + /// + /// The type of value to test. + /// + /// + /// The value to test. + /// + /// + /// The message to include in the exception when + /// is not positive. The message is shown in test results. + /// + /// + /// Thrown if is not positive. + /// + public static void IsPositive(T value, string message = "") + where T : struct, IComparable + { + var zero = default(T); + + // Handle special case for floating point NaN values + if (value is float.NaN) + { + string userMessage = BuildUserMessage(message); + ThrowAssertIsPositiveFailed(value, userMessage); + return; + } + + if (value is double.NaN) + { + string userMessage = BuildUserMessage(message); + ThrowAssertIsPositiveFailed(value, userMessage); + return; + } + + if (value.CompareTo(zero) > 0) + { + return; + } + + string userMessage2 = BuildUserMessage(message); + ThrowAssertIsPositiveFailed(value, userMessage2); + } + + #endregion // IsPositive + + #region IsNegative + + /// + /// Tests whether the specified value is negative and throws an exception + /// if it is not. + /// + /// + /// The type of value to test. + /// + /// + /// The value to test. + /// + /// + /// The message to include in the exception when + /// is not negative. The message is shown in test results. + /// + /// + /// Thrown if is not negative. + /// + public static void IsNegative(T value, string message = "") + where T : struct, IComparable + { + var zero = default(T); + + // Handle special case for floating point NaN values + if (value is float.NaN) + { + string userMessage = BuildUserMessage(message); + ThrowAssertIsNegativeFailed(value, userMessage); + return; + } + + if (value is double.NaN) + { + string userMessage = BuildUserMessage(message); + ThrowAssertIsNegativeFailed(value, userMessage); + return; + } + + if (value.CompareTo(zero) < 0) + { + return; + } + + string userMessage2 = BuildUserMessage(message); + ThrowAssertIsNegativeFailed(value, userMessage2); + } + + #endregion // IsNegative + + [DoesNotReturn] + private static void ThrowAssertIsGreaterThanFailed(T lowerBound, T value, string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.IsGreaterThanFailMsg, + userMessage, + ReplaceNulls(lowerBound), + ReplaceNulls(value)); + ThrowAssertFailed("Assert.IsGreaterThan", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertIsGreaterThanOrEqualToFailed(T lowerBound, T value, string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.IsGreaterThanOrEqualToFailMsg, + userMessage, + ReplaceNulls(lowerBound), + ReplaceNulls(value)); + ThrowAssertFailed("Assert.IsGreaterThanOrEqualTo", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertIsLessThanFailed(T upperBound, T value, string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.IsLessThanFailMsg, + userMessage, + ReplaceNulls(upperBound), + ReplaceNulls(value)); + ThrowAssertFailed("Assert.IsLessThan", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertIsLessThanOrEqualToFailed(T upperBound, T value, string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.IsLessThanOrEqualToFailMsg, + userMessage, + ReplaceNulls(upperBound), + ReplaceNulls(value)); + ThrowAssertFailed("Assert.IsLessThanOrEqualTo", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertIsPositiveFailed(T value, string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.IsPositiveFailMsg, + userMessage, + ReplaceNulls(value)); + ThrowAssertFailed("Assert.IsPositive", finalMessage); + } + + [DoesNotReturn] + private static void ThrowAssertIsNegativeFailed(T value, string userMessage) + { + string finalMessage = string.Format( + CultureInfo.CurrentCulture, + FrameworkMessages.IsNegativeFailMsg, + userMessage, + ReplaceNulls(value)); + ThrowAssertFailed("Assert.IsNegative", finalMessage); + } +} diff --git a/src/TestFramework/TestFramework/Assertions/Assert.Matches.cs b/src/TestFramework/TestFramework/Assertions/Assert.Matches.cs new file mode 100644 index 0000000000..224c4ecb86 --- /dev/null +++ b/src/TestFramework/TestFramework/Assertions/Assert.Matches.cs @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + +public sealed partial class Assert +{ + #region MatchesRegex + + /// + /// Tests whether the specified string MatchesRegex a regular expression and + /// throws an exception if the string does not match the expression. + /// + /// + /// The regular expression that is + /// expected to match. + /// + /// + /// The string that is expected to match . + /// + /// + /// The message to include in the exception when + /// does not match . The message is shown in + /// test results. + /// + /// + /// is null, or is null, + /// or does not match . + /// + public static void MatchesRegex([NotNull] Regex? pattern, [NotNull] string? value, string message = "") + { + CheckParameterNotNull(value, "Assert.MatchesRegex", "value", string.Empty); + CheckParameterNotNull(pattern, "Assert.MatchesRegex", "pattern", string.Empty); + + if (!pattern.IsMatch(value)) + { + string userMessage = BuildUserMessage(message); + string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.IsMatchFail, value, pattern, userMessage); + ThrowAssertFailed("Assert.MatchesRegex", finalMessage); + } + } + + /// + /// Tests whether the specified string MatchesRegex a regular expression and + /// throws an exception if the string does not match the expression. + /// + /// + /// The regular expression that is + /// expected to match. + /// + /// + /// The string that is expected to match . + /// + /// + /// The message to include in the exception when + /// does not match . The message is shown in + /// test results. + /// + /// + /// is null, or is null, + /// or does not match . + /// + public static void MatchesRegex([NotNull] string? pattern, [NotNull] string? value, string message = "") + => MatchesRegex(ToRegex(pattern), value, message); + + #endregion // MatchesRegex + + #region DoesNotMatchRegex + + /// + /// Tests whether the specified string does not match a regular expression + /// and throws an exception if the string MatchesRegex the expression. + /// + /// + /// The regular expression that is + /// expected to not match. + /// + /// + /// The string that is expected not to match . + /// + /// + /// The message to include in the exception when + /// MatchesRegex . The message is shown in test + /// results. + /// + /// + /// is null, or is null, + /// or MatchesRegex . + /// + public static void DoesNotMatchRegex([NotNull] Regex? pattern, [NotNull] string? value, string message = "") + { + CheckParameterNotNull(value, "Assert.DoesNotMatchRegex", "value", string.Empty); + CheckParameterNotNull(pattern, "Assert.DoesNotMatchRegex", "pattern", string.Empty); + + if (pattern.IsMatch(value)) + { + string userMessage = BuildUserMessage(message); + string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.IsNotMatchFail, value, pattern, userMessage); + ThrowAssertFailed("Assert.DoesNotMatchRegex", finalMessage); + } + } + + /// + /// Tests whether the specified string does not match a regular expression + /// and throws an exception if the string MatchesRegex the expression. + /// + /// + /// The regular expression that is + /// expected to not match. + /// + /// + /// The string that is expected not to match . + /// + /// + /// The message to include in the exception when + /// MatchesRegex . The message is shown in test + /// results. + /// + /// + /// is null, or is null, + /// or MatchesRegex . + /// + public static void DoesNotMatchRegex([NotNull] string? pattern, [NotNull] string? value, string message = "") + => DoesNotMatchRegex(ToRegex(pattern), value, message); + + #endregion // DoesNotMatchRegex + + private static Regex? ToRegex([NotNull] string? pattern) + { + CheckParameterNotNull(pattern, "Assert.MatchesRegex", "pattern", string.Empty); + return new Regex(pattern); + } +} diff --git a/src/TestFramework/TestFramework/Assertions/Assert.StartsWith.cs b/src/TestFramework/TestFramework/Assertions/Assert.StartsWith.cs new file mode 100644 index 0000000000..9f6904a939 --- /dev/null +++ b/src/TestFramework/TestFramework/Assertions/Assert.StartsWith.cs @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + +public sealed partial class Assert +{ + #region StartsWith + + /// + /// Tests whether the specified string begins with the specified substring + /// and throws an exception if the test string does not start with the + /// substring. + /// + /// + /// The string expected to be a prefix of . + /// + /// + /// The string that is expected to begin with . + /// + /// + /// The message to include in the exception when + /// does not begin with . The message is + /// shown in test results. + /// + /// + /// is null, or is null, + /// or does not start with . + /// + public static void StartsWith([NotNull] string? substring, [NotNull] string? value, string message = "") + => StartsWith(substring, value, StringComparison.Ordinal, message); + + /// + /// Tests whether the specified string begins with the specified substring + /// and throws an exception if the test string does not start with the + /// substring. + /// + /// + /// The string expected to be a prefix of . + /// + /// + /// The string that is expected to begin with . + /// + /// + /// The comparison method to compare strings . + /// + /// + /// The message to include in the exception when + /// does not begin with . The message is + /// shown in test results. + /// + /// + /// is null, or is null, + /// or does not start with . + /// + public static void StartsWith([NotNull] string? substring, [NotNull] string? value, StringComparison comparisonType, string message = "") + { + CheckParameterNotNull(value, "Assert.StartsWith", "value", string.Empty); + CheckParameterNotNull(substring, "Assert.StartsWith", "substring", string.Empty); + if (!value.StartsWith(substring, comparisonType)) + { + string userMessage = BuildUserMessage(message); + string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.StartsWithFail, value, substring, userMessage); + ThrowAssertFailed("Assert.StartsWith", finalMessage); + } + } + + #endregion // StartsWith + + #region DoesNotStartWith + + /// + /// Tests whether the specified string does not begin with the specified substring + /// and throws an exception if the test string does start with the substring. + /// + /// + /// The string expected to be a prefix of . + /// + /// + /// The string that is expected to begin with . + /// + /// + /// The message to include in the exception when + /// does not begin with . The message is + /// shown in test results. + /// + /// + /// is null, or is null, + /// or does not start with . + /// + public static void DoesNotStartWith([NotNull] string? substring, [NotNull] string? value, string message = "") + => DoesNotStartWith(substring, value, StringComparison.Ordinal, message); + + /// + /// Tests whether the specified string does not begin with the specified substring + /// and throws an exception if the test string does start with the substring. + /// + /// + /// The string expected to be a prefix of . + /// + /// + /// The string that is expected to begin with . + /// + /// + /// The comparison method to compare strings . + /// + /// + /// The message to include in the exception when + /// does not begin with . The message is + /// shown in test results. + /// + /// + /// is null, or is null, + /// or does not start with . + /// + public static void DoesNotStartWith([NotNull] string? substring, [NotNull] string? value, StringComparison comparisonType, string message = "") + { + CheckParameterNotNull(value, "Assert.DoesNotStartWith", "value", string.Empty); + CheckParameterNotNull(substring, "Assert.DoesNotStartWith", "substring", string.Empty); + if (value.StartsWith(substring, comparisonType)) + { + string userMessage = BuildUserMessage(message); + string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DoesNotStartWithFail, value, substring, userMessage); + ThrowAssertFailed("Assert.DoesNotStartWith", finalMessage); + } + } + + #endregion // DoesNotStartWith +} diff --git a/src/TestFramework/TestFramework/Assertions/Assert.ThrowsException.cs b/src/TestFramework/TestFramework/Assertions/Assert.ThrowsException.cs index d57d2c31c9..b02272b50a 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.ThrowsException.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.ThrowsException.cs @@ -31,6 +31,11 @@ public AssertNonStrictThrowsInterpolatedStringHandler(int literalLength, int for } } + public AssertNonStrictThrowsInterpolatedStringHandler(int literalLength, int formattedCount, Func action, out bool shouldAppend) + : this(literalLength, formattedCount, (Action)(() => _ = action()), out shouldAppend) + { + } + internal TException ComputeAssertion() { if (_state.FailAction is not null) @@ -98,6 +103,11 @@ public AssertThrowsExactlyInterpolatedStringHandler(int literalLength, int forma } } + public AssertThrowsExactlyInterpolatedStringHandler(int literalLength, int formattedCount, Func action, out bool shouldAppend) + : this(literalLength, formattedCount, (Action)(() => _ = action()), out shouldAppend) + { + } + internal TException ComputeAssertion() { if (_state.FailAction is not null) @@ -218,6 +228,13 @@ public static TException Throws(Action action, [InterpolatedStringHa where TException : Exception => message.ComputeAssertion(); + /// +#pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/76578 + public static TException Throws(Func action, [InterpolatedStringHandlerArgument(nameof(action))] ref AssertNonStrictThrowsInterpolatedStringHandler message) +#pragma warning restore IDE0060 // Remove unused parameter + where TException : Exception + => message.ComputeAssertion(); + /// /// Asserts that the delegate throws an exception of type /// (and not of derived type) and throws AssertFailedException if code does not throws exception or throws @@ -288,6 +305,13 @@ public static TException ThrowsExactly(Action action, [InterpolatedS where TException : Exception => message.ComputeAssertion(); + /// +#pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/76578 + public static TException ThrowsExactly(Func action, [InterpolatedStringHandlerArgument(nameof(action))] ref AssertThrowsExactlyInterpolatedStringHandler message) +#pragma warning restore IDE0060 // Remove unused parameter + where TException : Exception + => message.ComputeAssertion(); + /// /// Tests whether the code specified by delegate throws exact given exception /// of type (and not of derived type) and throws AssertFailedException diff --git a/src/TestFramework/TestFramework/Assertions/Assert.cs b/src/TestFramework/TestFramework/Assertions/Assert.cs index 61ebec34ae..ba2c122a2c 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.cs @@ -14,6 +14,17 @@ private Assert() { } + /// + /// Gets the singleton instance of the Assert functionality. + /// + /// + /// Users can use this to plug-in custom assertions through C# extension methods. + /// For instance, the signature of a custom assertion provider could be "public static void IsOfType<T>(this Assert assert, object obj)" + /// Users could then use a syntax similar to the default assertions which in this case is "Assert.Instance.IsOfType<Dog>(animal);" + /// More documentation is at "https://github.com/Microsoft/testfx/docs/README.md". + /// + public static Assert Instance { get; } = new Assert(); + /// /// Gets the singleton instance of the Assert functionality. /// @@ -23,7 +34,12 @@ private Assert() /// Users could then use a syntax similar to the default assertions which in this case is "Assert.That.IsOfType<Dog>(animal);" /// More documentation is at "https://github.com/Microsoft/testfx/docs/README.md". /// - public static Assert That { get; } = new Assert(); +#if NET6_0_OR_GREATER + [Obsolete(FrameworkConstants.ThatPropertyObsoleteMessage, DiagnosticId = "MSTESTOBS")] +#else + [Obsolete(FrameworkConstants.ThatPropertyObsoleteMessage)] +#endif + public static Assert That => Instance; /// /// Replaces null characters ('\0') with "\\0". @@ -139,24 +155,53 @@ private static int CompareInternal(string? expected, string? actual, bool ignore => string.Compare(expected, actual, ignoreCase, culture); #pragma warning restore CA1309 // Use ordinal string comparison - #region EqualsAssertion + #region DoNotUse /// /// Static equals overloads are used for comparing instances of two types for reference /// equality. This method should not be used for comparison of two instances for - /// equality. This object will always throw with Assert.Fail. Please use - /// Assert.AreEqual and associated overloads in your unit tests. + /// equality. Please use Assert.AreEqual and associated overloads in your unit tests. /// /// Object A. /// Object B. - /// False, always. + /// Never returns. [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "We want to compare 'object A' with 'object B', so it makes sense to have 'obj' in the parameter name")] -#pragma warning disable IDE0060 // Remove unused parameter + [Obsolete( + FrameworkConstants.DoNotUseAssertEquals, +#if DEBUG + error: false)] +#else + error: true)] +#endif + [DoesNotReturn] public static new bool Equals(object? objA, object? objB) -#pragma warning restore IDE0060 // Remove unused parameter { Fail(FrameworkMessages.DoNotUseAssertEquals); return false; } + + /// + /// Static ReferenceEquals overloads are used for comparing instances of two types for reference + /// equality. This method should not be used for comparison of two instances for + /// reference equality. Please use Assert.AreSame and associated overloads in your unit tests. + /// + /// Object A. + /// Object B. + /// Never returns. + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "We want to compare 'object A' with 'object B', so it makes sense to have 'obj' in the parameter name")] + [Obsolete( + FrameworkConstants.DoNotUseAssertReferenceEquals, +#if DEBUG + error: false)] +#else + error: true)] +#endif + [DoesNotReturn] + public static new bool ReferenceEquals(object? objA, object? objB) + { + Fail(FrameworkMessages.DoNotUseAssertReferenceEquals); + return false; + } + #endregion } diff --git a/src/TestFramework/TestFramework/Assertions/CollectionAssert.cs b/src/TestFramework/TestFramework/Assertions/CollectionAssert.cs index 0d87f35366..bb65e2780e 100644 --- a/src/TestFramework/TestFramework/Assertions/CollectionAssert.cs +++ b/src/TestFramework/TestFramework/Assertions/CollectionAssert.cs @@ -16,6 +16,17 @@ private CollectionAssert() { } + /// + /// Gets the singleton instance of the CollectionAssert functionality. + /// + /// + /// Users can use this to plug-in custom assertions through C# extension methods. + /// For instance, the signature of a custom assertion provider could be "public static void AreEqualUnordered(this CollectionAssert customAssert, ICollection expected, ICollection actual)" + /// Users could then use a syntax similar to the default assertions which in this case is "CollectionAssert.Instance.AreEqualUnordered(list1, list2);" + /// More documentation is at "https://github.com/Microsoft/testfx/docs/README.md". + /// + public static CollectionAssert Instance { get; } = new CollectionAssert(); + /// /// Gets the singleton instance of the CollectionAssert functionality. /// @@ -25,7 +36,12 @@ private CollectionAssert() /// Users could then use a syntax similar to the default assertions which in this case is "CollectionAssert.That.AreEqualUnordered(list1, list2);" /// More documentation is at "https://github.com/Microsoft/testfx/docs/README.md". /// - public static CollectionAssert That { get; } = new CollectionAssert(); +#if NET6_0_OR_GREATER + [Obsolete(FrameworkConstants.ThatPropertyObsoleteMessage, DiagnosticId = "MSTESTOBS")] +#else + [Obsolete(FrameworkConstants.ThatPropertyObsoleteMessage)] +#endif + public static CollectionAssert That => Instance; #endregion @@ -99,7 +115,7 @@ public static void Contains([NotNull] ICollection? collection, object? element, foreach (object? current in collection) { - if (Equals(current, element)) + if (object.Equals(current, element)) { return; } @@ -176,7 +192,7 @@ public static void DoesNotContain([NotNull] ICollection? collection, object? ele foreach (object? current in collection) { - if (Equals(current, element)) + if (object.Equals(current, element)) { Assert.ThrowAssertFailed("CollectionAssert.DoesNotContain", Assert.BuildUserMessage(message, parameters)); } @@ -327,8 +343,7 @@ public static void AllItemsAreUnique([NotNull] ICollection? collection, [StringS } else { -#pragma warning disable CA1864 // Prefer the 'IDictionary.TryAdd(TKey, TValue)' method - if (table.ContainsKey(current)) + if (!table.TryAdd(current, true)) { string userMessage = Assert.BuildUserMessage(message, parameters); string finalMessage = string.Format( @@ -339,11 +354,6 @@ public static void AllItemsAreUnique([NotNull] ICollection? collection, [StringS Assert.ThrowAssertFailed("CollectionAssert.AllItemsAreUnique", finalMessage); } - else - { - table.Add(current, true); - } -#pragma warning restore CA1864 // Prefer the 'IDictionary.TryAdd(TKey, TValue)' method } } } @@ -691,7 +701,7 @@ public static void AreEquivalent( } // If the references are the same or both collections are null, they are equivalent. - if (ReferenceEquals(expected, actual) || expected == null) + if (object.ReferenceEquals(expected, actual) || expected == null) { return; } @@ -926,7 +936,7 @@ public static void AreNotEquivalent( // If the references are the same or both collections are null, they // are equivalent. object.ReferenceEquals will handle case where both are null. - if (ReferenceEquals(expected, actual)) + if (object.ReferenceEquals(expected, actual)) { string userMessage = Assert.BuildUserMessage(message, parameters); string finalMessage = string.Format( @@ -1598,7 +1608,7 @@ private static bool AreCollectionsEqual(ICollection? expected, ICollection? actu ref string reason) { Assert.CheckParameterNotNull(comparer, "Assert.AreCollectionsEqual", "comparer", string.Empty); - if (ReferenceEquals(expected, actual)) + if (object.ReferenceEquals(expected, actual)) { reason = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.BothCollectionsSameReference, string.Empty); return true; @@ -1685,4 +1695,54 @@ private sealed class ObjectComparer : IComparer int IComparer.Compare(object? x, object? y) => Equals(x, y) ? 0 : -1; } #endregion + + #region DoNotUse + + /// + /// Static equals overloads are used for comparing instances of two types for equality. + /// This method should not be used for comparison of two instances for equality. + /// Please use CollectionAssert.AreEqual and associated overloads in your unit tests. + /// + /// Object A. + /// Object B. + /// Never returns. + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "We want to compare 'object A' with 'object B', so it makes sense to have 'obj' in the parameter name")] + [Obsolete( + FrameworkConstants.DoNotUseCollectionAssertEquals, +#if DEBUG + error: false)] +#else + error: true)] +#endif + [DoesNotReturn] + public static new bool Equals(object? objA, object? objB) + { + Assert.Fail(FrameworkMessages.DoNotUseCollectionAssertEquals); + return false; + } + + /// + /// Static ReferenceEquals overloads are used for comparing instances of two types for reference + /// equality. This method should not be used for comparison of two instances for + /// reference equality. Please use CollectionAssert methods or Assert.AreSame and associated overloads in your unit tests. + /// + /// Object A. + /// Object B. + /// Never returns. + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "We want to compare 'object A' with 'object B', so it makes sense to have 'obj' in the parameter name")] + [Obsolete( + FrameworkConstants.DoNotUseCollectionAssertReferenceEquals, +#if DEBUG + error: false)] +#else + error: true)] +#endif + [DoesNotReturn] + public static new bool ReferenceEquals(object? objA, object? objB) + { + Assert.Fail(FrameworkMessages.DoNotUseCollectionAssertReferenceEquals); + return false; + } + + #endregion } diff --git a/src/TestFramework/TestFramework/Assertions/StringAssert.cs b/src/TestFramework/TestFramework/Assertions/StringAssert.cs index a55c653c4f..a70c740716 100644 --- a/src/TestFramework/TestFramework/Assertions/StringAssert.cs +++ b/src/TestFramework/TestFramework/Assertions/StringAssert.cs @@ -16,6 +16,17 @@ private StringAssert() { } + /// + /// Gets the singleton instance of the StringAssert functionality. + /// + /// + /// Users can use this to plug-in custom assertions through C# extension methods. + /// For instance, the signature of a custom assertion provider could be "public static void ContainsWords(this StringAssert customAssert, string value, ICollection substrings)" + /// Users could then use a syntax similar to the default assertions which in this case is "StringAssert.Instance.ContainsWords(value, substrings);" + /// More documentation is at "https://github.com/Microsoft/testfx/docs/README.md". + /// + public static StringAssert Instance { get; } = new StringAssert(); + /// /// Gets the singleton instance of the StringAssert functionality. /// @@ -25,7 +36,12 @@ private StringAssert() /// Users could then use a syntax similar to the default assertions which in this case is "StringAssert.That.ContainsWords(value, substrings);" /// More documentation is at "https://github.com/Microsoft/testfx/docs/README.md". /// - public static StringAssert That { get; } = new StringAssert(); +#if NET6_0_OR_GREATER + [Obsolete(FrameworkConstants.ThatPropertyObsoleteMessage, DiagnosticId = "MSTESTOBS")] +#else + [Obsolete(FrameworkConstants.ThatPropertyObsoleteMessage)] +#endif + public static StringAssert That => Instance; #endregion @@ -657,4 +673,54 @@ public static void DoesNotMatch([NotNull] string? value, [NotNull] Regex? patter } #endregion Regular Expressions + + #region DoNotUse + + /// + /// Static equals overloads are used for comparing instances of two types for equality. + /// This method should not be used for comparison of two instances for equality. + /// Please use StringAssert methods or Assert.AreEqual and associated overloads in your unit tests. + /// + /// Object A. + /// Object B. + /// Never returns. + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "We want to compare 'object A' with 'object B', so it makes sense to have 'obj' in the parameter name")] + [Obsolete( + FrameworkConstants.DoNotUseStringAssertEquals, +#if DEBUG + error: false)] +#else + error: true)] +#endif + [DoesNotReturn] + public static new bool Equals(object? objA, object? objB) + { + Assert.Fail(FrameworkMessages.DoNotUseStringAssertEquals); + return false; + } + + /// + /// Static ReferenceEquals overloads are used for comparing instances of two types for reference + /// equality. This method should not be used for comparison of two instances for + /// reference equality. Please use StringAssert methods or Assert.AreSame and associated overloads in your unit tests. + /// + /// Object A. + /// Object B. + /// Never returns. + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "We want to compare 'object A' with 'object B', so it makes sense to have 'obj' in the parameter name")] + [Obsolete( + FrameworkConstants.DoNotUseStringAssertReferenceEquals, +#if DEBUG + error: false)] +#else + error: true)] +#endif + [DoesNotReturn] + public static new bool ReferenceEquals(object? objA, object? objB) + { + Assert.Fail(FrameworkMessages.DoNotUseStringAssertReferenceEquals); + return false; + } + + #endregion } diff --git a/src/TestFramework/TestFramework/Attributes/DataSource/DataTestMethodAttribute.cs b/src/TestFramework/TestFramework/Attributes/DataSource/DataTestMethodAttribute.cs index ed2e10f86f..d93c2161ee 100644 --- a/src/TestFramework/TestFramework/Attributes/DataSource/DataTestMethodAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/DataSource/DataTestMethodAttribute.cs @@ -13,7 +13,7 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; [EditorBrowsable(EditorBrowsableState.Never)] public class DataTestMethodAttribute : TestMethodAttribute { - private protected override bool UseAsync => true; + private protected override bool UseAsync => GetType() == typeof(DataTestMethodAttribute); /// /// Initializes a new instance of the class. diff --git a/src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataAttribute.cs b/src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataAttribute.cs index 900906b127..6768a2195b 100644 --- a/src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataAttribute.cs @@ -36,7 +36,7 @@ public sealed class DynamicDataAttribute : Attribute, ITestDataSource, ITestData { private readonly string _dynamicDataSourceName; private readonly DynamicDataSourceType _dynamicDataSourceType; - + private readonly object?[] _dynamicDataSourceArguments = []; private readonly Type? _dynamicDataDeclaringType; /// @@ -67,6 +67,22 @@ public DynamicDataAttribute(string dynamicDataSourceName) _dynamicDataSourceType = DynamicDataSourceType.AutoDetect; } + /// + /// Initializes a new instance of the class. + /// + /// + /// The name of method or property having test data. + /// + /// + /// Arguments to be passed to method referred to by . + /// + public DynamicDataAttribute(string dynamicDataSourceName, params object?[] dynamicDataSourceArguments) + { + _dynamicDataSourceName = dynamicDataSourceName; + _dynamicDataSourceType = DynamicDataSourceType.AutoDetect; + _dynamicDataSourceArguments = dynamicDataSourceArguments; + } + /// /// Initializes a new instance of the class when the test data is present in a class different /// from test method's class. @@ -99,6 +115,27 @@ public DynamicDataAttribute(string dynamicDataSourceName, Type dynamicDataDeclar public DynamicDataAttribute(string dynamicDataSourceName, Type dynamicDataDeclaringType) : this(dynamicDataSourceName) => _dynamicDataDeclaringType = dynamicDataDeclaringType; + /// + /// Initializes a new instance of the class when the test data is present in a class different + /// from test method's class. + /// + /// + /// The name of method or property having test data. + /// + /// + /// The declaring type of property or method having data. Useful in cases when declaring type is present in a class different from + /// test method's class. If null, declaring type defaults to test method's class type. + /// + /// + /// Arguments to be passed to method referred to by . + /// + public DynamicDataAttribute(string dynamicDataSourceName, Type dynamicDataDeclaringType, params object?[] dynamicDataSourceArguments) + : this(dynamicDataSourceName) + { + _dynamicDataDeclaringType = dynamicDataDeclaringType; + _dynamicDataSourceArguments = dynamicDataSourceArguments; + } + internal static TestIdGenerationStrategy TestIdGenerationStrategy { get; set; } /// @@ -121,7 +158,7 @@ public DynamicDataAttribute(string dynamicDataSourceName, Type dynamicDataDeclar /// public IEnumerable GetData(MethodInfo methodInfo) - => DynamicDataOperations.GetData(_dynamicDataDeclaringType, _dynamicDataSourceType, _dynamicDataSourceName, methodInfo); + => DynamicDataOperations.GetData(_dynamicDataDeclaringType, _dynamicDataSourceType, _dynamicDataSourceName, _dynamicDataSourceArguments, methodInfo); /// public string? GetDisplayName(MethodInfo methodInfo, object?[]? data) diff --git a/src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataOperations.cs b/src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataOperations.cs index 1c91754b59..8a654af412 100644 --- a/src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataOperations.cs +++ b/src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataOperations.cs @@ -7,45 +7,45 @@ internal static class DynamicDataOperations { private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; - public static IEnumerable GetData(Type? _dynamicDataDeclaringType, DynamicDataSourceType _dynamicDataSourceType, string _dynamicDataSourceName, MethodInfo methodInfo) + public static IEnumerable GetData(Type? dynamicDataDeclaringType, DynamicDataSourceType dynamicDataSourceType, string dynamicDataSourceName, object?[] dynamicDataSourceArguments, MethodInfo methodInfo) { // Check if the declaring type of test data is passed in. If not, default to test method's class type. - _dynamicDataDeclaringType ??= methodInfo.DeclaringType; - DebugEx.Assert(_dynamicDataDeclaringType is not null, "Declaring type of test data cannot be null."); + dynamicDataDeclaringType ??= methodInfo.DeclaringType; + DebugEx.Assert(dynamicDataDeclaringType is not null, "Declaring type of test data cannot be null."); object? obj = null; - switch (_dynamicDataSourceType) + switch (dynamicDataSourceType) { case DynamicDataSourceType.AutoDetect: #pragma warning disable IDE0045 // Convert to conditional expression - it becomes less readable. - if (GetPropertyConsideringInheritance(_dynamicDataDeclaringType, _dynamicDataSourceName) is { } dynamicDataPropertyInfo) + if (GetPropertyConsideringInheritance(dynamicDataDeclaringType, dynamicDataSourceName) is { } dynamicDataPropertyInfo) { obj = GetDataFromProperty(dynamicDataPropertyInfo); } - else if (GetMethodConsideringInheritance(_dynamicDataDeclaringType, _dynamicDataSourceName) is { } dynamicDataMethodInfo) + else if (GetMethodConsideringInheritance(dynamicDataDeclaringType, dynamicDataSourceName) is { } dynamicDataMethodInfo) { - obj = GetDataFromMethod(dynamicDataMethodInfo); + obj = GetDataFromMethod(dynamicDataMethodInfo, dynamicDataSourceArguments); } else { - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, FrameworkMessages.DynamicDataSourceShouldExistAndBeValid, _dynamicDataSourceName, _dynamicDataDeclaringType.FullName)); + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, FrameworkMessages.DynamicDataSourceShouldExistAndBeValid, dynamicDataSourceName, dynamicDataDeclaringType.FullName)); } #pragma warning restore IDE0045 // Convert to conditional expression break; case DynamicDataSourceType.Property: - PropertyInfo property = GetPropertyConsideringInheritance(_dynamicDataDeclaringType, _dynamicDataSourceName) - ?? throw new ArgumentNullException($"{DynamicDataSourceType.Property} {_dynamicDataSourceName}"); + PropertyInfo property = GetPropertyConsideringInheritance(dynamicDataDeclaringType, dynamicDataSourceName) + ?? throw new ArgumentNullException($"{DynamicDataSourceType.Property} {dynamicDataSourceName}"); obj = GetDataFromProperty(property); break; case DynamicDataSourceType.Method: - MethodInfo method = GetMethodConsideringInheritance(_dynamicDataDeclaringType, _dynamicDataSourceName) - ?? throw new ArgumentNullException($"{DynamicDataSourceType.Method} {_dynamicDataSourceName}"); + MethodInfo method = GetMethodConsideringInheritance(dynamicDataDeclaringType, dynamicDataSourceName) + ?? throw new ArgumentNullException($"{DynamicDataSourceType.Method} {dynamicDataSourceName}"); - obj = GetDataFromMethod(method); + obj = GetDataFromMethod(method, dynamicDataSourceArguments); break; } @@ -55,8 +55,8 @@ public static IEnumerable GetData(Type? _dynamicDataDeclaringType, Dyn string.Format( CultureInfo.InvariantCulture, FrameworkMessages.DynamicDataValueNull, - _dynamicDataSourceName, - _dynamicDataDeclaringType.FullName)); + dynamicDataSourceName, + dynamicDataDeclaringType.FullName)); } if (!TryGetData(obj, out IEnumerable? data)) @@ -65,29 +65,40 @@ public static IEnumerable GetData(Type? _dynamicDataDeclaringType, Dyn string.Format( CultureInfo.InvariantCulture, FrameworkMessages.DynamicDataIEnumerableNull, - _dynamicDataSourceName, - _dynamicDataDeclaringType.FullName)); + dynamicDataSourceName, + dynamicDataDeclaringType.FullName)); } // Data is valid, return it. return data; } - private static object? GetDataFromMethod(MethodInfo method) + private static object? GetDataFromMethod(MethodInfo method, object?[] arguments) { - if (!method.IsStatic - || method.ContainsGenericParameters - || method.GetParameters().Length > 0) + if (!method.IsStatic || method.ContainsGenericParameters) { throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, - FrameworkMessages.DynamicDataInvalidPropertyLayout, + FrameworkMessages.DynamicDataInvalidMethodLayout, method.DeclaringType?.FullName is { } typeFullName ? $"{typeFullName}.{method.Name}" : method.Name)); } - // Note: the method is static and takes no parameters. - return method.Invoke(null, null); + ParameterInfo[] methodParameters = method.GetParameters(); + ParameterInfo? lastParameter = methodParameters.Length > 0 ? methodParameters[methodParameters.Length - 1] : null; + if (lastParameter is not null && + (lastParameter.GetCustomAttribute() is not null || + lastParameter.GetCustomAttribute() is not null)) + { + throw new NotSupportedException( + string.Format( + CultureInfo.InvariantCulture, + FrameworkMessages.DynamicDataInvalidMethodLayout, + method.DeclaringType?.FullName is { } typeFullName ? $"{typeFullName}.{method.Name}" : method.Name)); + } + + // Note: the method is static. + return method.Invoke(null, arguments.Length == 0 ? null : arguments); } private static object? GetDataFromProperty(PropertyInfo property) @@ -115,16 +126,10 @@ private static bool TryGetData(object dataSource, [NotNullWhen(true)] out IEnume if (dataSource is IEnumerable enumerable and not string) { - List objects = new(); + List objects = []; foreach (object? entry in enumerable) { - if (entry is null) - { - data = null; - return false; - } - - objects.Add(new[] { entry }); + objects.Add([entry!]); } data = objects; diff --git a/src/TestFramework/TestFramework/Attributes/Lifecycle/Cleanup/GlobalTestCleanupAttribute.cs b/src/TestFramework/TestFramework/Attributes/Lifecycle/Cleanup/GlobalTestCleanupAttribute.cs new file mode 100644 index 0000000000..fcb06aad7b --- /dev/null +++ b/src/TestFramework/TestFramework/Attributes/Lifecycle/Cleanup/GlobalTestCleanupAttribute.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +/// +/// A global test cleanup attribute that applies to every test method in the assembly. +/// The method to which this attribute is applied must be public, static, non-generic, has a single parameter of type TestContext, and either returns void or a Task. +/// +/// +/// Multiple methods with this attribute in the assembly is allowed, but there is no guarantee of the order in which they will be executed. +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +public sealed class GlobalTestCleanupAttribute : Attribute; diff --git a/src/TestFramework/TestFramework/Attributes/Lifecycle/Initialization/GlobalTestInitializeAttribute.cs b/src/TestFramework/TestFramework/Attributes/Lifecycle/Initialization/GlobalTestInitializeAttribute.cs new file mode 100644 index 0000000000..ae7b0be236 --- /dev/null +++ b/src/TestFramework/TestFramework/Attributes/Lifecycle/Initialization/GlobalTestInitializeAttribute.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +/// +/// A global test initialize attribute that applies to every test method in the assembly. +/// The method to which this attribute is applied must be public, static, non-generic, has a single parameter of type TestContext, and either returns void or a Task. +/// +/// +/// Multiple methods with this attribute in the assembly is allowed, but there is no guarantee of the order in which they will be executed. In addition, TimeoutAttribute isn't supported on methods with this attribute. +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +public sealed class GlobalTestInitializeAttribute : Attribute; diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/CIConditionAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/CIConditionAttribute.cs new file mode 100644 index 0000000000..e4ae082e85 --- /dev/null +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/CIConditionAttribute.cs @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +/// +/// This attribute is used to conditionally control whether a test class or a test method will run or be ignored based on whether the test is running in a CI environment. +/// +/// +/// This attribute isn't inherited. Applying it to a base class will not affect derived classes. +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = false)] +public sealed class CIConditionAttribute : ConditionBaseAttribute +{ + private readonly IEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// Decides whether the test should be included or excluded in CI environments. + public CIConditionAttribute(ConditionMode mode) + : this(mode, new EnvironmentWrapper()) + { + } + + internal CIConditionAttribute(ConditionMode mode, IEnvironment environment) + : base(mode) + { + _environment = environment; + IgnoreMessage = mode == ConditionMode.Include + ? "Test is only supported in CI environments" + : "Test is not supported in CI environments"; + } + + /// + /// Gets a value indicating whether the test method or test class should run. + /// + public override bool ShouldRun => IsCIEnvironment(); + + /// + public override string? IgnoreMessage { get; set; } + + /// + /// Gets the group name for this attribute. + /// + public override string GroupName => nameof(CIConditionAttribute); + + // CI Detection logic based on https://learn.microsoft.com/dotnet/core/tools/telemetry#continuous-integration-detection + // From: https://github.com/dotnet/sdk/blob/main/src/Cli/dotnet/Telemetry/CIEnvironmentDetectorForTelemetry.cs + private bool IsCIEnvironment() + { + // Systems that provide boolean values only, so we can simply parse and check for true + string[] booleanVariables = + [ + // Azure Pipelines - https://docs.microsoft.com/azure/devops/pipelines/build/variables#system-variables-devops-services + "TF_BUILD", + + // GitHub Actions - https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables + "GITHUB_ACTIONS", + + // AppVeyor - https://www.appveyor.com/docs/environment-variables/ + "APPVEYOR", + + // A general-use flag - Many of the major players support this: AzDo, GitHub, GitLab, AppVeyor, Travis CI, CircleCI. + "CI", + + // Travis CI - https://docs.travis-ci.com/user/environment-variables/#default-environment-variables + "TRAVIS", + + // CircleCI - https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables + "CIRCLECI" + ]; + + // Systems where every variable must be present and not-null before returning true + string[][] allNotNullVariables = + [ + // AWS CodeBuild - https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html + ["CODEBUILD_BUILD_ID", "AWS_REGION"], + + // Jenkins - https://github.com/jenkinsci/jenkins/blob/master/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.groovy + ["BUILD_ID", "BUILD_URL"], + + // Google Cloud Build - https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values#using_default_substitutions + ["BUILD_ID", "PROJECT_ID"], + ]; + + // Systems where the variable must be present and not-null + string[] ifNonNullVariables = + [ + // TeamCity - https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters + "TEAMCITY_VERSION", + + // JetBrains Space - https://www.jetbrains.com/help/space/automation-environment-variables.html#general + "JB_SPACE_API_URL" + ]; + + foreach (string booleanVariable in booleanVariables) + { + if (bool.TryParse(_environment.GetEnvironmentVariable(booleanVariable), out bool envVar) && envVar) + { + return true; + } + } + + foreach (string[] variables in allNotNullVariables) + { + bool allVariablesPresent = true; + foreach (string variable in variables) + { + if (string.IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) + { + allVariablesPresent = false; + break; + } + } + + if (allVariablesPresent) + { + return true; + } + } + + foreach (string variable in ifNonNullVariables) + { + if (!string.IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) + { + return true; + } + } + + return false; + } +} diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/ConditionBaseAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/ConditionBaseAttribute.cs index 7a5d8168fd..ed94a814d3 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/ConditionBaseAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/ConditionBaseAttribute.cs @@ -19,13 +19,16 @@ public abstract class ConditionBaseAttribute : Attribute protected ConditionBaseAttribute(ConditionMode mode) => Mode = mode; - internal ConditionMode Mode { get; } + /// + /// Gets the condition mode. + /// + public ConditionMode Mode { get; } /// - /// Gets the ignore message (in case returns ) indicating + /// Gets or sets the ignore message (in case returns ) indicating /// the reason for ignoring the test method or test class. /// - public abstract string? IgnoreMessage { get; } + public virtual string? IgnoreMessage { get; set; } /// /// Gets the group name for this attribute. This is relevant when multiple diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/CssIterationAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/CssIterationAttribute.cs index a1c070d4a1..54f0a0d610 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/CssIterationAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/CssIterationAttribute.cs @@ -7,6 +7,11 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; /// CSS Iteration URI. /// [AttributeUsage(AttributeTargets.Method)] +#if NET6_0_OR_GREATER +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +#else +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] +#endif public sealed class CssIterationAttribute : Attribute { /// diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/CssProjectStructureAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/CssProjectStructureAttribute.cs index eb3a354b45..e88074fde4 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/CssProjectStructureAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/CssProjectStructureAttribute.cs @@ -7,6 +7,11 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; /// CSS Project Structure URI. /// [AttributeUsage(AttributeTargets.Method)] +#if NET6_0_OR_GREATER +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +#else +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] +#endif public sealed class CssProjectStructureAttribute : Attribute { /// diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/DescriptionAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/DescriptionAttribute.cs index 7917128c42..60fa6e5efb 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/DescriptionAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/DescriptionAttribute.cs @@ -7,16 +7,19 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; /// Description of the test. /// [AttributeUsage(AttributeTargets.Method)] -public sealed class DescriptionAttribute : Attribute +public sealed class DescriptionAttribute : TestPropertyAttribute { /// /// Initializes a new instance of the class to describe a test. /// /// The description. - public DescriptionAttribute(string? description) => Description = description; + public DescriptionAttribute(string? description) + : base("Description", description ?? string.Empty) + { + } /// /// Gets the description of a test. /// - public string? Description { get; } + public string? Description => Value; } diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/IgnoreAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/IgnoreAttribute.cs index bab35c458d..122ae1fccf 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/IgnoreAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/IgnoreAttribute.cs @@ -30,10 +30,8 @@ public IgnoreAttribute(string? message) : base(ConditionMode.Include) => IgnoreMessage = message; - /// - /// Gets the ignore message indicating the reason for ignoring the test method or test class. - /// - public override string? IgnoreMessage { get; } + /// + public override string? IgnoreMessage { get; set; } /// public override bool ShouldRun => false; diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/OSConditionAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/OSConditionAttribute.cs index 49906ede5d..63a8e6db00 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/OSConditionAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/OSConditionAttribute.cs @@ -32,7 +32,9 @@ public OSConditionAttribute(ConditionMode mode, OperatingSystems operatingSystem : base(mode) { _operatingSystems = operatingSystems; - IgnoreMessage = $"Test is only supported on {operatingSystems}"; + IgnoreMessage = mode == ConditionMode.Include + ? $"Test is only supported on {operatingSystems}" + : $"Test is not supported on {operatingSystems}"; } /// @@ -77,10 +79,8 @@ public override bool ShouldRun } #endif - /// - /// Gets the ignore message (in case returns ). - /// - public override string? IgnoreMessage { get; } + /// + public override string? IgnoreMessage { get; set; } /// /// Gets the group name for this attribute. diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/OwnerAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/OwnerAttribute.cs index 5f33b2ed23..72526ac379 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/OwnerAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/OwnerAttribute.cs @@ -7,7 +7,7 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; /// Test Owner. /// [AttributeUsage(AttributeTargets.Method)] -public sealed class OwnerAttribute : Attribute +public sealed class OwnerAttribute : TestPropertyAttribute { /// /// Initializes a new instance of the class. @@ -15,10 +15,13 @@ public sealed class OwnerAttribute : Attribute /// /// The owner. /// - public OwnerAttribute(string? owner) => Owner = owner; + public OwnerAttribute(string? owner) + : base("Owner", owner ?? string.Empty) + { + } /// /// Gets the owner. /// - public string? Owner { get; } + public string? Owner => Value; } diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/PriorityAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/PriorityAttribute.cs index eaf0ae7532..ab0da4cddf 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/PriorityAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/PriorityAttribute.cs @@ -7,7 +7,7 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; /// Priority attribute; used to specify the priority of a unit test. /// [AttributeUsage(AttributeTargets.Method)] -public sealed class PriorityAttribute : Attribute +public sealed class PriorityAttribute : TestPropertyAttribute { /// /// Initializes a new instance of the class. @@ -15,7 +15,8 @@ public sealed class PriorityAttribute : Attribute /// /// The priority. /// - public PriorityAttribute(int priority) => Priority = priority; + public PriorityAttribute(int priority) + : base("Priority", priority.ToString(CultureInfo.InvariantCulture)) => Priority = priority; /// /// Gets the priority. diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/RetryAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/RetryAttribute.cs index 0ee55befc5..811a7b0e37 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/RetryAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/RetryAttribute.cs @@ -15,10 +15,12 @@ public sealed class RetryAttribute : RetryBaseAttribute /// The maximum number of retry attempts. This must be greater than or equal to 1. public RetryAttribute(int maxRetryAttempts) { +#pragma warning disable CA1512 // Use ArgumentOutOfRangeException throw helper if (maxRetryAttempts < 1) { throw new ArgumentOutOfRangeException(nameof(maxRetryAttempts)); } +#pragma warning disable CA1512 // Use ArgumentOutOfRangeException throw helper MaxRetryAttempts = maxRetryAttempts; } @@ -71,13 +73,13 @@ protected internal override async Task ExecuteAsync(RetryContext re for (int i = 0; i < MaxRetryAttempts; i++) { // The caller already executed the test once. So we need to do the delay here. - await Task.Delay(currentDelay); + await Task.Delay(currentDelay).ConfigureAwait(false); if (BackoffType == DelayBackoffType.Exponential) { currentDelay *= 2; } - TestResult[] testResults = await retryContext.ExecuteTaskGetter(); + TestResult[] testResults = await retryContext.ExecuteTaskGetter().ConfigureAwait(false); result.AddResult(testResults); if (IsAcceptableResultForRetry(testResults)) { diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/RetryResult.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/RetryResult.cs index 60dc976cf9..855893fc95 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/RetryResult.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/RetryResult.cs @@ -9,7 +9,7 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; [Experimental("MSTESTEXP", UrlFormat = "https://aka.ms/mstest/diagnostics#{0}")] public sealed class RetryResult { - private readonly List _testResults = new(); + private readonly List _testResults = []; /// /// Adds a set of test results to the retry result. diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/STATestMethodAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/STATestMethodAttribute.cs index a0cecc24aa..3f317a3eac 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/STATestMethodAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/STATestMethodAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; [AttributeUsage(AttributeTargets.Method)] public class STATestMethodAttribute : TestMethodAttribute { - private protected override bool UseAsync => true; + private protected override bool UseAsync => GetType() == typeof(STATestMethodAttribute); /// /// Initializes a new instance of the class. diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/TestMethodAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/TestMethodAttribute.cs index 75f7455b3b..aa76cac719 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/TestMethodAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/TestMethodAttribute.cs @@ -67,9 +67,8 @@ public TestMethodAttribute(string? displayName) /// The test method to execute. /// An array of TestResult objects that represent the outcome(s) of the test. /// Extensions can override this method to customize running a TestMethod. - // TODO: Double check whether this breaks async local propagation between test init, test, test cleanup internal virtual async Task ExecuteAsync(ITestMethod testMethod) => UseAsync - ? [await testMethod.InvokeAsync(null)] + ? [await testMethod.InvokeAsync(null).ConfigureAwait(false)] : Execute(testMethod); } diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/TestTimeout.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/TestTimeout.cs index 3c5aab0c09..629d58628c 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/TestTimeout.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/TestTimeout.cs @@ -8,6 +8,11 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; /// The type of the enumeration must match. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "Compat reasons")] +#if NET6_0_OR_GREATER +[Obsolete(FrameworkConstants.TestTimeoutAttributeObsoleteMessage, error: false, DiagnosticId = "MSTESTOBS")] +#else +[Obsolete(FrameworkConstants.TestTimeoutAttributeObsoleteMessage, error: false)] +#endif public enum TestTimeout { /// diff --git a/src/TestFramework/TestFramework/Attributes/TestMethod/TimeoutAttribute.cs b/src/TestFramework/TestFramework/Attributes/TestMethod/TimeoutAttribute.cs index b57e1941b2..a23a6ba47e 100644 --- a/src/TestFramework/TestFramework/Attributes/TestMethod/TimeoutAttribute.cs +++ b/src/TestFramework/TestFramework/Attributes/TestMethod/TimeoutAttribute.cs @@ -23,6 +23,11 @@ public sealed class TimeoutAttribute : Attribute /// /// The timeout. /// +#if NET6_0_OR_GREATER + [Obsolete(FrameworkConstants.TestTimeoutAttributeObsoleteMessage, error: false, DiagnosticId = "MSTESTOBS")] +#else + [Obsolete(FrameworkConstants.TestTimeoutAttributeObsoleteMessage, error: false)] +#endif public TimeoutAttribute(TestTimeout timeout) => Timeout = (int)timeout; /// diff --git a/src/TestFramework/TestFramework/Constants.cs b/src/TestFramework/TestFramework/Constants.cs deleted file mode 100644 index 6973e5008c..0000000000 --- a/src/TestFramework/TestFramework/Constants.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestTools.UnitTesting; - -/// -/// Constants used throughout. -/// -internal static class Constants -{ - internal const string PublicTypeObsoleteMessage = "We will remove or hide this type starting with v4. If you are using this type, reach out to our team on https://github.com/microsoft/testfx."; -} diff --git a/src/TestFramework/TestFramework/Exceptions/AssertFailedException.cs b/src/TestFramework/TestFramework/Exceptions/AssertFailedException.cs index bff933dbd6..2bbd14c132 100644 --- a/src/TestFramework/TestFramework/Exceptions/AssertFailedException.cs +++ b/src/TestFramework/TestFramework/Exceptions/AssertFailedException.cs @@ -45,7 +45,7 @@ public AssertFailedException() /// Serialization info. /// Streaming context. #if NET8_0_OR_GREATER - [Obsolete(DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] #endif [EditorBrowsable(EditorBrowsableState.Never)] protected AssertFailedException(SerializationInfo info, StreamingContext context) diff --git a/src/TestFramework/TestFramework/Exceptions/AssertInconclusiveException.cs b/src/TestFramework/TestFramework/Exceptions/AssertInconclusiveException.cs index b6734d5e38..277ce83509 100644 --- a/src/TestFramework/TestFramework/Exceptions/AssertInconclusiveException.cs +++ b/src/TestFramework/TestFramework/Exceptions/AssertInconclusiveException.cs @@ -45,7 +45,7 @@ public AssertInconclusiveException() /// Serialization info. /// Streaming context. #if NET8_0_OR_GREATER - [Obsolete(DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] #endif [EditorBrowsable(EditorBrowsableState.Never)] protected AssertInconclusiveException(SerializationInfo info, StreamingContext context) diff --git a/src/TestFramework/TestFramework/Exceptions/InternalTestFailureException.cs b/src/TestFramework/TestFramework/Exceptions/InternalTestFailureException.cs index 78f3de327f..519eb8b651 100644 --- a/src/TestFramework/TestFramework/Exceptions/InternalTestFailureException.cs +++ b/src/TestFramework/TestFramework/Exceptions/InternalTestFailureException.cs @@ -14,9 +14,9 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; /// For all practical purposes either use AssertFailedException/AssertInconclusiveException. /// #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif [Serializable] public class InternalTestFailureException : UnitTestAssertException @@ -54,7 +54,7 @@ public InternalTestFailureException() /// Serialization info. /// Streaming context. #if NET8_0_OR_GREATER - [Obsolete(DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] #endif [EditorBrowsable(EditorBrowsableState.Never)] protected InternalTestFailureException(SerializationInfo info, StreamingContext context) diff --git a/src/TestFramework/TestFramework/Exceptions/UnitTestAssertException.cs b/src/TestFramework/TestFramework/Exceptions/UnitTestAssertException.cs index 37e2a86510..85978e9597 100644 --- a/src/TestFramework/TestFramework/Exceptions/UnitTestAssertException.cs +++ b/src/TestFramework/TestFramework/Exceptions/UnitTestAssertException.cs @@ -44,7 +44,7 @@ protected UnitTestAssertException(string msg) /// Serialization info. /// Streaming context. #if NET8_0_OR_GREATER - [Obsolete(DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] #endif [EditorBrowsable(EditorBrowsableState.Never)] protected UnitTestAssertException(SerializationInfo info, StreamingContext context) diff --git a/src/TestFramework/TestFramework/FrameworkConstants.cs b/src/TestFramework/TestFramework/FrameworkConstants.cs new file mode 100644 index 0000000000..f0bc8da76e --- /dev/null +++ b/src/TestFramework/TestFramework/FrameworkConstants.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +/// +/// Constants used throughout. +/// +internal static class FrameworkConstants +{ + internal const string PublicTypeObsoleteMessage = "We will remove or hide this type starting with v4. If you are using this type, reach out to our team on https://github.com/microsoft/testfx."; + internal const string ThatPropertyObsoleteMessage = "The 'That' property is obsolete and will be removed in a future version. Use the 'Instance' property instead."; + internal const string DoNotUseAssertEquals = "Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead."; + internal const string DoNotUseAssertReferenceEquals = "Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead."; + internal const string DoNotUseStringAssertEquals = "StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead."; + internal const string DoNotUseStringAssertReferenceEquals = "StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead."; + internal const string DoNotUseCollectionAssertEquals = "CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead."; + internal const string DoNotUseCollectionAssertReferenceEquals = "CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead."; + internal const string TestTimeoutAttributeObsoleteMessage = "The 'TestTimeout' attribute is obsolete and will be removed in v4. Consider removing the 'Timeout' attribute or use the 'Timeout' attribute with the 'int.MaxValue' for infinite timeout."; +} diff --git a/src/TestFramework/TestFramework/Friends.cs b/src/TestFramework/TestFramework/Friends.cs deleted file mode 100644 index ebbc3313b8..0000000000 --- a/src/TestFramework/TestFramework/Friends.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] -[assembly: InternalsVisibleTo("MSTest.TestAnywhereAdapter, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] diff --git a/src/TestFramework/TestFramework/GenericParameterHelper.cs b/src/TestFramework/TestFramework/GenericParameterHelper.cs index 2012f7c748..238cbe201d 100644 --- a/src/TestFramework/TestFramework/GenericParameterHelper.cs +++ b/src/TestFramework/TestFramework/GenericParameterHelper.cs @@ -16,9 +16,9 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; [SuppressMessage("Microsoft.Design", "CA1036:OverrideMethodsOnComparableTypes", Justification = "Compat reasons.")] [SuppressMessage("Design", "CA1010:Generic interface should also be implemented", Justification = "Part of the public API")] #if NET6_0_OR_GREATER -[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")] #else -[Obsolete(Constants.PublicTypeObsoleteMessage)] +[Obsolete(FrameworkConstants.PublicTypeObsoleteMessage)] #endif // GenericParameterHelper in full CLR version also implements ICloneable, but we don't have ICloneable in core CLR public class GenericParameterHelper : IComparable, IEnumerable diff --git a/src/TestFramework/TestFramework/ITestDataRow.cs b/src/TestFramework/TestFramework/ITestDataRow.cs index 2150fa1c96..ed8ea6c612 100644 --- a/src/TestFramework/TestFramework/ITestDataRow.cs +++ b/src/TestFramework/TestFramework/ITestDataRow.cs @@ -10,4 +10,6 @@ internal interface ITestDataRow string? IgnoreMessage { get; } string? DisplayName { get; } + + IList? TestCategories { get; } } diff --git a/src/TestFramework/TestFramework/Internal/DebugEx.cs b/src/TestFramework/TestFramework/Internal/DebugEx.cs index 77b9d8fd02..9fdce6f146 100644 --- a/src/TestFramework/TestFramework/Internal/DebugEx.cs +++ b/src/TestFramework/TestFramework/Internal/DebugEx.cs @@ -17,7 +17,9 @@ public static void Assert([DoesNotReturnIf(false)] bool b, string message) // ends up causing the job to timeout. We use FailFast instead. // FailFast is better than throwing an exception to avoid anyone // catching an exception and masking an assert failure. +#pragma warning disable CA2201 // Do not raise reserved exception types var ex = new Exception($"Debug.Assert failed: {message}"); +#pragma warning restore CA2201 // Do not raise reserved exception types Environment.FailFast(ex.Message, ex); } } diff --git a/src/TestFramework/TestFramework/Internal/IEnvironment.cs b/src/TestFramework/TestFramework/Internal/IEnvironment.cs new file mode 100644 index 0000000000..6624207d3e --- /dev/null +++ b/src/TestFramework/TestFramework/Internal/IEnvironment.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +/// +/// Interface to abstract environment related information. +/// +internal interface IEnvironment +{ + /// + /// Gets the machine name. + /// + string MachineName { get; } + + /// + void SetEnvironmentVariable(string variable, string? value); + + /// + string? GetEnvironmentVariable(string name); +} + +internal sealed class EnvironmentWrapper : IEnvironment +{ + public string MachineName => Environment.MachineName; + + public string? GetEnvironmentVariable(string name) => Environment.GetEnvironmentVariable(name); + + public void SetEnvironmentVariable(string variable, string? value) => Environment.SetEnvironmentVariable(variable, value); +} diff --git a/src/TestFramework/TestFramework/Internal/TestDataSourceUtilities.cs b/src/TestFramework/TestFramework/Internal/TestDataSourceUtilities.cs index 525f25fda2..d594f38ad4 100644 --- a/src/TestFramework/TestFramework/Internal/TestDataSourceUtilities.cs +++ b/src/TestFramework/TestFramework/Internal/TestDataSourceUtilities.cs @@ -29,7 +29,7 @@ internal static class TestDataSourceUtilities CultureInfo.CurrentCulture, FrameworkMessages.DataDrivenResultDisplayName, methodDisplayName, - string.Join(",", displayData.Select(x => GetHumanizedArguments(x, testIdGenerationStrategy)))); + string.Join(',', displayData.Select(x => GetHumanizedArguments(x, testIdGenerationStrategy)))); } /// @@ -65,6 +65,6 @@ internal static class TestDataSourceUtilities // We need to box the object here so that we can support value types IEnumerable boxedObjectEnumerable = ((IEnumerable)data).Cast(); IEnumerable elementStrings = boxedObjectEnumerable.Select(x => GetHumanizedArguments(x, testIdGenerationStrategy)); - return $"[{string.Join(",", elementStrings)}]"; + return $"[{string.Join(',', elementStrings)}]"; } } diff --git a/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Shipped.txt b/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Shipped.txt index 12691b823c..e05ec781bb 100644 --- a/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Shipped.txt +++ b/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Shipped.txt @@ -2,6 +2,7 @@ [MSTESTEXP]abstract Microsoft.VisualStudio.TestTools.UnitTesting.RetryBaseAttribute.ExecuteAsync(Microsoft.VisualStudio.TestTools.UnitTesting.RetryContext retryContext) -> System.Threading.Tasks.Task! [MSTESTEXP]Microsoft.VisualStudio.TestTools.UnitTesting.RetryContext [MSTESTEXP]Microsoft.VisualStudio.TestTools.UnitTesting.RetryContext.ExecuteTaskGetter.get -> System.Func!>! +[MSTESTEXP]Microsoft.VisualStudio.TestTools.UnitTesting.RetryContext.FirstRunResults.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestResult![]! [MSTESTEXP]Microsoft.VisualStudio.TestTools.UnitTesting.RetryContext.RetryContext() -> void [MSTESTEXP]Microsoft.VisualStudio.TestTools.UnitTesting.RetryResult [MSTESTEXP]Microsoft.VisualStudio.TestTools.UnitTesting.RetryResult.AddResult(Microsoft.VisualStudio.TestTools.UnitTesting.TestResult![]! testResults) -> void @@ -243,10 +244,12 @@ Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException.AssertFailedException() -> void Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException.AssertFailedException(string! msg, System.Exception! ex) -> void Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException.AssertFailedException(string! msg) -> void +Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException.AssertFailedException(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException.AssertInconclusiveException() -> void Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException.AssertInconclusiveException(string! msg, System.Exception! ex) -> void Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException.AssertInconclusiveException(string! msg) -> void +Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException.AssertInconclusiveException(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupAttribute Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupAttribute.ClassCleanupAttribute() -> void Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupAttribute.ClassCleanupAttribute(Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupBehavior cleanupBehavior) -> void @@ -369,6 +372,7 @@ Microsoft.VisualStudio.TestTools.UnitTesting.InternalTestFailureException Microsoft.VisualStudio.TestTools.UnitTesting.InternalTestFailureException.InternalTestFailureException() -> void Microsoft.VisualStudio.TestTools.UnitTesting.InternalTestFailureException.InternalTestFailureException(string! msg, System.Exception! ex) -> void Microsoft.VisualStudio.TestTools.UnitTesting.InternalTestFailureException.InternalTestFailureException(string! msg) -> void +Microsoft.VisualStudio.TestTools.UnitTesting.InternalTestFailureException.InternalTestFailureException(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void Microsoft.VisualStudio.TestTools.UnitTesting.ITestDataSource Microsoft.VisualStudio.TestTools.UnitTesting.ITestDataSource.GetData(System.Reflection.MethodInfo! methodInfo) -> System.Collections.Generic.IEnumerable! Microsoft.VisualStudio.TestTools.UnitTesting.ITestDataSource.GetDisplayName(System.Reflection.MethodInfo! methodInfo, object?[]? data) -> string? @@ -382,6 +386,7 @@ Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod.Arguments.get -> object Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod.GetAllAttributes(bool inherit) -> System.Attribute![]? Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod.GetAttributes(bool inherit) -> TAttributeType![]! Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod.Invoke(object![]? arguments) -> Microsoft.VisualStudio.TestTools.UnitTesting.TestResult! +Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod.InvokeAsync(object![]? arguments) -> System.Threading.Tasks.Task! Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod.MethodInfo.get -> System.Reflection.MethodInfo! Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod.ParameterTypes.get -> System.Reflection.ParameterInfo![]! Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod.ReturnType.get -> System.Type! @@ -512,6 +517,7 @@ Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestAssertException Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestAssertException.UnitTestAssertException() -> void Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestAssertException.UnitTestAssertException(string! msg, System.Exception! ex) -> void Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestAssertException.UnitTestAssertException(string! msg) -> void +Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestAssertException.UnitTestAssertException(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome.Aborted = 6 -> Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome.Error = 4 -> Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome @@ -618,7 +624,6 @@ static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(string! subs static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(string! substring, string! value, System.StringComparison comparisonType, string? message) -> void static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(string! substring, string! value, System.StringComparison comparisonType) -> void static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(string! substring, string! value) -> void -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(System.Collections.Generic.IEnumerable! collection, System.Func! predicate, string? message) -> void static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(System.Func! predicate, System.Collections.Generic.IEnumerable! collection, string? message, params object?[]? parameters) -> void static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(System.Func! predicate, System.Collections.Generic.IEnumerable! collection) -> void static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(T expected, System.Collections.Generic.IEnumerable! collection, string? message, params object?[]? parameters) -> void @@ -714,11 +719,15 @@ static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.That.get -> Microsoft static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Throws(System.Action! action, ref Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AssertNonStrictThrowsInterpolatedStringHandler message) -> TException! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Throws(System.Action! action, string! message = "", params object![]! messageArgs) -> TException! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Throws(System.Action! action, System.Func! messageBuilder) -> TException! +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Throws(System.Func! action, string! message = "", params object![]! messageArgs) -> TException! +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Throws(System.Func! action, System.Func! messageBuilder) -> TException! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsAsync(System.Func! action, string! message = "", params object![]! messageArgs) -> System.Threading.Tasks.Task! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsAsync(System.Func! action, System.Func! messageBuilder) -> System.Threading.Tasks.Task! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactly(System.Action! action, ref Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AssertThrowsExactlyInterpolatedStringHandler message) -> TException! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactly(System.Action! action, string! message = "", params object![]! messageArgs) -> TException! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactly(System.Action! action, System.Func! messageBuilder) -> TException! +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactly(System.Func! action, string! message = "", params object![]! messageArgs) -> TException! +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactly(System.Func! action, System.Func! messageBuilder) -> TException! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactlyAsync(System.Func! action, string! message = "", params object![]! messageArgs) -> System.Threading.Tasks.Task! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactlyAsync(System.Func! action, System.Func! messageBuilder) -> System.Threading.Tasks.Task! static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsException(System.Action! action, string! message, params object?[]? parameters) -> T! diff --git a/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt b/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt index 284951033c..abe780feb5 100644 --- a/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt @@ -1,11 +1,55 @@ #nullable enable -Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException.AssertFailedException(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void -Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException.AssertInconclusiveException(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void -Microsoft.VisualStudio.TestTools.UnitTesting.InternalTestFailureException.InternalTestFailureException(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void -Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod.InvokeAsync(object![]? arguments) -> System.Threading.Tasks.Task! -Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestAssertException.UnitTestAssertException(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Throws(System.Func! action, string! message = "", params object![]! messageArgs) -> TException! -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Throws(System.Func! action, System.Func! messageBuilder) -> TException! -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactly(System.Func! action, string! message = "", params object![]! messageArgs) -> TException! -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactly(System.Func! action, System.Func! messageBuilder) -> TException! -[MSTESTEXP]Microsoft.VisualStudio.TestTools.UnitTesting.RetryContext.FirstRunResults.get -> Microsoft.VisualStudio.TestTools.UnitTesting.TestResult![]! +Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AssertNonStrictThrowsInterpolatedStringHandler.AssertNonStrictThrowsInterpolatedStringHandler(int literalLength, int formattedCount, System.Func! action, out bool shouldAppend) -> void +Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AssertThrowsExactlyInterpolatedStringHandler.AssertThrowsExactlyInterpolatedStringHandler(int literalLength, int formattedCount, System.Func! action, out bool shouldAppend) -> void +Microsoft.VisualStudio.TestTools.UnitTesting.CIConditionAttribute +Microsoft.VisualStudio.TestTools.UnitTesting.CIConditionAttribute.CIConditionAttribute(Microsoft.VisualStudio.TestTools.UnitTesting.ConditionMode mode) -> void +Microsoft.VisualStudio.TestTools.UnitTesting.ConditionBaseAttribute.Mode.get -> Microsoft.VisualStudio.TestTools.UnitTesting.ConditionMode +Microsoft.VisualStudio.TestTools.UnitTesting.GlobalTestCleanupAttribute +Microsoft.VisualStudio.TestTools.UnitTesting.GlobalTestCleanupAttribute.GlobalTestCleanupAttribute() -> void +Microsoft.VisualStudio.TestTools.UnitTesting.GlobalTestInitializeAttribute +Microsoft.VisualStudio.TestTools.UnitTesting.GlobalTestInitializeAttribute.GlobalTestInitializeAttribute() -> void +override Microsoft.VisualStudio.TestTools.UnitTesting.CIConditionAttribute.GroupName.get -> string! +override Microsoft.VisualStudio.TestTools.UnitTesting.CIConditionAttribute.IgnoreMessage.get -> string? +override Microsoft.VisualStudio.TestTools.UnitTesting.CIConditionAttribute.IgnoreMessage.set -> void +override Microsoft.VisualStudio.TestTools.UnitTesting.CIConditionAttribute.ShouldRun.get -> bool +Microsoft.VisualStudio.TestTools.UnitTesting.DynamicDataAttribute.DynamicDataAttribute(string! dynamicDataSourceName, params object?[]! dynamicDataSourceArguments) -> void +Microsoft.VisualStudio.TestTools.UnitTesting.DynamicDataAttribute.DynamicDataAttribute(string! dynamicDataSourceName, System.Type! dynamicDataDeclaringType, params object?[]! dynamicDataSourceArguments) -> void +Microsoft.VisualStudio.TestTools.UnitTesting.TestDataRow.TestCategories.get -> System.Collections.Generic.IList? +Microsoft.VisualStudio.TestTools.UnitTesting.TestDataRow.TestCategories.set -> void +override Microsoft.VisualStudio.TestTools.UnitTesting.IgnoreAttribute.IgnoreMessage.set -> void +override Microsoft.VisualStudio.TestTools.UnitTesting.OSConditionAttribute.IgnoreMessage.set -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ContainsSingle(System.Func! predicate, System.Collections.Generic.IEnumerable! collection, string! message = "") -> T +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.DoesNotEndWith(string? substring, string? value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.DoesNotEndWith(string? substring, string? value, System.StringComparison comparisonType, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.DoesNotMatchRegex(string? pattern, string? value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.DoesNotMatchRegex(System.Text.RegularExpressions.Regex? pattern, string? value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.DoesNotStartWith(string? substring, string? value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.DoesNotStartWith(string? substring, string? value, System.StringComparison comparisonType, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.EndsWith(string? substring, string? value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.EndsWith(string? substring, string? value, System.StringComparison comparisonType, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsGreaterThan(T lowerBound, T value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsGreaterThanOrEqualTo(T lowerBound, T value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Instance.get -> Microsoft.VisualStudio.TestTools.UnitTesting.Assert! +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(System.Func! predicate, System.Collections.Generic.IEnumerable! collection, string? message) -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsInRange(T minValue, T maxValue, T value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsLessThan(T upperBound, T value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsLessThanOrEqualTo(T upperBound, T value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsNegative(T value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsPositive(T value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.MatchesRegex(string? pattern, string? value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.MatchesRegex(System.Text.RegularExpressions.Regex? pattern, string? value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.StartsWith(string? substring, string? value, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.StartsWith(string? substring, string? value, System.StringComparison comparisonType, string! message = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Throws(System.Func! action, ref Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AssertNonStrictThrowsInterpolatedStringHandler message) -> TException! +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsExactly(System.Func! action, ref Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AssertThrowsExactlyInterpolatedStringHandler message) -> TException! +static Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert.Instance.get -> Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert! +static Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert.Instance.get -> Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert! +*REMOVED*static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Contains(System.Collections.Generic.IEnumerable! collection, System.Func! predicate, string? message) -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ReferenceEquals(object? objA, object? objB) -> bool +static Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert.Equals(object? objA, object? objB) -> bool +static Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert.ReferenceEquals(object? objA, object? objB) -> bool +static Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert.Equals(object? objA, object? objB) -> bool +static Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert.ReferenceEquals(object? objA, object? objB) -> bool +*REMOVED*abstract Microsoft.VisualStudio.TestTools.UnitTesting.ConditionBaseAttribute.IgnoreMessage.get -> string? +virtual Microsoft.VisualStudio.TestTools.UnitTesting.ConditionBaseAttribute.IgnoreMessage.get -> string? +virtual Microsoft.VisualStudio.TestTools.UnitTesting.ConditionBaseAttribute.IgnoreMessage.set -> void diff --git a/src/TestFramework/TestFramework/Resources/FrameworkMessages.Designer.cs b/src/TestFramework/TestFramework/Resources/FrameworkMessages.Designer.cs index 51c9d1dd52..6f6bd8b572 100644 --- a/src/TestFramework/TestFramework/Resources/FrameworkMessages.Designer.cs +++ b/src/TestFramework/TestFramework/Resources/FrameworkMessages.Designer.cs @@ -150,15 +150,6 @@ internal static string AreSameGivenValues { } } - /// - /// Looks up a localized string similar to Type '{0}' is not assignable to '{1}'.. - /// - internal static string ArgumentXMustDeriveFromClassY { - get { - return ResourceManager.GetString("ArgumentXMustDeriveFromClassY", resourceCulture); - } - } - /// /// Looks up a localized string similar to {0} failed. {1}. /// @@ -168,24 +159,6 @@ internal static string AssertionFailed { } } - /// - /// Looks up a localized string similar to async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute.. - /// - internal static string AsyncUITestMethodNotSupported { - get { - return ResourceManager.GetString("AsyncUITestMethodNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization.. - /// - internal static string AsyncUITestMethodWithNoDispatcherQueue { - get { - return ResourceManager.GetString("AsyncUITestMethodWithNoDispatcherQueue", resourceCulture); - } - } - /// /// Looks up a localized string similar to Both collections are empty. {0}. /// @@ -258,6 +231,42 @@ internal static string ContainsFail { } } + /// + /// Looks up a localized string similar to Expected collection to contain the specified item. {0}. + /// + internal static string ContainsItemFailMsg { + get { + return ResourceManager.GetString("ContainsItemFailMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected at least one item to match the predicate. {0}. + /// + internal static string ContainsPredicateFailMsg { + get { + return ResourceManager.GetString("ContainsPredicateFailMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected collection to contain exactly one element but found {1} element(s). {0}. + /// + internal static string ContainsSingleFailMsg { + get { + return ResourceManager.GetString("ContainsSingleFailMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected exactly one item to match the predicate but found {1} item(s). {0}. + /// + internal static string ContainsSingleMatchFailMsg { + get { + return ResourceManager.GetString("ContainsSingleMatchFailMsg", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} ({1}). /// @@ -276,6 +285,42 @@ internal static string DoesNotContainFail { } } + /// + /// Looks up a localized string similar to Expected collection to not contain the specified item. {0}. + /// + internal static string DoesNotContainItemFailMsg { + get { + return ResourceManager.GetString("DoesNotContainItemFailMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected no items to match the predicate. {0}. + /// + internal static string DoesNotContainPredicateFailMsg { + get { + return ResourceManager.GetString("DoesNotContainPredicateFailMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to String '{0}' ends with string '{1}'. {2}. + /// + internal static string DoesNotEndWithFail { + get { + return ResourceManager.GetString("DoesNotEndWithFail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to String '{0}' starts with string '{1}'. {2}. + /// + internal static string DoesNotStartWithFail { + get { + return ResourceManager.GetString("DoesNotStartWithFail", resourceCulture); + } + } + /// /// Looks up a localized string similar to Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead.. /// @@ -285,6 +330,51 @@ internal static string DoNotUseAssertEquals { } } + /// + /// Looks up a localized string similar to Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead.. + /// + internal static string DoNotUseAssertReferenceEquals { + get { + return ResourceManager.GetString("DoNotUseAssertReferenceEquals", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead.. + /// + internal static string DoNotUseCollectionAssertEquals { + get { + return ResourceManager.GetString("DoNotUseCollectionAssertEquals", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead.. + /// + internal static string DoNotUseCollectionAssertReferenceEquals { + get { + return ResourceManager.GetString("DoNotUseCollectionAssertReferenceEquals", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead.. + /// + internal static string DoNotUseStringAssertEquals { + get { + return ResourceManager.GetString("DoNotUseStringAssertEquals", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead.. + /// + internal static string DoNotUseStringAssertReferenceEquals { + get { + return ResourceManager.GetString("DoNotUseStringAssertReferenceEquals", resourceCulture); + } + } + /// /// Looks up a localized string similar to Method {0} must match the expected signature: public static {1} {0}({2}).. /// @@ -313,7 +403,7 @@ internal static string DynamicDataIEnumerableNull { } /// - /// Looks up a localized string similar to Dynamic data method '{0}' should be static, parameterless and non-generic.. + /// Looks up a localized string similar to Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter.. /// internal static string DynamicDataInvalidMethodLayout { get { @@ -378,7 +468,7 @@ internal static string ElementTypesAtIndexDontMatch { } /// - /// Looks up a localized string similar to String '{0}' does not end with string '{1}'. {2}.. + /// Looks up a localized string similar to String '{0}' does not end with string '{1}'. {2}. /// internal static string EndsWithFail { get { @@ -413,6 +503,33 @@ internal static string InvalidPropertyType { } } + /// + /// Looks up a localized string similar to Actual value <{2}> is not greater than expected value <{1}>. {0}. + /// + internal static string IsGreaterThanFailMsg { + get { + return ResourceManager.GetString("IsGreaterThanFailMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Actual value <{2}> is not greater than or equal to expected value <{1}>. {0}. + /// + internal static string IsGreaterThanOrEqualToFailMsg { + get { + return ResourceManager.GetString("IsGreaterThanOrEqualToFailMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value '{0}' is not within the expected range [{1}, {2}]. {3}. + /// + internal static string IsInRangeFail { + get { + return ResourceManager.GetString("IsInRangeFail", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} Expected type:<{1}>. Actual type:<{2}>.. /// @@ -423,7 +540,25 @@ internal static string IsInstanceOfFailMsg { } /// - /// Looks up a localized string similar to String '{0}' does not match pattern '{1}'. {2}.. + /// Looks up a localized string similar to Actual value <{2}> is not less than expected value <{1}>. {0}. + /// + internal static string IsLessThanFailMsg { + get { + return ResourceManager.GetString("IsLessThanFailMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Actual value <{2}> is not less than or equal to expected value <{1}>. {0}. + /// + internal static string IsLessThanOrEqualToFailMsg { + get { + return ResourceManager.GetString("IsLessThanOrEqualToFailMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to String '{0}' does not match pattern '{1}'. {2}. /// internal static string IsMatchFail { get { @@ -431,6 +566,15 @@ internal static string IsMatchFail { } } + /// + /// Looks up a localized string similar to Expected value <{1}> to be negative. {0}. + /// + internal static string IsNegativeFailMsg { + get { + return ResourceManager.GetString("IsNegativeFailMsg", resourceCulture); + } + } + /// /// Looks up a localized string similar to Expected collection to contain any item but it is empty. {0}. /// @@ -450,7 +594,7 @@ internal static string IsNotInstanceOfFailMsg { } /// - /// Looks up a localized string similar to String '{0}' matches pattern '{1}'. {2}.. + /// Looks up a localized string similar to String '{0}' matches pattern '{1}'. {2}. /// internal static string IsNotMatchFail { get { @@ -458,6 +602,15 @@ internal static string IsNotMatchFail { } } + /// + /// Looks up a localized string similar to Expected value <{1}> to be positive. {0}. + /// + internal static string IsPositiveFailMsg { + get { + return ResourceManager.GetString("IsPositiveFailMsg", resourceCulture); + } + } + /// /// Looks up a localized string similar to Expected exception type:<{1}> but no exception was thrown. {0}. /// @@ -512,7 +665,7 @@ internal static string PrivateAccessorMemberNotFound { } /// - /// Looks up a localized string similar to String '{0}' does not start with string '{1}'. {2}.. + /// Looks up a localized string similar to String '{0}' does not start with string '{1}'. {2}. /// internal static string StartsWithFail { get { diff --git a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx index ceca8be756..2fbf6e32e0 100644 --- a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx +++ b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx @@ -165,6 +165,9 @@ String '{0}' does not contain string '{1}'. {2}. + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + The number of elements in the collections do not match. Expected:<{1}>. Actual:<{2}>.{0} @@ -177,7 +180,7 @@ Actual: {2} Element at index {1} is not of expected type. Expected type:<{2}>. Actual type:<{3}>.{0} - String '{0}' does not end with string '{1}'. {2}. + String '{0}' does not end with string '{1}'. {2} {0} failed. {1} @@ -186,16 +189,13 @@ Actual: {2} {0} Expected type:<{1}>. Actual type:<{2}>. - String '{0}' does not match pattern '{1}'. {2}. + String '{0}' does not match pattern '{1}'. {2} Wrong Type:<{1}>. Actual type:<{2}>. {0} - String '{0}' matches pattern '{1}'. {2}. - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + String '{0}' matches pattern '{1}'. {2} @@ -218,7 +218,7 @@ Actual: {2} Different number of elements. - String '{0}' does not start with string '{1}'. {2}. + String '{0}' does not start with string '{1}'. {2} The property {0} has type {1}; expected type {2}. @@ -256,12 +256,6 @@ Actual: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. @@ -274,15 +268,8 @@ Actual: {2} Property or method {0} on {1} returns empty IEnumerable<object[]>. - - Type '{0}' is not assignable to '{1}'. - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - - - Dynamic data method '{0}' should be static, parameterless and non-generic. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. Dynamic data property '{0}' should be static and have a getter. @@ -293,6 +280,24 @@ Actual: {2} Expected collection of size {1}. Actual: {2}. {0} + + Expected exactly one item to match the predicate but found {1} item(s). {0} + + + Expected collection to contain exactly one element but found {1} element(s). {0} + + + Expected collection to contain the specified item. {0} + + + Expected at least one item to match the predicate. {0} + + + Expected collection to not contain the specified item. {0} + + + Expected no items to match the predicate. {0} + Expected collection to contain any item but it is empty. {0} @@ -302,4 +307,46 @@ Actual: {2} String '{0}' does contain string '{1}'. {2}. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + + + Actual value <{2}> is not less than expected value <{1}>. {0} + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + + + Expected value <{1}> to be positive. {0} + + + Expected value <{1}> to be negative. {0} + + + String '{0}' ends with string '{1}'. {2} + + + String '{0}' starts with string '{1}'. {2} + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + \ No newline at end of file diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf index ddfcc9862b..c5e59f0e0c 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf @@ -82,14 +82,54 @@ Řetězec '{0}' neobsahuje řetězec '{1}'. {2}. + + Expected collection to contain the specified item. {0} + Očekávala se kolekce, která bude obsahovat zadanou položku. {0} + + + + Expected at least one item to match the predicate. {0} + Očekávala se alespoň jedna položka odpovídající predikátu. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + Očekávalo se, že kolekce bude obsahovat přesně jeden prvek, ale našlo se tolik elementů: {1}. {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + Očekávala se přesně jedna položka odpovídající predikátu, ale našlo se tolik položek: {1}. {0} + + String '{0}' does contain string '{1}'. {2}. Řetězec {0} obsahuje řetězec {1}. {2}. + + Expected collection to not contain the specified item. {0} + Očekávalo se, že kolekce nebude obsahovat zadanou položku. {0} + + + + Expected no items to match the predicate. {0} + Očekávaly se žádné položky, které by odpovídaly predikátu. {0} + + + + String '{0}' ends with string '{1}'. {2} + Řetězec „{0}“ končí řetězcem „{1}“. {2} + + + + String '{0}' starts with string '{1}'. {2} + Řetězec „{0}“ začíná řetězcem „{1}“. {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - Metoda dynamických dat {0} by měla být statická, bez parametrů a negenerická. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + Dynamická datová metoda {0} by měla být statická a neobecná a nemůže mít parametr params. @@ -122,9 +162,9 @@ Skutečnost: {2} - String '{0}' does not end with string '{1}'. {2}. - Řetězec '{0}' nekončí řetězcem '{1}'. {2}. - + String '{0}' does not end with string '{1}'. {2} + Řetězec „{0}“ nekončí řetězcem „{1}“. {2} + {0} failed. {1} @@ -141,15 +181,20 @@ Skutečnost: {2} Neplatná adresa URL lístku GitHubu + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + Hodnota {0} není v očekávaném rozsahu [{1}, {2}]. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} Očekávaný typ:<{1}>. Aktuální typ:<{2}>. - String '{0}' does not match pattern '{1}'. {2}. - Řetězec '{0}' neodpovídá vzoru '{1}'. {2}. - + String '{0}' does not match pattern '{1}'. {2} + Řetězec „{0}“ neodpovídá vzoru „{1}“. {2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Skutečnost: {2} - String '{0}' matches pattern '{1}'. {2}. - Řetězec '{0}' odpovídá vzoru '{1}'. {2}. - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Assert.Equals by neměla být pro kontrolní výrazy používána. Použijte prosím místo toho Assert.AreEqual a její přetížení. - + String '{0}' matches pattern '{1}'. {2} + Řetězec „{0}“ odpovídá vzoru „{1}“. {2} + @@ -182,7 +222,7 @@ Skutečnost: {2} nebo může být člen soukromý a definovaný v základní třídě. Pokud je tvrzení pravdivé, bude zapotřebí předat typ , který definuje člena do konstruktoru PrivateObject. - + @@ -195,7 +235,7 @@ Skutečnost: {2} nebo může být člen soukromý a definovaný v základní třídě. Pokud je tvrzení pravdivé, bude zapotřebí předat typ , který definuje člena do konstruktoru PrivateObject. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Skutečnost: {2} - String '{0}' does not start with string '{1}'. {2}. - Řetězec '{0}' nezačíná řetězcem '{1}'. {2}. - + String '{0}' does not start with string '{1}'. {2} + Řetězec „{0}“ nezačíná řetězcem „{1}“. {2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Skutečnost: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - async TestMethod s atributem UITestMethodAttribute se nepodporují. Buď odeberte async, nebo použijte TestMethodAttribute. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. Vlastnost nebo metoda {0} na návratovém typu {1} se nedá přiřadit k „IEnumerable“. @@ -297,18 +332,65 @@ Skutečnost: {2} Vlastnost nebo metoda {0} ve třídě {1} vrací prázdné IEnumerable<object[]>. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue nesmí mít hodnotu null. Pokud chcete použít UITestMethodAttribute v desktopové aplikaci WinUI, nezapomeňte během inicializace testu nastavit statický UITestMethodAttribute.DispatcherQueue. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + Skutečná hodnota <{2}> není větší než očekávaná hodnota <{1}>. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + Skutečná hodnota <{2}> není větší nebo rovna očekávané hodnotě <{1}>. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + Skutečná hodnota <{2}> není menší než očekávaná hodnota <{1}>. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + Skutečná hodnota <{2}> není menší nebo rovna očekávané hodnotě <{1}>. {0} + + + + Expected value <{1}> to be positive. {0} + Očekávaná hodnota <{1}> má být kladná. {0} + + + + Expected value <{1}> to be negative. {0} + Očekávaná hodnota <{1}> má být záporná. {0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Assert.Equals by neměla být pro kontrolní výrazy používána. Použijte prosím místo toho Assert.AreEqual a její přetížení. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Assert.ReferenceEquals se nemá používat pro kontrolní výrazy. Použijte prosím místo toho Assert.AreEqual & overloads. - - Type '{0}' is not assignable to '{1}'. - Typ „{0}“ nelze přiřadit k „{1}“. - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + StringAssert.Equals se nemá používat pro kontrolní výrazy. Místo toho použijte metody StringAssert nebo Assert.AreEqual & overloads. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + StringAssert.ReferenceEquals se nemá používat pro kontrolní výrazy. Místo toho použijte metody StringAssert nebo Assert.AreSame & overloads. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + CollectionAssert.Equals se nemá používat pro kontrolní výrazy. Místo toho použijte CollectionAssert.AreEqual & overloads. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + CollectionAssert.ReferenceEquals se nemá používat pro kontrolní výrazy. Místo toho použijte metody CollectionAssert nebo Assert.AreSame & overloads. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf index 651d41e168..9a44a844f2 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf @@ -82,14 +82,54 @@ Die Zeichenfolge "{0}" enthält nicht die Zeichenfolge "{1}". {2}. + + Expected collection to contain the specified item. {0} + Es wurde erwartet, dass die Sammlung das angegebene Element enthält. {0} + + + + Expected at least one item to match the predicate. {0} + Es wurde erwartet, dass mindestens ein Element mit dem Prädikat übereinstimmt. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + Es wurde erwartet, dass die Sammlung genau ein Element enthält, es wurden jedoch {1} gefunden. {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + Es wurde erwartet, dass genau ein Element mit dem Prädikat übereinstimmt, es wurden jedoch {1} Element(e) gefunden. {0} + + String '{0}' does contain string '{1}'. {2}. Die Zeichenfolge „{0}“ enthält die Zeichenfolge „{1}“. {2}. + + Expected collection to not contain the specified item. {0} + Es wurde erwartet, dass die Sammlung das angegebene Element nicht enthält. {0} + + + + Expected no items to match the predicate. {0} + Es wurden erwartet, dass keine Elemente mit dem Prädikat übereinstimmen. {0} + + + + String '{0}' ends with string '{1}'. {2} + Die Zeichenfolge „{0}“ endet mit der Zeichenfolge „{1}“. {2} + + + + String '{0}' starts with string '{1}'. {2} + Die Zeichenfolge „{0}“ beginnt mit der Zeichenfolge „{1}“. {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - Die dynamische Datenmethode "{0}" muss statisch, parameterlos sein und nichtgenerisch sein. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + Die dynamische Datenmethode „{0}“ muss statisch, nicht generisch sein und darf keinen Parameter „params“ enthalten. @@ -122,9 +162,9 @@ Tatsächlich: {2} - String '{0}' does not end with string '{1}'. {2}. - Die Zeichenfolge "{0}" endet nicht auf die Zeichenfolge "{1}". {2}. - + String '{0}' does not end with string '{1}'. {2} + Die Zeichenfolge „{0}“ endet nicht auf die Zeichenfolge „{1}“. {2} + {0} failed. {1} @@ -141,15 +181,20 @@ Tatsächlich: {2} Ungültige GitHub-Ticket-URL. + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + Der Wert „{0}“ liegt nicht im erwarteten Bereich [{1}, {2}]. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0}Erwarteter Typ:<{1}>. Tatsächlicher Typ:<{2}>. - String '{0}' does not match pattern '{1}'. {2}. - Die Zeichenfolge "{0}" stimmt nicht mit dem Muster "{1}" überein. {2}. - + String '{0}' does not match pattern '{1}'. {2} + Die Zeichenfolge „{0}“ stimmt nicht mit dem Muster „{1}“ überein. {2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Tatsächlich: {2} - String '{0}' matches pattern '{1}'. {2}. - Die Zeichenfolge "{0}" stimmt mit dem Muster "{1}" überein. {2}. - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Assert.Equals sollte nicht für Assertions verwendet werden. Verwenden Sie stattdessen Assert.AreEqual und Überladungen. - + String '{0}' matches pattern '{1}'. {2} + Die Zeichenfolge „{0}“ stimmt mit dem Muster „{1}“ überein. {2} + @@ -182,7 +222,7 @@ Tatsächlich: {2} oder der Member ist möglicherweise privat und für die Basisklasse definiert. Wenn letzteres zutrifft, müssen Sie den Typ, der den Member definiert, an den Konstruktor von PrivateObject übergeben. - + @@ -195,7 +235,7 @@ Tatsächlich: {2} oder der Member ist möglicherweise privat und für die Basisklasse definiert. Wenn letzteres zutrifft, müssen Sie den Typ, der den Member definiert, an den Konstruktor von PrivateObject übergeben. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Tatsächlich: {2} - String '{0}' does not start with string '{1}'. {2}. - Die Zeichenfolge "{0}" beginnt nicht mit der Zeichenfolge "{1}". {2}. - + String '{0}' does not start with string '{1}'. {2} + Die Zeichenfolge „{0}“ beginnt nicht mit der Zeichenfolge „{1}“. {2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Tatsächlich: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - "async TestMethod" wird mit UITestMethodAttribute nicht unterstützt. Entfernen Sie "async", oder verwenden Sie TestMethodAttribute. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. Eigenschaft oder Methode {0} für {1} Rückgabetyp kann „IEnumerable“ nicht zugewiesen werden. @@ -297,18 +332,65 @@ Tatsächlich: {2} Eigenschaft oder Methode "{0}" in "{1}" gibt leeres IEnumerable<object[]> zurück. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue darf nicht NULL sein. Um UITestMethodAttribute in einer WinUI-Desktop-App zu verwenden, denken Sie daran, die statische UITestMethodAttribute.DispatcherQueue während der Testinitialisierung festzulegen. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + Der tatsächliche Wert <{2}> ist nicht größer als der erwartete Wert <{1}>. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + Der tatsächliche Wert <{2}> ist nicht größer oder gleich dem erwarteten Wert <{1}>. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + Der tatsächliche Wert <{2}> ist nicht kleiner als der erwartete Wert <{1}>. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + Der tatsächliche Wert <{2}> ist nicht kleiner oder gleich dem erwarteten Wert <{1}>. {0} + + + + Expected value <{1}> to be positive. {0} + Es wurde erwartet, dass der Wert <{1}> positiv ist. {0} + + + + Expected value <{1}> to be negative. {0} + Es wurde erwartet, dass der Wert <{1}> negativ ist. {0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Assert.Equals sollte nicht für Assertions verwendet werden. Verwenden Sie stattdessen Assert.AreEqual und Überladungen. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Assert.ReferenceEquals sollte nicht für Assertions verwendet werden. Verwenden Sie stattdessen Assert.AreSame und Überladungen. - - Type '{0}' is not assignable to '{1}'. - Der Typ "{0}" kann nicht "{1}" zugewiesen werden. - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + StringAssert.Equals sollte nicht für Assertions verwendet werden. Verwenden Sie stattdessen StringAssert-Methoden oder Assert.AreEqual und Überladungen. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + StringAssert.ReferenceEquals darf nicht für Assertions verwendet werden. Verwenden Sie stattdessen StringAssert-Methoden oder Assert.AreSame und Überladungen. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + CollectionAssert.Equals sollte nicht für Assertions verwendet werden. Verwenden Sie stattdessen CollectionAssert.AreEqual und Überladungen. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + CollectionAssert.ReferenceEquals darf nicht für Assertions verwendet werden. Verwenden Sie stattdessen CollectionAssert-Methoden oder Assert.AreSame und Überladungen. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf index f838df72e1..9a157e3763 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf @@ -82,14 +82,54 @@ La cadena '{0}' no contiene la cadena '{1}'. {2}. + + Expected collection to contain the specified item. {0} + Se esperaba que la colección contuviera el elemento especificado. {0} + + + + Expected at least one item to match the predicate. {0} + Se esperaba al menos un elemento para que coincida con el predicado. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + Se esperaba que la colección contuviera exactamente un elemento, pero se encontraron {1} elementos. {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + Se esperaba exactamente un elemento para que coincida con el predicado, pero se encontraron {1} elementos. {0} + + String '{0}' does contain string '{1}'. {2}. La cadena '{0}' contiene la cadena '{1}'. {2}. + + Expected collection to not contain the specified item. {0} + Se esperaba que la colección no contenga el elemento especificado. {0} + + + + Expected no items to match the predicate. {0} + No se esperaba que ningún elemento coincidía con el predicado. {0} + + + + String '{0}' ends with string '{1}'. {2} + La cadena "{0}" termina con la cadena "{1}". {2} + + + + String '{0}' starts with string '{1}'. {2} + La cadena "{0}" comienza con la cadena "{1}". {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - El método de datos dinámicos '{0}' debe ser estático, sin parámetros y no genérico. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + El método de datos dinámicos '{0}' debe ser estático, no genérico y no puede tener un parámetro 'params'. @@ -122,9 +162,9 @@ Real: {2} - String '{0}' does not end with string '{1}'. {2}. - La cadena '{0}' no termina con la cadena '{1}'. {2}. - + String '{0}' does not end with string '{1}'. {2} + La cadena "{0}" no termina con la cadena "{1}". {2} + {0} failed. {1} @@ -141,15 +181,20 @@ Real: {2} Dirección URL de vale de GitHub no válida + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + El valor "{0}" no está dentro del rango esperado [{1}, {2}]. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} Tipo esperado:<{1}>. Tipo real:<{2}>. - String '{0}' does not match pattern '{1}'. {2}. - La cadena '{0}' no coincide con el patrón '{1}'. {2}. - + String '{0}' does not match pattern '{1}'. {2} + La cadena "{0}" no coincide con el patrón "{1}". {2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Real: {2} - String '{0}' matches pattern '{1}'. {2}. - La cadena '{0}' coincide con el patrón '{1}'. {2}. - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - No se debe usar Assert.Equals para aserciones. Use Assert.AreEqual y Overloads en su lugar. - + String '{0}' matches pattern '{1}'. {2} + La cadena "{0}" coincide con el patrón "{1}". {2} + @@ -182,7 +222,7 @@ Real: {2} o que el miembro sea privado y esté definido en una clase base. Si esto último es cierto, debe pasar el tipo que define el miembro al constructor de PrivateObject. - + @@ -195,7 +235,7 @@ Real: {2} o que el miembro sea privado y esté definido en una clase base. Si esto último es cierto, debe pasar el tipo que define el miembro al constructor de PrivateObject. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Real: {2} - String '{0}' does not start with string '{1}'. {2}. - La cadena '{0}' no empieza con la cadena '{1}'. {2}. - + String '{0}' does not start with string '{1}'. {2} + La cadena "{0}" no empieza con la cadena "{1}". {2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Real: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - async TestMethod con UITestMethodAttribute no son compatibles. Quite async o use TestMethodAttribute. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. La propiedad o el método {0} en el tipo de retorno {1} no se puede asignar a "IEnumerable". @@ -297,18 +332,65 @@ Real: {2} La propiedad o el método {0} en {1} devuelve un elemento IEnumerable<object[]> vacío. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue no debe ser null. Para usar UITestMethodAttribute en una aplicación de escritorio WinUI, recuerde establecer el UITestMethodAttribute.DispatcherQueue estático durante la inicialización de la prueba. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + El valor real <{2}> no es mayor que el valor esperado <{1}>. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + El valor real <{2}> no es mayor o igual que el valor esperado <{1}>. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + El valor real <{2}> no es menor que el valor esperado <{1}>. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + El valor real <{2}> no es menor o igual que el valor esperado <{1}>. {0} + + + + Expected value <{1}> to be positive. {0} + Se esperaba que el valor <{1}> ser positivo. {0} + + + + Expected value <{1}> to be negative. {0} + Se esperaba que el valor <{1}> ser negativo. {0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + No se debe usar Assert.Equals para aserciones. Use Assert.AreEqual y Overloads en su lugar. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Assert.ReferenceEquals no se debe usar para las aserciones. Use Assert.AreSame & sobrecargas en su lugar. - - Type '{0}' is not assignable to '{1}'. - Tipo "{0}" no se puede asignar a "{1}". - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + StringAssert.Equals no se debe usar para las aserciones. Use los métodos StringAssert o las sobrecargas Assert.AreEqual & en su lugar. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + StringAssert.ReferenceEquals no se debe usar para las aserciones. Use los métodos StringAssert o las sobrecargas Assert.AreSame & en su lugar. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + CollectionAssert.Equals no se debe usar para las aserciones. Use CollectionAssert.AreEqual y sobrecargas en su lugar. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + CollectionAssert.ReferenceEquals no se debe usar para las aserciones. Use los métodos CollectionAssert o las sobrecargas Assert.AreSame & en su lugar. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf index c342c620e5..29f3fb510f 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf @@ -82,14 +82,54 @@ La chaîne '{0}' ne contient pas la chaîne '{1}'. {2}. + + Expected collection to contain the specified item. {0} + Collection attendue pour contenir l’élément spécifié. {0} + + + + Expected at least one item to match the predicate. {0} + Au moins un élément doit correspondre au prédicat. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + Collection attendue pour contenir exactement un élément mais {1} élément(s) trouvé(s). {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + Un seul élément était attendu pour correspondre au prédicat, mais {1} élément(s) trouvé(s). {0} + + String '{0}' does contain string '{1}'. {2}. La chaîne « {0} » contient la chaîne « {1} ». {2}. + + Expected collection to not contain the specified item. {0} + Collection attendue pour ne pas contenir l’élément spécifié. {0} + + + + Expected no items to match the predicate. {0} + Aucun élément ne doit correspondre au prédicat. {0} + + + + String '{0}' ends with string '{1}'. {2} + La chaîne '{0}' se termine par la chaîne '{1}'. {2} + + + + String '{0}' starts with string '{1}'. {2} + La chaîne '{0}' commence par la chaîne '{1}'. {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - La méthode de données dynamiques « {0} » doit être statique, sans paramètre et non générique. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + La méthode de données dynamiques « {0} » doit être statique, non générique et ne peut pas avoir le paramètre « params ». @@ -122,9 +162,9 @@ Réel : {2} - String '{0}' does not end with string '{1}'. {2}. - La chaîne '{0}' ne se termine pas par la chaîne '{1}'. {2}. - + String '{0}' does not end with string '{1}'. {2} + La chaîne '{0}' ne se termine pas par la chaîne '{1}'. {2} + {0} failed. {1} @@ -141,15 +181,20 @@ Réel : {2} URL de ticket GitHub non valide + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + La valeur « {0} » n'est pas dans la plage attendue [{1}, {2}]. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0}Type attendu :<{1}>. Type réel :<{2}>. - String '{0}' does not match pattern '{1}'. {2}. - La chaîne '{0}' ne correspond pas au modèle '{1}'. {2}. - + String '{0}' does not match pattern '{1}'. {2} + La chaîne '{0}' ne correspond pas au modèle '{1}'. {2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Réel : {2} - String '{0}' matches pattern '{1}'. {2}. - La chaîne '{0}' correspond au modèle '{1}'. {2}. - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Assert.Equals ne doit pas être utilisé pour les assertions. Utilisez Assert.AreEqual & overloads à la place. - + String '{0}' matches pattern '{1}'. {2} + La chaîne '{0}' correspond au modèle '{1}'. {2} + @@ -182,7 +222,7 @@ Réel : {2} ou le membre est peut-être private et défini sur une classe de base. Si le dernier cas est vrai, vous devez transmettre le type qui définit le membre dans le constructeur de PrivateObject. - + @@ -195,7 +235,7 @@ Réel : {2} ou le membre est peut-être private et défini sur une classe de base. Si le dernier cas est vrai, vous devez transmettre le type qui définit le membre dans le constructeur de PrivateObject. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Réel : {2} - String '{0}' does not start with string '{1}'. {2}. - La chaîne '{0}' ne commence pas par la chaîne '{1}'. {2}. - + String '{0}' does not start with string '{1}'. {2} + La chaîne '{0}' ne commence pas par la chaîne '{1}'. {2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Réel : {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - async TestMethod avec UITestMethodAttribute ne sont pas pris en charge. Supprimez async ou utilisez TestMethodAttribute. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. La propriété ou la méthode {0} sur le type de retour {1} ne peut pas être attribuée à « IEnumerable ». @@ -297,18 +332,65 @@ Réel : {2} La propriété ou la méthode {0} sur {1} retourne un IEnumerable<object[]> vide. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue ne doit pas avoir la valeur nul. Pour utiliser UITestMethodAttribute dans une application de bureau WinUI, n’oubliez pas de définir l’UITestMethodAttribute.DispatcherQueue statique pendant l’initialisation du test. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + La valeur réelle <{2}> n’est pas supérieure à la valeur attendue <{1}>. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + La valeur réelle <{2}> n’est pas supérieure ou égale à la valeur attendue <{1}>. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + La valeur réelle <{2}> n’est pas inférieure à la valeur attendue <{1}>. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + La valeur réelle <{2}> n’est pas inférieure ou égale à la valeur attendue <{1}>. {0} + + + + Expected value <{1}> to be positive. {0} + La valeur attendue <{1}> doit être positive. {0} + + + + Expected value <{1}> to be negative. {0} + La valeur attendue <{1}> doit être négative. {0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Assert.Equals ne doit pas être utilisé pour les assertions. Utilisez Assert.AreEqual & overloads à la place. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Assert.ReferenceEquals ne doit pas être utilisé pour les assertions. Utilisez Assert.AreEqual & overloads à la place. - - Type '{0}' is not assignable to '{1}'. - Impossible d'assigner le type '{0}' à '{1}'. - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + StringAssert.Equals ne doit pas être utilisé pour les assertions. Utilisez plutôt les méthodes StringAssert ou Assert.AreEqual & overloads. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + StringAssert.ReferenceEquals ne doit pas être utilisé pour les assertions. Utilisez plutôt les méthodes StringAssert ou Assert.AreSame & overloads. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + Assert.Equals ne doit pas être utilisé pour les assertions. Utilisez plutôt CollectionAssert.AreEqual & overloads. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + CollectionAssert.ReferenceEquals ne doit pas être utilisé pour les assertions. Utilisez plutôt les méthodes CollectionAssert ou Assert.AreSame & overloads. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf index 3b297c7af2..bf538f0172 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf @@ -82,14 +82,54 @@ La stringa '{0}' non contiene la stringa '{1}'. {2}. + + Expected collection to contain the specified item. {0} + La raccolta dovrebbe contenere l'elemento specificato. {0} + + + + Expected at least one item to match the predicate. {0} + Almeno un elemento dovrebbe corrispondere al predicato. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + La raccolta dovrebbe contenere un unico elemento, ma ne sono stati trovati {1}. {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + Un unico elemento dovrebbe corrispondere al predicato, ma ne sono stati trovati {1}. {0} + + String '{0}' does contain string '{1}'. {2}. La stringa '{0}' contiene la stringa '{1}'. {2}. + + Expected collection to not contain the specified item. {0} + La raccolta non dovrebbe contenere l'elemento specificato. {0} + + + + Expected no items to match the predicate. {0} + Nessun elemento dovrebbe corrispondere al predicato. {0} + + + + String '{0}' ends with string '{1}'. {2} + La stringa '{0}' termina con la stringa '{1}'. {2} + + + + String '{0}' starts with string '{1}'. {2} + La stringa '{0}' inizia con la stringa '{1}'. {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - Il metodo '{0}' di Dynamic Data deve essere statico, senza parametri e non generico. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + Il metodo dei dati dinamici '{0}' deve essere statico, non generico e non può includere un parametro 'params'. @@ -122,9 +162,9 @@ Effettivo: {2} - String '{0}' does not end with string '{1}'. {2}. - La stringa '{0}' non termina con la stringa '{1}'. {2}. - + String '{0}' does not end with string '{1}'. {2} + La stringa '{0}' non termina con la stringa '{1}'. {2} + {0} failed. {1} @@ -141,15 +181,20 @@ Effettivo: {2} L'URL del ticket GitHub non è valido + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + Il valore '{0}' non è compreso nell'intervallo previsto [{1}, {2}]. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} Tipo previsto:<{1}>. Tipo effettivo:<{2}>. - String '{0}' does not match pattern '{1}'. {2}. - La stringa '{0}' non corrisponde al criterio '{1}'. {2}. - + String '{0}' does not match pattern '{1}'. {2} + La stringa '{0}' non corrisponde al criterio '{1}'. {2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Effettivo: {2} - String '{0}' matches pattern '{1}'. {2}. - La stringa '{0}' corrisponde al criterio '{1}'. {2}. - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Non è possibile usare Assert.Equals per le asserzioni. Usare Assert.AreEqual e gli overload. - + String '{0}' matches pattern '{1}'. {2} + La stringa '{0}' corrisponde al criterio '{1}'. {2} + @@ -182,7 +222,7 @@ Effettivo: {2} oppure il membro potrebbe essere privato e definito per una classe base. In quest'ultimo caso, è necessario passare il tipo che definisce il membro nel costruttore di PrivateObject. - + @@ -195,7 +235,7 @@ Effettivo: {2} oppure il membro potrebbe essere privato e definito per una classe base. In quest'ultimo caso, è necessario passare il tipo che definisce il membro nel costruttore di PrivateObject. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Effettivo: {2} - String '{0}' does not start with string '{1}'. {2}. - La stringa '{0}' non inizia con la stringa '{1}'. {2}. - + String '{0}' does not start with string '{1}'. {2} + La stringa '{0}' non inizia con la stringa '{1}'. {2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Effettivo: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - L'elemento async TestMethod con UITestMethodAttribute non è supportato. Rimuovere async o usare TestMethodAttribute. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. La proprietà o il metodo {0} su {1} tipo restituito non è assegnabile a 'IEnumerable'. @@ -297,18 +332,65 @@ Effettivo: {2} La proprietà o il metodo {0} nella classe {1} restituisce un elemento IEnumerable<object[]> vuoto. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue non deve essere Null. Per usare UITestMethodAttribute all'interno di un'app desktop WinUI, ricordarsi di impostare il parametro statico uiTestMethodAttribute.DispatcherQueue durante l'inizializzazione del test. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + Il valore effettivo <{2}> non è maggiore del valore previsto <{1}>. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + Il valore effettivo <{2}> non è maggiore o uguale al valore previsto <{1}>. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + Il valore effettivo <{2}> non è minore del valore previsto <{1}>. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + Il valore effettivo <{2}> non è minore o uguale al valore previsto <{1}>. {0} + + + + Expected value <{1}> to be positive. {0} + Il valore <{1}{0}> dovrebbe essere positivo. + + + + Expected value <{1}> to be negative. {0} + Il valore <{1}{0}> dovrebbe essere negativo. + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Non è possibile usare Assert.Equals per le asserzioni. Usare Assert.AreEqual e gli overload. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Non è possibile usare Assert.ReferenceEquals per le asserzioni. In alternativa, usare Assert.AreSame e gli overload. - - Type '{0}' is not assignable to '{1}'. - Il tipo '{0}' non è assegnabile a '{1}'. - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + Non è possibile usare StringAssert.Equals per le asserzioni. In alternativa, usare i metodi StringAssert o Assert.AreEqual e gli overload. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + Non è possibile usare StringAssert.ReferenceEquals per le asserzioni. In alternativa, usare i metodi StringAssert o Assert.AreSame e gli overload. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + Non è possibile usare CollectionAssert.Equals per le asserzioni. In alternativa, usare CollectionAssert.AreEqual e gli overload. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + Non è possibile usare CollectionAssert.ReferenceEquals per le asserzioni. In alternativa, usare i metodi CollectionAssert o Assert.AreSame e gli overload. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf index ad0c99078d..b23c0df7bb 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf @@ -82,14 +82,54 @@ 文字列 '{0}' は文字列 '{1}' を含んでいません。{2}。 + + Expected collection to contain the specified item. {0} + 指定された項目を含むコレクションが必要です。{0} + + + + Expected at least one item to match the predicate. {0} + 述語と一致する項目が少なくとも 1 つ必要です。{0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + コレクションには 1 つの要素だけを含める必要がありますが、{1} 要素が見つかりました。{0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + 述語と一致する項目が 1 つだけ必要ですが、{1} 項目が見つかりました。{0} + + String '{0}' does contain string '{1}'. {2}. 文字列 '{0}' は文字列 '{1}' を含んでいます。{2}。 + + Expected collection to not contain the specified item. {0} + 指定された項目を含まないコレクションが必要です。{0} + + + + Expected no items to match the predicate. {0} + 述語に一致する項目が必要ありません。{0} + + + + String '{0}' ends with string '{1}'. {2} + 文字列 '{0}' の末尾は文字列 '{1}' です。{2} + + + + String '{0}' starts with string '{1}'. {2} + 文字列 '{0}' は文字列 '{1}' で始まります。 {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - 動的データ メソッド '{0}' は、静的、パラメーターなし、および非ジェネリックである必要があります。 + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + 動的データ メソッド '{0}' は、静的で、非ジェネリックである必要があり、'params' パラメーターを持つことはできません。 @@ -122,9 +162,9 @@ Actual: {2} - String '{0}' does not end with string '{1}'. {2}. - 文字列 '{0}' は文字列 '{1}' で終わりません。{2}。 - + String '{0}' does not end with string '{1}'. {2} + 文字列 '{0}' は文字列 '{1}' で終わりません。{2} + {0} failed. {1} @@ -141,15 +181,20 @@ Actual: {2} GitHub チケット URL が無効です + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + 値 '{0}' は予期される範囲 [{1}, {2}] にありません。 {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} には型 <{1}> が必要ですが、型 <{2}> が指定されました。 - String '{0}' does not match pattern '{1}'. {2}. - 文字列 '{0}' はパターン '{1}' と一致しません。{2}。 - + String '{0}' does not match pattern '{1}'. {2} + 文字列 '{0}' はパターン '{1}' と一致しません。{2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Actual: {2} - String '{0}' matches pattern '{1}'. {2}. - 文字列 '{0}' はパターン '{1}' と一致します。{2}。 - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - アサーションには Assert.Equals を使用せずに、Assert.AreEqual とオーバーロードを使用してください。(& ) - + String '{0}' matches pattern '{1}'. {2} + 文字列 '{0}' はパターン '{1}' と一致します。{2} + @@ -182,7 +222,7 @@ Actual: {2} またはメンバーがプライベートであり、基底クラスで定義されている可能性があります。後者である場合は、メンバーを 定義する型を PrivateObject のコンストラクターに渡す必要があります。 - + @@ -195,7 +235,7 @@ Actual: {2} またはメンバーがプライベートであり、基底クラスで定義されている可能性があります。後者である場合は、メンバーを 定義する型を PrivateObject のコンストラクターに渡す必要があります。 - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Actual: {2} - String '{0}' does not start with string '{1}'. {2}. - 文字列 '{0}' は文字列 '{1}' で始まりません。{2}。 - + String '{0}' does not start with string '{1}'. {2} + 文字列 '{0}' は文字列 '{1}' で始まりません。{2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Actual: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - UITestMethodAttribute が指定された非同期の TestMethod はサポートされていません。非同期を削除するか、TestMethodAttribute を使用してください。 - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. {1} 戻り値の型のプロパティまたはメソッド {0} は、'IEnumerable' に割り当てできません。 @@ -297,18 +332,65 @@ Actual: {2} {1} 上のプロパティまたはメソッド {0} は空の IEnumerable<object[]> を返します。 - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue を null にすることはできません。WinUI デスクトップ アプリ内で UITestMethodAttribute を使用するには、テストの初期化中に静的な UITestMethodAttribute.DispatcherQueue を設定してください。 + + Actual value <{2}> is not greater than expected value <{1}>. {0} + 実際の値 <{2}> は、予期された値 <{1}> より大きくありません。{0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + 実際の値 <{2}> は、予期された値 <{1}> 以上ではありません。{0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + 実際の値 <{2}> は、予期された値 <{1}> より小さくありません。{0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + 実際の値 <{2}> は、予期された値 <{1}> 以下ではありません。{0} + + + + Expected value <{1}> to be positive. {0} + 正の値 <{1}> が必要です。{0} + + + + Expected value <{1}> to be negative. {0} + 負の値 <{1}> が必要です。{0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + アサーションには Assert.Equals を使用せずに、Assert.AreEqual とオーバーロードを使用してください。(& ) + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + アサーションには Assert.ReferenceEquals を使用しないでください。Assert.AreSame およびオーバーロードを使用してください。 - - Type '{0}' is not assignable to '{1}'. - 型 '{0}' を '{1}' に割り当てることはできません。 - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + アサーションには StringAssert.Equals を使用しないでください。代わりに StringAssert メソッドまたは Assert.AreEqual およびオーバーロードを使用してください。 + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + アサーションには StringAssert.ReferenceEquals を使用しないでください。代わりに StringAssert メソッドまたは Assert.AreSame およびオーバーロードを使用してください。 + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + アサーションには CollectionAssert.Equals を使用しないでください。代わりに CollectionAssert.AreEqual およびオーバーロードを使用してください。 + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + アサーションには CollectionAssert.ReferenceEquals を使用しないでください。代わりに CollectionAssert メソッドまたは Assert.AreSame およびオーバーロードを使用してください。 + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf index e0428e081c..19b6b3453e 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf @@ -82,14 +82,54 @@ '{0}' 문자열이 '{1}' 문자열을 포함하지 않습니다. {2} + + Expected collection to contain the specified item. {0} + 지정한 항목을 포함할 컬렉션이 필요합니다. {0} + + + + Expected at least one item to match the predicate. {0} + 조건자와 일치하는 항목이 하나 이상 필요합니다. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + 정확히 하나의 요소를 포함할 컬렉션이 필요하지만 {1}개 요소가 발견되었습니다. {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + 조건자에 일치하는 항목이 하나만 필요하지만 {1}개 항목이 발견되었습니다. {0} + + String '{0}' does contain string '{1}'. {2}. '{0}' 문자열에 '{1}' 문자열이 포함되어 있습니다. {2}. + + Expected collection to not contain the specified item. {0} + 지정한 항목을 포함하지 않을 컬렉션이 필요합니다. {0} + + + + Expected no items to match the predicate. {0} + 조건자와 일치하는 항목이 필요하지 않습니다. {0} + + + + String '{0}' ends with string '{1}'. {2} + 문자열 '{0}'은 문자열 '{1}'(으)로 끝납니다. {2} + + + + String '{0}' starts with string '{1}'. {2} + 문자열 '{0}'은 문자열 '{1}'(으)로 시작합니다. {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - 동적 데이터 메서드 '{0}'은(는) 정적이고 매개 변수가 없으며 제네릭이 아니어야 합니다. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + 동적 데이터 메서드 '{0}'은(는) 정적이고 제네릭이 아니어야 하며 'params' 매개 변수를 사용할 수 없습니다. @@ -122,9 +162,9 @@ Actual: {2} - String '{0}' does not end with string '{1}'. {2}. + String '{0}' does not end with string '{1}'. {2} '{0}' 문자열이 '{1}' 문자열로 끝나지 않습니다. {2} - + {0} failed. {1} @@ -141,15 +181,20 @@ Actual: {2} 잘못된 GitHub 티켓 URL + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + '{0}' 값이 예상 범위 [{1}, {2}] 내에 있지 않습니다. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} 예상 형식: <{1}>, 실제 형식: <{2}>. - String '{0}' does not match pattern '{1}'. {2}. + String '{0}' does not match pattern '{1}'. {2} '{0}' 문자열이 '{1}' 패턴과 일치하지 않습니다. {2} - + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Actual: {2} - String '{0}' matches pattern '{1}'. {2}. + String '{0}' matches pattern '{1}'. {2} '{0}' 문자열이 '{1}' 패턴과 일치합니다. {2} - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - 어설션에 Assert.Equals를 사용할 수 없습니다. 대신 Assert.AreEqual 및 오버로드를 사용하세요. - + @@ -182,7 +222,7 @@ Actual: {2} 또는 멤버가 기본 클래스에 정의된 프라이빗 멤버일 수 있습니다. 기본 클래스에 정의된 전용 멤버인 경우에는 이 멤버를 정의하는 형식을 PrivateObject의 생성자에 전달해야 합니다. - + @@ -195,7 +235,7 @@ Actual: {2} 또는 멤버가 기본 클래스에 정의된 프라이빗 멤버일 수 있습니다. 기본 클래스에 정의된 전용 멤버인 경우에는 이 멤버를 정의하는 형식을 PrivateObject의 생성자에 전달해야 합니다. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Actual: {2} - String '{0}' does not start with string '{1}'. {2}. + String '{0}' does not start with string '{1}'. {2} '{0}' 문자열이 '{1}' 문자열로 시작되지 않습니다. {2} - + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Actual: {2} {0}({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - async TestMethod with UITestMethodAttribute는 지원되지 않습니다. async를 제거하거나 TestMethodAttribute를 사용하세요. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. {1} 반환 형식의 속성 또는 메서드 {0}은(는) 'IEnumerable'에 할당할 수 없습니다. @@ -297,18 +332,65 @@ Actual: {2} {1}의 속성 또는 메서드 {0}이(가) 빈 IEnumerable<object[]>를 반환합니다. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue는 null이 아니어야 합니다. WinUI 데스크톱 앱 내에서 UITestMethodAttribute를 사용하려면 테스트 초기화 중에 정적 UITestMethodAttribute.DispatcherQueue를 설정해야 합니다. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + 실제 값 <{2}>은(는)는 예상 값 <{1}>보다 크지 않습니다. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + 실제 값 <{2}>은(는)는 예상 값 <{1}>보다 크거나 같지 않습니다. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + 실제 값 <{2}>은(는)는 예상 값 <{1}>보다 작지 않습니다. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + 실제 값 <{2}>은(는)는 예상 값 <{1}>보다 작거나 같지 않습니다. {0} + + + + Expected value <{1}> to be positive. {0} + 예상 값 <{1}>은(는) 양수일 것으로 예상합니다. {0} + + + + Expected value <{1}> to be negative. {0} + 예상 값 <{1}>은(는) 음수일 것으로 예상합니다. {0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + 어설션에 Assert.Equals를 사용할 수 없습니다. 대신 Assert.AreEqual 및 오버로드를 사용하세요. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + 어설션에 Assert.ReferenceEquals를 사용할 수 없습니다. 대신 Assert.AreSame 및 오버로드를 사용하세요. - - Type '{0}' is not assignable to '{1}'. - '{0}' 형식은 '{1}'에 할당할 수 없습니다. - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + 어설션에 StringAssert.Equals를 사용할 수 없습니다. 대신 StringAssert 메서드 또는 Assert.AreEqual 및 오버로드를 사용하세요. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + StringAssert.ReferenceEquals는 Assertions에 사용할 수 없습니다. 대신 StringAssert 메서드 또는 Assert.AreSame 및 오버로드를 사용하세요. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + 어설션에 CollectionAssert.Equals를 사용할 수 없습니다. 대신 CollectionAssert.AreEqual 및 오버로드를 사용하세요. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + CollectionAssert.ReferenceEquals는 Assertions에 사용할 수 없습니다. 대신 CollectionAssert 메서드 또는 Assert.AreSame 및 오버로드를 사용하세요. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf index 41afe70660..3482be7955 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf @@ -82,14 +82,54 @@ Ciąg „{0}” nie zawiera ciągu „{1}”. {2}. + + Expected collection to contain the specified item. {0} + Oczekiwano, że kolekcja będzie zawierać określony element. {0} + + + + Expected at least one item to match the predicate. {0} + Oczekiwano co najmniej jednego elementu zgodnego z predykatem. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + Oczekiwano, że kolekcja będzie zawierać dokładnie jeden element, ale znaleziono {1} elementów. {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + Oczekiwano dokładnie jednego elementu zgodnego z predykatem, ale znaleziono {1} elementów. {0} + + String '{0}' does contain string '{1}'. {2}. Ciąg „{0}” zawiera ciąg „{1}”. {2}. + + Expected collection to not contain the specified item. {0} + Oczekiwano, że kolekcja nie będzie zawierać określonego elementu. {0} + + + + Expected no items to match the predicate. {0} + Nie oczekiwano elementów zgodnych z predykatem. {0} + + + + String '{0}' ends with string '{1}'. {2} + Ciąg „{0}” kończy się ciągiem „{1}”. {2} + + + + String '{0}' starts with string '{1}'. {2} + Ciąg „{0}” rozpoczyna się od ciągu „{1}”. {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - Metoda danych dynamicznych „{0}” powinna być statyczna, bez parametrów i nie generyczna. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + Metoda danych dynamicznych „{0}” powinna być statyczna, niestandardowa i nie może mieć parametru „params”. @@ -122,9 +162,9 @@ Rzeczywiste: {2} - String '{0}' does not end with string '{1}'. {2}. - Ciąg „{0}” nie kończy się ciągiem „{1}”. {2}. - + String '{0}' does not end with string '{1}'. {2} + Ciąg „{0}” nie kończy się ciągiem „{1}”. {2} + {0} failed. {1} @@ -141,15 +181,20 @@ Rzeczywiste: {2} Nieprawidłowy adres URL biletu usługi GitHub + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + Wartość „{0}” nie mieści się w oczekiwanym zakresie [{1}, {2}]. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} Oczekiwany typ:<{1}>. Rzeczywisty typ:<{2}>. - String '{0}' does not match pattern '{1}'. {2}. - Ciąg „{0}” nie jest zgodny ze wzorcem „{1}”. {2}. - + String '{0}' does not match pattern '{1}'. {2} + Ciąg „{0}” nie jest zgodny ze wzorcem „{1}”. {2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Rzeczywiste: {2} - String '{0}' matches pattern '{1}'. {2}. - Ciąg „{0}” jest zgodny ze wzorcem „{1}”. {2}. - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Assert.Equals nie powinno być używane do potwierdzania. Zamiast tego użyj Assert.AreEqual i przeciążeń. - + String '{0}' matches pattern '{1}'. {2} + Ciąg „{0}” jest zgodny ze wzorcem „{1}”. {2} + @@ -182,7 +222,7 @@ Rzeczywiste: {2} lub składowa może być zdefiniowana jako prywatna w klasie bazowej. W drugim przypadku należy przekazać typ, który definiuje składową w konstruktorze obiektu PrivateObject. - + @@ -195,7 +235,7 @@ Rzeczywiste: {2} lub składowa może być zdefiniowana jako prywatna w klasie bazowej. W drugim przypadku należy przekazać typ, który definiuje składową w konstruktorze obiektu PrivateObject. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Rzeczywiste: {2} - String '{0}' does not start with string '{1}'. {2}. - Ciąg „{0}” nie rozpoczyna się od ciągu „{1}”. {2}. - + String '{0}' does not start with string '{1}'. {2} + Ciąg „{0}” nie rozpoczyna się od ciągu „{1}”. {2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Rzeczywiste: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - asynchroniczna metoda TestMethod z elementem UITestMethodAttribute nie są obsługiwane. Usuń element asynchroniczny lub użyj elementu TestMethodAttribute. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. Właściwości lub metody {0} dla zwracanego typu {1} nie można przypisać do elementu „IEnumerable”. @@ -297,18 +332,65 @@ Rzeczywiste: {2} Właściwość lub metoda {0} w elemencie {1} zwraca pusty interfejs IEnumerable<object[]>. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - Element UITestMethodAttribute.DispatcherQueue nie powinien mieć wartości null. Aby użyć atrybutu UITestMethodAttribute w aplikacji klasycznej WinUI, pamiętaj o ustawieniu statycznego atrybutu UITestMethodAttribute.DispatcherQueue podczas inicjowania testu. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + Wartość rzeczywista <{2}> nie jest większa niż oczekiwana wartość <{1}>. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + Wartość rzeczywista <{2}> nie jest większa lub równa oczekiwanej wartości <{1}>. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + Wartość rzeczywista <{2}> nie jest mniejsza niż oczekiwana wartość <{1}>. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + Wartość rzeczywista <{2}> nie jest mniejsza lub równa oczekiwanej wartości <{1}>. {0} + + + + Expected value <{1}> to be positive. {0} + Oczekiwana wartość <{1}> powinna być dodatnia. {0} + + + + Expected value <{1}> to be negative. {0} + Oczekiwana wartość <{1}> powinna być negatywna. {0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Assert.Equals nie powinno być używane do potwierdzania. Zamiast tego użyj Assert.AreEqual i przeciążeń. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Element Assert.ReferenceEquals nie powinien być używany dla asercji. Zamiast tego użyj metody Assert.AreSame i przeciążeń. - - Type '{0}' is not assignable to '{1}'. - Typu „{0}” nie można przypisać do typu „{1}”. - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + Element StringAssert.Equals nie powinien być używany dla asercji. Zamiast tego użyj metod StringAssert lub Assert.AreEqual i przeciążeń. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + Element StringAssert.ReferenceEquals nie powinien być używany dla asercji. Zamiast tego użyj metod StringAssert lub Assert.AreSame i obciążeń. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + Element CollectionAssert.Equals nie powinien być używany dla asercji. Zamiast tego użyj metody CollectionAssert.AreEqual i przeciążeń. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + Element Assert.ReferenceEquals nie powinien być używany dla asercji. Zamiast tego użyj metod CollectionAssert lub Assert.AreSame oraz ich przeciążeń. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf index 8078eeba69..78710455a7 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf @@ -82,14 +82,54 @@ A cadeia de caracteres '{0}' não contém a cadeia de caracteres '{1}'. {2}. + + Expected collection to contain the specified item. {0} + A coleção esperada contém o item especificado. {0} + + + + Expected at least one item to match the predicate. {0} + Esperava-se que pelo menos um item correspondesse ao predicado. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + A coleção esperada contém exatamente um elemento, mas encontrou {1} elementos. {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + Esperava-se exatamente um item para corresponder ao predicado, mas encontrou {1} itens. {0} + + String '{0}' does contain string '{1}'. {2}. A cadeia de caracteres "{0}" contém a cadeia de caracteres "{1}". {2}. + + Expected collection to not contain the specified item. {0} + A coleção esperada não contém o item especificado. {0} + + + + Expected no items to match the predicate. {0} + Não era esperado nenhum item que corresponda ao predicado. {0} + + + + String '{0}' ends with string '{1}'. {2} + A cadeia de caracteres “{0}” termina com cadeia de caracteres “{1}”. {2} + + + + String '{0}' starts with string '{1}'. {2} + A cadeia de caracteres “{0}” começa com a cadeia de caracteres “{1}”. {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - O método de dados dinâmicos "{0}" deve ser estático, sem parâmetros e não genérico. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + O método de dados dinâmicos '{0}' deve ser estático, não genérico e não pode ter um parâmetro 'params'. @@ -122,9 +162,9 @@ Real: {2} - String '{0}' does not end with string '{1}'. {2}. - A cadeia de caracteres '{0}' não termina com a cadeia de caracteres '{1}'. {2}. - + String '{0}' does not end with string '{1}'. {2} + A cadeia de caracteres “{0}” não termina com a cadeia de caracteres “{1}”. {2} + {0} failed. {1} @@ -141,15 +181,20 @@ Real: {2} URL de tíquete do GitHub inválida + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + O valor '{0}' não está dentro do intervalo esperado [{1}, {2}]. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} Tipo esperado:<{1}>. Tipo real:<{2}>. - String '{0}' does not match pattern '{1}'. {2}. - A cadeia de caracteres '{0}' não corresponde ao padrão '{1}'. {2}. - + String '{0}' does not match pattern '{1}'. {2} + A cadeia de caracteres “{0}” não corresponde ao padrão “{1}”. {2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Real: {2} - String '{0}' matches pattern '{1}'. {2}. - A cadeia de caracteres '{0}' corresponde ao padrão '{1}'. {2}. - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Assert.Equals não deveria ser usado para Declarações. Use Assert.AreEqual e sobrecargas em seu lugar. - + String '{0}' matches pattern '{1}'. {2} + A cadeia de caracteres “{0}” corresponde ao padrão “{1}”. {2} + @@ -182,7 +222,7 @@ Real: {2} ou o membro pode ser particular e definido em uma classe base. Se o último caso for verdadeiro, será necessário passar o tipo que define o membro no construtor do PrivateObject. - + @@ -195,7 +235,7 @@ Real: {2} ou o membro pode ser particular e definido em uma classe base. Se o último caso for verdadeiro, será necessário passar o tipo que define o membro para o construtor do PrivateObject. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Real: {2} - String '{0}' does not start with string '{1}'. {2}. - A cadeia de caracteres '{0}' não começa com a cadeia de caracteres '{1}'. {2}. - + String '{0}' does not start with string '{1}'. {2} + A cadeia de caracteres “{0}” não começa com a cadeia de caracteres “{1}”. {2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Real: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - TestMethod assíncrono com UITestMethodAttribute não têm suporte. Remova o assíncrono ou use o TestMethodAttribute. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. A propriedade ou o método {0} no tipo de retorno {1} não podem ser atribuídos a "IEnumerable". @@ -297,18 +332,65 @@ Real: {2} A propriedade ou o método {0} em {1} retorna um IEnumerable<object[]> vazio. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue não deve ser nulo. Para usar UITestMethodAttribute em um aplicativo WinUI Desktop, lembre-se de definir o UITestMethodAttribute.DispatcherQueue estático durante a inicialização do teste. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + O valor <{2}> real não é maior que o valor esperado <{1}>. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + O valor <{2}> real não é maior ou igual ao valor esperado <{1}>. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + O valor <{2}> real não é menor que o valor esperado <{1}>. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + O valor <{2}> real não é menor ou igual ao valor esperado <{1}>. {0} + + + + Expected value <{1}> to be positive. {0} + O valor <{1}> esperado deve ser positivo. {0} + + + + Expected value <{1}> to be negative. {0} + O valor <{1}> esperado deve ser negativo. {0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Assert.Equals não deveria ser usado para Declarações. Use Assert.AreEqual e sobrecargas em seu lugar. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Assert.ReferenceEquals não deve ser usado com as Declarações. Em vez disso, use Assert.AreSame e as sobrecargas. - - Type '{0}' is not assignable to '{1}'. - Tipo '{0}' não é atribuível a '{1}'. - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + StringAssert.Equals não deve ser usado com as Declarações. Em vez disso, use os métodos StringAssert ou Assert.AreEqual e as sobrecargas. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + StringAssert.ReferenceEquals não deve ser usado com as Declarações. Em vez disso, use os métodos StringAssert ou Assert.AreSame e as sobrecargas. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + CollectionAssert.Equals não deve ser usado com as Declarações. Em vez disso, use CollectionAssert.AreEqual e as sobrecargas. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + CollectionAssert.ReferenceEquals não deve ser usado com as Declarações. Em vez disso, use os métodos CollectionAssert ou Assert.AreSame e as sobrecargas. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf index f27e54ae56..00f8b5968b 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf @@ -82,14 +82,54 @@ Строка "{0}" не содержит строку "{1}". {2}. + + Expected collection to contain the specified item. {0} + Ожидалось, что коллекция будет содержать указанный элемент. {0} + + + + Expected at least one item to match the predicate. {0} + Ожидался по крайней мере один элемент, соответствующий предикату. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + Ожидалось, что коллекция будет содержать ровно один элемент, но найдено элементов: {1}. {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + Ожидался ровно один элемент, соответствующий предикату, но найдено элементов: {1}. {0} + + String '{0}' does contain string '{1}'. {2}. Строка "{0}" не содержит строку "{1}". {2}. + + Expected collection to not contain the specified item. {0} + Ожидалось, что коллекция не будет содержать указанный элемент. {0} + + + + Expected no items to match the predicate. {0} + Ожидалось, что ни один элемент не будет соответствовать предикату. {0} + + + + String '{0}' ends with string '{1}'. {2} + Строка "{0}" заканчивается строкой "{1}". {2} + + + + String '{0}' starts with string '{1}'. {2} + Строка "{0}" начинается со строки "{1}". {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - Метод динамических данных "{0}" должен быть статическим, не иметь параметров и быть неуниверсальным. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + Метод динамических данных "{0}" должен быть статическим, неуниверсальным и не может иметь содержать параметр params. @@ -122,9 +162,9 @@ Actual: {2} - String '{0}' does not end with string '{1}'. {2}. - Строка "{0}" не оканчивается строкой "{1}". {2}. - + String '{0}' does not end with string '{1}'. {2} + Строка "{0}" не заканчивается строкой "{1}". {2} + {0} failed. {1} @@ -141,15 +181,20 @@ Actual: {2} Недопустимый URL-адрес билета GitHub + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + Значение "{0}" не находится в пределах ожидаемого диапазона [{1}, {2}]. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0}Ожидается тип: <{1}>. Фактический тип: <{2}>. - String '{0}' does not match pattern '{1}'. {2}. - Строка "{0}" не соответствует шаблону "{1}". {2}. - + String '{0}' does not match pattern '{1}'. {2} + Строка "{0}" не соответствует шаблону "{1}". {2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Actual: {2} - String '{0}' matches pattern '{1}'. {2}. - Строка "{0}" соответствует шаблону "{1}". {2}. - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Нельзя использовать Assert.Equals для Assertions. Вместо этого используйте Assert.AreEqual и перегрузки. - + String '{0}' matches pattern '{1}'. {2} + Строка "{0}" соответствует шаблону "{1}". {2} + @@ -182,7 +222,7 @@ Actual: {2} либо член является закрытым и определенным на основе базового класса. Если справедливо последнее, то необходимо передать тип, определяющий член, в конструктор для PrivateObject. - + @@ -195,7 +235,7 @@ Actual: {2} метод доступа либо член является закрытым и определенным на основе базового класса. Если справедливо последнее, то необходимо передать тип, определяющий член, в конструктор для PrivateObject. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Actual: {2} - String '{0}' does not start with string '{1}'. {2}. - Строка "{0}" не начинается со строки "{1}". {2}. - + String '{0}' does not start with string '{1}'. {2} + Строка "{0}" не начинается со строки "{1}". {2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Actual: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - Асинхронный метод TestMethod с UITestMethodAttribute не поддерживается. Удалите префикс async или используйте TestMethodAttribute. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. Свойство или метод {0} в {1} тип возвращаемого значения не может быть назначен "IEnumerable". @@ -297,18 +332,65 @@ Actual: {2} Свойство или метод {0} класса {1} возвращает пустой IEnumerable<object[]>. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - Параметр UITestMethodAttribute.DispatcherQueue не должен иметь значение NULL. Чтобы использовать параметр UITestMethodAttribute в классических приложениях WinUI, не забудьте задать статический параметр UITestMethodAttribute.DispatcherQueue во время инициализации теста. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + Действительное значение <{2}> не больше ожидаемого значения <{1}>. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + Действительное значение <{2}> не больше или не равно ожидаемому значению <{1}>. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + Действительное значение <{2}> не меньше ожидаемого значения <{1}>. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + Действительное значение <{2}> не меньше или не равно ожидаемому значению <{1}>. {0} + + + + Expected value <{1}> to be positive. {0} + Ожидалось, что значение <{1}> будет положительным. {0} + + + + Expected value <{1}> to be negative. {0} + Ожидалось, что значение <{1}> будет отрицательным. {0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Нельзя использовать Assert.Equals для Assertions. Вместо этого используйте Assert.AreEqual и перегрузки. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Нельзя использовать Assert.ReferenceEquals для Assertions. Вместо этого используйте Assert.AreSame и перегрузки. - - Type '{0}' is not assignable to '{1}'. - Тип "{0}" не может быть назначен "{1}". - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + Нельзя использовать StringAssert.Equals для Assertions. Вместо этого используйте методы StringAssert или Assert.AreEqual и перегрузки. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + Нельзя использовать StringAssert.ReferenceEquals для Assertions. Вместо этого используйте методы StringAssert или Assert.AreSame и перегрузки. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + Нельзя использовать CollectionAssert.Equals для Assertions. Вместо этого используйте CollectionAssert.AreEqual и перегрузки. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + Нельзя использовать CollectionAssert.ReferenceEquals для Assertions. Вместо этого используйте методы CollectionAssert или Assert.AreSame и перегрузки. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf index 6ba4ddec3d..db8f3f9bc8 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf @@ -82,14 +82,54 @@ '{0}' dizesi, '{1}' dizesini içermiyor. {2}. + + Expected collection to contain the specified item. {0} + Koleksiyonun belirtilen öğeyi içermesi bekleniyordu. {0} + + + + Expected at least one item to match the predicate. {0} + En az bir öğenin koşulla eşleşmesi bekleniyordu. {0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + Beklenen koleksiyonun tam olarak bir öğe içermesi beklenirken, {1} öğe bulundu. {0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + Özellikle bir öğenin koşulla eşleşmesi beklenirken {1} öğe bulundu. {0} + + String '{0}' does contain string '{1}'. {2}. '{0}' dizesi, '{1}' dizesini içermiyor. {2}. + + Expected collection to not contain the specified item. {0} + Koleksiyonun belirtilen öğeyi içermemesi bekleniyordu. {0} + + + + Expected no items to match the predicate. {0} + Hiçbir öğenin koşulla eşleşmesi beklenmiyordu. {0} + + + + String '{0}' ends with string '{1}'. {2} + '{0}' dizesi '{1}' dizesi ile bitiyor. {2} + + + + String '{0}' starts with string '{1}'. {2} + '{0}' dizesi '{1}' dizesi ile başlıyor. {2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - '{0}' dinamik veri yöntemi statik ve parametresiz olmalı ve genel olmamalıdır. + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + Dinamik veri yöntemi ‘{0}’ statik, genel olmayan ve ‘params’ parametresine sahip olamaz. @@ -122,9 +162,9 @@ Gerçekte olan: {2} - String '{0}' does not end with string '{1}'. {2}. - '{0}' dizesi, '{1}' dizesi ile sonlanmıyor. {2}. - + String '{0}' does not end with string '{1}'. {2} + '{0}' dizesi, '{1}' dizesi ile sonlanmıyor. {2} + {0} failed. {1} @@ -141,15 +181,20 @@ Gerçekte olan: {2} Geçersiz GitHub anahtar URL'si + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + '{0}' değeri beklenen aralıkta [{1}, {2}] değil. {3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} Beklenen tür:<{1}>. Gerçek tür:<{2}>. - String '{0}' does not match pattern '{1}'. {2}. - '{0}' dizesi, '{1}' deseni ile eşleşmiyor. {2}. - + String '{0}' does not match pattern '{1}'. {2} + '{0}' dizesi, '{1}' deseni ile eşleşmiyor. {2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Gerçekte olan: {2} - String '{0}' matches pattern '{1}'. {2}. - '{0}' dizesi, '{1}' deseni ile eşleşiyor. {2}. - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Assert.Equals, Onaylama için kullanılmamalı. Lütfen yerine Assert.AreEqual & aşırı yüklemeleri kullanın. - + String '{0}' matches pattern '{1}'. {2} + '{0}' dizesi, '{1}' deseni ile eşleşiyor. {2} + @@ -182,7 +222,7 @@ Gerçekte olan: {2} veya üye, özel olabilir ve temel sınıfta tanımlı olabilir. Eğer ikincisi doğru ise, türü geçirmeniz gerekir; bu tür PrivateObject'in oluşturucusunda üyeyi tanımlar. - + @@ -195,7 +235,7 @@ Gerçekte olan: {2} veya üye, özel olabilir ve temel sınıfta tanımlı olabilir. Eğer ikincisi doğru ise, türü geçirmeniz gerekir; bu tür, PrivateObject'in oluşturucusunda üyeyi tanımlar. - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Gerçekte olan: {2} - String '{0}' does not start with string '{1}'. {2}. - '{0}' dizesi, '{1}' dizesi ile başlamıyor. {2}. - + String '{0}' does not start with string '{1}'. {2} + '{0}' dizesi, '{1}' dizesi ile başlamıyor. {2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Gerçekte olan: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - UITestMethodAttribute özniteliğine sahip async TestMethod metodu desteklenmiyor. async ifadesini kaldırın ya da TestMethodAttribute özniteliğini kullanın. - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. {1} dönüş türündeki {0} özelliği veya yöntemi 'IEnumerable' öğesine atanamaz. @@ -297,18 +332,65 @@ Gerçekte olan: {2} {1} üzerindeki {0} özelliği veya metodu boş IEnumerable<object[]> döndürür. - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue boş olmamalıdır. UITestMethodAttribute'ı bir WinUI Masaüstü Uygulamasında kullanmak için, test başlatma sırasında statik UITestMethodAttribute.DispatcherQueue'yu ayarlamayı unutmayın. + + Actual value <{2}> is not greater than expected value <{1}>. {0} + Geçerli <{2}> değeri, beklenen <{1}> değerinden daha büyük değil. {0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + Geçerli <{2}> değeri, beklenen <{1}> değerinden büyük veya bu değere eşit değil. {0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + Geçerli <{2}> değeri, beklenen <{1}> değerinden daha küçük değil. {0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + Geçerli <{2}> değeri, beklenen <{1}> değerinden küçük veya bu değere eşit değil. {0} + + + + Expected value <{1}> to be positive. {0} + Beklenen <{1}> değeri pozitif olmalıdır. {0} + + + + Expected value <{1}> to be negative. {0} + Beklenen <{1}> değeri negatif olmalıdır. {0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Assert.Equals, Onaylama için kullanılmamalı. Lütfen yerine Assert.AreEqual & aşırı yüklemeleri kullanın. + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Assert.ReferenceEquals, Onaylama için kullanılmamalı. Lütfen yerine Assert.AreSame & aşırı yüklemeleri kullanın. - - Type '{0}' is not assignable to '{1}'. - '{0}' tipi '{1}'ye atanamaz. - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + StringAssert.Equals, Onaylama için kullanılmamalı. Lütfen bunun yerine StringAssert yöntemlerini veya Assert.AreEqual & aşırı yüklemelerini kullanın. + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + StringAssert.ReferenceEquals, Onaylama için kullanılmamalı. Lütfen bunun yerine StringAssert yöntemlerini veya Assert.AreSame & aşırı yüklemelerini kullanın. + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + CollectionAssert.Equals, Onaylama için kullanılmamalı. Lütfen yerine CollectionAssert.AreEqual & aşırı yüklemeleri kullanın. + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + CollectionAssert.ReferenceEquals, Onaylama için kullanılmamalı. Lütfen bunun yerine CollectionAssert yöntemlerini veya Assert.AreSame & aşırı yüklemelerini kullanın. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf index f8f3b68731..fa0014b034 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf @@ -82,14 +82,54 @@ 字符串“{0}”不包含字符串“{1}”。{2}。 + + Expected collection to contain the specified item. {0} + 预期集合包含指定项。{0} + + + + Expected at least one item to match the predicate. {0} + 应至少有一项与谓词匹配。{0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + 预期集合仅包含一个元素,但找到 {1} 个元素。{0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + 应恰好只有一项与谓词匹配,但找到 {1} 项。{0} + + String '{0}' does contain string '{1}'. {2}. 字符串“{0}”确实包含字符串“{1}”。{2} + + Expected collection to not contain the specified item. {0} + 预期集合不包含指定项。{0} + + + + Expected no items to match the predicate. {0} + 预期没有与谓词匹配的项。{0} + + + + String '{0}' ends with string '{1}'. {2} + 字符串 '{0}' 以字符串 '{1}'结尾。{2} + + + + String '{0}' starts with string '{1}'. {2} + 字符串 '{0}' 以字符串 '{1}' 开头。{2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - 动态数据方法“{0}”应为静态、无参数和非泛型。 + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + 动态数据方法 ‘{0}’ 应为静态、非泛型,并且不能具有 ‘params’ 参数。 @@ -122,9 +162,9 @@ Actual: {2} - String '{0}' does not end with string '{1}'. {2}. - 字符串“{0}”不以字符串“{1}”结尾。{2}。 - + String '{0}' does not end with string '{1}'. {2} + 字符串 '{0}' 不以字符串 '{1}' 结尾。{2} + {0} failed. {1} @@ -141,15 +181,20 @@ Actual: {2} GitHub 票证 URL 无效 + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + 值“{0}”不在预期范围 [{1}, {2}] 内。{3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} 类型应为: <{1}>。类型实为: <{2}>。 - String '{0}' does not match pattern '{1}'. {2}. - 字符串“{0}”与模式“{1}”不匹配。{2}。 - + String '{0}' does not match pattern '{1}'. {2} + 字符串 '{0}' 与模式 '{1}' 不匹配。{2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Actual: {2} - String '{0}' matches pattern '{1}'. {2}. - 字符串“{0}”与模式“{1}”匹配。{2}。 - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Assert.Equals 不应用于断言。请改用 Assert.AreEqual 和重载。 - + String '{0}' matches pattern '{1}'. {2} + 字符串 '{0}' 与模式 '{1}' 匹配。{2} + @@ -182,7 +222,7 @@ Actual: {2} 或者该成员可能是私有成员并且是在基类上定义的。如果属于后一种情况,则需要将定义 该成员的类型传递到 PrivateObject 的构造函数中。 - + @@ -195,7 +235,7 @@ Actual: {2} 或者该成员可能是私有成员并且是在基类上定义的。如果属于后一种情况,则需要将定义 该成员的类型传递到 PrivateObject 的构造函数。 - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Actual: {2} - String '{0}' does not start with string '{1}'. {2}. - 字符串“{0}”没有以字符串“{1}”开头。{2}。 - + String '{0}' does not start with string '{1}'. {2} + 字符串 '{0}' 不以字符串 '{1}' 开头。{2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Actual: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - 不支持具有 UITestMethodAttribute 的异步 TestMethod。请删除异步或使用 TestMethodAttribute。 - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. {1} 返回类型上的属性或方法 {0} 不能分配给 "IEnumerable"。 @@ -297,18 +332,65 @@ Actual: {2} {1} 上的属性或方法 {0} 返回空 IEnumerable<object[]>。 - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue 不应为 null。若要在 WinUI 桌面应用中使用 UITestMethodAttribute,请在测试初始化期间设置静态 UITestMethodAttribute.DispatcherQueue。 + + Actual value <{2}> is not greater than expected value <{1}>. {0} + 实际值 <{2}> 不大于预期值 <{1}>。{0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + 实际值 <{2}> 不大于或等于预期值 <{1}>。{0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + 实际值 <{2}> 不小于预期值 <{1}>。{0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + 实际值 <{2}> 不小于或等于预期值 <{1}>。{0} + + + + Expected value <{1}> to be positive. {0} + 预期值 <{1}> 为正值。{0} + + + + Expected value <{1}> to be negative. {0} + 预期值 <{1}> 为负值。{0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Assert.Equals 不应用于断言。请改用 Assert.AreEqual 和重载。 + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Assert.ReferenceEquals 不应用于断言。请改用 Assert.AreSame 和重载。 - - Type '{0}' is not assignable to '{1}'. - 类型“{0}”不能分配给“{1}”。 - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + StringAssert.Equals 不应用于断言。请改用 StringAssert 方法或 Assert.AreEqual 和重载。 + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + StringAssert.ReferenceEquals 不应用于断言。请改用 StringAssert 方法或 Assert.AreSame 和重载。 + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + CollectionAssert.Equals 不应用于断言。请改用 CollectionAssert.AreEqual 和重载。 + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + CollectionAssert.ReferenceEquals 不应用于断言。请改用 CollectionAssert 方法或 Assert.AreSame 和重载。 + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf index 49aa1e77f7..e4688b69d9 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf @@ -82,14 +82,54 @@ 字串 '{0}' 未包含字串 '{1}'。{2}。 + + Expected collection to contain the specified item. {0} + 預期集合包含指定的項目。{0} + + + + Expected at least one item to match the predicate. {0} + 必須至少有一個項目符合述詞。{0} + + + + Expected collection to contain exactly one element but found {1} element(s). {0} + 預期集合應僅包含一個元素,但發現 {1} 個元素。{0} + + + + Expected exactly one item to match the predicate but found {1} item(s). {0} + 預期只有一個項目符合述詞,但找到 {1} 個項目。{0} + + String '{0}' does contain string '{1}'. {2}. 字串 '{0}' 有包含字串 '{1}'。{2}。 + + Expected collection to not contain the specified item. {0} + 預期集合不包含指定的項目。{0} + + + + Expected no items to match the predicate. {0} + 預期沒有任何項目符合述詞。{0} + + + + String '{0}' ends with string '{1}'. {2} + 字串 '{0}' 以字串 '{1}' 結尾。{2} + + + + String '{0}' starts with string '{1}'. {2} + 字串 '{0}' 以字串 '{1}' 開頭。{2} + + - Dynamic data method '{0}' should be static, parameterless and non-generic. - 動態資料方法 '{0}' 應為靜態、無參數及非泛型。 + Dynamic data method '{0}' should be static, non-generic, and cannot have 'params' parameter. + 動態資料方法 '{0}' 應該是靜態、非一般,而且不能有 'params' 參數。 @@ -122,9 +162,9 @@ Actual: {2} - String '{0}' does not end with string '{1}'. {2}. - 字串 '{0}' 不是以字串 '{1}' 結尾。{2}。 - + String '{0}' does not end with string '{1}'. {2} + 字串 '{0}' 不是以字串 '{1}' 結尾。{2} + {0} failed. {1} @@ -141,15 +181,20 @@ Actual: {2} 無效的 GitHub 票證 URL + + Value '{0}' is not within the expected range [{1}, {2}]. {3} + 值 '{0}' 不在預期的範圍 [{1}, {2}] 內。{3} + + {0} Expected type:<{1}>. Actual type:<{2}>. {0} 預期的類型: <{1}>,實際的類型: <{2}>。 - String '{0}' does not match pattern '{1}'. {2}. - 字串 '{0}' 與模式 '{1}' 不符。{2}。 - + String '{0}' does not match pattern '{1}'. {2} + 字串 '{0}' 與模式 '{1}' 不符。{2} + Expected collection to contain any item but it is empty. {0} @@ -162,14 +207,9 @@ Actual: {2} - String '{0}' matches pattern '{1}'. {2}. - 字串 '{0}' 與模式 '{1}' 相符。{2}。 - - - - Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. - Assert.Equals 不應使用於判斷提示。請改用 Assert.AreEqual 及多載。 - + String '{0}' matches pattern '{1}'. {2} + 字串 '{0}' 與模式 '{1}' 相符。{2} + @@ -182,7 +222,7 @@ Actual: {2} 或者該成員可能為私用,並且定義在基底類別上。如果是後者, 您必須將定義該成員的類型傳遞至 PrivateObject 的建構函式。 - + @@ -195,7 +235,7 @@ Actual: {2} 或者該成員可能為私用,並且定義在基底類別上。如果是後者,您必須 將定義該成員的類型傳遞至 PrivateObject 的建構函式。 - + The parameter '{0}' is invalid. The value cannot be null. {1}. @@ -208,9 +248,9 @@ Actual: {2} - String '{0}' does not start with string '{1}'. {2}. - 字串 '{0}' 不是以字串 '{1}' 開頭。{2}。 - + String '{0}' does not start with string '{1}'. {2} + 字串 '{0}' 不是以字串 '{1}' 開頭。{2} + The property {0} has type {1}; expected type {2}. @@ -272,11 +312,6 @@ Actual: {2} {0} ({1}) - - async TestMethod with UITestMethodAttribute are not supported. Either remove async or use TestMethodAttribute. - 不支援有 UITestMethodAttribute 的 async TestMethod。請移除 async 或使用 TestMethodAttribute。 - - Property or method {0} on {1} return type is not assignable to 'IEnumerable'. {1} 傳回類型上的屬性或方法 {0} 無法指派給 'IEnumerable'。 @@ -297,18 +332,65 @@ Actual: {2} {1} 上的屬性或方法 {0} 傳回空的 IEnumerable<object[]>。 - - UITestMethodAttribute.DispatcherQueue should not be null. To use UITestMethodAttribute within a WinUI Desktop App, remember to set the static UITestMethodAttribute.DispatcherQueue during the test initialization. - UITestMethodAttribute.DispatcherQueue 不應為 Null。若要在 WinUI 傳統型應用程式內使用 UITestMethodAttribute,請記得在測試初始化期間設定靜態 UITestMethodAttribute.DispatcherQueue。 + + Actual value <{2}> is not greater than expected value <{1}>. {0} + 實際值 <{2}> 不大於預期值 <{1}>。{0} + + + + Actual value <{2}> is not greater than or equal to expected value <{1}>. {0} + 實際值 <{2}> 不大於或等於預期值 <{1}>。{0} + + + + Actual value <{2}> is not less than expected value <{1}>. {0} + 實際值 <{2}> 不小於預期值 <{1}>。{0} + + + + Actual value <{2}> is not less than or equal to expected value <{1}>. {0} + 實際值 <{2}> 不小於或等於預期值 <{1}>。{0} + + + + Expected value <{1}> to be positive. {0} + 預期值 <{1}> 為正數。{0} + + + + Expected value <{1}> to be negative. {0} + 預期值 <{1}> 為負數。{0} + + + + Assert.Equals should not be used for Assertions. Please use Assert.AreEqual & overloads instead. + Assert.Equals 不應使用於判斷提示。請改用 Assert.AreEqual 及多載。 + + + + Assert.ReferenceEquals should not be used for Assertions. Please use Assert.AreSame & overloads instead. + Assert.ReferenceEquals 不應使用於判斷提示。請改用 Assert.AreSame 及多載。 - - Type '{0}' is not assignable to '{1}'. - 無法將類型 '{0}' {0} 指派給 '{1}。 - - - {0} argument name like "applicationType" - - {1} fully qualified class name like "Microsoft.UI.Xaml.Application" - + + StringAssert.Equals should not be used for Assertions. Please use StringAssert methods or Assert.AreEqual & overloads instead. + StringAssert.Equals 不應使用於判斷提示。請改用 StringAssert 方法或 Assert.AreEqual 及其多載。 + + + + StringAssert.ReferenceEquals should not be used for Assertions. Please use StringAssert methods or Assert.AreSame & overloads instead. + StringAssert.ReferenceEquals 不應使用於判斷提示。請改用 StringAssert 方法或 Assert.AreSame 及其多載。 + + + + CollectionAssert.Equals should not be used for Assertions. Please use CollectionAssert.AreEqual & overloads instead. + CollectionAssert.Equals 不應使用於判斷提示。請改用 CollectionAssert.AreEqual 及多載。 + + + + CollectionAssert.ReferenceEquals should not be used for Assertions. Please use CollectionAssert methods or Assert.AreSame & overloads instead. + CollectionAssert.ReferenceEquals 不應使用於判斷提示。請改用 CollectionAssert 方法或 Assert.AreSame 及其多載。 + diff --git a/src/TestFramework/TestFramework/TestDataRow.cs b/src/TestFramework/TestFramework/TestDataRow.cs index bd271d9c69..ff3a433e2a 100644 --- a/src/TestFramework/TestFramework/TestDataRow.cs +++ b/src/TestFramework/TestFramework/TestDataRow.cs @@ -13,11 +13,13 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; [DataContract] public sealed class TestDataRow : ITestDataRow { +#pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Initializes a new instance of the class. /// - /// The value to be held by this instance, which could be a or if the test method has more than one parameter. + /// The value to be held by this instance, which could be a or if the test method has more than one parameter. public TestDataRow(T value) +#pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => Value = value; /// @@ -38,6 +40,12 @@ public TestDataRow(T value) [DataMember] public string? DisplayName { get; set; } + /// + /// Gets or sets the test categories for the test case. + /// + [DataMember] + public IList? TestCategories { get; set; } + /// object? ITestDataRow.Value => Value; } diff --git a/src/TestFramework/TestFramework/TestFramework.csproj b/src/TestFramework/TestFramework/TestFramework.csproj index a48363f7b4..265bc3d974 100644 --- a/src/TestFramework/TestFramework/TestFramework.csproj +++ b/src/TestFramework/TestFramework/TestFramework.csproj @@ -8,7 +8,7 @@ Microsoft.VisualStudio.TestTools.UnitTesting Microsoft.VisualStudio.TestPlatform.TestFramework - TRACE + $(DefineConstants);TRACE @@ -33,9 +33,14 @@ - - + + + + + + + diff --git a/test/.editorconfig b/test/.editorconfig index 4ffa71b86f..58ccc42e50 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -25,6 +25,10 @@ dotnet_diagnostic.CA1822.severity = none # CA1822: Mark members as st dotnet_diagnostic.CA1852.severity = none # CA1852: Type can be sealed dotnet_diagnostic.CA1859.severity = none # CA1859: Change return type to be more specific dotnet_diagnostic.CA1861.severity = none # CA1861: Avoid constant arrays as arguments + +# CA2007: Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.CA2007.severity = none + dotnet_diagnostic.CA2201.severity = none # CA2201: Do not raise reserved exception types dotnet_diagnostic.CA3075.severity = none # CA3075: Insecure DTD processing in XML diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 7b462d3b5c..09674c87fb 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -16,6 +16,8 @@ $(DefineConstants);ENABLE_CODECOVERAGE false + false + $(NoWarn);SA0001;EnableGenerateDocumentationFile diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index 2980dfd99e..8d8896cb3d 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -11,23 +11,26 @@ x64 $(MSBuildProjectName)_$(TargetFramework)_$(Configuration)_$(Architecture) - - $(TestRunnerAdditionalArguments) --diagnostic --diagnostic-output-directory $(RepoRoot)artifacts/log/$(Configuration) --diagnostic-output-fileprefix $(ModuleName) --diagnostic-verbosity trace - $(TestRunnerAdditionalArguments) --crashdump - $(TestRunnerAdditionalArguments) --hangdump --hangdump-timeout 15m - $(TestRunnerAdditionalArguments) --coverage --coverage-settings $(RepoRoot)test/coverage.config --coverage-output $(ModuleName).coverage - + Recommended - + $(TestingPlatformCommandLineArguments) --diagnostic --diagnostic-output-directory $(RepoRoot)artifacts/log/$(Configuration) --diagnostic-output-fileprefix $(ModuleName) --diagnostic-verbosity trace + $(TestingPlatformCommandLineArguments) --crashdump + $(TestingPlatformCommandLineArguments) --hangdump --hangdump-timeout 15m + $(TestingPlatformCommandLineArguments) --report-azdo + $(TestingPlatformCommandLineArguments) --coverage --coverage-settings $(RepoRoot)test/coverage.config --coverage-output $(ModuleName).coverage + + + + + + + + + + <_TestArchitecture>$(PlatformTarget) <_TestArchitecture Condition="'$(PlatformTarget)' == '' or '$(PlatformTarget)' == 'AnyCpu'">x64 - - <_ResultFileNameNoExt>$(MSBuildProjectName)_$(TargetFramework)_$(_TestArchitecture) - $(ArtifactsTestResultsDir)$(_ResultFileNameNoExt).trx - <_TestResultTrxFileName>$([System.IO.Path]::GetFileName('$(ResultsTrxPath)')) - <_TestResultDirectory>$([System.IO.Path]::GetDirectoryName('$(ResultsTrxPath)')) - $(TestingPlatformCommandLineArguments) --report-trx --report-trx-filename "$(_TestResultTrxFileName)" --results-directory "$(_TestResultDirectory)" --report-azdo $(TestRunnerAdditionalArguments) - + $(TestingPlatformCommandLineArguments) --report-trx --report-trx-filename $(MSBuildProjectName)_$(TargetFramework)_$(_TestArchitecture).trx --results-directory $(ArtifactsTestResultsDir) @@ -47,7 +50,6 @@ - diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/AnalyzersTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/AnalyzersTests.cs index b7db7f3140..bf6d87b7c3 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/AnalyzersTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/AnalyzersTests.cs @@ -233,7 +233,7 @@ private static async Task AssertAnalysisModeAsync(string mode, string[] contains foreach (string containsElement in contains) { - StringAssert.Contains(output, containsElement, $"Expected to find '{containsElement}' for analysisMode {mode}"); + Assert.Contains(containsElement, output, $"Expected to find '{containsElement}' for analysisMode {mode}"); } foreach (string doesNotContainElement in doesNotContain) diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ConfigurationSettingsTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ConfigurationSettingsTests.cs index 8637871e8b..8886430a27 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ConfigurationSettingsTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ConfigurationSettingsTests.cs @@ -208,13 +208,13 @@ public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture. { "mstest": { "timeout": { - "assemblyInitialize": 300, - "assemblyCleanup": 300, - "classInitialize": 200, - "classCleanup": 200, - "testInitialize": 100, - "testCleanup": 100, - "test": 60, + "assemblyInitialize": 300000, + "assemblyCleanup": 300000, + "classInitialize": 200000, + "classCleanup": 200000, + "testInitialize": 100000, + "testCleanup": 100000, + "test": 60000, "useCooperativeCancellation": true }, "parallelism": { diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/DynamicDataMethodTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/DynamicDataMethodTests.cs new file mode 100644 index 0000000000..0e2701b754 --- /dev/null +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/DynamicDataMethodTests.cs @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Acceptance.IntegrationTests; +using Microsoft.Testing.Platform.Acceptance.IntegrationTests.Helpers; +using Microsoft.Testing.Platform.Helpers; + +namespace MSTest.Acceptance.IntegrationTests; + +[TestClass] +public sealed class DynamicDataMethodTests : AcceptanceTestBase +{ + [TestMethod] + [DynamicData(nameof(TargetFrameworks.AllForDynamicData), typeof(TargetFrameworks))] + public async Task DynamicDataTestWithParameterizedDataProviderMethod(string tfm) + { + var testHost = TestHost.LocateFrom(AssetFixture.ProjectPath, TestAssetFixture.ProjectName, tfm); + TestHostResult testHostResult = await testHost.ExecuteAsync("--settings my.runsettings"); + + testHostResult.AssertExitCodeIs(ExitCodes.AtLeastOneTestFailed); + testHostResult.AssertOutputContainsSummary(failed: 3, passed: 9, skipped: 0); + + // failed TestMethodSingleParameterIntCountMismatchSmaller (0ms) + // Parameter count mismatch. + // at System.Reflection.MethodBaseInvoker.ThrowTargetParameterCountException() + // at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) + // at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) + // + // failed TestMethodSingleParameterIntCountMismatchLarger (0ms) + // Parameter count mismatch. + // at System.Reflection.MethodBaseInvoker.ThrowTargetParameterCountException() + // at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) + // at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) + // + // failed TestMethodParamsNotSupported (0ms) + // Dynamic data method 'TestClass1.GetDataParams' should be static, non-generic, and cannot have 'params' parameter. + testHostResult.AssertOutputMatchesRegex(@"failed TestMethodSingleParameterIntCountMismatchSmaller \(\d+ms\)[\r\n]+\s+Parameter count mismatch."); + testHostResult.AssertOutputMatchesRegex(@"failed TestMethodSingleParameterIntCountMismatchLarger \(\d+ms\)[\r\n]+\s+Parameter count mismatch."); + testHostResult.AssertOutputMatchesRegex(@"failed TestMethodParamsNotSupported \(\d+ms\)[\r\n]+\s+Dynamic data method 'TestClass1.GetDataParams' should be static, non-generic, and cannot have 'params' parameter."); + + testHostResult.AssertOutputContains("TestMethodSingleParameterInt called with: 4"); + testHostResult.AssertOutputContains("TestMethodSingleParameterInt called with: 5"); + testHostResult.AssertOutputContains("TestMethodSingleParameterInt called with: 6"); + + testHostResult.AssertOutputContains("TestMethodTwoParametersIntAndString called with: 4, Hello1"); + testHostResult.AssertOutputContains("TestMethodTwoParametersIntAndString called with: 5, Hello2"); + testHostResult.AssertOutputContains("TestMethodTwoParametersIntAndString called with: 6, Hello3"); + + testHostResult.AssertOutputContains("TestMethodSingleParameterIntArray called with: 5"); + testHostResult.AssertOutputContains("TestMethodSingleParameterIntArray called with: 7"); + testHostResult.AssertOutputContains("TestMethodSingleParameterIntArray called with: 9"); + } + + public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture.NuGetGlobalPackagesFolder) + { + public const string ProjectName = "DynamicDataMethodTests"; + + public string ProjectPath => GetAssetPath(ProjectName); + + public override IEnumerable<(string ID, string Name, string Code)> GetAssetsToGenerate() + { + yield return (ProjectName, ProjectName, + SourceCode + .PatchTargetFrameworks(TargetFrameworks.All) + .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion)); + } + + private const string SourceCode = """ +#file DynamicDataMethodTests.csproj + + + + Exe + true + $TargetFrameworks$ + preview + + + + + + + + + + PreserveNewest + + + + +#file TestClass1.cs +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public class TestClass1 +{ + [TestMethod] + [DynamicData(nameof(GetDataSingleParameterInt), 4)] + public void TestMethodSingleParameterInt(int a) + { + // We call GetDataSingleParameterInt with 4, so it should yield 4, 5, and 6. + Console.WriteLine($"TestMethodSingleParameterInt called with: {a}"); + } + + [TestMethod] + [DynamicData(nameof(GetDataTwoParametersIntAndString), 4, "Hello")] + public void TestMethodTwoParametersIntAndString(int a, string s) + { + // We call GetDataTwoParametersIntAndString with 4 and "Hello", so it should yield: + // - (4, "Hello1") + // - (5, "Hello2") + // - (6, "Hello3") + Console.WriteLine($"TestMethodTwoParametersIntAndString called with: {a}, {s}"); + } + + [TestMethod] + [DynamicData(nameof(GetDataSingleParameterIntArray), [new int[] { 4, 5, 6 }])] + public void TestMethodSingleParameterIntArray(int x) + { + // We call GetDataSingleParameterIntArray with an array (4, 5, and 6), so it should yield 5, 7, and 9. + Console.WriteLine($"TestMethodSingleParameterIntArray called with: {x}"); + } + + [TestMethod] + [DynamicData(nameof(GetDataSingleParameterInt))] + public void TestMethodSingleParameterIntCountMismatchSmaller(int x) + { + // This test should fail due parameter count mismatch. + } + + [TestMethod] + [DynamicData(nameof(GetDataSingleParameterInt), 1, 2)] + public void TestMethodSingleParameterIntCountMismatchLarger(int x) + { + // This test should fail due parameter count mismatch. + } + + [TestMethod] + [DynamicData(nameof(GetDataParams), 1, 2)] + public void TestMethodParamsNotSupported(int x) + { + // This test should fail because we don't support params. + } + + public static IEnumerable GetDataSingleParameterInt(int i) + { + yield return i++; + yield return i++; + yield return i++; + } + + public static IEnumerable GetDataSingleParameterIntArray(int[] input) + { + yield return [1 + input[0]]; + yield return [2 + input[1]]; + yield return [3 + input[2]]; + } + + public static IEnumerable GetDataTwoParametersIntAndString(int i, string s) + { + yield return new object[] { i++, s + "1" }; + yield return new object[] { i++, s + "2" }; + yield return new object[] { i++, s + "3" }; + } + + public static IEnumerable GetDataParams(params int[] i) + { + yield return 0; + yield return 1; + } +} + +#file my.runsettings + + + false + + +"""; + } +} diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/GenericTestMethodTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/GenericTestMethodTests.cs index c298349c7a..99ee91910a 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/GenericTestMethodTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/GenericTestMethodTests.cs @@ -20,59 +20,55 @@ public async Task TestDifferentGenericMethodTestCases() testHostResult.AssertExitCodeIs(ExitCodes.AtLeastOneTestFailed); testHostResult.AssertOutputMatchesRegex( """ - failed AMethodWithBadConstraints \(0\) \(\d+ms\) + failed AMethodWithBadConstraints \(0\) \((\d+s )?\d+ms\) GenericArguments\[0], 'System\.Int32', on 'Void AMethodWithBadConstraints\[T]\(T\)' violates the constraint of type 'T'\. .+? - failed NonParameterizedTestMethod \(\d+ms\) + failed NonParameterizedTestMethod \((\d+s )?\d+ms\) The generic test method 'NonParameterizedTestMethod' doesn't have arguments, so the generic parameter cannot be inferred\. .+? - failed ParameterizedMethodSimple \(1\) \(\d+ms\) + failed ParameterizedMethodSimple \(1\) \((\d+s )?\d+ms\) Assert\.Fail failed\. Test method 'ParameterizedMethodSimple' did run with parameter '1' and type 'System\.Byte'\. .+? - failed ParameterizedMethodSimple \(2\) \(\d+ms\) + failed ParameterizedMethodSimple \(2\) \((\d+s )?\d+ms\) Assert\.Fail failed\. Test method 'ParameterizedMethodSimple' did run with parameter '2' and type 'System\.Int32'\. .+? - failed ParameterizedMethodSimple \("Hello world"\) \(\d+ms\) + failed ParameterizedMethodSimple \("Hello world"\) \((\d+s )?\d+ms\) Assert\.Fail failed\. Test method 'ParameterizedMethodSimple' did run with parameter 'Hello world' and type 'System\.String'\. .+? - failed ParameterizedMethodSimple \(null\) \(\d+ms\) + failed ParameterizedMethodSimple \(null\) \((\d+s )?\d+ms\) Test method TestClass\.ParameterizedMethodSimple threw exception: System\.InvalidOperationException: The type of the generic parameter 'T' could not be inferred\. - .+? - failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \(1,"Hello world",2,3\) \(\d+ms\) + failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \(1,"Hello world",2,3\) \((\d+s )?\d+ms\) Test method TestClass\.ParameterizedMethodTwoGenericParametersAndFourMethodParameters threw exception: System\.InvalidOperationException: Found two conflicting types for generic parameter 'T2'\. The conflicting types are 'System\.Byte' and 'System\.Int32'\. - .+? - failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \(null,"Hello world","Hello again",3\) \(\d+ms\) + failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \(null,"Hello world","Hello again",3\) \((\d+s )?\d+ms\) Assert\.Fail failed\. Test method 'ParameterizedMethodTwoGenericParametersAndFourMethodParameters' did run with parameters '', 'Hello world', 'Hello again', '3' and generic types 'System\.Int32', 'System\.String'\. .+? - failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \("Hello hello","Hello world",null,null\) \(\d+ms\) + failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \("Hello hello","Hello world",null,null\) \((\d+s )?\d+ms\) Test method TestClass\.ParameterizedMethodTwoGenericParametersAndFourMethodParameters threw exception: System\.InvalidOperationException: The type of the generic parameter 'T1' could not be inferred\. - .+? - failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \(null,null,null,null\) \(\d+ms\) + failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \(null,null,null,null\) \((\d+s )?\d+ms\) Test method TestClass\.ParameterizedMethodTwoGenericParametersAndFourMethodParameters threw exception: System\.InvalidOperationException: The type of the generic parameter 'T1' could not be inferred\. - .+? - failed ParameterizedMethodSimpleParams \(1\) \(\d+ms\) + failed ParameterizedMethodSimpleParams \(1\) \((\d+s )?\d+ms\) Cannot create an instance of T\[] because Type\.ContainsGenericParameters is true\. .+? - failed ParameterizedMethodSimpleParams \(1,2\) \(\d+ms\) + failed ParameterizedMethodSimpleParams \(1,2\) \((\d+s )?\d+ms\) Cannot create an instance of T\[] because Type\.ContainsGenericParameters is true\. .+? - failed ParameterizedMethodSimpleParams \("Hello world"\) \(\d+ms\) + failed ParameterizedMethodSimpleParams \("Hello world"\) \((\d+s )?\d+ms\) Cannot create an instance of T\[] because Type\.ContainsGenericParameters is true\. .+? - failed ParameterizedMethodSimpleParams \(null\) \(\d+ms\) + failed ParameterizedMethodSimpleParams \(null\) \((\d+s )?\d+ms\) Cannot create an instance of T\[] because Type\.ContainsGenericParameters is true\. .+? - failed ParameterizedMethodSimpleParams \(null,"Hello world"\) \(\d+ms\) + failed ParameterizedMethodSimpleParams \(null,"Hello world"\) \((\d+s )?\d+ms\) Cannot create an instance of T\[] because Type\.ContainsGenericParameters is true\. .+? - failed ParameterizedMethodWithNestedGeneric \(System\.Collections\.Generic\.List`1\[System.String],System\.Collections\.Generic\.List`1\[System.String]\) \(\d+ms\) + failed ParameterizedMethodWithNestedGeneric \(System\.Collections\.Generic\.List`1\[System.String],System\.Collections\.Generic\.List`1\[System.String]\) \((\d+s )?\d+ms\) Assert\.Fail failed\. Test method 'ParameterizedMethodWithNestedGeneric' did run with first list \[Hello, World] and second list \[Unit, Testing] .+? - failed ParameterizedMethodWithNestedGeneric \(System\.Collections\.Generic\.List`1\[System.Int32],System\.Collections\.Generic\.List`1\[System.Int32]\) \(\d+ms\) + failed ParameterizedMethodWithNestedGeneric \(System\.Collections\.Generic\.List`1\[System.Int32],System\.Collections\.Generic\.List`1\[System.Int32]\) \((\d+s )?\d+ms\) Assert\.Fail failed\. Test method 'ParameterizedMethodWithNestedGeneric' did run with first list \[0, 1] and second list \[2, 3] .+? """, RegexOptions.Singleline); diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.cs index d43193af01..f65ad6d7c4 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.cs @@ -45,6 +45,8 @@ Output directory of the diagnostic logging. The available values are 'Trace', 'Debug', 'Information', 'Warning', 'Error', and 'Critical'. --exit-on-process-exit Exit the test process if dependent process exits. PID must be provided. + --filter-uid + Provides a list of test node UIDs to filter by. --help Show the command line help. --ignore-exit-code diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/LeakTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/LeakTests.cs new file mode 100644 index 0000000000..fff4190e48 --- /dev/null +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/LeakTests.cs @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Acceptance.IntegrationTests; +using Microsoft.Testing.Platform.Acceptance.IntegrationTests.Helpers; + +namespace MSTest.Acceptance.IntegrationTests; + +[TestClass] +public sealed class LeakTests : AcceptanceTestBase +{ + [TestMethod] + [DynamicData(nameof(TargetFrameworks.AllForDynamicData), typeof(TargetFrameworks))] + public async Task TestContextInstancesShouldNotLeak(string tfm) + { + var testHost = TestHost.LocateFrom(AssetFixture.ProjectPath, TestAssetFixture.ProjectName, tfm); + TestHostResult testHostResult = await testHost.ExecuteAsync(); + + testHostResult.AssertExitCodeIs(0); + testHostResult.AssertOutputContainsSummary(failed: 0, passed: 100, skipped: 0); + } + + public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture.NuGetGlobalPackagesFolder) + { + public const string ProjectName = "LeakTests"; + + public string ProjectPath => GetAssetPath(ProjectName); + + public override IEnumerable<(string ID, string Name, string Code)> GetAssetsToGenerate() + { + yield return (ProjectName, ProjectName, + SourceCode + .PatchTargetFrameworks(TargetFrameworks.All) + .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion)); + } + + private const string SourceCode = """ +#file LeakTests.csproj + + + + Exe + true + $TargetFrameworks$ + preview + + + true + + + + + + + + +#file UnitTest1.cs +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; + + +[TestClass] +public class TestClass +{ + private static ConcurrentBag> _testContexts = new(); + + [AssemblyInitialize] + public static void AssemblyInitialize(TestContext context) + => _testContexts.Add(new WeakReference(context)); + + [ClassInitialize] + public static void ClassInitialize(TestContext context) + => _testContexts.Add(new WeakReference(context)); + + public TestContext TestContext { get; set; } + + [TestMethod] + [DynamicData(nameof(Data))] + public void Test3(int a) + => _testContexts.Add(new WeakReference(TestContext)); + + [ClassCleanup] + public static void ClassCleanup(TestContext testContext) + => _testContexts.Add(new WeakReference(testContext)); + + [AssemblyCleanup] + public static void AssemblyCleanup() + { + for (int i = 0; i < 3; i++) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + + // Assembly init, class init, 100 tests, and class cleanup. (total 103). + Assert.AreEqual(103, _testContexts.Count); + + var alive = 0; + foreach (var weakReference in _testContexts) + { + if (weakReference.TryGetTarget(out _)) + { + alive++; + } + } + + // AssemblyCleanup is executed along with the last test. + // So, we are still holding 2 references to the TestContext. The one for the execution of last test, as well as the one for ClassCleanup. + // Holding into these two references is okay. + Assert.AreEqual(2, alive); + } + + public static IEnumerable Data + { + get + { + for (int i = 0; i < 100; i++) + { + yield return i; + } + } + } +} + +"""; + } +} diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/LifecycleTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/LifecycleTests.cs new file mode 100644 index 0000000000..98ceefdc11 --- /dev/null +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/LifecycleTests.cs @@ -0,0 +1,249 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Acceptance.IntegrationTests; +using Microsoft.Testing.Platform.Acceptance.IntegrationTests.Helpers; +using Microsoft.Testing.Platform.Helpers; + +namespace MSTest.Acceptance.IntegrationTests; + +[TestClass] +public sealed class LifecycleTests : AcceptanceTestBase +{ + [TestMethod] + [DynamicData(nameof(TargetFrameworks.AllForDynamicData), typeof(TargetFrameworks))] + public async Task LifecycleTest(string tfm) + { + var testHost = TestHost.LocateFrom(AssetFixture.ProjectPath, TestAssetFixture.ProjectName, tfm); + TestHostResult testHostResult = await testHost.ExecuteAsync("--settings my.runsettings"); + + testHostResult.AssertExitCodeIs(ExitCodes.Success); + testHostResult.AssertOutputContainsSummary(failed: 0, passed: 4, skipped: 0); + // Order is: + // - Assembly initialize + // - foreach test class + // - ClassInitialize + // - foreach test: + // - GlobalTestInitialize + // - ctor + // - TestContext property setter + // - TestInitialize + // - TestMethod + // - TestCleanup + // - Dispose + // - GlobalTestCleanup + // - ClassCleanup + // - AssemblyCleanup + testHostResult.AssertOutputContains(""" + AssemblyInitialize called. + TestClass1.ClassInitialize called. + GlobalTestInitialize called for 'TestMethodParameterized (0)'. + TestClass1 constructor called. + TestContext property set for TestClass1. + TestClass1.TestInitialize for 'TestMethodParameterized (0)' is called. + TestMethodParameterized called with: 0 + TestClass1.TestCleanup for 'TestMethodParameterized (0)' is called. + TestClass1 disposed. + GlobalTestCleanup called for 'TestMethodParameterized (0)'. + GlobalTestInitialize called for 'TestMethodParameterized (1)'. + TestClass1 constructor called. + TestContext property set for TestClass1. + TestClass1.TestInitialize for 'TestMethodParameterized (1)' is called. + TestMethodParameterized called with: 1 + TestClass1.TestCleanup for 'TestMethodParameterized (1)' is called. + TestClass1 disposed. + GlobalTestCleanup called for 'TestMethodParameterized (1)'. + GlobalTestInitialize called for 'TestMethodNonParameterized'. + TestClass1 constructor called. + TestContext property set for TestClass1. + TestClass1.TestInitialize for 'TestMethodNonParameterized' is called. + TestMethodNonParameterized called + TestClass1.TestCleanup for 'TestMethodNonParameterized' is called. + TestClass1 disposed. + GlobalTestCleanup called for 'TestMethodNonParameterized'. + TestClass1.ClassCleanup called. + TestClass2.ClassInitialize called. + GlobalTestInitialize called for 'TestMethodFromTestClass2'. + TestClass2 constructor called. + TestContext property set for TestClass2. + TestClass2.TestInitialize for 'TestMethodFromTestClass2' is called. + TestMethodFromTestClass2 called + TestClass2.TestCleanup for 'TestMethodFromTestClass2' is called. + TestClass2 disposed. + GlobalTestCleanup called for 'TestMethodFromTestClass2'. + TestClass2.ClassCleanup called. + AssemblyCleanup called. + """); + } + + public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture.NuGetGlobalPackagesFolder) + { + public const string ProjectName = "LifecycleTests"; + + public string ProjectPath => GetAssetPath(ProjectName); + + public override IEnumerable<(string ID, string Name, string Code)> GetAssetsToGenerate() + { + yield return (ProjectName, ProjectName, + SourceCode + .PatchTargetFrameworks(TargetFrameworks.All) + .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion)); + } + + private const string SourceCode = """ +#file LifecycleTests.csproj + + + + Exe + true + $TargetFrameworks$ + preview + + + + + + + + + + PreserveNewest + + + + +#file TestClass1.cs +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public static class Fixtures +{ + [AssemblyInitialize] + public static void AssemblyInitialize(TestContext context) + => Console.WriteLine("AssemblyInitialize called."); + + [AssemblyCleanup] + public static void AssemblyCleanup(TestContext context) + => Console.WriteLine("AssemblyCleanup called."); + + [GlobalTestInitialize] + public static void GlobalTestInitialize(TestContext context) + => Console.WriteLine($"GlobalTestInitialize called for '{context.TestDisplayName}'."); + + [GlobalTestCleanup] + public static void GlobalTestCleanup(TestContext context) + => Console.WriteLine($"GlobalTestCleanup called for '{context.TestDisplayName}'."); +} + +[TestClass] +public class TestClass1 : IDisposable +{ + public TestClass1() + { + Console.WriteLine("TestClass1 constructor called."); + } + + public TestContext TestContext + { + get => field; + set + { + field = value; + Console.WriteLine("TestContext property set for TestClass1."); + } + } + + [TestInitialize] + public void TestInitialize() + { + Console.WriteLine($"TestClass1.TestInitialize for '{TestContext.TestDisplayName}' is called."); + } + + [TestCleanup] + public void TestCleanup() + { + Console.WriteLine($"TestClass1.TestCleanup for '{TestContext.TestDisplayName}' is called."); + } + + [ClassInitialize] + public static void ClassInitialize(TestContext context) + => Console.WriteLine("TestClass1.ClassInitialize called."); + + [ClassCleanup] + public static void ClassCleanup(TestContext context) + => Console.WriteLine("TestClass1.ClassCleanup called."); + + [TestMethod] + [DataRow(0)] + [DataRow(1)] + public void TestMethodParameterized(int a) + => Console.WriteLine($"TestMethodParameterized called with: {a}"); + + [TestMethod] + public void TestMethodNonParameterized() + => Console.WriteLine("TestMethodNonParameterized called"); + + public void Dispose() + => Console.WriteLine("TestClass1 disposed."); +} + +[TestClass] +public class TestClass2 : IDisposable +{ + public TestClass2() + { + Console.WriteLine("TestClass2 constructor called."); + } + + public TestContext TestContext + { + get => field; + set + { + field = value; + Console.WriteLine("TestContext property set for TestClass2."); + } + } + + [TestInitialize] + public void TestInitialize() + { + Console.WriteLine($"TestClass2.TestInitialize for '{TestContext.TestDisplayName}' is called."); + } + + [TestCleanup] + public void TestCleanup() + { + Console.WriteLine($"TestClass2.TestCleanup for '{TestContext.TestDisplayName}' is called."); + } + + [ClassInitialize] + public static void ClassInitialize(TestContext context) + => Console.WriteLine("TestClass2.ClassInitialize called."); + + [ClassCleanup] + public static void ClassCleanup(TestContext context) + => Console.WriteLine("TestClass2.ClassCleanup called."); + + [TestMethod] + public void TestMethodFromTestClass2() + => Console.WriteLine("TestMethodFromTestClass2 called"); + + public void Dispose() + => Console.WriteLine("TestClass2 disposed."); +} + +#file my.runsettings + + + false + EndOfClass + + +"""; + } +} diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MaxFailedTestsExtensionTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MaxFailedTestsExtensionTests.cs index 6d11054c28..0df04d170a 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MaxFailedTestsExtensionTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MaxFailedTestsExtensionTests.cs @@ -26,8 +26,8 @@ public async Task SimpleMaxFailedTestsScenario(string tfm) // We can't know the number of tests that will be executed exactly due to the async // nature of publish/consume on the platform side. But we expect the cancellation to // happen "fast" enough that we don't execute all tests. - Assert.IsTrue(total < 12); - Assert.IsTrue(total >= 5); + Assert.IsLessThan(12, total); + Assert.IsGreaterThanOrEqualTo(5, total); testHostResult = await testHost.ExecuteAsync(); testHostResult.AssertExitCodeIs(ExitCodes.AtLeastOneTestFailed); diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ParameterizedTestTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ParameterizedTestTests.cs index 0a029a6421..1783bf3843 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ParameterizedTestTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ParameterizedTestTests.cs @@ -12,6 +12,7 @@ public class ParameterizedTestTests : AcceptanceTestBase await UsingDataRowThatDoesNotRoundTripUsingDataContractJsonSerializerCore(currentTfm, "AppDomainEnabled"); + + [TestMethod] + [DynamicData(nameof(TargetFrameworks.AllForDynamicData), typeof(TargetFrameworks))] + public async Task UsingDataRowThatDoesNotRoundTripUsingDataContractJsonSerializerWithoutAppDomains(string currentTfm) + => await UsingDataRowThatDoesNotRoundTripUsingDataContractJsonSerializerCore(currentTfm, "AppDomainDisabled"); + + private static async Task UsingDataRowThatDoesNotRoundTripUsingDataContractJsonSerializerCore(string currentTfm, string runSettings) + { + var testHost = TestHost.LocateFrom(AssetFixture.GetAssetPath(DataRowAssetName), DataRowAssetName, currentTfm); + + TestHostResult testHostResult = await testHost.ExecuteAsync($"--settings {runSettings}.runsettings --filter ClassName=ParameterizedTestSerializationIssue2390"); + + testHostResult.AssertExitCodeIs(ExitCodes.Success); + testHostResult.AssertOutputContainsSummary(failed: 0, passed: 3, skipped: 0); + } + private static async Task RunTestsAsync(string currentTfm, string assetName, bool? isEmptyDataInconclusive) { var testHost = TestHost.LocateFrom(AssetFixture.GetAssetPath(assetName), assetName, currentTfm); @@ -163,7 +184,97 @@ public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture. SourceCodeDataSource .PatchTargetFrameworks(TargetFrameworks.All) .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion)); + yield return (DataRowAssetName, DataRowAssetName, + SourceCodeDataRow + .PatchTargetFrameworks(TargetFrameworks.All) + .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion)); + } + + private const string SourceCodeDataRow = """ +#file DataRowTests.csproj + + + + Exe + true + $TargetFrameworks$ + preview + + + + + + + + + + PreserveNewest + + + + + + PreserveNewest + + + + + +#file AppDomainEnabled.runsettings + + + + + false + + + +#file AppDomainDisabled.runsettings + + + + true + + + +#file UnitTest1.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +// Test for https://github.com/microsoft/testfx/issues/2390 +[TestClass] +public class ParameterizedTestSerializationIssue2390 +{ + [TestMethod] + [DataRow((byte)0, new object[] { (byte)0 })] + [DataRow((short)0, new object[] { (short)0 })] + [DataRow(0L, new object[] { 0L })] + public void CheckNestedInputTypes(object expected, object nested) + { + object[] array = (object[])nested; + object actual = Assert.ContainsSingle(array); + +#if NETFRAMEWORK + var appDomainEnabled = Environment.GetCommandLineArgs().Contains("AppDomainEnabled.runsettings"); + if (appDomainEnabled) + { + // Buggy behavior, because of app domains. + Assert.AreEqual(typeof(int), actual.GetType(), AppDomain.CurrentDomain.FriendlyName); } + else +#endif + { + Assert.AreEqual(expected.GetType(), actual.GetType(), AppDomain.CurrentDomain.FriendlyName); + Assert.AreEqual(expected, actual); + } + } +} + +"""; private const string SourceCodeDynamicData = """ #file DynamicData.csproj @@ -181,7 +292,7 @@ public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture. - + PreserveNewest diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RunnerTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RunnerTests.cs index e8316ee811..f33fa0eb98 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RunnerTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RunnerTests.cs @@ -102,7 +102,7 @@ public async SystemTask EnableMSTestRunner_False_Will_Run_Empty_Program_EntryPoi { if (TargetFrameworks.NetFramework.Any(x => x == tfm)) { - Assert.IsTrue(ex.Message.Contains("Program does not contain a static 'Main' method suitable for an entry point"), ex.Message); + Assert.Contains("Program does not contain a static 'Main' method suitable for an entry point", ex.Message, ex.Message); // .NET Framework does not insert the entry point for empty program. } } diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SdkTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SdkTests.cs index 3260b69c61..4d6885fd96 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SdkTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SdkTests.cs @@ -428,7 +428,7 @@ public async Task SettingIsTestApplicationToFalseReducesAddedExtensionsAndMakesP SL.Build binLog = SL.Serialization.Read(compilationResult.BinlogPath!); SL.Task cscTask = binLog.FindChildrenRecursive(task => task.Name == "Csc").Single(); - SL.Item[] references = cscTask.FindChildrenRecursive(p => p.Name == "References").Single().Children.OfType().ToArray(); + SL.Item[] references = [.. cscTask.FindChildrenRecursive(p => p.Name == "References").Single().Children.OfType()]; // Ensure that MSTest.Framework is referenced Assert.IsTrue(references.Any(r => r.Text.EndsWith("Microsoft.VisualStudio.TestPlatform.TestFramework.dll", StringComparison.OrdinalIgnoreCase))); diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ServerModeTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ServerModeTests.cs index b79c30d152..a4975ed3da 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ServerModeTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ServerModeTests.cs @@ -16,9 +16,9 @@ public sealed class ServerModeTests : ServerModeTestsBase x.Node.NodeType == "action"), "Wrong number of discovery"); - Assert.AreEqual(2, runCollector.TestNodeUpdates.Count, "Wrong number of updates"); + Assert.HasCount(2, runCollector.TestNodeUpdates); Assert.AreNotEqual(0, logs.Count, "Logs are empty"); Assert.IsFalse(telemetry.IsEmpty, "telemetry is empty"); await jsonClient.Exit(); @@ -48,9 +48,9 @@ public async Task DiscoverAndRun(string tfm) public async Task WhenClientDies_Server_ShouldClose_Gracefully(string tfm) { using TestingPlatformClient jsonClient = await StartAsServerAndConnectToTheClientAsync(TestHost.LocateFrom(AssetFixture.ProjectPath, "MSTestProject", tfm, buildConfiguration: BuildConfiguration.Release)); - LogsCollector logs = new(); + LogsCollector logs = []; jsonClient.RegisterLogListener(logs); - TelemetryCollector telemetry = new(); + TelemetryCollector telemetry = []; jsonClient.RegisterTelemetryListener(telemetry); InitializeResponse initializeResponseArgs = await jsonClient.Initialize(); diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TestContextTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TestContextTests.cs index 7b86cfbcb4..06b1624ef7 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TestContextTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TestContextTests.cs @@ -10,9 +10,10 @@ namespace MSTest.Acceptance.IntegrationTests; public sealed class TestContextTests : AcceptanceTestBase { [TestMethod] - public async Task TestContextsAreCorrectlySet() + [DynamicData(nameof(TargetFrameworks.AllForDynamicData), typeof(TargetFrameworks))] + public async Task TestContextsAreCorrectlySet(string tfm) { - var testHost = TestHost.LocateFrom(AssetFixture.ProjectPath, TestAssetFixture.ProjectName, TargetFrameworks.NetCurrent); + var testHost = TestHost.LocateFrom(AssetFixture.ProjectPath, TestAssetFixture.ProjectName, tfm); TestHostResult testHostResult = await testHost.ExecuteAsync("--filter ClassName~TestContextCtor"); // Assert @@ -76,7 +77,7 @@ public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture. { yield return (ProjectName, ProjectName, SourceCode - .PatchTargetFrameworks(TargetFrameworks.NetCurrent) + .PatchTargetFrameworks(TargetFrameworks.All) .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion)); } @@ -88,6 +89,7 @@ public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture. Exe true $TargetFrameworks$ + preview + net472;net6.0 + net6.0 true true diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/NonNullableReferenceNotInitializedSuppressorTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/NonNullableReferenceNotInitializedSuppressorTests.cs index 23d263569a..7fb1ece97f 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/NonNullableReferenceNotInitializedSuppressorTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/NonNullableReferenceNotInitializedSuppressorTests.cs @@ -1,13 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Immutable; - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier< - MSTest.Analyzers.UnitTests.NonNullableReferenceNotInitializedSuppressorTests.DoNothingAnalyzer, + MSTest.Analyzers.NonNullableReferenceNotInitializedSuppressor, Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; namespace MSTest.Analyzers.UnitTests; @@ -27,20 +24,11 @@ public async Task TestContextPropertyOnTestClass_DiagnosticIsSuppressed() [TestClass] public class SomeClass { - public TestContext [|TestContext|] { get; set; } + public TestContext {|#0:TestContext|} { get; set; } } "; - // Verify issues are reported - await new VerifyCS.Test - { - TestState = { Sources = { code } }, - }.RunAsync(); - - await new TestWithSuppressor - { - TestState = { Sources = { code } }, - }.RunAsync(); + await VerifySingleSuppressionAsync(code, isSuppressed: true); } [TestMethod] @@ -54,56 +42,55 @@ public async Task TestContextPropertyOnNonTestClass_DiagnosticIsNotSuppressed() public class SomeClass { - public TestContext [|TestContext|] { get; set; } + public TestContext {|#0:TestContext|} { get; set; } } "; - // Verify issues are reported - await new VerifyCS.Test - { - TestState = { Sources = { code } }, - }.RunAsync(); - - await new TestWithSuppressor - { - TestState = { Sources = { code } }, - }.RunAsync(); + await VerifySingleSuppressionAsync(code, isSuppressed: false); } - [DiagnosticAnalyzer(LanguageNames.CSharp)] - [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1038:Compiler extensions should be implemented in assemblies with compiler-provided references", Justification = "For suppression test only.")] - [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1036:Specify analyzer banned API enforcement setting", Justification = "For suppression test only.")] - [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1041:Compiler extensions should be implemented in assemblies targeting netstandard2.0", Justification = "For suppression test only.")] - public class DoNothingAnalyzer : DiagnosticAnalyzer + [TestMethod] + public async Task TestContextPropertyOnTestClassConstructor_DiagnosticIsSuppressed() { - [SuppressMessage("MicrosoftCodeAnalysisDesign", "RS1017:DiagnosticId for analyzers must be a non-null constant.", Justification = "For suppression test only.")] - public static readonly DiagnosticDescriptor Rule = new(NonNullableReferenceNotInitializedSuppressor.Rule.SuppressedDiagnosticId, "Title", "Message", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true); + string code = @" +#nullable enable - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; - public override void Initialize(AnalysisContext context) - { - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); - context.EnableConcurrentExecution(); +[TestClass] +public class SomeClass +{ + public {|#0:SomeClass|}() + { + } - context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Property); - } + public TestContext TestContext { get; set; } +} +"; - private void AnalyzeSymbol(SymbolAnalysisContext context) - { - } + await VerifySingleSuppressionAsync(code, isSuppressed: true); } - internal sealed class TestWithSuppressor : VerifyCS.Test + private Task VerifySingleSuppressionAsync(string source, bool isSuppressed) + => VerifyDiagnosticsAsync(source, [(0, isSuppressed)]); + + private async Task VerifyDiagnosticsAsync(string source, List<(int Location, bool IsSuppressed)> diagnostics) { - protected override IEnumerable GetDiagnosticAnalyzers() + var test = new VerifyCS.Test { - foreach (DiagnosticAnalyzer analyzer in base.GetDiagnosticAnalyzers()) - { - yield return analyzer; - } + TestCode = source, + }; - yield return new NonNullableReferenceNotInitializedSuppressor(); + foreach ((int location, bool isSuppressed) in diagnostics) + { + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS8618") + .WithLocation(location) + .WithOptions(DiagnosticOptions.IgnoreAdditionalLocations) + .WithArguments("property", "TestContext") + .WithIsSuppressed(isSuppressed)); } + + await test.RunAsync(); } } diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs index f6335eedb7..7e265f7aa1 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs @@ -251,4 +251,156 @@ public MyTestClass(int y) await VerifyCS.VerifyCodeFixAsync(code, fixedCode); } + + [TestMethod] + public async Task WhenTestClassHasStaticCtorAndTestInitialize_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + private object _instanceVariable; + + static MyTestClass() + { + } + + [TestInitialize] + public void [|MyTestInit|]() + { + _instanceVariable = new object(); + } + } + """; + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + private object _instanceVariable; + + static MyTestClass() + { + } + + public MyTestClass() + { + _instanceVariable = new object(); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTestClassHasFieldsAndMethods_ConstructorPlacedAfterFields() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public sealed class Test1 + { + private object _instanceVariable; + + [TestInitialize] + public void [|Initialize|]() + { + _instanceVariable = new object(); + } + + [TestMethod] + public void TestMethod1() + { + } + + private void SomePrivateMethod() + { + } + } + """; + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public sealed class Test1 + { + private object _instanceVariable; + + public Test1() + { + _instanceVariable = new object(); + } + + [TestMethod] + public void TestMethod1() + { + } + + private void SomePrivateMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTestClassHasFieldsAndTestMethodBeforeTestInitialize_ConstructorPlacedAfterFields() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public sealed class Test1 + { + private object _instanceVariable; + + [TestMethod] + public void TestMethod1() + { + } + + [TestInitialize] + public void [|Initialize|]() + { + _instanceVariable = new object(); + } + + private void SomePrivateMethod() + { + } + } + """; + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public sealed class Test1 + { + private object _instanceVariable; + + [TestMethod] + public void TestMethod1() + { + } + + public Test1() + { + _instanceVariable = new object(); + } + + private void SomePrivateMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } } diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferDisposeOverTestCleanupAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferDisposeOverTestCleanupAnalyzerTests.cs index 65bb4d83c5..16a8b62191 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferDisposeOverTestCleanupAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferDisposeOverTestCleanupAnalyzerTests.cs @@ -29,6 +29,7 @@ public void Dispose() await VerifyCS.VerifyCodeFixAsync(code, code); } +#if NET [TestMethod] public async Task WhenTestClassHasDisposeAsync_NoDiagnostic() { @@ -49,6 +50,7 @@ public ValueTask DisposeAsync() await VerifyCS.VerifyCodeFixAsync(code, code); } +#endif [TestMethod] public async Task WhenTestClassHasTestCleanup_Diagnostic() @@ -159,7 +161,7 @@ public void Dispose() [TestMethod] public async Task WhenTestClassHasTestCleanup_AndHasDisposeInAnotherPartial_Diagnostic() { - // This scenario is currently broken. The test is to document the current behavior + // This scenario should now work correctly after fixing the codefix string code = """ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; @@ -192,21 +194,146 @@ public partial class MyTestClass : IDisposable public void Dispose() { int x = 1; + int y = 1; } } [TestClass] - public partial class MyTestClass : IDisposable + public partial class MyTestClass { - public void {|CS0111:Dispose|}() - { - int y = 1; - } } """; await VerifyCS.VerifyCodeFixAsync(code, fixedCode); } + [TestMethod] + public async Task WhenTestClassHasTestCleanup_AndHasDisposeInAnotherPartialInDifferentFile_Diagnostic() + { + var test = new VerifyCS.Test + { + TestState = + { + Sources = + { + @" +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +public partial class MyTestClass : IDisposable +{ + public void Dispose() + { + int x = 1; + } +}", + @" +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public partial class MyTestClass +{ + [TestCleanup] + public void [|MyTestCleanup|]() + { + int y = 1; + } +}", + }, + }, + FixedState = + { + Sources = + { + @" +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +public partial class MyTestClass : IDisposable +{ + public void Dispose() + { + int x = 1; + int y = 1; + } +}", + @" +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public partial class MyTestClass +{ +}", + }, + }, + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task WhenTestClassHasTestCleanup_AndHasDisposeInAnotherPartialInDifferentFile_ReversedOrder_Diagnostic() + { + var test = new VerifyCS.Test + { + TestState = + { + Sources = + { + @" +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public partial class MyTestClass +{ + [TestCleanup] + public void [|MyTestCleanup|]() + { + int y = 1; + } +}", + @" +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +public partial class MyTestClass : IDisposable +{ + public void Dispose() + { + int x = 1; + } +}", + }, + }, + FixedState = + { + Sources = + { + @" +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public partial class MyTestClass +{ +}", + @" +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +public partial class MyTestClass : IDisposable +{ + public void Dispose() + { + int x = 1; + int y = 1; + } +}", + }, + }, + }; + + await test.RunAsync(); + } + [TestMethod] public async Task WhenTestClassHasTestCleanupTask_Diagnostic() { @@ -230,6 +357,7 @@ public class MyTestClass await VerifyCS.VerifyCodeFixAsync(code, code); } +#if NET [TestMethod] public async Task WhenTestClassHasTestCleanupValueTask_Diagnostic() { @@ -251,4 +379,5 @@ public class MyTestClass await VerifyCS.VerifyCodeFixAsync(code, code); } +#endif } diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferTestCleanupOverDisposeAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferTestCleanupOverDisposeAnalyzerTests.cs index fcee06522e..c6f26187d3 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferTestCleanupOverDisposeAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferTestCleanupOverDisposeAnalyzerTests.cs @@ -68,6 +68,7 @@ public interface IMyInterface { } await VerifyCS.VerifyCodeFixAsync(code, fixedCode); } +#if NET [TestMethod] public async Task WhenTestClassHasDisposeAsync_Diagnostic() { @@ -143,4 +144,5 @@ public ValueTask MyTestCleanup() await VerifyCS.VerifyCodeFixAsync(code, code); } +#endif } diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferTestMethodOverDataTestMethodAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferTestMethodOverDataTestMethodAnalyzerTests.cs new file mode 100644 index 0000000000..b642a86ca7 --- /dev/null +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferTestMethodOverDataTestMethodAnalyzerTests.cs @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier< + MSTest.Analyzers.PreferTestMethodOverDataTestMethodAnalyzer, + MSTest.Analyzers.PreferTestMethodOverDataTestMethodFixer>; + +namespace MSTest.Analyzers.Test; + +[TestClass] +public sealed class PreferTestMethodOverDataTestMethodAnalyzerTests +{ + [TestMethod] + public async Task WhenUsingTestMethod_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, code); + } + + [TestMethod] + public async Task WhenUsingDataTestMethod_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [[|DataTestMethod|]] + public void MyTestMethod() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenUsingDataTestMethodWithDisplayName_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [[|DataTestMethod("Display Name")|]] + public void MyTestMethod() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod("Display Name")] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenUsingDataTestMethodWithMultipleAttributesInSameList_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [Ignore, [|DataTestMethod|]] + public void MyTestMethod() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [Ignore, TestMethod] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenInheritingDataTestMethod_Diagnostic() + { + // TODO: Codefix doesn't handle this yet. So no codefix is offered. + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + internal sealed class [|MyDataTestMethodAttribute|] : DataTestMethodAttribute + { + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, code); + } +} diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/Program.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/Program.cs index 92aed8206f..aaaee854d8 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/Program.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/Program.cs @@ -3,6 +3,8 @@ using Microsoft.Testing.Extensions; +using ExecutionScope = Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope; + [assembly: Parallelize(Scope = ExecutionScope.MethodLevel, Workers = 0)] [assembly: ClassCleanupExecution(ClassCleanupBehavior.EndOfClass)] diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/PublicTypeShouldBeTestClassAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/PublicTypeShouldBeTestClassAnalyzerTests.cs index b2438a3742..6bcbaaf960 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/PublicTypeShouldBeTestClassAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/PublicTypeShouldBeTestClassAnalyzerTests.cs @@ -62,6 +62,42 @@ await VerifyCS.VerifyCodeFixAsync( fixedCode); } + [TestMethod] + public async Task WhenClassIsPublicAndHasSTATestClassAttribute_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [STATestClass] + public class MyTestClass + { + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + code); + } + + [TestMethod] + public async Task WhenClassIsPublicAndHasDerivedTestClassAttribute_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + internal sealed class MyTestClassAttribute : TestClassAttribute; + + [MyTestClass] + public class MyTestClass + { + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + code); + } + [TestMethod] public async Task WhenClassIsPublicAndNotClass_NoDiagnostic() { diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/StringAssertToAssertAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/StringAssertToAssertAnalyzerTests.cs new file mode 100644 index 0000000000..7f41a59d10 --- /dev/null +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/StringAssertToAssertAnalyzerTests.cs @@ -0,0 +1,311 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier< + MSTest.Analyzers.StringAssertToAssertAnalyzer, + MSTest.Analyzers.CodeFixes.StringAssertToAssertFixer>; + +namespace MSTest.Analyzers.Test; + +[TestClass] +public sealed class StringAssertToAssertAnalyzerTests +{ + [TestMethod] + public async Task WhenStringAssertContains() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + string substring = "World"; + {|#0:StringAssert.Contains(value, substring)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + string substring = "World"; + Assert.Contains(substring, value); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0046: Use 'Assert.Contains' instead of 'StringAssert.Contains' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("Contains", "Contains"), + fixedCode); + } + + [TestMethod] + public async Task WhenStringAssertStartsWith() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + string substring = "Hello"; + {|#0:StringAssert.StartsWith(value, substring)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + string substring = "Hello"; + Assert.StartsWith(substring, value); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0046: Use 'Assert.StartsWith' instead of 'StringAssert.StartsWith' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("StartsWith", "StartsWith"), + fixedCode); + } + + [TestMethod] + public async Task WhenStringAssertEndsWith() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + string substring = "World"; + {|#0:StringAssert.EndsWith(value, substring)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + string substring = "World"; + Assert.EndsWith(substring, value); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0046: Use 'Assert.EndsWith' instead of 'StringAssert.EndsWith' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("EndsWith", "EndsWith"), + fixedCode); + } + + [TestMethod] + public async Task WhenStringAssertMatches() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Text.RegularExpressions; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + Regex pattern = new Regex("Hello.*"); + {|#0:StringAssert.Matches(value, pattern)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Text.RegularExpressions; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + Regex pattern = new Regex("Hello.*"); + Assert.MatchesRegex(pattern, value); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(12,9): info MSTEST0046: Use 'Assert.MatchesRegex' instead of 'StringAssert.Matches' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("MatchesRegex", "Matches"), + fixedCode); + } + + [TestMethod] + public async Task WhenStringAssertDoesNotMatch() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Text.RegularExpressions; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + Regex pattern = new Regex("Goodbye.*"); + {|#0:StringAssert.DoesNotMatch(value, pattern)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Text.RegularExpressions; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + Regex pattern = new Regex("Goodbye.*"); + Assert.DoesNotMatchRegex(pattern, value); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(12,9): info MSTEST0046: Use 'Assert.DoesNotMatchRegex' instead of 'StringAssert.DoesNotMatch' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("DoesNotMatchRegex", "DoesNotMatch"), + fixedCode); + } + + [TestMethod] + public async Task WhenStringAssertContainsWithMessage() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + string substring = "World"; + {|#0:StringAssert.Contains(value, substring, "Custom message")|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + string substring = "World"; + Assert.Contains(substring, value, "Custom message"); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0046: Use 'Assert.Contains' instead of 'StringAssert.Contains' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("Contains", "Contains"), + fixedCode); + } + + [TestMethod] + public async Task WhenNotStringAssertMethod_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string value = "Hello World"; + Assert.AreEqual("expected", value); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenStringAssertMethodWithInsufficientArguments_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + // This won't compile but should not crash the analyzer + // error CS1501: No overload for method 'Contains' takes 1 arguments + StringAssert.{|CS1501:Contains|}("single"); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } +} diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/TestClassShouldHaveTestMethodAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/TestClassShouldHaveTestMethodAnalyzerTests.cs index 46bff4564b..e92555de5b 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/TestClassShouldHaveTestMethodAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/TestClassShouldHaveTestMethodAnalyzerTests.cs @@ -287,4 +287,65 @@ await VerifyCS.VerifyAnalyzerAsync( .WithLocation(0) .WithArguments("Derived")); } + + [TestMethod] + public async Task WhenStaticTestClassWithGlobalTestInitialize_DoesNotHaveTestMethod_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public static class MyTestClass + { + [GlobalTestInitialize] + public static void GlobalTestInitialize(TestContext context) + { + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenStaticTestClassWithGlobalTestCleanup_DoesNotHaveTestMethod_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public static class MyTestClass + { + [GlobalTestCleanup] + public static void GlobalTestCleanup(TestContext context) + { + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenNonStaticTestClassWithGlobalTestInitialize_DoesNotHaveTestMethod_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class {|#0:MyTestClass|} + { + [GlobalTestInitialize] + public static void GlobalTestInitialize(TestContext context) + { + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync( + code, + VerifyCS.Diagnostic(TestClassShouldHaveTestMethodAnalyzer.TestClassShouldHaveTestMethodRule) + .WithLocation(0) + .WithArguments("MyTestClass")); + } } diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/TestCleanupShouldBeValidAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/TestCleanupShouldBeValidAnalyzerTests.cs index cdfea41d81..aede7da0fb 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/TestCleanupShouldBeValidAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/TestCleanupShouldBeValidAnalyzerTests.cs @@ -292,6 +292,7 @@ await VerifyCS.VerifyCodeFixAsync( fixedCode); } +#if NET [TestMethod] public async Task WhenTestCleanupReturnTypeIsNotValid_Diagnostic() { @@ -399,6 +400,7 @@ public ValueTask TestCleanup2() await VerifyCS.VerifyAnalyzerAsync(code); } +#endif [TestMethod] public async Task WhenTestCleanupIsAsyncVoid_Diagnostic() diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/TestContextPropertyUsageAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/TestContextPropertyUsageAnalyzerTests.cs new file mode 100644 index 0000000000..96a769a53e --- /dev/null +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/TestContextPropertyUsageAnalyzerTests.cs @@ -0,0 +1,259 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier< + MSTest.Analyzers.TestContextPropertyUsageAnalyzer, + Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; + +namespace MSTest.Analyzers.Test; + +[TestClass] +public sealed class TestContextPropertyUsageAnalyzerTests +{ + [TestMethod] + public async Task WhenTestContextPropertyAccessedInAssemblyInitialize_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyInitialize] + public static void AssemblyInit(TestContext testContext) + { + _ = [|testContext.TestData|]; + _ = [|testContext.TestDisplayName|]; + _ = [|testContext.TestName|]; + _ = [|testContext.ManagedMethod|]; + _ = [|testContext.FullyQualifiedTestClassName|]; + _ = [|testContext.ManagedType|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenTestContextPropertyAccessedInAssemblyCleanup_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyCleanup] + public static void AssemblyCleanup() + { + TestContext testContext = GetTestContext(); + _ = [|testContext.TestData|]; + _ = [|testContext.TestDisplayName|]; + _ = [|testContext.TestName|]; + _ = [|testContext.ManagedMethod|]; + _ = [|testContext.FullyQualifiedTestClassName|]; + _ = [|testContext.ManagedType|]; + } + + private static TestContext GetTestContext() => null; + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenTestContextPropertyAccessedInClassInitialize_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [ClassInitialize] + public static void ClassInit(TestContext testContext) + { + _ = [|testContext.TestData|]; + _ = [|testContext.TestDisplayName|]; + _ = [|testContext.TestName|]; + _ = [|testContext.ManagedMethod|]; + // These should NOT trigger diagnostics in class initialize + _ = testContext.FullyQualifiedTestClassName; + _ = testContext.ManagedType; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenTestContextPropertyAccessedInClassCleanup_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [ClassCleanup] + public static void ClassCleanup() + { + TestContext testContext = GetTestContext(); + _ = [|testContext.TestData|]; + _ = [|testContext.TestDisplayName|]; + _ = [|testContext.TestName|]; + _ = [|testContext.ManagedMethod|]; + // These should NOT trigger diagnostics in class cleanup + _ = testContext.FullyQualifiedTestClassName; + _ = testContext.ManagedType; + } + + private static TestContext GetTestContext() => null; + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenTestContextPropertyAccessedInTestMethod_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + public TestContext TestContext { get; set; } + + [TestMethod] + public void TestMethod() + { + // All of these should be allowed in test methods + _ = TestContext.TestData; + _ = TestContext.TestDisplayName; + _ = TestContext.TestName; + _ = TestContext.ManagedMethod; + _ = TestContext.FullyQualifiedTestClassName; + _ = TestContext.ManagedType; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenTestContextPropertyAccessedInTestInitialize_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + public TestContext TestContext { get; set; } + + [TestInitialize] + public void TestInit() + { + // All of these should be allowed in test initialize + _ = TestContext.TestData; + _ = TestContext.TestDisplayName; + _ = TestContext.TestName; + _ = TestContext.ManagedMethod; + _ = TestContext.FullyQualifiedTestClassName; + _ = TestContext.ManagedType; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenTestContextPropertyAccessedInTestCleanup_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + public TestContext TestContext { get; set; } + + [TestCleanup] + public void TestCleanup() + { + // All of these should be allowed in test cleanup + _ = TestContext.TestData; + _ = TestContext.TestDisplayName; + _ = TestContext.TestName; + _ = TestContext.ManagedMethod; + _ = TestContext.FullyQualifiedTestClassName; + _ = TestContext.ManagedType; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + +#if NETFRAMEWORK + [TestMethod] + public async Task WhenDataRowAndDataConnectionAccessedInNetFramework_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyInitialize] + public static void AssemblyInit(TestContext testContext) + { + _ = [|testContext.DataRow|]; + _ = [|testContext.DataConnection|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } +#endif + + [TestMethod] + public async Task WhenAllowedPropertiesAccessedInFixtureMethods_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyInitialize] + public static void AssemblyInit(TestContext testContext) + { + // These properties should be allowed in fixture methods + _ = testContext.Properties; + testContext.WriteLine("test"); + testContext.Write("test"); + } + + [ClassInitialize] + public static void ClassInit(TestContext testContext) + { + // These properties should be allowed in class initialize + _ = testContext.FullyQualifiedTestClassName; + _ = testContext.ManagedType; + _ = testContext.Properties; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } +} diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/TestContextShouldBeValidAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/TestContextShouldBeValidAnalyzerTests.cs index efd9c1c560..ad6598ca1a 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/TestContextShouldBeValidAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/TestContextShouldBeValidAnalyzerTests.cs @@ -472,4 +472,50 @@ public class MyTestClass await VerifyCS.VerifyCodeFixAsync(code, code); } + + [TestMethod] + public async Task WhenTestContextAssignedInConstructorWithNullCheck_NoDiagnostic() + { + string code = """ + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + private readonly TestContext _testContext; + + public MyTestClass(TestContext testContext) + { + _testContext = testContext ?? throw new ArgumentNullException(nameof(testContext)); + } + + public TestContext TestContext => _testContext; + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, code); + } + + [TestMethod] + public async Task WhenTestContextPropertyAssignedInConstructorWithNullCheck_NoDiagnostic() + { + string code = """ + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + public MyTestClass(TestContext testContext) + { + TestContext = testContext ?? throw new ArgumentNullException(nameof(testContext)); + } + + public TestContext TestContext { get; } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, code); + } } diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/TestInitializeShouldBeValidAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/TestInitializeShouldBeValidAnalyzerTests.cs index d8eb9cbe5e..05367fc67d 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/TestInitializeShouldBeValidAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/TestInitializeShouldBeValidAnalyzerTests.cs @@ -290,6 +290,7 @@ await VerifyCS.VerifyCodeFixAsync( fixedCode); } +#if NET [TestMethod] public async Task WhenTestInitializeReturnTypeIsNotValid_Diagnostic() { @@ -397,6 +398,7 @@ public ValueTask TestInitialize2() await VerifyCS.VerifyAnalyzerAsync(code); } +#endif [TestMethod] public async Task WhenTestInitializeIsAsyncVoid_Diagnostic() diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/TestMethodShouldBeValidAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/TestMethodShouldBeValidAnalyzerTests.cs index 05977b87d7..b311c1976f 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/TestMethodShouldBeValidAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/TestMethodShouldBeValidAnalyzerTests.cs @@ -247,6 +247,7 @@ public class MyTestClass await VerifyCS.VerifyAnalyzerAsync(code); } +#if NET [TestMethod] public async Task WhenTestMethodReturnTypeIsNotValid_Diagnostic() { @@ -346,6 +347,7 @@ public ValueTask MyTestMethod2() await VerifyCS.VerifyCodeFixAsync(code, code); } +#endif [TestMethod] public async Task WhenTestMethodIsAsyncVoid_Diagnostic() diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs index ebbd1131ab..bec343fbaf 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs @@ -290,4 +290,176 @@ public void TestMethod1() await VerifyCS.VerifyCodeFixAsync(code, fixedCode); } + + [TestMethod] + public async Task WhenStructWithTestMethod_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public struct [|TestStruct|] + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class TestStruct + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenStructWithoutTestMethod_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public struct TestStruct + { + public void RegularMethod() + { + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenRecordStructWithTestMethod_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public record struct [|TestRecordStruct|] + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public record TestRecordStruct + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenRecordClassWithTestMethod_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public record class [|TestRecordClass|] + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public record class TestRecordClass + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenRecordWithTestMethod_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public record [|TestRecord|] + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public record TestRecord + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenReadonlyRecordStructWithTestMethod_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public readonly record struct [|TestRecordStruct|] + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public record TestRecordStruct + { + [TestMethod] + public void TestMethod1() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } } diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/UnusedParameterSuppressorTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/UnusedParameterSuppressorTests.cs new file mode 100644 index 0000000000..d620499902 --- /dev/null +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/UnusedParameterSuppressorTests.cs @@ -0,0 +1,298 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier< + MSTest.Analyzers.UnitTests.UnusedParameterSuppressorTests.WarnForUnusedParameters, + Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; + +namespace MSTest.Analyzers.UnitTests; + +[TestClass] +public sealed class UnusedParameterSuppressorTests +{ + [TestMethod] + public async Task AssemblyInitializeWithUnusedTestContext_DiagnosticIsSuppressed() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class SomeClass + { + [AssemblyInitialize] + public static void Initialize(TestContext {|#0:context|}) + { + // TestContext parameter is unused but required by MSTest + } + } + """; + + // Verify issue is reported without suppressor + await new VerifyCS.Test + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForUnusedParameters.Rule) + .WithLocation(0) + .WithArguments("context") + .WithIsSuppressed(false), + }, + }.RunAsync(); + + // Verify issue is suppressed with suppressor + await new TestWithSuppressor + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForUnusedParameters.Rule) + .WithLocation(0) + .WithArguments("context") + .WithIsSuppressed(true), + }, + }.RunAsync(); + } + + [TestMethod] + public async Task ClassInitializeWithUnusedTestContext_DiagnosticIsSuppressed() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class SomeClass + { + [ClassInitialize] + public static void Initialize(TestContext {|#0:context|}) + { + // TestContext parameter is unused but required by MSTest + } + } + """; + + // Verify issue is reported without suppressor + await new VerifyCS.Test + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForUnusedParameters.Rule) + .WithLocation(0) + .WithArguments("context") + .WithIsSuppressed(false), + }, + }.RunAsync(); + + // Verify issue is suppressed with suppressor + await new TestWithSuppressor + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForUnusedParameters.Rule) + .WithLocation(0) + .WithArguments("context") + .WithIsSuppressed(true), + }, + }.RunAsync(); + } + + [TestMethod] + public async Task GlobalTestInitializeWithUnusedTestContext_DiagnosticIsSuppressed() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public static class SomeClass + { + [GlobalTestInitialize] + public static void Initialize(TestContext [|context|]) + { + // TestContext parameter is unused but required by MSTest + } + } + """; + + // Verify issue is reported without suppressor + await new VerifyCS.Test + { + TestState = { Sources = { code } }, + }.RunAsync(); + + // Verify issue is suppressed with suppressor + await new TestWithSuppressor + { + TestState = { Sources = { code } }, + }.RunAsync(); + } + + [TestMethod] + public async Task GlobalTestCleanupWithUnusedTestContext_DiagnosticIsSuppressed() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public static class SomeClass + { + [GlobalTestCleanup] + public static void Cleanup(TestContext [|context|]) + { + // TestContext parameter is unused but required by MSTest + } + } + """; + + // Verify issue is reported without suppressor + await new VerifyCS.Test + { + TestState = { Sources = { code } }, + }.RunAsync(); + + // Verify issue is suppressed with suppressor + await new TestWithSuppressor + { + TestState = { Sources = { code } }, + }.RunAsync(); + } + + [TestMethod] + public async Task TestMethodWithUnusedParameter_DiagnosticIsNotSuppressed() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class SomeClass + { + [TestMethod] + public void TestMethod(int {|#0:unusedParam|}) + { + // This should not be suppressed + } + } + """; + + // Verify issue is reported without suppressor + await new VerifyCS.Test + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForUnusedParameters.Rule) + .WithLocation(0) + .WithArguments("unusedParam") + .WithIsSuppressed(false), + }, + }.RunAsync(); + + // Verify issue is still reported with suppressor (not suppressed) + await new TestWithSuppressor + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForUnusedParameters.Rule) + .WithLocation(0) + .WithArguments("unusedParam") + .WithIsSuppressed(false), + }, + }.RunAsync(); + } + + [TestMethod] + public async Task RegularMethodWithUnusedTestContext_DiagnosticIsNotSuppressed() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class SomeClass + { + public void RegularMethod(TestContext {|#0:context|}) + { + // This should not be suppressed as it's not AssemblyInitialize or ClassInitialize + } + } + """; + + // Verify issue is reported without suppressor + await new VerifyCS.Test + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForUnusedParameters.Rule) + .WithLocation(0) + .WithArguments("context") + .WithIsSuppressed(false), + }, + }.RunAsync(); + + // Verify issue is still reported with suppressor (not suppressed) + await new TestWithSuppressor + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForUnusedParameters.Rule) + .WithLocation(0) + .WithArguments("context") + .WithIsSuppressed(false), + }, + }.RunAsync(); + } + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1038:Compiler extensions should be implemented in assemblies with compiler-provided references", Justification = "For suppression test only.")] + [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1036:Specify analyzer banned API enforcement setting", Justification = "For suppression test only.")] + [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1041:Compiler extensions should be implemented in assemblies targeting netstandard2.0", Justification = "For suppression test only.")] + public class WarnForUnusedParameters : DiagnosticAnalyzer + { + [SuppressMessage("MicrosoftCodeAnalysisDesign", "RS1017:DiagnosticId for analyzers must be a non-null constant.", Justification = "For suppression test only.")] + public static readonly DiagnosticDescriptor Rule = new(UnusedParameterSuppressor.Rule.SuppressedDiagnosticId, "Remove unused parameter", "Remove unused parameter '{0}' if it is not part of a shipped public API", "Style", DiagnosticSeverity.Warning, isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics => [Rule]; + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Parameter); + } + + private static void AnalyzeSymbol(SymbolAnalysisContext context) + { + if (context.Symbol is IParameterSymbol parameter) + { + // Simple mock: report all parameters as unused for testing purposes + var diagnostic = Diagnostic.Create( + Rule, + parameter.Locations.FirstOrDefault(), + parameter.Name); + context.ReportDiagnostic(diagnostic); + } + } + } + + internal sealed class TestWithSuppressor : VerifyCS.Test + { + protected override IEnumerable GetDiagnosticAnalyzers() + { + foreach (DiagnosticAnalyzer analyzer in base.GetDiagnosticAnalyzers()) + { + yield return analyzer; + } + + yield return new UnusedParameterSuppressor(); + } + } +} diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/UseAsyncSuffixTestFixtureMethodSuppressorTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/UseAsyncSuffixTestFixtureMethodSuppressorTests.cs index 069d599c3e..d72f02d562 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/UseAsyncSuffixTestFixtureMethodSuppressorTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/UseAsyncSuffixTestFixtureMethodSuppressorTests.cs @@ -26,22 +26,22 @@ public async Task AsyncTestFixtureMethodsWithoutSuffix_DiagnosticIsSuppressed() public class SomeClass { [AssemblyInitialize] - public static async Task [|AssemblyInitialize|]() { } + public static async Task {|#0:AssemblyInitialize|}() { } [AssemblyCleanup] - public static async Task [|AssemblyCleanup|]() { } + public static async Task {|#1:AssemblyCleanup|}() { } [ClassInitialize] - public static async Task [|ClassInitialize|]() { } + public static async Task {|#2:ClassInitialize|}() { } [ClassCleanup] - public static async Task [|ClassCleanup|]() { } + public static async Task {|#3:ClassCleanup|}() { } [TestInitialize] - public async Task [|TestInitialize|]() { } + public async Task {|#4:TestInitialize|}() { } [TestCleanup] - public async Task [|TestCleanup|]() { } + public async Task {|#5:TestCleanup|}() { } } "; @@ -49,11 +49,101 @@ public class SomeClass await new VerifyCS.Test { TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(0) + .WithIsSuppressed(false), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(1) + .WithIsSuppressed(false), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(2) + .WithIsSuppressed(false), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(3) + .WithIsSuppressed(false), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(4) + .WithIsSuppressed(false), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(5) + .WithIsSuppressed(false), + }, + }.RunAsync(); + + await new TestWithSuppressor + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(0) + .WithIsSuppressed(true), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(1) + .WithIsSuppressed(true), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(2) + .WithIsSuppressed(true), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(3) + .WithIsSuppressed(true), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(4) + .WithIsSuppressed(true), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(5) + .WithIsSuppressed(true), + }, + }.RunAsync(); + } + + [TestMethod] + public async Task GlobalTestMethodsWithoutAsyncSuffix_DiagnosticIsSuppressed() + { + string code = @" +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public static class SomeClass +{ + [GlobalTestInitialize] + public static async Task {|#0:GlobalTestInitialize|}(TestContext context) { } + + [GlobalTestCleanup] + public static async Task {|#1:GlobalTestCleanup|}(TestContext context) { } +} +"; + + // Verify issues Are reported + await new VerifyCS.Test + { + TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(0) + .WithIsSuppressed(false), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(1) + .WithIsSuppressed(false), + }, }.RunAsync(); await new TestWithSuppressor { TestState = { Sources = { code } }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(0) + .WithIsSuppressed(true), + VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule) + .WithLocation(1) + .WithIsSuppressed(true), + }, }.RunAsync(); } @@ -61,33 +151,37 @@ public class SomeClass public async Task AsyncTestMethodWithSuffix_NoDiagnostic() { string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; - using System.Threading.Tasks; - using Microsoft.VisualStudio.TestTools.UnitTesting; + [TestClass] + public class SomeClass + { + [AssemblyInitialize] + public static async Task AssemblyInitializeAsync() { } - [TestClass] - public class SomeClass - { - [AssemblyInitialize] - public static async Task AssemblyInitializeAsync() { } + [AssemblyCleanup] + public static async Task AssemblyCleanupAsync() { } - [AssemblyCleanup] - public static async Task AssemblyCleanupAsync() { } + [ClassInitialize] + public static async Task ClassInitializeAsync() { } - [ClassInitialize] - public static async Task ClassInitializeAsync() { } + [ClassCleanup] + public static async Task ClassCleanupAsync() { } - [ClassCleanup] - public static async Task ClassCleanupAsync() { } + [TestInitialize] + public async Task TestInitializeAsync() { } - [TestInitialize] - public async Task TestInitializeAsync() { } + [TestCleanup] + public async Task TestCleanupAsync() { } - [TestCleanup] - public async Task TestCleanupAsync() { } - } + [GlobalTestInitialize] + public static async Task GlobalTestInitializeAsync(TestContext context) { } - """; + [GlobalTestCleanup] + public static async Task GlobalTestCleanupAsync(TestContext context) { } + } + """; await new VerifyCS.Test { @@ -104,7 +198,7 @@ public class WarnForMissingAsyncSuffix : DiagnosticAnalyzer [SuppressMessage("MicrosoftCodeAnalysisDesign", "RS1017:DiagnosticId for analyzers must be a non-null constant.", Justification = "For suppression test only.")] public static readonly DiagnosticDescriptor Rule = new(UseAsyncSuffixTestFixtureMethodSuppressor.Rule.SuppressedDiagnosticId, "Title", "Message", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + public override ImmutableArray SupportedDiagnostics => [Rule]; public override void Initialize(AnalysisContext context) { diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/UseAsyncSuffixTestMethodSuppressorTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/UseAsyncSuffixTestMethodSuppressorTests.cs index ba566c293c..95acdb7338 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/UseAsyncSuffixTestMethodSuppressorTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/UseAsyncSuffixTestMethodSuppressorTests.cs @@ -28,7 +28,7 @@ public async Task AsyncTestMethodWithoutSuffix_DiagnosticIsSuppressed() public class SomeClass { [TestMethod] - public async Task [|TestMethod|]() { } + public async Task {|#0:TestMethod|}() { } } """; @@ -37,11 +37,13 @@ public class SomeClass await new VerifyCS.Test { TestState = { Sources = { code } }, + ExpectedDiagnostics = { VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule).WithLocation(0).WithIsSuppressed(false) }, }.RunAsync(); await new TestWithSuppressor { TestState = { Sources = { code } }, + ExpectedDiagnostics = { VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule).WithLocation(0).WithIsSuppressed(true) }, }.RunAsync(); } @@ -58,7 +60,7 @@ public async Task AsyncDataTestMethodWithoutSuffix_DiagnosticIsSuppressed() public class SomeClass { [DataTestMethod, DataRow(0)] - public async Task [|TestMethod|](int arg) { } + public async Task {|#0:TestMethod|}(int arg) { } } """; @@ -66,11 +68,13 @@ public class SomeClass await new VerifyCS.Test { TestState = { Sources = { code } }, + ExpectedDiagnostics = { VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule).WithLocation(0).WithIsSuppressed(false) }, }.RunAsync(); await new TestWithSuppressor { TestState = { Sources = { code } }, + ExpectedDiagnostics = { VerifyCS.Diagnostic(WarnForMissingAsyncSuffix.Rule).WithLocation(0).WithIsSuppressed(true) }, }.RunAsync(); } @@ -107,7 +111,7 @@ public class WarnForMissingAsyncSuffix : DiagnosticAnalyzer [SuppressMessage("MicrosoftCodeAnalysisDesign", "RS1017:DiagnosticId for analyzers must be a non-null constant.", Justification = "For suppression test only.")] public static readonly DiagnosticDescriptor Rule = new(UseAsyncSuffixTestMethodSuppressor.Rule.SuppressedDiagnosticId, "Title", "Message", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + public override ImmutableArray SupportedDiagnostics => [Rule]; public override void Initialize(AnalysisContext context) { diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/UseAttributeOnTestMethodAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/UseAttributeOnTestMethodAnalyzerTests.cs index f7353183ad..8ddb170745 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/UseAttributeOnTestMethodAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/UseAttributeOnTestMethodAnalyzerTests.cs @@ -91,7 +91,7 @@ public void TestMethod() string fixedCode = $$""" using Microsoft.VisualStudio.TestTools.UnitTesting; - + {{MyExpectedExceptionAttributeDeclaration}} [TestClass] @@ -118,7 +118,7 @@ public async Task WhenMethodIsMarkedWithMultipleTestAttributesButNotWithTestMeth { string code = $$""" using Microsoft.VisualStudio.TestTools.UnitTesting; - + {{MyExpectedExceptionAttributeDeclaration}} [TestClass] @@ -134,7 +134,7 @@ public void TestMethod() string fixedCode = $$""" using Microsoft.VisualStudio.TestTools.UnitTesting; - + {{MyExpectedExceptionAttributeDeclaration}} [TestClass] @@ -149,7 +149,7 @@ public void TestMethod() } """; - await VerifyCS.VerifyCodeFixAsync(code, new[] { VerifyCS.Diagnostic(rule1).WithLocation(0), VerifyCS.Diagnostic(rule2).WithLocation(1) }, fixedCode); + await VerifyCS.VerifyCodeFixAsync(code, [VerifyCS.Diagnostic(rule1).WithLocation(0), VerifyCS.Diagnostic(rule2).WithLocation(1)], fixedCode); } [DynamicData(nameof(GetAttributeUsageExamples), DynamicDataSourceType.Method)] @@ -159,7 +159,7 @@ public async Task WhenMethodIsMarkedWithTestAttributeAndCustomTestMethod_NoDiagn string code = $$""" using System; using Microsoft.VisualStudio.TestTools.UnitTesting; - + {{MyExpectedExceptionAttributeDeclaration}} [TestClass] diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/UseCooperativeCancellationForTimeoutAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/UseCooperativeCancellationForTimeoutAnalyzerTests.cs new file mode 100644 index 0000000000..5d090b4bae --- /dev/null +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/UseCooperativeCancellationForTimeoutAnalyzerTests.cs @@ -0,0 +1,443 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier< + MSTest.Analyzers.UseCooperativeCancellationForTimeoutAnalyzer, + MSTest.Analyzers.UseCooperativeCancellationForTimeoutFixer>; + +namespace MSTest.Analyzers.Test; + +[TestClass] +public sealed class UseCooperativeCancellationForTimeoutAnalyzerTests +{ + [TestMethod] + public async Task WhenTimeoutAttributeHasCooperativeCancellationTrue_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + [Timeout(5000, CooperativeCancellation = true)] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, code); + } + + [TestMethod] + public async Task WhenTimeoutAttributeWithoutCooperativeCancellation_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + [[|Timeout(5000)|]] + public void MyTestMethod() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + [Timeout(5000, CooperativeCancellation = true)] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTimeoutAttributeWithCooperativeCancellationFalse_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + [[|Timeout(5000, CooperativeCancellation = false)|]] + public void MyTestMethod() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + [Timeout(5000, CooperativeCancellation = true)] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTimeoutAttributeOnNonTestMethod_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [[|Timeout(5000)|]] + public void NonTestMethod() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [Timeout(5000, CooperativeCancellation = true)] + public void NonTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTestMethodWithoutTimeoutAttribute_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, code); + } + + [TestMethod] + public async Task WhenTimeoutAttributeWithoutCooperativeCancellation_CodeFixAddsProperty() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + [{|#0:Timeout(5000)|}] + public void MyTestMethod() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + [Timeout(5000, CooperativeCancellation = true)] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, VerifyCS.Diagnostic().WithLocation(0), fixedCode); + } + + [TestMethod] + public async Task WhenTimeoutAttributeWithCooperativeCancellationFalse_CodeFixChangesToTrue() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + [{|#0:Timeout(5000, CooperativeCancellation = false)|}] + public void MyTestMethod() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + [Timeout(5000, CooperativeCancellation = true)] + public void MyTestMethod() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, VerifyCS.Diagnostic().WithLocation(0), fixedCode); + } + + [TestMethod] + public async Task WhenTimeoutAttributeOnClassInitialize_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [ClassInitialize] + [[|Timeout(5000)|]] + public static void MyClassInitialize(TestContext context) + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [ClassInitialize] + [Timeout(5000, CooperativeCancellation = true)] + public static void MyClassInitialize(TestContext context) + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTimeoutAttributeOnClassInitializeWithCooperativeCancellationTrue_NoDiagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [ClassInitialize] + [Timeout(5000, CooperativeCancellation = true)] + public static void MyClassInitialize(TestContext context) + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, code); + } + + [TestMethod] + public async Task WhenTimeoutAttributeOnAssemblyInitialize_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyInitialize] + [[|Timeout(5000)|]] + public static void MyAssemblyInitialize(TestContext context) + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyInitialize] + [Timeout(5000, CooperativeCancellation = true)] + public static void MyAssemblyInitialize(TestContext context) + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTimeoutAttributeOnTestInitialize_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestInitialize] + [[|Timeout(5000)|]] + public void MyTestInitialize() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestInitialize] + [Timeout(5000, CooperativeCancellation = true)] + public void MyTestInitialize() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTimeoutAttributeOnTestCleanup_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestCleanup] + [[|Timeout(5000)|]] + public void MyTestCleanup() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestCleanup] + [Timeout(5000, CooperativeCancellation = true)] + public void MyTestCleanup() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTimeoutAttributeOnClassCleanup_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [ClassCleanup] + [[|Timeout(5000)|]] + public static void MyClassCleanup() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [ClassCleanup] + [Timeout(5000, CooperativeCancellation = true)] + public static void MyClassCleanup() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTimeoutAttributeOnAssemblyCleanup_Diagnostic() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyCleanup] + [[|Timeout(5000)|]] + public static void MyAssemblyCleanup() + { + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyCleanup] + [Timeout(5000, CooperativeCancellation = true)] + public static void MyAssemblyCleanup() + { + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } +} diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/UseParallelizeAttributeAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/UseParallelizeAttributeAnalyzerTests.cs index 8872cb744b..bb48573015 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/UseParallelizeAttributeAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/UseParallelizeAttributeAnalyzerTests.cs @@ -24,7 +24,9 @@ private static async Task VerifyAsync(string code, bool includeTestAdapter, para if (includeTestAdapter) { // NOTE: Test constructor already adds TestFramework refs. +#pragma warning disable CS0618 // Type or member is obsolete test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(MSTestExecutor).Assembly.Location)); +#pragma warning restore CS0618 // Type or member is obsolete } test.ExpectedDiagnostics.AddRange(expected); diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/UseProperAssertMethodsAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/UseProperAssertMethodsAnalyzerTests.cs index 0be2307acd..53e6281640 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/UseProperAssertMethodsAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/UseProperAssertMethodsAnalyzerTests.cs @@ -1309,4 +1309,787 @@ public void MyTestMethod() await VerifyCS.VerifyAnalyzerAsync(code); } + + #region New test cases for string methods + + [TestMethod] + public async Task WhenAssertIsTrueWithStringStartsWith() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + {|#0:Assert.IsTrue(myString.StartsWith("Hello"))|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + Assert.StartsWith("Hello", myString); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(10,9): info MSTEST0037: Use 'Assert.StartsWith' instead of 'Assert.IsTrue' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("StartsWith", "IsTrue"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertIsTrueWithStringEndsWith() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + {|#0:Assert.IsTrue(myString.EndsWith("World"))|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + Assert.EndsWith("World", myString); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(10,9): info MSTEST0037: Use 'Assert.EndsWith' instead of 'Assert.IsTrue' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("EndsWith", "IsTrue"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertIsTrueWithStringContains() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + {|#0:Assert.IsTrue(myString.Contains("lo Wo"))|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + Assert.Contains("lo Wo", myString); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(10,9): info MSTEST0037: Use 'Assert.Contains' instead of 'Assert.IsTrue' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("Contains", "IsTrue"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertIsFalseWithStringStartsWith() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + {|#0:Assert.IsFalse(myString.StartsWith("Hello"))|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + Assert.DoesNotStartWith("Hello", myString); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(10,9): info MSTEST0037: Use 'Assert.DoesNotStartWith' instead of 'Assert.IsFalse' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("DoesNotStartWith", "IsFalse"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertIsFalseWithStringEndsWith() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + {|#0:Assert.IsFalse(myString.EndsWith("World"))|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + Assert.DoesNotEndWith("World", myString); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(10,9): info MSTEST0037: Use 'Assert.DoesNotEndWith' instead of 'Assert.IsFalse' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("DoesNotEndWith", "IsFalse"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertIsFalseWithStringContains() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + {|#0:Assert.IsFalse(myString.Contains("test"))|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + string myString = "Hello World"; + Assert.DoesNotContain("test", myString); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(10,9): info MSTEST0037: Use 'Assert.DoesNotContain' instead of 'Assert.IsFalse' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("DoesNotContain", "IsFalse"), + fixedCode); + } + + #endregion + + #region New test cases for collection methods + + [TestMethod] + public async Task WhenAssertIsTrueWithCollectionContains() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List { 1, 2, 3 }; + {|#0:Assert.IsTrue(list.Contains(2))|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List { 1, 2, 3 }; + Assert.Contains(2, list); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.Contains' instead of 'Assert.IsTrue' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("Contains", "IsTrue"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertIsFalseWithCollectionContains() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List { 1, 2, 3 }; + {|#0:Assert.IsFalse(list.Contains(4))|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List { 1, 2, 3 }; + Assert.DoesNotContain(4, list); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.DoesNotContain' instead of 'Assert.IsFalse' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("DoesNotContain", "IsFalse"), + fixedCode); + } + + #endregion + + #region New test cases for comparisons + + [TestMethod] + public async Task WhenAssertIsTrueWithGreaterThanComparison() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + int a = 5; + int b = 3; + {|#0:Assert.IsTrue(a > b)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + int a = 5; + int b = 3; + Assert.IsGreaterThan(b, a); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.IsGreaterThan' instead of 'Assert.IsTrue' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("IsGreaterThan", "IsTrue"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertIsFalseWithGreaterThanComparison() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + int a = 5; + int b = 3; + {|#0:Assert.IsFalse(a > b)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + int a = 5; + int b = 3; + Assert.IsLessThanOrEqualTo(b, a); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.IsLessThanOrEqualTo' instead of 'Assert.IsFalse' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("IsLessThanOrEqualTo", "IsFalse"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertIsTrueWithEqualsComparison() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + int a = 5; + int b = 5; + {|#0:Assert.IsTrue(a == b)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + int a = 5; + int b = 5; + Assert.AreEqual(b, a); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.AreEqual' instead of 'Assert.IsTrue' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("AreEqual", "IsTrue"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertIsFalseWithEqualsComparison() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + int a = 5; + int b = 3; + {|#0:Assert.IsFalse(a == b)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + int a = 5; + int b = 3; + Assert.AreNotEqual(b, a); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.AreNotEqual' instead of 'Assert.IsFalse' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("AreNotEqual", "IsFalse"), + fixedCode); + } + + #endregion + + #region New test cases for collection count + + [TestMethod] + public async Task WhenAssertAreEqualWithCollectionCountZero() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List(); + {|#0:Assert.AreEqual(0, list.Count)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List(); + Assert.IsEmpty(list); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.IsEmpty' instead of 'Assert.AreEqual' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("IsEmpty", "AreEqual"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertAreEqualWithCollectionCountNonZero() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List { 1, 2, 3 }; + {|#0:Assert.AreEqual(3, list.Count)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List { 1, 2, 3 }; + Assert.HasCount(3, list); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.HasCount' instead of 'Assert.AreEqual' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("HasCount", "AreEqual"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertAreNotEqualWithCollectionCountZero() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List(); + Assert.AreNotEqual(0, list.Count); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenAssertAreNotEqualWithCollectionCountNonZero() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List { 1, 2, 3 }; + Assert.AreNotEqual(3, list.Count); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenAssertAreNotEqualWithArrayLength() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + Assert.AreNotEqual(5, array.Length); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task WhenAssertAreEqualWithCollectionCountAndMessage_HasCount() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var myCollection = new List { 1, 2 }; + {|#0:Assert.AreEqual(2, myCollection.Count, "Wrong number of elements")|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var myCollection = new List { 1, 2 }; + Assert.HasCount(2, myCollection, "Wrong number of elements"); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.HasCount' instead of 'Assert.AreEqual' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("HasCount", "AreEqual"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertAreEqualWithCollectionCountZeroAndMessage_IsEmpty() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List(); + {|#0:Assert.AreEqual(0, list.Count, "Collection should be empty")|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List(); + Assert.IsEmpty(list, "Collection should be empty"); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.IsEmpty' instead of 'Assert.AreEqual' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("IsEmpty", "AreEqual"), + fixedCode); + } + + [TestMethod] + public async Task WhenAssertAreEqualWithCollectionCountAndMultipleParameters() + { + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List { 1, 2, 3 }; + {|#0:Assert.AreEqual(3, list.Count, "Wrong count: expected {0} but was {1}", 3, list.Count)|}; + } + } + """; + + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void MyTestMethod() + { + var list = new List { 1, 2, 3 }; + Assert.HasCount(3, list, "Wrong count: expected {0} but was {1}", 3, list.Count); + } + } + """; + + await VerifyCS.VerifyCodeFixAsync( + code, + // /0/Test0.cs(11,9): info MSTEST0037: Use 'Assert.HasCount' instead of 'Assert.AreEqual' + VerifyCS.DiagnosticIgnoringAdditionalLocations().WithLocation(0).WithArguments("HasCount", "AreEqual"), + fixedCode); + } + + #endregion } diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/CSharpCodeFixVerifier`2+Test.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/CSharpCodeFixVerifier`2+Test.cs index 3fc45b7658..05f286761c 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/CSharpCodeFixVerifier`2+Test.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/CSharpCodeFixVerifier`2+Test.cs @@ -19,7 +19,13 @@ public class Test : CSharpCodeFixTest { public Test() { +#if NET462 + ReferenceAssemblies = ReferenceAssemblies.NetFramework.Net462.Default; + TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(ValueTask<>).Assembly.Location)); + TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(IAsyncDisposable).Assembly.Location)); +#else ReferenceAssemblies = ReferenceAssemblies.Net.Net60; +#endif TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(ParallelizeAttribute).Assembly.Location)); TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(TestContext).Assembly.Location)); SolutionTransforms.Add((solution, projectId) => diff --git a/test/UnitTests/MSTest.Engine.UnitTests/Adapter_ExecuteRequestAsyncTests.cs b/test/UnitTests/MSTest.Engine.UnitTests/Adapter_ExecuteRequestAsyncTests.cs index 5100e968e7..73bc6395ab 100644 --- a/test/UnitTests/MSTest.Engine.UnitTests/Adapter_ExecuteRequestAsyncTests.cs +++ b/test/UnitTests/MSTest.Engine.UnitTests/Adapter_ExecuteRequestAsyncTests.cs @@ -27,19 +27,17 @@ public async Task ExecutableNode_ThatDoesNotThrow_ShouldReportPassed() }; var services = new Services(); - var adapter = new TestFramework(new(), new[] { new FactoryTestNodesBuilder(() => new[] { testNode }) }, new(), + var adapter = new TestFramework(new(), [new FactoryTestNodesBuilder(() => [testNode])], new(), services.ServiceProvider.GetSystemClock(), services.ServiceProvider.GetTask(), services.ServiceProvider.GetConfiguration(), new Platform.Capabilities.TestFramework.TestFrameworkCapabilities()); CancellationToken cancellationToken = CancellationToken.None; // Act -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. await adapter.ExecuteRequestAsync(new( new RunTestExecutionRequest(new(new("id"), new ClientInfo(string.Empty, string.Empty))), services.ServiceProvider.GetRequiredService(), new SemaphoreSlimRequestCompleteNotifier(new SemaphoreSlim(1)), cancellationToken)); -#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. // Assert IEnumerable nodeStateChanges = services.MessageBus.Messages.OfType(); @@ -62,18 +60,16 @@ public async Task ExecutableNode_ThatThrows_ShouldReportError() var services = new Services(); var fakeClock = (FakeClock)services.ServiceProvider.GetService(typeof(FakeClock))!; - var adapter = new TestFramework(new(), new[] { new FactoryTestNodesBuilder(() => new[] { testNode }) }, new(), + var adapter = new TestFramework(new(), [new FactoryTestNodesBuilder(() => [testNode])], new(), services.ServiceProvider.GetSystemClock(), services.ServiceProvider.GetTask(), services.ServiceProvider.GetConfiguration(), new Platform.Capabilities.TestFramework.TestFrameworkCapabilities()); CancellationToken cancellationToken = CancellationToken.None; // Act -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. await adapter.ExecuteRequestAsync(new( new RunTestExecutionRequest(new(new("id"), new ClientInfo(string.Empty, string.Empty))), services.ServiceProvider.GetRequiredService(), new SemaphoreSlimRequestCompleteNotifier(new SemaphoreSlim(1)), cancellationToken)); -#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. // Assert IEnumerable nodeStateChanges = services.MessageBus.Messages.OfType(); @@ -81,19 +77,18 @@ await adapter.ExecuteRequestAsync(new( Platform.Extensions.Messages.TestNode lastNode = nodeStateChanges.Last().TestNode; _ = lastNode.Properties.Single(); Assert.AreEqual("Oh no!", lastNode.Properties.Single().Exception!.Message); - Assert.IsTrue( - lastNode.Properties.Single().Exception!.StackTrace! - .Contains(nameof(ExecutableNode_ThatThrows_ShouldReportError)), "lastNode properties should contain the name of the test"); + Assert.Contains( + nameof(ExecutableNode_ThatThrows_ShouldReportError), lastNode.Properties.Single().Exception!.StackTrace!, "lastNode properties should contain the name of the test"); TimingProperty timingProperty = lastNode.Properties.Single(); Assert.AreEqual(fakeClock.UsedTimes[0], timingProperty.GlobalTiming.StartTime); Assert.IsTrue(timingProperty.GlobalTiming.StartTime <= timingProperty.GlobalTiming.EndTime, "start time is before (or the same as) stop time"); Assert.AreEqual(fakeClock.UsedTimes[1], timingProperty.GlobalTiming.EndTime); - Assert.IsTrue(timingProperty.GlobalTiming.Duration.TotalMilliseconds > 0, $"duration should be greater than 0"); + Assert.IsGreaterThan(0, timingProperty.GlobalTiming.Duration.TotalMilliseconds, $"duration should be greater than 0"); } private sealed class FakeClock : IClock { - public List UsedTimes { get; } = new(); + public List UsedTimes { get; } = []; public DateTimeOffset UtcNow { @@ -115,9 +110,7 @@ public Services() ServiceProvider.AddService(new LoggerFactory()); ServiceProvider.AddService(new FakeClock()); ServiceProvider.AddService(new SystemTask()); -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - ServiceProvider.AddService(new AggregatedConfiguration(Array.Empty(), new CurrentTestApplicationModuleInfo(new SystemEnvironment(), new SystemProcessHandler()), new SystemFileSystem(), new(null, [], []))); -#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + ServiceProvider.AddService(new AggregatedConfiguration([], new CurrentTestApplicationModuleInfo(new SystemEnvironment(), new SystemProcessHandler()), new SystemFileSystem(), new(null, [], []))); } public MessageBus MessageBus { get; } @@ -127,7 +120,7 @@ public Services() private sealed class MessageBus : IMessageBus { - public List Messages { get; } = new(); + public List Messages { get; } = []; public Task PublishAsync(IDataProducer dataProducer, IData data) { diff --git a/test/UnitTests/MSTest.Engine.UnitTests/BFSTestNodeVisitorTests.cs b/test/UnitTests/MSTest.Engine.UnitTests/BFSTestNodeVisitorTests.cs index 847ecdf276..0676c3dd5f 100644 --- a/test/UnitTests/MSTest.Engine.UnitTests/BFSTestNodeVisitorTests.cs +++ b/test/UnitTests/MSTest.Engine.UnitTests/BFSTestNodeVisitorTests.cs @@ -4,7 +4,6 @@ using Microsoft.Testing.Platform.Extensions.Messages; using Microsoft.Testing.Platform.Requests; -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. namespace Microsoft.Testing.Framework.UnitTests; [TestClass] @@ -18,21 +17,21 @@ public async Task Visit_WhenFilterDoesNotUseEncodedSlash_NodeIsNotIncluded() { StableUid = "ID1", DisplayName = "A", - Tests = new[] - { + Tests = + [ new TestNode { StableUid = "ID2", DisplayName = "B/C", }, - }, + ], }; var filter = new TreeNodeFilter("/A/B/C"); var visitor = new BFSTestNodeVisitor(new[] { rootNode }, filter, null!); // Act - List includedTestNodes = new(); + List includedTestNodes = []; await visitor.VisitAsync((testNode, _) => { includedTestNodes.Add(testNode); @@ -40,7 +39,7 @@ await visitor.VisitAsync((testNode, _) => }); // Assert - Assert.AreEqual(1, includedTestNodes.Count); + Assert.HasCount(1, includedTestNodes); Assert.AreEqual("ID1", includedTestNodes[0].StableUid); } @@ -55,21 +54,21 @@ public async Task Visit_WhenFilterUsesEncodedEntry_NodeIsIncluded(string nodeSpe { StableUid = "ID1", DisplayName = "A", - Tests = new[] - { + Tests = + [ new TestNode { StableUid = "ID2", DisplayName = "B" + nodeSpecialString + "C", }, - }, + ], }; var filter = new TreeNodeFilter("/A/B" + filterEncodedSpecialString + "C"); var visitor = new BFSTestNodeVisitor(new[] { rootNode }, filter, null!); // Act - List includedTestNodes = new(); + List includedTestNodes = []; await visitor.VisitAsync((testNode, _) => { includedTestNodes.Add(testNode); @@ -77,7 +76,7 @@ await visitor.VisitAsync((testNode, _) => }); // Assert - Assert.AreEqual(2, includedTestNodes.Count); + Assert.HasCount(2, includedTestNodes); Assert.AreEqual("ID1", includedTestNodes[0].StableUid); Assert.AreEqual("ID2", includedTestNodes[1].StableUid); } @@ -107,7 +106,7 @@ public async Task Visit_WhenNodeIsNotParameterizedNode_DoesNotExpand(string nonP var visitor = new BFSTestNodeVisitor(new[] { rootNode }, new NopFilter(), null!); // Act - List includedTestNodes = new(); + List includedTestNodes = []; await visitor.VisitAsync((testNode, _) => { includedTestNodes.Add(testNode); @@ -115,7 +114,7 @@ await visitor.VisitAsync((testNode, _) => }); // Assert - Assert.AreEqual(1, includedTestNodes.Count); + Assert.HasCount(1, includedTestNodes); Assert.AreEqual("ID1", includedTestNodes[0].StableUid); } @@ -129,7 +128,7 @@ public async Task Visit_WhenNodeIsParameterizedNodeAndPropertyIsAbsentOrTrue_Exp var visitor = new BFSTestNodeVisitor(new[] { rootNode }, new NopFilter(), new TestArgumentsManager()); // Act - List<(TestNode Node, TestNodeUid? ParentNodeUid)> includedTestNodes = new(); + List<(TestNode Node, TestNodeUid? ParentNodeUid)> includedTestNodes = []; await visitor.VisitAsync((testNode, parentNodeUid) => { includedTestNodes.Add((testNode, parentNodeUid)); @@ -137,7 +136,7 @@ await visitor.VisitAsync((testNode, parentNodeUid) => }); // Assert - Assert.AreEqual(3, includedTestNodes.Count); + Assert.HasCount(3, includedTestNodes); Assert.AreEqual("ID1", includedTestNodes[0].Node.StableUid); Assert.IsNull(includedTestNodes[0].ParentNodeUid); @@ -158,7 +157,7 @@ public async Task Visit_WhenNodeIsParameterizedNodeAndDoesNotAllowExpansion_Does var visitor = new BFSTestNodeVisitor(new[] { rootNode }, new NopFilter(), new TestArgumentsManager()); // Act - List<(TestNode Node, TestNodeUid? ParentNodeUid)> includedTestNodes = new(); + List<(TestNode Node, TestNodeUid? ParentNodeUid)> includedTestNodes = []; await visitor.VisitAsync((testNode, parentNodeUid) => { includedTestNodes.Add((testNode, parentNodeUid)); @@ -166,7 +165,7 @@ await visitor.VisitAsync((testNode, parentNodeUid) => }); // Assert - Assert.AreEqual(1, includedTestNodes.Count); + Assert.HasCount(1, includedTestNodes); } [TestMethod] @@ -177,14 +176,14 @@ public async Task Visit_WithModuleNamespaceClassMethodLevelAndExpansion_Discover { StableUid = "MyModule", DisplayName = "MyModule", - Tests = new[] - { + Tests = + [ new TestNode { StableUid = "MyNamespace", DisplayName = "MyNamespace", - Tests = new[] - { + Tests = + [ new TestNode { StableUid = "MyType", @@ -200,14 +199,14 @@ public async Task Visit_WithModuleNamespaceClassMethodLevelAndExpansion_Discover }, }, }, - }, + ], }, - }, + ], }; var visitor = new BFSTestNodeVisitor(new[] { rootNode }, new NopFilter(), new TestArgumentsManager()); // Act - List<(TestNode Node, TestNodeUid? ParentNodeUid)> includedTestNodes = new(); + List<(TestNode Node, TestNodeUid? ParentNodeUid)> includedTestNodes = []; await visitor.VisitAsync((testNode, parentNodeUid) => { includedTestNodes.Add((testNode, parentNodeUid)); @@ -215,7 +214,7 @@ await visitor.VisitAsync((testNode, parentNodeUid) => }); // Assert - Assert.AreEqual(7, includedTestNodes.Count); + Assert.HasCount(7, includedTestNodes); Assert.AreEqual("MyModule", includedTestNodes[0].Node.StableUid); Assert.IsNull(includedTestNodes[0].ParentNodeUid); @@ -267,13 +266,13 @@ private static TestNode CreateParameterizedTestNode(string parameterizedTestNode static IEnumerable GetArguments() => new byte[] { 0, 1 }; static IProperty[] GetProperties(bool? hasExpansionProperty) => hasExpansionProperty.HasValue - ? new IProperty[1] - { + ? + [ new FrameworkEngineMetadataProperty { PreventArgumentsExpansion = hasExpansionProperty.Value, }, - } - : Array.Empty(); + ] + : []; } } diff --git a/test/UnitTests/MSTest.Engine.UnitTests/DynamicDataNameProviderTests.cs b/test/UnitTests/MSTest.Engine.UnitTests/DynamicDataNameProviderTests.cs index f511c2ff51..f6c7004659 100644 --- a/test/UnitTests/MSTest.Engine.UnitTests/DynamicDataNameProviderTests.cs +++ b/test/UnitTests/MSTest.Engine.UnitTests/DynamicDataNameProviderTests.cs @@ -15,7 +15,7 @@ public void NullTranslatesToNullString() // you will get empty string while with the call you will get "null,a". // // check that this is still true: - string fragment = DynamicDataNameProvider.GetUidFragment(["parameter1", "parameter2"], new object?[] { null, "a" }, 0); + string fragment = DynamicDataNameProvider.GetUidFragment(["parameter1", "parameter2"], [null, "a"], 0); Assert.AreEqual("(parameter1: null, parameter2: a)[0]", fragment); } @@ -28,7 +28,7 @@ public void ParameterMismatchShowsDataInMessage() // you will get empty string while with the call you will get "null,a". // // check that this is still true: - ArgumentException exception = Assert.ThrowsException(() => DynamicDataNameProvider.GetUidFragment(["parameter1"], new object?[] { null, "a" }, 0)); + ArgumentException exception = Assert.ThrowsExactly(() => DynamicDataNameProvider.GetUidFragment(["parameter1"], [null, "a"], 0)); Assert.AreEqual("Parameter count mismatch. The provided data (null, a) have 2 items, but there are 1 parameters.", exception.Message); } } diff --git a/test/UnitTests/MSTest.Engine.UnitTests/DynamicDataTests.cs b/test/UnitTests/MSTest.Engine.UnitTests/DynamicDataTests.cs index ea608a39d3..1fa1ce4990 100644 --- a/test/UnitTests/MSTest.Engine.UnitTests/DynamicDataTests.cs +++ b/test/UnitTests/MSTest.Engine.UnitTests/DynamicDataTests.cs @@ -10,11 +10,11 @@ namespace Microsoft.Testing.Framework.UnitTests; public class DynamicDataTests { public static IEnumerable IntDataProperty - => new[] - { - new object[] { 1, 2 }, - new object[] { 2, 3 }, - }; + => + [ + [1, 2], + [2, 3] + ]; [DynamicData(nameof(IntDataProperty))] [TestMethod] @@ -37,11 +37,11 @@ public void DynamicDataWithIntMethodAndExplicitSourceType(int expected, int actu => Assert.AreEqual(expected, actualPlus1 - 1); public static IEnumerable IntDataMethod() - => new[] - { - new object[] { 1, 2 }, - new object[] { 2, 3 }, - }; + => + [ + [1, 2], + [2, 3] + ]; [DynamicData(nameof(IntDataProperty), typeof(DataClass))] [TestMethod] @@ -60,11 +60,11 @@ public void DynamicDataWithUserProperty(User _, User _2) } public static IEnumerable UserDataProperty - => new[] - { - new object[] { new User("Jakub"), new User("Amaury") }, - new object[] { new User("Marco"), new User("Pavel") }, - }; + => + [ + [new User("Jakub"), new User("Amaury")], + [new User("Marco"), new User("Pavel")] + ]; [DynamicData(nameof(UserDataMethod), DynamicDataSourceType.Method)] [TestMethod] @@ -73,28 +73,28 @@ public void DynamicDataWithUserMethod(User _, User _2) } public static IEnumerable UserDataMethod() - => new[] - { - new object[] { new User("Jakub"), new User("Amaury") }, - new object[] { new User("Marco"), new User("Pavel") }, - }; + => + [ + [new User("Jakub"), new User("Amaury")], + [new User("Marco"), new User("Pavel")] + ]; } public class DataClass { public static IEnumerable IntDataProperty - => new[] - { - new object[] { 1, 3 }, - new object[] { 2, 4 }, - }; + => + [ + [1, 3], + [2, 4] + ]; public static IEnumerable IntDataMethod() - => new[] - { - new object[] { 1, 3 }, - new object[] { 2, 4 }, - }; + => + [ + [1, 3], + [2, 4] + ]; } public class User diff --git a/test/UnitTests/MSTest.Engine.UnitTests/TestBase.cs b/test/UnitTests/MSTest.Engine.UnitTests/TestBase.cs index 9c09f265b5..0e748f47ce 100644 --- a/test/UnitTests/MSTest.Engine.UnitTests/TestBase.cs +++ b/test/UnitTests/MSTest.Engine.UnitTests/TestBase.cs @@ -6,6 +6,4 @@ namespace Microsoft.Testing.Framework.UnitTests; /// /// Empty test base, because TestInfrastructure project depends on Testing.Framework, and we cannot use that. /// -public abstract class TestBase -{ -} +public abstract class TestBase; diff --git a/test/UnitTests/MSTest.SelfRealExamples.UnitTests/MSTest.SelfRealExamples.UnitTests.csproj b/test/UnitTests/MSTest.SelfRealExamples.UnitTests/MSTest.SelfRealExamples.UnitTests.csproj new file mode 100644 index 0000000000..f8e01b977b --- /dev/null +++ b/test/UnitTests/MSTest.SelfRealExamples.UnitTests/MSTest.SelfRealExamples.UnitTests.csproj @@ -0,0 +1,29 @@ + + + + Exe + net472;net9.0 + enable + Exe + true + + + + + + + + + + + + + + + + + + + + + diff --git a/test/UnitTests/MSTest.SelfRealExamples.UnitTests/ParameterizedTestSerializationIssue2390.cs b/test/UnitTests/MSTest.SelfRealExamples.UnitTests/ParameterizedTestSerializationIssue2390.cs new file mode 100644 index 0000000000..073cc54902 --- /dev/null +++ b/test/UnitTests/MSTest.SelfRealExamples.UnitTests/ParameterizedTestSerializationIssue2390.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MSTest.SelfRealExamples.UnitTests; + +// Test for https://github.com/microsoft/testfx/issues/2390 +[TestClass] +public class ParameterizedTestSerializationIssue2390 +{ + [TestMethod] + [DataRow((byte)0, new object[] { (byte)0 })] + [DataRow((short)0, new object[] { (short)0 })] + [DataRow(0L, new object[] { 0L })] + public void CheckNestedInputTypes(object expected, object nested) + { + object[] array = (object[])nested; + object actual = Assert.ContainsSingle(array); +#if NETFRAMEWORK + // Buggy behavior, because of app domains. + Assert.AreEqual(typeof(int), actual.GetType()); +#else + Assert.AreEqual(expected.GetType(), actual.GetType()); + Assert.AreEqual(expected, actual); +#endif + } +} diff --git a/test/UnitTests/MSTest.SelfRealExamples.UnitTests/Program.cs b/test/UnitTests/MSTest.SelfRealExamples.UnitTests/Program.cs new file mode 100644 index 0000000000..904b1066e1 --- /dev/null +++ b/test/UnitTests/MSTest.SelfRealExamples.UnitTests/Program.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Extensions; +using Microsoft.Testing.Platform.Builder; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[assembly: Parallelize(Scope = Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope.ClassLevel, Workers = 0)] + +ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args); + +testApplicationBuilder.AddMSTest(() => [Assembly.GetEntryAssembly()!]); +testApplicationBuilder.AddTrxReportProvider(); +testApplicationBuilder.AddAppInsightsTelemetryProvider(); +testApplicationBuilder.AddCodeCoverageProvider(); +testApplicationBuilder.AddAzureDevOpsProvider(); +using ITestApplication testApplication = await testApplicationBuilder.BuildAsync(); +return await testApplication.RunAsync(); diff --git a/test/UnitTests/MSTest.SelfRealExamples.UnitTests/TestExecutionContextPropagationFromTestMethodAttributeToTestMethod.cs b/test/UnitTests/MSTest.SelfRealExamples.UnitTests/TestExecutionContextPropagationFromTestMethodAttributeToTestMethod.cs new file mode 100644 index 0000000000..274c3c5524 --- /dev/null +++ b/test/UnitTests/MSTest.SelfRealExamples.UnitTests/TestExecutionContextPropagationFromTestMethodAttributeToTestMethod.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MSTest.SelfRealExamples.UnitTests; + +[TestClass] +public sealed class TestExecutionContextPropagationFromTestMethodAttributeToTestMethod +{ + private static readonly AsyncLocal State = new(); + + [ClassInitialize] + public static void ClassInitialize(TestContext testContext) + { + } + + [MyTestMethod] + public void TestAsyncLocalValueIsPreserved() + => Assert.AreEqual("In Execute", State.Value); + + private sealed class MyTestMethodAttribute : TestMethodAttribute + { + public override TestResult[] Execute(ITestMethod testMethod) + { + State.Value = "In Execute"; + return base.Execute(testMethod); + } + } +} diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/DataRowAttributeGenerationTests.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/DataRowAttributeGenerationTests.cs index 352b28d89f..905e697241 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/DataRowAttributeGenerationTests.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/DataRowAttributeGenerationTests.cs @@ -13,6 +13,8 @@ namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests.Generators; [TestClass] public sealed class DataRowAttributeGenerationTests : TestBase { + public TestContext TestContext { get; set; } + [TestMethod] public async Task DataRowAttribute_HandlesPrimitiveTypes() { @@ -98,7 +100,7 @@ public Task MethodWithUShort(ushort s) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -213,7 +215,7 @@ public Task TestMethod(string s, int i, bool b, double d) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry<(string s, int i)>[] @@ -257,7 +259,7 @@ public Task TestMethod(string a) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -301,7 +303,7 @@ public Task TestMethod(Type a) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -348,7 +350,7 @@ public Task TestMethod(MyEnum a) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -408,7 +410,7 @@ public Task TestMethod(MyEnum a) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -462,7 +464,7 @@ public Task TestMethod(ConflictingNamespace.MyEnum a) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -511,7 +513,7 @@ public Task TestMethod1(string s, object a) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -565,7 +567,7 @@ public Task TestMethod2(string a, string b) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" // The test method is parameterized but no argument was specified. @@ -646,7 +648,7 @@ public Task OneObjectArray(object[] args) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -683,7 +685,7 @@ public Task OneIntArray(int[] args) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -720,7 +722,7 @@ public Task OneStringArray(string[] args) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -756,7 +758,7 @@ public Task OneParamsObjectArray2(object[] args) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -794,7 +796,7 @@ public Task OneIntArray(object[] args) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry[] @@ -831,7 +833,7 @@ public Task TwoObjectArrays(object[] args, object[] args2) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => new MSTF::InternalUnsafeTestArgumentsEntry<(object[] args, object[] args2)>[] diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/DynamicDataAttributeTests.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/DynamicDataAttributeTests.cs index 1016eaf683..21c0def72c 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/DynamicDataAttributeTests.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/DynamicDataAttributeTests.cs @@ -13,6 +13,8 @@ namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests.Generators; [TestClass] public sealed class DynamicDataAttributeGenerationTests : TestBase { + public TestContext TestContext { get; set; } + [TestMethod] public async Task DynamicDataAttribute_TakesDataFromProperty() { @@ -47,7 +49,7 @@ public void TestMethod(int expected, int actualPlus1) SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => { @@ -99,7 +101,7 @@ public static IEnumerable Data() => new[] SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" GetArguments = static () => { diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/IgnoreAttributeGenerationTests.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/IgnoreAttributeGenerationTests.cs index 26e69d96c2..402f796376 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/IgnoreAttributeGenerationTests.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/IgnoreAttributeGenerationTests.cs @@ -13,6 +13,8 @@ namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests.Generators; [TestClass] public sealed class IgnoreAttributeGenerationTests : TestBase { + public TestContext TestContext { get; set; } + [TestMethod] public async Task IgnoreAttribute_OnMethodExcludesTheMethodFromCompilation() { @@ -62,7 +64,7 @@ public void IgnoredVoidMethodWithReason() { } SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode("""StableUid = "TestAssembly.MyNamespace.TestClass.TestMethod1()","""); diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/StaticMethodGenerationTests.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/StaticMethodGenerationTests.cs index 8a5a7de839..d536926a30 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/StaticMethodGenerationTests.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/StaticMethodGenerationTests.cs @@ -13,6 +13,8 @@ namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests.Generators; [TestClass] public sealed class StaticMethodGenerationTests { + public TestContext TestContext { get; set; } + [TestMethod] public async Task StaticMethods_StaticMethodsWontGenerateTests() { @@ -46,7 +48,7 @@ public static void StaticTestMethod() { } SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode("""StableUid = "TestAssembly.MyNamespace.TestClass.TestMethod1()","""); diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/TestNodesGeneratorTests.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/TestNodesGeneratorTests.cs index 7695466e03..c528c601ba 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/TestNodesGeneratorTests.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/TestNodesGeneratorTests.cs @@ -13,6 +13,8 @@ namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests.Generators; [TestClass] public sealed class TestNodesGeneratorTests : TestBase { + public TestContext TestContext { get; set; } + [DataRow("class", "public")] [DataRow("class", "internal")] [DataRow("record", "public")] @@ -44,7 +46,7 @@ public Task TestMethod() generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(3); - SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); myTypeSource.Should().ContainSourceCode(""" public static readonly MSTF::TestNode TestNode = new MSTF::TestNode { @@ -89,7 +91,7 @@ public Task TestMethod() }; """); - SourceText rootSource = await generatorResult.RunResult.GeneratedTrees[1].GetTextAsync(); + SourceText rootSource = await generatorResult.RunResult.GeneratedTrees[1].GetTextAsync(TestContext.CancellationTokenSource.Token); rootSource.Should().ContainSourceCode(""" MSTF::TestNode root = new MSTF::TestNode { @@ -223,7 +225,7 @@ public Task TestMethod() generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(3); - SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); myTypeSource.Should().ContainSourceCode(""" public static readonly MSTF::TestNode TestNode = new MSTF::TestNode { @@ -330,7 +332,7 @@ public Task TestMethod() generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(4); - SourceText myBaseClassSource = await generatorResult.GeneratedTrees[0].GetTextAsync(); + SourceText myBaseClassSource = await generatorResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); myBaseClassSource.Should().ContainSourceCode(""" public static readonly MSTF::TestNode TestNode = new MSTF::TestNode { @@ -375,7 +377,7 @@ public Task TestMethod() }; """); - SourceText myTypeSource = await generatorResult.GeneratedTrees[1].GetTextAsync(); + SourceText myTypeSource = await generatorResult.GeneratedTrees[1].GetTextAsync(TestContext.CancellationTokenSource.Token); myTypeSource.Should().ContainSourceCode(""" public static readonly MSTF::TestNode TestNode = new MSTF::TestNode { @@ -488,7 +490,7 @@ public Task TestMethod() generatorResult.AssertSuccessfulGeneration(); generatorResult.RunResult.GeneratedTrees.Should().HaveCount(3); - SourceText testClass = await generatorResult.GeneratedTrees[0].GetTextAsync(); + SourceText testClass = await generatorResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode( "public static readonly MSTF::TestNode TestNode = new MSTF::TestNode", @@ -533,7 +535,7 @@ public Task TestMethod2() SyntaxTree? testClassTree = generatorResult.GeneratedTrees.FirstOrDefault(r => r.FilePath.EndsWith("TestSubClass.g.cs", StringComparison.OrdinalIgnoreCase)); testClassTree.Should().NotBeNull(); - SourceText testClass = await testClassTree!.GetTextAsync(); + SourceText testClass = await testClassTree!.GetTextAsync(TestContext.CancellationTokenSource.Token); testClass.Should().ContainSourceCode(""" new MSTF::InternalUnsafeAsyncActionTestNode { @@ -589,7 +591,7 @@ public Task TestMethod() generatorResult.AssertSuccessfulGeneration(); generatorResult.RunResult.GeneratedTrees.Should().HaveCount(3); - SourceText myTypeSource = await generatorResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); myTypeSource.Should().ContainSourceCode(""" public static readonly MSTF::TestNode TestNode = new MSTF::TestNode { @@ -601,7 +603,7 @@ public Task TestMethod() }, """); - SourceText rootSource = await generatorResult.GeneratedTrees[1].GetTextAsync(); + SourceText rootSource = await generatorResult.GeneratedTrees[1].GetTextAsync(TestContext.CancellationTokenSource.Token); rootSource.Should().ContainSourceCode(""" MSTF::TestNode root = new MSTF::TestNode { @@ -626,25 +628,24 @@ public Task TestMethod() public async Task When_MultipleClassesFromSameNamespace_ItGeneratesASingleNamespaceTestNode() { GeneratorCompilationResult generatorResult = await GeneratorTester.TestGraph.CompileAndExecuteAsync( - new[] - { - $$""" - using System.Threading.Tasks; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - namespace MyNamespace - { - [TestClass] - public class MyType1 - { - [TestMethod] - public Task TestMethod() - { - return Task.CompletedTask; - } - } - } - """, + [ + $$""" + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyNamespace + { + [TestClass] + public class MyType1 + { + [TestMethod] + public Task TestMethod() + { + return Task.CompletedTask; + } + } + } + """, $$""" using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -661,13 +662,13 @@ public Task TestMethod() } } } - """, - }, CancellationToken.None); + """ + ], CancellationToken.None); generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(4); - SourceText rootSource = await generatorResult.RunResult.GeneratedTrees[2].GetTextAsync(); + SourceText rootSource = await generatorResult.RunResult.GeneratedTrees[2].GetTextAsync(TestContext.CancellationTokenSource.Token); rootSource.Should().ContainSourceCode(""" ColGen::List namespace1Tests = new(); namespace1Tests.Add(MyNamespace_MyType1.TestNode); @@ -729,7 +730,7 @@ public Task InitializeAsync(InitializationContext context) generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(2); - SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); // The test node for the type should not have a test node for the InitializeAsync method. myTypeSource.Should().NotContain("StableUid = \"TestAssembly.MyNamespace.MyType.InitializeAsync\""); @@ -787,7 +788,7 @@ public Task CleanupAsync(CleanupContext context) generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(2); - SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); // The test node for the type should not have a test node for the CleanupAsync method. myTypeSource.Should().NotContain("StableUid = \"TestAssembly.MyNamespace.MyType.CleanupAsync\""); @@ -852,7 +853,7 @@ public void Dispose() generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(2); - SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); // The test node for the type should not have a test node for the Dispose method. myTypeSource.Should().NotContain("StableUid = \"TestAssembly.MyNamespace.MyType.Dispose\""); @@ -910,7 +911,7 @@ public ValueTask DisposeAsync() generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(2); - SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); // The test node for the type should not have a test node for the DisposeAsync method. myTypeSource.Should().NotContain("StableUid = \"TestAssembly.MyNamespace.MyType.DisposeAsync\""); @@ -972,7 +973,7 @@ public void Dispose() generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(2); - SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); // The body of the test node for the method should call only DisposeAsync after calling the test method. myTypeSource.Should().ContainSourceCode(""" @@ -1047,21 +1048,21 @@ public Task CleanupAsync(CleanupContext context) generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(4); - SourceText myClass1Source = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myClass1Source = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); myClass1Source.Should().ContainSourceCode(""" new MSTF::InternalUnsafeAsyncActionTestNode { StableUid = "TestAssembly.MyNamespace.MyClass1.TestMethod()", """); - SourceText myClass2Source = await generatorResult.RunResult.GeneratedTrees[1].GetTextAsync(); + SourceText myClass2Source = await generatorResult.RunResult.GeneratedTrees[1].GetTextAsync(TestContext.CancellationTokenSource.Token); myClass2Source.Should().ContainSourceCode(""" new MSTF::InternalUnsafeAsyncActionTestNode { StableUid = "TestAssembly.MyNamespace.MyClass2.TestMethod()", """); - SourceText myClass3Source = await generatorResult.RunResult.GeneratedTrees[2].GetTextAsync(); + SourceText myClass3Source = await generatorResult.RunResult.GeneratedTrees[2].GetTextAsync(TestContext.CancellationTokenSource.Token); myClass3Source.Should().ContainSourceCode(""" new MSTF::InternalUnsafeAsyncActionTestNode { @@ -1117,7 +1118,7 @@ public Task TestMethod4() generatorResult.AssertFailedGeneration("*error CS0619: 'MyType.TestMethod4()' is obsolete*"); generatorResult.GeneratedTrees.Should().HaveCount(3); - SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); myTypeSource.Should().ContainSourceCode(""" #pragma warning disable CS0612 // Type or member is obsolete await instance.TestMethod1(); @@ -1154,27 +1155,26 @@ public void GenerateValidNamespaceName_WithGivenAssemblyName_ReturnsExpectedName public async Task When_APartialTypeIsMarkedWithTestClass_ItGeneratesAGraphWithAssemblyNamespaceTypeAndMethods() { GeneratorCompilationResult generatorResult = await GeneratorTester.TestGraph.CompileAndExecuteAsync( - new string[] - { - $$""" - using System.Threading.Tasks; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - namespace MyNamespace - { - [TestClass] - public partial class MyType - { - public MyType(int a) { } - - [TestMethod] - public Task TestMethod1() - { - return Task.CompletedTask; - } - } - } - """, + [ + $$""" + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyNamespace + { + [TestClass] + public partial class MyType + { + public MyType(int a) { } + + [TestMethod] + public Task TestMethod1() + { + return Task.CompletedTask; + } + } + } + """, $$""" using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -1196,13 +1196,13 @@ public Task TestMethod2() } } } - """, - }, CancellationToken.None); + """ + ], CancellationToken.None); generatorResult.AssertSuccessfulGeneration(); generatorResult.GeneratedTrees.Should().HaveCount(3); - SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(); + SourceText myTypeSource = await generatorResult.RunResult.GeneratedTrees[0].GetTextAsync(TestContext.CancellationTokenSource.Token); myTypeSource.Should().ContainSourceCode(""" public static class MyNamespace_MyType { diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/MinimalTestRunner.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/MinimalTestRunner.cs index e00e391545..5537de1ad2 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/MinimalTestRunner.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/MinimalTestRunner.cs @@ -11,7 +11,7 @@ public static async Task RunAllAsync(string? testNameContainsFilter = null) #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code IEnumerable classes = Assembly.GetExecutingAssembly().GetTypes().Where(c => c.IsPublic); #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code - object[][] emptyRow = new[] { Array.Empty() }; + object[][] emptyRow = [[]]; int total = 0; int failed = 0; @@ -63,7 +63,7 @@ public static async Task RunAllAsync(string? testNameContainsFilter = null) object?[][]? rows = null; if (methodAttributes.Any(a => a.AttributeType == typeof(DataRowAttribute))) { - rows = methodAttributes + rows = [.. methodAttributes .Where(a => a.AttributeType == typeof(DataRowAttribute)) .SelectMany(a => a.ConstructorArguments.Select(arg => { @@ -79,8 +79,7 @@ public static async Task RunAllAsync(string? testNameContainsFilter = null) return [arg.Value]; } #pragma warning restore IDE0046 // Convert to conditional expression - })) - .ToArray(); + }))]; } foreach (object?[]? row in rows ?? emptyRow) diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/SyntaxExtensions.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/SyntaxExtensions.cs index 5b7a153773..17133da1c3 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/SyntaxExtensions.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/SyntaxExtensions.cs @@ -32,7 +32,7 @@ public static string ShowWhitespace(this string text) { " ", "·" }, }; - var regex = new Regex(string.Join("|", map.Keys)); + var regex = new Regex(string.Join('|', map.Keys)); return regex.Replace(text, m => map[m.Value]); } diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestBase.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestBase.cs index fcc6fa6db5..7a6d1c82ee 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestBase.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestBase.cs @@ -6,6 +6,4 @@ namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests; /// /// Empty test base, because TestInfrastructure project depends on Testing.Framework, and we cannot use that. /// -public abstract class TestBase -{ -} +public abstract class TestBase; diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/CSharpCodeFixVerifier.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/CSharpCodeFixVerifier.cs index 4d606aedc6..7b2cfb8660 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/CSharpCodeFixVerifier.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/CSharpCodeFixVerifier.cs @@ -23,7 +23,5 @@ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticRes public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) => CSharpCodeFixVerifier.Diagnostic(descriptor); - public sealed class Test : CSharpCodeFixTest - { - } + public sealed class Test : CSharpCodeFixTest; } diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/GeneratorTester.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/GeneratorTester.cs index 83f1290dcc..1bbd56f15a 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/GeneratorTester.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/GeneratorTester.cs @@ -30,8 +30,7 @@ public GeneratorTester(Func incrementalGeneratorFactory, public static GeneratorTester TestGraph { get; } = new( () => new TestNodesGenerator(), - new[] - { + [ // Microsoft.Testing.Platform dll Assembly.GetAssembly(typeof(IProperty))!.Location, @@ -45,13 +44,13 @@ public GeneratorTester(Func incrementalGeneratorFactory, Assembly.GetAssembly(typeof(TrxExceptionProperty))!.Location, // MSTest.TestFramework dll - Assembly.GetAssembly(typeof(TestClassAttribute))!.Location, - }); + Assembly.GetAssembly(typeof(TestClassAttribute))!.Location + ]); public static ImmutableArray? Net60MetadataReferences { get; set; } public async Task CompileAndExecuteAsync(string source, CancellationToken cancellationToken) - => await CompileAndExecuteAsync(new[] { source }, cancellationToken); + => await CompileAndExecuteAsync([source], cancellationToken); public async Task CompileAndExecuteAsync(string[] sources, CancellationToken cancellationToken) { @@ -79,10 +78,7 @@ public async Task CompileAndExecuteAsync(string[] so } } - MetadataReference[] metadataReferences = - Net60MetadataReferences.Value - .Concat(_additionalReferences.Select(loc => MetadataReference.CreateFromFile(loc))) - .ToArray(); + MetadataReference[] metadataReferences = [.. Net60MetadataReferences.Value, .. _additionalReferences.Select(loc => MetadataReference.CreateFromFile(loc))]; var compilation = CSharpCompilation.Create( "TestAssembly", @@ -92,7 +88,7 @@ public async Task CompileAndExecuteAsync(string[] so ISourceGenerator generator = _incrementalGeneratorFactory().AsSourceGenerator(); GeneratorDriver driver = CSharpGeneratorDriver.Create( - generators: new ISourceGenerator[] { generator }); + generators: [generator]); driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation? outputCompilation, out ImmutableArray diagnostics, cancellationToken); diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/TestingFrameworkVerifier.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/TestingFrameworkVerifier.cs index c870abcfe3..d21e00b691 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/TestingFrameworkVerifier.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/TestingFrameworkVerifier.cs @@ -11,7 +11,7 @@ namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests.TestUtilities; internal sealed class TestingFrameworkVerifier : IVerifier { public TestingFrameworkVerifier() - : this(ImmutableStack.Empty) + : this([]) { } @@ -20,7 +20,7 @@ internal TestingFrameworkVerifier(ImmutableStack context) public ImmutableStack Context { get; } - public void Empty(string collectionName, IEnumerable collection) => Assert.IsFalse(collection?.Any() == true, CreateMessage($"expected '{collectionName}' to be empty, contains '{collection?.Count()}' elements")); + public void Empty(string collectionName, IEnumerable collection) => Assert.AreNotEqual(true, collection?.Any(), CreateMessage($"expected '{collectionName}' to be empty, contains '{collection?.Count()}' elements")); public void Equal(T expected, T actual, string? message = null) { @@ -63,7 +63,7 @@ public void False([DoesNotReturnIf(true)] bool assert, string? message = null) public void LanguageIsSupported(string language) => Assert.IsFalse(language is not LanguageNames.CSharp and not LanguageNames.VisualBasic, CreateMessage($"Unsupported Language: '{language}'")); - public void NotEmpty(string collectionName, IEnumerable collection) => Assert.IsTrue(collection?.Any() == true, CreateMessage($"expected '{collectionName}' to be non-empty, contains")); + public void NotEmpty(string collectionName, IEnumerable collection) => Assert.IsNotEmpty(collection, CreateMessage($"expected '{collectionName}' to be non-empty, contains")); public IVerifier PushContext(string context) { @@ -108,9 +108,7 @@ private sealed class SequenceEqualEnumerableEqualityComparer : IEqualityCompa private readonly IEqualityComparer _itemEqualityComparer; public SequenceEqualEnumerableEqualityComparer(IEqualityComparer? itemEqualityComparer) - { - _itemEqualityComparer = itemEqualityComparer ?? EqualityComparer.Default; - } + => _itemEqualityComparer = itemEqualityComparer ?? EqualityComparer.Default; public bool Equals(IEnumerable? x, IEnumerable? y) => ReferenceEquals(x, y) diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/AssemblyResolverTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/AssemblyResolverTests.cs index 4e5035c30c..3af7639fa0 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/AssemblyResolverTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/AssemblyResolverTests.cs @@ -24,7 +24,7 @@ public void AddSubDirectoriesShouldReturnSubDirectoriesInDfsOrder() @"C:\unitTesting\b", ]; - TestableAssemblyResolver assemblyResolver = new(new List { @"c:\dummy" }) + TestableAssemblyResolver assemblyResolver = new([@"c:\dummy"]) { DoesDirectoryExistSetter = (str) => true, GetDirectoriesSetter = (str) => @@ -42,7 +42,7 @@ public void AddSubDirectoriesShouldReturnSubDirectoriesInDfsOrder() return [@"C:\unitTesting\a\c\d"]; } - return new List().ToArray(); + return []; }, }; @@ -88,7 +88,7 @@ public void OnResolveShouldAddSearchDirectoryListOnANeedToBasis() return [@"C:\FunctionalTesting\c"]; } - return new List().ToArray(); + return []; }; assemblyResolver.SearchAssemblySetter = @@ -147,7 +147,7 @@ public void ReflectionOnlyOnResolveShouldNotReturnACachedDefaultLoadedAssembly() { Assembly currentAssembly = typeof(AssemblyResolverTests).Assembly; string currentAssemblyPath = Path.GetDirectoryName(currentAssembly.Location); - var assemblyResolver = new TestableAssemblyResolver(new List { currentAssemblyPath }); + var assemblyResolver = new TestableAssemblyResolver([currentAssemblyPath]); bool isAssemblyLoaded = false; bool isAssemblyReflectionOnlyLoaded = false; diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/AssemblyEnumeratorTests.cs similarity index 95% rename from test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/AssemblyEnumeratorTests.cs index 4a34f4c0bb..bb874f4757 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/AssemblyEnumeratorTests.cs @@ -7,6 +7,7 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.TestableImplementations; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; @@ -26,7 +27,7 @@ public class AssemblyEnumeratorTests : TestContainer public AssemblyEnumeratorTests() { _assemblyEnumerator = new AssemblyEnumerator(); - _warnings = new List(); + _warnings = []; _testablePlatformServiceProvider = new TestablePlatformServiceProvider(); PlatformServiceProvider.Instance = _testablePlatformServiceProvider; @@ -94,7 +95,7 @@ public void GetTypesShouldReturnSetOfDefinedTypes() // Setup mocks mockAssembly.Setup(a => a.GetTypes()).Returns(expectedTypes); - IReadOnlyList types = AssemblyEnumerator.GetTypes(mockAssembly.Object, string.Empty, _warnings); + Type[] types = AssemblyEnumerator.GetTypes(mockAssembly.Object, string.Empty, _warnings); Verify(expectedTypes.SequenceEqual(types)); } @@ -116,7 +117,7 @@ public void GetTypesShouldReturnReflectionTypeLoadExceptionTypesOnException() // Setup mocks mockAssembly.Setup(a => a.GetTypes()).Throws(new ReflectionTypeLoadException(reflectedTypes, null)); - IReadOnlyList types = AssemblyEnumerator.GetTypes(mockAssembly.Object, string.Empty, _warnings); + Type[] types = AssemblyEnumerator.GetTypes(mockAssembly.Object, string.Empty, _warnings); Verify(types is not null); Verify(reflectedTypes.Equals(types)); @@ -131,7 +132,10 @@ public void GetTypesShouldLogWarningsWhenReflectionFailsWithLoaderExceptions() mockAssembly.Setup(a => a.GetTypes()).Throws(new ReflectionTypeLoadException(null, exceptions)); mockAssembly.Setup(a => a.GetTypes()).Throws(new ReflectionTypeLoadException(null, exceptions)); - IReadOnlyList types = AssemblyEnumerator.GetTypes(mockAssembly.Object, "DummyAssembly", _warnings); + Type[] types = AssemblyEnumerator.GetTypes(mockAssembly.Object, "DummyAssembly", _warnings); + + // Depending on the TFM, .NET either gives us null or empty array. + Verify(types is null || types.Length == 0); Verify(_warnings.Count == 1); Verify(_warnings.ToList().Contains( @@ -256,7 +260,7 @@ public void EnumerateAssemblyShouldReturnTestElementsForAType() _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("DummyAssembly", false)) .Returns(mockAssembly.Object); testableAssemblyEnumerator.MockTypeEnumerator.Setup(te => te.Enumerate(_warnings)) - .Returns(new List { unitTestElement }); + .Returns([unitTestElement]); AssemblyEnumerationResult result = testableAssemblyEnumerator.EnumerateAssembly("DummyAssembly"); _warnings.AddRange(result.Warnings); @@ -389,6 +393,9 @@ private static Mock CreateMockTestableAssembly() // The mock must be configured with a return value for GetCustomAttributes for this attribute type, but the // actual return value is irrelevant for these tests. + // NOTE: Don't convert Array.Empty() to [] as it will cause an InvalidCastException. + // [] will produce `object[]`, then it will fail to cast here: + // https://github.com/dotnet/runtime/blob/4252c8d09b2ec537928f34dad269f02f167c8ce5/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs#L710 mockAssembly .Setup(a => a.GetCustomAttributes( typeof(DiscoverInternalsAttribute), diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorWrapperTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/AssemblyEnumeratorWrapperTests.cs similarity index 98% rename from test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorWrapperTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/AssemblyEnumeratorWrapperTests.cs index e652995ef1..4276e16d93 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorWrapperTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/AssemblyEnumeratorWrapperTests.cs @@ -3,14 +3,13 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.TestableImplementations; using Moq; using TestFramework.ForTestingMSTest; -using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; - namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Discovery; public class AssemblyEnumeratorWrapperTests : TestContainer @@ -23,7 +22,7 @@ public class AssemblyEnumeratorWrapperTests : TestContainer public AssemblyEnumeratorWrapperTests() { _testableAssemblyEnumeratorWrapper = new AssemblyEnumeratorWrapper(); - _warnings = new List(); + _warnings = []; _testablePlatformServiceProvider = new TestablePlatformServiceProvider(); PlatformServiceProvider.Instance = _testablePlatformServiceProvider; @@ -178,11 +177,11 @@ private void SetupMocks(string assemblyName, bool doesFileExist, bool isAssembly #region dummy implementations. - [UTF.TestClass] + [TestClass] public class ValidTestClass { // This is just a dummy method for test validation. - [UTF.TestMethod] + [TestMethod] public void ValidTestMethod() { } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TestMethodValidatorTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TestMethodValidatorTests.cs similarity index 94% rename from test/UnitTests/MSTestAdapter.UnitTests/Discovery/TestMethodValidatorTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TestMethodValidatorTests.cs index 10067ed9da..faf2d778f2 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TestMethodValidatorTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TestMethodValidatorTests.cs @@ -8,8 +8,6 @@ using TestFramework.ForTestingMSTest; -using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; - namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Discovery; public class TestMethodValidatorTests : TestContainer @@ -34,7 +32,7 @@ public TestMethodValidatorTests() public void IsValidTestMethodShouldReturnFalseForMethodsWithoutATestMethodAttributeOrItsDerivedAttributes() { _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(It.IsAny(), false)).Returns(false); + rh => rh.IsAttributeDefined(It.IsAny(), false)).Returns(false); Verify(!_testMethodValidator.IsValidTestMethod(_mockMethodInfo.Object, _type, _warnings)); } @@ -57,7 +55,7 @@ public void IsValidTestMethodShouldNotReportWarningsForGenericTestMethodDefiniti SetupTestMethod(); _mockReflectHelper - .Setup(x => x.GetFirstNonDerivedAttributeOrDefault(_mockMethodInfo.Object, false)) + .Setup(x => x.GetFirstAttributeOrDefault(_mockMethodInfo.Object, false)) .Returns(default(AsyncStateMachineAttribute?)); _mockMethodInfo.Setup(mi => mi.IsGenericMethodDefinition).Returns(true); @@ -114,7 +112,7 @@ public void IsValidTestMethodShouldReturnFalseForAsyncMethodsWithNonTaskReturnTy MethodInfo methodInfo = typeof(DummyTestClass).GetMethod( "AsyncMethodWithVoidReturnType", BindingFlags.Instance | BindingFlags.Public)!; - _mockReflectHelper.Setup(_mockReflectHelper => _mockReflectHelper.GetFirstNonDerivedAttributeOrDefault(methodInfo, false)) + _mockReflectHelper.Setup(_mockReflectHelper => _mockReflectHelper.GetFirstAttributeOrDefault(methodInfo, false)) .CallBase(); Verify(!_testMethodValidator.IsValidTestMethod(methodInfo, typeof(DummyTestClass), _warnings)); @@ -190,7 +188,7 @@ public void WhenDiscoveryOfInternalsIsEnabledIsValidTestMethodShouldReturnFalseF private void SetupTestMethod() => _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(It.IsAny(), false)).Returns(true); + rh => rh.IsAttributeDefined(It.IsAny(), false)).Returns(true); } #region Dummy types diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeEnumeratorTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.cs similarity index 99% rename from test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeEnumeratorTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.cs index 43d39526a2..8def534a6f 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeEnumeratorTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.cs @@ -33,7 +33,7 @@ public TypeEnumeratorTests() _mockTypeValidator = new Mock(MockBehavior.Default, _mockReflectHelper.Object); _mockTestMethodValidator = new Mock(MockBehavior.Default, _mockReflectHelper.Object, false); - _warnings = new List(); + _warnings = []; _mockMessageLogger = new Mock(); _testablePlatformServiceProvider = new TestablePlatformServiceProvider(); @@ -403,7 +403,8 @@ public void GetTestFromMethodShouldSetDescription() MSTest.TestAdapter.ObjectModel.UnitTestElement testElement = typeEnumerator.GetTestFromMethod(methodInfo, true, _warnings); - Verify(testElement.Description == "Dummy description"); + Verify(testElement.Traits is not null); + Verify(testElement.Traits.Any(t => t.Name == "Description" && t.Value == "Dummy description")); } public void GetTestFromMethodShouldSetWorkItemIds() diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeValidatorTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeValidatorTests.cs similarity index 87% rename from test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeValidatorTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeValidatorTests.cs index 1fedee983c..7916f355c1 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeValidatorTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeValidatorTests.cs @@ -1,17 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Moq; using TestFramework.ForTestingMSTest; -using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; -using UTFExtension = Microsoft.VisualStudio.TestTools.UnitTesting; - namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Discovery; public class TypeValidatorTests : TestContainer @@ -41,15 +38,15 @@ public TypeValidatorTests() public void IsValidTestClassShouldReturnFalseForClassesNotHavingTestClassAttributeOrDerivedAttributeTypes() { - _mockReflectHelper.Setup(rh => rh.IsNonDerivedAttributeDefined(It.IsAny(), false)).Returns(false); + _mockReflectHelper.Setup(rh => rh.IsAttributeDefined(It.IsAny(), false)).Returns(false); Verify(!_typeValidator.IsValidTestClass(typeof(TypeValidatorTests), _warnings)); } public void IsValidTestClassShouldReturnTrueForClassesMarkedByAnAttributeDerivedFromTestClass() { - _mockReflectHelper.Setup(rh => rh.IsNonDerivedAttributeDefined(It.IsAny(), false)).Returns(false); + _mockReflectHelper.Setup(rh => rh.IsAttributeDefined(It.IsAny(), false)).Returns(false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(It.IsAny(), false)).Returns(true); + rh => rh.IsAttributeDefined(It.IsAny(), false)).Returns(true); Verify(_typeValidator.IsValidTestClass(typeof(TypeValidatorTests), _warnings)); } @@ -240,8 +237,8 @@ public void AllTypesContainAllPrivateClasses() { // The names of private types are not accessible by nameof or typeof, ensure that we have them in the // list of our test types, to avoid bugs caused by typos. - string[] allTypes = GetAllTestTypes().Select(t => t.Name).ToArray(); - string[] privateTypes = typeof(PrivateClassNames).GetProperties().Select(n => n.Name).ToArray(); + string[] allTypes = [.. GetAllTestTypes().Select(t => t.Name)]; + string[] privateTypes = [.. typeof(PrivateClassNames).GetProperties().Select(n => n.Name)]; Verify(privateTypes.Length >= 1); foreach (string type in privateTypes) @@ -264,9 +261,9 @@ public void TypeHasValidAccessibilityShouldReturnTrueForAllPublicTypesIncludingN ]; bool discoverInternal = false; - string[] actualDiscoveredTypes = allTypes + string[] actualDiscoveredTypes = [.. allTypes .Where(t => TypeValidator.TypeHasValidAccessibility(t, discoverInternal)) - .Select(t => t.Name).ToArray(); + .Select(t => t.Name)]; Array.Sort(actualDiscoveredTypes); Array.Sort(expectedDiscoveredTypes); @@ -307,9 +304,9 @@ public void TypeHasValidAccessibilityShouldReturnFalseForAllTypesThatAreNotPubli ]; bool discoverInternal = false; - string[] actualDiscoveredTypes = allTypes + string[] actualDiscoveredTypes = [.. allTypes .Where(t => !TypeValidator.TypeHasValidAccessibility(t, discoverInternal)) - .Select(t => t.Name).ToArray(); + .Select(t => t.Name)]; Array.Sort(actualDiscoveredTypes); Array.Sort(expectedNonDiscoveredTypes); @@ -342,9 +339,9 @@ public void TypeHasValidAccessibilityShouldReturnTrueForAllPublicAndInternalType ]; bool discoverInternal = true; - string[] actualDiscoveredTypes = allTypes + string[] actualDiscoveredTypes = [.. allTypes .Where(t => TypeValidator.TypeHasValidAccessibility(t, discoverInternal)) - .Select(t => t.Name).ToArray(); + .Select(t => t.Name)]; Array.Sort(actualDiscoveredTypes); Array.Sort(expectedDiscoveredTypes); @@ -372,9 +369,9 @@ public void TypeHasValidAccessibilityShouldReturnFalseForAllTypesThatAreNotPubli ]; bool discoverInternal = true; - string[] actualDiscoveredTypes = allTypes + string[] actualDiscoveredTypes = [.. allTypes .Where(t => !TypeValidator.TypeHasValidAccessibility(t, discoverInternal)) - .Select(t => t.Name).ToArray(); + .Select(t => t.Name)]; Array.Sort(actualDiscoveredTypes); Array.Sort(expectedNonDiscoveredTypes); @@ -384,16 +381,16 @@ public void TypeHasValidAccessibilityShouldReturnFalseForAllTypesThatAreNotPubli private static Type[] GetAllTestTypes() { Type[] types = [typeof(PublicClass2), typeof(PublicClass3), typeof(InternalClass), typeof(InternalClass2)]; - Type[] nestedTypes = types.SelectMany(t => t.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)).ToArray(); - Type[] nestedNestedTypes = nestedTypes.SelectMany(t => t.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)).ToArray(); - Type[] allTypes = new[] { types, nestedTypes, nestedNestedTypes }.SelectMany(t => t).ToArray(); + Type[] nestedTypes = [.. types.SelectMany(t => t.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))]; + Type[] nestedNestedTypes = [.. nestedTypes.SelectMany(t => t.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))]; + Type[] allTypes = [.. new[] { types, nestedTypes, nestedNestedTypes }.SelectMany(t => t)]; return allTypes; } #endregion #region private methods - private void SetupTestClass() => _mockReflectHelper.Setup(rh => rh.IsDerivedAttributeDefined(It.IsAny(), false)).Returns(true); + private void SetupTestClass() => _mockReflectHelper.Setup(rh => rh.IsAttributeDefined(It.IsAny(), false)).Returns(true); #endregion } @@ -412,33 +409,33 @@ public class GenericClass; public class ClassWithTestContextGetterOnly { - public UTFExtension.TestContext TestContext { get; } = null!; + public TestContext TestContext => null!; } public class ClassWithTestContextPrivateSetter { - public UTFExtension.TestContext TestContext { get; private set; } = null!; + public TestContext TestContext { get; private set; } = null!; } public class ClassWithStaticTestContext { - public static UTFExtension.TestContext TestContext { get; set; } = null!; + public static TestContext TestContext { get; set; } = null!; } public abstract class ClassWithAbstractTestContext { - public abstract UTFExtension.TestContext TestContext { get; set; } + public abstract TestContext TestContext { get; set; } } public class ClassWithTestContext { - public UTFExtension.TestContext TestContext { get; set; } = null!; + public TestContext TestContext { get; set; } = null!; } public class GenericClassWithProperty { #pragma warning disable CA1000 // Do not declare static members on generic types - public static T ReturnAStableSomething { get; } = default!; + public static T ReturnAStableSomething => default!; #pragma warning restore CA1000 // Do not declare static members on generic types public T ReturnSomething { get; set; } = default!; @@ -449,14 +446,14 @@ public class GenericClassWithProperty public class GenericClassWithTestContext { #pragma warning disable CA1000 // Do not declare static members on generic types - public static T ReturnAStableSomething { get; } = default!; + public static T ReturnAStableSomething => default!; #pragma warning restore CA1000 // Do not declare static members on generic types public T ReturnSomething { get; set; } = default!; public bool Something { get; } - public UTFExtension.TestContext TestContext { get; set; } = null!; + public TestContext TestContext { get; set; } = null!; } public class PublicTestClass; @@ -550,25 +547,25 @@ public sealed class PublicClassNestedInPrivateClassNestedInInternalClass; /// internal class PrivateClassNames { - public string ProtectedInteralNestedClassInPublicClass { get; } = null!; + public string ProtectedInteralNestedClassInPublicClass => null!; - public string ProtectedNestedClassInPublicClass { get; } = null!; + public string ProtectedNestedClassInPublicClass => null!; - public string PrivateProtectedNestedClassInPublicClass { get; } = null!; + public string PrivateProtectedNestedClassInPublicClass => null!; - public string PrivateClassNestedInPublicClass { get; } = null!; + public string PrivateClassNestedInPublicClass => null!; - public string ProtectedInteralClassNestedInInternalClass { get; } = null!; + public string ProtectedInteralClassNestedInInternalClass => null!; - public string ProtectedClassNestedInInternalClass { get; } = null!; + public string ProtectedClassNestedInInternalClass => null!; - public string PrivateProtectedClassNestedInInternalClass { get; } = null!; + public string PrivateProtectedClassNestedInInternalClass => null!; - public string PrivateClassNestedInInternalClass { get; } = null!; + public string PrivateClassNestedInInternalClass => null!; - public string PublicClassNestedInPrivateClassNestedInPublicClass { get; } = null!; + public string PublicClassNestedInPrivateClassNestedInPublicClass => null!; - public string PublicClassNestedInPrivateClassNestedInInternalClass { get; } = null!; + public string PublicClassNestedInPrivateClassNestedInInternalClass => null!; } #endregion diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/UnitTestDiscovererTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/UnitTestDiscovererTests.cs similarity index 99% rename from test/UnitTests/MSTestAdapter.UnitTests/Discovery/UnitTestDiscovererTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/UnitTestDiscovererTests.cs index 9911a3ddf6..cd441bf364 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/UnitTestDiscovererTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/UnitTestDiscovererTests.cs @@ -434,7 +434,7 @@ internal sealed class TestableTestCaseFilterExpression : ITestCaseFilterExpressi public TestableTestCaseFilterExpression(Func matchTestCase) => _matchTest = matchTestCase; - public string TestCaseFilterValue { get; } = null!; + public string TestCaseFilterValue => null!; public bool MatchTestCase(TestCase testCase, Func propertyValueProvider) => _matchTest(testCase); } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/ClassCleanupManagerTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/ClassCleanupManagerTests.cs similarity index 86% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/ClassCleanupManagerTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/ClassCleanupManagerTests.cs index 50d3f59707..76c86755e8 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/ClassCleanupManagerTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/ClassCleanupManagerTests.cs @@ -24,13 +24,13 @@ public void AssemblyCleanupRunsAfterAllTestsFinishEvenIfWeScheduleTheSameTestMul // Setting 2 of the same test to run, we should run assembly cleanup after both these tests // finish, not after the first one finishes. - List testsToRun = new() - { - new(testMethod), + List testsToRun = + [ new(testMethod), - }; + new(testMethod) + ]; - var classCleanupManager = new ClassCleanupManager(testsToRun, ClassCleanupBehavior.EndOfClass, ClassCleanupBehavior.EndOfClass, reflectHelper); + var classCleanupManager = new ClassCleanupManager(testsToRun, ClassCleanupBehavior.EndOfClass, reflectHelper); TestClassInfo testClassInfo = new(typeof(FakeTestClass), null!, true, new TestClassAttribute(), null!) { @@ -38,13 +38,13 @@ public void AssemblyCleanupRunsAfterAllTestsFinishEvenIfWeScheduleTheSameTestMul ClassCleanupMethod = classCleanupMethodInfo, }; TestMethodInfo testMethodInfo = new(methodInfo, testClassInfo, null!); - classCleanupManager.MarkTestComplete(testMethodInfo, testMethod, out bool shouldRunEndOfClassCleanup); + classCleanupManager.MarkTestComplete(testMethodInfo, out bool shouldRunEndOfClassCleanup); // The cleanup should not run here yet, we have 1 remaining test to run. Assert.IsFalse(shouldRunEndOfClassCleanup); Assert.IsFalse(classCleanupManager.ShouldRunEndOfAssemblyCleanup); - classCleanupManager.MarkTestComplete(testMethodInfo, testMethod, out shouldRunEndOfClassCleanup); + classCleanupManager.MarkTestComplete(testMethodInfo, out shouldRunEndOfClassCleanup); // The cleanup should run here. Assert.IsTrue(shouldRunEndOfClassCleanup); Assert.IsTrue(classCleanupManager.ShouldRunEndOfAssemblyCleanup); diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/LogMessageListenerTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/LogMessageListenerTests.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/LogMessageListenerTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/LogMessageListenerTests.cs diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TcmTestPropertiesProviderTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TcmTestPropertiesProviderTests.cs similarity index 87% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TcmTestPropertiesProviderTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TcmTestPropertiesProviderTests.cs index 9c14439ad2..44116b386d 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TcmTestPropertiesProviderTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TcmTestPropertiesProviderTests.cs @@ -2,33 +2,32 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using TestFramework.ForTestingMSTest; -using TestAdapterConstants = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Constants; - namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution; public class TcmTestPropertiesProviderTests : TestContainer { private readonly TestProperty[] _tcmKnownProperties = [ - TestAdapterConstants.TestRunIdProperty, - TestAdapterConstants.TestPlanIdProperty, - TestAdapterConstants.BuildConfigurationIdProperty, - TestAdapterConstants.BuildDirectoryProperty, - TestAdapterConstants.BuildFlavorProperty, - TestAdapterConstants.BuildNumberProperty, - TestAdapterConstants.BuildPlatformProperty, - TestAdapterConstants.BuildUriProperty, - TestAdapterConstants.TfsServerCollectionUrlProperty, - TestAdapterConstants.TfsTeamProjectProperty, - TestAdapterConstants.IsInLabEnvironmentProperty, - TestAdapterConstants.TestCaseIdProperty, - TestAdapterConstants.TestConfigurationIdProperty, - TestAdapterConstants.TestConfigurationNameProperty, - TestAdapterConstants.TestPointIdProperty, + EngineConstants.TestRunIdProperty, + EngineConstants.TestPlanIdProperty, + EngineConstants.BuildConfigurationIdProperty, + EngineConstants.BuildDirectoryProperty, + EngineConstants.BuildFlavorProperty, + EngineConstants.BuildNumberProperty, + EngineConstants.BuildPlatformProperty, + EngineConstants.BuildUriProperty, + EngineConstants.TfsServerCollectionUrlProperty, + EngineConstants.TfsTeamProjectProperty, + EngineConstants.IsInLabEnvironmentProperty, + EngineConstants.TestCaseIdProperty, + EngineConstants.TestConfigurationIdProperty, + EngineConstants.TestConfigurationNameProperty, + EngineConstants.TestPointIdProperty, ]; public void GetTcmPropertiesShouldReturnEmptyDictionaryIfTestCaseIsNull() @@ -220,9 +219,9 @@ public void GetTcmPropertiesShouldHandleDuplicateTestsProperlyFromTestCase() private void SetTestCaseProperties(TestCase testCase, object[] propertiesValue) { - System.Collections.IEnumerator tcmKnownPropertiesEnumerator = _tcmKnownProperties.GetEnumerator(); + IEnumerator tcmKnownPropertiesEnumerator = _tcmKnownProperties.GetEnumerator(); - System.Collections.IEnumerator propertiesValueEnumerator = propertiesValue.GetEnumerator(); + IEnumerator propertiesValueEnumerator = propertiesValue.GetEnumerator(); while (tcmKnownPropertiesEnumerator.MoveNext() && propertiesValueEnumerator.MoveNext()) { object? property = tcmKnownPropertiesEnumerator.Current; diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestAssemblyInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs similarity index 96% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TestAssemblyInfoTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs index c2f674af8d..e95b9c01cc 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestAssemblyInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs @@ -9,7 +9,6 @@ using TestFramework.ForTestingMSTest; using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; -using UTFExtension = Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution; @@ -19,14 +18,14 @@ public class TestAssemblyInfoTests : TestContainer private readonly MethodInfo _dummyMethodInfo; - private readonly UTFExtension.TestContext _testContext; + private readonly TestContext _testContext; public TestAssemblyInfoTests() { _testAssemblyInfo = new TestAssemblyInfo(typeof(TestAssemblyInfoTests).Assembly); _dummyMethodInfo = typeof(TestAssemblyInfoTests).GetMethods().First(); - var testContext = new Mock(); + var testContext = new Mock(); testContext.SetupGet(x => x.CancellationTokenSource).Returns(new CancellationTokenSource()); _testContext = testContext.Object; } @@ -152,7 +151,7 @@ public void RunAssemblyInitializeShouldThrowTestFailedExceptionOnAssertionFailur Verify(exception.StackTraceInformation!.ErrorStackTrace.StartsWith( " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests.<>c.", StringComparison.Ordinal)); #endif - Verify(exception.InnerException!.GetType() == typeof(UTF.AssertFailedException)); + Verify(exception.InnerException!.GetType() == typeof(AssertFailedException)); } public void RunAssemblyInitializeShouldThrowTestFailedExceptionWithInconclusiveOnAssertInconclusive() @@ -169,7 +168,7 @@ public void RunAssemblyInitializeShouldThrowTestFailedExceptionWithInconclusiveO Verify(exception.StackTraceInformation!.ErrorStackTrace.StartsWith( " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests.<>c.", StringComparison.Ordinal)); #endif - Verify(exception.InnerException!.GetType() == typeof(UTF.AssertInconclusiveException)); + Verify(exception.InnerException!.GetType() == typeof(AssertInconclusiveException)); } public void RunAssemblyInitializeShouldThrowTestFailedExceptionWithNonAssertExceptions() @@ -311,16 +310,16 @@ public void RunAssemblyCleanupShouldThrowTheInnerMostExceptionWhenThereAreMultip #endregion - [UTF.TestClass] + [TestClass] public class DummyTestClass { public static Action AssemblyInitializeMethodBody { get; set; } = null!; public static Action AssemblyCleanupMethodBody { get; set; } = null!; - public UTFExtension.TestContext TestContext { get; set; } = null!; + public TestContext TestContext { get; set; } = null!; - public static void AssemblyInitializeMethod(UTFExtension.TestContext testContext) => AssemblyInitializeMethodBody.Invoke(testContext); + public static void AssemblyInitializeMethod(TestContext testContext) => AssemblyInitializeMethodBody.Invoke(testContext); public static void AssemblyCleanupMethod() => AssemblyCleanupMethodBody.Invoke(); } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestAssemblySettingsProviderTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblySettingsProviderTests.cs similarity index 91% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TestAssemblySettingsProviderTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblySettingsProviderTests.cs index 9d7754323d..328091f21f 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestAssemblySettingsProviderTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblySettingsProviderTests.cs @@ -9,7 +9,7 @@ using TestFramework.ForTestingMSTest; -using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; +using ExecutionScope = Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope; namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution; @@ -58,8 +58,8 @@ public void GetSettingsShouldSetParallelWorkers() .Returns(Assembly.GetExecutingAssembly()); _testablePlatformServiceProvider .MockReflectionOperations - .Setup(ro => ro.GetCustomAttributes(It.IsAny(), typeof(UTF.ParallelizeAttribute))) - .Returns([new UTF.ParallelizeAttribute { Workers = 10 }]); + .Setup(ro => ro.GetCustomAttributes(It.IsAny(), typeof(ParallelizeAttribute))) + .Returns([new ParallelizeAttribute { Workers = 10 }]); // Act. MSTest.TestAdapter.ObjectModel.TestAssemblySettings settings = new TestAssemblySettingsProvider().GetSettings("Foo"); @@ -77,8 +77,8 @@ public void GetSettingsShouldSetParallelWorkersToProcessorCountIfZero() .Returns(Assembly.GetExecutingAssembly()); _testablePlatformServiceProvider .MockReflectionOperations - .Setup(ro => ro.GetCustomAttributes(It.IsAny(), typeof(UTF.ParallelizeAttribute))) - .Returns([new UTF.ParallelizeAttribute { Workers = 0 }]); + .Setup(ro => ro.GetCustomAttributes(It.IsAny(), typeof(ParallelizeAttribute))) + .Returns([new ParallelizeAttribute { Workers = 0 }]); // Act. MSTest.TestAdapter.ObjectModel.TestAssemblySettings settings = new TestAssemblySettingsProvider().GetSettings("Foo"); @@ -111,8 +111,8 @@ public void GetSettingsShouldSetParallelScope() .Returns(Assembly.GetExecutingAssembly()); _testablePlatformServiceProvider .MockReflectionOperations - .Setup(ro => ro.GetCustomAttributes(It.IsAny(), typeof(UTF.ParallelizeAttribute))) - .Returns([new UTF.ParallelizeAttribute { Scope = ExecutionScope.MethodLevel }]); + .Setup(ro => ro.GetCustomAttributes(It.IsAny(), typeof(ParallelizeAttribute))) + .Returns([new ParallelizeAttribute { Scope = ExecutionScope.MethodLevel }]); // Act. MSTest.TestAdapter.ObjectModel.TestAssemblySettings settings = new TestAssemblySettingsProvider().GetSettings("Foo"); @@ -145,8 +145,8 @@ public void GetSettingsShouldSetCanParallelizeAssemblyToFalseIfDoNotParallelizeI .Returns(Assembly.GetExecutingAssembly()); _testablePlatformServiceProvider .MockReflectionOperations - .Setup(ro => ro.GetCustomAttributes(It.IsAny(), typeof(UTF.DoNotParallelizeAttribute))) - .Returns([new UTF.DoNotParallelizeAttribute()]); + .Setup(ro => ro.GetCustomAttributes(It.IsAny(), typeof(DoNotParallelizeAttribute))) + .Returns([new DoNotParallelizeAttribute()]); // Act. MSTest.TestAdapter.ObjectModel.TestAssemblySettings settings = new TestAssemblySettingsProvider().GetSettings("Foo"); diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestCaseDiscoverySinkTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestCaseDiscoverySinkTests.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TestCaseDiscoverySinkTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestCaseDiscoverySinkTests.cs diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestClassInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs similarity index 92% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TestClassInfoTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs index a079faea13..9242df3d9f 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestClassInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs @@ -11,15 +11,14 @@ using TestFramework.ForTestingMSTest; using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; -using UTFExtension = Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution; public class TestClassInfoTests : TestContainer { - private sealed class TestTestCoxtextImpl : ITestContext + private sealed class TestTestContextImpl : ITestContext { - public TestTestCoxtextImpl(TestContext testContext) + public TestTestContextImpl(TestContext testContext) => Context = testContext; public TestContext Context { get; } @@ -55,11 +54,11 @@ public void ClearDiagnosticMessages() private readonly ConstructorInfo _testClassConstructor; - private readonly UTF.TestClassAttribute _testClassAttribute; + private readonly TestClassAttribute _testClassAttribute; private readonly TestAssemblyInfo _testAssemblyInfo; - private readonly UTFExtension.TestContext _testContext; + private readonly TestContext _testContext; private readonly TestClassInfo _testClassInfo; @@ -77,7 +76,7 @@ public TestClassInfoTests() _testClassAttribute, _testAssemblyInfo); - var testContext = new Mock(); + var testContext = new Mock(); testContext.SetupGet(x => x.CancellationTokenSource).Returns(new CancellationTokenSource()); _testContext = testContext.Object; @@ -132,7 +131,7 @@ public void TestClassInfoClassCleanupMethodShouldNotInvokeWhenNoTestClassInitial _testClassInfo.ClassCleanupMethod = typeof(DummyTestClass).GetMethod("ClassCleanupMethod")!; _testClassInfo.ClassInitializeMethod = typeof(DummyTestClass).GetMethod("ClassInitializeMethod")!; - TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); // call cleanup without calling init + TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // call cleanup without calling init Verify(ex is null); Verify(classCleanupCallCount == 0); } @@ -146,7 +145,7 @@ public void TestClassInfoClassCleanupMethodShouldInvokeWhenTestClassInitializedI _testClassInfo.ClassInitializeMethod = typeof(DummyTestClass).GetMethod("ClassInitializeMethod")!; GetResultOrRunClassInitialize(); - TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); // call cleanup without calling init + TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // call cleanup without calling init Verify(ex is null); Verify(classCleanupCallCount == 1); @@ -161,7 +160,7 @@ public void TestClassInfoClassCleanupMethodShouldInvokeBaseClassCleanupMethodWhe _testClassInfo.BaseClassCleanupMethods.Add(typeof(DummyBaseTestClass).GetMethod("CleanupClassMethod")!); GetResultOrRunClassInitialize(); - TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); Verify(ex is null); Verify(classCleanupCallCount == 1); @@ -363,7 +362,7 @@ public void RunClassInitializeShouldThrowTestFailedExceptionOnAssertionFailure() Verify(exception.StackTraceInformation!.ErrorStackTrace.StartsWith( " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests.<>c.", StringComparison.Ordinal)); #endif - Verify(exception.InnerException!.GetType() == typeof(UTF.AssertFailedException)); + Verify(exception.InnerException!.GetType() == typeof(AssertFailedException)); } public void RunClassInitializeShouldThrowTestFailedExceptionWithInconclusiveOnAssertInconclusive() @@ -382,7 +381,7 @@ public void RunClassInitializeShouldThrowTestFailedExceptionWithInconclusiveOnAs Verify(exception.StackTraceInformation!.ErrorStackTrace.StartsWith( " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests.<>c.", StringComparison.Ordinal)); #endif - Verify(exception.InnerException!.GetType() == typeof(UTF.AssertInconclusiveException)); + Verify(exception.InnerException!.GetType() == typeof(AssertInconclusiveException)); } public void RunClassInitializeShouldThrowTestFailedExceptionWithNonAssertExceptions() @@ -451,7 +450,7 @@ private TestResult GetResultOrRunClassInitialize() => GetResultOrRunClassInitialize(_testContext); private TestResult GetResultOrRunClassInitialize(TestContext? testContext) - => _testClassInfo.GetResultOrRunClassInitialize(new TestTestCoxtextImpl(testContext!), string.Empty, string.Empty, string.Empty, string.Empty); + => _testClassInfo.GetResultOrRunClassInitialize(new TestTestContextImpl(testContext!), string.Empty, string.Empty, string.Empty, string.Empty); #endregion #region Run Class Cleanup tests @@ -465,7 +464,7 @@ public void RunClassCleanupShouldInvokeIfClassCleanupMethod() // Act GetResultOrRunClassInitialize(null); - TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // Assert Verify(ex is null); @@ -480,7 +479,7 @@ public void RunClassCleanupShouldNotInvokeIfClassCleanupIsNull() _testClassInfo.ClassCleanupMethod = null; // Act - TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // Assert Verify(ex is null); @@ -495,7 +494,7 @@ public void RunClassCleanupShouldReturnAssertFailureExceptionDetails() // Act GetResultOrRunClassInitialize(null); - TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // Assert Verify(classCleanupException is not null); @@ -517,7 +516,7 @@ public void RunClassCleanupShouldReturnAssertInconclusiveExceptionDetails() // Act GetResultOrRunClassInitialize(null); - TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // Assert Verify(classCleanupException is not null); @@ -538,7 +537,7 @@ public void RunClassCleanupShouldReturnExceptionDetailsOfNonAssertExceptions() // Act GetResultOrRunClassInitialize(null); - TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // Assert Verify(classCleanupException is not null); @@ -557,7 +556,7 @@ public void RunBaseClassCleanupWithNoDerivedClassCleanupShouldReturnExceptionDet // Act GetResultOrRunClassInitialize(null); - TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // Assert Verify(classCleanupException is not null); @@ -576,7 +575,7 @@ public void RunBaseClassCleanupEvenIfThereIsNoDerivedClassCleanup() _testClassInfo.BaseClassCleanupMethods.Add(baseClassCleanupMethod); // Act - TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + TestFailedException? ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // Assert Verify(ex is null); @@ -585,7 +584,7 @@ public void RunBaseClassCleanupEvenIfThereIsNoDerivedClassCleanup() // Act 2 GetResultOrRunClassInitialize(null); - ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // Assert 2 Verify(ex is null); @@ -594,7 +593,7 @@ public void RunBaseClassCleanupEvenIfThereIsNoDerivedClassCleanup() Verify(classCleanupCallCount == 1, "DummyBaseTestClass.CleanupClassMethod call count"); // Act 3 - ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + ex = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); // Assert 3 Verify(ex is null); @@ -611,7 +610,7 @@ public void RunClassCleanupShouldThrowTheInnerMostExceptionWhenThereAreMultipleN _testClassInfo.ClassCleanupMethod = typeof(DummyTestClass).GetMethod("ClassCleanupMethod")!; GetResultOrRunClassInitialize(null); - TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary()), out _); + TestFailedException? classCleanupException = _testClassInfo.ExecuteClassCleanup(new TestContextImplementation(null, new StringWriter(), new Dictionary())); Verify(classCleanupException is not null); Verify(classCleanupException.Message.StartsWith("Class Cleanup method DummyTestClass.ClassCleanupMethod failed. Error Message: System.InvalidOperationException: I fail..", StringComparison.Ordinal)); @@ -627,10 +626,10 @@ public class DummyGrandParentTestClass public static Action CleanupClassMethodBody { get; set; } = null!; - public UTFExtension.TestContext BaseTestContext { get; set; } = null!; + public TestContext BaseTestContext { get; set; } = null!; - [UTF.ClassInitialize(UTF.InheritanceBehavior.BeforeEachDerivedClass)] - public static void InitClassMethod(UTFExtension.TestContext testContext) => ClassInitMethodBody?.Invoke(testContext); + [ClassInitialize(UTF.InheritanceBehavior.BeforeEachDerivedClass)] + public static void InitClassMethod(TestContext testContext) => ClassInitMethodBody?.Invoke(testContext); public static void ClassCleanupMethod() => CleanupClassMethodBody?.Invoke(); } @@ -642,10 +641,10 @@ public class DummyBaseTestClass : DummyGrandParentTestClass public static Action ClassCleanupMethodBody { get; set; } = null!; - public UTFExtension.TestContext TestContext { get; set; } = null!; + public TestContext TestContext { get; set; } = null!; - [UTF.ClassInitialize(UTF.InheritanceBehavior.BeforeEachDerivedClass)] - public static void InitBaseClassMethod(UTFExtension.TestContext testContext) => ClassInitializeMethodBody?.Invoke(testContext); + [ClassInitialize(UTF.InheritanceBehavior.BeforeEachDerivedClass)] + public static void InitBaseClassMethod(TestContext testContext) => ClassInitializeMethodBody?.Invoke(testContext); public static void CleanupClassMethod() => ClassCleanupMethodBody?.Invoke(); } @@ -657,9 +656,9 @@ public class DummyDerivedTestClass : DummyBaseTestClass public static Action DerivedClassCleanupMethodBody { get; set; } = null!; - public UTFExtension.TestContext Context { get; set; } = null!; + public TestContext Context { get; set; } = null!; - public static void InitDerivedClassMethod(UTFExtension.TestContext testContext) => DerivedClassInitializeMethodBody?.Invoke(testContext); + public static void InitDerivedClassMethod(TestContext testContext) => DerivedClassInitializeMethodBody?.Invoke(testContext); public static void CleanupDerivedClassMethod() => DerivedClassCleanupMethodBody?.Invoke(); } @@ -671,14 +670,14 @@ public class DummyTestClass public static Action ClassCleanupMethodBody { get; set; } = null!; - public UTFExtension.TestContext TestContext { get; set; } = null!; + public TestContext TestContext { get; set; } = null!; - public static void ClassInitializeMethod(UTFExtension.TestContext testContext) => ClassInitializeMethodBody?.Invoke(testContext); + public static void ClassInitializeMethod(TestContext testContext) => ClassInitializeMethodBody?.Invoke(testContext); public static void ClassCleanupMethod() => ClassCleanupMethodBody?.Invoke(); } - private class DummyTestClassAttribute : UTF.TestClassAttribute; + private class DummyTestClassAttribute : TestClassAttribute; private static class FailingStaticHelper { diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestExecutionManagerTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestExecutionManagerTests.cs similarity index 96% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TestExecutionManagerTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestExecutionManagerTests.cs index cea2718a3b..7c10d74213 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestExecutionManagerTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestExecutionManagerTests.cs @@ -3,7 +3,6 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Discovery; @@ -16,7 +15,7 @@ using TestFramework.ForTestingMSTest; -using TestAdapterConstants = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Constants; +using ExecutionScope = Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope; using TestResult = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResult; namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution; @@ -30,25 +29,25 @@ public class TestExecutionManagerTests : TestContainer private readonly TestProperty[] _tcmKnownProperties = [ - TestAdapterConstants.TestRunIdProperty, - TestAdapterConstants.TestPlanIdProperty, - TestAdapterConstants.BuildConfigurationIdProperty, - TestAdapterConstants.BuildDirectoryProperty, - TestAdapterConstants.BuildFlavorProperty, - TestAdapterConstants.BuildNumberProperty, - TestAdapterConstants.BuildPlatformProperty, - TestAdapterConstants.BuildUriProperty, - TestAdapterConstants.TfsServerCollectionUrlProperty, - TestAdapterConstants.TfsTeamProjectProperty, - TestAdapterConstants.IsInLabEnvironmentProperty, - TestAdapterConstants.TestCaseIdProperty, - TestAdapterConstants.TestConfigurationIdProperty, - TestAdapterConstants.TestConfigurationNameProperty, - TestAdapterConstants.TestPointIdProperty, + EngineConstants.TestRunIdProperty, + EngineConstants.TestPlanIdProperty, + EngineConstants.BuildConfigurationIdProperty, + EngineConstants.BuildDirectoryProperty, + EngineConstants.BuildFlavorProperty, + EngineConstants.BuildNumberProperty, + EngineConstants.BuildPlatformProperty, + EngineConstants.BuildUriProperty, + EngineConstants.TfsServerCollectionUrlProperty, + EngineConstants.TfsTeamProjectProperty, + EngineConstants.IsInLabEnvironmentProperty, + EngineConstants.TestCaseIdProperty, + EngineConstants.TestConfigurationIdProperty, + EngineConstants.TestConfigurationNameProperty, + EngineConstants.TestPointIdProperty, ]; private TestableRunContextTestExecutionTests _runContext; - private List _callers = new(); + private List _callers = []; private int _enqueuedParallelTestsCount; public TestExecutionManagerTests() @@ -666,8 +665,8 @@ public async Task RunTestsForTestShouldRunNonParallelizableTestsSeparately() TestCase testCase3 = GetTestCase(typeof(DummyTestClassWithDoNotParallelizeMethods), "TestMethod3"); TestCase testCase4 = GetTestCase(typeof(DummyTestClassWithDoNotParallelizeMethods), "TestMethod4"); - testCase3.SetPropertyValue(TestAdapterConstants.DoNotParallelizeProperty, true); - testCase4.SetPropertyValue(TestAdapterConstants.DoNotParallelizeProperty, true); + testCase3.SetPropertyValue(EngineConstants.DoNotParallelizeProperty, true); + testCase4.SetPropertyValue(EngineConstants.DoNotParallelizeProperty, true); TestCase[] tests = [testCase1, testCase2, testCase3, testCase4]; _runContext.MockRunSettings.Setup(rs => rs.SettingsXml).Returns( @@ -776,7 +775,7 @@ private async Task RunTestsForTestShouldRunTestsInTheParentDomainsApartmentState TestCase testCase3 = GetTestCase(typeof(DummyTestClassWithDoNotParallelizeMethods), "TestMethod3"); TestCase testCase4 = GetTestCase(typeof(DummyTestClassWithDoNotParallelizeMethods), "TestMethod4"); - testCase4.SetPropertyValue(TestAdapterConstants.DoNotParallelizeProperty, true); + testCase4.SetPropertyValue(EngineConstants.DoNotParallelizeProperty, true); TestCase[] tests = [testCase1, testCase2, testCase3, testCase4]; _runContext.MockRunSettings.Setup(rs => rs.SettingsXml).Returns( @@ -861,9 +860,9 @@ private void VerifyTcmProperties(IDictionary? tcmProperties, Tes private void SetTestCaseProperties(TestCase testCase, object[] propertiesValue) { - System.Collections.IEnumerator tcmKnownPropertiesEnumerator = _tcmKnownProperties.GetEnumerator(); + IEnumerator tcmKnownPropertiesEnumerator = _tcmKnownProperties.GetEnumerator(); - System.Collections.IEnumerator propertiesValueEnumerator = propertiesValue.GetEnumerator(); + IEnumerator propertiesValueEnumerator = propertiesValue.GetEnumerator(); while (tcmKnownPropertiesEnumerator.MoveNext() && propertiesValueEnumerator.MoveNext()) { object? property = tcmKnownPropertiesEnumerator.Current; @@ -1119,7 +1118,7 @@ internal sealed class TestableTestCaseFilterExpression : ITestCaseFilterExpressi public TestableTestCaseFilterExpression(Func matchTestCase) => _matchTest = matchTestCase; - public string TestCaseFilterValue { get; } = null!; + public string TestCaseFilterValue => null!; public bool MatchTestCase(TestCase testCase, Func propertyValueProvider) => _matchTest(testCase); } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestMethodFilterTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodFilterTests.cs similarity index 92% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TestMethodFilterTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodFilterTests.cs index e416447e4b..28f5710903 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestMethodFilterTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodFilterTests.cs @@ -2,15 +2,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using TestFramework.ForTestingMSTest; -using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; -using UTFExtension = Microsoft.VisualStudio.TestTools.UnitTesting; - namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution; public class TestMethodFilterTests : TestContainer @@ -59,7 +57,7 @@ public void PropertyProviderValueForInvalidPropertyNameReturnsNull() { Type type = typeof(DummyTestClassWithTestMethods); string fullName = $"{type.FullName}.TestMethod"; - TestCase testCase = new(fullName, MSTest.TestAdapter.Constants.ExecutorUri, Assembly.GetExecutingAssembly().FullName!); + TestCase testCase = new(fullName, EngineConstants.ExecutorUri, Assembly.GetExecutingAssembly().FullName!); object? result = _testMethodFilter.PropertyValueProvider(testCase, null); Verify(result is null); @@ -70,7 +68,7 @@ public void PropertyProviderValueForSupportedPropertyNameWhichIsNotSetReturnsNul Type type = typeof(DummyTestClassWithTestMethods); string fullName = $"{type.FullName}.TestMethod"; - TestCase testCase = new(fullName, MSTest.TestAdapter.Constants.ExecutorUri, Assembly.GetExecutingAssembly().FullName!); + TestCase testCase = new(fullName, EngineConstants.ExecutorUri, Assembly.GetExecutingAssembly().FullName!); object? result = _testMethodFilter.PropertyValueProvider(testCase, "Priority"); Verify(result is null); } @@ -80,7 +78,7 @@ public void PropertyProviderValueForValidTestAndSupportedPropertyNameReturnsValu Type type = typeof(DummyTestClassWithTestMethods); string fullName = $"{type.FullName}.TestMethod"; - TestCase testCase = new(fullName, MSTest.TestAdapter.Constants.ExecutorUri, Assembly.GetExecutingAssembly().FullName!); + TestCase testCase = new(fullName, EngineConstants.ExecutorUri, Assembly.GetExecutingAssembly().FullName!); object? result = _testMethodFilter.PropertyValueProvider(testCase, "FullyQualifiedName"); Verify(fullName.Equals(result)); @@ -163,9 +161,9 @@ public void GetFilterExpressionForDiscoveryContextWithGetTestCaseFilterThrowingE [DummyTestClass] internal class DummyTestClassWithTestMethods { - public UTFExtension.TestContext TestContext { get; set; } = null!; + public TestContext TestContext { get; set; } = null!; - [UTF.TestMethod] + [TestMethod] public void TestMethod() { } @@ -227,10 +225,10 @@ private class TestableDiscoveryContextWithoutGetTestCaseFilter : IDiscoveryConte private sealed class TestableTestCaseFilterExpression : ITestCaseFilterExpression { - public string TestCaseFilterValue { get; } = null!; + public string TestCaseFilterValue => null!; public bool MatchTestCase(TestCase testCase, Func propertyValueProvider) => throw new NotImplementedException(); } - private class DummyTestClassAttribute : UTF.TestClassAttribute; + private class DummyTestClassAttribute : TestClassAttribute; } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestMethodInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs similarity index 81% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TestMethodInfoTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs index b935c23c3b..a6f7dea1cc 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestMethodInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs @@ -12,9 +12,7 @@ using TestFramework.ForTestingMSTest; -using Resource = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Resource; using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; -using UTFExtension = Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution; @@ -27,9 +25,9 @@ public class TestMethodInfoTests : TestContainer private readonly MethodInfo _methodInfo; - private readonly UTF.TestClassAttribute _classAttribute; + private readonly TestClassAttribute _classAttribute; - private readonly UTF.TestMethodAttribute _testMethodAttribute; + private readonly TestMethodAttribute _testMethodAttribute; private readonly TestAssemblyInfo _testAssemblyInfo; @@ -39,20 +37,20 @@ public class TestMethodInfoTests : TestContainer private readonly TestClassInfo _testClassInfo; - private readonly UTF.ExpectedExceptionAttribute _expectedException; + private readonly ExpectedExceptionAttribute _expectedException; public TestMethodInfoTests() { _constructorInfo = typeof(DummyTestClass).GetConstructor([])!; _methodInfo = typeof(DummyTestClass).GetMethods().Single(m => m.Name.Equals("DummyTestMethod", StringComparison.Ordinal)); - _classAttribute = new UTF.TestClassAttribute(); - _testMethodAttribute = new UTF.TestMethodAttribute(); + _classAttribute = new TestClassAttribute(); + _testMethodAttribute = new TestMethodAttribute(); _testAssemblyInfo = new TestAssemblyInfo(typeof(DummyTestClass).Assembly); var testMethod = new TestMethod("dummyTestName", "dummyClassName", "dummyAssemblyName", false); _testContextImplementation = new TestContextImplementation(testMethod, new ThreadSafeStringWriter(null!, "test"), new Dictionary()); _testClassInfo = new TestClassInfo(typeof(DummyTestClass), _constructorInfo, true, _classAttribute, _testAssemblyInfo); - _expectedException = new UTF.ExpectedExceptionAttribute(typeof(DivideByZeroException)); + _expectedException = new ExpectedExceptionAttribute(typeof(DivideByZeroException)); _testMethodInfo = new TestMethodInfo( _methodInfo, @@ -84,7 +82,7 @@ public void SetArgumentsShouldSetArgumentsNeededForCurrentTestRun() #region TestMethod invoke scenarios - public void TestMethodInfoInvokeShouldWaitForAsyncTestMethodsToComplete() + public async Task TestMethodInfoInvokeShouldWaitForAsyncTestMethodsToComplete() { bool methodCalled = false; DummyTestClass.DummyAsyncTestMethodBody = () => Task.Run(() => methodCalled = true); @@ -96,15 +94,15 @@ public void TestMethodInfoInvokeShouldWaitForAsyncTestMethodsToComplete() Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(methodCalled); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeAsyncShouldHandleThrowAssertInconclusive() + public async Task TestMethodInfoInvokeAsyncShouldHandleThrowAssertInconclusive() { - DummyTestClass.DummyAsyncTestMethodBody = () => Task.Run(() => throw new UTF.AssertInconclusiveException()); + DummyTestClass.DummyAsyncTestMethodBody = () => Task.Run(() => throw new AssertInconclusiveException()); MethodInfo asyncMethodInfo = typeof(DummyTestClass).GetMethod("DummyAsyncTestMethod")!; var method = new TestMethodInfo( @@ -116,12 +114,12 @@ public void TestMethodInfoInvokeAsyncShouldHandleThrowAssertInconclusive() Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); } - public void TestMethodInfoInvokeAsyncShouldHandleAssertInconclusive() + public async Task TestMethodInfoInvokeAsyncShouldHandleAssertInconclusive() { DummyTestClass.DummyAsyncTestMethodBody = () => Task.Run(() => UTF.Assert.Inconclusive()); MethodInfo asyncMethodInfo = typeof(DummyTestClass).GetMethod("DummyAsyncTestMethod")!; @@ -135,14 +133,14 @@ public void TestMethodInfoInvokeAsyncShouldHandleAssertInconclusive() Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); } - public void TestMethodInfoInvokeShouldHandleThrowAssertInconclusive() + public async Task TestMethodInfoInvokeShouldHandleThrowAssertInconclusive() { - DummyTestClass.TestMethodBody = d => throw new UTF.AssertInconclusiveException(); + DummyTestClass.TestMethodBody = d => throw new AssertInconclusiveException(); MethodInfo dummyMethodInfo = typeof(DummyTestClass).GetMethod("DummyTestMethod")!; var method = new TestMethodInfo( @@ -154,12 +152,12 @@ public void TestMethodInfoInvokeShouldHandleThrowAssertInconclusive() Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); } - public void TestMethodInfoInvokeShouldHandleAssertInconclusive() + public async Task TestMethodInfoInvokeShouldHandleAssertInconclusive() { DummyTestClass.TestMethodBody = d => UTF.Assert.Inconclusive(); MethodInfo dummyMethodInfo = typeof(DummyTestClass).GetMethod("DummyTestMethod")!; @@ -173,12 +171,12 @@ public void TestMethodInfoInvokeShouldHandleAssertInconclusive() Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); } - public void TestMethodInfoInvokeShouldReportTestContextMessages() + public async Task TestMethodInfoInvokeShouldReportTestContextMessages() { DummyTestClass.TestMethodBody = o => _testContextImplementation.WriteLine("TestContext"); @@ -191,12 +189,12 @@ public void TestMethodInfoInvokeShouldReportTestContextMessages() Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.TestContextMessages!.Contains("TestContext")); } - public void TestMethodInfoInvokeShouldClearTestContextMessagesAfterReporting() + public async Task TestMethodInfoInvokeShouldClearTestContextMessagesAfterReporting() { DummyTestClass.TestMethodBody = o => _testContextImplementation.WriteLine("TestContext"); @@ -209,18 +207,18 @@ public void TestMethodInfoInvokeShouldClearTestContextMessagesAfterReporting() Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.TestContextMessages!.Contains("TestContext")); DummyTestClass.TestMethodBody = o => _testContextImplementation.WriteLine("SeaShore"); - result = method.Invoke(null); + result = await method.InvokeAsync(null); Verify(result.TestContextMessages!.Contains("SeaShore")); } - public void Invoke_WhenTestMethodThrowsMissingMethodException_TestOutcomeIsFailedAndExceptionIsPreserved() + public async Task Invoke_WhenTestMethodThrowsMissingMethodException_TestOutcomeIsFailedAndExceptionIsPreserved() { DummyTestClass.TestMethodBody = _ => { @@ -242,7 +240,7 @@ public void Invoke_WhenTestMethodThrowsMissingMethodException_TestOutcomeIsFaile Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); Verify(result.TestFailureException is TestFailedException); @@ -253,32 +251,32 @@ public void Invoke_WhenTestMethodThrowsMissingMethodException_TestOutcomeIsFaile #region TestClass constructor setup - public void TestMethodInfoInvokeShouldCreateNewInstanceOfTestClassOnEveryCall() + public async Task TestMethodInfoInvokeShouldCreateNewInstanceOfTestClassOnEveryCall() { int ctorCallCount = 0; DummyTestClass.TestConstructorMethodBody = () => ctorCallCount++; - UTF.TestResult result = _testMethodInfo.Invoke(null); - _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); + await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); Verify(ctorCallCount == 2); } - public void TestMethodInfoInvokeShouldMarkOutcomeFailedIfTestClassConstructorThrows() + public async Task TestMethodInfoInvokeShouldMarkOutcomeFailedIfTestClassConstructorThrows() { DummyTestClass.TestConstructorMethodBody = () => throw new NotImplementedException(); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void TestMethodInfoInvokeShouldSetErrorMessageIfTestClassConstructorThrows() + public async Task TestMethodInfoInvokeShouldSetErrorMessageIfTestClassConstructorThrows() { DummyTestClass.TestConstructorMethodBody = () => throw new NotImplementedException("dummyExceptionMessage"); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); string errorMessage = string.Format( CultureInfo.InvariantCulture, @@ -288,7 +286,7 @@ public void TestMethodInfoInvokeShouldSetErrorMessageIfTestClassConstructorThrow Verify(errorMessage == result.TestFailureException!.Message); } - public void TestMethodInfoInvokeShouldSetErrorMessageIfTestClassConstructorThrowsWithoutInnerException() + public async Task TestMethodInfoInvokeShouldSetErrorMessageIfTestClassConstructorThrowsWithoutInnerException() { ConstructorInfo ctorInfo = typeof(DummyTestClassWithParameterizedCtor).GetConstructors().Single(); var testClass = new TestClassInfo(typeof(DummyTestClassWithParameterizedCtor), ctorInfo, true, _classAttribute, _testAssemblyInfo); @@ -298,7 +296,7 @@ public void TestMethodInfoInvokeShouldSetErrorMessageIfTestClassConstructorThrow Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); string errorMessage = string.Format( CultureInfo.InvariantCulture, Resource.UTA_InstanceCreationError, @@ -309,11 +307,11 @@ public void TestMethodInfoInvokeShouldSetErrorMessageIfTestClassConstructorThrow Verify(errorMessage == result.TestFailureException!.Message); } - public void TestMethodInfoInvokeShouldSetStackTraceInformationIfTestClassConstructorThrows() + public async Task TestMethodInfoInvokeShouldSetStackTraceInformationIfTestClassConstructorThrows() { DummyTestClass.TestConstructorMethodBody = () => throw new NotImplementedException("dummyExceptionMessage"); - var exception = _testMethodInfo.Invoke(null).TestFailureException as TestFailedException; + var exception = (await _testMethodInfo.InvokeAsync(null)).TestFailureException as TestFailedException; Verify(exception is not null); Verify(exception.StackTraceInformation is not null); @@ -322,7 +320,7 @@ public void TestMethodInfoInvokeShouldSetStackTraceInformationIfTestClassConstru " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestMethodInfoTests.<>c.b__", StringComparison.Ordinal)); } - public void TestMethodInfoInvokeShouldSetStackTraceInformationIfTestClassConstructorThrowsWithoutInnerException() + public async Task TestMethodInfoInvokeShouldSetStackTraceInformationIfTestClassConstructorThrowsWithoutInnerException() { ConstructorInfo ctorInfo = typeof(DummyTestClassWithParameterizedCtor).GetConstructors().Single(); var testClass = new TestClassInfo(typeof(DummyTestClassWithParameterizedCtor), ctorInfo, true, _classAttribute, _testAssemblyInfo); @@ -332,7 +330,7 @@ public void TestMethodInfoInvokeShouldSetStackTraceInformationIfTestClassConstru Executor = _testMethodAttribute, }; - var exception = method.Invoke(null).TestFailureException as TestFailedException; + var exception = (await method.InvokeAsync(null)).TestFailureException as TestFailedException; Verify(exception is not null); Verify(exception.StackTraceInformation is not null); @@ -341,11 +339,11 @@ public void TestMethodInfoInvokeShouldSetStackTraceInformationIfTestClassConstru " at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)", StringComparison.Ordinal)); } - public void TestMethodInfoInvokeShouldSetResultFilesIfTestContextHasAttachments() + public async Task TestMethodInfoInvokeShouldSetResultFilesIfTestContextHasAttachments() { Mock testContext = new(); - testContext.Setup(tc => tc.GetResultFiles()).Returns(new List { "C:\\temp.txt" }); - var mockInnerContext = new Mock(); + testContext.Setup(tc => tc.GetResultFiles()).Returns(["C:\\temp.txt"]); + var mockInnerContext = new Mock(); testContext.SetupGet(tc => tc.Context).Returns(mockInnerContext.Object); mockInnerContext.SetupGet(tc => tc.CancellationTokenSource).Returns(new CancellationTokenSource()); @@ -355,13 +353,13 @@ public void TestMethodInfoInvokeShouldSetResultFilesIfTestContextHasAttachments( Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.ResultFiles!.Contains("C:\\temp.txt")); } - public void TestMethodInfoInvoke_WhenCtorHasOneParameterOfTypeTestContext_SetsItToTestContext() + public async Task TestMethodInfoInvoke_WhenCtorHasOneParameterOfTypeTestContext_SetsItToTestContext() { - ConstructorInfo ctorInfo = typeof(DummyTestClass).GetConstructor([typeof(UTFExtension.TestContext)])!; + ConstructorInfo ctorInfo = typeof(DummyTestClass).GetConstructor([typeof(TestContext)])!; var testClassInfo = new TestClassInfo(typeof(DummyTestClass), ctorInfo, false, _classAttribute, _testAssemblyInfo); var testMethodInfo = new TestMethodInfo(_methodInfo, testClassInfo, _testContextImplementation) { @@ -369,7 +367,7 @@ public void TestMethodInfoInvoke_WhenCtorHasOneParameterOfTypeTestContext_SetsIt Executor = _testMethodAttribute, }; - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } @@ -378,7 +376,7 @@ public void TestMethodInfoInvoke_WhenCtorHasOneParameterOfTypeTestContext_SetsIt #region TestClass.TestContext property setup - public void TestMethodInfoInvokeShouldNotThrowIfTestContextIsNotPresent() + public async Task TestMethodInfoInvokeShouldNotThrowIfTestContextIsNotPresent() { var testClass = new TestClassInfo(typeof(DummyTestClass), _constructorInfo, true, _classAttribute, _testAssemblyInfo); var method = new TestMethodInfo(_methodInfo, testClass, _testContextImplementation) @@ -387,14 +385,16 @@ public void TestMethodInfoInvokeShouldNotThrowIfTestContextIsNotPresent() Executor = _testMethodAttribute, }; - UTF.TestResult result; - void RunMethod() => result = method.Invoke(null); +#pragma warning disable IDE0059 // Unnecessary assignment of a value - fp + TestResult result = null!; +#pragma warning restore IDE0059 // Unnecessary assignment of a value + async Task RunMethod() => result = await method.InvokeAsync(null); - RunMethod(); + await RunMethod(); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeShouldNotThrowIfTestContextDoesNotHaveASetter() + public async Task TestMethodInfoInvokeShouldNotThrowIfTestContextDoesNotHaveASetter() { var testClass = new TestClassInfo(typeof(DummyTestClass), _constructorInfo, true, _classAttribute, _testAssemblyInfo); var method = new TestMethodInfo(_methodInfo, testClass, _testContextImplementation) @@ -403,37 +403,39 @@ public void TestMethodInfoInvokeShouldNotThrowIfTestContextDoesNotHaveASetter() Executor = _testMethodAttribute, }; - UTF.TestResult result; - void RunMethod() => result = method.Invoke(null); +#pragma warning disable IDE0059 // Unnecessary assignment of a value - fp + TestResult result = null!; +#pragma warning restore IDE0059 // Unnecessary assignment of a value + async Task RunMethod() => result = await method.InvokeAsync(null); - RunMethod(); + await RunMethod(); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeShouldSetTestContextForTestClassInstance() + public async Task TestMethodInfoInvokeShouldSetTestContextForTestClassInstance() { - UTFExtension.TestContext? testContext = null; - DummyTestClass.TestContextSetterBody = context => testContext = context as UTFExtension.TestContext; + TestContext? testContext = null; + DummyTestClass.TestContextSetterBody = context => testContext = context as TestContext; - _testMethodInfo.Invoke(null); + await _testMethodInfo.InvokeAsync(null); Verify(_testContextImplementation.Equals(testContext)); } - public void TestMethodInfoInvokeShouldMarkOutcomeFailedIfSetTestContextThrows() + public async Task TestMethodInfoInvokeShouldMarkOutcomeFailedIfSetTestContextThrows() { DummyTestClass.TestContextSetterBody = value => throw new NotImplementedException(); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void TestMethodInfoInvokeShouldSetErrorMessageIfSetTestContextThrows() + public async Task TestMethodInfoInvokeShouldSetErrorMessageIfSetTestContextThrows() { DummyTestClass.TestContextSetterBody = value => throw new NotImplementedException("dummyExceptionMessage"); - var exception = _testMethodInfo.Invoke(null).TestFailureException as TestFailedException; + var exception = (await _testMethodInfo.InvokeAsync(null)).TestFailureException as TestFailedException; string errorMessage = string.Format( CultureInfo.InvariantCulture, @@ -444,11 +446,11 @@ public void TestMethodInfoInvokeShouldSetErrorMessageIfSetTestContextThrows() Verify(errorMessage == exception?.Message); } - public void TestMethodInfoInvokeShouldSetStackTraceInformationIfSetTestContextThrows() + public async Task TestMethodInfoInvokeShouldSetStackTraceInformationIfSetTestContextThrows() { DummyTestClass.TestConstructorMethodBody = () => throw new NotImplementedException("dummyExceptionMessage"); - var exception = _testMethodInfo.Invoke(null).TestFailureException as TestFailedException; + var exception = (await _testMethodInfo.InvokeAsync(null)).TestFailureException as TestFailedException; Verify(exception is not null); Verify(exception.StackTraceInformation is not null); @@ -457,19 +459,19 @@ public void TestMethodInfoInvokeShouldSetStackTraceInformationIfSetTestContextTh " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestMethodInfoTests.<>c.b__", StringComparison.Ordinal)); } - public void TestMethodInfoInvoke_WhenCtorHasOneParameterOfTypeTestContextAndTestContextProperty_InitializeBothTestContexts() + public async Task TestMethodInfoInvoke_WhenCtorHasOneParameterOfTypeTestContextAndTestContextProperty_InitializeBothTestContexts() { - ConstructorInfo ctorInfo = typeof(DummyTestClass).GetConstructor([typeof(UTFExtension.TestContext)])!; + ConstructorInfo ctorInfo = typeof(DummyTestClass).GetConstructor([typeof(TestContext)])!; var testClassInfo = new TestClassInfo(typeof(DummyTestClass), ctorInfo, false, _classAttribute, _testAssemblyInfo); var testMethodInfo = new TestMethodInfo(_methodInfo, testClassInfo, _testContextImplementation) { TimeoutInfo = TimeoutInfo.FromTimeout(3600 * 1000), Executor = _testMethodAttribute, }; - UTFExtension.TestContext? testContext = null; - DummyTestClass.TestContextSetterBody = context => testContext = context as UTFExtension.TestContext; + TestContext? testContext = null; + DummyTestClass.TestContextSetterBody = context => testContext = context as TestContext; - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); Verify(_testContextImplementation.Equals(testContext)); @@ -479,31 +481,31 @@ public void TestMethodInfoInvoke_WhenCtorHasOneParameterOfTypeTestContextAndTest #region TestInitialize method setup - public void TestMethodInfoInvokeShouldCallTestInitialize() + public async Task TestMethodInfoInvokeShouldCallTestInitialize() { bool testInitializeCalled = false; DummyTestClass.TestInitializeMethodBody = classInstance => testInitializeCalled = true; _testClassInfo.TestInitializeMethod = typeof(DummyTestClass).GetMethod("DummyTestInitializeMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(testInitializeCalled); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeShouldCallAsyncTestInitializeAndWaitForCompletion() + public async Task TestMethodInfoInvokeShouldCallAsyncTestInitializeAndWaitForCompletion() { bool testInitializeCalled = false; DummyTestClass.DummyAsyncTestMethodBody = () => Task.Run(() => testInitializeCalled = true); _testClassInfo.TestInitializeMethod = typeof(DummyTestClass).GetMethod("DummyAsyncTestMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(testInitializeCalled); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeShouldCallTestInitializeOfAllBaseClasses() + public async Task TestMethodInfoInvokeShouldCallTestInitializeOfAllBaseClasses() { var callOrder = new List(); DummyTestClassBase.BaseTestClassMethodBody = classInstance => callOrder.Add("baseTestInitializeCalled2"); @@ -513,7 +515,7 @@ public void TestMethodInfoInvokeShouldCallTestInitializeOfAllBaseClasses() _testClassInfo.BaseTestInitializeMethodsQueue.Enqueue(typeof(DummyTestClassBase).GetMethod("DummyBaseTestClassMethod")!); _testClassInfo.BaseTestInitializeMethodsQueue.Enqueue(typeof(DummyTestClass).GetMethod("DummyAsyncTestMethod")!); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); var expectedCallOrder = new List { @@ -525,25 +527,25 @@ public void TestMethodInfoInvokeShouldCallTestInitializeOfAllBaseClasses() Verify(expectedCallOrder.SequenceEqual(callOrder)); } - public void TestMethodInfoInvokeShouldNotThrowIfTestInitializeIsNull() + public async Task TestMethodInfoInvokeShouldNotThrowIfTestInitializeIsNull() { _testClassInfo.TestInitializeMethod = null; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeShouldNotThrowIfTestInitializeForBaseClassIsNull() + public async Task TestMethodInfoInvokeShouldNotThrowIfTestInitializeForBaseClassIsNull() { _testClassInfo.BaseTestInitializeMethodsQueue.Enqueue(null!); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeWhenTestThrowsReturnsExpectedResult() + public async Task TestMethodInfoInvokeWhenTestThrowsReturnsExpectedResult() { // Arrange. DummyTestClass.TestInitializeMethodBody = classInstance => throw new ArgumentException("Some exception message", new InvalidOperationException("Inner exception message")); @@ -563,7 +565,7 @@ public void TestMethodInfoInvokeWhenTestThrowsReturnsExpectedResult() }; // Act. - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); // Assert. Verify(result.Outcome == UTF.UnitTestOutcome.Failed); @@ -580,7 +582,7 @@ public void TestMethodInfoInvokeWhenTestThrowsReturnsExpectedResult() #endif } - public void TestInitialize_WhenTestReturnsTaskFromException_DisplayProperException() + public async Task TestInitialize_WhenTestReturnsTaskFromException_DisplayProperException() { // Arrange. DummyTestClass.TestInitializeMethodBodyAsync = async classInstance => await Task.FromException(new Exception("Outer", new InvalidOperationException("Inner"))); @@ -593,7 +595,7 @@ public void TestInitialize_WhenTestReturnsTaskFromException_DisplayProperExcepti }; // Act. - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); // Assert. Verify(result.Outcome == UTF.UnitTestOutcome.Failed); @@ -614,7 +616,7 @@ public void TestInitialize_WhenTestReturnsTaskFromException_DisplayProperExcepti Verify(exception.StackTraceInformation is not null); } - public void TestMethodInfoInvokeWhenTestThrowsAssertFailReturnsExpectedResult() + public async Task TestMethodInfoInvokeWhenTestThrowsAssertFailReturnsExpectedResult() { // Arrange. DummyTestClass.TestInitializeMethodBody = classInstance => UTF.Assert.Fail("dummyFailMessage"); @@ -634,7 +636,7 @@ public void TestMethodInfoInvokeWhenTestThrowsAssertFailReturnsExpectedResult() }; // Act. - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); // Assert. Verify(result.Outcome == UTF.UnitTestOutcome.Failed); @@ -643,14 +645,14 @@ public void TestMethodInfoInvokeWhenTestThrowsAssertFailReturnsExpectedResult() Verify(exception is not null); Verify(errorMessage == exception.Message); Verify(exception.Outcome == UTF.UnitTestOutcome.Failed); - Verify(exception.InnerException!.GetType() == typeof(UTF.AssertFailedException)); + Verify(exception.InnerException!.GetType() == typeof(AssertFailedException)); #if DEBUG Verify(exception.StackTraceInformation!.ErrorStackTrace.StartsWith( " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestMethodInfoTests.<>c.b__", StringComparison.Ordinal)); #endif } - public void TestMethodInfoInvokeWhenTestThrowsAssertInconclusiveReturnsExpectedResult() + public async Task TestMethodInfoInvokeWhenTestThrowsAssertInconclusiveReturnsExpectedResult() { // Arrange. DummyTestClass.TestInitializeMethodBody = classInstance => UTF.Assert.Inconclusive("dummyFailMessage"); @@ -670,7 +672,7 @@ public void TestMethodInfoInvokeWhenTestThrowsAssertInconclusiveReturnsExpectedR }; // Act. - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); // Assert. Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); @@ -679,7 +681,7 @@ public void TestMethodInfoInvokeWhenTestThrowsAssertInconclusiveReturnsExpectedR Verify(exception is not null); Verify(errorMessage == exception.Message); Verify(exception.Outcome == UTF.UnitTestOutcome.Inconclusive); - Verify(exception.InnerException!.GetType() == typeof(UTF.AssertInconclusiveException)); + Verify(exception.InnerException!.GetType() == typeof(AssertInconclusiveException)); #if DEBUG Verify(exception.StackTraceInformation!.ErrorStackTrace.StartsWith( " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestMethodInfoTests.<>c.b__", StringComparison.Ordinal)); @@ -690,7 +692,7 @@ public void TestMethodInfoInvokeWhenTestThrowsAssertInconclusiveReturnsExpectedR #region TestCleanup method setup - public void TestCleanup_WhenTestReturnsTaskFromException_DisplayProperException() + public async Task TestCleanup_WhenTestReturnsTaskFromException_DisplayProperException() { // Arrange. DummyTestClass.TestCleanupMethodBodyAsync = async classInstance => await Task.FromException(new Exception("Outer", new InvalidOperationException("Inner"))); @@ -702,7 +704,7 @@ public void TestCleanup_WhenTestReturnsTaskFromException_DisplayProperException( }; // Act. - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); // Assert. Verify(result.Outcome == UTF.UnitTestOutcome.Failed); @@ -727,40 +729,40 @@ public void TestCleanup_WhenTestReturnsTaskFromException_DisplayProperException( } } - public void TestMethodInfoInvokeShouldCallTestCleanup() + public async Task TestMethodInfoInvokeShouldCallTestCleanup() { bool cleanupMethodCalled = false; DummyTestClass.DummyAsyncTestMethodBody = () => Task.Run(() => cleanupMethodCalled = true); _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyAsyncTestMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); Verify(cleanupMethodCalled); } - public void TestMethodInfoInvokeShouldCallAsyncTestCleanup() + public async Task TestMethodInfoInvokeShouldCallAsyncTestCleanup() { bool cleanupMethodCalled = false; DummyTestClass.TestCleanupMethodBody = classInstance => cleanupMethodCalled = true; _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); Verify(cleanupMethodCalled); } - public void TestMethodInfoInvokeShouldNotThrowIfTestCleanupMethodIsNull() + public async Task TestMethodInfoInvokeShouldNotThrowIfTestCleanupMethodIsNull() { _testClassInfo.TestCleanupMethod = null; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeShouldCallTestCleanupForBaseTestClasses() + public async Task TestMethodInfoInvokeShouldCallTestCleanupForBaseTestClasses() { var callOrder = new List(); DummyTestClassBase.BaseTestClassMethodBody = classInstance => callOrder.Add("baseTestCleanupCalled" + callOrder.Count); @@ -769,7 +771,7 @@ public void TestMethodInfoInvokeShouldCallTestCleanupForBaseTestClasses() _testClassInfo.BaseTestCleanupMethodsQueue.Enqueue(typeof(DummyTestClassBase).GetMethod("DummyBaseTestClassMethod")!); _testClassInfo.BaseTestCleanupMethodsQueue.Enqueue(typeof(DummyTestClassBase).GetMethod("DummyBaseTestClassMethod")!); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); var expectedCallOrder = new List { @@ -781,7 +783,7 @@ public void TestMethodInfoInvokeShouldCallTestCleanupForBaseTestClasses() Verify(expectedCallOrder.SequenceEqual(callOrder)); } - public void TestMethodInfoInvokeShouldCallTestCleanupForBaseTestClassesAlways() + public async Task TestMethodInfoInvokeShouldCallTestCleanupForBaseTestClassesAlways() { var callOrder = new List(); DummyTestClassBase.BaseTestClassMethodBody = classInstance => callOrder.Add("baseTestCleanupCalled" + callOrder.Count); @@ -790,8 +792,8 @@ public void TestMethodInfoInvokeShouldCallTestCleanupForBaseTestClassesAlways() _testClassInfo.BaseTestCleanupMethodsQueue.Enqueue(typeof(DummyTestClassBase).GetMethod("DummyBaseTestClassMethod")!); _testClassInfo.BaseTestCleanupMethodsQueue.Enqueue(typeof(DummyTestClassBase).GetMethod("DummyBaseTestClassMethod")!); - _testMethodInfo.Invoke(null); - UTF.TestResult result = _testMethodInfo.Invoke(null); + await _testMethodInfo.InvokeAsync(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); var expectedCallOrder = new List { @@ -807,7 +809,7 @@ public void TestMethodInfoInvokeShouldCallTestCleanupForBaseTestClassesAlways() Verify(expectedCallOrder.SequenceEqual(callOrder)); } - public void TestMethodInfoInvokeWhenTestCleanupThrowsReturnsExpectedResult() + public async Task TestMethodInfoInvokeWhenTestCleanupThrowsReturnsExpectedResult() { DummyTestClass.TestCleanupMethodBody = classInstance => throw new ArgumentException("Some exception message", new InvalidOperationException("Inner exception message")); _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; @@ -819,7 +821,7 @@ public void TestMethodInfoInvokeWhenTestCleanupThrowsReturnsExpectedResult() _testClassInfo.TestCleanupMethod!.Name, "System.ArgumentException: Some exception message ---> System.InvalidOperationException: Inner exception message"); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); @@ -836,7 +838,7 @@ public void TestMethodInfoInvokeWhenTestCleanupThrowsReturnsExpectedResult() #endif } - public void TestMethodInfoInvokeWhenTestCleanupThrowsAssertInconclusiveReturnsExpectedResult() + public async Task TestMethodInfoInvokeWhenTestCleanupThrowsAssertInconclusiveReturnsExpectedResult() { DummyTestClass.TestCleanupMethodBody = classInstance => UTF.Assert.Inconclusive("Test inconclusive"); _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; @@ -848,7 +850,7 @@ public void TestMethodInfoInvokeWhenTestCleanupThrowsAssertInconclusiveReturnsEx _testClassInfo.TestCleanupMethod.Name, "Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException: Assert.Inconclusive failed. Test inconclusive"); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); @@ -856,14 +858,14 @@ public void TestMethodInfoInvokeWhenTestCleanupThrowsAssertInconclusiveReturnsEx Verify(exception is not null); Verify(exception.Outcome == UTF.UnitTestOutcome.Inconclusive); Verify(expectedErrorMessage == exception.Message); - Verify(exception.InnerException!.GetType() == typeof(UTF.AssertInconclusiveException)); + Verify(exception.InnerException!.GetType() == typeof(AssertInconclusiveException)); #if DEBUG Verify(exception.StackTraceInformation!.ErrorStackTrace.StartsWith( " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestMethodInfoTests.<>c.b__", StringComparison.Ordinal)); #endif } - public void TestMethodInfoInvokeWhenTestCleanupThrowsAssertFailedReturnsExpectedResult() + public async Task TestMethodInfoInvokeWhenTestCleanupThrowsAssertFailedReturnsExpectedResult() { DummyTestClass.TestCleanupMethodBody = classInstance => UTF.Assert.Fail("Test failed"); _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; @@ -875,7 +877,7 @@ public void TestMethodInfoInvokeWhenTestCleanupThrowsAssertFailedReturnsExpected _testClassInfo.TestCleanupMethod!.Name, "Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.Fail failed. Test failed"); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); @@ -883,20 +885,20 @@ public void TestMethodInfoInvokeWhenTestCleanupThrowsAssertFailedReturnsExpected Verify(exception is not null); Verify(exception.Outcome == UTF.UnitTestOutcome.Failed); Verify(expectedErrorMessage == exception.Message); - Verify(exception.InnerException!.GetType() == typeof(UTF.AssertFailedException)); + Verify(exception.InnerException!.GetType() == typeof(AssertFailedException)); #if DEBUG Verify(exception.StackTraceInformation!.ErrorStackTrace.StartsWith( " at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestMethodInfoTests.<>c.b__", StringComparison.Ordinal)); #endif } - public void TestMethodInfoInvokeShouldAppendErrorMessagesIfBothTestMethodAndTestCleanupThrows() + public async Task TestMethodInfoInvokeShouldAppendErrorMessagesIfBothTestMethodAndTestCleanupThrows() { DummyTestClass.TestCleanupMethodBody = classInstance => throw new NotImplementedException("dummyErrorMessage"); DummyTestClass.TestMethodBody = classInstance => throw new NotImplementedException("dummyMethodError"); _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); var exception = result.TestFailureException as AggregateException; string errorMessage = string.Format( CultureInfo.CurrentCulture, @@ -917,13 +919,13 @@ public void TestMethodInfoInvokeShouldAppendErrorMessagesIfBothTestMethodAndTest Verify(exception.InnerExceptions[1].Message.Contains(cleanupError)); } - public void TestMethodInfoInvokeShouldAppendStackTraceInformationIfBothTestMethodAndTestCleanupThrows() + public async Task TestMethodInfoInvokeShouldAppendStackTraceInformationIfBothTestMethodAndTestCleanupThrows() { DummyTestClass.TestCleanupMethodBody = classInstance => throw new NotImplementedException(); DummyTestClass.TestMethodBody = classInstance => throw new NotImplementedException("dummyMethodError"); _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); var exception = result.TestFailureException as AggregateException; Verify(result.Outcome == UTF.UnitTestOutcome.Failed); @@ -934,12 +936,12 @@ public void TestMethodInfoInvokeShouldAppendStackTraceInformationIfBothTestMetho #endif } - public void TestMethodInfoInvokeShouldSetOutcomeAsInconclusiveIfTestCleanupIsInconclusive() + public async Task TestMethodInfoInvokeShouldSetOutcomeAsInconclusiveIfTestCleanupIsInconclusive() { - DummyTestClass.TestCleanupMethodBody = classInstance => throw new UTF.AssertInconclusiveException(); + DummyTestClass.TestCleanupMethodBody = classInstance => throw new AssertInconclusiveException(); _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); var exception = result.TestFailureException as TestFailedException; Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); @@ -947,18 +949,18 @@ public void TestMethodInfoInvokeShouldSetOutcomeAsInconclusiveIfTestCleanupIsInc Verify(exception.Message.Contains("Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException")); } - public void TestMethodInfoInvokeShouldSetMoreImportantOutcomeIfTestCleanupIsInconclusiveButTestMethodFails() + public async Task TestMethodInfoInvokeShouldSetMoreImportantOutcomeIfTestCleanupIsInconclusiveButTestMethodFails() { - DummyTestClass.TestCleanupMethodBody = classInstance => throw new UTF.AssertInconclusiveException(); + DummyTestClass.TestCleanupMethodBody = classInstance => throw new AssertInconclusiveException(); DummyTestClass.TestMethodBody = classInstance => Fail(); _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void TestMethodInfoInvokeShouldCallDisposeForDisposableTestClass() + public async Task TestMethodInfoInvokeShouldCallDisposeForDisposableTestClass() { bool disposeCalled = false; DummyTestClassWithDisposable.DisposeMethodBody = () => disposeCalled = true; @@ -970,13 +972,13 @@ public void TestMethodInfoInvokeShouldCallDisposeForDisposableTestClass() Executor = _testMethodAttribute, }; - method.Invoke(null); + await method.InvokeAsync(null); Verify(disposeCalled); } #if NET6_0_OR_GREATER - public void TestMethodInfoInvoke_WhenTestClassIsAsyncDisposable_ShouldDisposeAsync() + public async Task TestMethodInfoInvoke_WhenTestClassIsAsyncDisposable_ShouldDisposeAsync() { // Arrange bool asyncDisposeCalled = false; @@ -990,13 +992,13 @@ public void TestMethodInfoInvoke_WhenTestClassIsAsyncDisposable_ShouldDisposeAsy }; // Act - method.Invoke(null); + await method.InvokeAsync(null); // Assert Verify(asyncDisposeCalled); } - public void TestMethodInfoInvoke_WhenTestClassIsDisposableAndAsyncDisposable_ShouldCallAsyncDisposeThenDispose() + public async Task TestMethodInfoInvoke_WhenTestClassIsDisposableAndAsyncDisposable_ShouldCallAsyncDisposeThenDispose() { // Arrange int order = 0; @@ -1015,7 +1017,7 @@ public void TestMethodInfoInvoke_WhenTestClassIsDisposableAndAsyncDisposable_Sho }; // Act - method.Invoke(null); + await method.InvokeAsync(null); // Assert Verify(disposeCalledOrder == 2); @@ -1023,7 +1025,7 @@ public void TestMethodInfoInvoke_WhenTestClassIsDisposableAndAsyncDisposable_Sho } #endif - public void TestMethodInfoInvokeShouldCallDisposeForDisposableTestClassIfTestCleanupThrows() + public async Task TestMethodInfoInvokeShouldCallDisposeForDisposableTestClassIfTestCleanupThrows() { bool disposeCalled = false; DummyTestClassWithDisposable.DisposeMethodBody = () => disposeCalled = true; @@ -1039,25 +1041,25 @@ public void TestMethodInfoInvokeShouldCallDisposeForDisposableTestClassIfTestCle Executor = _testMethodAttribute, }; - method.Invoke(null); + await method.InvokeAsync(null); Verify(disposeCalled); } - public void TestMethodInfoInvokeShouldCallTestCleanupEvenIfTestMethodThrows() + public async Task TestMethodInfoInvokeShouldCallTestCleanupEvenIfTestMethodThrows() { bool testCleanupMethodCalled = false; DummyTestClass.TestMethodBody = classInstance => throw new NotImplementedException(); DummyTestClass.TestCleanupMethodBody = classInstance => testCleanupMethodCalled = true; _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(testCleanupMethodCalled); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void TestMethodInfoInvokeShouldCallTestCleanupEvenIfTestInitializeMethodThrows() + public async Task TestMethodInfoInvokeShouldCallTestCleanupEvenIfTestInitializeMethodThrows() { bool testCleanupMethodCalled = false; DummyTestClass.TestInitializeMethodBody = classInstance => throw new NotImplementedException(); @@ -1065,13 +1067,13 @@ public void TestMethodInfoInvokeShouldCallTestCleanupEvenIfTestInitializeMethodT _testClassInfo.TestInitializeMethod = typeof(DummyTestClass).GetMethod("DummyTestInitializeMethod")!; _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(testCleanupMethodCalled); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void TestMethodInfoInvokeShouldCallTestCleanupIfTestClassInstanceIsNotNull() + public async Task TestMethodInfoInvokeShouldCallTestCleanupIfTestClassInstanceIsNotNull() { bool testCleanupMethodCalled = false; @@ -1079,25 +1081,25 @@ public void TestMethodInfoInvokeShouldCallTestCleanupIfTestClassInstanceIsNotNul DummyTestClass.TestConstructorMethodBody = () => throw new NotImplementedException(); DummyTestClass.TestCleanupMethodBody = classInstance => testCleanupMethodCalled = true; - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); Verify(!testCleanupMethodCalled); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void TestMethodInfoInvokeShouldNotCallTestCleanupIfClassSetContextThrows() + public async Task TestMethodInfoInvokeShouldNotCallTestCleanupIfClassSetContextThrows() { bool testCleanupCalled = false; DummyTestClass.TestCleanupMethodBody = classInstance => testCleanupCalled = true; DummyTestClass.TestContextSetterBody = o => throw new NotImplementedException(); _testClassInfo.TestCleanupMethod = typeof(DummyTestClass).GetMethod("DummyTestCleanupMethod")!; - _testMethodInfo.Invoke(null); + await _testMethodInfo.InvokeAsync(null); Verify(!testCleanupCalled); } - public void TestMethodInfoInvokeShouldSetResultAsPassedIfExpectedExceptionIsThrown() + public async Task TestMethodInfoInvokeShouldSetResultAsPassedIfExpectedExceptionIsThrown() { DummyTestClass.TestMethodBody = o => throw new DivideByZeroException(); var testMethodInfo = new TestMethodInfo(_methodInfo, _testClassInfo, _testContextImplementation) @@ -1107,12 +1109,12 @@ public void TestMethodInfoInvokeShouldSetResultAsPassedIfExpectedExceptionIsThro ExpectedException = _expectedException, }; - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeShouldSetResultAsFailedIfExceptionDifferentFromExpectedExceptionIsThrown() + public async Task TestMethodInfoInvokeShouldSetResultAsFailedIfExceptionDifferentFromExpectedExceptionIsThrown() { DummyTestClass.TestMethodBody = o => throw new IndexOutOfRangeException(); var testMethodInfo = new TestMethodInfo(_methodInfo, _testClassInfo, _testContextImplementation) @@ -1122,7 +1124,7 @@ public void TestMethodInfoInvokeShouldSetResultAsFailedIfExceptionDifferentFromE ExpectedException = _expectedException, }; - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); string message = "Test method threw exception System.IndexOutOfRangeException, but exception System.DivideByZeroException was expected. " + @@ -1130,7 +1132,7 @@ public void TestMethodInfoInvokeShouldSetResultAsFailedIfExceptionDifferentFromE Verify(message == result.TestFailureException!.Message); } - public void TestMethodInfoInvokeShouldSetResultAsFailedWhenExceptionIsExpectedButIsNotThrown() + public async Task TestMethodInfoInvokeShouldSetResultAsFailedWhenExceptionIsExpectedButIsNotThrown() { DummyTestClass.TestMethodBody = o => { }; var testMethodInfo = new TestMethodInfo(_methodInfo, _testClassInfo, _testContextImplementation) @@ -1139,31 +1141,31 @@ public void TestMethodInfoInvokeShouldSetResultAsFailedWhenExceptionIsExpectedBu Executor = _testMethodAttribute, ExpectedException = _expectedException, }; - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); string message = "Test method did not throw expected exception System.DivideByZeroException."; Verify(result.TestFailureException!.Message.Contains(message)); } - public void TestMethodInfoInvokeShouldSetResultAsInconclusiveWhenExceptionIsAssertInconclusiveException() + public async Task TestMethodInfoInvokeShouldSetResultAsInconclusiveWhenExceptionIsAssertInconclusiveException() { - DummyTestClass.TestMethodBody = o => throw new UTF.AssertInconclusiveException(); + DummyTestClass.TestMethodBody = o => throw new AssertInconclusiveException(); var testMethodInfo = new TestMethodInfo(_methodInfo, _testClassInfo, _testContextImplementation) { TimeoutInfo = TimeoutInfo.FromTimeout(3600 * 1000), Executor = _testMethodAttribute, ExpectedException = _expectedException, }; - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); string message = "Exception of type 'Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException' was thrown."; Verify(message == result.TestFailureException!.Message); } - public void TestMethodInfoInvokeShouldSetTestOutcomeBeforeTestCleanup() + public async Task TestMethodInfoInvokeShouldSetTestOutcomeBeforeTestCleanup() { UTF.UnitTestOutcome testOutcome = UTF.UnitTestOutcome.Unknown; - DummyTestClass.TestMethodBody = o => throw new UTF.AssertInconclusiveException(); + DummyTestClass.TestMethodBody = o => throw new AssertInconclusiveException(); DummyTestClass.TestCleanupMethodBody = c => { if (DummyTestClass.GetTestContext() != null) @@ -1179,12 +1181,12 @@ public void TestMethodInfoInvokeShouldSetTestOutcomeBeforeTestCleanup() ExpectedException = _expectedException, }; - UTF.TestResult result = testMethodInfo.Invoke(null); + TestResult result = await testMethodInfo.InvokeAsync(null); Verify(testOutcome == UTF.UnitTestOutcome.Inconclusive); } - public void HandleMethodExceptionShouldInvokeVerifyOfCustomExpectedException() + public async Task HandleMethodExceptionShouldInvokeVerifyOfCustomExpectedException() { CustomExpectedExceptionAttribute customExpectedException = new(typeof(DivideByZeroException), "Attempted to divide by zero"); var method = new TestMethodInfo( @@ -1198,12 +1200,12 @@ public void HandleMethodExceptionShouldInvokeVerifyOfCustomExpectedException() }; DummyTestClass.TestMethodBody = o => throw new DivideByZeroException(); - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(customExpectedException.IsVerifyInvoked); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void HandleMethodExceptionShouldSetOutcomeAsFailedIfVerifyOfExpectedExceptionThrows() + public async Task HandleMethodExceptionShouldSetOutcomeAsFailedIfVerifyOfExpectedExceptionThrows() { CustomExpectedExceptionAttribute customExpectedException = new(typeof(DivideByZeroException), "Custom Exception"); var method = new TestMethodInfo( @@ -1217,12 +1219,12 @@ public void HandleMethodExceptionShouldSetOutcomeAsFailedIfVerifyOfExpectedExcep }; DummyTestClass.TestMethodBody = o => throw new DivideByZeroException(); - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.TestFailureException!.Message == "The exception message doesn't contain the string defined in the exception attribute"); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void HandleMethodExceptionShouldSetOutcomeAsInconclusiveIfVerifyOfExpectedExceptionThrowsAssertInconclusiveException() + public async Task HandleMethodExceptionShouldSetOutcomeAsInconclusiveIfVerifyOfExpectedExceptionThrowsAssertInconclusiveException() { CustomExpectedExceptionAttribute customExpectedException = new(typeof(DivideByZeroException), "Custom Exception"); var method = new TestMethodInfo( @@ -1235,14 +1237,14 @@ public void HandleMethodExceptionShouldSetOutcomeAsInconclusiveIfVerifyOfExpecte ExpectedException = customExpectedException, }; - DummyTestClass.TestMethodBody = o => throw new UTF.AssertInconclusiveException(); - UTF.TestResult result = method.Invoke(null); + DummyTestClass.TestMethodBody = o => throw new AssertInconclusiveException(); + TestResult result = await method.InvokeAsync(null); string message = "Exception of type 'Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException' was thrown."; Verify(result.TestFailureException!.Message == message); Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); } - public void HandleMethodExceptionShouldInvokeVerifyOfDerivedCustomExpectedException() + public async Task HandleMethodExceptionShouldInvokeVerifyOfDerivedCustomExpectedException() { DerivedCustomExpectedExceptionAttribute derivedCustomExpectedException = new(typeof(DivideByZeroException), "Attempted to divide by zero"); var method = new TestMethodInfo( @@ -1256,14 +1258,14 @@ public void HandleMethodExceptionShouldInvokeVerifyOfDerivedCustomExpectedExcept }; DummyTestClass.TestMethodBody = o => throw new DivideByZeroException(); - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(derivedCustomExpectedException.IsVerifyInvoked); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void VerifyShouldNotThrowIfThrownExceptionCanBeAssignedToExpectedException() + public async Task VerifyShouldNotThrowIfThrownExceptionCanBeAssignedToExpectedException() { - UTF.ExpectedExceptionAttribute expectedException = new(typeof(Exception)) + ExpectedExceptionAttribute expectedException = new(typeof(Exception)) { AllowDerivedTypes = true, }; @@ -1278,13 +1280,13 @@ public void VerifyShouldNotThrowIfThrownExceptionCanBeAssignedToExpectedExceptio }; DummyTestClass.TestMethodBody = o => throw new DivideByZeroException(); - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void VerifyShouldThrowExceptionIfThrownExceptionCannotBeAssignedToExpectedException() + public async Task VerifyShouldThrowExceptionIfThrownExceptionCannotBeAssignedToExpectedException() { - UTF.ExpectedExceptionAttribute expectedException = new(typeof(DivideByZeroException), "Custom Exception") + ExpectedExceptionAttribute expectedException = new(typeof(DivideByZeroException), "Custom Exception") { AllowDerivedTypes = true, }; @@ -1299,16 +1301,16 @@ public void VerifyShouldThrowExceptionIfThrownExceptionCannotBeAssignedToExpecte }; DummyTestClass.TestMethodBody = o => throw new ArgumentNullException(); - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); string message = "Test method threw exception System.ArgumentNullException, but exception System.DivideByZeroException" + " or a type derived from it was expected. Exception message: System.ArgumentNullException: Value cannot be null."; Verify(result.TestFailureException!.Message == message); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void VerifyShouldRethrowExceptionIfThrownExceptionIsAssertFailedException() + public async Task VerifyShouldRethrowExceptionIfThrownExceptionIsAssertFailedException() { - UTF.ExpectedExceptionAttribute expectedException = new(typeof(DivideByZeroException)) + ExpectedExceptionAttribute expectedException = new(typeof(DivideByZeroException)) { AllowDerivedTypes = true, }; @@ -1322,16 +1324,16 @@ public void VerifyShouldRethrowExceptionIfThrownExceptionIsAssertFailedException ExpectedException = expectedException, }; - DummyTestClass.TestMethodBody = o => throw new UTF.AssertFailedException(); - UTF.TestResult result = method.Invoke(null); + DummyTestClass.TestMethodBody = o => throw new AssertFailedException(); + TestResult result = await method.InvokeAsync(null); string message = "Exception of type 'Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException' was thrown."; Verify(result.TestFailureException!.Message == message); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void VerifyShouldRethrowExceptionIfThrownExceptionIsAssertInconclusiveException() + public async Task VerifyShouldRethrowExceptionIfThrownExceptionIsAssertInconclusiveException() { - UTF.ExpectedExceptionAttribute expectedException = new(typeof(DivideByZeroException)) + ExpectedExceptionAttribute expectedException = new(typeof(DivideByZeroException)) { AllowDerivedTypes = true, }; @@ -1345,16 +1347,16 @@ public void VerifyShouldRethrowExceptionIfThrownExceptionIsAssertInconclusiveExc ExpectedException = expectedException, }; - DummyTestClass.TestMethodBody = o => throw new UTF.AssertInconclusiveException(); - UTF.TestResult result = method.Invoke(null); + DummyTestClass.TestMethodBody = o => throw new AssertInconclusiveException(); + TestResult result = await method.InvokeAsync(null); string message = "Exception of type 'Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException' was thrown."; Verify(result.TestFailureException!.Message == message); Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); } - public void VerifyShouldThrowIfThrownExceptionIsNotSameAsExpectedException() + public async Task VerifyShouldThrowIfThrownExceptionIsNotSameAsExpectedException() { - UTF.ExpectedExceptionAttribute expectedException = new(typeof(Exception)); + ExpectedExceptionAttribute expectedException = new(typeof(Exception)); var method = new TestMethodInfo( _methodInfo, _testClassInfo, @@ -1366,16 +1368,16 @@ public void VerifyShouldThrowIfThrownExceptionIsNotSameAsExpectedException() }; DummyTestClass.TestMethodBody = o => throw new DivideByZeroException(); - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); string message = "Test method threw exception System.DivideByZeroException, but exception System.Exception was expected. " + "Exception message: System.DivideByZeroException: Attempted to divide by zero."; Verify(result.TestFailureException!.Message == message); Verify(result.Outcome == UTF.UnitTestOutcome.Failed); } - public void VerifyShouldRethrowIfThrownExceptionIsAssertExceptionWhichIsNotSameAsExpectedException() + public async Task VerifyShouldRethrowIfThrownExceptionIsAssertExceptionWhichIsNotSameAsExpectedException() { - UTF.ExpectedExceptionAttribute expectedException = new(typeof(Exception)); + ExpectedExceptionAttribute expectedException = new(typeof(Exception)); var method = new TestMethodInfo( _methodInfo, _testClassInfo, @@ -1386,8 +1388,8 @@ public void VerifyShouldRethrowIfThrownExceptionIsAssertExceptionWhichIsNotSameA ExpectedException = expectedException, }; - DummyTestClass.TestMethodBody = o => throw new UTF.AssertInconclusiveException(); - UTF.TestResult result = method.Invoke(null); + DummyTestClass.TestMethodBody = o => throw new AssertInconclusiveException(); + TestResult result = await method.InvokeAsync(null); string message = "Exception of type 'Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException' was thrown."; Verify(result.TestFailureException!.Message == message); Verify(result.Outcome == UTF.UnitTestOutcome.Inconclusive); @@ -1398,9 +1400,9 @@ public void ResolveExpectedExceptionShouldThrowWhenAttributeIsDefinedTwice_Diffe MethodInfo testMethodInfo = typeof(DummyTestClassForExpectedException).GetMethod(nameof(DummyTestClassForExpectedException.DummyTestMethod1))!; TestClassInfo classInfo = new( typeof(DummyTestClassForExpectedException), - typeof(DummyTestClassForExpectedException).GetConstructor(Array.Empty())!, + typeof(DummyTestClassForExpectedException).GetConstructor([])!, isParameterlessConstructor: true, - new UTF.TestClassAttribute(), + new TestClassAttribute(), new TestAssemblyInfo(typeof(DummyTestClassForExpectedException).Assembly)); TypeInspectionException ex = UTF.Assert.ThrowsException(() => new TestMethodInfo(testMethodInfo, classInfo, _testContextImplementation) @@ -1416,9 +1418,9 @@ public void ResolveExpectedExceptionShouldThrowWhenAttributeIsDefinedTwice_SameC MethodInfo testMethodInfo = typeof(DummyTestClassForExpectedException).GetMethod(nameof(DummyTestClassForExpectedException.DummyTestMethod1))!; TestClassInfo classInfo = new( typeof(DummyTestClassForExpectedException), - typeof(DummyTestClassForExpectedException).GetConstructor(Array.Empty())!, + typeof(DummyTestClassForExpectedException).GetConstructor([])!, isParameterlessConstructor: true, - new UTF.TestClassAttribute(), + new TestClassAttribute(), new TestAssemblyInfo(typeof(DummyTestClassForExpectedException).Assembly)); TypeInspectionException ex = UTF.Assert.ThrowsException(() => new TestMethodInfo(testMethodInfo, classInfo, _testContextImplementation) @@ -1435,9 +1437,9 @@ public void ResolveExpectedExceptionHelperShouldReturnExpectedExceptionAttribute MethodInfo methodInfo = type.GetMethod(nameof(DummyTestClassForExpectedException.TestMethodWithExpectedException))!; TestClassInfo classInfo = new( typeof(DummyTestClassForExpectedException), - typeof(DummyTestClassForExpectedException).GetConstructor(Array.Empty())!, + typeof(DummyTestClassForExpectedException).GetConstructor([])!, isParameterlessConstructor: true, - new UTF.TestClassAttribute(), + new TestClassAttribute(), new TestAssemblyInfo(typeof(DummyTestClassForExpectedException).Assembly)); var testMethodInfo = new TestMethodInfo(methodInfo, classInfo, _testContextImplementation) @@ -1447,7 +1449,7 @@ public void ResolveExpectedExceptionHelperShouldReturnExpectedExceptionAttribute }; Verify(testMethodInfo.ExpectedException is not null); - Verify(((UTF.ExpectedExceptionAttribute)testMethodInfo.ExpectedException).ExceptionType == typeof(DivideByZeroException)); + Verify(((ExpectedExceptionAttribute)testMethodInfo.ExpectedException).ExceptionType == typeof(DivideByZeroException)); } public void ResolveExpectedExceptionHelperShouldReturnNullIfExpectedExceptionAttributeIsNotPresent() @@ -1456,9 +1458,9 @@ public void ResolveExpectedExceptionHelperShouldReturnNullIfExpectedExceptionAtt MethodInfo methodInfo = type.GetMethod(nameof(DummyTestClassForExpectedException.TestMethodWithoutExpectedException))!; TestClassInfo classInfo = new( typeof(DummyTestClassForExpectedException), - typeof(DummyTestClassForExpectedException).GetConstructor(Array.Empty())!, + typeof(DummyTestClassForExpectedException).GetConstructor([])!, isParameterlessConstructor: true, - new UTF.TestClassAttribute(), + new TestClassAttribute(), new TestAssemblyInfo(typeof(DummyTestClassForExpectedException).Assembly)); var testMethodInfo = new TestMethodInfo(methodInfo, classInfo, _testContextImplementation) @@ -1474,7 +1476,7 @@ public void ResolveExpectedExceptionHelperShouldReturnNullIfExpectedExceptionAtt #region TestMethod invoke setup order - public void TestMethodInfoInvokeShouldInitializeClassInstanceTestInitializeAndTestCleanupInOrder() + public async Task TestMethodInfoInvokeShouldInitializeClassInstanceTestInitializeAndTestCleanupInOrder() { var callOrder = new List(); _testClassInfo.TestInitializeMethod = typeof(DummyTestClass).GetMethod("DummyTestInitializeMethod")!; @@ -1486,7 +1488,7 @@ public void TestMethodInfoInvokeShouldInitializeClassInstanceTestInitializeAndTe DummyTestClass.TestMethodBody = classInstance => callOrder.Add("testMethodInfo"); DummyTestClass.TestCleanupMethodBody = classInstance => callOrder.Add("testCleanup"); - UTF.TestResult result = _testMethodInfo.Invoke(null); + TestResult result = await _testMethodInfo.InvokeAsync(null); var expectedCallOrder = new List { @@ -1504,11 +1506,11 @@ public void TestMethodInfoInvokeShouldInitializeClassInstanceTestInitializeAndTe #region TestMethod timeout scenarios - public void TestMethodInfoInvokeShouldReturnTestFailureOnTimeout() + public async Task TestMethodInfoInvokeShouldReturnTestFailureOnTimeout() { var testablePlatformServiceProvider = new TestablePlatformServiceProvider(); - RunWithTestablePlatformService(testablePlatformServiceProvider, () => + await RunWithTestablePlatformService(testablePlatformServiceProvider, async () => { testablePlatformServiceProvider.MockThreadOperations.CallBase = true; @@ -1522,14 +1524,14 @@ public void TestMethodInfoInvokeShouldReturnTestFailureOnTimeout() Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Timeout); Verify(result.TestFailureException!.Message.Equals("Test 'DummyTestMethod' timed out after 1ms", StringComparison.Ordinal)); }); } - public void TestMethodInfoInvokeShouldReturnTestPassedOnCompletionWithinTimeout() + public async Task TestMethodInfoInvokeShouldReturnTestPassedOnCompletionWithinTimeout() { DummyTestClass.TestMethodBody = o => { /* do nothing */ }; var method = new TestMethodInfo(_methodInfo, _testClassInfo, _testContextImplementation) @@ -1537,14 +1539,14 @@ public void TestMethodInfoInvokeShouldReturnTestPassedOnCompletionWithinTimeout( TimeoutInfo = TimeoutInfo.FromTimeout(3600 * 1000), Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Passed); } - public void TestMethodInfoInvokeShouldCancelTokenSourceOnTimeout() + public async Task TestMethodInfoInvokeShouldCancelTokenSourceOnTimeout() { var testablePlatformServiceProvider = new TestablePlatformServiceProvider(); - RunWithTestablePlatformService(testablePlatformServiceProvider, () => + await RunWithTestablePlatformService(testablePlatformServiceProvider, async () => { testablePlatformServiceProvider.MockThreadOperations.CallBase = true; PlatformServiceProvider.Instance = testablePlatformServiceProvider; @@ -1557,7 +1559,7 @@ public void TestMethodInfoInvokeShouldCancelTokenSourceOnTimeout() TimeoutInfo = TimeoutInfo.FromTimeout(1), Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Timeout); Verify(result.TestFailureException!.Message.Equals("Test 'DummyTestMethod' timed out after 1ms", StringComparison.Ordinal)); @@ -1565,10 +1567,10 @@ public void TestMethodInfoInvokeShouldCancelTokenSourceOnTimeout() }); } - public void TestMethodInfoInvokeShouldFailOnTokenSourceCancellation() + public async Task TestMethodInfoInvokeShouldFailOnTokenSourceCancellation() { var testablePlatformServiceProvider = new TestablePlatformServiceProvider(); - RunWithTestablePlatformService(testablePlatformServiceProvider, () => + await RunWithTestablePlatformService(testablePlatformServiceProvider, async () => { testablePlatformServiceProvider.MockThreadOperations.CallBase = true; PlatformServiceProvider.Instance = testablePlatformServiceProvider; @@ -1591,7 +1593,7 @@ public void TestMethodInfoInvokeShouldFailOnTokenSourceCancellation() TimeoutInfo = TimeoutInfo.FromTimeout(100000), Executor = _testMethodAttribute, }; - UTF.TestResult result = method.Invoke(null); + TestResult result = await method.InvokeAsync(null); Verify(result.Outcome == UTF.UnitTestOutcome.Timeout); Verify(result.TestFailureException!.Message.Equals("Test 'DummyTestMethod' was canceled", StringComparison.Ordinal)); @@ -1733,7 +1735,7 @@ public void ResolveArgumentsShouldReturnPopulatedParamsWithAllProvided() #region helper methods - private static void RunWithTestablePlatformService(TestablePlatformServiceProvider testablePlatformServiceProvider, Action action) + private static async Task RunWithTestablePlatformService(TestablePlatformServiceProvider testablePlatformServiceProvider, Func action) { try { @@ -1742,7 +1744,7 @@ private static void RunWithTestablePlatformService(TestablePlatformServiceProvid Returns(true). Callback((Action a, int timeout, CancellationToken token) => a.Invoke()); - action.Invoke(); + await action(); } finally { @@ -1762,11 +1764,11 @@ public class DummyTestClassBase public class DummyTestClass : DummyTestClassBase { - private static UTFExtension.TestContext s_tc = null!; + private static TestContext s_tc = null!; public DummyTestClass() => TestConstructorMethodBody(); - public DummyTestClass(UTFExtension.TestContext tc) => Verify(tc is not null); + public DummyTestClass(TestContext tc) => Verify(tc is not null); public static Action TestConstructorMethodBody { get; set; } = null!; @@ -1784,9 +1786,9 @@ public class DummyTestClass : DummyTestClassBase public static Func DummyAsyncTestMethodBody { get; set; } = null!; - public static UTFExtension.TestContext GetTestContext() => s_tc; + public static TestContext GetTestContext() => s_tc; - public UTFExtension.TestContext TestContext + public TestContext TestContext { get => throw new NotImplementedException(); @@ -1836,7 +1838,7 @@ public DummyTestClassWithParameterizedCtor(int x) public class DummyTestClassWithTestContextWithoutSetter { - public UTFExtension.TestContext TestContext { get; } = null!; + public TestContext TestContext => null!; } public class DummyTestClassWithDisposable : IDisposable @@ -1859,7 +1861,7 @@ public void DummyTestMethod() /// /// Custom Expected exception attribute which overrides the Verify method. /// - public class CustomExpectedExceptionAttribute : UTF.ExpectedExceptionBaseAttribute + public class CustomExpectedExceptionAttribute : ExpectedExceptionBaseAttribute { public CustomExpectedExceptionAttribute(Type exceptionType, string noExceptionMessage) : base(noExceptionMessage) => ExceptionType = exceptionType; @@ -1871,9 +1873,9 @@ public CustomExpectedExceptionAttribute(Type exceptionType, string noExceptionMe protected internal override void Verify(Exception exception) { IsVerifyInvoked = true; - if (exception is UTF.AssertInconclusiveException) + if (exception is AssertInconclusiveException) { - throw new UTF.AssertInconclusiveException(); + throw new AssertInconclusiveException(); } else if (!exception.Message.Contains(NoExceptionMessage)) { @@ -1897,9 +1899,9 @@ public DerivedCustomExpectedExceptionAttribute(Type exceptionType, string noExce protected internal override void Verify(Exception exception) { IsVerifyInvoked = true; - if (exception is UTF.AssertInconclusiveException) + if (exception is AssertInconclusiveException) { - throw new UTF.AssertInconclusiveException(); + throw new AssertInconclusiveException(); } else if (!exception.Message.Contains(NoExceptionMessage)) { @@ -1912,18 +1914,18 @@ protected internal override void Verify(Exception exception) public class DummyTestClassForExpectedException { - private class MyExpectedException1Attribute : UTF.ExpectedExceptionBaseAttribute + private class MyExpectedException1Attribute : ExpectedExceptionBaseAttribute { protected internal override void Verify(Exception exception) => throw new NotImplementedException(); } [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - public class MyExpectedException2Attribute : UTF.ExpectedExceptionBaseAttribute + public class MyExpectedException2Attribute : ExpectedExceptionBaseAttribute { protected internal override void Verify(Exception exception) => throw new NotImplementedException(); } - [UTF.ExpectedException(typeof(Exception))] + [ExpectedException(typeof(Exception))] [MyExpectedException1] public void DummyTestMethod1() @@ -1936,7 +1938,7 @@ public void DummyTestMethod2() { } - [UTF.ExpectedException(typeof(DivideByZeroException))] + [ExpectedException(typeof(DivideByZeroException))] public void TestMethodWithExpectedException() { } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestMethodRunnerTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodRunnerTests.cs similarity index 97% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TestMethodRunnerTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodRunnerTests.cs index edb63ea7ab..a6a3817026 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestMethodRunnerTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodRunnerTests.cs @@ -266,7 +266,7 @@ public async Task RunTestMethodShouldSetDataRowIndexForDataDrivenTestsWhenDataIs // Setup mocks _testablePlatformServiceProvider.MockReflectionOperations.Setup(rf => rf.GetCustomAttributes(methodInfo, It.IsAny())).Returns(attributes); - var testMethodInfo = new TestableTestMethodInfo(methodInfo, _testClassInfo, _testMethodOptions, () => new UTF.TestResult()); + var testMethodInfo = new TestableTestMethodInfo(methodInfo, _testClassInfo, _testMethodOptions, () => new TestResult()); var testMethodRunner = new TestMethodRunner(testMethodInfo, _testMethod, _testContextImplementation); _testablePlatformServiceProvider.MockTestDataSource.Setup(tds => tds.GetData(testMethodInfo, _testContextImplementation)).Returns([1, 2, 3]); @@ -293,7 +293,7 @@ public async Task RunTestMethodShouldRunOnlyDataSourceTestsWhenBothDataSourceAnd // Setup mocks _testablePlatformServiceProvider.MockReflectionOperations.Setup(rf => rf.GetCustomAttributes(_methodInfo, It.IsAny())).Returns(attributes); - var testMethodInfo = new TestableTestMethodInfo(_methodInfo, _testClassInfo, _testMethodOptions, () => new UTF.TestResult()); + var testMethodInfo = new TestableTestMethodInfo(_methodInfo, _testClassInfo, _testMethodOptions, () => new TestResult()); var testMethodRunner = new TestMethodRunner(testMethodInfo, _testMethod, _testContextImplementation); _testablePlatformServiceProvider.MockTestDataSource.Setup(tds => tds.GetData(testMethodInfo, _testContextImplementation)).Returns([1, 2, 3]); @@ -359,7 +359,7 @@ public async Task RunTestMethodShouldSetResultFilesIfPresentForDataDrivenTests() { TestResult testResult = new() { - ResultFiles = new List { "C:\\temp.txt" }, + ResultFiles = ["C:\\temp.txt"], }; int dummyIntData1 = 1; @@ -388,7 +388,7 @@ public async Task RunTestMethodWithEmptyDataSourceShouldNotFailBecauseConsiderEm private async Task RunTestMethodWithEmptyDataSourceShouldFailIfConsiderEmptyDataSourceAsInconclusiveIsNotTrueHelper(bool considerEmptyAsInconclusive) { - Mock? existingMock = _testablePlatformServiceProvider.MockReflectionOperations; + Mock? existingMock = _testablePlatformServiceProvider.MockReflectionOperations; try { // We want this test to go through the "real" reflection to hit the product code path relevant for the test. @@ -459,7 +459,7 @@ private class TestableTestMethodInfo : TestMethodInfo { private readonly Func _invokeTest; - internal TestableTestMethodInfo(MethodInfo testMethod, TestClassInfo parent, TestMethodOptions testMethodOptions, Func invoke) + internal TestableTestMethodInfo(MethodInfo testMethod, TestClassInfo parent, TestMethodOptions testMethodOptions, Func invoke) : base(testMethod, parent, testMethodOptions.TestContext) { TimeoutInfo = testMethodOptions.TimeoutInfo; @@ -532,12 +532,12 @@ public DummyTestClassWithParameterizedCtor(int x) public class DummyTestClassWithTestContextWithoutSetter { - public TestContext TestContext { get; } = null!; + public TestContext TestContext => null!; } public class DummyTestClassEmptyDataSource { - public static IEnumerable EmptyProperty => Array.Empty(); + public static IEnumerable EmptyProperty => []; [DynamicData("EmptyProperty")] public void TestMethod(int x) diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestPropertyAttributeTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestPropertyAttributeTests.cs similarity index 93% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TestPropertyAttributeTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestPropertyAttributeTests.cs index a61975dfb5..a2c6b1aafe 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TestPropertyAttributeTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestPropertyAttributeTests.cs @@ -60,7 +60,7 @@ public void GetTestMethodInfoShouldAddPropertiesFromContainingClassCorrectly() Assert.IsTrue(testContext.TryGetPropertyValue("DummyTestClassBaseKey2", out object? value3)); Assert.AreEqual("DummyTestClassBaseValue2", value3); - TestPlatform.ObjectModel.Trait[] traits = ReflectHelper.Instance.GetTestPropertiesAsTraits(typeof(DummyTestClassBase).GetMethod(nameof(DummyTestClassBase.VirtualTestMethodInBaseAndDerived))!).ToArray(); + TestPlatform.ObjectModel.Trait[] traits = [.. ReflectHelper.Instance.GetTestPropertiesAsTraits(typeof(DummyTestClassBase).GetMethod(nameof(DummyTestClassBase.VirtualTestMethodInBaseAndDerived))!)]; Assert.AreEqual(3, traits.Length); Assert.AreEqual("TestMethodKeyFromBase", traits[0].Name); Assert.AreEqual("TestMethodValueFromBase", traits[0].Value); @@ -99,7 +99,7 @@ public void GetTestMethodInfoShouldAddPropertiesFromContainingClassAndBaseClasse Assert.IsTrue(testContext.TryGetPropertyValue("DummyTestClassBaseKey2", out object? value6)); Assert.AreEqual("DummyTestClassBaseValue2", value6); - TestPlatform.ObjectModel.Trait[] traits = ReflectHelper.Instance.GetTestPropertiesAsTraits(typeof(DummyTestClassDerived).GetMethod(nameof(DummyTestClassDerived.VirtualTestMethodInBaseAndDerived))!).ToArray(); + TestPlatform.ObjectModel.Trait[] traits = [.. ReflectHelper.Instance.GetTestPropertiesAsTraits(typeof(DummyTestClassDerived).GetMethod(nameof(DummyTestClassDerived.VirtualTestMethodInBaseAndDerived))!)]; Assert.AreEqual(6, traits.Length); Assert.AreEqual("DerivedMethod1Key", traits[0].Name); Assert.AreEqual("DerivedMethod1Value", traits[0].Value); @@ -144,7 +144,7 @@ public void GetTestMethodInfoShouldAddPropertiesFromContainingClassAndBaseClasse Assert.IsTrue(testContext.TryGetPropertyValue("DummyTestClassBaseKey2", out object? value6)); Assert.AreEqual("DummyTestClassBaseValue2", value6); - TestPlatform.ObjectModel.Trait[] traits = ReflectHelper.Instance.GetTestPropertiesAsTraits(typeof(DummyTestClassDerived).GetMethod(nameof(DummyTestClassDerived.VirtualTestMethodInDerivedButNotTestMethodInBase))!).ToArray(); + TestPlatform.ObjectModel.Trait[] traits = [.. ReflectHelper.Instance.GetTestPropertiesAsTraits(typeof(DummyTestClassDerived).GetMethod(nameof(DummyTestClassDerived.VirtualTestMethodInDerivedButNotTestMethodInBase))!)]; Assert.AreEqual(6, traits.Length); Assert.AreEqual("DerivedMethod2Key", traits[0].Name); Assert.AreEqual("DerivedMethod2Value", traits[0].Value); diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TypeCacheTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TypeCacheTests.cs similarity index 80% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/TypeCacheTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TypeCacheTests.cs index a1348ff357..4b3a1cd12b 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TypeCacheTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TypeCacheTests.cs @@ -152,7 +152,7 @@ public void GetTestMethodInfoShouldSetTestContextIfPresent() var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( testMethod, @@ -169,7 +169,7 @@ public void GetTestMethodInfoShouldSetTestContextToNullIfNotPresent() var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( testMethod, @@ -188,7 +188,7 @@ public void GetTestMethodInfoShouldAddAssemblyInfoToTheCache() var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -204,10 +204,10 @@ public void GetTestMethodInfoShouldNotThrowIfWeFailToDiscoverTypeFromAnAssembly( var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(It.IsAny(), true)).Throws(new Exception()); + rh => rh.IsAttributeDefined(It.IsAny(), true)).Throws(new Exception()); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(typeof(DummyTestClassWithTestMethods), true)).Returns(true); + rh => rh.IsAttributeDefined(typeof(DummyTestClassWithTestMethods), true)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -222,10 +222,10 @@ public void GetTestMethodInfoShouldCacheAssemblyInitializeAttribute() var testMethod = new TestMethod("TestInit", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -241,10 +241,10 @@ public void GetTestMethodInfoShouldCacheAssemblyCleanupAttribute() var testMethod = new TestMethod("TestCleanup", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -260,12 +260,12 @@ public void GetTestMethodInfoShouldCacheAssemblyInitAndCleanupAttribute() var testMethod = new TestMethod("TestInitOrCleanup", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -282,10 +282,10 @@ public void GetTestMethodInfoShouldThrowIfAssemblyInitHasIncorrectSignature() var testMethod = new TestMethod("M", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); void A() => _typeCache.GetTestMethodInfo( @@ -311,10 +311,10 @@ public void GetTestMethodInfoShouldThrowIfAssemblyCleanupHasIncorrectSignature() var testMethod = new TestMethod("M", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); void A() => _typeCache.GetTestMethodInfo( @@ -341,7 +341,7 @@ public void GetTestMethodInfoShouldCacheAssemblyInfoInstanceAndReuseTheCache() var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -351,7 +351,7 @@ public void GetTestMethodInfoShouldCacheAssemblyInfoInstanceAndReuseTheCache() testMethod, new TestContextImplementation(testMethod, new ThreadSafeStringWriter(null!, "test"), new Dictionary())); - _mockReflectHelper.Verify(rh => rh.IsDerivedAttributeDefined(type, false), Times.Once); + _mockReflectHelper.Verify(rh => rh.IsAttributeDefined(type, false), Times.Once); Verify(_typeCache.AssemblyInfoCache.Count == 1); } @@ -366,7 +366,7 @@ public void GetTestMethodInfoShouldAddClassInfoToTheCache() var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -383,10 +383,10 @@ public void GetTestMethodInfoShouldCacheClassInitializeAttribute() var testMethod = new TestMethod("TestInit", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -405,16 +405,16 @@ public void GetTestMethodInfoShouldCacheBaseClassInitializeAttributes() var testMethod = new TestMethod("TestMethod", type.FullName!, "A", false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(baseType.GetMethod("AssemblyInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(baseType.GetMethod("AssemblyInit")!, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.GetFirstDerivedAttributeOrDefault(baseType.GetMethod("AssemblyInit")!, true)) + rh => rh.GetFirstAttributeOrDefault(baseType.GetMethod("AssemblyInit")!, true)) .Returns(new ClassInitializeAttribute(InheritanceBehavior.BeforeEachDerivedClass)); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("ClassInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("ClassInit")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -431,10 +431,10 @@ public void GetTestMethodInfoShouldCacheClassCleanupAttribute() var testMethod = new TestMethod("TestCleanup", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -452,11 +452,11 @@ public void GetTestMethodInfoShouldCacheBaseClassCleanupAttributes() var testMethod = new TestMethod("TestMethod", type.FullName!, "A", false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(baseType.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(baseType.GetMethod("AssemblyCleanup")!, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.GetFirstDerivedAttributeOrDefault(baseType.GetMethod("AssemblyCleanup")!, true)) + rh => rh.GetFirstAttributeOrDefault(baseType.GetMethod("AssemblyCleanup")!, true)) .Returns(new ClassCleanupAttribute(InheritanceBehavior.BeforeEachDerivedClass)); _typeCache.GetTestMethodInfo( @@ -474,11 +474,11 @@ public void GetTestMethodInfoShouldCacheClassInitAndCleanupAttribute() var testMethod = new TestMethod("TestInitOrCleanup", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -499,23 +499,23 @@ public void GetTestMethodInfoShouldCacheBaseClassInitAndCleanupAttributes() MethodInfo baseCleanupMethod = baseType.GetMethod("ClassCleanup")!; _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(baseInitializeMethod, false)).Returns(true); + rh => rh.IsAttributeDefined(baseInitializeMethod, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.GetFirstDerivedAttributeOrDefault(baseInitializeMethod, true)) + rh => rh.GetFirstAttributeOrDefault(baseInitializeMethod, true)) .Returns(new ClassInitializeAttribute(InheritanceBehavior.BeforeEachDerivedClass)); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(baseCleanupMethod, false)).Returns(true); + rh => rh.IsAttributeDefined(baseCleanupMethod, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.GetFirstDerivedAttributeOrDefault(baseCleanupMethod, true)) + rh => rh.GetFirstAttributeOrDefault(baseCleanupMethod, true)) .Returns(new ClassCleanupAttribute(InheritanceBehavior.BeforeEachDerivedClass)); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -541,35 +541,35 @@ public void GetTestMethodInfoShouldCacheParentAndGrandparentClassInitAndCleanupA MethodInfo parentCleanupMethod = parentType.GetMethod("ChildClassCleanup")!; _mockReflectHelper - .Setup(rh => rh.IsNonDerivedAttributeDefined(type, true)) + .Setup(rh => rh.IsAttributeDefined(type, true)) .Returns(true); // Setup grandparent class init/cleanup methods _mockReflectHelper - .Setup(rh => rh.IsNonDerivedAttributeDefined(grandparentInitMethod, false)) + .Setup(rh => rh.IsAttributeDefined(grandparentInitMethod, false)) .Returns(true); _mockReflectHelper - .Setup(rh => rh.GetFirstDerivedAttributeOrDefault(grandparentInitMethod, true)) + .Setup(rh => rh.GetFirstAttributeOrDefault(grandparentInitMethod, true)) .Returns(new ClassInitializeAttribute(InheritanceBehavior.BeforeEachDerivedClass)); _mockReflectHelper - .Setup(rh => rh.IsNonDerivedAttributeDefined(grandparentCleanupMethod, false)) + .Setup(rh => rh.IsAttributeDefined(grandparentCleanupMethod, false)) .Returns(true); _mockReflectHelper - .Setup(rh => rh.GetFirstDerivedAttributeOrDefault(grandparentCleanupMethod, true)) + .Setup(rh => rh.GetFirstAttributeOrDefault(grandparentCleanupMethod, true)) .Returns(new ClassCleanupAttribute(InheritanceBehavior.BeforeEachDerivedClass)); // Setup parent class init/cleanup methods _mockReflectHelper - .Setup(rh => rh.IsNonDerivedAttributeDefined(parentInitMethod, false)) + .Setup(rh => rh.IsAttributeDefined(parentInitMethod, false)) .Returns(true); _mockReflectHelper - .Setup(rh => rh.GetFirstDerivedAttributeOrDefault(parentInitMethod, true)) + .Setup(rh => rh.GetFirstAttributeOrDefault(parentInitMethod, true)) .Returns(new ClassInitializeAttribute(InheritanceBehavior.BeforeEachDerivedClass)); _mockReflectHelper - .Setup(rh => rh.IsNonDerivedAttributeDefined(parentCleanupMethod, false)) + .Setup(rh => rh.IsAttributeDefined(parentCleanupMethod, false)) .Returns(true); _mockReflectHelper - .Setup(rh => rh.GetFirstDerivedAttributeOrDefault(parentCleanupMethod, true)) + .Setup(rh => rh.GetFirstAttributeOrDefault(parentCleanupMethod, true)) .Returns(new ClassCleanupAttribute(InheritanceBehavior.BeforeEachDerivedClass)); var testMethod = new TestMethod("TestMethod", type.FullName!, "A", isAsync: false); @@ -597,10 +597,10 @@ public void GetTestMethodInfoShouldThrowIfClassInitHasIncorrectSignature() var testMethod = new TestMethod("M", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyInit")!, false)).Returns(true); void A() => _typeCache.GetTestMethodInfo( @@ -626,10 +626,10 @@ public void GetTestMethodInfoShouldThrowIfClassCleanupHasIncorrectSignature() var testMethod = new TestMethod("M", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); void A() => _typeCache.GetTestMethodInfo( @@ -655,10 +655,10 @@ public void GetTestMethodInfoShouldCacheTestInitializeAttribute() var testMethod = new TestMethod("TestInit", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("TestInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("TestInit")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -674,10 +674,10 @@ public void GetTestMethodInfoShouldCacheTestCleanupAttribute() var testMethod = new TestMethod("TestCleanup", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("TestCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("TestCleanup")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -693,10 +693,10 @@ public void GetTestMethodInfoShouldThrowIfTestInitOrCleanupHasIncorrectSignature var testMethod = new TestMethod("M", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("TestInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("TestInit")!, false)).Returns(true); void A() => _typeCache.GetTestMethodInfo( @@ -723,10 +723,10 @@ public void GetTestMethodInfoShouldCacheTestInitializeAttributeDefinedInBaseClas var testMethod = new TestMethod("TestMethod", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(baseType.GetMethod("TestInit")!, false)).Returns(true); + rh => rh.IsAttributeDefined(baseType.GetMethod("TestInit")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -743,10 +743,10 @@ public void GetTestMethodInfoShouldCacheTestCleanupAttributeDefinedInBaseClass() var testMethod = new TestMethod("TestMethod", type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(baseType.GetMethod("TestCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(baseType.GetMethod("TestCleanup")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -763,7 +763,7 @@ public void GetTestMethodInfoShouldCacheClassInfoInstanceAndReuseFromCache() var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -809,12 +809,12 @@ public void GetTestMethodInfoShouldReturnTestMethodInfo() MethodInfo methodInfo = type.GetMethod("TestMethod")!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); - _mockReflectHelper.Setup(rh => rh.GetFirstDerivedAttributeOrDefault(It.IsAny(), false)).CallBase(); + _mockReflectHelper.Setup(rh => rh.GetFirstAttributeOrDefault(It.IsAny(), false)).CallBase(); TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( testMethod, new TestContextImplementation(testMethod, new ThreadSafeStringWriter(null!, "test"), new Dictionary())); - Verify(methodInfo == testMethodInfo!.TestMethod); + Verify(methodInfo == testMethodInfo!.MethodInfo); Verify(testMethodInfo.TimeoutInfo.Timeout == 0); Verify(_typeCache.ClassInfoCache.First() == testMethodInfo.Parent); Verify(testMethodInfo.Executor is not null); @@ -826,15 +826,15 @@ public void GetTestMethodInfoShouldReturnTestMethodInfoWithTimeout() MethodInfo methodInfo = type.GetMethod("TestMethodWithTimeout")!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); - _mockReflectHelper.Setup(rh => rh.IsNonDerivedAttributeDefined(methodInfo, false)) + _mockReflectHelper.Setup(rh => rh.IsAttributeDefined(methodInfo, false)) .Returns(true); - _mockReflectHelper.Setup(rh => rh.GetFirstDerivedAttributeOrDefault(It.IsAny(), false)).CallBase(); - _mockReflectHelper.Setup(rh => rh.GetFirstNonDerivedAttributeOrDefault(methodInfo, false)).CallBase(); + _mockReflectHelper.Setup(rh => rh.GetFirstAttributeOrDefault(It.IsAny(), false)).CallBase(); + _mockReflectHelper.Setup(rh => rh.GetFirstAttributeOrDefault(methodInfo, false)).CallBase(); TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( testMethod, new TestContextImplementation(testMethod, new ThreadSafeStringWriter(null!, "test"), new Dictionary())); - Verify(methodInfo == testMethodInfo!.TestMethod); + Verify(methodInfo == testMethodInfo!.MethodInfo); Verify(testMethodInfo.TimeoutInfo.Timeout == 10); Verify(_typeCache.ClassInfoCache.First() == testMethodInfo.Parent); Verify(testMethodInfo.Executor is not null); @@ -846,9 +846,9 @@ public void GetTestMethodInfoShouldThrowWhenTimeoutIsNegative() MethodInfo methodInfo = type.GetMethod("TestMethodWithNegativeTimeout")!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); - _mockReflectHelper.Setup(rh => rh.IsNonDerivedAttributeDefined(methodInfo, false)) + _mockReflectHelper.Setup(rh => rh.IsAttributeDefined(methodInfo, false)) .Returns(true); - _mockReflectHelper.Setup(ReflectHelper => ReflectHelper.GetFirstNonDerivedAttributeOrDefault(methodInfo, false)) + _mockReflectHelper.Setup(ReflectHelper => ReflectHelper.GetFirstAttributeOrDefault(methodInfo, false)) .CallBase(); void A() => _typeCache.GetTestMethodInfo( @@ -873,9 +873,9 @@ public void GetTestMethodInfoShouldThrowWhenTimeoutIsZero() MethodInfo methodInfo = type.GetMethod("TestMethodWithTimeoutOfZero")!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); - _mockReflectHelper.Setup(rh => rh.IsNonDerivedAttributeDefined(methodInfo, false)) + _mockReflectHelper.Setup(rh => rh.IsAttributeDefined(methodInfo, false)) .Returns(true); - _mockReflectHelper.Setup(ReflectHelper => ReflectHelper.GetFirstNonDerivedAttributeOrDefault(methodInfo, false)) + _mockReflectHelper.Setup(ReflectHelper => ReflectHelper.GetFirstAttributeOrDefault(methodInfo, false)) .CallBase(); void A() => _typeCache.GetTestMethodInfo( @@ -935,9 +935,9 @@ public void GetTestMethodInfoWhenTimeoutAttributeSetShouldReturnTimeoutBasedOnAt MethodInfo methodInfo = type.GetMethod("TestMethodWithTimeout")!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); - _mockReflectHelper.Setup(rh => rh.IsNonDerivedAttributeDefined(methodInfo, false)) + _mockReflectHelper.Setup(rh => rh.IsAttributeDefined(methodInfo, false)) .Returns(true); - _mockReflectHelper.Setup(ReflectHelper => ReflectHelper.GetFirstNonDerivedAttributeOrDefault(methodInfo, false)) + _mockReflectHelper.Setup(ReflectHelper => ReflectHelper.GetFirstAttributeOrDefault(methodInfo, false)) .CallBase(); TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( @@ -977,12 +977,12 @@ public void GetTestMethodInfoShouldReturnTestMethodInfoForMethodsAdornedWithADer MethodInfo methodInfo = type.GetMethod("TestMethodWithDerivedTestMethodAttribute")!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); - _mockReflectHelper.Setup(rh => rh.GetFirstDerivedAttributeOrDefault(It.IsAny(), false)).CallBase(); + _mockReflectHelper.Setup(rh => rh.GetFirstAttributeOrDefault(It.IsAny(), false)).CallBase(); TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( testMethod, new TestContextImplementation(testMethod, new ThreadSafeStringWriter(null!, "test"), new Dictionary())); - Verify(methodInfo == testMethodInfo!.TestMethod); + Verify(methodInfo == testMethodInfo!.MethodInfo); Verify(testMethodInfo.TimeoutInfo.Timeout == 0); Verify(_typeCache.ClassInfoCache.First() == testMethodInfo.Parent); Verify(testMethodInfo.Executor is not null); @@ -1015,6 +1015,30 @@ public void GetTestMethodInfoShouldReportWarningIfCustomPropertyHasSameNameAsPre // Setting up the mock feels unnecessary when the original production implementation can work just fine. var typeCache = new TypeCache(new ReflectHelper()); Type type = typeof(DummyTestClassWithTestMethods); + MethodInfo methodInfo = type.GetMethod("TestMethodWithTestCategoryAsCustomProperty")!; + var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); + var testContext = new TestContextImplementation( + testMethod, + new ThreadSafeStringWriter(null!, "test"), + new Dictionary()); + + TestMethodInfo? testMethodInfo = typeCache.GetTestMethodInfo(testMethod, testContext); + + Verify(testMethodInfo is not null); + string expectedMessage = string.Format( + CultureInfo.InvariantCulture, + "UTA023: {0}: Cannot define predefined property {2} on method {1}.", + methodInfo.DeclaringType!.FullName!, + methodInfo.Name, + "TestCategory"); + Verify(expectedMessage == testMethodInfo.NotRunnableReason); + } + + public void GetTestMethodInfoShouldReportWarningIfCustomOwnerPropertyIsDefined() + { + // Test that [TestProperty("Owner", "value")] is still blocked + var typeCache = new TypeCache(new ReflectHelper()); + Type type = typeof(DummyTestClassWithTestMethods); MethodInfo methodInfo = type.GetMethod("TestMethodWithOwnerAsCustomProperty")!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); var testContext = new TestContextImplementation( @@ -1034,6 +1058,74 @@ public void GetTestMethodInfoShouldReportWarningIfCustomPropertyHasSameNameAsPre Verify(expectedMessage == testMethodInfo.NotRunnableReason); } + public void GetTestMethodInfoShouldReportWarningIfCustomPriorityPropertyIsDefined() + { + // Test that [TestProperty("Priority", "value")] is still blocked + var typeCache = new TypeCache(new ReflectHelper()); + Type type = typeof(DummyTestClassWithTestMethods); + MethodInfo methodInfo = type.GetMethod("TestMethodWithPriorityAsCustomProperty")!; + var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); + var testContext = new TestContextImplementation( + testMethod, + new ThreadSafeStringWriter(null!, "test"), + new Dictionary()); + + TestMethodInfo? testMethodInfo = typeCache.GetTestMethodInfo(testMethod, testContext); + + Verify(testMethodInfo is not null); + string expectedMessage = string.Format( + CultureInfo.InvariantCulture, + "UTA023: {0}: Cannot define predefined property {2} on method {1}.", + methodInfo.DeclaringType!.FullName!, + methodInfo.Name, + "Priority"); + Verify(expectedMessage == testMethodInfo.NotRunnableReason); + } + + public void GetTestMethodInfoShouldAllowActualOwnerAttribute() + { + // Test that the actual OwnerAttribute is allowed + var typeCache = new TypeCache(new ReflectHelper()); + Type type = typeof(DummyTestClassWithTestMethods); + MethodInfo methodInfo = type.GetMethod("TestMethodWithActualOwnerAttribute")!; + var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); + var testContext = new TestContextImplementation( + testMethod, + new ThreadSafeStringWriter(null!, "test"), + new Dictionary()); + + TestMethodInfo? testMethodInfo = typeCache.GetTestMethodInfo(testMethod, testContext); + + Verify(testMethodInfo is not null); + // Owner should be allowed - no NotRunnableReason should be set + Verify(string.IsNullOrEmpty(testMethodInfo.NotRunnableReason)); + // The Owner property should be added to the test context + Verify(testContext.TryGetPropertyValue("Owner", out object? ownerValue)); + Verify(ownerValue?.ToString() == "TestOwner"); + } + + public void GetTestMethodInfoShouldAllowActualPriorityAttribute() + { + // Test that the actual PriorityAttribute is allowed + var typeCache = new TypeCache(new ReflectHelper()); + Type type = typeof(DummyTestClassWithTestMethods); + MethodInfo methodInfo = type.GetMethod("TestMethodWithActualPriorityAttribute")!; + var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); + var testContext = new TestContextImplementation( + testMethod, + new ThreadSafeStringWriter(null!, "test"), + new Dictionary()); + + TestMethodInfo? testMethodInfo = typeCache.GetTestMethodInfo(testMethod, testContext); + + Verify(testMethodInfo is not null); + // Priority should be allowed - no NotRunnableReason should be set + Verify(string.IsNullOrEmpty(testMethodInfo.NotRunnableReason)); + // The Priority property should be added to the test context + Verify(testContext.TryGetPropertyValue("Priority", out object? priorityValue)); + Verify(priorityValue?.ToString() == "1"); + } + public void GetTestMethodInfoShouldReportWarningIfCustomPropertyNameIsEmpty() { // Not using _typeCache here which uses a mocked ReflectHelper which doesn't work well with this test. @@ -1110,12 +1202,12 @@ public void GetTestMethodInfoShouldReturnTestMethodInfoForDerivedTestClasses() MethodInfo methodInfo = type.GetRuntimeMethod("DummyTestMethod", [])!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); - _mockReflectHelper.Setup(rh => rh.GetFirstDerivedAttributeOrDefault(It.IsAny(), false)).CallBase(); + _mockReflectHelper.Setup(rh => rh.GetFirstAttributeOrDefault(It.IsAny(), false)).CallBase(); TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( testMethod, new TestContextImplementation(testMethod, new ThreadSafeStringWriter(null!, "test"), new Dictionary())); - Verify(methodInfo == testMethodInfo!.TestMethod); + Verify(methodInfo == testMethodInfo!.MethodInfo); Verify(testMethodInfo.TimeoutInfo.Timeout == 0); Verify(_typeCache.ClassInfoCache.First() == testMethodInfo.Parent); Verify(testMethodInfo.Executor is not null); @@ -1127,12 +1219,12 @@ public void GetTestMethodInfoShouldReturnTestMethodInfoForDerivedClassMethodOver MethodInfo methodInfo = type.GetRuntimeMethod("OverloadedTestMethod", [])!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); - _mockReflectHelper.Setup(rh => rh.GetFirstDerivedAttributeOrDefault(It.IsAny(), false)).CallBase(); + _mockReflectHelper.Setup(rh => rh.GetFirstAttributeOrDefault(It.IsAny(), false)).CallBase(); TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( testMethod, new TestContextImplementation(testMethod, new ThreadSafeStringWriter(null!, "test"), new Dictionary())); - Verify(methodInfo == testMethodInfo!.TestMethod); + Verify(methodInfo == testMethodInfo!.MethodInfo); Verify(testMethodInfo.TimeoutInfo.Timeout == 0); Verify(_typeCache.ClassInfoCache.First() == testMethodInfo.Parent); Verify(testMethodInfo.Executor is not null); @@ -1148,14 +1240,14 @@ public void GetTestMethodInfoShouldReturnTestMethodInfoForDeclaringTypeMethodOve DeclaringClassFullName = baseType.FullName!, }; - _mockReflectHelper.Setup(rh => rh.GetFirstDerivedAttributeOrDefault(It.IsAny(), false)).CallBase(); + _mockReflectHelper.Setup(rh => rh.GetFirstAttributeOrDefault(It.IsAny(), false)).CallBase(); TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo( testMethod, new TestContextImplementation(testMethod, new ThreadSafeStringWriter(null!, "test"), new Dictionary())); // The two MethodInfo instances will have different ReflectedType properties, // so cannot be compared directly. Use MethodHandle to verify it's the same. - Verify(methodInfo.MethodHandle == testMethodInfo!.TestMethod.MethodHandle); + Verify(methodInfo.MethodHandle == testMethodInfo!.MethodInfo.MethodHandle); Verify(testMethodInfo.TimeoutInfo.Timeout == 0); Verify(_typeCache.ClassInfoCache.First() == testMethodInfo.Parent); Verify(testMethodInfo.Executor is not null); @@ -1181,10 +1273,10 @@ public void ClassInfoListWithExecutableCleanupMethodsShouldReturnEmptyListWhenCl var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("TestCleanup")!, false)).Returns(false); + rh => rh.IsAttributeDefined(type.GetMethod("TestCleanup")!, false)).Returns(false); _typeCache.GetTestMethodInfo( testMethod, @@ -1202,10 +1294,10 @@ public void ClassInfoListWithExecutableCleanupMethodsShouldReturnClassInfosWithE var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type, true)).Returns(true); + rh => rh.IsAttributeDefined(type, true)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -1235,10 +1327,10 @@ public void AssemblyInfoListWithExecutableCleanupMethodsShouldReturnEmptyListWhe var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(false); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(false); _typeCache.GetTestMethodInfo( testMethod, @@ -1256,10 +1348,10 @@ public void AssemblyInfoListWithExecutableCleanupMethodsShouldReturnAssemblyInfo var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); _mockReflectHelper.Setup( - rh => rh.IsDerivedAttributeDefined(type, false)).Returns(true); + rh => rh.IsAttributeDefined(type, false)).Returns(true); _mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyCleanup")!, false)).Returns(true); _typeCache.GetTestMethodInfo( testMethod, @@ -1281,7 +1373,7 @@ public void ResolveExpectedExceptionHelperShouldThrowIfMultipleExpectedException MethodInfo methodInfo = type.GetMethod("TestMethodWithMultipleExpectedException")!; var testMethod = new TestMethod(methodInfo.Name, type.FullName!, "A", isAsync: false); - _mockReflectHelper.Setup(rh => rh.IsNonDerivedAttributeDefined(methodInfo, false)) + _mockReflectHelper.Setup(rh => rh.IsAttributeDefined(methodInfo, false)) .Returns(true); try @@ -1350,6 +1442,30 @@ public void TestMethodWithOwnerAsCustomProperty() { } + [TestMethod] + [TestProperty("TestCategory", "SomeCategory")] + public void TestMethodWithTestCategoryAsCustomProperty() + { + } + + [TestMethod] + [Owner("TestOwner")] + public void TestMethodWithActualOwnerAttribute() + { + } + + [TestMethod] + [Priority(1)] + public void TestMethodWithActualPriorityAttribute() + { + } + + [TestMethod] + [TestProperty("Priority", "2")] + public void TestMethodWithPriorityAsCustomProperty() + { + } + [TestMethod] [TestProperty("", "You")] public void TestMethodWithEmptyCustomPropertyName() diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/UnitTestResultTest.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/UnitTestResultTest.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/UnitTestResultTest.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/UnitTestResultTest.cs diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/UnitTestRunnerTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/UnitTestRunnerTests.cs similarity index 98% rename from test/UnitTests/MSTestAdapter.UnitTests/Execution/UnitTestRunnerTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/UnitTestRunnerTests.cs index 380c69c3fd..fec3b90852 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/UnitTestRunnerTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/UnitTestRunnerTests.cs @@ -31,7 +31,7 @@ public UnitTestRunnerTests() _mockMessageLogger = new Mock(); PlatformServiceProvider.Instance = _testablePlatformServiceProvider; - _unitTestRunner = new UnitTestRunner(GetSettingsWithDebugTrace(false)!, Array.Empty(), null); + _unitTestRunner = new UnitTestRunner(GetSettingsWithDebugTrace(false)!, [], null); } protected override void Dispose(bool disposing) @@ -65,7 +65,7 @@ public void ConstructorShouldPopulateSettings() }); MSTestSettings adapterSettings = MSTestSettings.GetSettings(runSettingsXml, MSTestSettings.SettingsName, _mockMessageLogger.Object)!; - var assemblyEnumerator = new UnitTestRunner(adapterSettings, Array.Empty(), null); + var assemblyEnumerator = new UnitTestRunner(adapterSettings, [], null); Verify(MSTestSettings.CurrentSettings.ForcedLegacyMode); Verify(MSTestSettings.CurrentSettings.TestSettingsFile == "DummyPath\\TestSettings1.testsettings"); @@ -283,7 +283,7 @@ public async Task RunSingleTestShouldSetTestsAsInProgressInTestContext() public async Task RunSingleTestShouldCallAssemblyInitializeAndClassInitializeMethodsInOrder() { var mockReflectHelper = new Mock(); - _unitTestRunner = new UnitTestRunner(new MSTestSettings(), Array.Empty(), null, mockReflectHelper.Object); + _unitTestRunner = new UnitTestRunner(new MSTestSettings(), [], null, mockReflectHelper.Object); Type type = typeof(DummyTestClassWithInitializeMethods); MethodInfo methodInfo = type.GetMethod("TestMethod")!; @@ -292,7 +292,7 @@ public async Task RunSingleTestShouldCallAssemblyInitializeAndClassInitializeMet _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("A", It.IsAny())) .Returns(Assembly.GetExecutingAssembly()); mockReflectHelper.Setup( - rh => rh.IsNonDerivedAttributeDefined(type.GetMethod("AssemblyInitialize")!, It.IsAny())) + rh => rh.IsAttributeDefined(type.GetMethod("AssemblyInitialize")!, It.IsAny())) .Returns(true); int validator = 1; diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/ExceptionExtensionsTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/ExceptionExtensionsTests.cs index 4aba233eba..ec2af07cf3 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/ExceptionExtensionsTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/ExceptionExtensionsTests.cs @@ -1,10 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; using TestFramework.ForTestingMSTest; +using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; + namespace MSTestAdapter.PlatformServices.Tests.Extensions; public class ExceptionExtensionsTests : TestContainer @@ -27,4 +31,196 @@ public void GetExceptionMessageShouldReturnInnerExceptionMessageAsWell() Verify(expectedMessage == ex.GetExceptionMessage()); } + + #region TryGetExceptionMessage scenarios + + public void ExceptionTryGetMessageGetsTheExceptionMessage() + { + var exception = new Exception("dummyMessage"); + + Verify(exception.TryGetMessage() == "dummyMessage"); + } + + public void ExceptionTryGetMessageReturnsEmptyStringIfExceptionMessageIsNull() + { + var exception = new DummyException(() => null!); + + Verify(exception.TryGetMessage() == string.Empty); + } + + public void ExceptionTryGetMessageReturnsErrorMessageIfExceptionIsNull() + { + string errorMessage = string.Format(CultureInfo.InvariantCulture, Resource.UTF_FailedToGetExceptionMessage, "null"); + + var exception = (Exception?)null; + + Verify(errorMessage == exception.TryGetMessage()); + } + + public void ExceptionTryGetMessageShouldThrowIfExceptionMessageThrows() + { + var exception = new DummyException(() => throw new NotImplementedException()); + + VerifyThrows(() => exception.TryGetMessage()); + } + + #endregion + + #region TryGetStackTraceInformation scenarios + + public void TryGetStackTraceInformationReturnsNullIfExceptionStackTraceIsNullOrEmpty() + { + var exception = new DummyExceptionForStackTrace(() => null!); + + Verify(exception.TryGetStackTraceInformation() is null); + } + + public void TryGetStackTraceInformationReturnsStackTraceForAnException() + { + var exception = new DummyExceptionForStackTrace(() => " at A()\r\n at B()"); + + StackTraceInformation? stackTraceInformation = exception.TryGetStackTraceInformation(); + + Verify(stackTraceInformation!.ErrorStackTrace.StartsWith(" at A()", StringComparison.Ordinal)); + Verify(stackTraceInformation.ErrorFilePath is null); + Verify(stackTraceInformation.ErrorLineNumber == 0); + } + + public void TryGetStackTraceInformationShouldThrowIfStackTraceThrows() + { + var exception = new DummyExceptionForStackTrace(() => throw new NotImplementedException()); + + VerifyThrows(() => exception.TryGetStackTraceInformation()); + } + +#pragma warning disable CA1710 // Identifiers should have correct suffix + public class DummyExceptionForStackTrace : Exception +#pragma warning restore CA1710 // Identifiers should have correct suffix + { + private readonly Func _getStackTrace; + + public DummyExceptionForStackTrace(Func getStackTrace) => _getStackTrace = getStackTrace; + + public override string StackTrace => _getStackTrace(); + } + + internal class DummyException : Exception + { + private readonly Func _getMessage; + + public DummyException(Func message) => _getMessage = message; + + public override string Message => _getMessage(); + } + + #endregion + + #region IsUnitTestAssertException scenarios + + public void IsUnitTestAssertExceptionReturnsTrueIfExceptionIsAssertException() + { + var exception = new AssertInconclusiveException(); + Verify(exception.TryGetUnitTestAssertException(out _, out _, out _)); + } + + public void IsUnitTestAssertExceptionReturnsFalseIfExceptionIsNotAssertException() + { + var exception = new NotImplementedException(); + Verify(!exception.TryGetUnitTestAssertException(out _, out _, out _)); + } + + public void IsUnitTestAssertExceptionSetsOutcomeAsInconclusiveIfAssertInconclusiveException() + { + var exception = new AssertInconclusiveException("Dummy Message", new NotImplementedException("notImplementedException")); + exception.TryGetUnitTestAssertException(out UTF.UnitTestOutcome outcome, out string? exceptionMessage, out _); + + Verify(outcome == UTF.UnitTestOutcome.Inconclusive); + Verify(exceptionMessage == "Dummy Message"); + } + + public void IsUnitTestAssertExceptionSetsOutcomeAsFailedIfAssertFailedException() + { + var exception = new AssertFailedException("Dummy Message", new NotImplementedException("notImplementedException")); + exception.TryGetUnitTestAssertException(out UTF.UnitTestOutcome outcome, out string? exceptionMessage, out _); + + Verify(outcome == UTF.UnitTestOutcome.Failed); + Verify(exceptionMessage == "Dummy Message"); + } + #endregion + + #region GetRealException scenarios + public void GetRealExceptionGetsTheTopExceptionWhenThereIsJustOne() + { + var exception = new InvalidOperationException(); + Exception actual = exception.GetRealException(); + + Verify(actual is InvalidOperationException); + } + + public void GetRealExceptionGetsTheInnerExceptionWhenTheExceptionIsTargetInvocation() + { + var exception = new TargetInvocationException(new InvalidOperationException()); + Exception actual = exception.GetRealException(); + + Verify(actual is InvalidOperationException); + } + + public void GetRealExceptionGetsTheTargetInvocationExceptionWhenTargetInvocationIsProvidedWithNullInnerException() + { + var exception = new TargetInvocationException(null); + Exception actual = exception.GetRealException(); + + Verify(actual is TargetInvocationException); + } + + public void GetRealExceptionGetsTheInnerMostRealException() + { + var exception = new TargetInvocationException(new TargetInvocationException(new TargetInvocationException(new InvalidOperationException()))); + Exception actual = exception.GetRealException(); + + Verify(actual is InvalidOperationException); + } + + public void GetRealExceptionGetsTheInnerMostTargetInvocationException() + { + var exception = new TargetInvocationException(new TargetInvocationException(new TargetInvocationException("inner most", null))); + Exception actual = exception.GetRealException(); + + Verify(actual is TargetInvocationException); + Verify(actual.Message == "inner most"); + } + + public void GetRealExceptionGetsTheInnerExceptionWhenTheExceptionIsTypeInitialization() + { + var exception = new TypeInitializationException("some type", new InvalidOperationException()); + Exception actual = exception.GetRealException(); + + Verify(actual is InvalidOperationException); + } + + public void GetRealExceptionGetsTheTypeInitializationExceptionWhenTypeInitializationIsProvidedWithNullInnerException() + { + var exception = new TypeInitializationException("some type", null); + Exception actual = exception.GetRealException(); + + Verify(actual is TypeInitializationException); + } + + public void GetRealExceptionGetsTheInnerMostRealExceptionOfTypeInitialization() + { + var exception = new TypeInitializationException("some type", new TypeInitializationException("some type", new TypeInitializationException("some type", new InvalidOperationException()))); + Exception actual = exception.GetRealException(); + + Verify(actual is InvalidOperationException); + } + + public void GetRealExceptionGetsTheInnerMostTypeInitializationException() + { + var exception = new TypeInitializationException("some type", new TypeInitializationException("some type", new TypeInitializationException("inner most", null))); + Exception actual = exception.GetRealException(); + + Verify(actual is TypeInitializationException); + Verify(actual.Message == "The type initializer for 'inner most' threw an exception."); + } + #endregion } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/MethodInfoExtensionsTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/MethodInfoExtensionsTests.cs similarity index 96% rename from test/UnitTests/MSTestAdapter.UnitTests/Extensions/MethodInfoExtensionsTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/MethodInfoExtensionsTests.cs index b8887cb5f2..3341676ab3 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/MethodInfoExtensionsTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/MethodInfoExtensionsTests.cs @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions; using TestFramework.ForTestingMSTest; using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; -using UTFExtension = Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Extensions; @@ -244,13 +244,13 @@ public void HasCorrectTestMethodSignatureShouldReturnFalseForAsyncTestMethodsWit public void HasCorrectTimeoutShouldReturnFalseForMethodsWithInvalidTimeoutAttribute() { - var timeoutAttribute = new UTF.TimeoutAttribute(-11); + var timeoutAttribute = new TimeoutAttribute(-11); Verify(!timeoutAttribute.HasCorrectTimeout); } public void HasCorrectTimeoutShouldReturnTrueForMethodsWithTimeoutAttribute() { - var timeoutAttribute = new UTF.TimeoutAttribute(11); + var timeoutAttribute = new TimeoutAttribute(11); Verify(timeoutAttribute.HasCorrectTimeout); } @@ -462,18 +462,18 @@ public static void PublicStaticMethodWithInt(int a) { } - public static int PublicStaticMethodWithTCReturningInt(UTFExtension.TestContext tc) => 0; + public static int PublicStaticMethodWithTCReturningInt(TestContext tc) => 0; - public static void PublicStaticMethodWithTC(UTFExtension.TestContext tc) + public static void PublicStaticMethodWithTC(TestContext tc) { } - public static async Task PublicStaticAsyncTaskMethodWithTC(UTFExtension.TestContext tc) => await Task.FromResult(true).ConfigureAwait(false); + public static async Task PublicStaticAsyncTaskMethodWithTC(TestContext tc) => await Task.FromResult(true).ConfigureAwait(false); - public static Task PublicStaticNonAsyncTaskMethodWithTC(UTFExtension.TestContext tc) => Task.FromResult(true); + public static Task PublicStaticNonAsyncTaskMethodWithTC(TestContext tc) => Task.FromResult(true); [SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "Done on purpose")] - public static async void PublicStaticAsyncVoidMethodWithTC(UTFExtension.TestContext tc) => await Task.FromResult(true).ConfigureAwait(false); + public static async void PublicStaticAsyncVoidMethodWithTC(TestContext tc) => await Task.FromResult(true).ConfigureAwait(false); public static int PublicStaticMethodReturningInt() => 0; @@ -507,12 +507,12 @@ public void PublicMethodWithInt(int a) public Task PublicNonAsyncTaskMethod() => Task.FromResult(true); - [UTF.Timeout(-11)] + [Timeout(-11)] public void PublicMethodWithInvalidTimeout() { } - [UTF.Timeout(11)] + [Timeout(11)] public void PublicMethodWithTimeout() { } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/TestCaseExtensionsTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/TestCaseExtensionsTests.cs similarity index 79% rename from test/UnitTests/MSTestAdapter.UnitTests/Extensions/TestCaseExtensionsTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/TestCaseExtensionsTests.cs index 5e2ba8b8df..1c8ad83b56 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/TestCaseExtensionsTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/TestCaseExtensionsTests.cs @@ -2,12 +2,11 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using TestFramework.ForTestingMSTest; -using Constants = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Constants; - namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Extensions; public class TestCaseExtensionsTests : TestContainer @@ -20,9 +19,9 @@ public void ToUnitTestElementShouldReturnUnitTestElementWithFieldsSet() }; string[] testCategories = ["DummyCategory"]; - testCase.SetPropertyValue(Constants.PriorityProperty, 2); - testCase.SetPropertyValue(Constants.TestCategoryProperty, testCategories); - testCase.SetPropertyValue(Constants.TestClassNameProperty, "DummyClassName"); + testCase.SetPropertyValue(EngineConstants.PriorityProperty, 2); + testCase.SetPropertyValue(EngineConstants.TestCategoryProperty, testCategories); + testCase.SetPropertyValue(EngineConstants.TestClassNameProperty, "DummyClassName"); var resultUnitTestElement = testCase.ToUnitTestElement(testCase.Source); @@ -37,7 +36,7 @@ public void ToUnitTestElementShouldReturnUnitTestElementWithFieldsSet() public void ToUnitTestElementForTestCaseWithNoPropertiesShouldReturnUnitTestElementWithDefaultFields() { TestCase testCase = new("DummyClass.DummyMethod", new("DummyUri", UriKind.Relative), Assembly.GetCallingAssembly().FullName!); - testCase.SetPropertyValue(Constants.TestClassNameProperty, "DummyClassName"); + testCase.SetPropertyValue(EngineConstants.TestClassNameProperty, "DummyClassName"); var resultUnitTestElement = testCase.ToUnitTestElement(testCase.Source); @@ -49,8 +48,8 @@ public void ToUnitTestElementForTestCaseWithNoPropertiesShouldReturnUnitTestElem public void ToUnitTestElementShouldAddDeclaringClassNameToTestElementWhenAvailable() { TestCase testCase = new("DummyClass.DummyMethod", new("DummyUri", UriKind.Relative), Assembly.GetCallingAssembly().FullName!); - testCase.SetPropertyValue(Constants.TestClassNameProperty, "DummyClassName"); - testCase.SetPropertyValue(Constants.DeclaringClassNameProperty, "DummyDeclaringClassName"); + testCase.SetPropertyValue(EngineConstants.TestClassNameProperty, "DummyClassName"); + testCase.SetPropertyValue(EngineConstants.DeclaringClassNameProperty, "DummyDeclaringClassName"); var resultUnitTestElement = testCase.ToUnitTestElement(testCase.Source); diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/TestContextExtensionsTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/TestContextExtensionsTests.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/Extensions/TestContextExtensionsTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/TestContextExtensionsTests.cs diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/TestResultExtensionsTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/TestResultExtensionsTests.cs similarity index 93% rename from test/UnitTests/MSTestAdapter.UnitTests/Extensions/TestResultExtensionsTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/TestResultExtensionsTests.cs index 0b116fc5a8..28f878600d 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/TestResultExtensionsTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/TestResultExtensionsTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using TestFramework.ForTestingMSTest; @@ -32,7 +33,7 @@ public void ToUnitTestResultsForTestResultWithExceptionConvertsToUnitTestResults public void ToUnitTestResultsForTestResultShouldSetLoggingDataForConvertedUnitTestResults() { var timespan = default(TimeSpan); - var result = new UTF.TestResult + var result = new TestResult { DebugTrace = "debugTrace", DisplayName = "displayName", @@ -43,7 +44,7 @@ public void ToUnitTestResultsForTestResultShouldSetLoggingDataForConvertedUnitTe }; var convertedResult = result.ToTestResult(new() { DisplayName = result.DisplayName }, default, default, string.Empty, new()); - VSTestTestResultMessage[] stdOutMessages = convertedResult.Messages.Where(m => m.Category == VSTestTestResultMessage.StandardOutCategory).ToArray(); + VSTestTestResultMessage[] stdOutMessages = [.. convertedResult.Messages.Where(m => m.Category == VSTestTestResultMessage.StandardOutCategory)]; Verify(stdOutMessages[0].Text == "logOutput"); Verify(convertedResult.Messages.Single(m => m.Category == VSTestTestResultMessage.StandardErrorCategory).Text == "logError"); Verify(convertedResult.DisplayName == "displayName (Data Row 1)"); @@ -166,9 +167,9 @@ public void ToUnitTestResultsForTestResultShouldSetParentInfo() var convertedResult = result.ToTestResult(new(), default, default, string.Empty, new()); - Verify(executionId == (Guid)convertedResult.GetPropertyValue(MSTest.TestAdapter.Constants.ExecutionIdProperty)!); - Verify(parentExecId == (Guid)convertedResult.GetPropertyValue(MSTest.TestAdapter.Constants.ParentExecIdProperty)!); - Verify(innerResultsCount == (int)convertedResult.GetPropertyValue(MSTest.TestAdapter.Constants.InnerResultsCountProperty)!); + Verify(executionId == (Guid)convertedResult.GetPropertyValue(EngineConstants.ExecutionIdProperty)!); + Verify(parentExecId == (Guid)convertedResult.GetPropertyValue(EngineConstants.ParentExecIdProperty)!); + Verify(innerResultsCount == (int)convertedResult.GetPropertyValue(EngineConstants.InnerResultsCountProperty)!); } public void ToUnitTestResultsShouldHaveResultsFileProvidedToTestResult() @@ -177,7 +178,7 @@ public void ToUnitTestResultsShouldHaveResultsFileProvidedToTestResult() // Otherwise, ToTestResult will crash because it calls new Uri on the result file. string resultFile = Path.GetFullPath("DummyFile.txt"); - var result = new TestResult { ResultFiles = new List() { resultFile } }; + var result = new TestResult { ResultFiles = [resultFile] }; var convertedResult = result.ToTestResult(new(), default, default, string.Empty, new()); Verify(convertedResult.Attachments[0].Attachments[0].Description == resultFile); } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/UnitTestOutcomeExtensionsTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/UnitTestOutcomeExtensionsTests.cs similarity index 73% rename from test/UnitTests/MSTestAdapter.UnitTests/Extensions/UnitTestOutcomeExtensionsTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/UnitTestOutcomeExtensionsTests.cs index 77c056e763..86bc0fb6cb 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/UnitTestOutcomeExtensionsTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Extensions/UnitTestOutcomeExtensionsTests.cs @@ -14,7 +14,7 @@ public class UnitTestOutcomeExtensionsTests : TestContainer { public void ToUnitTestOutComeForPassedTestResultsConvertsToPassedUnitTestOutCome() { - UTF.UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Passed; + UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Passed; var convertedOutcome = frameworkOutcome.ToUnitTestOutcome(); Verify(convertedOutcome == AdapterTestOutcome.Passed); @@ -22,7 +22,7 @@ public void ToUnitTestOutComeForPassedTestResultsConvertsToPassedUnitTestOutCome public void ToUnitTestResultsForFailedTestResultsConvertsToFailedUnitTestResults() { - UTF.UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Failed; + UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Failed; var convertedOutcome = frameworkOutcome.ToUnitTestOutcome(); Verify(convertedOutcome == AdapterTestOutcome.Failed); @@ -30,7 +30,7 @@ public void ToUnitTestResultsForFailedTestResultsConvertsToFailedUnitTestResults public void ToUnitTestResultsForInProgressTestResultsConvertsToInProgressUnitTestResults() { - UTF.UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.InProgress; + UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.InProgress; var convertedOutcome = frameworkOutcome.ToUnitTestOutcome(); Verify(convertedOutcome == AdapterTestOutcome.InProgress); @@ -38,7 +38,7 @@ public void ToUnitTestResultsForInProgressTestResultsConvertsToInProgressUnitTes public void ToUnitTestResultsForInconclusiveTestResultsConvertsToInconclusiveUnitTestResults() { - UTF.UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Inconclusive; + UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Inconclusive; var convertedOutcome = frameworkOutcome.ToUnitTestOutcome(); Verify(convertedOutcome == AdapterTestOutcome.Inconclusive); @@ -46,7 +46,7 @@ public void ToUnitTestResultsForInconclusiveTestResultsConvertsToInconclusiveUni public void ToUnitTestResultsForTimeoutTestResultsConvertsToTimeoutUnitTestResults() { - UTF.UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Timeout; + UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Timeout; var convertedOutcome = frameworkOutcome.ToUnitTestOutcome(); Verify(convertedOutcome == AdapterTestOutcome.Timeout); @@ -54,7 +54,7 @@ public void ToUnitTestResultsForTimeoutTestResultsConvertsToTimeoutUnitTestResul public void ToUnitTestResultsForUnknownTestResultsConvertsToErrorUnitTestResults() { - UTF.UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Unknown; + UnitTestOutcome frameworkOutcome = UTF.UnitTestOutcome.Unknown; var convertedOutcome = frameworkOutcome.ToUnitTestOutcome(); Verify(convertedOutcome == AdapterTestOutcome.Error); @@ -62,25 +62,25 @@ public void ToUnitTestResultsForUnknownTestResultsConvertsToErrorUnitTestResults public void GetMoreImportantOutcomeShouldReturnFailIfTwoOutcomesAreFailedAndInconclusive() { - UTF.UnitTestOutcome resultOutcome = UTF.UnitTestOutcome.Failed.GetMoreImportantOutcome(UTF.UnitTestOutcome.Inconclusive); + UnitTestOutcome resultOutcome = UTF.UnitTestOutcome.Failed.GetMoreImportantOutcome(UTF.UnitTestOutcome.Inconclusive); Verify(resultOutcome == UTF.UnitTestOutcome.Failed); } public void GetMoreImportantOutcomeShouldReturnInconclusiveIfTwoOutcomesArePassedAndInconclusive() { - UTF.UnitTestOutcome resultOutcome = UTF.UnitTestOutcome.Passed.GetMoreImportantOutcome(UTF.UnitTestOutcome.Inconclusive); + UnitTestOutcome resultOutcome = UTF.UnitTestOutcome.Passed.GetMoreImportantOutcome(UTF.UnitTestOutcome.Inconclusive); Verify(resultOutcome == UTF.UnitTestOutcome.Inconclusive); } public void GetMoreImportantOutcomeShouldReturnFailedIfTwoOutcomesArePassedAndFailed() { - UTF.UnitTestOutcome resultOutcome = UTF.UnitTestOutcome.Passed.GetMoreImportantOutcome(UTF.UnitTestOutcome.Failed); + UnitTestOutcome resultOutcome = UTF.UnitTestOutcome.Passed.GetMoreImportantOutcome(UTF.UnitTestOutcome.Failed); Verify(resultOutcome == UTF.UnitTestOutcome.Failed); } public void GetMoreImportantOutcomeShouldReturnFailedIfBothOutcomesAreFailed() { - UTF.UnitTestOutcome resultOutcome = UTF.UnitTestOutcome.Failed.GetMoreImportantOutcome(UTF.UnitTestOutcome.Failed); + UnitTestOutcome resultOutcome = UTF.UnitTestOutcome.Failed.GetMoreImportantOutcome(UTF.UnitTestOutcome.Failed); Verify(resultOutcome == UTF.UnitTestOutcome.Failed); } } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Helpers/DataSerializationHelperTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/DataSerializationHelperTests.cs similarity index 73% rename from test/UnitTests/MSTestAdapter.UnitTests/Helpers/DataSerializationHelperTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/DataSerializationHelperTests.cs index 17f093237a..1b7e4aa18e 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Helpers/DataSerializationHelperTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/DataSerializationHelperTests.cs @@ -55,4 +55,28 @@ public void DataSerializerShouldRoundTripDateTimeOfKindUtc() Verify(actual[0]!.Equals(source)); Verify(((DateTime)actual[0]!).Kind.Equals(source.Kind)); } + +#if NET7_0_OR_GREATER + public void DataSerializerShouldRoundTripDateOnly() + { + var source = new DateOnly(1999, 11, 3); + + object?[]? actual = DataSerializationHelper.Deserialize(DataSerializationHelper.Serialize([source])); + + Verify(actual!.Length == 1); + Verify(actual[0]!.GetType() == typeof(DateOnly)); + Verify(actual[0]!.Equals(source)); + } + + public void DataSerializerShouldRoundTripTimeOnly() + { + var source = new TimeOnly(hour: 14, minute: 50, second: 13, millisecond: 15); + + object?[]? actual = DataSerializationHelper.Deserialize(DataSerializationHelper.Serialize([source])); + + Verify(actual!.Length == 1); + Verify(actual[0]!.GetType() == typeof(TimeOnly)); + Verify(actual[0]!.Equals(source)); + } +#endif } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Helpers/DictionaryHelperTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/DictionaryHelperTests.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/Helpers/DictionaryHelperTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/DictionaryHelperTests.cs diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Helpers/ReflectHelperTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/ReflectHelperTests.cs similarity index 88% rename from test/UnitTests/MSTestAdapter.UnitTests/Helpers/ReflectHelperTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/ReflectHelperTests.cs index f6856b60ba..f77540b6f9 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Helpers/ReflectHelperTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/ReflectHelperTests.cs @@ -49,7 +49,7 @@ public void GetTestCategoryAttributeShouldIncludeTestCategoriesAtClassLevel() _attributeMockingHelper.SetCustomAttribute(typeof(TestCategoryBaseAttribute), [new TestCategoryAttribute("ClassLevel")], MemberTypes.TypeInfo); string[] expected = ["ClassLevel"]; - string[] actual = _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests)).ToArray(); + string[] actual = [.. _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests))]; Verify(expected.SequenceEqual(actual)); } @@ -64,7 +64,7 @@ public void GetTestCategoryAttributeShouldIncludeTestCategoriesAtAllLevels() _attributeMockingHelper.SetCustomAttribute(typeof(TestCategoryBaseAttribute), [new TestCategoryAttribute("ClassLevel")], MemberTypes.TypeInfo); _attributeMockingHelper.SetCustomAttribute(typeof(TestCategoryBaseAttribute), [new TestCategoryAttribute("MethodLevel")], MemberTypes.Method); - string[] actual = _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests)).ToArray(); + string[] actual = [.. _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests))]; string[] expected = ["MethodLevel", "ClassLevel", "AsmLevel1", "AsmLevel2", "AsmLevel3"]; Verify(expected.SequenceEqual(actual)); @@ -82,7 +82,7 @@ public void GetTestCategoryAttributeShouldConcatCustomAttributeOfSameType() _attributeMockingHelper.SetCustomAttribute(typeof(TestCategoryBaseAttribute), [new TestCategoryAttribute("MethodLevel1")], MemberTypes.Method); _attributeMockingHelper.SetCustomAttribute(typeof(TestCategoryBaseAttribute), [new TestCategoryAttribute("MethodLevel2")], MemberTypes.Method); - string[] actual = _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests)).ToArray(); + string[] actual = [.. _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests))]; string[] expected = ["MethodLevel1", "MethodLevel2", "ClassLevel1", "ClassLevel2", "AsmLevel1", "AsmLevel2"]; Verify(expected.SequenceEqual(actual)); @@ -97,7 +97,7 @@ public void GetTestCategoryAttributeShouldIncludeTestCategoriesAtAssemblyLevel() string[] expected = ["AsmLevel"]; - string[] actual = _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests)).ToArray(); + string[] actual = [.. _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests))]; Verify(expected.SequenceEqual(actual)); } @@ -110,7 +110,7 @@ public void GetTestCategoryAttributeShouldIncludeMultipleTestCategoriesAtClassLe _attributeMockingHelper.SetCustomAttribute(typeof(TestCategoryBaseAttribute), [new TestCategoryAttribute("ClassLevel"), new TestCategoryAttribute("ClassLevel1")], MemberTypes.TypeInfo); string[] expected = ["ClassLevel", "ClassLevel1"]; - string[] actual = _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests)).ToArray(); + string[] actual = [.. _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests))]; Verify(expected.SequenceEqual(actual)); } @@ -123,7 +123,7 @@ public void GetTestCategoryAttributeShouldIncludeMultipleTestCategoriesAtAssembl _attributeMockingHelper.SetCustomAttribute(typeof(TestCategoryBaseAttribute), [new TestCategoryAttribute("AsmLevel"), new TestCategoryAttribute("AsmLevel1")], MemberTypes.All); string[] expected = ["AsmLevel", "AsmLevel1"]; - string[] actual = _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests)).ToArray(); + string[] actual = [.. _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests))]; Verify(expected.SequenceEqual(actual)); } @@ -135,7 +135,7 @@ public void GetTestCategoryAttributeShouldIncludeTestCategoriesAtMethodLevel() _attributeMockingHelper.SetCustomAttribute(typeof(TestCategoryBaseAttribute), [new TestCategoryAttribute("MethodLevel")], MemberTypes.Method); string[] expected = ["MethodLevel"]; - string[] actual = _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests)).ToArray(); + string[] actual = [.. _reflectHelper.GetTestCategories(_method.Object, typeof(ReflectHelperTests))]; Verify(expected.SequenceEqual(actual)); } @@ -150,7 +150,7 @@ public void IsAttributeDefinedShouldReturnTrueIfSpecifiedAttributeIsDefinedOnAMe Setup(ro => ro.GetCustomAttributes(mockMemberInfo.Object, true)). Returns(attributes); - Verify(rh.IsNonDerivedAttributeDefined(mockMemberInfo.Object, true)); + Verify(rh.IsAttributeDefined(mockMemberInfo.Object, true)); } public void IsAttributeDefinedShouldReturnFalseIfSpecifiedAttributeIsNotDefinedOnAMember() @@ -163,7 +163,7 @@ public void IsAttributeDefinedShouldReturnFalseIfSpecifiedAttributeIsNotDefinedO Setup(ro => ro.GetCustomAttributes(mockMemberInfo.Object, true)). Returns(attributes); - Verify(!rh.IsNonDerivedAttributeDefined(mockMemberInfo.Object, true)); + Verify(!rh.IsAttributeDefined(mockMemberInfo.Object, true)); } public void IsAttributeDefinedShouldReturnFromCache() @@ -180,10 +180,10 @@ public void IsAttributeDefinedShouldReturnFromCache() Setup(ro => ro.GetCustomAttributes(memberInfo, true)). Returns(attributes); - Verify(rh.IsNonDerivedAttributeDefined(memberInfo, true)); + Verify(rh.IsAttributeDefined(memberInfo, true)); // Validate that reflection APIs are not called again. - Verify(rh.IsNonDerivedAttributeDefined(memberInfo, true)); + Verify(rh.IsAttributeDefined(memberInfo, true)); _testablePlatformServiceProvider.MockReflectionOperations.Verify(ro => ro.GetCustomAttributes(memberInfo, true), Times.Once); // Also validate that reflection APIs for an individual type is not called since the cache gives us what we need already. @@ -200,7 +200,7 @@ public void HasAttributeDerivedFromShouldReturnTrueIfSpecifiedAttributeIsDefined Setup(ro => ro.GetCustomAttributes(mockMemberInfo.Object, true)). Returns(attributes); - Verify(rh.IsDerivedAttributeDefined(mockMemberInfo.Object, true)); + Verify(rh.IsAttributeDefined(mockMemberInfo.Object, true)); } public void HasAttributeDerivedFromShouldReturnFalseIfSpecifiedAttributeIsNotDefinedOnAMember() @@ -213,7 +213,7 @@ public void HasAttributeDerivedFromShouldReturnFalseIfSpecifiedAttributeIsNotDef Setup(ro => ro.GetCustomAttributes(mockMemberInfo.Object, true)). Returns(attributes); - Verify(!rh.IsNonDerivedAttributeDefined(mockMemberInfo.Object, true)); + Verify(!rh.IsAttributeDefined(mockMemberInfo.Object, true)); } public void HasAttributeDerivedFromShouldReturnFromCache() @@ -230,10 +230,10 @@ public void HasAttributeDerivedFromShouldReturnFromCache() Setup(ro => ro.GetCustomAttributes(memberInfo, true)). Returns(attributes); - Verify(rh.IsDerivedAttributeDefined(memberInfo, true)); + Verify(rh.IsAttributeDefined(memberInfo, true)); // Validate that reflection APIs are not called again. - Verify(rh.IsDerivedAttributeDefined(memberInfo, true)); + Verify(rh.IsAttributeDefined(memberInfo, true)); _testablePlatformServiceProvider.MockReflectionOperations.Verify(ro => ro.GetCustomAttributes(memberInfo, true), Times.Once); // Also validate that reflection APIs for an individual type is not called since the cache gives us what we need already. @@ -254,7 +254,7 @@ public void HasAttributeDerivedFromShouldReturnFalseQueryingProvidedAttributesEx Setup(ro => ro.GetCustomAttributes(mockMemberInfo.Object, typeof(TestMethodAttribute), true)). Returns(attributes); - Verify(!rh.IsNonDerivedAttributeDefined(mockMemberInfo.Object, true)); + Verify(!rh.IsAttributeDefined(mockMemberInfo.Object, true)); } public void GettingAttributesShouldNotReturnInheritedAttributesWhenAskingForNonInheritedAttributes() @@ -274,8 +274,8 @@ public void GettingAttributesShouldNotReturnInheritedAttributesWhenAskingForNonI Setup(ro => ro.GetCustomAttributes(It.IsAny(), /* inherit */ false)). Returns([new TestClassAttribute()]); - TestClassAttribute[] inheritedAttributes = rh.GetDerivedAttributes(typeof(object), inherit: true).ToArray(); - TestClassAttribute[] nonInheritedAttributes = rh.GetDerivedAttributes(typeof(object), inherit: false).ToArray(); + TestClassAttribute[] inheritedAttributes = [.. rh.GetAttributes(typeof(object), inherit: true)]; + TestClassAttribute[] nonInheritedAttributes = [.. rh.GetAttributes(typeof(object), inherit: false)]; Verify(inheritedAttributes.Length == 2); Verify(nonInheritedAttributes.Length == 1); @@ -291,7 +291,7 @@ internal class AttributeMockingHelper /// MemberTypes.TypeInfo for class level /// MemberTypes.Method for method level. /// - private readonly List<(Type Type, Attribute Attribute, MemberTypes MemberType)> _data = new(); + private readonly List<(Type Type, Attribute Attribute, MemberTypes MemberType)> _data = []; private readonly Mock _mockReflectionOperations; public void SetCustomAttribute(Type type, Attribute[] values, MemberTypes memberTypes) diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Helpers/RunSettingsUtilitiesTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/RunSettingsUtilitiesTests.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/Helpers/RunSettingsUtilitiesTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/RunSettingsUtilitiesTests.cs diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/TestDataSourceHelpersTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/TestDataSourceHelpersTests.cs new file mode 100644 index 0000000000..c470744a70 --- /dev/null +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/TestDataSourceHelpersTests.cs @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; + +using TestFramework.ForTestingMSTest; + +namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.UnitTests.Helpers; + +public class TestDataSourceHelpersTests : TestContainer +{ + public void TryHandleITestDataRow_WithTestDataRow_ShouldExtractTestCategories() + { + // Arrange + var testData = new TestDataRow("test_value") + { + TestCategories = ["Category1", "Category2"], + IgnoreMessage = "ignore_message", + DisplayName = "display_name", + }; + object?[] dataArray = [testData]; + ParameterInfo[] parameters = []; // No method parameters for this test + + // Act + bool result = TestDataSourceHelpers.TryHandleITestDataRow( + dataArray, + parameters, + out object?[] extractedData, + out string? ignoreMessage, + out string? displayName, + out IList? testCategories); + + // Assert + Verify(result); + Verify(extractedData != null); + Verify(extractedData.Length == 1); + Verify((string?)extractedData[0] == "test_value"); + Verify(ignoreMessage == "ignore_message"); + Verify(displayName == "display_name"); + Verify(testCategories != null); + Verify(testCategories.Count == 2); + Verify(testCategories.Contains("Category1")); + Verify(testCategories.Contains("Category2")); + } + + public void TryHandleITestDataRow_WithTestDataRowNullCategories_ShouldReturnNullCategories() + { + // Arrange + var testData = new TestDataRow("test_value"); + object?[] dataArray = [testData]; + ParameterInfo[] parameters = []; + + // Act + bool result = TestDataSourceHelpers.TryHandleITestDataRow( + dataArray, + parameters, + out _, + out _, + out _, + out IList? testCategories); + + // Assert + Verify(result); + Verify(testCategories == null); + } + + public void TryHandleITestDataRow_WithNonTestDataRow_ShouldReturnFalseAndNullCategories() + { + // Arrange + object?[] dataArray = ["regular_string"]; + ParameterInfo[] parameters = []; + + // Act + bool result = TestDataSourceHelpers.TryHandleITestDataRow( + dataArray, + parameters, + out object?[] extractedData, + out string? ignoreMessage, + out string? displayName, + out IList? testCategories); + + // Assert + Verify(!result); + Verify(extractedData == dataArray); + Verify(ignoreMessage == null); + Verify(displayName == null); + Verify(testCategories == null); + } + + public void TryHandleITestDataRow_BackwardCompatibilityOverload_ShouldWork() + { + // Arrange + var testData = new TestDataRow("test_value") + { + TestCategories = ["Category1", "Category2"], + IgnoreMessage = "ignore_message", + DisplayName = "display_name", + }; + object?[] dataArray = [testData]; + ParameterInfo[] parameters = []; + + // Act + bool result = TestDataSourceHelpers.TryHandleITestDataRow( + dataArray, + parameters, + out object?[] extractedData, + out string? ignoreMessage, + out string? displayName); + + // Assert - should work without TestCategories parameter + Verify(result); + Verify(extractedData != null); + Verify(extractedData.Length == 1); + Verify((string?)extractedData[0] == "test_value"); + Verify(ignoreMessage == "ignore_message"); + Verify(displayName == "display_name"); + } +} diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Helpers/UnitTestOutcomeHelperTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/UnitTestOutcomeHelperTests.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/Helpers/UnitTestOutcomeHelperTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Helpers/UnitTestOutcomeHelperTests.cs diff --git a/test/UnitTests/MSTestAdapter.UnitTests/MSTestSettingsTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestSettingsTests.cs similarity index 99% rename from test/UnitTests/MSTestAdapter.UnitTests/MSTestSettingsTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestSettingsTests.cs index 688b87b1bb..af31738440 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/MSTestSettingsTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestSettingsTests.cs @@ -3,6 +3,7 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.TestableImplementations; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; @@ -11,6 +12,8 @@ using Moq; using TestFramework.ForTestingMSTest; + +using ExecutionScope = Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope; #pragma warning disable CS0618 // Type or member is obsolete namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests; @@ -563,7 +566,7 @@ public void GetSettingsShouldThrowWhenParallelizeHasInvalidElements() """; AdapterSettingsException exception = VerifyThrows(() => MSTestSettings.GetSettings(runSettingsXml, MSTestSettings.SettingsNameAlias, _mockMessageLogger.Object)); - Verify(exception.Message.Contains("Invalid settings 'Parallelize'. Unexpected XmlElement: 'Hola'.")); + Verify(exception.Message.Contains("MSTestAdapter encountered an unexpected element 'Hola' in its settings 'Parallelize'. Remove this element and try again.")); } public void GetSettingsShouldBeAbleToReadAfterParallelizationSettings() diff --git a/test/UnitTests/MSTestAdapter.UnitTests/ObjectModel/UnitTestElementTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs similarity index 81% rename from test/UnitTests/MSTestAdapter.UnitTests/ObjectModel/UnitTestElementTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs index 2985183fb9..27dc52885b 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/ObjectModel/UnitTestElementTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs @@ -2,14 +2,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Polyfills; using TestFramework.ForTestingMSTest; -using Constants = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Constants; - namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.ObjectModel; public class UnitTestElementTests : TestContainer @@ -43,7 +42,7 @@ public void ToTestCaseShouldSetExecutorUri() { var testCase = _unitTestElement.ToTestCase(); - Verify(testCase.ExecutorUri == Constants.ExecutorUri); + Verify(testCase.ExecutorUri == EngineConstants.ExecutorUri); } public void ToTestCaseShouldSetAssemblyName() @@ -72,7 +71,7 @@ public void ToTestCaseShouldSetTestClassNameProperty() { var testCase = _unitTestElement.ToTestCase(); - Verify((testCase.GetPropertyValue(Constants.TestClassNameProperty) as string) == "C"); + Verify((testCase.GetPropertyValue(EngineConstants.TestClassNameProperty) as string) == "C"); } public void ToTestCaseShouldSetDeclaringClassNameIfPresent() @@ -80,12 +79,12 @@ public void ToTestCaseShouldSetDeclaringClassNameIfPresent() _testMethod.DeclaringClassFullName = null; var testCase = _unitTestElement.ToTestCase(); - Verify(testCase.GetPropertyValue(Constants.DeclaringClassNameProperty) is null); + Verify(testCase.GetPropertyValue(EngineConstants.DeclaringClassNameProperty) is null); _testMethod.DeclaringClassFullName = "DC"; testCase = _unitTestElement.ToTestCase(); - Verify((testCase.GetPropertyValue(Constants.DeclaringClassNameProperty) as string) == "DC"); + Verify((testCase.GetPropertyValue(EngineConstants.DeclaringClassNameProperty) as string) == "DC"); } public void ToTestCaseShouldSetTestCategoryIfPresent() @@ -93,17 +92,17 @@ public void ToTestCaseShouldSetTestCategoryIfPresent() _unitTestElement.TestCategory = null; var testCase = _unitTestElement.ToTestCase(); - Verify(testCase.GetPropertyValue(Constants.TestCategoryProperty) is null); + Verify(testCase.GetPropertyValue(EngineConstants.TestCategoryProperty) is null); _unitTestElement.TestCategory = []; testCase = _unitTestElement.ToTestCase(); - Verify(testCase.GetPropertyValue(Constants.TestCategoryProperty) is null); + Verify(testCase.GetPropertyValue(EngineConstants.TestCategoryProperty) is null); _unitTestElement.TestCategory = ["TC"]; testCase = _unitTestElement.ToTestCase(); - Verify(new string[] { "TC" }.SequenceEqual((string[])testCase.GetPropertyValue(Constants.TestCategoryProperty)!)); + Verify(new string[] { "TC" }.SequenceEqual((string[])testCase.GetPropertyValue(EngineConstants.TestCategoryProperty)!)); } public void ToTestCaseShouldSetPriorityIfPresent() @@ -111,12 +110,12 @@ public void ToTestCaseShouldSetPriorityIfPresent() _unitTestElement.Priority = null; var testCase = _unitTestElement.ToTestCase(); - Verify((int)testCase.GetPropertyValue(Constants.PriorityProperty)! == 0); + Verify((int)testCase.GetPropertyValue(EngineConstants.PriorityProperty)! == 0); _unitTestElement.Priority = 1; testCase = _unitTestElement.ToTestCase(); - Verify((int)testCase.GetPropertyValue(Constants.PriorityProperty)! == 1); + Verify((int)testCase.GetPropertyValue(EngineConstants.PriorityProperty)! == 1); } public void ToTestCaseShouldSetTraitsIfPresent() @@ -141,15 +140,13 @@ public void ToTestCaseShouldSetPropertiesIfPresent() { _unitTestElement.CssIteration = "12"; _unitTestElement.CssProjectStructure = "ProjectStructure"; - _unitTestElement.Description = "I am a dummy test"; _unitTestElement.WorkItemIds = ["2312", "22332"]; var testCase = _unitTestElement.ToTestCase(); - Verify((testCase.GetPropertyValue(Constants.CssIterationProperty) as string) == "12"); - Verify((testCase.GetPropertyValue(Constants.CssProjectStructureProperty) as string) == "ProjectStructure"); - Verify((testCase.GetPropertyValue(Constants.DescriptionProperty) as string) == "I am a dummy test"); - Verify(new string[] { "2312", "22332" }.SequenceEqual((string[])testCase.GetPropertyValue(Constants.WorkItemIdsProperty)!)); + Verify((testCase.GetPropertyValue(EngineConstants.CssIterationProperty) as string) == "12"); + Verify((testCase.GetPropertyValue(EngineConstants.CssProjectStructureProperty) as string) == "ProjectStructure"); + Verify(new string[] { "2312", "22332" }.SequenceEqual((string[])testCase.GetPropertyValue(EngineConstants.WorkItemIdsProperty)!)); } public void ToTestCaseShouldSetDeploymentItemPropertyIfPresent() @@ -157,29 +154,29 @@ public void ToTestCaseShouldSetDeploymentItemPropertyIfPresent() _unitTestElement.DeploymentItems = null; var testCase = _unitTestElement.ToTestCase(); - Verify(testCase.GetPropertyValue(Constants.DeploymentItemsProperty) is null); + Verify(testCase.GetPropertyValue(EngineConstants.DeploymentItemsProperty) is null); _unitTestElement.DeploymentItems = []; testCase = _unitTestElement.ToTestCase(); - Verify(testCase.GetPropertyValue(Constants.DeploymentItemsProperty) is null); + Verify(testCase.GetPropertyValue(EngineConstants.DeploymentItemsProperty) is null); _unitTestElement.DeploymentItems = [new("s", "d")]; testCase = _unitTestElement.ToTestCase(); - Verify(_unitTestElement.DeploymentItems.SequenceEqual(testCase.GetPropertyValue(Constants.DeploymentItemsProperty) as KeyValuePair[])); + Verify(_unitTestElement.DeploymentItems.SequenceEqual(testCase.GetPropertyValue(EngineConstants.DeploymentItemsProperty) as KeyValuePair[])); } [Obsolete("Remove test case when enum entry is removed")] public void ToTestCase_WhenStrategyIsLegacy_UsesDefaultTestCaseId() { #pragma warning disable CA2263 // Prefer generic overload when type is known - foreach (DynamicDataType dataType in EnumPolyfill.GetValues()) + foreach (DynamicDataType dataType in Enum.GetValues()) { var testCase = new UnitTestElement(new("MyMethod", "MyProduct.MyNamespace.MyClass", "MyAssembly", null, TestIdGenerationStrategy.Legacy) { DataType = dataType }).ToTestCase(); var expectedTestCase = new TestCase(testCase.FullyQualifiedName, testCase.ExecutorUri, testCase.Source); Verify(expectedTestCase.Id == testCase.Id); - Verify(testCase.GetPropertyValue(Constants.TestIdGenerationStrategyProperty)!.Equals((int)TestIdGenerationStrategy.Legacy)); + Verify(testCase.GetPropertyValue(EngineConstants.TestIdGenerationStrategyProperty)!.Equals((int)TestIdGenerationStrategy.Legacy)); } #pragma warning restore CA2263 // Prefer generic overload when type is known } @@ -188,7 +185,7 @@ public void ToTestCase_WhenStrategyIsLegacy_UsesDefaultTestCaseId() public void ToTestCase_WhenStrategyIsDisplayName_DoesNotUseDefaultTestCaseId() { #pragma warning disable CA2263 // Prefer generic overload when type is known - foreach (DynamicDataType dataType in EnumPolyfill.GetValues()) + foreach (DynamicDataType dataType in Enum.GetValues()) { var testCase = new UnitTestElement(new("MyMethod", "MyProduct.MyNamespace.MyClass", "MyAssembly", null, TestIdGenerationStrategy.DisplayName) { DataType = dataType }).ToTestCase(); var expectedTestCase = new TestCase(testCase.FullyQualifiedName, testCase.ExecutorUri, testCase.Source); @@ -201,7 +198,7 @@ public void ToTestCase_WhenStrategyIsDisplayName_DoesNotUseDefaultTestCaseId() Verify(expectedTestCase.Id != testCase.Id); } - Verify(testCase.GetPropertyValue(Constants.TestIdGenerationStrategyProperty)!.Equals((int)TestIdGenerationStrategy.DisplayName)); + Verify(testCase.GetPropertyValue(EngineConstants.TestIdGenerationStrategyProperty)!.Equals((int)TestIdGenerationStrategy.DisplayName)); } #pragma warning restore CA2263 // Prefer generic overload when type is known } @@ -209,12 +206,12 @@ public void ToTestCase_WhenStrategyIsDisplayName_DoesNotUseDefaultTestCaseId() public void ToTestCase_WhenStrategyIsData_DoesNotUseDefaultTestCaseId() { #pragma warning disable CA2263 // Prefer generic overload when type is known - foreach (DynamicDataType dataType in EnumPolyfill.GetValues()) + foreach (DynamicDataType dataType in Enum.GetValues()) { var testCase = new UnitTestElement(new("MyMethod", "MyProduct.MyNamespace.MyClass", "MyAssembly", null, TestIdGenerationStrategy.FullyQualified) { DataType = dataType }).ToTestCase(); var expectedTestCase = new TestCase(testCase.FullyQualifiedName, testCase.ExecutorUri, testCase.Source); Verify(expectedTestCase.Id != testCase.Id); - Verify(testCase.GetPropertyValue(Constants.TestIdGenerationStrategyProperty)!.Equals((int)TestIdGenerationStrategy.FullyQualified)); + Verify(testCase.GetPropertyValue(EngineConstants.TestIdGenerationStrategyProperty)!.Equals((int)TestIdGenerationStrategy.FullyQualified)); } #pragma warning restore CA2263 // Prefer generic overload when type is known } @@ -240,7 +237,7 @@ public void ToTestCase_WhenStrategyIsDisplayName_ExamplesOfTestCaseIdUniqueness( new UnitTestElement( new("MyMethod", "MyProduct.MyNamespace.MyClass", "MyAssembly", null, testIdStrategy) { - DataType = DynamicDataType.DataSourceAttribute, + DataType = DynamicDataType.ITestDataSource, }) { DisplayName = "SomeDisplayName", @@ -269,20 +266,20 @@ public void ToTestCase_WhenStrategyIsDisplayName_ExamplesOfTestCaseIdCollision() new UnitTestElement( new("MyMethod", "MyProduct.MyNamespace.MyClass", "MyAssembly", null, testIdStrategy) { - DataType = DynamicDataType.DataSourceAttribute, + DataType = DynamicDataType.None, }) .ToTestCase(), new UnitTestElement( new("MyMethod", "MyProduct.MyNamespace.MyClass", "MyAssembly", null, testIdStrategy) { - DataType = DynamicDataType.DataSourceAttribute, + DataType = DynamicDataType.None, SerializedData = ["1"], }) .ToTestCase(), new UnitTestElement( new("MyMethod", "MyProduct.MyNamespace.MyClass", "MyAssembly", null, testIdStrategy) { - DataType = DynamicDataType.DataSourceAttribute, + DataType = DynamicDataType.None, SerializedData = ["2"], }) .ToTestCase(), @@ -302,7 +299,10 @@ public void ToTestCase_WhenStrategyIsDisplayName_ExamplesOfTestCaseIdCollision() .ToTestCase() ]; - Verify(testCases.Select(tc => tc.Id.ToString()).Distinct().Count() == 1); + // All the test cases with DynamicDataType.None will have the same Id (showing collisions). + // All the test cases with DynamicDataType.ITestDataSource will have the same Id, but different one (showing collisions). + // So for the 5 test cases, we have 2 distinct Ids. + Verify(testCases.Select(tc => tc.Id.ToString()).Distinct().Count() == 2); } public void ToTestCase_WhenStrategyIsFullyQualifiedTest_ExamplesOfTestCaseIdUniqueness() diff --git a/test/UnitTests/MSTestAdapter.UnitTests/ObjectModel/UnitTestResultTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestResultTests.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/ObjectModel/UnitTestResultTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestResultTests.cs diff --git a/test/UnitTests/MSTestAdapter.UnitTests/PlatformServiceProviderTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/PlatformServiceProviderTests.cs similarity index 97% rename from test/UnitTests/MSTestAdapter.UnitTests/PlatformServiceProviderTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/PlatformServiceProviderTests.cs index 8d1f6f8884..2d4e5d21d4 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/PlatformServiceProviderTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/PlatformServiceProviderTests.cs @@ -58,13 +58,12 @@ public void GetTestContextShouldReturnAValidTestContext() { // Arrange. var testMethod = new Mock(); - var writer = new ThreadSafeStringWriter(null!, "test"); var properties = new Dictionary { { "prop", "value" } }; testMethod.Setup(tm => tm.FullClassName).Returns("A.C.M"); testMethod.Setup(tm => tm.Name).Returns("M"); // Act. - PlatformServices.Interface.ITestContext testContext = PlatformServiceProvider.Instance.GetTestContext(testMethod.Object, writer, properties, null!, default); + PlatformServices.Interface.ITestContext testContext = PlatformServiceProvider.Instance.GetTestContext(testMethod.Object, properties, null!, default); // Assert. Verify(testContext.Context.FullyQualifiedTestClassName == "A.C.M"); diff --git a/test/UnitTests/MSTestAdapter.UnitTests/RunConfigurationSettingsTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/RunConfigurationSettingsTests.cs similarity index 100% rename from test/UnitTests/MSTestAdapter.UnitTests/RunConfigurationSettingsTests.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/RunConfigurationSettingsTests.cs diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/DesktopTestDeploymentTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/DesktopTestDeploymentTests.cs index f7f7883ca2..d436619ee5 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/DesktopTestDeploymentTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/DesktopTestDeploymentTests.cs @@ -32,7 +32,7 @@ public DesktopTestDeploymentTests() { _mockReflectionUtility = new Mock(); _mockFileUtility = new Mock(); - _warnings = new List(); + _warnings = []; // Reset adapter settings. MSTestSettingsProvider.Reset(); diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/MSTestSettingsProviderTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/MSTestSettingsProviderTests.cs index be5a238fa1..874367ce73 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/MSTestSettingsProviderTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/MSTestSettingsProviderTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using TestFramework.ForTestingMSTest; @@ -70,4 +71,32 @@ public void LoadShouldReadAndFillInSettings() _settingsProvider.Load(reader); Verify(!MSTestSettingsProvider.Settings.DeploymentEnabled); } + + public void LoadShouldReadAndFillInSettingsFromIConfiguration() + { + Verify(MSTestSettingsProvider.Settings.DeploymentEnabled); + + MSTestSettingsProvider.Load(new MockConfiguration( + new Dictionary() + { + ["mstest:deployment:enabled"] = "false", + }, null)); + + Verify(!MSTestSettingsProvider.Settings.DeploymentEnabled); + } + + private sealed class MockConfiguration : IConfiguration + { + private readonly Dictionary _values; + private readonly string? _defaultValue; + + public MockConfiguration(Dictionary values, string? defaultValue) + { + _values = values; + _defaultValue = defaultValue; + } + + public string? this[string key] + => _values.TryGetValue(key, out string? value) ? value : _defaultValue; + } } diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/ReflectionOperationsTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/ReflectionOperationsTests.cs index dfd8626b64..97159226f6 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/ReflectionOperationsTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/ReflectionOperationsTests.cs @@ -67,9 +67,7 @@ public void GetCustomAttributesOnTypeShouldReturnAllAttributes() } private object[] GetMemberAttributes(Type type, bool inherit) - => _reflectionOperations.GetCustomAttributes(type, inherit) - .Where(x => x.GetType().FullName != "System.Runtime.CompilerServices.NullableContextAttribute") - .ToArray(); + => [.. _reflectionOperations.GetCustomAttributes(type, inherit).Where(x => x.GetType().FullName != "System.Runtime.CompilerServices.NullableContextAttribute")]; public void GetCustomAttributesOnTypeShouldReturnAllAttributesIgnoringBaseInheritance() { @@ -203,7 +201,7 @@ private static string[] GetAttributeValuePairs(object[] attributes) } } - return attribValuePairs.ToArray(); + return [.. attribValuePairs]; } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestContextImplementationTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestContextImplementationTests.cs index fdcfe307d2..92d5588978 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestContextImplementationTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestContextImplementationTests.cs @@ -398,7 +398,7 @@ public void DisplayMessageShouldForwardToIMessageLogger() messageLoggerMock .Setup(l => l.SendMessage(It.IsAny(), It.IsAny())); - _testContextImplementation = new TestContextImplementation(_testMethod.Object, new ThreadSafeStringWriter(null!, "test"), _properties, messageLoggerMock.Object); + _testContextImplementation = new TestContextImplementation(_testMethod.Object, _properties, messageLoggerMock.Object, testRunCancellationToken: null); _testContextImplementation.DisplayMessage(MessageLevel.Informational, "InfoMessage"); _testContextImplementation.DisplayMessage(MessageLevel.Warning, "WarningMessage"); _testContextImplementation.DisplayMessage(MessageLevel.Error, "ErrorMessage"); diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestDeploymentTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestDeploymentTests.cs index 49b2bf0e66..37cf9f5605 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestDeploymentTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestDeploymentTests.cs @@ -33,7 +33,7 @@ public TestDeploymentTests() { _mockReflectionUtility = new Mock(); _mockFileUtility = new Mock(); - _warnings = new List(); + _warnings = []; // Reset adapter settings. MSTestSettingsProvider.Reset(); diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/ThreadSafeStringWriterTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/ThreadSafeStringWriterTests.cs index a1c3c7f4ee..f58616a2cd 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/ThreadSafeStringWriterTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/ThreadSafeStringWriterTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#if false using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using TestFramework.ForTestingMSTest; @@ -127,3 +128,4 @@ public void ThreadSafeStringWriterWritesLinesIntoDifferentWritesSeparately() } } } +#endif diff --git a/test/UnitTests/MSTestAdapter.UnitTests/TestableImplementations/TestablePlatformServiceProvider.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/TestableImplementations/TestablePlatformServiceProvider.cs similarity index 92% rename from test/UnitTests/MSTestAdapter.UnitTests/TestableImplementations/TestablePlatformServiceProvider.cs rename to test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/TestableImplementations/TestablePlatformServiceProvider.cs index 8cbc5c2de4..73acb57073 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/TestableImplementations/TestablePlatformServiceProvider.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/TestableImplementations/TestablePlatformServiceProvider.cs @@ -10,7 +10,6 @@ using ITestDataSource = Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestDataSource; using ITestMethod = Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel.ITestMethod; -using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.TestableImplementations; @@ -70,9 +69,9 @@ public IReflectionOperations2 ReflectionOperations public bool IsGracefulStopRequested { get; set; } - public ITestContext GetTestContext(ITestMethod testMethod, StringWriter writer, IDictionary properties, IMessageLogger messageLogger, UTF.UnitTestOutcome outcome) + public ITestContext GetTestContext(ITestMethod testMethod, IDictionary properties, IMessageLogger messageLogger, UnitTestOutcome outcome) { - var testContextImpl = new TestContextImplementation(testMethod, writer, properties, messageLogger); + var testContextImpl = new TestContextImplementation(testMethod, properties, messageLogger, testRunCancellationToken: null); testContextImpl.SetOutcome(outcome); return testContextImpl; } diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DeploymentUtilityTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DeploymentUtilityTests.cs index 673c1159d9..928a13ca44 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DeploymentUtilityTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DeploymentUtilityTests.cs @@ -42,7 +42,7 @@ public DeploymentUtilityTests() _mockReflectionUtility = new Mock(); _mockFileUtility = new Mock(); _mockAssemblyUtility = new Mock(); - _warnings = new List(); + _warnings = []; _deploymentUtility = new DeploymentUtility( new DeploymentItemUtility(_mockReflectionUtility.Object), diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DesktopReflectionUtilityTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DesktopReflectionUtilityTests.cs index 2e7348f8e9..80b9663729 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DesktopReflectionUtilityTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DesktopReflectionUtilityTests.cs @@ -40,7 +40,7 @@ internal static string[] GetAttributeValuePairs(IEnumerable attributes) } } - return attribValuePairs.ToArray(); + return [.. attribValuePairs]; } [DummyA("ba")] diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/VSInstallationUtilitiesTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/VSInstallationUtilitiesTests.cs index 1f772ec276..5f836c7f96 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/VSInstallationUtilitiesTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/VSInstallationUtilitiesTests.cs @@ -14,7 +14,7 @@ public void CheckResolutionPathsDoNotContainPrivateAssembliesPathTest() { TestSourceHost isolatedHost = new(null!, null, null); List paths = isolatedHost.GetResolutionPaths(Assembly.GetExecutingAssembly().FullName, true); - Verify(!paths.Contains(Constants.PublicAssemblies) || paths.Contains(Constants.PrivateAssemblies)); + Verify(!paths.Contains(EngineConstants.PublicAssemblies) || paths.Contains(EngineConstants.PrivateAssemblies)); } } #endif diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns10FileUtilityTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns10FileUtilityTests.cs index adea291520..5f83427888 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns10FileUtilityTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns10FileUtilityTests.cs @@ -105,10 +105,10 @@ public void AddFilesWithIgnoreDirectory() _fileUtility.Setup(fu => fu.GetDirectoriesInADirectory(It.IsAny())).Returns(directory => { IEnumerable directories = allFiles.Where(file => IsFileUnderDirectory(directory, file)).Select(file => Path.GetDirectoryName(file)!).Distinct(); - return directories.ToArray(); + return [.. directories]; }); - _fileUtility.Setup(fu => fu.GetFilesInADirectory(It.IsAny())).Returns(directory => allFiles.Where(file => Path.GetDirectoryName(file)!.Equals(directory, StringComparison.OrdinalIgnoreCase)).Distinct().ToArray()); + _fileUtility.Setup(fu => fu.GetFilesInADirectory(It.IsAny())).Returns(directory => [.. allFiles.Where(file => Path.GetDirectoryName(file)!.Equals(directory, StringComparison.OrdinalIgnoreCase)).Distinct()]); // Act List files = _fileUtility.Object.AddFilesFromDirectory("C:\\MainClock", directory => directory.Contains("Results"), false); @@ -145,10 +145,10 @@ public void AddFilesWithNoIgnoreDirectory() _fileUtility.Setup(fu => fu.GetDirectoriesInADirectory(It.IsAny())).Returns(directory => { IEnumerable directories = allFiles.Where(file => IsFileUnderDirectory(directory, file)).Select(file => Path.GetDirectoryName(file)!).Distinct(); - return directories.ToArray(); + return [.. directories]; }); - _fileUtility.Setup(fu => fu.GetFilesInADirectory(It.IsAny())).Returns(directory => allFiles.Where(file => Path.GetDirectoryName(file)!.Equals(directory, StringComparison.OrdinalIgnoreCase)).Distinct().ToArray()); + _fileUtility.Setup(fu => fu.GetFilesInADirectory(It.IsAny())).Returns(directory => [.. allFiles.Where(file => Path.GetDirectoryName(file)!.Equals(directory, StringComparison.OrdinalIgnoreCase)).Distinct()]); // Act List files = _fileUtility.Object.AddFilesFromDirectory("C:\\MainClock", false); @@ -171,9 +171,8 @@ private void SetupMockFileAPIs(string[] files) { _fileUtility.Setup(fu => fu.GetFilesInADirectory(It.IsAny())).Returns((string dp) => #pragma warning disable CA1865 // Use char overload - files.Where(f => f.Contains(dp) && f.LastIndexOf('\\') == (f.IndexOf(dp, StringComparison.Ordinal) + dp.Length) && !f.EndsWith("\\", StringComparison.Ordinal)) - .ToArray()); - _fileUtility.Setup(fu => fu.GetDirectoriesInADirectory(It.IsAny())).Returns((string dp) => files.Where(f => f.Contains(dp) && f.LastIndexOf('\\') > (f.IndexOf(dp, StringComparison.Ordinal) + dp.Length)) + [.. files.Where(f => f.Contains(dp) && f.LastIndexOf('\\') == (f.IndexOf(dp, StringComparison.Ordinal) + dp.Length) && !f.EndsWith("\\", StringComparison.Ordinal))]); + _fileUtility.Setup(fu => fu.GetDirectoriesInADirectory(It.IsAny())).Returns((string dp) => [.. files.Where(f => f.Contains(dp) && f.LastIndexOf('\\') > (f.IndexOf(dp, StringComparison.Ordinal) + dp.Length)) .Select(f => { #pragma warning disable IDE0057 // Use range operator @@ -183,8 +182,7 @@ private void SetupMockFileAPIs(string[] files) return f.Substring(0, dp.Length + 1 + val.IndexOf('\\')); #pragma warning restore IDE0057 // Use range operator }) - .Distinct() - .ToArray()); + .Distinct()]); } #endregion diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13DeploymentItemUtilityTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13DeploymentItemUtilityTests.cs index 06ee4478ee..0cdb0d537d 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13DeploymentItemUtilityTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13DeploymentItemUtilityTests.cs @@ -34,7 +34,7 @@ public DeploymentItemUtilityTests() { _mockReflectionUtility = new Mock(); _deploymentItemUtility = new DeploymentItemUtility(_mockReflectionUtility.Object); - _warnings = new List(); + _warnings = []; } #region GetClassLevelDeploymentItems tests diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/ExceptionExtensionsTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/Extensions/ExceptionExtensionsTests.cs deleted file mode 100644 index 4bea35ee12..0000000000 --- a/test/UnitTests/MSTestAdapter.UnitTests/Extensions/ExceptionExtensionsTests.cs +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions; - -using TestFramework.ForTestingMSTest; - -using UTF = Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Extensions; - -/// -/// Tests for class. -/// -public class ExceptionExtensionsTests : TestContainer -{ - #region TryGetExceptionMessage scenarios - - public void ExceptionTryGetMessageGetsTheExceptionMessage() - { - var exception = new Exception("dummyMessage"); - - Verify(exception.TryGetMessage() == "dummyMessage"); - } - - public void ExceptionTryGetMessageReturnsEmptyStringIfExceptionMessageIsNull() - { - var exception = new DummyException(() => null!); - - Verify(exception.TryGetMessage() == string.Empty); - } - - public void ExceptionTryGetMessageReturnsErrorMessageIfExceptionIsNull() - { - string errorMessage = string.Format(CultureInfo.InvariantCulture, Resource.UTF_FailedToGetExceptionMessage, "null"); - - var exception = (Exception?)null; - - Verify(errorMessage == exception.TryGetMessage()); - } - - public void ExceptionTryGetMessageShouldThrowIfExceptionMessageThrows() - { - var exception = new DummyException(() => throw new NotImplementedException()); - - VerifyThrows(() => exception.TryGetMessage()); - } - - #endregion - - #region TryGetStackTraceInformation scenarios - - public void TryGetStackTraceInformationReturnsNullIfExceptionStackTraceIsNullOrEmpty() - { - var exception = new DummyExceptionForStackTrace(() => null!); - - Verify(exception.TryGetStackTraceInformation() is null); - } - - public void TryGetStackTraceInformationReturnsStackTraceForAnException() - { - var exception = new DummyExceptionForStackTrace(() => " at A()\r\n at B()"); - - MSTest.TestAdapter.ObjectModel.StackTraceInformation? stackTraceInformation = exception.TryGetStackTraceInformation(); - - Verify(stackTraceInformation!.ErrorStackTrace.StartsWith(" at A()", StringComparison.Ordinal)); - Verify(stackTraceInformation.ErrorFilePath is null); - Verify(stackTraceInformation.ErrorLineNumber == 0); - } - - public void TryGetStackTraceInformationShouldThrowIfStackTraceThrows() - { - var exception = new DummyExceptionForStackTrace(() => throw new NotImplementedException()); - - VerifyThrows(() => exception.TryGetStackTraceInformation()); - } - -#pragma warning disable CA1710 // Identifiers should have correct suffix - public class DummyExceptionForStackTrace : Exception -#pragma warning restore CA1710 // Identifiers should have correct suffix - { - private readonly Func _getStackTrace; - - public DummyExceptionForStackTrace(Func getStackTrace) => _getStackTrace = getStackTrace; - - public override string StackTrace => _getStackTrace(); - } - - internal class DummyException : Exception - { - private readonly Func _getMessage; - - public DummyException(Func message) => _getMessage = message; - - public override string Message => _getMessage(); - } - - #endregion - - #region IsUnitTestAssertException scenarios - - public void IsUnitTestAssertExceptionReturnsTrueIfExceptionIsAssertException() - { - var exception = new UTF.AssertInconclusiveException(); - Verify(exception.TryGetUnitTestAssertException(out _, out _, out _)); - } - - public void IsUnitTestAssertExceptionReturnsFalseIfExceptionIsNotAssertException() - { - var exception = new NotImplementedException(); - Verify(!exception.TryGetUnitTestAssertException(out _, out _, out _)); - } - - public void IsUnitTestAssertExceptionSetsOutcomeAsInconclusiveIfAssertInconclusiveException() - { - var exception = new UTF.AssertInconclusiveException("Dummy Message", new NotImplementedException("notImplementedException")); - exception.TryGetUnitTestAssertException(out UTF.UnitTestOutcome outcome, out string? exceptionMessage, out _); - - Verify(outcome == UTF.UnitTestOutcome.Inconclusive); - Verify(exceptionMessage == "Dummy Message"); - } - - public void IsUnitTestAssertExceptionSetsOutcomeAsFailedIfAssertFailedException() - { - var exception = new UTF.AssertFailedException("Dummy Message", new NotImplementedException("notImplementedException")); - exception.TryGetUnitTestAssertException(out UTF.UnitTestOutcome outcome, out string? exceptionMessage, out _); - - Verify(outcome == UTF.UnitTestOutcome.Failed); - Verify(exceptionMessage == "Dummy Message"); - } - #endregion - - #region GetRealException scenarios - public void GetRealExceptionGetsTheTopExceptionWhenThereIsJustOne() - { - var exception = new InvalidOperationException(); - Exception actual = exception.GetRealException(); - - Verify(actual is InvalidOperationException); - } - - public void GetRealExceptionGetsTheInnerExceptionWhenTheExceptionIsTargetInvocation() - { - var exception = new TargetInvocationException(new InvalidOperationException()); - Exception actual = exception.GetRealException(); - - Verify(actual is InvalidOperationException); - } - - public void GetRealExceptionGetsTheTargetInvocationExceptionWhenTargetInvocationIsProvidedWithNullInnerException() - { - var exception = new TargetInvocationException(null); - Exception actual = exception.GetRealException(); - - Verify(actual is TargetInvocationException); - } - - public void GetRealExceptionGetsTheInnerMostRealException() - { - var exception = new TargetInvocationException(new TargetInvocationException(new TargetInvocationException(new InvalidOperationException()))); - Exception actual = exception.GetRealException(); - - Verify(actual is InvalidOperationException); - } - - public void GetRealExceptionGetsTheInnerMostTargetInvocationException() - { - var exception = new TargetInvocationException(new TargetInvocationException(new TargetInvocationException("inner most", null))); - Exception actual = exception.GetRealException(); - - Verify(actual is TargetInvocationException); - Verify(actual.Message == "inner most"); - } - - public void GetRealExceptionGetsTheInnerExceptionWhenTheExceptionIsTypeInitialization() - { - var exception = new TypeInitializationException("some type", new InvalidOperationException()); - Exception actual = exception.GetRealException(); - - Verify(actual is InvalidOperationException); - } - - public void GetRealExceptionGetsTheTypeInitializationExceptionWhenTypeInitializationIsProvidedWithNullInnerException() - { - var exception = new TypeInitializationException("some type", null); - Exception actual = exception.GetRealException(); - - Verify(actual is TypeInitializationException); - } - - public void GetRealExceptionGetsTheInnerMostRealExceptionOfTypeInitialization() - { - var exception = new TypeInitializationException("some type", new TypeInitializationException("some type", new TypeInitializationException("some type", new InvalidOperationException()))); - Exception actual = exception.GetRealException(); - - Verify(actual is InvalidOperationException); - } - - public void GetRealExceptionGetsTheInnerMostTypeInitializationException() - { - var exception = new TypeInitializationException("some type", new TypeInitializationException("some type", new TypeInitializationException("inner most", null))); - Exception actual = exception.GetRealException(); - - Verify(actual is TypeInitializationException); - Verify(actual.Message == "The type initializer for 'inner most' threw an exception."); - } - #endregion -} diff --git a/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj b/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj index 2f3eddd243..bedb8b4472 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj +++ b/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj @@ -2,7 +2,7 @@ net48 - net6.0;net462;$(NetStandardNetFrameworkHolder);netcoreapp3.1 + net6.0;net7.0;net462;$(NetStandardNetFrameworkHolder);netcoreapp3.1 $(TargetFrameworks);$(WinUiMinimum) true Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests @@ -21,6 +21,10 @@ + + + + diff --git a/test/UnitTests/MSTestAdapter.UnitTests/MSTestDiscovererTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/MSTestDiscovererTests.cs index c738849994..ea65306c21 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/MSTestDiscovererTests.cs +++ b/test/UnitTests/MSTestAdapter.UnitTests/MSTestDiscovererTests.cs @@ -226,4 +226,15 @@ public void AreValidSourcesShouldReturnFalseForInvalidSourceExtensions() _testablePlatformServiceProvider.MockTestSourceValidator.SetupGet(ts => ts.ValidSourceExtensions).Returns(new List { ".nte", ".tep" }); Verify(!MSTestDiscovererHelpers.AreValidSources(new List { "dummy.te" })); } + + [TestClass] + public class DummyClass + { + [TestMethod] + public void DummyTestMethod() + { + // This is a dummy test method to ensure that the MSTestDiscoverer can discover tests. + // It does not perform any assertions or operations. + } + } } diff --git a/test/UnitTests/MSTestAdapter.UnitTests/MSTestExecutorTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/MSTestExecutorTests.cs index 65ac7fc0d9..ca7774fca5 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/MSTestExecutorTests.cs +++ b/test/UnitTests/MSTestAdapter.UnitTests/MSTestExecutorTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; @@ -32,7 +33,7 @@ public void MSTestExecutorShouldProvideTestExecutionUri() var extensionUriString = (ExtensionUriAttribute)testExecutor.GetType().GetCustomAttributes(typeof(ExtensionUriAttribute), false).Single(); - Verify(extensionUriString.ExtensionUri == MSTest.TestAdapter.Constants.ExecutorUriString); + Verify(extensionUriString.ExtensionUri == EngineConstants.ExecutorUriString); } public async Task RunTestsShouldNotExecuteTestsIfTestSettingsIsGiven() diff --git a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AppInsightsProviderTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AppInsightsProviderTests.cs index 95068374c5..c281ef4a14 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AppInsightsProviderTests.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AppInsightsProviderTests.cs @@ -32,7 +32,7 @@ public void Platform_CancellationToken_Cancellation_Should_Exit_Gracefully() Mock testApplicationCancellationTokenSource = new(); testApplicationCancellationTokenSource.Setup(x => x.CancellationToken).Returns(cancellationTokenSource.Token); - List events = new(); + List events = []; Mock testTelemetryClient = new(); testTelemetryClient.Setup(x => x.TrackEvent(It.IsAny(), It.IsAny>(), It.IsAny>())) .Callback((string eventName, Dictionary properties, Dictionary metrics) => diff --git a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Helpers/TestExtension.cs b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Helpers/TestExtension.cs index 85bdd02fc3..5019e8d619 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Helpers/TestExtension.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Helpers/TestExtension.cs @@ -5,13 +5,13 @@ namespace Microsoft.Testing.Extensions.UnitTests.Helpers; internal sealed class TestExtension : IExtension { - public string Uid { get; } = "Uid"; + public string Uid => "Uid"; - public string Version { get; } = "Version"; + public string Version => "Version"; - public string DisplayName { get; } = "DisplayName"; + public string DisplayName => "DisplayName"; - public string Description { get; } = "Description"; + public string Description => "Description"; public Task IsEnabledAsync() => Task.FromResult(true); } diff --git a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs index 0f1a96c59d..1dd7387681 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs @@ -27,7 +27,7 @@ public class TrxTests private readonly Mock _testFrameworkMock = new(); private readonly Mock _testApplicationModuleInfoMock = new(); private readonly Mock _fileSystem = new(); - private readonly Dictionary> _artifactsByExtension = new(); + private readonly Dictionary> _artifactsByExtension = []; [TestMethod] public async Task TrxReportEngine_GenerateReportAsyncWithNullAdapterSupportTrxCapability_TrxDoesNotContainClassName() @@ -68,7 +68,7 @@ public async Task TrxReportEngine_GenerateReportAsyncWithNotExecutedTests_TrxExe XDocument xml = memoryStream.TrxContent; AssertTrxOutcome(xml, "Completed"); string trxContent = xml.ToString(); - Assert.IsTrue(trxContent.Contains(@"notExecuted=""1""")); + Assert.Contains(@"notExecuted=""1""", trxContent); } [TestMethod] @@ -89,7 +89,7 @@ public async Task TrxReportEngine_GenerateReportAsyncWithTimeoutTests_TrxTimeout XDocument xml = memoryStream.TrxContent; AssertTrxOutcome(xml, "Completed"); string trxContent = xml.ToString(); - Assert.IsTrue(trxContent.Contains(@"timeout=""1""")); + Assert.Contains(@"timeout=""1""", trxContent); } [TestMethod] @@ -122,7 +122,7 @@ public async Task TrxReportEngine_GenerateReportAsync_WithArgumentTrxReportFileN _ = _commandLineOptionsMock.Setup(_ => _.TryGetOptionArgumentList(TrxReportGeneratorCommandLine.TrxReportFileNameOptionName, out argumentTrxReportFileName)).Returns(true); PropertyBag propertyBag = new(new PassedTestNodeStateProperty()); TrxReportEngine trxReportEngine = GenerateTrxReportEngine(1, 0, propertyBag, memoryStream, isExplicitFileName: true); - _ = _fileSystem.Setup(x => x.Exists(It.IsAny())).Returns(true); + _ = _fileSystem.Setup(x => x.ExistFile(It.IsAny())).Returns(true); // Act (string fileName, string? warning) = await trxReportEngine.GenerateReportAsync(); @@ -405,7 +405,7 @@ public async Task TrxReportEngine_GenerateReportAsync_WithAdapterSupportTrxCapab XDocument xml = memoryStream.TrxContent; AssertTrxOutcome(xml, "Completed"); string trxContent = xml.ToString(); - Assert.IsTrue(trxContent.Contains(@"className=""TrxFullyQualifiedTypeName"), trxContent); + Assert.Contains(@"className=""TrxFullyQualifiedTypeName", trxContent, trxContent); } [TestMethod] @@ -503,6 +503,51 @@ public async Task TrxReportEngine_GenerateReportAsync_FileAlreadyExists_WillRetr Assert.AreEqual(4, retryCount); } + [TestMethod] + public async Task TrxReportEngine_GenerateReportAsync_WithMetadataProperties_TrxHandlesProperties() + { + // Arrange + using MemoryFileStream memoryStream = new(); + TrxReportEngine trxReportEngine = GenerateTrxReportEngine(1, 0, + new( + new PassedTestNodeStateProperty(), + new TestMetadataProperty("Owner", "ValueOfOwner"), + new TestMetadataProperty("Priority", "5"), + new TestMetadataProperty("MyProperty1", "MyValue1"), + new TestMetadataProperty("MyProperty2", "MyValue2")), memoryStream); + + // Act + (string fileName, string? warning) = await trxReportEngine.GenerateReportAsync(); + + // Assert + Assert.IsNull(warning); + AssertExpectedTrxFileName(fileName); + Assert.IsNotNull(memoryStream.TrxContent); + XDocument xml = memoryStream.TrxContent; + AssertTrxOutcome(xml, "Completed"); + string trxContent = xml.ToString(); + string trxContentsPattern = @" + + + + + + + + MyProperty2 + MyValue2 + + + MyProperty1 + MyValue1 + + + + + "; + Assert.IsTrue(Regex.IsMatch(trxContent, trxContentsPattern)); + } + private static void AssertTrxOutcome(XDocument xml, string expectedOutcome) { Assert.IsNotNull(xml); @@ -516,7 +561,7 @@ private static void AssertTrxOutcome(XDocument xml, string expectedOutcome) } private static void AssertExpectedTrxFileName(string fileName) - => Assert.IsTrue(fileName.Equals("_MachineName_0001-01-01_00_00_00.000.trx", StringComparison.Ordinal)); + => Assert.IsTrue(fileName.Equals("_MachineName_0001-01-01_00_00_00.0000000.trx", StringComparison.Ordinal)); private TrxReportEngine GenerateTrxReportEngine(int passedTestsCount, int failedTestsCount, PropertyBag propertyBag, MemoryFileStream memoryStream, bool? adapterSupportTrxCapability = null, int notExecutedTestsCount = 0, int timeoutTestsCount = 0, @@ -531,7 +576,7 @@ private TrxReportEngine GenerateTrxReportEngine(int passedTestsCount, int failed DateTime testStartTime = DateTime.Now; CancellationToken cancellationToken = CancellationToken.None; - _ = _fileSystem.Setup(x => x.Exists(It.IsAny())).Returns(false); + _ = _fileSystem.Setup(x => x.ExistFile(It.IsAny())).Returns(false); _ = _fileSystem.Setup(x => x.NewFileStream(It.IsAny(), isExplicitFileName ? FileMode.Create : FileMode.CreateNew)) .Returns(memoryStream); diff --git a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/CommandLine/RunSettingsCommandLineOptionsProviderTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/CommandLine/RunSettingsCommandLineOptionsProviderTests.cs index 1609ade663..8788c56af4 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/CommandLine/RunSettingsCommandLineOptionsProviderTests.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/CommandLine/RunSettingsCommandLineOptionsProviderTests.cs @@ -20,7 +20,7 @@ public async Task RunSettingsOption_WhenFileDoesNotExist_IsNotValid() // Arrange const string filePath = "file"; var fileSystem = new Mock(MockBehavior.Strict); - fileSystem.Setup(fs => fs.Exists(It.IsAny())).Returns(false); + fileSystem.Setup(fs => fs.ExistFile(It.IsAny())).Returns(false); var provider = new RunSettingsCommandLineOptionsProvider(new TestExtension(), fileSystem.Object); CommandLineOption option = provider.GetCommandLineOptions().Single(); @@ -39,7 +39,7 @@ public async Task RunSettingsOption_WhenFileCannotBeOpen_IsNotValid() // Arrange const string filePath = "file"; var fileSystem = new Mock(MockBehavior.Strict); - fileSystem.Setup(fs => fs.Exists(filePath)).Returns(true); + fileSystem.Setup(fs => fs.ExistFile(filePath)).Returns(true); fileSystem.Setup(fs => fs.NewFileStream(filePath, FileMode.Open, FileAccess.Read)).Throws(new IOException()); var provider = new RunSettingsCommandLineOptionsProvider(new TestExtension(), fileSystem.Object); @@ -59,7 +59,7 @@ public async Task RunSettingsOption_WhenFileExistsAndCanBeOpen_IsValid() // Arrange const string filePath = "file"; var fileSystem = new Mock(MockBehavior.Strict); - fileSystem.Setup(fs => fs.Exists(filePath)).Returns(true); + fileSystem.Setup(fs => fs.ExistFile(filePath)).Returns(true); fileSystem.Setup(fs => fs.NewFileStream(filePath, FileMode.Open, FileAccess.Read)).Returns(new Mock().Object); var provider = new RunSettingsCommandLineOptionsProvider(new TestExtension(), fileSystem.Object); diff --git a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/Helpers/TestExtension.cs b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/Helpers/TestExtension.cs index fd087790e7..71ba44329a 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/Helpers/TestExtension.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/Helpers/TestExtension.cs @@ -5,13 +5,13 @@ namespace Microsoft.Testing.Extensions.VSTestBridge.UnitTests.Helpers; internal sealed class TestExtension : IExtension { - public string Uid { get; } = "Uid"; + public string Uid => "Uid"; - public string Version { get; } = "Version"; + public string Version => "Version"; - public string DisplayName { get; } = "DisplayName"; + public string DisplayName => "DisplayName"; - public string Description { get; } = "Description"; + public string Description => "Description"; public Task IsEnabledAsync() => Task.FromResult(true); } diff --git a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/ObjectModelConvertersTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/ObjectModelConvertersTests.cs index 09809de7f8..a619ae84ad 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/ObjectModelConvertersTests.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/ObjectModelConvertersTests.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - using Microsoft.Testing.Extensions.TrxReport.Abstractions; using Microsoft.Testing.Extensions.VSTestBridge.ObjectModel; using Microsoft.Testing.Platform.Capabilities.TestFramework; @@ -23,22 +21,25 @@ public sealed class ObjectModelConvertersTests private static readonly IClientInfo ClientInfo = new ClientInfoService(WellKnownClients.VisualStudio, "1.0.0"); [TestMethod] - public void ToTestNode_WhenTestCaseHasDisplayName_TestNodeDisplayNameUsesIt() + [DataRow(true)] + [DataRow(false)] + public void ToTestNode_WhenTestCaseHasDisplayName_TestNodeDisplayNameUsesIt(bool useFullyQualifiedNameAsUid) { TestCase testCase = new("SomeFqn", new("executor://uri", UriKind.Absolute), "source.cs") { DisplayName = "MyDisplayName", }; - var testNode = testCase.ToTestNode(false, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testCase.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid, null, new ConsoleCommandLineOptions(), ClientInfo); Assert.AreEqual("MyDisplayName", testNode.DisplayName); + Assert.AreEqual(useFullyQualifiedNameAsUid ? "SomeFqn" : testCase.Id.ToString(), testNode.Uid.Value); } [TestMethod] public void ToTestNode_WhenTestCaseHasNoDisplayName_TestNodeDisplayNameUsesIt() { TestCase testCase = new("SomeFqn", new("executor://uri", UriKind.Absolute), "source.cs"); - var testNode = testCase.ToTestNode(false, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testCase.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo); Assert.AreEqual("SomeFqn", testNode.DisplayName); } @@ -50,7 +51,7 @@ public void ToTestNode_WhenTestResultHasCodeFilePath_SetsTestFileLocationPropert { CodeFilePath = "FilePath", }); - var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo); Assert.AreEqual("FilePath", testNode.Properties.Single().FilePath); } @@ -63,10 +64,10 @@ public void ToTestNode_WhenTestResultOutcomeIsFailed_TestNodePropertiesContainFa ErrorMessage = "SomeErrorMessage", ErrorStackTrace = "SomeStackTrace", }; - var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo); - FailedTestNodeStateProperty[] failedTestNodeStateProperties = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(1, failedTestNodeStateProperties.Length); + FailedTestNodeStateProperty[] failedTestNodeStateProperties = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, failedTestNodeStateProperties); Assert.IsTrue(failedTestNodeStateProperties[0].Exception is VSTestException); Assert.AreEqual(testResult.ErrorStackTrace, failedTestNodeStateProperties[0].Exception!.StackTrace); Assert.AreEqual(testResult.ErrorMessage, failedTestNodeStateProperties[0].Exception!.Message); @@ -76,13 +77,15 @@ public void ToTestNode_WhenTestResultOutcomeIsFailed_TestNodePropertiesContainFa public void ToTestNode_WhenTestResultHasMSTestDiscovererTestCategoryTestProperty_TestNodePropertiesContainTheCategoryInTraits() { TestResult testResult = new(new TestCase("SomeFqn", new("executor://uri", UriKind.Absolute), "source.cs")); - var testCategoryProperty = TestProperty.Register("MSTestDiscoverer.TestCategory", "Label", typeof(string[]), TestPropertyAttributes.None, typeof(TestCase)); +#pragma warning disable CS0618 // Type or member is obsolete + var testCategoryProperty = TestProperty.Register("MSTestDiscoverer.TestCategory", "Label", typeof(string[]), TestPropertyAttributes.Trait, typeof(TestCase)); +#pragma warning restore CS0618 // Type or member is obsolete testResult.SetPropertyValue(testCategoryProperty, ["category1"]); - var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); - TestMetadataProperty[] testMetadatas = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(1, testMetadatas.Length); + TestMetadataProperty[] testMetadatas = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, testMetadatas); Assert.AreEqual("category1", testMetadatas[0].Key); Assert.AreEqual(string.Empty, testMetadatas[0].Value); } @@ -91,14 +94,16 @@ public void ToTestNode_WhenTestResultHasMSTestDiscovererTestCategoryTestProperty public void ToTestNode_WhenTestResultHasMSTestDiscovererTestCategoryTestPropertyWithTrxEnabled_TestNodePropertiesContainTrxCategoriesProperty() { TestResult testResult = new(new TestCase("assembly.class.SomeFqn", new("executor://uri", UriKind.Absolute), "source.cs")); - var testCategoryProperty = TestProperty.Register("MSTestDiscoverer.TestCategory", "Label", typeof(string[]), TestPropertyAttributes.None, typeof(TestCase)); +#pragma warning disable CS0618 // Type or member is obsolete + var testCategoryProperty = TestProperty.Register("MSTestDiscoverer.TestCategory", "Label", typeof(string[]), TestPropertyAttributes.Trait, typeof(TestCase)); +#pragma warning restore CS0618 // Type or member is obsolete testResult.SetPropertyValue(testCategoryProperty, ["category1"]); - var testNode = testResult.ToTestNode(true, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: true, useFullyQualifiedNameAsUid: false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); - TrxCategoriesProperty[] trxCategoriesProperty = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(1, trxCategoriesProperty.Length); - Assert.AreEqual(1, trxCategoriesProperty[0].Categories.Length); + TrxCategoriesProperty[] trxCategoriesProperty = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, trxCategoriesProperty); + Assert.HasCount(1, trxCategoriesProperty[0].Categories); Assert.AreEqual("category1", trxCategoriesProperty[0].Categories[0]); } @@ -111,10 +116,10 @@ public void ToTestNode_WhenTestCaseHasOriginalExecutorUriProperty_TestNodeProper testCase.SetPropertyValue(originalExecutorUriProperty, new Uri("https://vs.com/")); - var testNode = testCase.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); + var testNode = testCase.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); - SerializableKeyValuePairStringProperty[] serializableKeyValuePairStringProperty = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(3, serializableKeyValuePairStringProperty.Length); + SerializableKeyValuePairStringProperty[] serializableKeyValuePairStringProperty = [.. testNode.Properties.OfType()]; + Assert.HasCount(3, serializableKeyValuePairStringProperty); Assert.AreEqual(VSTestTestNodeProperties.OriginalExecutorUriPropertyName, serializableKeyValuePairStringProperty[0].Key); Assert.AreEqual("https://vs.com/", serializableKeyValuePairStringProperty[0].Value); } @@ -124,9 +129,9 @@ public void ToTestNode_WhenTestResultHasFullyQualifiedTypeAndTrxEnabled_TestNode { TestResult testResult = new(new TestCase("assembly.class.test", new("executor://uri", UriKind.Absolute), "source.cs")); - var testNode = testResult.ToTestNode(true, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: true, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo); - Assert.AreEqual(1, testNode.Properties.OfType()?.Length); + Assert.AreEqual(0, testNode.Properties.OfType()?.Length); Assert.AreEqual("assembly.class", testNode.Properties.Single().FullyQualifiedTypeName); } @@ -135,9 +140,9 @@ public void ToTestNode_WhenTestResultHasNoFullyQualifiedTypeAndTrxEnabled_Throws { TestResult testResult = new(new TestCase("test", new("executor://uri", UriKind.Absolute), "source.cs")); - string errorMessage = Assert.ThrowsException(() => testResult.ToTestNode(true, null, new ConsoleCommandLineOptions(), ClientInfo)).Message; + string errorMessage = Assert.ThrowsExactly(() => testResult.ToTestNode(isTrxEnabled: true, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo)).Message; - Assert.IsTrue(errorMessage.Contains("Unable to parse fully qualified type name from test case: ")); + Assert.Contains("Unable to parse fully qualified type name from test case: ", errorMessage); } [TestMethod] @@ -153,7 +158,7 @@ public void ToTestNode_FromTestResult_TestNodePropertiesContainCorrectTimingProp EndTime = endTime, Duration = duration, }; - var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo); var testResultTimingProperty = new TimingProperty(new(startTime, endTime, duration), []); Assert.AreEqual(testNode.Properties.OfType()[0], testResultTimingProperty); @@ -167,13 +172,13 @@ public void ToTestNode_WhenTestResultOutcomeIsNotFoundWithoutSetErrorMessage_Tes Outcome = TestOutcome.NotFound, ErrorStackTrace = "SomeStackTrace", }; - var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo); - ErrorTestNodeStateProperty[] errorTestNodeStateProperties = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(1, errorTestNodeStateProperties.Length); + ErrorTestNodeStateProperty[] errorTestNodeStateProperties = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, errorTestNodeStateProperties); Assert.IsTrue(errorTestNodeStateProperties[0].Exception is VSTestException); Assert.AreEqual(testResult.ErrorStackTrace, errorTestNodeStateProperties[0].Exception!.StackTrace); - Assert.IsTrue(errorTestNodeStateProperties[0].Exception!.Message.Contains("Not found")); + Assert.Contains("Not found", errorTestNodeStateProperties[0].Exception!.Message); } [TestMethod] @@ -183,10 +188,10 @@ public void ToTestNode_WhenTestResultOutcomeIsSkipped_TestNodePropertiesContainS { Outcome = TestOutcome.Skipped, }; - var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo); - SkippedTestNodeStateProperty[] skipTestNodeStateProperties = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(1, skipTestNodeStateProperties.Length); + SkippedTestNodeStateProperty[] skipTestNodeStateProperties = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, skipTestNodeStateProperties); } [TestMethod] @@ -196,10 +201,10 @@ public void ToTestNode_WhenTestResultOutcomeIsNone_TestNodePropertiesContainSkip { Outcome = TestOutcome.None, }; - var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo); - SkippedTestNodeStateProperty[] skipTestNodeStateProperties = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(1, skipTestNodeStateProperties.Length); + SkippedTestNodeStateProperty[] skipTestNodeStateProperties = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, skipTestNodeStateProperties); } [TestMethod] @@ -209,10 +214,10 @@ public void ToTestNode_WhenTestResultOutcomeIsPassed_TestNodePropertiesContainPa { Outcome = TestOutcome.Passed, }; - var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, null, new ConsoleCommandLineOptions(), ClientInfo); - PassedTestNodeStateProperty[] passedTestNodeStateProperties = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(1, passedTestNodeStateProperties.Length); + PassedTestNodeStateProperty[] passedTestNodeStateProperties = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, passedTestNodeStateProperties); } [TestMethod] @@ -220,10 +225,10 @@ public void ToTestNode_WhenTestCaseHasUidAndDisplayNameWithWellKnownClient_TestN { var testCase = new TestCase("SomeFqn", new("executor://uri", UriKind.Absolute), "source.cs"); - var testNode = testCase.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); + var testNode = testCase.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); - SerializableKeyValuePairStringProperty[] errorTestNodeStateProperties = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(2, errorTestNodeStateProperties.Length, "Expected 2 SerializableKeyValuePairStringProperty"); + SerializableKeyValuePairStringProperty[] errorTestNodeStateProperties = [.. testNode.Properties.OfType()]; + Assert.HasCount(2, errorTestNodeStateProperties); Assert.AreEqual("vstest.TestCase.FullyQualifiedName", errorTestNodeStateProperties[0].Key); Assert.AreEqual("SomeFqn", errorTestNodeStateProperties[0].Value); Assert.AreEqual("vstest.TestCase.Id", errorTestNodeStateProperties[1].Key); @@ -238,10 +243,10 @@ public void ToTestNode_WhenTestResultHasTraits_TestNodePropertiesContainIt() Traits = { new Trait("key", "value") }, }; - var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); - TestMetadataProperty[] testMetadatas = testNode.Properties.OfType().ToArray(); - Assert.AreEqual(1, testMetadatas.Length); + TestMetadataProperty[] testMetadatas = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, testMetadatas); Assert.AreEqual("key", testMetadatas[0].Key); Assert.AreEqual("value", testMetadatas[0].Value); } @@ -259,10 +264,10 @@ public void ToTestNode_WhenTestResultHasMultipleStandardOutputMessages_TestNodeP }, }; - var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); - StandardOutputProperty[] standardOutputProperties = testNode.Properties.OfType().ToArray(); - Assert.IsTrue(standardOutputProperties.Length == 1); + StandardOutputProperty[] standardOutputProperties = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, standardOutputProperties); Assert.AreEqual($"message1{Environment.NewLine}message2", standardOutputProperties[0].StandardOutput); } @@ -279,10 +284,10 @@ public void ToTestNode_WhenTestResultHasMultipleStandardErrorMessages_TestNodePr }, }; - var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); + var testNode = testResult.ToTestNode(isTrxEnabled: false, useFullyQualifiedNameAsUid: false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions(), ClientInfo); - StandardErrorProperty[] standardErrorProperties = testNode.Properties.OfType().ToArray(); - Assert.IsTrue(standardErrorProperties.Length == 1); + StandardErrorProperty[] standardErrorProperties = [.. testNode.Properties.OfType()]; + Assert.HasCount(1, standardErrorProperties); Assert.AreEqual($"message1{Environment.NewLine}message2", standardErrorProperties[0].StandardError); } diff --git a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunSettingsPatcherTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunSettingsPatcherTests.cs index 92c52dbde1..262f7bc9ae 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunSettingsPatcherTests.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunSettingsPatcherTests.cs @@ -94,7 +94,7 @@ public void Patch_WhenRunSettingsExists_MergesParameters() XDocument runSettingsDocument = RunSettingsPatcher.Patch(runSettings, _configuration.Object, new ClientInfoService(string.Empty, string.Empty), _commandLineOptions.Object); - XElement[] testRunParameters = runSettingsDocument.XPathSelectElements("RunSettings/TestRunParameters/Parameter").ToArray(); + XElement[] testRunParameters = [.. runSettingsDocument.XPathSelectElements("RunSettings/TestRunParameters/Parameter")]; Assert.AreEqual("key1", testRunParameters[0].Attribute("name")!.Value); Assert.AreEqual("value1", testRunParameters[0].Attribute("value")!.Value); Assert.AreEqual("key2", testRunParameters[1].Attribute("name")!.Value); @@ -118,7 +118,7 @@ public void Patch_WhenRunSettingsDoesNotExist_AddParameters() XDocument runSettingsDocument = RunSettingsPatcher.Patch(null, _configuration.Object, new ClientInfoService(string.Empty, string.Empty), _commandLineOptions.Object); - XElement[] testRunParameters = runSettingsDocument.XPathSelectElements("RunSettings/TestRunParameters/Parameter").ToArray(); + XElement[] testRunParameters = [.. runSettingsDocument.XPathSelectElements("RunSettings/TestRunParameters/Parameter")]; Assert.AreEqual("key1", testRunParameters[0].Attribute("name")!.Value); Assert.AreEqual("value1", testRunParameters[0].Attribute("value")!.Value); Assert.AreEqual("key2", testRunParameters[1].Attribute("name")!.Value); diff --git a/test/UnitTests/Microsoft.Testing.Platform.MSBuild.UnitTests/MSBuildTests.cs b/test/UnitTests/Microsoft.Testing.Platform.MSBuild.UnitTests/MSBuildTests.cs index ad5f780f08..e9762332bd 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.MSBuild.UnitTests/MSBuildTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.MSBuild.UnitTests/MSBuildTests.cs @@ -10,15 +10,11 @@ namespace Microsoft.Testing.Platform.MSBuild.UnitTests; [TestClass] public sealed class MSBuildTests { - private readonly Mock _buildEngine; - private readonly List _errors; + private readonly Mock _buildEngine = new(); + private readonly List _errors = []; - public MSBuildTests() - { - _buildEngine = new Mock(); - _errors = new List(); + public MSBuildTests() => _buildEngine.Setup(x => x.LogErrorEvent(It.IsAny())).Callback(e => _errors.Add(e)); - } [TestMethod] public void Verify_Correct_Registration_Order_For_WellKnown_Extensions() @@ -65,7 +61,7 @@ internal sealed class MicrosoftTestingPlatformEntryPoint private sealed class InMemoryFileSystem : IFileSystem { - public Dictionary Files { get; } = new(); + public Dictionary Files { get; } = []; public void CopyFile(string source, string destination) => throw new NotImplementedException(); @@ -80,7 +76,7 @@ private sealed class InMemoryFileSystem : IFileSystem private sealed class CustomTaskItem : ITaskItem { - private readonly Dictionary _keyValuePairs = new(); + private readonly Dictionary _keyValuePairs = []; public CustomTaskItem(string itemSpec) => ItemSpec = itemSpec; diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/ArgumentArityTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/ArgumentArityTests.cs index 5cada34ede..c688a2062f 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/ArgumentArityTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/ArgumentArityTests.cs @@ -121,16 +121,16 @@ public async Task ParseAndValidate_WhenOptionsGetsTheExpectedNumberOfArguments_R private sealed class ExtensionCommandLineProviderMockOptionsWithDifferentArity : ICommandLineOptionsProvider { - public string Uid { get; } = nameof(PlatformCommandLineProvider); + public string Uid => nameof(PlatformCommandLineProvider); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// - public string DisplayName { get; } = "Microsoft Testing Platform command line provider"; + public string DisplayName => "Microsoft Testing Platform command line provider"; /// - public string Description { get; } = "Built-in command line provider"; + public string Description => "Built-in command line provider"; /// public Task IsEnabledAsync() => Task.FromResult(true); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineHandlerTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineHandlerTests.cs index 50462c0cb1..4070f86876 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineHandlerTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineHandlerTests.cs @@ -38,8 +38,8 @@ public async Task ParseAndValidateAsync_InvalidCommandLineArguments_ReturnsFalse // Assert Assert.IsFalse(result.IsValid); - StringAssert.Contains(result.ErrorMessage, "Invalid command line arguments:"); - StringAssert.Contains(result.ErrorMessage, "Unexpected argument 'a'"); + Assert.Contains("Invalid command line arguments:", result.ErrorMessage); + Assert.Contains("Unexpected argument 'a'", result.ErrorMessage); } [TestMethod] @@ -75,7 +75,7 @@ public async Task ParseAndValidateAsync_DuplicateOption_ReturnsFalse() // Assert Assert.IsFalse(result.IsValid); - StringAssert.Contains(result.ErrorMessage, "Option '--userOption' is declared by multiple extensions: 'Microsoft Testing Platform command line provider', 'Microsoft Testing Platform command line provider'"); + Assert.Contains("Option '--userOption' is declared by multiple extensions: 'Microsoft Testing Platform command line provider', 'Microsoft Testing Platform command line provider'", result.ErrorMessage); } [TestMethod] @@ -275,8 +275,8 @@ public void GetOptionValue_OptionDoesNotExist_ReturnsNull() _outputDisplayMock.Setup(x => x.DisplayAsync(It.IsAny(), It.IsAny())) .Callback((IOutputDeviceDataProducer message, IOutputDeviceData data) => { - Assert.IsTrue(((TextOutputDeviceData)data).Text.Contains("Invalid command line arguments:")); - Assert.IsTrue(((TextOutputDeviceData)data).Text.Contains("Unexpected argument")); + Assert.Contains("Invalid command line arguments:", ((TextOutputDeviceData)data).Text); + Assert.Contains("Unexpected argument", ((TextOutputDeviceData)data).Text); }); CommandLineHandler commandLineHandler = new(parseResult, _extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, @@ -294,16 +294,16 @@ private sealed class ExtensionCommandLineProviderMockReservedOptions : ICommandL { public const string HelpOption = "help"; - public string Uid { get; } = nameof(PlatformCommandLineProvider); + public string Uid => nameof(PlatformCommandLineProvider); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// - public string DisplayName { get; } = "Microsoft Testing Platform command line provider"; + public string DisplayName => "Microsoft Testing Platform command line provider"; /// - public string Description { get; } = "Built-in command line provider"; + public string Description => "Built-in command line provider"; /// public Task IsEnabledAsync() => Task.FromResult(true); @@ -322,16 +322,16 @@ private sealed class ExtensionCommandLineProviderMockUnknownOption : ICommandLin { public const string Option = "option"; - public string Uid { get; } = nameof(PlatformCommandLineProvider); + public string Uid => nameof(PlatformCommandLineProvider); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// - public string DisplayName { get; } = "Microsoft Testing Platform command line provider"; + public string DisplayName => "Microsoft Testing Platform command line provider"; /// - public string Description { get; } = "Built-in command line provider"; + public string Description => "Built-in command line provider"; /// public Task IsEnabledAsync() => Task.FromResult(true); @@ -352,16 +352,16 @@ private sealed class ExtensionCommandLineProviderMockInvalidConfiguration : ICom public ExtensionCommandLineProviderMockInvalidConfiguration(string optionName = "option") => _option = optionName; - public string Uid { get; } = nameof(PlatformCommandLineProvider); + public string Uid => nameof(PlatformCommandLineProvider); /// - public string Version { get; } = AppVersion.DefaultSemVer; + public string Version => AppVersion.DefaultSemVer; /// - public string DisplayName { get; } = "Microsoft Testing Platform command line provider"; + public string DisplayName => "Microsoft Testing Platform command line provider"; /// - public string Description { get; } = "Built-in command line provider"; + public string Description => "Built-in command line provider"; /// public Task IsEnabledAsync() => Task.FromResult(true); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/PlatformCommandLineProviderTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/PlatformCommandLineProviderTests.cs index 4ea02fad22..f838ea4e3c 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/PlatformCommandLineProviderTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/PlatformCommandLineProviderTests.cs @@ -181,4 +181,77 @@ public async Task IsNotValid_If_ExitOnProcess_Not_Running() Assert.IsFalse(validateOptionsResult.IsValid); Assert.IsTrue(validateOptionsResult.ErrorMessage.StartsWith($"Invalid PID '{pid}'", StringComparison.OrdinalIgnoreCase)); } + + [TestMethod] + [DataRow("1.5s")] + [DataRow("2.0m")] + [DataRow("0.5h")] + [DataRow("10s")] + [DataRow("30m")] + [DataRow("1h")] + public async Task IsValid_If_Timeout_Has_CorrectFormat_InvariantCulture(string timeout) + { + var provider = new PlatformCommandLineProvider(); + CommandLineOption option = provider.GetCommandLineOptions().First(x => x.Name == PlatformCommandLineProvider.TimeoutOptionKey); + + // Save current culture + CultureInfo originalCulture = CultureInfo.CurrentCulture; + try + { + // Test with various cultures to ensure invariant parsing works + foreach (string cultureName in new[] { "en-US", "de-DE", "fr-FR" }) + { + CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo(cultureName); + ValidationResult validateOptionsResult = await provider.ValidateOptionArgumentsAsync(option, [timeout]); + Assert.IsTrue(validateOptionsResult.IsValid, $"Failed with culture {cultureName} and timeout {timeout}"); + Assert.IsTrue(string.IsNullOrEmpty(validateOptionsResult.ErrorMessage)); + } + } + finally + { + // Restore original culture + CultureInfo.CurrentCulture = originalCulture; + } + } + + [TestMethod] + [DataRow("1,5s")] // German decimal separator + [DataRow("invalid")] + [DataRow("1.5")] // Missing unit + [DataRow("abc.5s")] + public async Task IsInvalid_If_Timeout_Has_IncorrectFormat(string timeout) + { + var provider = new PlatformCommandLineProvider(); + CommandLineOption option = provider.GetCommandLineOptions().First(x => x.Name == PlatformCommandLineProvider.TimeoutOptionKey); + + ValidationResult validateOptionsResult = await provider.ValidateOptionArgumentsAsync(option, [timeout]); + Assert.IsFalse(validateOptionsResult.IsValid); + Assert.AreEqual(PlatformResources.PlatformCommandLineTimeoutArgumentErrorMessage, validateOptionsResult.ErrorMessage); + } + + [TestMethod] + public async Task Timeout_Parsing_Uses_InvariantCulture_NotCurrentCulture() + { + var provider = new PlatformCommandLineProvider(); + CommandLineOption option = provider.GetCommandLineOptions().First(x => x.Name == PlatformCommandLineProvider.TimeoutOptionKey); + + // Save current culture + CultureInfo originalCulture = CultureInfo.CurrentCulture; + try + { + // Set culture to German where decimal separator is comma + CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de-DE"); + // This should work because we use invariant culture (period as decimal separator) + ValidationResult validResult = await provider.ValidateOptionArgumentsAsync(option, ["1.5s"]); + Assert.IsTrue(validResult.IsValid, "1.5s should be valid when using invariant culture"); + // This should fail because comma is not valid in invariant culture + ValidationResult invalidResult = await provider.ValidateOptionArgumentsAsync(option, ["1,5s"]); + Assert.IsFalse(invalidResult.IsValid, "1,5s should be invalid when using invariant culture"); + } + finally + { + // Restore original culture + CultureInfo.CurrentCulture = originalCulture; + } + } } diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationExtensionsTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationExtensionsTests.cs index 49d2df67cb..104bff4626 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationExtensionsTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationExtensionsTests.cs @@ -42,6 +42,6 @@ public void ConfigurationExtensions_TestedMethod_ThrowsArgumentNullException(str .Setup(configuration => configuration[key]) .Returns(value: null); - Assert.ThrowsException(() => GetActualValueFromConfiguration(configuration.Object, key)); + Assert.ThrowsExactly(() => GetActualValueFromConfiguration(configuration.Object, key)); } } diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationManagerTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationManagerTests.cs index e1b6c394d2..063e9b5116 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationManagerTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationManagerTests.cs @@ -18,26 +18,18 @@ namespace Microsoft.Testing.Platform.UnitTests; [TestClass] public sealed class ConfigurationManagerTests { - private readonly ServiceProvider _serviceProvider; - - public ConfigurationManagerTests() - { - _serviceProvider = new(); - _serviceProvider.AddService(new SystemFileSystem()); - } - [TestMethod] [DynamicData(nameof(GetConfigurationValueFromJsonData))] public async ValueTask GetConfigurationValueFromJson(string jsonFileConfig, string key, string? result) { Mock fileSystem = new(); - fileSystem.Setup(x => x.Exists(It.IsAny())).Returns(true); + fileSystem.Setup(x => x.ExistFile(It.IsAny())).Returns(true); fileSystem.Setup(x => x.NewFileStream(It.IsAny(), FileMode.Open, FileAccess.Read)) .Returns(new MemoryFileStream(Encoding.UTF8.GetBytes(jsonFileConfig))); CurrentTestApplicationModuleInfo testApplicationModuleInfo = new(new SystemEnvironment(), new SystemProcessHandler()); ConfigurationManager configurationManager = new(fileSystem.Object, testApplicationModuleInfo); configurationManager.AddConfigurationSource(() => new JsonConfigurationSource(testApplicationModuleInfo, fileSystem.Object, null)); - IConfiguration configuration = await configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), Array.Empty())); + IConfiguration configuration = await configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), [])); Assert.AreEqual(result, configuration[key], $"Expected '{result}' found '{configuration[key]}'"); } @@ -62,7 +54,7 @@ public async ValueTask GetConfigurationValueFromJson(string jsonFileConfig, stri public async ValueTask InvalidJson_Fail() { Mock fileSystem = new(); - fileSystem.Setup(x => x.Exists(It.IsAny())).Returns(true); + fileSystem.Setup(x => x.ExistFile(It.IsAny())).Returns(true); fileSystem.Setup(x => x.NewFileStream(It.IsAny(), FileMode.Open, FileAccess.Read)).Returns(() => new MemoryFileStream(Encoding.UTF8.GetBytes(string.Empty))); CurrentTestApplicationModuleInfo testApplicationModuleInfo = new(new SystemEnvironment(), new SystemProcessHandler()); ConfigurationManager configurationManager = new(fileSystem.Object, testApplicationModuleInfo); @@ -71,9 +63,9 @@ public async ValueTask InvalidJson_Fail() // The behavior difference is System.Text.Json vs Jsonite #if NETFRAMEWORK - await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), Array.Empty())), ex => ex?.ToString() ?? "No exception was thrown"); + await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), [])), ex => ex?.ToString() ?? "No exception was thrown"); #else - await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), Array.Empty())), ex => ex?.ToString() ?? "No exception was thrown"); + await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), [])), ex => ex?.ToString() ?? "No exception was thrown"); #endif } @@ -84,7 +76,7 @@ public async ValueTask GetConfigurationValueFromJsonWithFileLoggerProvider(strin byte[] bytes = Encoding.UTF8.GetBytes(jsonFileConfig); Mock fileSystem = new(); - fileSystem.Setup(x => x.Exists(It.IsAny())).Returns(true); + fileSystem.Setup(x => x.ExistFile(It.IsAny())).Returns(true); fileSystem.Setup(x => x.NewFileStream(It.IsAny(), FileMode.Open, FileAccess.Read)) .Returns(() => new MemoryFileStream(bytes)); @@ -99,7 +91,7 @@ public async ValueTask GetConfigurationValueFromJsonWithFileLoggerProvider(strin configurationManager.AddConfigurationSource(() => new JsonConfigurationSource(testApplicationModuleInfo, fileSystem.Object, null)); - IConfiguration configuration = await configurationManager.BuildAsync(loggerProviderMock.Object, new CommandLineParseResult(null, new List(), Array.Empty())); + IConfiguration configuration = await configurationManager.BuildAsync(loggerProviderMock.Object, new CommandLineParseResult(null, new List(), [])); Assert.AreEqual(result, configuration[key], $"Expected '{result}' found '{configuration[key]}'"); loggerMock.Verify(x => x.LogAsync(LogLevel.Trace, It.IsAny(), null, LoggingExtensions.Formatter), Times.Once); @@ -110,7 +102,7 @@ public async ValueTask BuildAsync_EmptyConfigurationSources_ThrowsException() { CurrentTestApplicationModuleInfo testApplicationModuleInfo = new(new SystemEnvironment(), new SystemProcessHandler()); ConfigurationManager configurationManager = new(new SystemFileSystem(), testApplicationModuleInfo); - await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), Array.Empty()))); + await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), []))); } [TestMethod] @@ -123,7 +115,7 @@ public async ValueTask BuildAsync_ConfigurationSourcesNotEnabledAsync_ThrowsExce ConfigurationManager configurationManager = new(new SystemFileSystem(), testApplicationModuleInfo); configurationManager.AddConfigurationSource(() => mockConfigurationSource.Object); - await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), Array.Empty()))); + await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), []))); mockConfigurationSource.Verify(x => x.IsEnabledAsync(), Times.Once); } @@ -143,7 +135,7 @@ public async ValueTask BuildAsync_ConfigurationSourceIsAsyncInitializableExtensi ConfigurationManager configurationManager = new(new SystemFileSystem(), testApplicationModuleInfo); configurationManager.AddConfigurationSource(() => fakeConfigurationSource); - await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), Array.Empty()))); + await Assert.ThrowsAsync(() => configurationManager.BuildAsync(null, new CommandLineParseResult(null, new List(), []))); } private class FakeConfigurationSource : IConfigurationSource, IAsyncInitializableExtension diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/CountDownEventTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/CountDownEventTests.cs index ee938ad28a..5659911c9d 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/CountDownEventTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/CountDownEventTests.cs @@ -8,6 +8,8 @@ namespace Microsoft.Testing.Platform.UnitTests; [TestClass] public sealed class CountDownEventTests { + public TestContext TestContext { get; set; } + [TestMethod] public async Task CountDownEvent_WaitAsync_Succeeded() { @@ -15,11 +17,11 @@ public async Task CountDownEvent_WaitAsync_Succeeded() Task waiter1 = Task.Run(() => countdownEvent.WaitAsync(CancellationToken.None)); Task waiter2 = Task.Run(() => countdownEvent.WaitAsync(CancellationToken.None)); - await Task.Delay(500); + await Task.Delay(500, TestContext.CancellationTokenSource.Token); countdownEvent.Signal(); - await Task.Delay(500); + await Task.Delay(500, TestContext.CancellationTokenSource.Token); countdownEvent.Signal(); - await Task.Delay(500); + await Task.Delay(500, TestContext.CancellationTokenSource.Token); countdownEvent.Signal(); await waiter1.TimeoutAfterAsync(TimeSpan.FromSeconds(30)); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/SystemAsyncMonitorTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/SystemAsyncMonitorTests.cs index d6d0daaa03..966a695bb3 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/SystemAsyncMonitorTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/SystemAsyncMonitorTests.cs @@ -8,6 +8,8 @@ namespace Microsoft.Testing.Platform.UnitTests; [TestClass] public sealed class SystemAsyncMonitorTests { + public TestContext TestContext { get; set; } + [TestMethod] public async Task AsyncMonitor_ShouldCorrectlyLock() { @@ -17,15 +19,15 @@ public async Task AsyncMonitor_ShouldCorrectlyLock() var stopwatch = Stopwatch.StartNew(); for (int i = 0; i < 3; i++) { - tasks.Add(Task.Run(TestLock)); + tasks.Add(Task.Run(TestLock, TestContext.CancellationTokenSource.Token)); } - await Task.WhenAll(tasks.ToArray()); + await Task.WhenAll([.. tasks]); // Give more time to be above 3s Thread.Sleep(500); - Assert.IsTrue(stopwatch.ElapsedMilliseconds > 3000); + Assert.IsGreaterThan(3000, stopwatch.ElapsedMilliseconds); async Task TestLock() { @@ -37,7 +39,7 @@ async Task TestLock() } lockState = true; - await Task.Delay(1000); + await Task.Delay(1000, TestContext.CancellationTokenSource.Token); lockState = false; } } diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/TaskExtensionsTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/TaskExtensionsTests.cs index 1a020ae938..cc51318fd9 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/TaskExtensionsTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/TaskExtensionsTests.cs @@ -8,22 +8,24 @@ namespace Microsoft.Testing.Platform.UnitTests; [TestClass] public sealed class TaskExtensionsTests { + public TestContext TestContext { get; set; } + [TestMethod] public async Task TimeoutAfterAsync_Succeeds() => await Assert.ThrowsAsync(async () => - await Task.Delay(TimeSpan.FromSeconds(60)).TimeoutAfterAsync(TimeSpan.FromSeconds(2))); + await Task.Delay(TimeSpan.FromSeconds(60), TestContext.CancellationTokenSource.Token).TimeoutAfterAsync(TimeSpan.FromSeconds(2))); [TestMethod] public async Task TimeoutAfterAsync_CancellationToken_Succeeds() => await Assert.ThrowsAsync(async () => - await Task.Delay(TimeSpan.FromSeconds(60)).TimeoutAfterAsync( + await Task.Delay(TimeSpan.FromSeconds(60), TestContext.CancellationTokenSource.Token).TimeoutAfterAsync( TimeSpan.FromSeconds(30), new CancellationTokenSource(TimeSpan.FromSeconds(2)).Token)); [TestMethod] public async Task TimeoutAfterAsync_CancellationTokenNone_Succeeds() => await Assert.ThrowsAsync(async () => - await Task.Delay(TimeSpan.FromSeconds(60)).TimeoutAfterAsync( + await Task.Delay(TimeSpan.FromSeconds(60), TestContext.CancellationTokenSource.Token).TimeoutAfterAsync( TimeSpan.FromSeconds(2), CancellationToken.None)); @@ -75,16 +77,17 @@ public async Task CancellationAsync_ObserveException_Succeeds() { ManualResetEvent waitException = new(false); await Assert.ThrowsAsync(async () - => await Task.Run(async () => - { - await Task.Delay(TimeSpan.FromSeconds(10)); - waitException.Set(); - throw new InvalidOperationException(); - }).WithCancellationAsync(new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token)); + => await Task.Run( + async () => + { + await Task.Delay(TimeSpan.FromSeconds(10), TestContext.CancellationTokenSource.Token); + waitException.Set(); + throw new InvalidOperationException(); + }, TestContext.CancellationTokenSource.Token).WithCancellationAsync(new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token)); waitException.WaitOne(); - await Task.Delay(TimeSpan.FromSeconds(4)); - }, 3, TimeSpan.FromSeconds(3), _ => true); + await Task.Delay(TimeSpan.FromSeconds(4), TestContext.CancellationTokenSource.Token); + }, 3, TimeSpan.FromSeconds(3)); [TestMethod] public async Task CancellationAsyncWithReturnValue_ObserveException_Succeeds() @@ -95,7 +98,7 @@ public async Task CancellationAsyncWithReturnValue_ObserveException_Succeeds() await Assert.ThrowsAsync(async () => await Task.Run(async () => { - await Task.Delay(TimeSpan.FromSeconds(10)); + await Task.Delay(TimeSpan.FromSeconds(10), TestContext.CancellationTokenSource.Token); try { return 2; @@ -110,8 +113,8 @@ await Assert.ThrowsAsync(async () }).WithCancellationAsync(new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token)); waitException.WaitOne(); - await Task.Delay(TimeSpan.FromSeconds(4)); - }, 3, TimeSpan.FromSeconds(3), _ => true); + await Task.Delay(TimeSpan.FromSeconds(4), TestContext.CancellationTokenSource.Token); + }, 3, TimeSpan.FromSeconds(3)); private static async Task DoSomething() { diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/TestExtension.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/TestExtension.cs index 5d2729a8ab..404f11cd9a 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/TestExtension.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/TestExtension.cs @@ -5,13 +5,13 @@ namespace Microsoft.Testing.Platform.UnitTests.Helpers; internal class TestExtension : IExtension { - public string Uid { get; } = "Uid"; + public string Uid => "Uid"; - public string Version { get; } = "Version"; + public string Version => "Version"; - public string DisplayName { get; } = "DisplayName"; + public string DisplayName => "DisplayName"; - public string Description { get; } = "Description"; + public string Description => "Description"; public Task IsEnabledAsync() => Task.FromResult(true); } diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/IPCTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/IPCTests.cs index 78beb1d004..d8126aea94 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/IPCTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/IPCTests.cs @@ -22,45 +22,46 @@ public IPCTests(TestContext testContext) [TestMethod] public async Task SingleConnectionNamedPipeServer_MultipleConnection_Fails() { - PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N")); + PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"), new SystemEnvironment()); List openedPipe = []; List exceptions = []; ManualResetEventSlim waitException = new(false); - var waitTask = Task.Run(async () => - { - try + var waitTask = Task.Run( + async () => { - while (true) + try { - NamedPipeServer singleConnectionNamedPipeServer = new( - pipeNameDescription, - async _ => await Task.FromResult(VoidResponse.CachedInstance), - new SystemEnvironment(), - new Mock().Object, - new SystemTask(), - _testContext.CancellationTokenSource.Token); - - await singleConnectionNamedPipeServer.WaitConnectionAsync(_testContext.CancellationTokenSource.Token); - openedPipe.Add(singleConnectionNamedPipeServer); + while (true) + { + NamedPipeServer singleConnectionNamedPipeServer = new( + pipeNameDescription, + async _ => await Task.FromResult(VoidResponse.CachedInstance), + new SystemEnvironment(), + new Mock().Object, + new SystemTask(), + _testContext.CancellationTokenSource.Token); + + await singleConnectionNamedPipeServer.WaitConnectionAsync(_testContext.CancellationTokenSource.Token); + openedPipe.Add(singleConnectionNamedPipeServer); + } } - } - catch (Exception ex) - { - exceptions.Add(ex); - waitException.Set(); - } - }); + catch (Exception ex) + { + exceptions.Add(ex); + waitException.Set(); + } + }, _testContext.CancellationTokenSource.Token); NamedPipeClient namedPipeClient1 = new(pipeNameDescription.Name); await namedPipeClient1.ConnectAsync(_testContext.CancellationTokenSource.Token); - waitException.Wait(); + waitException.Wait(_testContext.CancellationTokenSource.Token); - Assert.AreEqual(1, openedPipe.Count); - Assert.AreEqual(1, exceptions.Count); + Assert.HasCount(1, openedPipe); + Assert.HasCount(1, exceptions); Assert.AreEqual(exceptions[0].GetType(), typeof(IOException)); - Assert.IsTrue(exceptions[0].Message.Contains("All pipe instances are busy.")); + Assert.Contains("All pipe instances are busy.", exceptions[0].Message); await waitTask; #if NETCOREAPP @@ -87,7 +88,7 @@ public async Task SingleConnectionNamedPipeServer_MultipleConnection_Fails() public async Task SingleConnectionNamedPipeServer_RequestReplySerialization_Succeeded() { Queue receivedMessages = new(); - PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N")); + PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"), new SystemEnvironment()); NamedPipeClient namedPipeClient = new(pipeNameDescription.Name); namedPipeClient.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse)); namedPipeClient.RegisterSerializer(new TextMessageSerializer(), typeof(TextMessage)); @@ -95,29 +96,30 @@ public async Task SingleConnectionNamedPipeServer_RequestReplySerialization_Succ namedPipeClient.RegisterSerializer(new LongMessageSerializer(), typeof(LongMessage)); ManualResetEventSlim manualResetEventSlim = new(false); - var clientConnected = Task.Run(async () => - { - while (true) + var clientConnected = Task.Run( + async () => { - try - { - await namedPipeClient.ConnectAsync(CancellationToken.None); - manualResetEventSlim.Set(); - break; - } - catch (OperationCanceledException ct) when (ct.CancellationToken == _testContext.CancellationTokenSource.Token) - { - throw new OperationCanceledException("SingleConnectionNamedPipeServer_RequestReplySerialization_Succeeded cancellation during connect, testContext.CancellationTokenSource.Token"); - } - catch (OperationCanceledException) - { - throw new OperationCanceledException("SingleConnectionNamedPipeServer_RequestReplySerialization_Succeeded cancellation during connect"); - } - catch (Exception) + while (true) { + try + { + await namedPipeClient.ConnectAsync(CancellationToken.None); + manualResetEventSlim.Set(); + break; + } + catch (OperationCanceledException ct) when (ct.CancellationToken == _testContext.CancellationTokenSource.Token) + { + throw new OperationCanceledException("SingleConnectionNamedPipeServer_RequestReplySerialization_Succeeded cancellation during connect, testContext.CancellationTokenSource.Token"); + } + catch (OperationCanceledException) + { + throw new OperationCanceledException("SingleConnectionNamedPipeServer_RequestReplySerialization_Succeeded cancellation during connect"); + } + catch (Exception) + { + } } - } - }); + }, _testContext.CancellationTokenSource.Token); NamedPipeServer singleConnectionNamedPipeServer = new( pipeNameDescription, request => @@ -134,7 +136,7 @@ public async Task SingleConnectionNamedPipeServer_RequestReplySerialization_Succ singleConnectionNamedPipeServer.RegisterSerializer(new IntMessageSerializer(), typeof(IntMessage)); singleConnectionNamedPipeServer.RegisterSerializer(new LongMessageSerializer(), typeof(LongMessage)); await singleConnectionNamedPipeServer.WaitConnectionAsync(CancellationToken.None); - manualResetEventSlim.Wait(); + manualResetEventSlim.Wait(_testContext.CancellationTokenSource.Token); await clientConnected.WithCancellationAsync(CancellationToken.None); @@ -151,7 +153,7 @@ public async Task SingleConnectionNamedPipeServer_RequestReplySerialization_Succ { string currentString = RandomString(random.Next(1024, 1024 * 1024 * 2), random); await namedPipeClient.RequestReplyAsync(new TextMessage(currentString), CancellationToken.None); - Assert.AreEqual(1, receivedMessages.Count); + Assert.HasCount(1, receivedMessages); Assert.AreEqual(receivedMessages.Dequeue(), new TextMessage(currentString)); currentRound--; } @@ -170,9 +172,9 @@ public async Task SingleConnectionNamedPipeServer_RequestReplySerialization_Succ [TestMethod] public async Task ConnectionNamedPipeServer_MultipleConnection_Succeeds() { - PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N")); + PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"), new SystemEnvironment()); - List pipes = new(); + List pipes = []; for (int i = 0; i < 3; i++) { pipes.Add(new( @@ -185,7 +187,7 @@ public async Task ConnectionNamedPipeServer_MultipleConnection_Succeeds() _testContext.CancellationTokenSource.Token)); } - IOException exception = Assert.ThrowsException(() => + IOException exception = Assert.ThrowsExactly(() => new NamedPipeServer( pipeNameDescription, async _ => await Task.FromResult(VoidResponse.CachedInstance), @@ -194,20 +196,21 @@ public async Task ConnectionNamedPipeServer_MultipleConnection_Succeeds() new SystemTask(), maxNumberOfServerInstances: 3, _testContext.CancellationTokenSource.Token)); - StringAssert.Contains(exception.Message, "All pipe instances are busy."); + Assert.Contains("All pipe instances are busy.", exception.Message); - List waitConnectionTask = new(); + List waitConnectionTask = []; int connectionCompleted = 0; foreach (NamedPipeServer namedPipeServer in pipes) { - waitConnectionTask.Add(Task.Run(async () => - { - await namedPipeServer.WaitConnectionAsync(_testContext.CancellationTokenSource.Token); - Interlocked.Increment(ref connectionCompleted); - })); + waitConnectionTask.Add(Task.Run( + async () => + { + await namedPipeServer.WaitConnectionAsync(_testContext.CancellationTokenSource.Token); + Interlocked.Increment(ref connectionCompleted); + }, _testContext.CancellationTokenSource.Token)); } - List connectedClients = new(); + List connectedClients = []; for (int i = 0; i < waitConnectionTask.Count; i++) { NamedPipeClient namedPipeClient = new(pipeNameDescription.Name); @@ -215,7 +218,7 @@ public async Task ConnectionNamedPipeServer_MultipleConnection_Succeeds() await namedPipeClient.ConnectAsync(_testContext.CancellationTokenSource.Token); } - await Task.WhenAll(waitConnectionTask.ToArray()); + await Task.WhenAll([.. waitConnectionTask]); Assert.AreEqual(3, connectionCompleted); @@ -235,8 +238,7 @@ public async Task ConnectionNamedPipeServer_MultipleConnection_Succeeds() private static string RandomString(int length, Random random) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - return new string(Enumerable.Repeat(chars, length) - .Select(s => s[random.Next(s.Length)]).ToArray()); + return new string([.. Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)])]); } private abstract record BaseMessage : IRequest; diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs index 019aa5219a..73f4309e2f 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs @@ -14,7 +14,7 @@ public void TestResultMessagesSerializeDeserialize() { var success = new SuccessfulTestResultMessage("uid", "displayName", 1, 100, "reason", "standardOutput", "errorOutput", "sessionUid"); var fail = new FailedTestResultMessage("uid", "displayName", 2, 200, "reason", [new ExceptionMessage("errorMessage", "errorType", "stackTrace")], "standardOutput", "errorOutput", "sessionUid"); - var message = new TestResultMessages("executionId", "instanceId", new[] { success }, new[] { fail }); + var message = new TestResultMessages("executionId", "instanceId", [success], [fail]); var stream = new MemoryStream(); new TestResultMessagesSerializer().Serialize(message, stream); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs index 2541881cac..fce8ad8527 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs @@ -11,6 +11,9 @@ namespace Microsoft.Testing.Platform.UnitTests; [TestClass] public sealed class FileLoggerTests : IDisposable { + // https://github.com/microsoft/testfx/issues/6136 + public TestContext TestContext { get; set; } = null!; + private const string LogFolder = "aaa"; private const string LogPrefix = "bbb"; private const string FileName = "ccc"; @@ -110,7 +113,7 @@ public void FileLogger_NullFileSyncFlush_FileStreamCreationThrows() .Throws() .Returns(_mockStream.Object); - Assert.ThrowsException(() => _ = new FileLogger( + Assert.ThrowsExactly(() => _ = new FileLogger( new(LogFolder, LogPrefix, fileName: null, syncFlush: true), LogLevel.Trace, _mockClock.Object, @@ -128,7 +131,7 @@ public void FileLogger_NullFileSyncFlush_FileStreamCreationThrows() public void FileLogger_ValidFileName_FileStreamCreatedSuccessfully(bool syncFlush, bool fileExists) { string expectedPath = Path.Combine(LogFolder, FileName); - _mockFileSystem.Setup(x => x.Exists(expectedPath)).Returns(fileExists); + _mockFileSystem.Setup(x => x.ExistFile(expectedPath)).Returns(fileExists); _mockFileStreamFactory .Setup(x => x.Create(It.IsAny(), fileExists ? FileMode.Append : FileMode.CreateNew, FileAccess.Write, FileShare.Read)) .Returns(_mockStream.Object); @@ -156,7 +159,7 @@ public void FileLogger_ValidFileName_FileStreamCreatedSuccessfully(bool syncFlus [DynamicData(nameof(LogTestHelpers.GetLogLevelCombinations), typeof(LogTestHelpers))] public async Task Log_WhenSyncFlush_StreamWriterIsCalledOnlyWhenLogLevelAllowsIt(LogLevel defaultLogLevel, LogLevel currentLogLevel) { - _mockFileSystem.Setup(x => x.Exists(It.IsAny())).Returns(false); + _mockFileSystem.Setup(x => x.ExistFile(It.IsAny())).Returns(false); _mockFileStreamFactory .Setup(x => x.Create(It.IsAny(), FileMode.CreateNew, FileAccess.Write, FileShare.Read)) .Returns(_mockStream.Object); @@ -173,15 +176,15 @@ public async Task Log_WhenSyncFlush_StreamWriterIsCalledOnlyWhenLogLevelAllowsIt if (LogTestHelpers.IsLogEnabled(defaultLogLevel, currentLogLevel)) { - await _memoryStream.FlushAsync(); + await _memoryStream.FlushAsync(TestContext.CancellationTokenSource.Token); int iteration = 0; while (_memoryStream.Length == 0 && iteration < 10) { iteration++; - await Task.Delay(200); + await Task.Delay(200, TestContext.CancellationTokenSource.Token); } - await _memoryStream.FlushAsync(); + await _memoryStream.FlushAsync(TestContext.CancellationTokenSource.Token); _mockConsole.Verify(x => x.WriteLine(It.IsAny()), Times.Never); Assert.AreEqual($"[00:00:00.000 Test - {currentLogLevel}] Message{Environment.NewLine}", Encoding.Default.GetString(_memoryStream.ToArray())); @@ -196,7 +199,7 @@ public async Task Log_WhenSyncFlush_StreamWriterIsCalledOnlyWhenLogLevelAllowsIt [DynamicData(nameof(LogTestHelpers.GetLogLevelCombinations), typeof(LogTestHelpers))] public void Log_WhenAsyncFlush_StreamWriterIsCalledOnlyWhenLogLevelAllowsIt(LogLevel defaultLogLevel, LogLevel currentLogLevel) { - _mockFileSystem.Setup(x => x.Exists(It.IsAny())).Returns(false); + _mockFileSystem.Setup(x => x.ExistFile(It.IsAny())).Returns(false); _mockFileStreamFactory .Setup(x => x.Create(It.IsAny(), FileMode.CreateNew, FileAccess.Write, FileShare.Read)) .Returns(_mockStream.Object); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/LogTestHelpers.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/LogTestHelpers.cs index 571f312dff..cc3883e67b 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/LogTestHelpers.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/LogTestHelpers.cs @@ -21,8 +21,8 @@ public static IEnumerable GetLogLevelsForDynamicData() public static IEnumerable<(LogLevel DefaultLevel, LogLevel CurrentLevel)> GetLogLevelCombinations() { - List<(LogLevel, LogLevel)> logLevelCombinations = new(); - LogLevel[] logLevels = GetLogLevels().ToArray(); + List<(LogLevel, LogLevel)> logLevelCombinations = []; + LogLevel[] logLevels = [.. GetLogLevels()]; for (int i = 0; i < logLevels.Length; i++) { diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/AsynchronousMessageBusTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/AsynchronousMessageBusTests.cs index 2d6ba5076e..afcbfd4392 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/AsynchronousMessageBusTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/AsynchronousMessageBusTests.cs @@ -13,6 +13,8 @@ namespace Microsoft.Testing.Platform.UnitTests; [TestClass] public sealed class AsynchronousMessageBusTests { + public TestContext TestContext { get; set; } + [TestMethod] public async Task UnexpectedTypePublished_ShouldFail() { @@ -56,7 +58,7 @@ public async Task DrainDataAsync_Loop_ShouldFail() } catch (InvalidOperationException ex) { - StringAssert.Contains(ex.Message, "Publisher/Consumer loop detected during the drain after"); + Assert.Contains("Publisher/Consumer loop detected during the drain after", ex.Message); } // Prevent loop to continue @@ -88,10 +90,10 @@ public async Task MessageBus_WhenConsumerProducesAndConsumesTheSameType_ShouldNo await proxy.DrainDataAsync(); // assert - Assert.AreEqual(1, consumerA.ConsumedData.Count); + Assert.HasCount(1, consumerA.ConsumedData); Assert.AreEqual(consumerBData, consumerA.ConsumedData[0]); - Assert.AreEqual(1, consumerB.ConsumedData.Count); + Assert.HasCount(1, consumerB.ConsumedData); Assert.AreEqual(consumerAData, consumerB.ConsumedData[0]); } @@ -105,7 +107,7 @@ public async Task Consumers_ConsumeData_ShouldNotMissAnyPayload() Random random = new(); for (int i = 0; i < totalConsumers; i++) { - DummyConsumer dummyConsumer = new(async _ => await Task.Delay(random.Next(40, 80))); + DummyConsumer dummyConsumer = new(async _ => await Task.Delay(random.Next(40, 80), TestContext.CancellationTokenSource.Token)); dummyConsumers.Add(dummyConsumer); } @@ -120,8 +122,7 @@ public async Task Consumers_ConsumeData_ShouldNotMissAnyPayload() proxy.SetBuiltMessageBus(asynchronousMessageBus); DummyConsumer.DummyProducer producer = new(); - await Task.WhenAll(Enumerable.Range(1, totalPayloads) - .Select(i => Task.Run(async () => await proxy.PublishAsync(producer, new DummyConsumer.DummyData { Data = i }))).ToArray()); + await Task.WhenAll([.. Enumerable.Range(1, totalPayloads).Select(i => Task.Run(async () => await proxy.PublishAsync(producer, new DummyConsumer.DummyData { Data = i }), TestContext.CancellationTokenSource.Token))]); await proxy.DrainDataAsync(); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/PropertyBagTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/PropertyBagTests.cs index 12f4ad6b23..e45f9d5d25 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/PropertyBagTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/PropertyBagTests.cs @@ -23,8 +23,8 @@ public void Ctors_CorrectlyInit() [TestMethod] public void Ctors_With_WrongInit_ShouldFail() { - Assert.ThrowsException(() => _ = new PropertyBag([new DummyProperty(), PassedTestNodeStateProperty.CachedInstance, PassedTestNodeStateProperty.CachedInstance])); - Assert.ThrowsException(() => _ = new PropertyBag(new IProperty[] { new DummyProperty(), PassedTestNodeStateProperty.CachedInstance, PassedTestNodeStateProperty.CachedInstance }.AsEnumerable())); + Assert.ThrowsExactly(() => _ = new PropertyBag([new DummyProperty(), PassedTestNodeStateProperty.CachedInstance, PassedTestNodeStateProperty.CachedInstance])); + Assert.ThrowsExactly(() => _ = new PropertyBag(new IProperty[] { new DummyProperty(), PassedTestNodeStateProperty.CachedInstance, PassedTestNodeStateProperty.CachedInstance }.AsEnumerable())); } [TestMethod] @@ -40,14 +40,14 @@ public void AddGet_Of_TestNodeStateProperty_Succed() PropertyBag property = new(); Assert.IsFalse(property.Any()); - Assert.AreEqual(0, property.OfType().Length); + Assert.IsEmpty(property.OfType()); property.Add(PassedTestNodeStateProperty.CachedInstance); Assert.AreEqual(PassedTestNodeStateProperty.CachedInstance, property.Single()); Assert.AreEqual(PassedTestNodeStateProperty.CachedInstance, property.SingleOrDefault()); Assert.IsTrue(property.Any()); - Assert.AreEqual(1, property.OfType().Length); + Assert.HasCount(1, property.OfType()); } [TestMethod] @@ -55,7 +55,7 @@ public void Add_Of_TestNodeStateProperty_More_Than_One_Time_Fail() { PropertyBag property = new(); property.Add(PassedTestNodeStateProperty.CachedInstance); - Assert.ThrowsException(() => property.Add(PassedTestNodeStateProperty.CachedInstance)); + Assert.ThrowsExactly(() => property.Add(PassedTestNodeStateProperty.CachedInstance)); } [TestMethod] @@ -64,7 +64,7 @@ public void Add_Same_Instance_More_Times_Fail() PropertyBag property = new(); DummyProperty dummyProperty = new(); property.Add(dummyProperty); - Assert.ThrowsException(() => property.Add(dummyProperty)); + Assert.ThrowsExactly(() => property.Add(dummyProperty)); } [TestMethod] @@ -92,7 +92,7 @@ public void SingleOrDefault_Should_Return_CorrectObject() Assert.IsNull(property.SingleOrDefault()); property.Add(new DummyProperty()); - Assert.ThrowsException(property.SingleOrDefault); + Assert.ThrowsExactly(property.SingleOrDefault); } [TestMethod] @@ -105,10 +105,10 @@ public void Single_Should_Return_CorrectObject() Assert.AreEqual(PassedTestNodeStateProperty.CachedInstance, property.Single()); Assert.AreEqual(prop, property.Single()); - Assert.ThrowsException(property.Single); + Assert.ThrowsExactly(property.Single); property.Add(new DummyProperty()); - Assert.ThrowsException(property.Single); + Assert.ThrowsExactly(property.Single); } [TestMethod] @@ -120,7 +120,7 @@ public void OfType_Should_Return_CorrectObject() property.Add(PassedTestNodeStateProperty.CachedInstance); Assert.AreEqual(PassedTestNodeStateProperty.CachedInstance, property.OfType().Single()); - Assert.AreEqual(2, property.OfType().Length); + Assert.HasCount(2, property.OfType()); } [TestMethod] @@ -141,15 +141,15 @@ public void AsEnumerable_Should_Return_CorrectItems() list.Remove(prop); } - Assert.AreEqual(0, list.Count); + Assert.IsEmpty(list); - list = property.AsEnumerable().ToList(); + list = [.. property.AsEnumerable()]; foreach (IProperty prop in property) { list.Remove(prop); } - Assert.AreEqual(0, list.Count); + Assert.IsEmpty(list); } [TestMethod] @@ -159,13 +159,13 @@ public void EmptyProperties_Should_NotFail() Assert.AreEqual(0, property.Count); Assert.IsFalse(property.Any()); Assert.IsNull(property.SingleOrDefault()); - Assert.ThrowsException(property.Single); - Assert.AreEqual(0, property.OfType().Length); + Assert.ThrowsExactly(property.Single); + Assert.IsEmpty(property.OfType()); Assert.AreEqual(0, property.AsEnumerable().Count()); foreach (IProperty item in property) { - Assert.IsTrue(false, "no item expected"); + Assert.Fail("no item expected"); } } diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/TestNodePropertiesTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/TestNodePropertiesTests.cs index 849b57375f..2a91a44c32 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/TestNodePropertiesTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/TestNodePropertiesTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#pragma warning disable CS0618 // Type or member is obsolete namespace Microsoft.Testing.Platform.Extensions.Messages.UnitTests; [TestClass] diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/TestNodeUidTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/TestNodeUidTests.cs index 6a57d3b664..794de47f8c 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/TestNodeUidTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/TestNodeUidTests.cs @@ -27,13 +27,13 @@ public void TestNodeUid_NullValue_ShouldFail() // Assert.Throw(() => { TestNodeUid testNode = null!; }); // Implicit conversion from a null, empty or whitespace string should throw. - Assert.ThrowsException(() => { TestNodeUid testNode = (string)null!; }); - Assert.ThrowsException(() => { TestNodeUid testNode = string.Empty; }); - Assert.ThrowsException(() => { TestNodeUid testNode = " "; }); + Assert.ThrowsExactly(() => { TestNodeUid testNode = (string)null!; }); + Assert.ThrowsExactly(() => { TestNodeUid testNode = string.Empty; }); + Assert.ThrowsExactly(() => { TestNodeUid testNode = " "; }); // Providing null, empty, or whitespace id should throw. - Assert.ThrowsException(() => { TestNodeUid testNode = new(null!); }); - Assert.ThrowsException(() => { TestNodeUid testNode = new(string.Empty); }); - Assert.ThrowsException(() => { TestNodeUid testNode = new(" "); }); + Assert.ThrowsExactly(() => { TestNodeUid testNode = new(null!); }); + Assert.ThrowsExactly(() => { TestNodeUid testNode = new(string.Empty); }); + Assert.ThrowsExactly(() => { TestNodeUid testNode = new(" "); }); } } diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterTests.cs index 0e3467d86c..f8d8a9b240 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterTests.cs @@ -3,6 +3,7 @@ using Microsoft.Testing.Platform.Helpers; using Microsoft.Testing.Platform.OutputDevice.Terminal; +using Microsoft.Testing.Platform.Services; namespace Microsoft.Testing.Platform.UnitTests; @@ -27,9 +28,11 @@ public void AppendStackFrameFormatsStackTraceLineCorrectly() TerminalTestReporter.AppendStackFrame(terminal, firstStackTraceLine); #if NETCOREAPP - StringAssert.Contains(terminal.Output, " at Microsoft.Testing.Platform.UnitTests.TerminalTestReporterTests.AppendStackFrameFormatsStackTraceLineCorrectly() in "); + Assert.Contains(" at Microsoft.Testing.Platform.UnitTests.TerminalTestReporterTests.AppendStackFrameFormatsStackTraceLineCorrectly() in ", terminal.Output); #else - StringAssert.Contains(terminal.Output, " at Microsoft.Testing.Platform.UnitTests.TerminalTestReporterTests.AppendStackFrameFormatsStackTraceLineCorrectly()"); + // This is caused by us using portable symbols, and .NET Framework 4.6.2, once we update to .NET Framework 4.7.2 the path to file will be included in the stacktrace and this won't be necessary. + // See first point here: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/symbols#support-for-portable-pdbs + Assert.Contains(" at Microsoft.Testing.Platform.UnitTests.TerminalTestReporterTests.AppendStackFrameFormatsStackTraceLineCorrectly()", terminal.Output); #endif // Line number without the respective file Assert.IsFalse(terminal.Output.Contains(" :0")); @@ -64,17 +67,120 @@ public void StackTraceRegexCapturesLines(string stackTraceLine, string expected) } [TestMethod] - public void OutputFormattingIsCorrect() + public void NonAnsiTerminal_OutputFormattingIsCorrect() { + string targetFramework = "net8.0"; + string architecture = "x64"; + string assembly = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work\assembly.dll" : "/mnt/work/assembly.dll"; + + var stringBuilderConsole = new StringBuilderConsole(); + var terminalReporter = new TerminalTestReporter(assembly, targetFramework, architecture, stringBuilderConsole, new CTRLPlusCCancellationTokenSource(), new TerminalTestReporterOptions + { + ShowPassedTests = () => true, + + // Like --no-ansi in commandline, should disable ANSI altogether. + UseAnsi = false, + + ShowProgress = () => false, + }); + + DateTimeOffset startTime = DateTimeOffset.MinValue; + DateTimeOffset endTime = DateTimeOffset.MaxValue; + terminalReporter.TestExecutionStarted(startTime, 1, isDiscovery: false); + + string folder = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work\" : "/mnt/work/"; + string folderNoSlash = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work" : "/mnt/work"; + string folderLink = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work/" : "mnt/work/"; + string folderLinkNoSlash = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work" : "mnt/work"; + + terminalReporter.AssemblyRunStarted(); + string standardOutput = "Hello!"; + string errorOutput = "Oh no!"; + + terminalReporter.TestCompleted(testNodeUid: "PassedTest1", "PassedTest1", TestOutcome.Passed, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); + terminalReporter.TestCompleted(testNodeUid: "SkippedTest1", "SkippedTest1", TestOutcome.Skipped, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); + // timed out + canceled + failed should all report as failed in summary + terminalReporter.TestCompleted(testNodeUid: "TimedoutTest1", "TimedoutTest1", TestOutcome.Timeout, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); + terminalReporter.TestCompleted(testNodeUid: "CanceledTest1", "CanceledTest1", TestOutcome.Canceled, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); + terminalReporter.TestCompleted(testNodeUid: "FailedTest1", "FailedTest1", TestOutcome.Fail, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: "Tests failed", exception: new StackTraceException(@$" at FailingTest() in {folder}codefile.cs:line 10"), expected: "ABC", actual: "DEF", standardOutput, errorOutput); + terminalReporter.ArtifactAdded(outOfProcess: true, testName: null, @$"{folder}artifact1.txt"); + terminalReporter.ArtifactAdded(outOfProcess: false, testName: null, @$"{folder}artifact2.txt"); + terminalReporter.AssemblyRunCompleted(); + terminalReporter.TestExecutionCompleted(endTime); + + string output = stringBuilderConsole.Output; + + string expected = $""" + passed PassedTest1 (10s 000ms) + Standard output + Hello! + Error output + Oh no! + skipped SkippedTest1 (10s 000ms) + Standard output + Hello! + Error output + Oh no! + failed (canceled) TimedoutTest1 (10s 000ms) + Standard output + Hello! + Error output + Oh no! + failed (canceled) CanceledTest1 (10s 000ms) + Standard output + Hello! + Error output + Oh no! + failed FailedTest1 (10s 000ms) + Tests failed + Expected + ABC + Actual + DEF + at FailingTest() in {folder}codefile.cs:10 + Standard output + Hello! + Error output + Oh no! + + Out of process file artifacts produced: + - {folder}artifact1.txt + In process file artifacts produced: + - {folder}artifact2.txt + + Test run summary: Failed! - {assembly} (net8.0|x64) + total: 5 + failed: 3 + succeeded: 1 + skipped: 1 + duration: 3652058d 23h 59m 59s 999ms + + """; + + Assert.AreEqual(expected, ShowEscape(output)); + } + + [TestMethod] + public void SimpleAnsiTerminal_OutputFormattingIsCorrect() + { + string targetFramework = "net8.0"; + string architecture = "x64"; + string assembly = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work\assembly.dll" : "/mnt/work/assembly.dll"; + var stringBuilderConsole = new StringBuilderConsole(); - var terminalReporter = new TerminalTestReporter(stringBuilderConsole, new TerminalTestReporterOptions + var terminalReporter = new TerminalTestReporter(assembly, targetFramework, architecture, stringBuilderConsole, new CTRLPlusCCancellationTokenSource(), new TerminalTestReporterOptions { ShowPassedTests = () => true, + // Like if we autodetect that we are in CI (e.g. by looking at TF_BUILD, and we don't disable ANSI. UseAnsi = true, + UseCIAnsi = true, ForceAnsi = true, - ShowAssembly = false, - ShowAssemblyStartAndComplete = false, ShowProgress = () => false, }); @@ -82,60 +188,157 @@ public void OutputFormattingIsCorrect() DateTimeOffset endTime = DateTimeOffset.MaxValue; terminalReporter.TestExecutionStarted(startTime, 1, isDiscovery: false); + string folder = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work\" : "/mnt/work/"; + string folderNoSlash = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work" : "/mnt/work"; + string folderLink = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work/" : "mnt/work/"; + string folderLinkNoSlash = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work" : "mnt/work"; + + terminalReporter.AssemblyRunStarted(); + string standardOutput = "Hello!"; + string errorOutput = "Oh no!"; + + terminalReporter.TestCompleted(testNodeUid: "PassedTest1", "PassedTest1", TestOutcome.Passed, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); + terminalReporter.TestCompleted(testNodeUid: "SkippedTest1", "SkippedTest1", TestOutcome.Skipped, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); + // timed out + canceled + failed should all report as failed in summary + terminalReporter.TestCompleted(testNodeUid: "TimedoutTest1", "TimedoutTest1", TestOutcome.Timeout, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); + terminalReporter.TestCompleted(testNodeUid: "CanceledTest1", "CanceledTest1", TestOutcome.Canceled, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); + terminalReporter.TestCompleted(testNodeUid: "FailedTest1", "FailedTest1", TestOutcome.Fail, TimeSpan.FromSeconds(10), + informativeMessage: null, errorMessage: "Tests failed", exception: new StackTraceException(@$" at FailingTest() in {folder}codefile.cs:line 10"), expected: "ABC", actual: "DEF", standardOutput, errorOutput); + terminalReporter.ArtifactAdded(outOfProcess: true, testName: null, @$"{folder}artifact1.txt"); + terminalReporter.ArtifactAdded(outOfProcess: false, testName: null, @$"{folder}artifact2.txt"); + terminalReporter.AssemblyRunCompleted(); + terminalReporter.TestExecutionCompleted(endTime); + + string output = stringBuilderConsole.Output; + + string expected = $""" + ␛[32mpassed␛[m PassedTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[90m Standard output + ␛[90m Hello! + ␛[90m Error output + ␛[90m Oh no! + ␛[m␛[33mskipped␛[m SkippedTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[90m Standard output + ␛[90m Hello! + ␛[90m Error output + ␛[90m Oh no! + ␛[m␛[31mfailed (canceled)␛[m TimedoutTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[90m Standard output + ␛[90m Hello! + ␛[90m Error output + ␛[90m Oh no! + ␛[m␛[31mfailed (canceled)␛[m CanceledTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[90m Standard output + ␛[90m Hello! + ␛[90m Error output + ␛[90m Oh no! + ␛[m␛[31mfailed␛[m FailedTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[31m Tests failed + ␛[m␛[31m Expected + ␛[31m ABC + ␛[31m Actual + ␛[31m DEF + ␛[m␛[90m at FailingTest() in {folder}codefile.cs:10␛[90m + ␛[m␛[90m Standard output + ␛[90m Hello! + ␛[90m Error output + ␛[90m Oh no! + ␛[m + Out of process file artifacts produced: + - {folder}artifact1.txt + In process file artifacts produced: + - {folder}artifact2.txt + + ␛[31mTest run summary: Failed!␛[90m - ␛[m{folder}assembly.dll (net8.0|x64) + ␛[m total: 5 + ␛[31m failed: 3 + ␛[m succeeded: 1 + skipped: 1 + duration: 3652058d 23h 59m 59s 999ms + + """; + + Assert.AreEqual(expected, ShowEscape(output)); + } + + [TestMethod] + public void AnsiTerminal_OutputFormattingIsCorrect() + { string targetFramework = "net8.0"; string architecture = "x64"; string assembly = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work\assembly.dll" : "/mnt/work/assembly.dll"; + + var stringBuilderConsole = new StringBuilderConsole(); + var terminalReporter = new TerminalTestReporter(assembly, targetFramework, architecture, stringBuilderConsole, new CTRLPlusCCancellationTokenSource(), new TerminalTestReporterOptions + { + ShowPassedTests = () => true, + // Like if we autodetect that we are in ANSI capable terminal. + UseAnsi = true, + UseCIAnsi = false, + ForceAnsi = true, + + ShowProgress = () => false, + }); + + DateTimeOffset startTime = DateTimeOffset.MinValue; + DateTimeOffset endTime = DateTimeOffset.MaxValue; + terminalReporter.TestExecutionStarted(startTime, 1, isDiscovery: false); + string folder = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work\" : "/mnt/work/"; string folderNoSlash = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work" : "/mnt/work"; string folderLink = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work/" : "mnt/work/"; string folderLinkNoSlash = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work" : "mnt/work"; - terminalReporter.AssemblyRunStarted(assembly, targetFramework, architecture); + terminalReporter.AssemblyRunStarted(); string standardOutput = "Hello!"; string errorOutput = "Oh no!"; - terminalReporter.TestCompleted(assembly, targetFramework, architecture, testNodeUid: "PassedTest1", "PassedTest1", TestOutcome.Passed, TimeSpan.FromSeconds(10), + terminalReporter.TestCompleted(testNodeUid: "PassedTest1", "PassedTest1", TestOutcome.Passed, TimeSpan.FromSeconds(10), informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); - terminalReporter.TestCompleted(assembly, targetFramework, architecture, testNodeUid: "SkippedTest1", "SkippedTest1", TestOutcome.Skipped, TimeSpan.FromSeconds(10), + terminalReporter.TestCompleted(testNodeUid: "SkippedTest1", "SkippedTest1", TestOutcome.Skipped, TimeSpan.FromSeconds(10), informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); // timed out + canceled + failed should all report as failed in summary - terminalReporter.TestCompleted(assembly, targetFramework, architecture, testNodeUid: "TimedoutTest1", "TimedoutTest1", TestOutcome.Timeout, TimeSpan.FromSeconds(10), + terminalReporter.TestCompleted(testNodeUid: "TimedoutTest1", "TimedoutTest1", TestOutcome.Timeout, TimeSpan.FromSeconds(10), informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); - terminalReporter.TestCompleted(assembly, targetFramework, architecture, testNodeUid: "CanceledTest1", "CanceledTest1", TestOutcome.Canceled, TimeSpan.FromSeconds(10), + terminalReporter.TestCompleted(testNodeUid: "CanceledTest1", "CanceledTest1", TestOutcome.Canceled, TimeSpan.FromSeconds(10), informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); - terminalReporter.TestCompleted(assembly, targetFramework, architecture, testNodeUid: "FailedTest1", "FailedTest1", TestOutcome.Fail, TimeSpan.FromSeconds(10), + terminalReporter.TestCompleted(testNodeUid: "FailedTest1", "FailedTest1", TestOutcome.Fail, TimeSpan.FromSeconds(10), informativeMessage: null, errorMessage: "Tests failed", exception: new StackTraceException(@$" at FailingTest() in {folder}codefile.cs:line 10"), expected: "ABC", actual: "DEF", standardOutput, errorOutput); - terminalReporter.ArtifactAdded(outOfProcess: true, assembly, targetFramework, architecture, testName: null, @$"{folder}artifact1.txt"); - terminalReporter.ArtifactAdded(outOfProcess: false, assembly, targetFramework, architecture, testName: null, @$"{folder}artifact2.txt"); - terminalReporter.AssemblyRunCompleted(assembly, targetFramework, architecture, exitCode: null, outputData: null, errorData: null); + terminalReporter.ArtifactAdded(outOfProcess: true, testName: null, @$"{folder}artifact1.txt"); + terminalReporter.ArtifactAdded(outOfProcess: false, testName: null, @$"{folder}artifact2.txt"); + terminalReporter.AssemblyRunCompleted(); terminalReporter.TestExecutionCompleted(endTime); string output = stringBuilderConsole.Output; string expected = $""" - ␛[92mpassed␛[m PassedTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[32mpassed␛[m PassedTest1␛[90m ␛[90m(10s 000ms)␛[m ␛[90m Standard output Hello! Error output Oh no! - ␛[m␛[93mskipped␛[m SkippedTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[m␛[33mskipped␛[m SkippedTest1␛[90m ␛[90m(10s 000ms)␛[m ␛[90m Standard output Hello! Error output Oh no! - ␛[m␛[91mfailed (canceled)␛[m TimedoutTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[m␛[31mfailed (canceled)␛[m TimedoutTest1␛[90m ␛[90m(10s 000ms)␛[m ␛[90m Standard output Hello! Error output Oh no! - ␛[m␛[91mfailed (canceled)␛[m CanceledTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[m␛[31mfailed (canceled)␛[m CanceledTest1␛[90m ␛[90m(10s 000ms)␛[m ␛[90m Standard output Hello! Error output Oh no! - ␛[m␛[91mfailed␛[m FailedTest1␛[90m ␛[90m(10s 000ms)␛[m - ␛[91m Tests failed - ␛[m␛[91m Expected + ␛[m␛[31mfailed␛[m FailedTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[31m Tests failed + ␛[m␛[31m Expected ABC Actual DEF @@ -149,33 +352,37 @@ Oh no! - ␛[90m␛]8;;file:///{folderLink}artifact1.txt␛\{folder}artifact1.txt␛]8;;␛\␛[m In process file artifacts produced: - ␛[90m␛]8;;file:///{folderLink}artifact2.txt␛\{folder}artifact2.txt␛]8;;␛\␛[m - - ␛[91mTest run summary: Failed!␛[90m - ␛[m␛[90m␛]8;;file:///{folderLinkNoSlash}␛\{folder}assembly.dll␛]8;;␛\␛[m (net8.0|x64) + + ␛[31mTest run summary: Failed!␛[90m - ␛[m␛[90m␛]8;;file:///{folderLinkNoSlash}␛\{folder}assembly.dll␛]8;;␛\␛[m (net8.0|x64) ␛[m total: 5 - ␛[91m failed: 3 + ␛[31m failed: 3 ␛[m succeeded: 1 skipped: 1 duration: 3652058d 23h 59m 59s 999ms - + """; Assert.AreEqual(expected, ShowEscape(output)); } [TestMethod] - public void OutputProgressFrameIsCorrect() + public void AnsiTerminal_OutputProgressFrameIsCorrect() { + string targetFramework = "net8.0"; + string architecture = "x64"; + string assembly = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work\assembly.dll" : "/mnt/work/assembly.dll"; + var stringBuilderConsole = new StringBuilderConsole(); var stopwatchFactory = new StopwatchFactory(); - var terminalReporter = new TerminalTestReporter(stringBuilderConsole, new TerminalTestReporterOptions + var terminalReporter = new TerminalTestReporter(assembly, targetFramework, architecture, stringBuilderConsole, new CTRLPlusCCancellationTokenSource(), new TerminalTestReporterOptions { ShowPassedTests = () => true, + // Like if we autodetect that we are in ANSI capable terminal. UseAnsi = true, + UseCIAnsi = false, ForceAnsi = true, ShowActiveTests = true, - ShowAssembly = false, - ShowAssemblyStartAndComplete = false, ShowProgress = () => true, }) { @@ -193,34 +400,31 @@ public void OutputProgressFrameIsCorrect() DateTimeOffset endTime = DateTimeOffset.MaxValue; terminalReporter.TestExecutionStarted(startTime, 1, isDiscovery: false); - string targetFramework = "net8.0"; - string architecture = "x64"; - string assembly = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work\assembly.dll" : "/mnt/work/assembly.dll"; string folder = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work\" : "/mnt/work/"; string folderNoSlash = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\work" : "/mnt/work"; string folderLink = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work/" : "mnt/work/"; string folderLinkNoSlash = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work" : "mnt/work"; - terminalReporter.AssemblyRunStarted(assembly, targetFramework, architecture); + terminalReporter.AssemblyRunStarted(); string standardOutput = "Hello!"; string errorOutput = "Oh no!"; // Note: Add 1ms to make the order of the progress frame deterministic. // Otherwise all tests that run for 1m31s could show in any order. - terminalReporter.TestInProgress(assembly, targetFramework, architecture, testNodeUid: "PassedTest1", displayName: "PassedTest1"); + terminalReporter.TestInProgress(testNodeUid: "PassedTest1", displayName: "PassedTest1"); stopwatchFactory.AddTime(TimeSpan.FromMilliseconds(1)); - terminalReporter.TestInProgress(assembly, targetFramework, architecture, testNodeUid: "SkippedTest1", displayName: "SkippedTest1"); + terminalReporter.TestInProgress(testNodeUid: "SkippedTest1", displayName: "SkippedTest1"); stopwatchFactory.AddTime(TimeSpan.FromMilliseconds(1)); - terminalReporter.TestInProgress(assembly, targetFramework, architecture, testNodeUid: "InProgressTest1", displayName: "InProgressTest1"); + terminalReporter.TestInProgress(testNodeUid: "InProgressTest1", displayName: "InProgressTest1"); stopwatchFactory.AddTime(TimeSpan.FromMinutes(1)); - terminalReporter.TestInProgress(assembly, targetFramework, architecture, testNodeUid: "InProgressTest2", displayName: "InProgressTest2"); + terminalReporter.TestInProgress(testNodeUid: "InProgressTest2", displayName: "InProgressTest2"); stopwatchFactory.AddTime(TimeSpan.FromSeconds(30)); - terminalReporter.TestInProgress(assembly, targetFramework, architecture, testNodeUid: "InProgressTest3", displayName: "InProgressTest3"); + terminalReporter.TestInProgress(testNodeUid: "InProgressTest3", displayName: "InProgressTest3"); stopwatchFactory.AddTime(TimeSpan.FromSeconds(1)); - terminalReporter.TestCompleted(assembly, targetFramework, architecture, testNodeUid: "PassedTest1", "PassedTest1", TestOutcome.Passed, TimeSpan.FromSeconds(10), + terminalReporter.TestCompleted(testNodeUid: "PassedTest1", "PassedTest1", TestOutcome.Passed, TimeSpan.FromSeconds(10), informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); - terminalReporter.TestCompleted(assembly, targetFramework, architecture, testNodeUid: "SkippedTest1", "SkippedTest1", TestOutcome.Skipped, TimeSpan.FromSeconds(10), + terminalReporter.TestCompleted(testNodeUid: "SkippedTest1", "SkippedTest1", TestOutcome.Skipped, TimeSpan.FromSeconds(10), informativeMessage: null, errorMessage: null, exception: null, expected: null, actual: null, standardOutput, errorOutput); string output = stringBuilderConsole.Output; @@ -233,29 +437,29 @@ public void OutputProgressFrameIsCorrect() // Note: The progress is drawn after each completed event. string expected = $""" - {busyIndicatorString}␛[?25l␛[92mpassed␛[m PassedTest1␛[90m ␛[90m(10s 000ms)␛[m + {busyIndicatorString}␛[?25l␛[32mpassed␛[m PassedTest1␛[90m ␛[90m(10s 000ms)␛[m ␛[90m Standard output Hello! Error output Oh no! ␛[m - [␛[92m✓1␛[m/␛[91mx0␛[m/␛[93m↓0␛[m] assembly.dll (net8.0|x64)␛[2147483640G(1m 31s) + [␛[32m✓1␛[m/␛[31mx0␛[m/␛[33m↓0␛[m] assembly.dll (net8.0|x64)␛[2147483640G(1m 31s) SkippedTest1␛[2147483640G(1m 31s) InProgressTest1␛[2147483640G(1m 31s) InProgressTest2␛[2147483643G(31s) InProgressTest3␛[2147483644G(1s) ␛[7F - ␛[J␛[93mskipped␛[m SkippedTest1␛[90m ␛[90m(10s 000ms)␛[m + ␛[J␛[33mskipped␛[m SkippedTest1␛[90m ␛[90m(10s 000ms)␛[m ␛[90m Standard output Hello! Error output Oh no! ␛[m - [␛[92m✓1␛[m/␛[91mx0␛[m/␛[93m↓1␛[m] assembly.dll (net8.0|x64)␛[2147483640G(1m 31s) + [␛[32m✓1␛[m/␛[31mx0␛[m/␛[33m↓1␛[m] assembly.dll (net8.0|x64)␛[2147483640G(1m 31s) InProgressTest1␛[2147483640G(1m 31s) InProgressTest2␛[2147483643G(31s) InProgressTest3␛[2147483644G(1s) - + """; Assert.AreEqual(expected, ShowEscape(output)); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TreeNodeFilterTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TreeNodeFilterTests.cs index f587f02457..241cf0a1d9 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TreeNodeFilterTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TreeNodeFilterTests.cs @@ -3,8 +3,8 @@ using Microsoft.Testing.Platform.Extensions.Messages; using Microsoft.Testing.Platform.Requests; +#pragma warning disable CS0618 // Type or member is obsolete -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. namespace Microsoft.Testing.Platform.UnitTests; [TestClass] @@ -26,10 +26,10 @@ public void MatchAllFilter_MatchesSubpaths() } [TestMethod] - public void MatchAllFilter_Invalid() => Assert.ThrowsException(() => _ = new TreeNodeFilter("/A(&B)")); + public void MatchAllFilter_Invalid() => Assert.ThrowsExactly(() => _ = new TreeNodeFilter("/A(&B)")); [TestMethod] - public void MatchAllFilter_DoNotAllowInMiddleOfFilter() => Assert.ThrowsException(() => _ = new TreeNodeFilter("/**/Path")); + public void MatchAllFilter_DoNotAllowInMiddleOfFilter() => Assert.ThrowsExactly(() => _ = new TreeNodeFilter("/**/Path")); [TestMethod] public void MatchWildcard_MatchesSubstrings() @@ -59,7 +59,7 @@ public void EscapeSequences_SupportsParentheses() } [TestMethod] - public void EscapeSequences_ThrowsIfLastCharIsAnEscapeChar() => Assert.ThrowsException(() => _ = new TreeNodeFilter("/*.\\(UnitTests\\)\\")); + public void EscapeSequences_ThrowsIfLastCharIsAnEscapeChar() => Assert.ThrowsExactly(() => _ = new TreeNodeFilter("/*.\\(UnitTests\\)\\")); [TestMethod] public void OrExpression_WorksForLiteralStrings() @@ -80,6 +80,112 @@ public void AndExpression() Assert.IsFalse(filter.MatchesFilter("/ProjectC.UnitTests.SomeExtension", new PropertyBag())); } + [TestMethod] + public void NotExpression_DisallowSuffix() + { + TreeNodeFilter filter = new("/(!*UnitTests)"); + Assert.IsFalse(filter.MatchesFilter("/A.UnitTests", new PropertyBag())); + Assert.IsFalse(filter.MatchesFilter("/UnitTests", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/A", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/UnitTests.A", new PropertyBag())); + } + + [TestMethod] + public void NotExpression_DisallowPrefix() + { + TreeNodeFilter filter = new("/(!UnitTests*)"); + Assert.IsFalse(filter.MatchesFilter("/UnitTests.A", new PropertyBag())); + Assert.IsFalse(filter.MatchesFilter("/UnitTests", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/A", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/A.UnitTests", new PropertyBag())); + } + + [TestMethod] + public void NotExpression_DisallowContains() + { + TreeNodeFilter filter = new("/(!*UnitTests*)"); + Assert.IsFalse(filter.MatchesFilter("/UnitTests.A", new PropertyBag())); + Assert.IsFalse(filter.MatchesFilter("/A.UnitTests", new PropertyBag())); + Assert.IsFalse(filter.MatchesFilter("/UnitTests", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/A", new PropertyBag())); + } + + [TestMethod] + public void NotExpression_CombinedWithAND_Parenthesized() + { + // Matches anything except A*Z + TreeNodeFilter filter = new("/(!(A*&*Z))"); + Assert.IsFalse(filter.MatchesFilter("/AZ", new PropertyBag())); // !(true && true) ==> false + Assert.IsFalse(filter.MatchesFilter("/ABCZ", new PropertyBag())); // !(true && true) ==> false + Assert.IsTrue(filter.MatchesFilter("/C", new PropertyBag())); // !(false && false) ==> true + Assert.IsTrue(filter.MatchesFilter("/A", new PropertyBag())); // !(true && false) ==> true + Assert.IsTrue(filter.MatchesFilter("/ABC", new PropertyBag())); // !(true && false) ==> true + Assert.IsTrue(filter.MatchesFilter("/Z", new PropertyBag())); // !(false && true) ==> true + Assert.IsTrue(filter.MatchesFilter("/XYZ", new PropertyBag())); // !(false && true) ==> true + } + + [TestMethod] + public void NotExpression_CombinedWithOR_Parenthesized() + { + // Doesn't match A*, and also doesn't match *Z + TreeNodeFilter filter = new("/(!(A*|*Z))"); + Assert.IsFalse(filter.MatchesFilter("/AZ", new PropertyBag())); // !(true || true) ==> false + Assert.IsFalse(filter.MatchesFilter("/AB", new PropertyBag())); // !(true || false) ==> false + Assert.IsFalse(filter.MatchesFilter("/A", new PropertyBag())); // !(true || true) ==> false + Assert.IsFalse(filter.MatchesFilter("/ABZ", new PropertyBag())); // !(true || true) ==> false + Assert.IsFalse(filter.MatchesFilter("/YZ", new PropertyBag())); // !(false || true) ==> false + Assert.IsFalse(filter.MatchesFilter("/Z", new PropertyBag())); // !(false || true) ==> false + + Assert.IsTrue(filter.MatchesFilter("/C", new PropertyBag())); // !(false || false) ==> true + Assert.IsTrue(filter.MatchesFilter("/CA", new PropertyBag())); // !(false || false) ==> true + Assert.IsTrue(filter.MatchesFilter("/ZS", new PropertyBag())); // !(false || false) ==> true + Assert.IsTrue(filter.MatchesFilter("/ZA", new PropertyBag())); // !(false || false) ==> true + Assert.IsTrue(filter.MatchesFilter("/ZYYA", new PropertyBag())); // !(false || false) ==> true + } + + [TestMethod] + public void NotExpression_CombinedWithAND_NotParenthesized() + { + // Matches anything that doesn't start with A, but should end with Z + TreeNodeFilter filter = new("/(!A*&*Z)"); + + // Cases not ending with Z, filter doesn't match. + Assert.IsFalse(filter.MatchesFilter("/A", new PropertyBag())); + Assert.IsFalse(filter.MatchesFilter("/ZA", new PropertyBag())); + Assert.IsFalse(filter.MatchesFilter("/AZA", new PropertyBag())); + + // Cases ending with Z but starts with A. Filter shouldn't match. + Assert.IsFalse(filter.MatchesFilter("/AZ", new PropertyBag())); + Assert.IsFalse(filter.MatchesFilter("/ABZ", new PropertyBag())); + + // Cases ending with Z and don't start with A. Filter should match. + Assert.IsTrue(filter.MatchesFilter("/BAZ", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/BZ", new PropertyBag())); + } + + [TestMethod] + public void NotExpression_CombinedWithOR_NotParenthesized() + { + // Matches anything that either doesn't start with A, or ends with Z + TreeNodeFilter filter = new("/(!A*|*Z)"); + + // Cases not starting with A + Assert.IsTrue(filter.MatchesFilter("/Y", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/Z", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/ZA", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/ZAZ", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/YAZ", new PropertyBag())); + + // Cases starting with A, and ending with Z + Assert.IsTrue(filter.MatchesFilter("/AZ", new PropertyBag())); + Assert.IsTrue(filter.MatchesFilter("/ABZ", new PropertyBag())); + + // Cases starting with A, and not ending with Z + Assert.IsFalse(filter.MatchesFilter("/A", new PropertyBag())); + Assert.IsFalse(filter.MatchesFilter("/AB", new PropertyBag())); + Assert.IsFalse(filter.MatchesFilter("/AZB", new PropertyBag())); + } + [TestMethod] public void Parentheses_EnsuresOrdering() { @@ -94,7 +200,7 @@ public void Parentheses_EnsuresOrdering() [TestMethod] public void Parenthesis_DisallowSeparatorInside() - => Assert.ThrowsException(() => new TreeNodeFilter("/(A/B)")); + => Assert.ThrowsExactly(() => new TreeNodeFilter("/(A/B)")); [TestMethod] public void Parameters_PropertyCheck() @@ -143,19 +249,19 @@ public void Parameters_NegatedPropertyCheckCombinedWithOr() [TestMethod] public void Parameters_DisallowAtStart() - => Assert.ThrowsException(() => _ = new TreeNodeFilter("/[Tag=Fast]")); + => Assert.ThrowsExactly(() => _ = new TreeNodeFilter("/[Tag=Fast]")); [TestMethod] public void Parameters_DisallowEmpty() - => Assert.ThrowsException(() => _ = new TreeNodeFilter("/Path[]")); + => Assert.ThrowsExactly(() => _ = new TreeNodeFilter("/Path[]")); [TestMethod] public void Parameters_DisallowMultiple() - => Assert.ThrowsException(() => _ = new TreeNodeFilter("/Path[Prop=2][Prop=B]")); + => Assert.ThrowsExactly(() => _ = new TreeNodeFilter("/Path[Prop=2][Prop=B]")); [TestMethod] public void Parameters_DisallowNested() - => Assert.ThrowsException(() => _ = new TreeNodeFilter("/Path[X=[Y=1]]")); + => Assert.ThrowsExactly(() => _ = new TreeNodeFilter("/Path[X=[Y=1]]")); [DataRow("/A/B", "/A/B", true)] [DataRow("/A/B", "/A%2FB", false)] @@ -221,5 +327,13 @@ public void MatchAllFilterSubpathWithPropertyExpression() } [TestMethod] - public void MatchAllFilterWithPropertyExpression_DoNotAllowInMiddleOfFilter() => Assert.ThrowsException(() => _ = new TreeNodeFilter("/**/Path[A=B]")); + public void MatchAllFilterSubpathWithPropertyExpression_WithTestMetadataProperty() + { + TreeNodeFilter filter = new("/A/**[A=B]"); + Assert.IsTrue(filter.MatchesFilter("/A/B/C/D", new PropertyBag(new TestMetadataProperty("A", "B")))); + Assert.IsFalse(filter.MatchesFilter("/B/A/C/D", new PropertyBag(new TestMetadataProperty("A", "B")))); + } + + [TestMethod] + public void MatchAllFilterWithPropertyExpression_DoNotAllowInMiddleOfFilter() => Assert.ThrowsExactly(() => _ = new TreeNodeFilter("/**/Path[A=B]")); } diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/FormatterUtilitiesTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/FormatterUtilitiesTests.cs index 75b6c6ee89..6fff45047f 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/FormatterUtilitiesTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/FormatterUtilitiesTests.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - using Microsoft.Testing.Platform.Extensions.Messages; using Microsoft.Testing.Platform.ServerMode; @@ -363,7 +361,7 @@ private static object CreateInstance(Type type) if (type == typeof(TestsAttachments)) { - return new TestsAttachments(new RunTestAttachment[] { new("Uri", "Producer", "Type", "DisplayName", "Description") }); + return new TestsAttachments([new("Uri", "Producer", "Type", "DisplayName", "Description")]); } if (type == typeof(RunTestAttachment)) diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/JsonTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/JsonTests.cs index cfa9e68ac5..f3e0ffd468 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/JsonTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/JsonTests.cs @@ -16,13 +16,13 @@ public sealed class JsonTests public JsonTests() { - Dictionary serializers = new(); - Dictionary deserializers = new(); + Dictionary serializers = []; + Dictionary deserializers = []; foreach (Type serializableType in SerializerUtilities.SerializerTypes) { serializers[serializableType] = new JsonObjectSerializer( - o => SerializerUtilities.Serialize(serializableType, o).Select(kvp => (kvp.Key, kvp.Value)).ToArray()); + o => [.. SerializerUtilities.Serialize(serializableType, o).Select(kvp => (kvp.Key, kvp.Value))]); } foreach (Type deserializableType in SerializerUtilities.DeserializerTypes) @@ -125,43 +125,14 @@ public void DeserializePerson() [typeof(Person)] = new JsonElementDeserializer((json, jsonElement) => new Person { Name = json.Bind(jsonElement, "name"), - Children = json.Bind>(jsonElement, "children"), }), - - [typeof(List)] = new JsonCollectionDeserializer, Person>(_ => [], (c, i) => c.Add(i)), }); // Act - Person actual = json.Deserialize(new("""{"name":"Thomas","children":[{"name":"Ruth","children":null}]}""".ToCharArray())); + Person actual = json.Deserialize(new("""{"name":"Thomas"}""".ToCharArray())); // Assert Assert.AreEqual("Thomas", actual.Name); - Assert.AreEqual(1, actual.Children!.Count); - Assert.AreEqual("Ruth", actual.Children![0].Name); - Assert.IsNull(actual.Children![0].Children); - } - - [TestMethod] - public void DeserializePersonList() - { - // Arrange - Json json = new(null, new Dictionary - { - [typeof(Person)] = new JsonElementDeserializer((json, jsonElement) => new Person - { - Name = json.Bind(jsonElement, "name"), - Children = json.Bind>(jsonElement, "children"), - }), - - [typeof(List)] = new JsonCollectionDeserializer, Person>(_ => [], (c, i) => c.Add(i)), - }); - - // Act - List actual = json.Deserialize>(new("""[{"name":"Thomas","children":[{"name":"Ruth","children":null}]}]""".ToCharArray())); - - // Assert - Assert.AreEqual(1, actual.Count); - Assert.AreEqual("Thomas", actual[0].Name); } private sealed class Person diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/JsoniteTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/JsoniteTests.cs index d2aa862511..ebc6fac83b 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/JsoniteTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/JsoniteTests.cs @@ -22,7 +22,7 @@ public void Serialize_SpecialCharacters() { // This test is testing if we can serialize the range 0x0000 - 0x001FF correctly, this range contains special characters like NUL. // This is a fix for Jsonite, which throws when such characters are found in a string (but does not fail when we provide them as character). - List errors = new(); + List errors = []; // This could be converted to Data source, but this way we have more control about where in the result message the // special characters will be (hopefully nowhere) so in case of failure, we can still serialize the message to IDE diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerDataConsumerServiceTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerDataConsumerServiceTests.cs index e1703f6e8d..8fe8ab2684 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerDataConsumerServiceTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerDataConsumerServiceTests.cs @@ -64,7 +64,7 @@ public async Task ConsumeAsync_WithTestNodeUpdatedMessage() await _service.ConsumeAsync(producer, testNode, CancellationToken.None).ConfigureAwait(false); List actual = _service.Artifacts; - Assert.AreEqual(0, actual.Count); + Assert.IsEmpty(actual); } [TestMethod] diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.cs index 6d14e1a477..f3c215d8c8 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.cs @@ -38,7 +38,7 @@ public async Task ServerCanBeStartedAndAborted_TcpIp() => await RetryHelper.Retr TestApplicationHooks testApplicationHooks = new(); string[] args = ["--no-banner", "--server", "--client-host", "localhost", "--client-port", $"{server.Port}", "--internal-testingplatform-skipbuildercheck"]; ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(args); - builder.TestHost.AddTestApplicationLifecycleCallbacks(_ => testApplicationHooks); + builder.TestHost.AddTestHostApplicationLifetime(_ => testApplicationHooks); builder.RegisterTestFramework(_ => new TestFrameworkCapabilities(), (_, __) => new MockTestAdapter()); var testApplication = (TestApplication)await builder.BuildAsync(); testApplication.ServiceProvider.GetRequiredService().SuppressOutput(); @@ -59,7 +59,7 @@ public async Task ServerCanInitialize() string[] args = ["--no-banner", "--server", "--client-port", $"{server.Port}", "--internal-testingplatform-skipbuildercheck"]; TestApplicationHooks testApplicationHooks = new(); ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(args); - builder.TestHost.AddTestApplicationLifecycleCallbacks(_ => testApplicationHooks); + builder.TestHost.AddTestHostApplicationLifetime(_ => testApplicationHooks); builder.RegisterTestFramework(_ => new TestFrameworkCapabilities(), (_, __) => new MockTestAdapter()); var testApplication = (TestApplication)await builder.BuildAsync(); testApplication.ServiceProvider.GetRequiredService().SuppressOutput(); @@ -252,7 +252,7 @@ private static async Task WriteMessageAsync(StreamWriter writer, string message) await writer.FlushAsync(); } - private sealed class TestApplicationHooks : ITestApplicationLifecycleCallbacks, IDisposable + private sealed class TestApplicationHooks : ITestHostApplicationLifetime, IDisposable { private readonly SemaphoreSlim _waitForBeforeRunAsync = new(0, 1); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/ServiceProviderTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/ServiceProviderTests.cs index 1ad71b8e80..431b5054a3 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/ServiceProviderTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/ServiceProviderTests.cs @@ -32,7 +32,10 @@ public void GetService_InternalExtension_ShouldNotReturn() Assert.IsNull(_serviceProvider.GetService()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); +#pragma warning disable CS0618 // Type or member is obsolete Assert.IsNull(_serviceProvider.GetService()); +#pragma warning restore CS0618 // Type or member is obsolete + Assert.IsNull(_serviceProvider.GetService()); } [TestMethod] @@ -51,7 +54,10 @@ public void GetServiceInternal_InternalExtension_ShouldReturn() Assert.IsNotNull(_serviceProvider.GetServiceInternal()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); +#pragma warning disable CS0618 // Type or member is obsolete Assert.IsNotNull(_serviceProvider.GetServiceInternal()); +#pragma warning restore CS0618 // Type or member is obsolete + Assert.IsNotNull(_serviceProvider.GetServiceInternal()); } [TestMethod] @@ -83,17 +89,17 @@ public void Clone_WithFilter_Succeeded() var clonedServiceProvider = (ServiceProvider)_serviceProvider.Clone(o => o is TestHostProcessLifetimeHandler); - Assert.AreEqual(1, clonedServiceProvider.Services.Count); + Assert.HasCount(1, clonedServiceProvider.Services); Assert.AreEqual(_serviceProvider.Services.ToArray()[0].GetType(), typeof(TestHostProcessLifetimeHandler)); } [TestMethod] public void AddService_TestFramework_ShouldFail() - => Assert.ThrowsException(() => _serviceProvider.AddService(new TestFramework())); + => Assert.ThrowsExactly(() => _serviceProvider.AddService(new TestFramework())); [TestMethod] public void TryAddService_TestFramework_ShouldFail() - => Assert.ThrowsException(() => _serviceProvider.TryAddService(new TestFramework())); + => Assert.ThrowsExactly(() => _serviceProvider.TryAddService(new TestFramework())); [TestMethod] public void AddService_TestFramework_ShouldNotFail() @@ -114,7 +120,7 @@ public void AddService_SameInstance_ShouldFail() { TestHostProcessLifetimeHandler instance = new(); _serviceProvider.AddService(instance); - _ = Assert.ThrowsException(() => _serviceProvider.AddService(instance)); + _ = Assert.ThrowsExactly(() => _serviceProvider.AddService(instance)); } [TestMethod] @@ -130,7 +136,7 @@ public void AddServices_SameInstance_ShouldFail() { TestHostProcessLifetimeHandler instance = new(); _serviceProvider.AddServices([instance]); - _ = Assert.ThrowsException(() => _serviceProvider.AddServices([instance])); + _ = Assert.ThrowsExactly(() => _serviceProvider.AddServices([instance])); } [TestMethod] @@ -155,7 +161,10 @@ public void GetServicesInternal_ExtensionMethod_InternalExtension_ShouldReturn() _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); +#pragma warning disable CS0618 // Type or member is obsolete Assert.AreEqual(2, _serviceProvider.GetServicesInternal().Count()); +#pragma warning restore CS0618 // Type or member is obsolete + Assert.AreEqual(2, _serviceProvider.GetServicesInternal().Count()); } [TestMethod] @@ -164,7 +173,10 @@ public void GetServicesInternal_InternalExtension_ShouldNotReturn() _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); +#pragma warning disable CS0618 // Type or member is obsolete Assert.AreEqual(0, _serviceProvider.GetServicesInternal(typeof(ITestApplicationLifecycleCallbacks), stopAtFirst: false, skipInternalOnlyExtensions: true).Count()); +#pragma warning restore CS0618 // Type or member is obsolete + Assert.AreEqual(0, _serviceProvider.GetServicesInternal(typeof(ITestHostApplicationLifetime), stopAtFirst: false, skipInternalOnlyExtensions: true).Count()); } [TestMethod] @@ -173,7 +185,10 @@ public void GetServicesInternal_InternalExtension_ShouldReturn() _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); +#pragma warning disable CS0618 // Type or member is obsolete Assert.AreEqual(2, _serviceProvider.GetServicesInternal(typeof(ITestApplicationLifecycleCallbacks), stopAtFirst: false, skipInternalOnlyExtensions: false).Count()); +#pragma warning restore CS0618 // Type or member is obsolete + Assert.AreEqual(2, _serviceProvider.GetServicesInternal(typeof(ITestHostApplicationLifetime), stopAtFirst: false, skipInternalOnlyExtensions: false).Count()); } [TestMethod] @@ -182,7 +197,10 @@ public void GetServicesInternal_InternalExtension_FirstOnly_ShouldReturnOne() _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); +#pragma warning disable CS0618 // Type or member is obsolete Assert.AreEqual(1, _serviceProvider.GetServicesInternal(typeof(ITestApplicationLifecycleCallbacks), stopAtFirst: true, skipInternalOnlyExtensions: false).Count()); +#pragma warning restore CS0618 // Type or member is obsolete + Assert.AreEqual(1, _serviceProvider.GetServicesInternal(typeof(ITestHostApplicationLifetime), stopAtFirst: true, skipInternalOnlyExtensions: false).Count()); } [TestMethod] @@ -191,7 +209,10 @@ public void GetServiceInternal_InternalExtension_ShouldReturnOne() _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); +#pragma warning disable CS0618 // Type or member is obsolete Assert.IsNotNull(_serviceProvider.GetServiceInternal(typeof(ITestApplicationLifecycleCallbacks), skipInternalOnlyExtensions: false)); +#pragma warning restore CS0618 // Type or member is obsolete + Assert.IsNotNull(_serviceProvider.GetServiceInternal(typeof(ITestHostApplicationLifetime), skipInternalOnlyExtensions: false)); } [TestMethod] @@ -200,7 +221,10 @@ public void GetServiceInternal_InternalExtension_SkipInternalOnlyExtensions_Shou _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); +#pragma warning disable CS0618 // Type or member is obsolete Assert.IsNull(_serviceProvider.GetServiceInternal(typeof(ITestApplicationLifecycleCallbacks), skipInternalOnlyExtensions: true)); +#pragma warning restore CS0618 // Type or member is obsolete + Assert.IsNull(_serviceProvider.GetServiceInternal(typeof(ITestHostApplicationLifetime), skipInternalOnlyExtensions: true)); } private sealed class TestFramework : ITestFramework @@ -294,7 +318,7 @@ private sealed class DataConsumer : IDataConsumer public Task IsEnabledAsync() => throw new NotImplementedException(); } - private sealed class TestApplicationLifecycleCallbacks : ITestApplicationLifecycleCallbacks + private sealed class TestApplicationLifecycleCallbacks : ITestHostApplicationLifetime { public string Uid => throw new NotImplementedException(); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/TestApplicationResultTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/TestApplicationResultTests.cs index 580fd28310..1d74be935a 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/TestApplicationResultTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/TestApplicationResultTests.cs @@ -214,10 +214,10 @@ public void GetProcessExitCodeAsync_IgnoreExitCodes(string? argument, int expect internal static IEnumerable FailedState() { - yield return new[] { new FailedTestNodeStateProperty() }; - yield return new[] { new ErrorTestNodeStateProperty() }; - yield return new[] { new CancelledTestNodeStateProperty() }; - yield return new[] { new TimeoutTestNodeStateProperty() }; + yield return [new FailedTestNodeStateProperty()]; + yield return [new ErrorTestNodeStateProperty()]; + yield return [new CancelledTestNodeStateProperty()]; + yield return [new TimeoutTestNodeStateProperty()]; } private sealed class CommandLineOption : ICommandLineOptions diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Telemetry/TelemetryManagerTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Telemetry/TelemetryManagerTests.cs index 763032a277..fd54131f0a 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Telemetry/TelemetryManagerTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Telemetry/TelemetryManagerTests.cs @@ -169,7 +169,7 @@ public async Task TelemetryManager_SentinelIsWrittenPerUserAndAvoidsShowingNotic // Combination of where LOCALAPPDATA or HOME is, the name of the exe and our file extension. string path = Path.Combine("sentinelDir", "Microsoft", "TestingPlatform", "myExe.testingPlatformFirstTimeUseSentinel"); - fileSystemMock.Verify(f => f.Exists(path), Times.Once); + fileSystemMock.Verify(f => f.ExistFile(path), Times.Once); // Message was written to screen. outputDevice.Verify(c => c.DisplayAsync(It.IsAny(), It.IsAny()), Times.Once); @@ -181,9 +181,9 @@ public async Task TelemetryManager_SentinelIsWrittenPerUserAndAvoidsShowingNotic outputDevice.Invocations.Clear(); fileSystemMock.Invocations.Clear(); - fileSystemMock.Setup(f => f.Exists(path)).Returns(true); + fileSystemMock.Setup(f => f.ExistFile(path)).Returns(true); await telemetryManager.BuildAsync(serviceProvider, loggerFactoryMock.Object, options); - fileSystemMock.Verify(f => f.Exists(path), Times.Once); + fileSystemMock.Verify(f => f.ExistFile(path), Times.Once); // Message is not written to screen. outputDevice.Verify(c => c.DisplayAsync(It.IsAny(), It.IsAny()), Times.Never); @@ -237,7 +237,7 @@ public async Task TelemetryManager_SentinelIsWrittenOnlyWhenUserWouldSeeTheMessa string path = Path.Combine("sentinelDir", "Microsoft", "TestingPlatform", "myExe.testingPlatformFirstTimeUseSentinel"); // We should not check for the sentinel, because we disabled the logo. - fileSystemMock.Verify(f => f.Exists(path), Times.Never); + fileSystemMock.Verify(f => f.ExistFile(path), Times.Never); // Message was not written to screen. outputDevice.Verify(c => c.DisplayAsync(It.IsAny(), It.IsAny()), Times.Never); @@ -252,9 +252,9 @@ public async Task TelemetryManager_SentinelIsWrittenOnlyWhenUserWouldSeeTheMessa // Enable showing the telemetry message. environmentMock.Setup(s => s.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_NOBANNER)).Returns("0"); - fileSystemMock.Setup(f => f.Exists(path)).Returns(false); + fileSystemMock.Setup(f => f.ExistFile(path)).Returns(false); await telemetryManager.BuildAsync(serviceProvider, loggerFactoryMock.Object, options); - fileSystemMock.Verify(f => f.Exists(path), Times.Once); + fileSystemMock.Verify(f => f.ExistFile(path), Times.Once); // Message is written to screen. outputDevice.Verify(c => c.DisplayAsync(It.IsAny(), It.IsAny()), Times.Once); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/TestApplicationBuilderTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/TestApplicationBuilderTests.cs index d35d3d8e62..48445513ee 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/TestApplicationBuilderTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/TestApplicationBuilderTests.cs @@ -30,9 +30,9 @@ public TestApplicationBuilderTests() public async Task TestApplicationLifecycleCallbacks_DuplicatedId_ShouldFail() { TestHostManager testHostManager = new(); - testHostManager.AddTestApplicationLifecycleCallbacks(_ => new ApplicationLifecycleCallbacks("duplicatedId")); - testHostManager.AddTestApplicationLifecycleCallbacks(_ => new ApplicationLifecycleCallbacks("duplicatedId")); - InvalidOperationException invalidOperationException = await Assert.ThrowsExceptionAsync(() => testHostManager.BuildTestApplicationLifecycleCallbackAsync(_serviceProvider)); + testHostManager.AddTestHostApplicationLifetime(_ => new ApplicationLifecycleCallbacks("duplicatedId")); + testHostManager.AddTestHostApplicationLifetime(_ => new ApplicationLifecycleCallbacks("duplicatedId")); + InvalidOperationException invalidOperationException = await Assert.ThrowsExactlyAsync(() => testHostManager.BuildTestApplicationLifecycleCallbackAsync(_serviceProvider)); Assert.IsTrue(invalidOperationException.Message.Contains("duplicatedId") && invalidOperationException.Message.Contains(typeof(ApplicationLifecycleCallbacks).ToString())); } @@ -42,7 +42,7 @@ public async Task DataConsumer_DuplicatedId_ShouldFail() TestHostManager testHostManager = new(); testHostManager.AddDataConsumer(_ => new Consumer("duplicatedId")); testHostManager.AddDataConsumer(_ => new Consumer("duplicatedId")); - InvalidOperationException invalidOperationException = await Assert.ThrowsExceptionAsync(() => testHostManager.BuildDataConsumersAsync(_serviceProvider, [])); + InvalidOperationException invalidOperationException = await Assert.ThrowsExactlyAsync(() => testHostManager.BuildDataConsumersAsync(_serviceProvider, [])); Assert.IsTrue(invalidOperationException.Message.Contains("duplicatedId") && invalidOperationException.Message.Contains(typeof(Consumer).ToString())); } @@ -53,7 +53,7 @@ public async Task DataConsumer_DuplicatedIdWithCompositeFactory_ShouldFail() CompositeExtensionFactory compositeExtensionFactory = new(() => new Consumer("duplicatedId")); testHostManager.AddDataConsumer(_ => new Consumer("duplicatedId")); testHostManager.AddDataConsumer(compositeExtensionFactory); - InvalidOperationException invalidOperationException = await Assert.ThrowsExceptionAsync(() => testHostManager.BuildDataConsumersAsync(_serviceProvider, [])); + InvalidOperationException invalidOperationException = await Assert.ThrowsExactlyAsync(() => testHostManager.BuildDataConsumersAsync(_serviceProvider, [])); Assert.IsTrue(invalidOperationException.Message.Contains("duplicatedId") && invalidOperationException.Message.Contains(typeof(Consumer).ToString())); } @@ -63,7 +63,7 @@ public async Task TestSessionLifetimeHandle_DuplicatedId_ShouldFail() TestHostManager testHostManager = new(); testHostManager.AddTestSessionLifetimeHandle(_ => new TestSessionLifetimeHandler("duplicatedId")); testHostManager.AddTestSessionLifetimeHandle(_ => new TestSessionLifetimeHandler("duplicatedId")); - InvalidOperationException invalidOperationException = await Assert.ThrowsExceptionAsync(() => testHostManager.BuildTestSessionLifetimeHandleAsync(_serviceProvider, [])); + InvalidOperationException invalidOperationException = await Assert.ThrowsExactlyAsync(() => testHostManager.BuildTestSessionLifetimeHandleAsync(_serviceProvider, [])); Assert.IsTrue(invalidOperationException.Message.Contains("duplicatedId") && invalidOperationException.Message.Contains(typeof(TestSessionLifetimeHandler).ToString())); } @@ -74,7 +74,7 @@ public async Task TestSessionLifetimeHandle_DuplicatedIdWithCompositeFactory_Sho CompositeExtensionFactory compositeExtensionFactory = new(() => new TestSessionLifetimeHandler("duplicatedId")); testHostManager.AddTestSessionLifetimeHandle(_ => new TestSessionLifetimeHandler("duplicatedId")); testHostManager.AddTestSessionLifetimeHandle(compositeExtensionFactory); - InvalidOperationException invalidOperationException = await Assert.ThrowsExceptionAsync(() => testHostManager.BuildTestSessionLifetimeHandleAsync(_serviceProvider, [])); + InvalidOperationException invalidOperationException = await Assert.ThrowsExactlyAsync(() => testHostManager.BuildTestSessionLifetimeHandleAsync(_serviceProvider, [])); Assert.IsTrue(invalidOperationException.Message.Contains("duplicatedId") && invalidOperationException.Message.Contains(typeof(TestSessionLifetimeHandler).ToString())); } @@ -91,10 +91,10 @@ public async Task TestHost_ComposeFactory_ShouldSucceed(bool withParameter) testHostManager.AddTestSessionLifetimeHandle(compositeExtensionFactory); testHostManager.AddDataConsumer(compositeExtensionFactory); List compositeExtensions = []; - IDataConsumer[] consumers = (await testHostManager.BuildDataConsumersAsync(_serviceProvider, compositeExtensions)).Select(x => (IDataConsumer)x.Consumer).ToArray(); - ITestSessionLifetimeHandler[] sessionLifetimeHandle = (await testHostManager.BuildTestSessionLifetimeHandleAsync(_serviceProvider, compositeExtensions)).Select(x => (ITestSessionLifetimeHandler)x.TestSessionLifetimeHandler).ToArray(); - Assert.AreEqual(1, consumers.Length); - Assert.AreEqual(1, sessionLifetimeHandle.Length); + IDataConsumer[] consumers = [.. (await testHostManager.BuildDataConsumersAsync(_serviceProvider, compositeExtensions)).Select(x => (IDataConsumer)x.Consumer)]; + ITestSessionLifetimeHandler[] sessionLifetimeHandle = [.. (await testHostManager.BuildTestSessionLifetimeHandleAsync(_serviceProvider, compositeExtensions)).Select(x => (ITestSessionLifetimeHandler)x.TestSessionLifetimeHandler)]; + Assert.HasCount(1, consumers); + Assert.HasCount(1, sessionLifetimeHandle); Assert.AreEqual(compositeExtensions[0].GetInstance(), consumers[0]); Assert.AreEqual(compositeExtensions[0].GetInstance(), sessionLifetimeHandle[0]); } @@ -105,7 +105,7 @@ public async Task TestHostControllerEnvironmentVariableProvider_DuplicatedId_Sho TestHostControllersManager testHostControllerManager = new(); testHostControllerManager.AddEnvironmentVariableProvider(_ => new TestHostEnvironmentVariableProvider("duplicatedId")); testHostControllerManager.AddEnvironmentVariableProvider(_ => new TestHostEnvironmentVariableProvider("duplicatedId")); - InvalidOperationException invalidOperationException = await Assert.ThrowsExceptionAsync(() => testHostControllerManager.BuildAsync(_serviceProvider)); + InvalidOperationException invalidOperationException = await Assert.ThrowsExactlyAsync(() => testHostControllerManager.BuildAsync(_serviceProvider)); Assert.IsTrue(invalidOperationException.Message.Contains("duplicatedId") && invalidOperationException.Message.Contains(typeof(TestHostEnvironmentVariableProvider).ToString())); } @@ -116,7 +116,7 @@ public async Task TestHostControllerEnvironmentVariableProvider_DuplicatedIdWith CompositeExtensionFactory compositeExtensionFactory = new(() => new TestHostEnvironmentVariableProvider("duplicatedId")); testHostControllerManager.AddEnvironmentVariableProvider(_ => new TestHostEnvironmentVariableProvider("duplicatedId")); testHostControllerManager.AddEnvironmentVariableProvider(compositeExtensionFactory); - InvalidOperationException invalidOperationException = await Assert.ThrowsExceptionAsync(() => testHostControllerManager.BuildAsync(_serviceProvider)); + InvalidOperationException invalidOperationException = await Assert.ThrowsExactlyAsync(() => testHostControllerManager.BuildAsync(_serviceProvider)); Assert.IsTrue(invalidOperationException.Message.Contains("duplicatedId") && invalidOperationException.Message.Contains(typeof(TestHostEnvironmentVariableProvider).ToString())); } @@ -126,7 +126,7 @@ public async Task TestHostControllerProcessLifetimeHandler_DuplicatedId_ShouldFa TestHostControllersManager testHostControllerManager = new(); testHostControllerManager.AddProcessLifetimeHandler(_ => new TestHostProcessLifetimeHandler("duplicatedId")); testHostControllerManager.AddProcessLifetimeHandler(_ => new TestHostProcessLifetimeHandler("duplicatedId")); - InvalidOperationException invalidOperationException = await Assert.ThrowsExceptionAsync(() => testHostControllerManager.BuildAsync(_serviceProvider)); + InvalidOperationException invalidOperationException = await Assert.ThrowsExactlyAsync(() => testHostControllerManager.BuildAsync(_serviceProvider)); Assert.IsTrue(invalidOperationException.Message.Contains("duplicatedId") && invalidOperationException.Message.Contains(typeof(TestHostProcessLifetimeHandler).ToString())); } @@ -137,7 +137,7 @@ public async Task TestHostControllerProcessLifetimeHandler_DuplicatedIdWithCompo CompositeExtensionFactory compositeExtensionFactory = new(() => new TestHostProcessLifetimeHandler("duplicatedId")); testHostControllerManager.AddProcessLifetimeHandler(_ => new TestHostProcessLifetimeHandler("duplicatedId")); testHostControllerManager.AddProcessLifetimeHandler(compositeExtensionFactory); - InvalidOperationException invalidOperationException = await Assert.ThrowsExceptionAsync(() => testHostControllerManager.BuildAsync(_serviceProvider)); + InvalidOperationException invalidOperationException = await Assert.ThrowsExactlyAsync(() => testHostControllerManager.BuildAsync(_serviceProvider)); Assert.IsTrue(invalidOperationException.Message.Contains("duplicatedId") && invalidOperationException.Message.Contains(typeof(TestHostProcessLifetimeHandler).ToString())); } @@ -155,8 +155,8 @@ public async Task TestHostController_ComposeFactory_ShouldSucceed(bool withParam testHostControllerManager.AddProcessLifetimeHandler(compositeExtensionFactory); TestHostControllerConfiguration configuration = await testHostControllerManager.BuildAsync(_serviceProvider); Assert.IsTrue(configuration.RequireProcessRestart); - Assert.AreEqual(1, configuration.LifetimeHandlers.Length); - Assert.AreEqual(1, configuration.EnvironmentVariableProviders.Length); + Assert.HasCount(1, configuration.LifetimeHandlers); + Assert.HasCount(1, configuration.EnvironmentVariableProviders); Assert.AreEqual((object)configuration.LifetimeHandlers[0], configuration.EnvironmentVariableProviders[0]); Assert.AreEqual(((ICompositeExtensionFactory)compositeExtensionFactory).GetInstance(), configuration.LifetimeHandlers[0]); Assert.AreEqual(((ICompositeExtensionFactory)compositeExtensionFactory).GetInstance(), configuration.EnvironmentVariableProviders[0]); @@ -171,7 +171,7 @@ public void ComposeFactory_InvalidComposition_ShouldFail(bool withParameter) withParameter ? new CompositeExtensionFactory(sp => new InvalidComposition(sp)) : new CompositeExtensionFactory(() => new InvalidComposition()); - InvalidOperationException invalidOperationException = Assert.ThrowsException(() => ((ICompositeExtensionFactory)compositeExtensionFactory).GetInstance()); + InvalidOperationException invalidOperationException = Assert.ThrowsExactly(() => ((ICompositeExtensionFactory)compositeExtensionFactory).GetInstance()); Assert.AreEqual(CompositeExtensionFactory.ValidateCompositionErrorMessage, invalidOperationException.Message); } @@ -345,7 +345,7 @@ private sealed class Consumer : IDataConsumer public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationToken cancellationToken) => throw new NotImplementedException(); } - private sealed class ApplicationLifecycleCallbacks : ITestApplicationLifecycleCallbacks + private sealed class ApplicationLifecycleCallbacks : ITestHostApplicationLifetime { public ApplicationLifecycleCallbacks(string id) => Uid = id; diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Contains.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Contains.cs index 10c11bb8b0..ea9da826ea 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Contains.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Contains.cs @@ -19,14 +19,13 @@ public partial class AssertTests : TestContainer /// /// The type parameter. /// The handler instance. - /// The assertion name. /// The exception message thrown by ComputeAssertion. - private static string GetComputeAssertionExceptionMessage(Assert.AssertSingleInterpolatedStringHandler handler, string assertionName) + private static string GetComputeAssertionExceptionMessage(Assert.AssertSingleInterpolatedStringHandler handler) { try { // This call is expected to throw when _builder is not null. - _ = handler.ComputeAssertion(assertionName); + _ = handler.ComputeAssertion(); } catch (Exception ex) { @@ -52,7 +51,7 @@ public void ComputeAssertion_WhenCollectionHasSingleElement_ReturnsElement() shouldAppend.Should().BeFalse(); // Act - int result = handler.ComputeAssertion("ContainsSingle"); + int result = handler.ComputeAssertion(); // Assert result.Should().Be(singleItem); @@ -69,7 +68,7 @@ public void ComputeAssertion_WhenCollectionDoesNotHaveSingleElement_ThrowsExcept shouldAppend.Should().BeTrue(); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert: verify that the exception message contains expected parts. exMsg.Should().Contain("ContainsSingle"); @@ -93,7 +92,7 @@ public void AppendLiteral_WhenCalled_AppendsLiteralText() handler.AppendLiteral(literal); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert: the exception message should contain the literal appended. exMsg.Should().Contain(literal); @@ -112,7 +111,7 @@ public void AppendFormatted_GenericValue_WithoutFormat_AppendsValue() handler.AppendFormatted(value); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert exMsg.Should().Contain(value); @@ -132,7 +131,7 @@ public void AppendFormatted_GenericValue_WithFormat_AppendsFormattedValue() handler.AppendFormatted(value, format); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert: Check if the value was formatted accordingly ("00123") exMsg.Should().Contain("00123"); @@ -152,7 +151,7 @@ public void AppendFormatted_GenericValue_WithAlignment_AppendsAlignedValue() handler.AppendFormatted(value, alignment); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert: alignment is applied via StringBuilder.AppendFormat so result should contain formatted spacing. exMsg.Should().Contain("3.14"); @@ -173,7 +172,7 @@ public void AppendFormatted_GenericValue_WithAlignmentAndFormat_AppendsFormatted handler.AppendFormatted(value, alignment, format); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert: formatted year "2023" should appear. exMsg.Should().Contain("2023"); @@ -192,7 +191,7 @@ public void AppendFormatted_StringValue_WithoutAdditionalParameters_AppendsStrin handler.AppendFormatted(value); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert exMsg.Should().Contain(value); @@ -213,7 +212,7 @@ public void AppendFormatted_StringValue_WithAlignmentAndFormat_AppendsFormattedS handler.AppendFormatted(value, alignment, format); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert exMsg.Should().Contain(value); @@ -234,7 +233,7 @@ public void AppendFormatted_ObjectValue_WithAlignmentAndFormat_AppendsFormattedO handler.AppendFormatted(value, alignment, format); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert: Formatted value should appear (e.g. "099"). exMsg.Should().Contain("099"); @@ -254,7 +253,7 @@ public void AppendFormatted_ReadOnlySpan_AppendsSpanValue() handler.AppendFormatted(spanValue); // Act - string exMsg = GetComputeAssertionExceptionMessage(handler, "ContainsSingle"); + string exMsg = GetComputeAssertionExceptionMessage(handler); // Assert exMsg.Should().Contain("SpanText"); @@ -309,7 +308,7 @@ public void ContainsSingle_InterpolatedHandler_WithMultipleElements_ThrowsExcept Action action = () => Assert.ContainsSingle(collection, ref handler); // Assert - action.Should().Throw().WithMessage("*1*"); + action.Should().Throw().WithMessage("Assert.ContainsSingle failed. Expected collection to contain exactly one element but found 3 element(s). "); } /// @@ -592,7 +591,345 @@ public void DoesNotContain_StringVersion_SubstringPresent_ThrowsException() action.Should().Throw().WithMessage("*brown*"); } + /// + /// Tests the string DoesNotContain overload with message and parameters when substring is not present. + /// This test ensures the method overload works correctly and prevents regression of stackoverflow bug. + /// + public void DoesNotContain_StringWithMessageAndParameters_SubstringNotPresent_DoesNotThrow() + { + // Arrange + string value = "The quick brown fox"; + string substring = "lazy"; + + // Act + Action action = () => Assert.DoesNotContain(substring, value, "Custom message: {0}", "test parameter"); + + // Assert + action.Should().NotThrow(); + } + + /// + /// Tests the string DoesNotContain overload with message and parameters when substring is present. + /// This test ensures the method overload works correctly and prevents regression of stackoverflow bug. + /// Expects an exception. + /// + public void DoesNotContain_StringWithMessageAndParameters_SubstringPresent_ThrowsException() + { + // Arrange + string value = "The quick brown fox"; + string substring = "brown"; + + // Act + Action action = () => Assert.DoesNotContain(substring, value, "Found unexpected substring: {0}", substring); + + // Assert + action.Should().Throw().WithMessage("*Found unexpected substring: brown*"); + } + + /// + /// Tests the string DoesNotContain overload with StringComparison and message when substring is not present. + /// This test ensures the method overload works correctly and prevents regression of stackoverflow bug. + /// + public void DoesNotContain_StringWithComparisonAndMessage_SubstringNotPresent_DoesNotThrow() + { + // Arrange + string value = "The quick brown fox"; + string substring = "LAZY"; + + // Act + Action action = () => Assert.DoesNotContain(substring, value, StringComparison.OrdinalIgnoreCase, "Should not contain lazy"); + + // Assert + action.Should().NotThrow(); + } + + /// + /// Tests the string DoesNotContain overload with StringComparison and message when substring is present. + /// This test ensures the method overload works correctly and prevents regression of stackoverflow bug. + /// Expects an exception. + /// + public void DoesNotContain_StringWithComparisonAndMessage_SubstringPresent_ThrowsException() + { + // Arrange + string value = "The quick brown fox"; + string substring = "BROWN"; + + // Act + Action action = () => Assert.DoesNotContain(substring, value, StringComparison.OrdinalIgnoreCase, "Found unexpected substring"); + + // Assert + action.Should().Throw().WithMessage("*Found unexpected substring*"); + } + + /// + /// Tests the simplest string DoesNotContain overload when substring is not present. + /// + public void DoesNotContain_StringSimpleOverload_SubstringNotPresent_DoesNotThrow() + { + // Arrange + string value = "The quick brown fox"; + string substring = "lazy"; + + // Act + Action action = () => Assert.DoesNotContain(substring, value); + + // Assert + action.Should().NotThrow(); + } + + /// + /// Tests the simplest string DoesNotContain overload when substring is present. + /// Expects an exception. + /// + public void DoesNotContain_StringSimpleOverload_SubstringPresent_ThrowsException() + { + // Arrange + string value = "The quick brown fox"; + string substring = "brown"; + + // Act + Action action = () => Assert.DoesNotContain(substring, value); + + // Assert + action.Should().Throw().WithMessage("*brown*"); + } + + /// + /// Tests the string DoesNotContain overload with message only when substring is not present. + /// + public void DoesNotContain_StringWithMessageOnly_SubstringNotPresent_DoesNotThrow() + { + // Arrange + string value = "The quick brown fox"; + string substring = "lazy"; + + // Act + Action action = () => Assert.DoesNotContain(substring, value, "Should not contain lazy"); + + // Assert + action.Should().NotThrow(); + } + + /// + /// Tests the string DoesNotContain overload with message only when substring is present. + /// Expects an exception. + /// + public void DoesNotContain_StringWithMessageOnly_SubstringPresent_ThrowsException() + { + // Arrange + string value = "The quick brown fox"; + string substring = "brown"; + + // Act + Action action = () => Assert.DoesNotContain(substring, value, "Found unexpected substring"); + + // Assert + action.Should().Throw().WithMessage("*Found unexpected substring*"); + } + private static bool IsEven(int x) => x % 2 == 0; #endregion + + #region ContainsSingle with Predicate Tests + + /// + /// Tests the ContainsSingle method with predicate when exactly one element matches. + /// + public void ContainsSinglePredicate_NoMessage_OneItemMatches_ReturnsElement() + { + // Arrange + var collection = new List { 1, 2, 3, 4, 5 }; + + // Act + int result = Assert.ContainsSingle(x => x == 3, collection); + + // Assert + result.Should().Be(3); + } + + /// + /// Tests the ContainsSingle method with predicate and message when exactly one element matches. + /// + public void ContainsSinglePredicate_WithMessage_OneItemMatches_ReturnsElement() + { + // Arrange + var collection = new List { "apple", "banana", "cherry" }; + + // Act +#pragma warning disable CA1865 // Use char overload - not netfx + string result = Assert.ContainsSingle(x => x.StartsWith("b", StringComparison.Ordinal), collection, "Expected one item starting with 'b'"); +#pragma warning restore CA1865 // Use char overload + + // Assert + result.Should().Be("banana"); + } + + /// + /// Tests the ContainsSingle method with predicate when no elements match. + /// Expects an exception. + /// + public void ContainsSinglePredicate_NoItemMatches_ThrowsException() + { + // Arrange + var collection = new List { 1, 3, 5 }; + + // Act + Action action = () => Assert.ContainsSingle(x => x % 2 == 0, collection); + + // Assert + action.Should().Throw().WithMessage("*Expected exactly one item to match the predicate but found 0 item(s)*"); + } + + /// + /// Tests the ContainsSingle method with predicate when multiple elements match. + /// Expects an exception. + /// + public void ContainsSinglePredicate_MultipleItemsMatch_ThrowsException() + { + // Arrange + var collection = new List { 2, 4, 6, 8 }; + + // Act + Action action = () => Assert.ContainsSingle(x => x % 2 == 0, collection); + + // Assert + action.Should().Throw().WithMessage("*Expected exactly one item to match the predicate but found 4 item(s)*"); + } + + /// + /// Tests the ContainsSingle method with predicate and formatted message when no elements match. + /// Expects an exception with the custom message. + /// + public void ContainsSinglePredicate_WithMessage_NoItemMatches_ThrowsException() + { + // Arrange + var collection = new List { 1, 3, 5 }; + + // Act + Action action = () => Assert.ContainsSingle(x => x % 2 == 0, collection, $"No even numbers found in collection with {collection.Count} items"); + + // Assert + action.Should().Throw().WithMessage("*No even numbers found in collection with 3 items*"); + } + + /// + /// Tests the ContainsSingle method with predicate and formatted message when multiple elements match. + /// Expects an exception with the custom message. + /// + public void ContainsSinglePredicate_WithMessage_MultipleItemsMatch_ThrowsException() + { + // Arrange + var collection = new List { 2, 4, 6 }; + + // Act + Action action = () => Assert.ContainsSingle(x => x % 2 == 0, collection, $"Too many even numbers found: {collection.Count}"); + + // Assert + action.Should().Throw().WithMessage("*Too many even numbers found: 3*"); + } + + /// + /// Tests the ContainsSingle method with predicate using complex objects. + /// + public void ContainsSinglePredicate_ComplexObjects_OneItemMatches_ReturnsElement() + { + // Arrange + var items = new List + { + new("Alice", 25), + new("Bob", 30), + new("Charlie", 35), + }; + + // Act + Person result = Assert.ContainsSingle(p => p.Age == 30, items); + + // Assert + result.Name.Should().Be("Bob"); + result.Age.Should().Be(30); + } + + /// + /// Tests the ContainsSingle method with predicate using null values. + /// + public void ContainsSinglePredicate_WithNullValues_OneItemMatches_ReturnsElement() + { + // Arrange + var collection = new List { "apple", null, "banana" }; + + // Act + string? result = Assert.ContainsSingle(x => x == null, collection); + + // Assert + result.Should().BeNull(); + } + + #region New Error Message Tests + + /// + /// Tests that Contains (item) failure shows specific error message. + /// + public void Contains_ItemNotFound_ShowsSpecificErrorMessage() + { + // Arrange + var collection = new List { 1, 2, 3 }; + + // Act + Action action = () => Assert.Contains(5, collection); + + // Assert + action.Should().Throw().WithMessage("*Expected collection to contain the specified item*"); + } + + /// + /// Tests that Contains (predicate) failure shows specific error message. + /// + public void Contains_PredicateNotMatched_ShowsSpecificErrorMessage() + { + // Arrange + var collection = new List { 1, 3, 5 }; + + // Act + Action action = () => Assert.Contains(x => x % 2 == 0, collection); + + // Assert + action.Should().Throw().WithMessage("*Expected at least one item to match the predicate*"); + } + + /// + /// Tests that DoesNotContain (item) failure shows specific error message. + /// + public void DoesNotContain_ItemFound_ShowsSpecificErrorMessage() + { + // Arrange + var collection = new List { 1, 2, 3 }; + + // Act + Action action = () => Assert.DoesNotContain(2, collection); + + // Assert + action.Should().Throw().WithMessage("*Expected collection to not contain the specified item*"); + } + + /// + /// Tests that DoesNotContain (predicate) failure shows specific error message. + /// + public void DoesNotContain_PredicateMatched_ShowsSpecificErrorMessage() + { + // Arrange + var collection = new List { 1, 2, 3 }; + + // Act + Action action = () => Assert.DoesNotContain(x => x % 2 == 0, collection); + + // Assert + action.Should().Throw().WithMessage("*Expected no items to match the predicate*"); + } + + #endregion + + private record Person(string Name, int Age); + + #endregion } diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IComparableTests.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IComparableTests.cs new file mode 100644 index 0000000000..33267fd00f --- /dev/null +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IComparableTests.cs @@ -0,0 +1,317 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using FluentAssertions; + +using TestFramework.ForTestingMSTest; + +namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests; + +public partial class AssertTests : TestContainer +{ + #region IsGreaterThan tests + + public void IsGreaterThanShouldNotThrowWhenActualIsGreater() => + Assert.IsGreaterThan(5, 10); + + public void IsGreaterThanShouldWorkWithReferenceTypes() => + Assert.IsGreaterThan("a", "b"); + + public void IsGreaterThanShouldThrowWhenActualIsNotGreater() + { + // Act + Action action = () => Assert.IsGreaterThan(10, 5); + + // Assert + action.Should().Throw(); + } + + public void IsGreaterThanShouldThrowWhenBothAreEqual() + { + // Act + Action action = () => Assert.IsGreaterThan(5, 5); + + // Assert + action.Should().Throw(); + } + + public void IsGreaterThanShouldThrowWithMessage() + { + // Act + Action action = () => Assert.IsGreaterThan(10, 5, "A Message"); + + // Assert + action.Should().Throw() + .WithMessage("Assert.IsGreaterThan failed. Actual value <5> is not greater than expected value <10>. A Message"); + } + + public void IsGreaterThanShouldWorkWithDoubles() => + Assert.IsGreaterThan(5.0, 5.5); + + public void IsGreaterThanShouldThrowWithDoubles() + { + // Act + Action action = () => Assert.IsGreaterThan(5.5, 5.0); + + // Assert + action.Should().Throw(); + } + + #endregion + + #region IsGreaterThanOrEqualTo tests + + public void IsGreaterThanOrEqualToShouldNotThrowWhenActualIsGreater() => + Assert.IsGreaterThanOrEqualTo(5, 10); + + public void IsGreaterThanOrEqualToShouldWorkWithReferenceTypes() => + Assert.IsGreaterThanOrEqualTo("a", "b"); + + public void IsGreaterThanOrEqualToShouldNotThrowWhenBothAreEqual() => + Assert.IsGreaterThanOrEqualTo(5, 5); + + public void IsGreaterThanOrEqualToShouldThrowWhenActualIsLess() + { + // Act + Action action = () => Assert.IsGreaterThanOrEqualTo(10, 5); + + // Assert + action.Should().Throw(); + } + + public void IsGreaterThanOrEqualToShouldThrowWithMessage() + { + // Act + Action action = () => Assert.IsGreaterThanOrEqualTo(10, 5, "A Message"); + + // Assert + action.Should().Throw() + .WithMessage("Assert.IsGreaterThanOrEqualTo failed. Actual value <5> is not greater than or equal to expected value <10>. A Message"); + } + + public void IsGreaterThanOrEqualToShouldWorkWithDoubles() => + Assert.IsGreaterThanOrEqualTo(5.0, 5.5); + + public void IsGreaterThanOrEqualToShouldWorkWithEqualDoubles() => + Assert.IsGreaterThanOrEqualTo(5.5, 5.5); + + #endregion + + #region IsLessThan tests + + public void IsLessThanShouldNotThrowWhenActualIsLess() => + Assert.IsLessThan(10, 5); + + public void IsLessThanShouldWorkWithReferenceTypes() => + Assert.IsLessThan("b", "a"); + + public void IsLessThanShouldThrowWhenActualIsNotLess() + { + // Act + Action action = () => Assert.IsLessThan(5, 10); + + // Assert + action.Should().Throw(); + } + + public void IsLessThanShouldThrowWhenBothAreEqual() + { + // Act + Action action = () => Assert.IsLessThan(5, 5); + + // Assert + action.Should().Throw(); + } + + public void IsLessThanShouldThrowWithMessage() + { + // Act + Action action = () => Assert.IsLessThan(5, 10, "A Message"); + + // Assert + action.Should().Throw() + .WithMessage("Assert.IsLessThan failed. Actual value <10> is not less than expected value <5>. A Message"); + } + + public void IsLessThanShouldWorkWithDoubles() => + Assert.IsLessThan(5.5, 5.0); + + public void IsLessThanShouldThrowWithDoubles() + { + // Act + Action action = () => Assert.IsLessThan(5.0, 5.5); + + // Assert + action.Should().Throw(); + } + + #endregion + + #region IsLessThanOrEqualTo tests + + public void IsLessThanOrEqualToShouldNotThrowWhenActualIsLess() => + Assert.IsLessThanOrEqualTo(10, 5); + + public void IsLessThanOrEqualToShouldWorkWithReferenceTypes() => + Assert.IsLessThanOrEqualTo("b", "a"); + + public void IsLessThanOrEqualToShouldNotThrowWhenBothAreEqual() => + Assert.IsLessThanOrEqualTo(5, 5); + + public void IsLessThanOrEqualToShouldThrowWhenActualIsGreater() + { + // Act + Action action = () => Assert.IsLessThanOrEqualTo(5, 10); + + // Assert + action.Should().Throw(); + } + + public void IsLessThanOrEqualToShouldThrowWithMessage() + { + // Act + Action action = () => Assert.IsLessThanOrEqualTo(5, 10, "A Message"); + + // Assert + action.Should().Throw() + .WithMessage("Assert.IsLessThanOrEqualTo failed. Actual value <10> is not less than or equal to expected value <5>. A Message"); + } + + public void IsLessThanOrEqualToShouldWorkWithDoubles() => + Assert.IsLessThanOrEqualTo(5.5, 5.0); + + public void IsLessThanOrEqualToShouldWorkWithEqualDoubles() => + Assert.IsLessThanOrEqualTo(5.5, 5.5); + + #endregion + + #region IsPositive tests + + public void IsPositiveShouldNotThrowForPositiveNumber() => + Assert.IsPositive(5); + + public void IsPositiveShouldThrowForZero() + { + // Act + Action action = () => Assert.IsPositive(0); + + // Assert + action.Should().Throw(); + } + + public void IsPositiveShouldThrowForNegativeNumber() + { + // Act + Action action = () => Assert.IsPositive(-5); + + // Assert + action.Should().Throw(); + } + + public void IsPositiveShouldThrowForNaN() + { + // Act + Action action = () => Assert.IsPositive(float.NaN); + + // Assert + action.Should().Throw(); + } + + public void IsPositiveShouldThrowForDoubleNaN() + { + // Act + Action action = () => Assert.IsPositive(double.NaN); + + // Assert + action.Should().Throw(); + } + + public void IsPositiveShouldThrowWithMessage() + { + // Act + Action action = () => Assert.IsPositive(-5, "A Message"); + + // Assert + action.Should().Throw() + .WithMessage("Assert.IsPositive failed. Expected value <-5> to be positive. A Message"); + } + + public void IsPositiveShouldWorkWithDoubles() => + Assert.IsPositive(5.5); + + public void IsPositiveShouldThrowForZeroDouble() + { + // Act + Action action = () => Assert.IsPositive(0.0); + + // Assert + action.Should().Throw(); + } + + #endregion + + #region IsNegative tests + + public void IsNegativeShouldNotThrowForNegativeNumber() => + Assert.IsNegative(-5); + + public void IsNegativeShouldThrowForZero() + { + // Act + Action action = () => Assert.IsNegative(0); + + // Assert + action.Should().Throw(); + } + + public void IsNegativeShouldThrowForPositiveNumber() + { + // Act + Action action = () => Assert.IsNegative(5); + + // Assert + action.Should().Throw(); + } + + public void IsNegativeShouldThrowForNaN() + { + // Act + Action action = () => Assert.IsNegative(float.NaN); + + // Assert + action.Should().Throw(); + } + + public void IsNegativeShouldThrowForDoubleNaN() + { + // Act + Action action = () => Assert.IsNegative(double.NaN); + + // Assert + action.Should().Throw(); + } + + public void IsNegativeShouldThrowWithMessage() + { + // Act + Action action = () => Assert.IsNegative(5, "A Message"); + + // Assert + action.Should().Throw() + .WithMessage("Assert.IsNegative failed. Expected value <5> to be negative. A Message"); + } + + public void IsNegativeShouldWorkWithDoubles() => + Assert.IsNegative(-5.5); + + public void IsNegativeShouldThrowForZeroDouble() + { + // Act + Action action = () => Assert.IsNegative(0.0); + + // Assert + action.Should().Throw(); + } + + #endregion +} diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IsInRange.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IsInRange.cs new file mode 100644 index 0000000000..016b02a799 --- /dev/null +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IsInRange.cs @@ -0,0 +1,335 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using FluentAssertions; + +using TestFramework.ForTestingMSTest; + +namespace Microsoft.VisualStudio.TestTools.UnitTesting.UnitTests; + +/// +/// Unit tests for the Assert.IsInRange methods. +/// +public partial class AssertTests : TestContainer +{ + #region IsInRange Tests + + public void IsInRange_WithValueInRange_DoesNotThrow() + { + // Arrange + int minValue = 1; + int maxValue = 10; + int value = 5; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value); + } + + public void IsInRange_WithValueEqualToMin_DoesNotThrow() + { + // Arrange + int minValue = 1; + int maxValue = 10; + int value = 1; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value); + } + + public void IsInRange_WithValueEqualToMax_DoesNotThrow() + { + // Arrange + int minValue = 1; + int maxValue = 10; + int value = 10; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value); + } + + public void IsInRange_WithValueBelowRange_ThrowsAssertFailedException() + { + // Arrange + int minValue = 5; + int maxValue = 10; + int value = 3; + + // Act & Assert + Exception ex = VerifyThrows(() => Assert.IsInRange(minValue, maxValue, value)); + Verify(ex.Message.Contains("Value '3' is not within the expected range [5, 10]")); + } + + public void IsInRange_WithValueAboveRange_ThrowsAssertFailedException() + { + // Arrange + int minValue = 1; + int maxValue = 5; + int value = 8; + + // Act & Assert + Exception ex = VerifyThrows(() => Assert.IsInRange(minValue, maxValue, value)); + Verify(ex.Message.Contains("Value '8' is not within the expected range [1, 5]")); + } + + public void IsInRange_WithCustomMessage_IncludesCustomMessage() + { + // Arrange + int minValue = 1; + int maxValue = 5; + int value = 10; + string customMessage = "Custom error message"; + + // Act + Action action = () => Assert.IsInRange(minValue, maxValue, value, customMessage); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("Value '10' is not within the expected range [1, 5]") + .And.Contain(customMessage); + } + + public void IsInRange_WithMessage_FormatsMessage() + { + // Arrange + int minValue = 1; + int maxValue = 5; + int value = 10; + string message = "Test with parameter: TestValue"; + + // Act + Action action = () => Assert.IsInRange(minValue, maxValue, value, message); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("Value '10' is not within the expected range [1, 5]") + .And.Contain("Test with parameter: TestValue"); + } + + public void IsInRange_WithDoubleValues_WorksCorrectly() + { + // Arrange + double minValue = 1.5; + double maxValue = 5.5; + double valueInRange = 3.0; + double valueOutOfRange = 6.0; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, valueInRange); + Exception ex = VerifyThrows(() => Assert.IsInRange(minValue, maxValue, valueOutOfRange)); + Verify(ex.Message.Contains("Value '6' is not within the expected range [1.5, 5.5]")); + } + + public void IsInRange_WithDateTimeValues_WorksCorrectly() + { + // Arrange + var minValue = new DateTime(2023, 1, 1); + var maxValue = new DateTime(2023, 12, 31); + var valueInRange = new DateTime(2023, 6, 15); + var valueOutOfRange = new DateTime(2024, 1, 1); + + // Act + Assert.IsInRange(minValue, maxValue, valueInRange); + Action action = () => Assert.IsInRange(minValue, maxValue, valueOutOfRange); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("is not within the expected range"); + } + + public void IsInRange_WithCharValues_WorksCorrectly() + { + // Arrange + char minValue = 'A'; + char maxValue = 'Z'; + char valueInRange = 'M'; + char valueOutOfRange = 'a'; + + // Act + Assert.IsInRange(minValue, maxValue, valueInRange); + Action action = () => Assert.IsInRange(minValue, maxValue, valueOutOfRange); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("Value 'a' is not within the expected range [A, Z]"); + } + + public void IsInRange_WithNullMessage_DoesNotThrow() + { + // Arrange + int minValue = 1; + int maxValue = 5; + int value = 3; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value, null!); + } + + public void IsInRange_WithEmptyMessage_DoesNotThrow() + { + // Arrange + int minValue = 1; + int maxValue = 5; + int value = 3; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value, string.Empty); + } + + public void IsInRange_WithMessage_DoesNotThrow() + { + // Arrange + int minValue = 1; + int maxValue = 5; + int value = 3; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value, "Test message"); + } + + public void IsInRange_WithAllNegativeValuesInRange_DoesNotThrow() + { + // Arrange + int minValue = -10; + int maxValue = -5; + int value = -7; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value); + } + + public void IsInRange_WithAllNegativeValuesBelowRange_ThrowsAssertFailedException() + { + // Arrange + int minValue = -10; + int maxValue = -5; + int value = -12; + + // Act & Assert + Action action = () => Assert.IsInRange(minValue, maxValue, value); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("Value '-12' is not within the expected range [-10, -5]"); + } + + public void IsInRange_WithAllNegativeValuesAboveRange_ThrowsAssertFailedException() + { + // Arrange + int minValue = -10; + int maxValue = -5; + int value = -3; + + // Act + Action action = () => Assert.IsInRange(minValue, maxValue, value); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("Value '-3' is not within the expected range [-10, -5]"); + } + + public void IsInRange_WithRangeSpanningNegativeToPositive_ValueInRange_DoesNotThrow() + { + // Arrange + int minValue = -5; + int maxValue = 5; + int value = 0; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value); + } + + public void IsInRange_WithRangeSpanningNegativeToPositive_NegativeValueInRange_DoesNotThrow() + { + // Arrange + int minValue = -5; + int maxValue = 5; + int value = -3; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value); + } + + public void IsInRange_WithRangeSpanningNegativeToPositive_PositiveValueInRange_DoesNotThrow() + { + // Arrange + int minValue = -5; + int maxValue = 5; + int value = 3; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, value); + } + + public void IsInRange_WithRangeSpanningNegativeToPositive_ValueBelowRange_ThrowsAssertFailedException() + { + // Arrange + int minValue = -5; + int maxValue = 5; + int value = -7; + + // Act + Action action = () => Assert.IsInRange(minValue, maxValue, value); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("Value '-7' is not within the expected range [-5, 5]"); + } + + public void IsInRange_WithRangeSpanningNegativeToPositive_ValueAboveRange_ThrowsAssertFailedException() + { + // Arrange + int minValue = -5; + int maxValue = 5; + int value = 7; + + // Act + Action action = () => Assert.IsInRange(minValue, maxValue, value); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("Value '7' is not within the expected range [-5, 5]"); + } + + public void IsInRange_WithNegativeDoubleValues_WorksCorrectly() + { + // Arrange + double minValue = -10.5; + double maxValue = -2.5; + double valueInRange = -5.0; + + // Act & Assert + Assert.IsInRange(minValue, maxValue, valueInRange); + } + + public void IsInRange_WithMaxValueLessThanMinValue_ThrowsArgumentOutOfRangeException() + { + // Arrange + int minValue = 10; + int maxValue = 5; + int value = 7; + + // Act + Action action = () => Assert.IsInRange(minValue, maxValue, value); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("The maximum value must be greater than the minimum value"); + } + + public void IsInRange_WithMaxValueEqualToMinValue_ThrowsArgumentOutOfRangeException() + { + // Arrange + int minValue = 5; + int maxValue = 5; + int value = 5; + + // Act + Action action = () => Assert.IsInRange(minValue, maxValue, value); + + // Assert + action.Should().ThrowExactly() + .And.Message.Should().Contain("The maximum value must be greater than the minimum value"); + } + + #endregion // IsInRange Tests +} diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Items.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Items.cs index fb3ddb017f..46dba4d95f 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Items.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Items.cs @@ -92,25 +92,25 @@ public void Single_InterpolatedString_WhenOneItem_ShouldPass() public void Single_WhenNoItems_ShouldFail() { Exception ex = VerifyThrows(() => Assert.ContainsSingle(Array.Empty())); - Verify(ex.Message == "Assert.ContainsSingle failed. Expected collection of size 1. Actual: 0. "); + Verify(ex.Message == "Assert.ContainsSingle failed. Expected collection to contain exactly one element but found 0 element(s). "); } public void Single_WhenMultipleItems_ShouldFail() { Exception ex = VerifyThrows(() => Assert.ContainsSingle([1, 2, 3])); - Verify(ex.Message == "Assert.ContainsSingle failed. Expected collection of size 1. Actual: 3. "); + Verify(ex.Message == "Assert.ContainsSingle failed. Expected collection to contain exactly one element but found 3 element(s). "); } public void Single_MessageArgs_WhenNoItem_ShouldFail() { Exception ex = VerifyThrows(() => Assert.ContainsSingle(Array.Empty(), "User-provided message: System.Object type: {0}", new object().GetType())); - Verify(ex.Message == "Assert.ContainsSingle failed. Expected collection of size 1. Actual: 0. User-provided message: System.Object type: System.Object"); + Verify(ex.Message == "Assert.ContainsSingle failed. Expected collection to contain exactly one element but found 0 element(s). User-provided message: System.Object type: System.Object"); } public void Single_MessageArgs_WhenMultipleItems_ShouldFail() { Exception ex = VerifyThrows(() => Assert.ContainsSingle([1, 2, 3], "User-provided message: System.Object type: {0}", new object().GetType())); - Verify(ex.Message == "Assert.ContainsSingle failed. Expected collection of size 1. Actual: 3. User-provided message: System.Object type: System.Object"); + Verify(ex.Message == "Assert.ContainsSingle failed. Expected collection to contain exactly one element but found 3 element(s). User-provided message: System.Object type: System.Object"); } public async Task Single_InterpolatedString_WhenNoItem_ShouldFail() @@ -118,7 +118,7 @@ public async Task Single_InterpolatedString_WhenNoItem_ShouldFail() DummyClassTrackingToStringCalls o = new(); DateTime dateTime = DateTime.Now; Exception ex = await VerifyThrowsAsync(async () => Assert.ContainsSingle(Array.Empty(), $"User-provided message. {o}, {o,35}, {await GetHelloStringAsync()}, {new DummyIFormattable()}, {dateTime:tt}, {dateTime,5:tt}")); - Verify(ex.Message == $"Assert.ContainsSingle failed. Expected collection of size 1. Actual: 0. User-provided message. DummyClassTrackingToStringCalls, DummyClassTrackingToStringCalls, Hello, DummyIFormattable.ToString(), {string.Format(null, "{0:tt}", dateTime)}, {string.Format(null, "{0,5:tt}", dateTime)}"); + Verify(ex.Message == $"Assert.ContainsSingle failed. Expected collection to contain exactly one element but found 0 element(s). User-provided message. DummyClassTrackingToStringCalls, DummyClassTrackingToStringCalls, Hello, DummyIFormattable.ToString(), {string.Format(null, "{0:tt}", dateTime)}, {string.Format(null, "{0,5:tt}", dateTime)}"); Verify(o.WasToStringCalled); } @@ -127,10 +127,54 @@ public async Task Single_InterpolatedString_WhenMultipleItems_ShouldFail() DummyClassTrackingToStringCalls o = new(); DateTime dateTime = DateTime.Now; Exception ex = await VerifyThrowsAsync(async () => Assert.ContainsSingle([1, 2, 3], $"User-provided message. {o}, {o,35}, {await GetHelloStringAsync()}, {new DummyIFormattable()}, {dateTime:tt}, {dateTime,5:tt}")); - Verify(ex.Message == $"Assert.ContainsSingle failed. Expected collection of size 1. Actual: 3. User-provided message. DummyClassTrackingToStringCalls, DummyClassTrackingToStringCalls, Hello, DummyIFormattable.ToString(), {string.Format(null, "{0:tt}", dateTime)}, {string.Format(null, "{0,5:tt}", dateTime)}"); + Verify(ex.Message == $"Assert.ContainsSingle failed. Expected collection to contain exactly one element but found 3 element(s). User-provided message. DummyClassTrackingToStringCalls, DummyClassTrackingToStringCalls, Hello, DummyIFormattable.ToString(), {string.Format(null, "{0:tt}", dateTime)}, {string.Format(null, "{0,5:tt}", dateTime)}"); Verify(o.WasToStringCalled); } + public void SinglePredicate_WhenOneItemMatches_ShouldPass() + { + var collection = new List { 1, 3, 5 }; + int result = Assert.ContainsSingle(x => x == 3, collection); + Verify(result == 3); + } + + public void SinglePredicate_WithMessage_WhenOneItemMatches_ShouldPass() + { + var collection = new List { "apple", "banana", "cherry" }; +#pragma warning disable CA1865 // Use char overload - not netfx + string result = Assert.ContainsSingle(x => x.StartsWith("b", StringComparison.Ordinal), collection, "Expected one item starting with 'b'"); +#pragma warning restore CA1865 + Verify(result == "banana"); + } + + public void SinglePredicate_WhenNoItemMatches_ShouldFail() + { + var collection = new List { 1, 3, 5 }; + Exception ex = VerifyThrows(() => Assert.ContainsSingle(x => x % 2 == 0, collection)); + Verify(ex.Message == "Assert.ContainsSingle failed. Expected exactly one item to match the predicate but found 0 item(s). "); + } + + public void SinglePredicate_WhenMultipleItemsMatch_ShouldFail() + { + var collection = new List { 2, 4, 6 }; + Exception ex = VerifyThrows(() => Assert.ContainsSingle(x => x % 2 == 0, collection)); + Verify(ex.Message == "Assert.ContainsSingle failed. Expected exactly one item to match the predicate but found 3 item(s). "); + } + + public void SinglePredicate_Message_WhenNoItemMatches_ShouldFail() + { + var collection = new List { 1, 3, 5 }; + Exception ex = VerifyThrows(() => Assert.ContainsSingle(x => x % 2 == 0, collection, "No even numbers found: test")); + Verify(ex.Message == "Assert.ContainsSingle failed. Expected exactly one item to match the predicate but found 0 item(s). No even numbers found: test"); + } + + public void SinglePredicate_Message_WhenMultipleItemsMatch_ShouldFail() + { + var collection = new List { 2, 4, 6 }; + Exception ex = VerifyThrows(() => Assert.ContainsSingle(x => x % 2 == 0, collection, "Too many even numbers: test")); + Verify(ex.Message == "Assert.ContainsSingle failed. Expected exactly one item to match the predicate but found 3 item(s). Too many even numbers: test"); + } + public void Any_WhenOneItem_ShouldPass() { var collection = new List { 1 }; diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.ThrowsExceptionTests.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.ThrowsExceptionTests.cs index 52b1fd9620..6ce17da296 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.ThrowsExceptionTests.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.ThrowsExceptionTests.cs @@ -202,6 +202,30 @@ public void Throws_WhenExceptionIsNotExpectedType_ShouldThrow() Verify(ex is AssertFailedException); } + public void Throws_WithInterpolation() + { + static string GetString() => throw new Exception(); + +#pragma warning disable IDE0200 // Remove unnecessary lambda expression - intentionally testing overload resolution for this case. + Exception ex = Assert.Throws(() => GetString(), $"Hello {GetString()}"); +#pragma warning restore IDE0200 // Remove unnecessary lambda expression + Exception ex2 = Assert.Throws(GetString, $"Hello {GetString()}"); + Verify(ex is not null); + Verify(ex2 is not null); + } + + public void ThrowsExactly_WithInterpolation() + { + static string GetString() => throw new Exception(); + +#pragma warning disable IDE0200 // Remove unnecessary lambda expression - intentionally testing overload resolution for this case. + Exception ex = Assert.ThrowsExactly(() => GetString(), $"Hello {GetString()}"); +#pragma warning restore IDE0200 // Remove unnecessary lambda expression + Exception ex2 = Assert.ThrowsExactly(GetString, $"Hello {GetString()}"); + Verify(ex is not null); + Verify(ex2 is not null); + } + public void ThrowsExactly_WhenExceptionIsDerivedFromExpectedType_ShouldThrow() { static void Action() => Assert.ThrowsExactly(() => throw new ArgumentNullException()); diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.cs index 91873731a5..c14d13fe4c 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.cs @@ -5,10 +5,10 @@ namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests; public partial class AssertTests { - #region That tests - public void ThatShouldReturnAnInstanceOfAssert() => Verify(Assert.That is not null); + #region Instance tests + public void InstanceShouldReturnAnInstanceOfAssert() => Verify(Assert.Instance is not null); - public void ThatShouldCacheAssertInstance() => Verify(ReferenceEquals(Assert.That, Assert.That)); + public void InstanceShouldCacheAssertInstance() => Verify(ReferenceEquals(Assert.Instance, Assert.Instance)); #endregion #region ReplaceNullChars tests @@ -38,6 +38,29 @@ public void BuildUserMessageDoesNotThrowWhenMessageContainsInvalidStringFormatCo } #endregion + #region Obsolete methods tests +#if DEBUG + public void ObsoleteEqualsMethodThrowsAssertFailedException() + { +#pragma warning disable CS0618 // Type or member is obsolete + Exception ex = VerifyThrows(() => Assert.Equals("test", "test")); +#pragma warning restore CS0618 // Type or member is obsolete + Verify(ex is AssertFailedException); + Verify(ex.Message.Contains("Assert.Equals should not be used for Assertions")); + } + + public void ObsoleteReferenceEqualsMethodThrowsAssertFailedException() + { + object obj = new(); +#pragma warning disable CS0618 // Type or member is obsolete + Exception ex = VerifyThrows(() => Assert.ReferenceEquals(obj, obj)); +#pragma warning restore CS0618 // Type or member is obsolete + Verify(ex is AssertFailedException); + Verify(ex.Message.Contains("Assert.ReferenceEquals should not be used for Assertions")); + } +#endif + #endregion + private static Task GetHelloStringAsync() => Task.FromResult("Hello"); diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/CollectionAssertTests.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/CollectionAssertTests.cs index 877e51b57a..66131b5ec1 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/CollectionAssertTests.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/CollectionAssertTests.cs @@ -9,9 +9,9 @@ namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests.Assertions public class CollectionAssertTests : TestContainer { - public void ThatShouldReturnAnInstanceOfCollectionAssert() => Verify(CollectionAssert.That is not null); + public void InstanceShouldReturnAnInstanceOfCollectionAssert() => Verify(CollectionAssert.Instance is not null); - public void ThatShouldCacheCollectionAssertInstance() => Verify(CollectionAssert.That == CollectionAssert.That); + public void InstanceShouldCacheCollectionAssertInstance() => Verify(CollectionAssert.Instance == CollectionAssert.Instance); public void CollectionAssertContainsNullabilityPostConditions() { @@ -488,7 +488,7 @@ private static List GenerateDeeplyNestedCollection(int depth) { if (depth == 0) { - return new List { new ReadOnlyCollection(Enumerable.Range(1, 10).ToList()) }; + return [new ReadOnlyCollection([.. Enumerable.Range(1, 10)])]; } var nestedCollection = new List(); @@ -528,14 +528,14 @@ private static List GenerateDeeplyNestedCollection(int depth) private ICollection? GetNonICollectionInnerCollection() => new List> { - new(new List { 1, 2 }), - new(new List { 3, 4 }), + new([1, 2]), + new([3, 4]), }; private ICollection? GetNotMatchingGetNonICollectionInnerCollection() => new List> { - new(new List { 6, 5 }), - new(new List { 3, 4 }), + new([6, 5]), + new([3, 4]), }; private Type? GetStringType() => typeof(string); @@ -561,4 +561,27 @@ private class CaseInsensitiveNotEqualityComparer : IEqualityComparer public int GetHashCode(string obj) => obj.ToUpperInvariant().GetHashCode(); } + + #region Obsolete methods tests +#if DEBUG + public void ObsoleteEqualsMethodThrowsAssertFailedException() + { +#pragma warning disable CS0618 // Type or member is obsolete + Exception ex = VerifyThrows(() => CollectionAssert.Equals("test", "test")); +#pragma warning restore CS0618 // Type or member is obsolete + Verify(ex is AssertFailedException); + Verify(ex.Message.Contains("CollectionAssert.Equals should not be used for Assertions")); + } + + public void ObsoleteReferenceEqualsMethodThrowsAssertFailedException() + { + object obj = new(); +#pragma warning disable CS0618 // Type or member is obsolete + Exception ex = VerifyThrows(() => CollectionAssert.ReferenceEquals(obj, obj)); +#pragma warning restore CS0618 // Type or member is obsolete + Verify(ex is AssertFailedException); + Verify(ex.Message.Contains("CollectionAssert.ReferenceEquals should not be used for Assertions")); + } +#endif + #endregion } diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/StringAssertTests.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/StringAssertTests.cs index 7ecf1a3ac8..0f9469d391 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/StringAssertTests.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/StringAssertTests.cs @@ -7,9 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests.Assertions public class StringAssertTests : TestContainer { - public void ThatShouldReturnAnInstanceOfStringAssert() => Verify(StringAssert.That is not null); + public void InstanceShouldReturnAnInstanceOfStringAssert() => Verify(StringAssert.Instance is not null); - public void ThatShouldCacheStringAssertInstance() => Verify(StringAssert.That == StringAssert.That); + public void InstanceShouldCacheStringAssertInstance() => Verify(StringAssert.Instance == StringAssert.Instance); public void StringAssertContains() { @@ -311,4 +311,27 @@ public void StringAssertDoesNotMatchMessageParametersNullabilitiesPostConditions private Regex? GetMatchingPattern() => new("some*"); private Regex? GetNonMatchingPattern() => new("something"); + + #region Obsolete methods tests +#if DEBUG + public void ObsoleteEqualsMethodThrowsAssertFailedException() + { +#pragma warning disable CS0618 // Type or member is obsolete + Exception ex = VerifyThrows(() => StringAssert.Equals("test", "test")); +#pragma warning restore CS0618 // Type or member is obsolete + Verify(ex is AssertFailedException); + Verify(ex.Message.Contains("StringAssert.Equals should not be used for Assertions")); + } + + public void ObsoleteReferenceEqualsMethodThrowsAssertFailedException() + { + object obj = new(); +#pragma warning disable CS0618 // Type or member is obsolete + Exception ex = VerifyThrows(() => StringAssert.ReferenceEquals(obj, obj)); +#pragma warning restore CS0618 // Type or member is obsolete + Verify(ex is AssertFailedException); + Verify(ex.Message.Contains("StringAssert.ReferenceEquals should not be used for Assertions")); + } +#endif + #endregion } diff --git a/test/UnitTests/TestFramework.UnitTests/Attributes/CIConditionAttributeTests.cs b/test/UnitTests/TestFramework.UnitTests/Attributes/CIConditionAttributeTests.cs new file mode 100644 index 0000000000..701a1f4ca7 --- /dev/null +++ b/test/UnitTests/TestFramework.UnitTests/Attributes/CIConditionAttributeTests.cs @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using FluentAssertions; + +using Moq; + +using TestFramework.ForTestingMSTest; + +namespace UnitTestFramework.Tests; + +/// +/// Tests for class CIConditionAttribute. +/// +public class CIConditionAttributeTests : TestContainer +{ + public void Constructor_SetsCorrectMode() + { + // Arrange + var mockEnvironment = new Mock(); + + // Act + var includeAttribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + var excludeAttribute = new CIConditionAttribute(ConditionMode.Exclude, mockEnvironment.Object); + + // Assert + includeAttribute.Mode.Should().Be(ConditionMode.Include); + excludeAttribute.Mode.Should().Be(ConditionMode.Exclude); + } + + public void GroupName_ReturnsCorrectValue() + { + // Arrange + var mockEnvironment = new Mock(); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.GroupName.Should().Be(nameof(CIConditionAttribute)); + } + + public void IgnoreMessage_IncludeMode_ReturnsCorrectMessage() + { + // Arrange + var mockEnvironment = new Mock(); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.IgnoreMessage.Should().Be("Test is only supported in CI environments"); + } + + public void IgnoreMessage_ExcludeMode_ReturnsCorrectMessage() + { + // Arrange + var mockEnvironment = new Mock(); + var attribute = new CIConditionAttribute(ConditionMode.Exclude, mockEnvironment.Object); + + // Act & Assert + attribute.IgnoreMessage.Should().Be("Test is not supported in CI environments"); + } + + public void ShouldRun_IncludeMode_WhenNotInCI_ReturnsFalse() + { + // Arrange + var mockEnvironment = new Mock(); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeFalse(); + } + + public void ShouldRun_ExcludeMode_WhenNotInCI_ReturnsFalse() + { + // Arrange + var mockEnvironment = new Mock(); + var attribute = new CIConditionAttribute(ConditionMode.Exclude, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeFalse(); + } + + public void ShouldRun_IncludeMode_WhenInCI_GitHub_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("GITHUB_ACTIONS")).Returns("true"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_ExcludeMode_WhenInCI_GitHub_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("GITHUB_ACTIONS")).Returns("true"); + var attribute = new CIConditionAttribute(ConditionMode.Exclude, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_AzurePipelines_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("TF_BUILD")).Returns("true"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_AppVeyor_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("APPVEYOR")).Returns("true"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_Travis_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("TRAVIS")).Returns("true"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_CircleCI_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("CIRCLECI")).Returns("true"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_Generic_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("CI")).Returns("true"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_TeamCity_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("TEAMCITY_VERSION")).Returns("2023.11"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_Jenkins_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("BUILD_ID")).Returns("123"); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("BUILD_URL")).Returns("http://jenkins.example.com/job/test/123/"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_AWSCodeBuild_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("CODEBUILD_BUILD_ID")).Returns("codebuild-demo-project:b1e6661e-e4f2-4156-9ab9-82a19EXAMPLE"); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("AWS_REGION")).Returns("us-east-1"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_GoogleCloudBuild_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("BUILD_ID")).Returns("abc-123-def-456"); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("PROJECT_ID")).Returns("my-project"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_IncludeMode_WhenInCI_JetBrainsSpace_ReturnsTrue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("JB_SPACE_API_URL")).Returns("https://mycompany.jetbrains.space"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert + attribute.ShouldRun.Should().BeTrue(); + } + + public void ShouldRun_Jenkins_RequiresBothVariables() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("BUILD_ID")).Returns("123"); + // BUILD_URL not set - should return null by default + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert - Should not detect as CI since both variables are required + attribute.ShouldRun.Should().BeFalse(); + } + + public void ShouldRun_AWSCodeBuild_RequiresBothVariables() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("CODEBUILD_BUILD_ID")).Returns("codebuild-demo-project:b1e6661e-e4f2-4156-9ab9-82a19EXAMPLE"); + // AWS_REGION not set - should return null by default + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert - Should not detect as CI since both variables are required + attribute.ShouldRun.Should().BeFalse(); + } + + public void ShouldRun_GoogleCloudBuild_RequiresBothVariables() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("BUILD_ID")).Returns("abc-123-def-456"); + // PROJECT_ID not set - should return null by default + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert - Should not detect as CI since both variables are required + attribute.ShouldRun.Should().BeFalse(); + } + + public void ShouldRun_BooleanVariable_RequiresTrueValue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("CI")).Returns("false"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert - Should not detect as CI since value is false + attribute.ShouldRun.Should().BeFalse(); + } + + public void ShouldRun_BooleanVariable_RequiresValidBooleanValue() + { + // Arrange + var mockEnvironment = new Mock(); + mockEnvironment.Setup(e => e.GetEnvironmentVariable("CI")).Returns("invalid"); + var attribute = new CIConditionAttribute(ConditionMode.Include, mockEnvironment.Object); + + // Act & Assert - Should not detect as CI since value is not a valid boolean + attribute.ShouldRun.Should().BeFalse(); + } +} diff --git a/test/UnitTests/MSTestAdapter.UnitTests/DynamicDataAttributeTests.cs b/test/UnitTests/TestFramework.UnitTests/Attributes/DynamicDataAttributeTests.cs similarity index 62% rename from test/UnitTests/MSTestAdapter.UnitTests/DynamicDataAttributeTests.cs rename to test/UnitTests/TestFramework.UnitTests/Attributes/DynamicDataAttributeTests.cs index dce014fc52..93630f184b 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/DynamicDataAttributeTests.cs +++ b/test/UnitTests/TestFramework.UnitTests/Attributes/DynamicDataAttributeTests.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; - using TestFramework.ForTestingMSTest; namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests.Attributes; @@ -19,8 +17,6 @@ public DynamicDataAttributeTests() _testMethodInfo = _dummyTestClass.GetType().GetTypeInfo().GetDeclaredMethod("TestMethod1")!; _dynamicDataAttribute = new DynamicDataAttribute("ReusableTestDataProperty"); - // Initializes DynamicDataProvider. Normally this happens automatically but we are running outside of test adapter. - _ = PlatformServiceProvider.Instance; DynamicDataAttribute.TestIdGenerationStrategy = TestIdGenerationStrategy.FullyQualified; } @@ -264,268 +260,268 @@ public void DynamicDataSource_WithValueTupleWithTupleSyntax_Works() dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.GetDataWithValueTupleWithTupleSyntax), typeof(TestClassTupleData), DynamicDataSourceType.Method); dynamicDataAttribute.GetData(testMethodInfo); } -} - -/// -/// The dummy test class. -/// -[TestClass] -internal class DummyTestClass -{ - /// - /// Gets the reusable test data property. - /// - public static IEnumerable ReusableTestDataProperty => [[1, 2, 3], [4, 5, 6]]; - - /// - /// Gets the null test data property. - /// - public static IEnumerable NullProperty => null!; - - /// - /// Gets the empty test data property. - /// - public static IEnumerable EmptyProperty => Array.Empty(); - - /// - /// Gets the wrong test data property i.e. Property returning something other than - /// expected data type of . - /// - public static string WrongDataTypeProperty => "Dummy"; - - /// - /// The reusable test data method. - /// - /// - /// The . - /// - public static IEnumerable ReusableTestDataMethod() => [[1, 2, 3], [4, 5, 6]]; - - /// - /// The custom display name method. - /// - /// - /// The method info of test method. - /// - /// - /// The test data which is passed to test method. - /// - /// - /// The . - /// - public static string GetCustomDynamicDataDisplayName(MethodInfo methodInfo, object[] data) - => $"DynamicDataTestWithDisplayName {methodInfo.Name} with {data.Length} parameters"; /// - /// Custom display name method with missing parameters. + /// The dummy test class. /// - /// - /// The . - /// - public static string GetDynamicDataDisplayNameWithMissingParameters() => throw new InvalidOperationException(); - - /// - /// Custom display name method with invalid return type. - /// - public static void GetDynamicDataDisplayNameWithInvalidReturnType() => throw new InvalidOperationException(); - - /// - /// Custom display name method with invalid first parameter type. - /// - /// - /// The method info of test method. - /// - /// - /// The test data which is passed to test method. - /// - /// - /// The . - /// - public static string GetDynamicDataDisplayNameWithInvalidFirstParameterType(string methodInfo, object[] data) => throw new InvalidOperationException(); - - /// - /// Custom display name method with invalid second parameter. - /// - /// - /// The method info of test method. - /// - /// - /// The test data which is passed to test method. - /// - /// - /// The . - /// - public static string GetDynamicDataDisplayNameWithInvalidSecondParameterType(MethodInfo methodInfo, string data) => throw new InvalidOperationException(); - - /// - /// Custom display name method that is not static. - /// - /// - /// The method info of test method. - /// - /// - /// The test data which is passed to test method. - /// - /// - /// The . - /// - public string GetDynamicDataDisplayNameNonStatic(MethodInfo methodInfo, object[] data) => throw new InvalidOperationException(); - - /// - /// The test method 1. - /// - [TestMethod] - [DynamicData("ReusableTestDataProperty")] - public void TestMethod1() - { - } + [TestClass] + internal class DummyTestClass + { + /// + /// Gets the reusable test data property. + /// + public static IEnumerable ReusableTestDataProperty => [[1, 2, 3], [4, 5, 6]]; + + /// + /// Gets the null test data property. + /// + public static IEnumerable NullProperty => null!; + + /// + /// Gets the empty test data property. + /// + public static IEnumerable EmptyProperty => []; + + /// + /// Gets the wrong test data property i.e. Property returning something other than + /// expected data type of . + /// + public static string WrongDataTypeProperty => "Dummy"; + + /// + /// The reusable test data method. + /// + /// + /// The . + /// + public static IEnumerable ReusableTestDataMethod() => [[1, 2, 3], [4, 5, 6]]; + + /// + /// The custom display name method. + /// + /// + /// The method info of test method. + /// + /// + /// The test data which is passed to test method. + /// + /// + /// The . + /// + public static string GetCustomDynamicDataDisplayName(MethodInfo methodInfo, object[] data) + => $"DynamicDataTestWithDisplayName {methodInfo.Name} with {data.Length} parameters"; + + /// + /// Custom display name method with missing parameters. + /// + /// + /// The . + /// + public static string GetDynamicDataDisplayNameWithMissingParameters() => throw new InvalidOperationException(); + + /// + /// Custom display name method with invalid return type. + /// + public static void GetDynamicDataDisplayNameWithInvalidReturnType() => throw new InvalidOperationException(); + + /// + /// Custom display name method with invalid first parameter type. + /// + /// + /// The method info of test method. + /// + /// + /// The test data which is passed to test method. + /// + /// + /// The . + /// + public static string GetDynamicDataDisplayNameWithInvalidFirstParameterType(string methodInfo, object[] data) => throw new InvalidOperationException(); + + /// + /// Custom display name method with invalid second parameter. + /// + /// + /// The method info of test method. + /// + /// + /// The test data which is passed to test method. + /// + /// + /// The . + /// + public static string GetDynamicDataDisplayNameWithInvalidSecondParameterType(MethodInfo methodInfo, string data) => throw new InvalidOperationException(); + + /// + /// Custom display name method that is not static. + /// + /// + /// The method info of test method. + /// + /// + /// The test data which is passed to test method. + /// + /// + /// The . + /// + public string GetDynamicDataDisplayNameNonStatic(MethodInfo methodInfo, object[] data) => throw new InvalidOperationException(); + + /// + /// The test method 1. + /// + [TestMethod] + [DynamicData("ReusableTestDataProperty")] + public void TestMethod1() + { + } - /// - /// The test method 2. - /// - [TestMethod] - [DynamicData("ReusableTestDataMethod")] - public void TestMethod2() - { - } + /// + /// The test method 2. + /// + [TestMethod] + [DynamicData("ReusableTestDataMethod")] + public void TestMethod2() + { + } - /// - /// The test method 3. - /// - [TestMethod] - [DynamicData("WrongDataTypeProperty")] - public void TestMethod3() - { - } + /// + /// The test method 3. + /// + [TestMethod] + [DynamicData("WrongDataTypeProperty")] + public void TestMethod3() + { + } - /// - /// The test method 4. - /// - [TestMethod] - [DynamicData("NullProperty")] - public void TestMethod4() - { - } + /// + /// The test method 4. + /// + [TestMethod] + [DynamicData("NullProperty")] + public void TestMethod4() + { + } - /// - /// The test method 5. - /// - [TestMethod] - [DynamicData("EmptyProperty")] - public void TestMethod5() - { - } + /// + /// The test method 5. + /// + [TestMethod] + [DynamicData("EmptyProperty")] + public void TestMethod5() + { + } - /// - /// DataRow test method 1. - /// - [DataRow("First", "Second", null)] - [DataRow(null, "First", "Second")] - [DataRow("First", null, "Second")] - [TestMethod] - public void DataRowTestMethod() - { - } + /// + /// DataRow test method 1. + /// + [DataRow("First", "Second", null)] + [DataRow(null, "First", "Second")] + [DataRow("First", null, "Second")] + [TestMethod] + public void DataRowTestMethod() + { + } - /// - /// Custom display name method that is private. - /// - /// - /// The method info of test method. - /// - /// - /// The test data which is passed to test method. - /// - /// - /// The . - /// + /// + /// Custom display name method that is private. + /// + /// + /// The method info of test method. + /// + /// + /// The test data which is passed to test method. + /// + /// + /// The . + /// #pragma warning disable IDE0051 // Remove unused private members - private static string GetDynamicDataDisplayNamePrivate(MethodInfo methodInfo, object[] data) => throw new InvalidOperationException(); -} - -public class DummyTestClass2 -{ - /// - /// Gets the reusable test data property. - /// - public static IEnumerable ReusableTestDataProperty2 => [[1, 2, 3], [4, 5, 6]]; - - /// - /// The reusable test data method. - /// - /// - /// The . - /// - public static IEnumerable ReusableTestDataMethod2() => [[1, 2, 3], [4, 5, 6]]; - - /// - /// The custom display name method. - /// - /// - /// The method info of test method. - /// - /// - /// The test data which is passed to test method. - /// - /// - /// The . - /// - public static string GetCustomDynamicDataDisplayName2(MethodInfo methodInfo, object[] data) - => $"DynamicDataTestWithDisplayName {methodInfo.Name} with {data.Length} parameters"; -} - -[TestClass] -internal class TestClassTupleData -{ - public static IEnumerable> GetDataWithTuple() - { - yield return new(0, "0"); - yield return new(1, "1"); - } - - public static IEnumerable> DataWithTuple - { - get + private static string GetDynamicDataDisplayNamePrivate(MethodInfo methodInfo, object[] data) => throw new InvalidOperationException(); + } + + public class DummyTestClass2 + { + /// + /// Gets the reusable test data property. + /// + public static IEnumerable ReusableTestDataProperty2 => [[1, 2, 3], [4, 5, 6]]; + + /// + /// The reusable test data method. + /// + /// + /// The . + /// + public static IEnumerable ReusableTestDataMethod2() => [[1, 2, 3], [4, 5, 6]]; + + /// + /// The custom display name method. + /// + /// + /// The method info of test method. + /// + /// + /// The test data which is passed to test method. + /// + /// + /// The . + /// + public static string GetCustomDynamicDataDisplayName2(MethodInfo methodInfo, object[] data) + => $"DynamicDataTestWithDisplayName {methodInfo.Name} with {data.Length} parameters"; + } + + [TestClass] + internal class TestClassTupleData + { + public static IEnumerable> GetDataWithTuple() { yield return new(0, "0"); yield return new(1, "1"); } - } - [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1141:Use tuple syntax", Justification = "We want to explicitly test this syntax")] - public static IEnumerable> GetDataWithValueTuple() - { - yield return new(0, "0"); - yield return new(1, "1"); - } + public static IEnumerable> DataWithTuple + { + get + { + yield return new(0, "0"); + yield return new(1, "1"); + } + } - [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1141:Use tuple syntax", Justification = "We want to explicitly test this syntax")] - public static IEnumerable> DataWithValueTuple - { - get + [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1141:Use tuple syntax", Justification = "We want to explicitly test this syntax")] + public static IEnumerable> GetDataWithValueTuple() { yield return new(0, "0"); yield return new(1, "1"); } - } - public static IEnumerable<(int Integer, string AsString)> GetDataWithValueTupleWithTupleSyntax() - { - yield return (0, "0"); - yield return (1, "1"); - } + [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1141:Use tuple syntax", Justification = "We want to explicitly test this syntax")] + public static IEnumerable> DataWithValueTuple + { + get + { + yield return new(0, "0"); + yield return new(1, "1"); + } + } - public static IEnumerable<(int Integer, string AsString)> DataWithValueTupleWithTupleSyntax - { - get + public static IEnumerable<(int Integer, string AsString)> GetDataWithValueTupleWithTupleSyntax() { yield return (0, "0"); yield return (1, "1"); } - } - [DataTestMethod] - public void DynamicDataTestWithTuple(int value, string integerAsString) - { + public static IEnumerable<(int Integer, string AsString)> DataWithValueTupleWithTupleSyntax + { + get + { + yield return (0, "0"); + yield return (1, "1"); + } + } + + [DataTestMethod] + public void DynamicDataTestWithTuple(int value, string integerAsString) + { + } } } diff --git a/test/UnitTests/TestFramework.UnitTests/TestDataRowTests.cs b/test/UnitTests/TestFramework.UnitTests/TestDataRowTests.cs new file mode 100644 index 0000000000..44f6138dec --- /dev/null +++ b/test/UnitTests/TestFramework.UnitTests/TestDataRowTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using TestFramework.ForTestingMSTest; + +namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests; + +public class TestDataRowTests : TestContainer +{ + public void TestDataRowShouldInitializeWithValue() + { + string value = "test_value"; + var testDataRow = new TestDataRow(value); + + Verify(testDataRow.Value == value); + Verify(testDataRow.IgnoreMessage == null); + Verify(testDataRow.DisplayName == null); + Verify(testDataRow.TestCategories == null); + } + + public void TestDataRowShouldAllowSettingTestCategories() + { + string value = "test_value"; + var testDataRow = new TestDataRow(value); + var testCategories = new List { "Category1", "Category2" }; + + testDataRow.TestCategories = testCategories; + + Verify(testDataRow.TestCategories == testCategories); + Verify(testDataRow.TestCategories.Count == 2); + Verify(testDataRow.TestCategories.Contains("Category1")); + Verify(testDataRow.TestCategories.Contains("Category2")); + } + + public void TestDataRowShouldImplementITestDataRowForTestCategories() + { + string value = "test_value"; + var testDataRow = new TestDataRow(value); + var testCategories = new List { "Integration", "Unit" }; + testDataRow.TestCategories = testCategories; + + ITestDataRow dataRow = testDataRow; + + Verify(dataRow.TestCategories != null); + Verify(dataRow.TestCategories.Count == 2); + Verify(dataRow.TestCategories.Contains("Integration")); + Verify(dataRow.TestCategories.Contains("Unit")); + } + + public void TestDataRowShouldAllowNullTestCategories() + { + string value = "test_value"; + var testDataRow = new TestDataRow(value) + { + TestCategories = null, + }; + + Verify(testDataRow.TestCategories == null); + + ITestDataRow dataRow = testDataRow; + Verify(dataRow.TestCategories == null); + } + + public void TestDataRowShouldAllowEmptyTestCategories() + { + string value = "test_value"; + var testDataRow = new TestDataRow(value); + var emptyCategories = new List(); + + testDataRow.TestCategories = emptyCategories; + + Verify(testDataRow.TestCategories == emptyCategories); + Verify(testDataRow.TestCategories.Count == 0); + + ITestDataRow dataRow = testDataRow; + Verify(dataRow.TestCategories != null); + Verify(dataRow.TestCategories.Count == 0); + } +} diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/CommandLine.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/CommandLine.cs index 3fd02adb5b..d2e33f7df4 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/CommandLine.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/CommandLine.cs @@ -14,8 +14,8 @@ public sealed class CommandLine : IDisposable public static int TotalProcessesAttempt => s_totalProcessesAttempt; - private readonly List _errorOutputLines = new(); - private readonly List _standardOutputLines = new(); + private readonly List _errorOutputLines = []; + private readonly List _standardOutputLines = []; private IProcessHandle? _process; public ReadOnlyCollection StandardOutputLines => _standardOutputLines.AsReadOnly(); @@ -60,7 +60,7 @@ private static (string Command, string Arguments) GetCommandAndArguments(string if (!commandLine.StartsWith('"')) { string[] tokens = commandLine.Split(' '); - return (tokens[0], string.Join(" ", tokens.Skip(1))); + return (tokens[0], string.Join(' ', tokens.Skip(1))); } int endQuote = commandLine.IndexOf('"', 1); @@ -72,7 +72,7 @@ public async Task RunAsyncAndReturnExitCodeAsync( IDictionary? environmentVariables = null, string? workingDirectory = null, bool cleanDefaultEnvironmentVariableIfCustomAreProvided = false, - int timeoutInSeconds = 60) + int timeoutInSeconds = 10000) { await s_maxOutstandingCommands_semaphore.WaitAsync(); try diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/DebuggerUtility.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/DebuggerUtility.cs index 2a7839e498..435e2f2d3d 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/DebuggerUtility.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/DebuggerUtility.cs @@ -125,7 +125,6 @@ private static bool AttachVs(Process vs, int pid, bool enableLog = false) if (dn.StartsWith("!VisualStudio.DTE.", StringComparison.Ordinal) && dn.EndsWith(dteSuffix, StringComparison.Ordinal)) { - object dbg, lps; runningObjectTable.GetObject(moniker[0], out object dte); // The COM object can be busy, we retry few times, hoping that it won't be busy next time. @@ -133,8 +132,8 @@ private static bool AttachVs(Process vs, int pid, bool enableLog = false) { try { - dbg = dte.GetType().InvokeMember("Debugger", BindingFlags.GetProperty, null, dte, null, CultureInfo.InvariantCulture)!; - lps = dbg.GetType().InvokeMember("LocalProcesses", BindingFlags.GetProperty, null, dbg, null, CultureInfo.InvariantCulture)!; + object dbg = dte.GetType().InvokeMember("Debugger", BindingFlags.GetProperty, null, dte, null, CultureInfo.InvariantCulture)!; + object lps = dbg.GetType().InvokeMember("LocalProcesses", BindingFlags.GetProperty, null, dbg, null, CultureInfo.InvariantCulture)!; var lpn = (System.Collections.IEnumerator)lps.GetType().InvokeMember("GetEnumerator", BindingFlags.InvokeMethod, null, lps, null, CultureInfo.InvariantCulture)!; while (lpn.MoveNext()) @@ -324,5 +323,5 @@ private static extern int NtQueryInformationProcess( out int returnLength); [DllImport("ole32.dll")] - private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc); + private static extern int CreateBindCtx(uint reserved, out IBindCtx? ppbc); } diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/DotnetCli.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/DotnetCli.cs index 999006ce74..61ec18e1b8 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/DotnetCli.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/DotnetCli.cs @@ -54,7 +54,7 @@ public static async Task RunAsync( Dictionary? environmentVariables = null, bool failIfReturnValueIsNotZero = true, bool disableTelemetry = true, - int timeoutInSeconds = 50, + int timeoutInSeconds = 10000, int retryCount = 5, bool disableCodeCoverage = true, bool warnAsError = true, @@ -64,7 +64,7 @@ public static async Task RunAsync( await s_maxOutstandingCommands_semaphore.WaitAsync(); try { - environmentVariables ??= new Dictionary(); + environmentVariables ??= []; foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables()) { // Skip all unwanted environment variables. diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/DotnetMuxer.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/DotnetMuxer.cs index 6be55cb242..c799142b28 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/DotnetMuxer.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/DotnetMuxer.cs @@ -92,14 +92,14 @@ protected virtual void Dispose(bool disposing) _isDisposed = true; } - public async Task ExecuteAsync(string arguments, string? workingDirectory = null, int timeoutInSeconds = 60) + public async Task ExecuteAsync(string arguments, string? workingDirectory = null, int timeoutInSeconds = 10000) => await ExecuteAsync(arguments, workingDirectory, _environmentVariables, timeoutInSeconds); public async Task ExecuteAsync( string arguments, string? workingDirectory, IDictionary environmentVariables, - int timeoutInSeconds = 60) + int timeoutInSeconds = 10000) => await _commandLine.RunAsyncAndReturnExitCodeAsync( $"{_dotnet} {arguments}", environmentVariables, diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj b/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj index 4fa39e0f86..5533e96445 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj @@ -4,6 +4,7 @@ $(MicrosoftTestingTargetFrameworks);netstandard2.0 enable $(DefineConstants);SKIP_INTERMEDIATE_TARGET_FRAMEWORKS + $(DefineConstants);ROOT_FINDER_PUBLIC diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/ProjectSystem.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/ProjectSystem.cs index 91deff4f72..f19bde0388 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/ProjectSystem.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/ProjectSystem.cs @@ -46,7 +46,7 @@ public VSSolution(string? solutionFolder, string? solutionName) AddOrUpdateFileContent(_solutionFileName, MergeSolutionContent()); } - public ICollection Projects { get; } = new List(); + public ICollection Projects { get; } = []; public string SolutionFile { get; private set; } diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/RetryHelper.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/RetryHelper.cs index a2adaf6262..821e5f5b9a 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/RetryHelper.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/RetryHelper.cs @@ -7,13 +7,13 @@ namespace Microsoft.Testing.TestInfrastructure; public class RetryHelper { - public static async Task RetryAsync(Func action, uint times, TimeSpan every, Func? predicate = null) - => await Policy.Handle(exception => predicate is null || predicate(exception)) + public static async Task RetryAsync(Func action, uint times, TimeSpan every) + => await Policy.Handle() .WaitAndRetryAsync((int)times, _ => every) .ExecuteAsync(action); - public static async Task RetryAsync(Func> action, uint times, TimeSpan every, Func? predicate = null) - => await Policy.Handle(exception => predicate is null || predicate(exception)) + public static async Task RetryAsync(Func> action, uint times, TimeSpan every) + => await Policy.Handle() .WaitAndRetryAsync((int)times, _ => every) .ExecuteAsync(action); } diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/RootFinder.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/RootFinder.cs index 32f01c4489..404f930f6a 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/RootFinder.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/RootFinder.cs @@ -3,22 +3,51 @@ namespace Microsoft.Testing.TestInfrastructure; -public static class RootFinder +/// +/// Provides functionality to locate the root directory of a Git repository. +/// +/// The class is used to find the root directory of a Git repository by +/// searching for a ".git" directory or file starting from the application's base directory and moving up the directory +/// hierarchy. This is useful for applications that need to determine the root of a project or repository. +#if ROOT_FINDER_PUBLIC +public +#else +internal +#endif + static class RootFinder { + private static string? s_root; + + /// + /// Finds the root directory of a Git repository starting from the application's base directory. + /// + /// This method searches for a ".git" directory or file in the application's base directory and + /// its parent directories. If a Git repository is found, the path to its root directory is returned. If no Git + /// repository is found, an is thrown. + /// The path to the root directory of the Git repository, ending with a directory separator character. + /// Thrown if a Git repository is not found in the application's base directory or any of its parent directories. public static string Find() { + if (s_root != null) + { + return s_root; + } + string path = AppContext.BaseDirectory; - string dir = path; - while (Directory.GetDirectoryRoot(dir) != dir) + string currentDirectory = path; + string rootDriveDirectory = Directory.GetDirectoryRoot(currentDirectory); + while (rootDriveDirectory != currentDirectory) { - if (Directory.Exists(Path.Combine(dir, ".git"))) - { - return dir; - } - else + string gitPath = Path.Combine(currentDirectory, ".git"); + + // When working with git worktrees, the .git is a file not a folder + if (Directory.Exists(gitPath) || File.Exists(gitPath)) { - dir = Directory.GetParent(dir)!.ToString(); + s_root = currentDirectory + Path.DirectorySeparatorChar; + return s_root; } + + currentDirectory = Directory.GetParent(currentDirectory)!.ToString(); } throw new InvalidOperationException($"Could not find solution root, .git not found in {path} or any parent directory."); diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/TargetFrameworks.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/TargetFrameworks.cs index 3d4b2ffb33..824e2f1676 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/TargetFrameworks.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/TargetFrameworks.cs @@ -24,12 +24,12 @@ public static class TargetFrameworks public static string[] All { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? Net.Concat(NetFramework).ToArray() + ? [.. Net, .. NetFramework] : Net; public static IEnumerable AllForDynamicData { get; } = All.Select(tfm => new object[] { tfm }); public static string ToMSBuildTargetFrameworks(this string[] targetFrameworksEntries) - => string.Join(";", targetFrameworksEntries); + => string.Join(';', targetFrameworksEntries); } diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/TempDirectory.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/TempDirectory.cs index 76dcfca4b6..285a53fe3a 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/TempDirectory.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/TempDirectory.cs @@ -131,7 +131,7 @@ public string[] CopyFile(params string[] filePaths) paths.Add(destination); } - return paths.ToArray(); + return [.. paths]; } /// diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/TestHost.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/TestHost.cs index 32352b750b..4187c76c72 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/TestHost.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/TestHost.cs @@ -41,7 +41,7 @@ public async Task ExecuteAsync( string? command = null, Dictionary? environmentVariables = null, bool disableTelemetry = true, - int timeoutSeconds = 60) + int timeoutSeconds = 10000) { await s_maxOutstandingExecutions_semaphore.WaitAsync(); try @@ -51,7 +51,7 @@ public async Task ExecuteAsync( throw new InvalidOperationException($"Command should not start with module name '{_testHostModuleName}'."); } - environmentVariables ??= new Dictionary(); + environmentVariables ??= []; if (disableTelemetry) { @@ -87,8 +87,10 @@ public async Task ExecuteAsync( .ExecuteAsync(async () => { CommandLine commandLine = new(); + // Disable ANSI rendering so tests have easier time parsing the output. + // Disable progress so tests don't mix progress with overall progress, and with test process output. int exitCode = await commandLine.RunAsyncAndReturnExitCodeAsync( - $"{FullName} {finalArguments}", + $"{FullName} --no-ansi --no-progress {finalArguments}", environmentVariables: environmentVariables, workingDirectory: null, cleanDefaultEnvironmentVariableIfCustomAreProvided: true, diff --git a/test/Utilities/TestFramework.ForTestingMSTest/TestFrameworkEngine.cs b/test/Utilities/TestFramework.ForTestingMSTest/TestFrameworkEngine.cs index 0f26913c36..922dd103ac 100644 --- a/test/Utilities/TestFramework.ForTestingMSTest/TestFrameworkEngine.cs +++ b/test/Utilities/TestFramework.ForTestingMSTest/TestFrameworkEngine.cs @@ -20,8 +20,7 @@ public TestFrameworkEngine(TestFrameworkExtension extension, ILoggerFactory logg _logger = loggerFactory.CreateLogger("InternalTestFrameworkEngine"); } - public Type[] DataTypesProduced { get; } - = new Type[1] { typeof(TestNodeUpdateMessage) }; + public Type[] DataTypesProduced { get; } = [typeof(TestNodeUpdateMessage)]; public string Uid => _extension.Uid; @@ -99,7 +98,7 @@ private async Task ExecuteTestNodeRunAsync(RunTestExecutionRequest request, IMes testContainerType.Name, publicMethod.Name, publicMethod.GetGenericArguments().Length, - publicMethod.GetParameters().Select(x => x.ParameterType.FullName!).ToArray(), + [.. publicMethod.GetParameters().Select(x => x.ParameterType.FullName!)], publicMethod.ReturnType.FullName!)); testNode.Properties.Add(new TrxFullyQualifiedTypeNameProperty(testContainerType.FullName!)); @@ -176,7 +175,7 @@ private async Task ExecuteTestNodeDiscoveryAsync(DiscoverTestExecutionRequest re testContainerType.Name, publicMethod.Name, publicMethod.GetGenericArguments().Length, - publicMethod.GetParameters().Select(x => x.ParameterType.FullName!).ToArray(), + [.. publicMethod.GetParameters().Select(x => x.ParameterType.FullName!)], publicMethod.ReturnType.FullName!)); await messageBus.PublishAsync(this, new TestNodeUpdateMessage(request.Session.SessionUid, testNode));