diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index f788f0266f..2874056945 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,6 +1,4 @@
# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners
-* @Evangelink
-
src/Package/MSTest.Sdk @MarcoRossignoli
-src/Platform @MarcoRossignoli @Evangelink
\ No newline at end of file
+src/Platform @MarcoRossignoli @Evangelink
diff --git a/.gitignore b/.gitignore
index 32f4784062..65109106dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -142,3 +142,6 @@ project.fragment.lock.json
# Playground project (use force add if a change is really worth it)
/samples/Playground/
+
+# jetbrains temp
+.idea/
\ No newline at end of file
diff --git a/.markdownlint.json b/.markdownlint.json
index e70a5096b2..80834d3dea 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -7,6 +7,9 @@
"MD024": {
"siblings_only": true
},
+ "MD033": {
+ "allowed_elements": ["a"]
+ },
"MD046": {
"style": "fenced"
},
diff --git a/Directory.Build.Local.props b/Directory.Build.Local.props
deleted file mode 100644
index 656f35a3a3..0000000000
--- a/Directory.Build.Local.props
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
-
-
-
- true
-
-
-
-
-
- preview
- enable
- true
-
- $(NoWarn),1573,1591
-
-
-
-
- net462
- uap10.0.16299
- net6.0-windows10.0.18362.0
- net8.0
-
- netcoreapp3.1;net6.0;net7.0;net8.0
- net6.0;net7.0;net8.0
-
-
-
-
-
- false
-
- true
- embedded
-
- true
-
-
-
-
- $(CopyrightMicrosoft)
- MIT
- true
-
-
-
-
- Microsoft
-
-
-
-
- TestingPlatformRunner
-
- true
- 0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7
-
-
-
diff --git a/Directory.Build.Local.targets b/Directory.Build.Local.targets
deleted file mode 100644
index dbeb8b8d9a..0000000000
--- a/Directory.Build.Local.targets
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
- 14.0.0.0
- 14.0.0.0
-
-
-
-
- true
- $(DefineConstants);ENABLE_CODECOVERAGE
- $(PlatformTarget)
- x64
- $(MSBuildProjectName)_$(TargetFramework)_$(Configuration)_$(Architecture)
-
- $(TestRunnerAdditionalArguments) --coverage --coverage-settings $(RepoRoot)eng/coverage.config --coverage-output $(ModuleName).coverage
-
-
-
diff --git a/Directory.Build.props b/Directory.Build.props
index aabb126076..8d175de01b 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,10 +1,67 @@
-
-
+
+
-
-
+
+ true
+
+
+
+
+
+ preview
+ enable
+ true
+
+ $(NoWarn),1573,1591
+
+
+
+
+ net462
+ uap10.0.16299
+ net6.0-windows10.0.18362.0
+ net8.0
+
+ netcoreapp3.1;net6.0;net7.0;net8.0
+ net6.0;net7.0;net8.0
+
+
+
+
+
+ false
+
+ true
+ embedded
+
+ true
+
+
+
+
+ $(CopyrightMicrosoft)MIT
+
+
+
+ Microsoft
+
+
+
+
+ TestingPlatformRunner
+
+ true
+ 0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7
+
+
diff --git a/Directory.Build.targets b/Directory.Build.targets
index e95c97089d..4220fbc3f6 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -1,6 +1,14 @@
-
-
+
+
+
+
+ 14.0.0.0
+ 14.0.0.0
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index f80853d6f7..c4af76c198 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,26 +5,29 @@
true
- 8.0.0-preview.6.24214.1
-
- 17.9.0
+ 8.0.1
+ 17.10.0-preview-24127-03
+ 3.11.0-beta1.24318.1
+ 3.11.0
+ $(MicrosoftCodeAnalysisAnalyzersVersion)
+ $(MicrosoftCodeAnalysisPublicApiAnalyzersVersion)6.2.14
-
+
+ 17.10.0
+ 1.44.04.3.14.3.1
- 3.11.0-beta1.24072.1
- 3.11.0
- $(MicrosoftCodeAnalysisAnalyzersVersion)
- $(MicrosoftCodeAnalysisPublicApiAnalyzersVersion)
- 1.42.0
- 1.1.2-beta1.24074.2
+ 1.1.3-beta1.24352.1
-
+
+
+
+
@@ -33,20 +36,18 @@
-
+
-
-
-
-
-
-
+
+
+
+
-
-
+
+
@@ -55,17 +56,18 @@
-
+
+
-
+
-
-
+
+
-
+
diff --git a/MSTest.slnf b/MSTest.slnf
new file mode 100644
index 0000000000..5985887daf
--- /dev/null
+++ b/MSTest.slnf
@@ -0,0 +1,60 @@
+{
+ "solution": {
+ "path": "TestFx.sln",
+ "projects": [
+ "samples\\FxExtensibility\\FxExtensibility.csproj",
+ "samples\\Playground\\Playground.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\\Package\\MSTest.Internal.TestFx.Documentation\\MSTest.Internal.TestFx.Documentation.csproj",
+ "src\\Package\\MSTest.Sdk\\MSTest.Sdk.csproj",
+ "src\\Package\\MSTest\\MSTest.csproj",
+ "src\\TestFramework\\TestFramework.Extensions\\TestFramework.Extensions.csproj",
+ "src\\TestFramework\\TestFramework\\TestFramework.csproj",
+ "test\\IntegrationTests\\MSTest.Acceptance.IntegrationTests\\MSTest.Acceptance.IntegrationTests.csproj",
+ "test\\IntegrationTests\\MSTest.IntegrationTests\\MSTest.IntegrationTests.csproj",
+ "test\\IntegrationTests\\MSTest.VstestConsoleWrapper.IntegrationTests\\MSTest.VstestConsoleWrapper.IntegrationTests.csproj",
+ "test\\IntegrationTests\\PlatformServices.Desktop.IntegrationTests\\PlatformServices.Desktop.IntegrationTests.csproj",
+ "test\\IntegrationTests\\TestAssets\\ClsTestProject\\ClsTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\DataRowTestProject\\DataRowTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\DataSourceTestProject\\DataSourceTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\DeploymentTestProject.Never\\DeploymentTestProject.Never.csproj",
+ "test\\IntegrationTests\\TestAssets\\DeploymentTestProject.PreserveNewest\\DeploymentTestProject.PreserveNewest.csproj",
+ "test\\IntegrationTests\\TestAssets\\DesktopTestProjectx64Debug\\DesktopTestProjectx64Debug.csproj",
+ "test\\IntegrationTests\\TestAssets\\DesktopTestProjectx64Release\\DesktopTestProjectx64Release.csproj",
+ "test\\IntegrationTests\\TestAssets\\DesktopTestProjectx86Debug\\DesktopTestProjectx86Debug.csproj",
+ "test\\IntegrationTests\\TestAssets\\DesktopTestProjectx86Release\\DesktopTestProjectx86Release.csproj",
+ "test\\IntegrationTests\\TestAssets\\DiscoverInternalsProject\\DiscoverInternalsProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\DoNotParallelizeTestProject\\DoNotParallelizeTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\DynamicDataTestProject\\DynamicDataTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\FSharpTestProject\\FSharpTestProject.fsproj",
+ "test\\IntegrationTests\\TestAssets\\FixturesTestProject\\FixturesTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\FxExtensibilityTestProject\\FxExtensibilityTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\HierarchyProject\\HierarchyProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\LibProjectReferencedByDataSourceTest\\LibProjectReferencedByDataSourceTest.csproj",
+ "test\\IntegrationTests\\TestAssets\\OutputTestProject\\OutputTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\ParallelTestClass\\ParallelClassesTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\ParallelTestMethods\\ParallelMethodsTestProject.csproj",
+ "test\\IntegrationTests\\TestAssets\\SampleFrameworkExtensions\\SampleFrameworkExtensions.csproj",
+ "test\\IntegrationTests\\TestAssets\\SampleProjectForAssemblyResolution\\SampleProjectForAssemblyResolution.csproj",
+ "test\\IntegrationTests\\TestAssets\\SuiteLifeCycleTestProject\\SuiteLifeCycleTestProject.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",
+ "test\\IntegrationTests\\TestAssets\\TestIdProject.LegacyStrategy\\TestIdProject.LegacyStrategy.csproj",
+ "test\\IntegrationTests\\TestAssets\\TestProject\\TestProjectForDiscovery.csproj",
+ "test\\IntegrationTests\\TestAssets\\TimeoutTestProject\\TimeoutTestProject.csproj",
+ "test\\Performance\\MSTest.Performance.Runner\\MSTest.Performance.Runner.csproj",
+ "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\\TestFramework.UnitTests\\TestFramework.UnitTests.csproj",
+ "test\\Utilities\\Automation.CLI\\Automation.CLI.csproj",
+ "test\\Utilities\\Microsoft.Testing.TestInfrastructure\\Microsoft.Testing.TestInfrastructure.csproj",
+ "test\\Utilities\\TestFramework.ForTestingMSTest\\TestFramework.ForTestingMSTest.csproj"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/Microsoft.Testing.Platform.slnf b/Microsoft.Testing.Platform.slnf
new file mode 100644
index 0000000000..1595904e3a
--- /dev/null
+++ b/Microsoft.Testing.Platform.slnf
@@ -0,0 +1,22 @@
+{
+ "solution": {
+ "path": "TestFx.sln",
+ "projects": [
+ "samples\\Playground\\Playground.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.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",
+ "test\\IntegrationTests\\Microsoft.Testing.Platform.Acceptance.IntegrationTests\\Microsoft.Testing.Platform.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.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
index cc9f95b2d5..0baa18d4f6 100644
--- a/TestFx.sln
+++ b/TestFx.sln
@@ -22,6 +22,8 @@ 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}"
@@ -46,8 +48,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
- Directory.Build.Local.props = Directory.Build.Local.props
- Directory.Build.Local.targets = Directory.Build.Local.targets
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
Directory.Packages.props = Directory.Packages.props
@@ -67,8 +67,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "eng", "eng", "{FE0DF239-0D8
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-WindowsSDK.ps1 = eng\Install-WindowsSDK.ps1
+ eng\install-windows-sdk.ps1 = eng\install-windows-sdk.ps1
eng\stylecop.json = eng\stylecop.json
eng\verify-nupkgs.ps1 = eng\verify-nupkgs.ps1
eng\Version.Details.xml = eng\Version.Details.xml
@@ -169,7 +170,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestingPlatformRunner", "Te
eng\TestingPlatformRunner\TestingPlatformRunner.targets = eng\TestingPlatformRunner\TestingPlatformRunner.targets
EndProjectSection
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1 - Runner", "1 - Runner", "{6AEE1440-FDF0-4729-8196-B24D0E333550}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1 - Platform & Extensions", "1 - Platform & 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
@@ -201,6 +205,28 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Playground", "samples\Playg
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
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -427,6 +453,50 @@ Global
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -503,6 +573,17 @@ Global
{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}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {31E0F4D5-975A-41CC-933E-545B2201FAF9}
diff --git a/azure-pipelines-official.yml b/azure-pipelines-official.yml
index 1580f7e745..2f60ab3f70 100644
--- a/azure-pipelines-official.yml
+++ b/azure-pipelines-official.yml
@@ -33,6 +33,14 @@ parameters:
displayName: "Produce RTM version?"
type: boolean
default: False
+- name: products
+ displayName: "Select the products to generate"
+ type: string
+ default: all
+ values:
+ - all
+ - mstest
+ - testing-platform
# This option should be used with caution. This is useful for unblocking circular deps issue with testanywhere
- name: SkipTests
displayName: "Skip tests"
@@ -54,6 +62,8 @@ variables:
value: ''
- name: _BuildConfig
value: Release
+ - name: _Products
+ value: ${{parameters.products}}
- ${{ if eq(parameters.isRTM, True) }}:
- name: _ReleaseVersionKind
@@ -74,6 +84,7 @@ variables:
/p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
/p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
/p:OfficialBuildId=$(BUILD.BUILDNUMBER)
+ /p:ProductsToBuild=$(_Products)
resources:
repositories:
@@ -124,6 +135,15 @@ extends:
failOnStderr: true
showWarnings: true
+ - task: PowerShell@2
+ displayName: 'Install procdump'
+ inputs:
+ targetType: filePath
+ filePath: ./eng/install-procdump.ps1
+ failOnStderr: true
+ showWarnings: true
+
+
- script: eng\common\CIBuild.cmd
-configuration $(_BuildConfig)
-prepareMachine
@@ -134,9 +154,11 @@ 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
name: Test
displayName: Test
@@ -181,9 +203,10 @@ 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
+ ./test.sh --configuration $(_BuildConfig) --ci --test --integrationTest --nobl
name: Test
displayName: Tests
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 35ab1a58b2..ce6cec7a1f 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -93,19 +93,30 @@ stages:
failOnStderr: true
showWarnings: true
+ - task: PowerShell@2
+ displayName: 'Install procdump'
+ inputs:
+ targetType: filePath
+ filePath: ./eng/install-procdump.ps1
+ failOnStderr: true
+ showWarnings: true
+
- script: eng\common\CIBuild.cmd
-configuration $(_BuildConfig)
-prepareMachine
$(_InternalBuildArgs)
/p:Test=false
+ /p:FastAcceptanceTest=true
name: Build
displayName: Build
- ${{ 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
name: Test
displayName: Test
@@ -122,7 +133,7 @@ stages:
timeoutInMinutes: 90
pool:
name: NetCore-Public
- demands: ImageOverride -equals build.ubuntu.2004.amd64.open
+ demands: ImageOverride -equals build.ubuntu.2004.amd64.open
strategy:
matrix:
Release:
@@ -135,12 +146,14 @@ stages:
-prepareMachine
/p:Test=false
/p:NonWindowsBuild=true
+ /p:FastAcceptanceTest=true
displayName: Build
- ${{ if eq(parameters.SkipTests, False) }}:
- # -ci is allowing to import some environment variables and some required configurations
+ # --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
+ ./test.sh --configuration $(_BuildConfig) --ci --test --integrationTest --nobl
name: Test
displayName: Tests
diff --git a/docs/AddingAnalyzerCodeFix.md b/docs/AddingAnalyzerCodeFix.md
new file mode 100644
index 0000000000..0bc44fab9a
--- /dev/null
+++ b/docs/AddingAnalyzerCodeFix.md
@@ -0,0 +1,13 @@
+# Adding analyzer code fix
+
+You should add it under src/Analyzers/MSTest.Analyzers.CodeFixes.
+
+Add your fixer logic and match the analyzer rule id with your analyzer.
+
+## To update unit tests you should replace
+
+`Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;` by `MSTest.Analyzers."fixerName">;`
+
+`VerifyCS.VerifyAnalyzerAsync` by `VerifyCS.VerifyCodeFixAsync`
+
+you can use this PR as refrence:[https://github.com/microsoft/testfx/pull/3091]
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 83ec291252..6b484a34b9 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -2,11 +2,76 @@
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.0.0/)
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
-## [3.4.0] - WIP
+## [3.4.3] - 2024-05-30
-See full log [here](https://github.com/microsoft/testfx/compare/v3.3.1...HEAD)
+See full log [here](https://github.com/microsoft/testfx/compare/v3.4.2...v3.4.3)
+
+### Fixed
+
+* Revert version of Code Coverage to 17.10.4 by @Evangelink in [#3048](https://github.com/microsoft/testfx/pull/3048)
+
+### Artifacts
+
+* MSTest: [3.4.3](https://www.nuget.org/packages/MSTest/3.4.3)
+* MSTest.TestFramework: [3.4.3](https://www.nuget.org/packages/MSTest.TestFramework/3.4.3)
+* MSTest.TestAdapter: [3.4.3](https://www.nuget.org/packages/MSTest.TestAdapter/3.4.3)
+* MSTest.Analyzers: [3.4.3](https://www.nuget.org/packages/MSTest.Analyzers/3.4.3)
+* MSTest.Sdk: [3.4.3](https://www.nuget.org/packages/MSTest.Sdk/3.4.3)
+* Microsoft.Testing.Extensions.CrashDump: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.2.1)
+* Microsoft.Testing.Extensions.HangDump: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.2.1)
+* Microsoft.Testing.Extensions.HotReload: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.2.1)
+* Microsoft.Testing.Extensions.Retry: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.2.1)
+* Microsoft.Testing.Extensions.TrxReport: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.2.1)
+
+## [3.4.2] - 2024-05-30
+
+See full log [here](https://github.com/microsoft/testfx/compare/v3.4.1...v3.4.2)
+
+### Fixed
+
+* Use latest released version for Playwright and Aspire by @Evangelink in [#3024](https://github.com/microsoft/testfx/pull/3024)
+* Fix project samples for 3.4 by @Evangelink in [#3032](https://github.com/microsoft/testfx/pull/3032)
+* Fix assembly resolution with DeploymentItem by @Evangelink in [#3034](https://github.com/microsoft/testfx/pull/3034)
+
+### Artifacts
+
+* MSTest: [3.4.2](https://www.nuget.org/packages/MSTest/3.4.2)
+* MSTest.TestFramework: [3.4.2](https://www.nuget.org/packages/MSTest.TestFramework/3.4.2)
+* MSTest.TestAdapter: [3.4.2](https://www.nuget.org/packages/MSTest.TestAdapter/3.4.2)
+* MSTest.Analyzers: [3.4.2](https://www.nuget.org/packages/MSTest.Analyzers/3.4.2)
+* MSTest.Sdk: [3.4.2](https://www.nuget.org/packages/MSTest.Sdk/3.4.2)
+* Microsoft.Testing.Extensions.CrashDump: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.2.1)
+* Microsoft.Testing.Extensions.HangDump: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.2.1)
+* Microsoft.Testing.Extensions.HotReload: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.2.1)
+* Microsoft.Testing.Extensions.Retry: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.2.1)
+* Microsoft.Testing.Extensions.TrxReport: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.2.1)
+
+## [3.4.1] - 2024-05-27
+
+See full log [here](https://github.com/microsoft/testfx/compare/v3.4.0...v3.4.1)
+
+### Fixed
+
+* Fix assembly resolution error by @Evangelink in [#2948](https://github.com/microsoft/testfx/pull/2948)
+
+### Artifacts
+
+* MSTest: [3.4.1](https://www.nuget.org/packages/MSTest/3.4.1)
+* MSTest.TestFramework: [3.4.1](https://www.nuget.org/packages/MSTest.TestFramework/3.4.1)
+* MSTest.TestAdapter: [3.4.1](https://www.nuget.org/packages/MSTest.TestAdapter/3.4.1)
+* MSTest.Analyzers: [3.4.1](https://www.nuget.org/packages/MSTest.Analyzers/3.4.1)
+* MSTest.Sdk: [3.4.1](https://www.nuget.org/packages/MSTest.Sdk/3.4.1)
+* Microsoft.Testing.Extensions.CrashDump: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.2.1)
+* Microsoft.Testing.Extensions.HangDump: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.2.1)
+* Microsoft.Testing.Extensions.HotReload: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.2.1)
+* Microsoft.Testing.Extensions.Retry: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.2.1)
+* Microsoft.Testing.Extensions.TrxReport: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.2.1)
+
+## [3.4.0] - 2024-05-23
+
+See full log [here](https://github.com/microsoft/testfx/compare/v3.3.1...v3.4.0)
### Added
@@ -57,6 +122,10 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.3.1...HEAD)
* Fix localappdata folder for Linux and Mac by @Evangelink in [#2765](https://github.com/microsoft/testfx/pull/2765)
* Fix deserializers for DiscoveryRequestArgs and RunRequestArgs by @mariam-abdulla in [#2768](https://github.com/microsoft/testfx/pull/2768)
* Don't start thread/task when not using timeout for fixture methods by @Evangelink in [#2825](https://github.com/microsoft/testfx/pull/2825)
+* Fix parameters/arguments check for data driven tests by @nohwnd in [#2829](https://github.com/microsoft/testfx/pull/2829)
+* Cleaning command line validations and adding unit tests by @fhnaseer in [#2847](https://github.com/microsoft/testfx/pull/2847)
+* Fix MSTEST0014 FP with arrays by @Evangelink in [#2857](https://github.com/microsoft/testfx/pull/2857)
+* Flow execution context across fixture methods when using timeout by @Evangelink [#2843](https://github.com/microsoft/testfx/pull/2843)
### Housekeeping
@@ -71,9 +140,31 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.3.1...HEAD)
* Add test for resource recursion problem by @nohwnd in [#2778](https://github.com/microsoft/testfx/pull/2778)
* Opt-out from CPM in samples by @Evangelink in [#2805](https://github.com/microsoft/testfx/pull/2805)
+### New Contributors
+
+* @mariam-abdulla made their first contribution in [#2564](https://github.com/microsoft/testfx/pull/2564)
+* @Varorbc made their first contribution in [#2696](https://github.com/microsoft/testfx/pull/2696)
+* @skanda890 made their first contribution in [#2706](https://github.com/microsoft/testfx/pull/2706)
+* @SimonCropp made their first contribution in [#2714](https://github.com/microsoft/testfx/pull/2714)
+* @Mrxx99 made their first contribution in [#2717](https://github.com/microsoft/testfx/pull/2717)
+* @dansiegel made their first contribution in [#2727](https://github.com/microsoft/testfx/pull/2727)
+* @thomhurst made their first contribution in [#2749](https://github.com/microsoft/testfx/pull/2749)
+* @Youssef1313 made their first contribution in [#2799](https://github.com/microsoft/testfx/pull/2799)
+
### Artifacts
-## [3.3.1] - 2024-04-04
+* MSTest: [3.4.0](https://www.nuget.org/packages/MSTest/3.4.0)
+* MSTest.TestFramework: [3.4.0](https://www.nuget.org/packages/MSTest.TestFramework/3.4.0)
+* MSTest.TestAdapter: [3.4.0](https://www.nuget.org/packages/MSTest.TestAdapter/3.4.0)
+* MSTest.Analyzers: [3.4.0](https://www.nuget.org/packages/MSTest.Analyzers/3.4.0)
+* MSTest.Sdk: [3.4.0](https://www.nuget.org/packages/MSTest.Sdk/3.4.0)
+* Microsoft.Testing.Extensions.CrashDump: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/1.2.1)
+* Microsoft.Testing.Extensions.HangDump: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/1.2.1)
+* Microsoft.Testing.Extensions.HotReload: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/1.2.1)
+* Microsoft.Testing.Extensions.Retry: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.2.1)
+* Microsoft.Testing.Extensions.TrxReport: [1.2.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.2.1)
+
+## [3.3.1] - 2024-04-04
See full log [here](https://github.com/microsoft/testfx/compare/v3.3.0...v3.3.1)
@@ -94,7 +185,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.3.0...v3.3.1)
* Microsoft.Testing.Extensions.Retry: [1.1.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.1.0)
* Microsoft.Testing.Extensions.TrxReport: [1.1.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.1.0)
-## [3.3.0] - 2024-04-03
+## [3.3.0] - 2024-04-03
See full log [here](https://github.com/microsoft/testfx/compare/v3.2.2...v3.3.0)
@@ -167,7 +258,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.2.2...v3.3.0)
* Microsoft.Testing.Extensions.Retry: [1.1.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.1.0)
* Microsoft.Testing.Extensions.TrxReport: [1.1.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.1.0)
-## [3.2.2] - 2024-02-22
+## [3.2.2] - 2024-02-22
See full log [here](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2)
@@ -191,7 +282,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2)
* Microsoft.Testing.Extensions.Retry: [1.0.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.0.2)
* Microsoft.Testing.Extensions.TrxReport: [1.0.2](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.0.2)
-## [3.2.1] - 2024-02-13
+## [3.2.1] - 2024-02-13
See full log [here](https://github.com/microsoft/testfx/compare/v3.2.0...v.3.2.1)
@@ -221,7 +312,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.2.0...v.3.2.1
* Microsoft.Testing.Extensions.Retry: [1.0.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.0.1)
* Microsoft.Testing.Extensions.TrxReport: [1.0.1](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.0.1)
-## [3.2.0] - 2024-01-24
+## [3.2.0] - 2024-01-24
See full log [here](https://github.com/microsoft/testfx/compare/v3.1.1...v.3.2.0)
@@ -302,7 +393,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.1.1...v.3.2.0
* Microsoft.Testing.Extensions.Retry: [1.0.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.0.0)
* Microsoft.Testing.Extensions.TrxReport: [1.0.0](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.0.0)
-## [3.2.0-preview.24069.3] - 2024-01-19
+## [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)
@@ -355,7 +446,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.2.0-preview.2
* Microsoft.Testing.Extensions.Retry: [1.0.0-preview.24068.6](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/1.0.0-preview.24068.6)
* Microsoft.Testing.Extensions.TrxReport: [1.0.0-preview.24068.6](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/1.0.0-preview.24068.6)
-## [3.2.0-preview.23623.1] - 2023-12-23
+## [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)
@@ -370,7 +461,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.2.0-preview.2
* MSTest.TestAdapter: [3.2.0-preview.23623.1](https://www.nuget.org/packages/MSTest.TestAdapter/3.2.0-preview.23623.1)
* MSTest.Analyzers: [3.2.0-preview.23623.1](https://www.nuget.org/packages/MSTest.Analyzers/3.2.0-preview.23623.1)
-## [3.2.0-preview.23622.1] - 2023-12-22
+## [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)
@@ -418,7 +509,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.1.1...v3.2.0-
* MSTest.TestAdapter: [3.2.0-preview.23622.1](https://www.nuget.org/packages/MSTest.TestAdapter/3.2.0-preview.23622.1)
* MSTest.Analyzers: [3.2.0-preview.23622.1](https://www.nuget.org/packages/MSTest.Analyzers/3.2.0-preview.23622.1)
-## [3.1.1] - 2023-07-14
+## [3.1.1] - 2023-07-14
### Fixed
@@ -432,7 +523,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.1.0...v3.1.1)
* MSTest.TestFramework: [3.1.1](https://www.nuget.org/packages/MSTest.TestFramework/3.1.1)
* MSTest.TestAdapter: [3.1.1](https://www.nuget.org/packages/MSTest.TestAdapter/3.1.1)
-## [3.1.0] - 2023-07-14
+## [3.1.0] - 2023-07-14
See full log [here](https://github.com/Microsoft/testfx/compare/v3.0.4...v3.1.0)
@@ -478,7 +569,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.0.4...v3.1.0)
* MSTest.TestFramework: [3.1.0](https://www.nuget.org/packages/MSTest.TestFramework/3.1.0)
* MSTest.TestAdapter: [3.1.0](https://www.nuget.org/packages/MSTest.TestAdapter/3.1.0)
-## [3.0.4] - 2023-06-01
+## [3.0.4] - 2023-06-01
See full log [here](https://github.com/microsoft/testfx/compare/v3.0.3...v3.0.4)
@@ -493,7 +584,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.0.3...v3.0.4)
* MSTest.TestFramework: [3.0.4](https://www.nuget.org/packages/MSTest.TestFramework/3.0.4)
* MSTest.TestAdapter: [3.0.4](https://www.nuget.org/packages/MSTest.TestAdapter/3.0.4)
-## [3.0.3] - 2023-05-24
+## [3.0.3] - 2023-05-24
See full log [here](https://github.com/Microsoft/testfx/compare/v3.0.2...v3.0.3)
@@ -514,7 +605,7 @@ See full log [here](https://github.com/Microsoft/testfx/compare/v3.0.2...v3.0.3)
* MSTest.TestFramework: [3.0.3](https://www.nuget.org/packages/MSTest.TestFramework/3.0.3)
* MSTest.TestAdapter: [3.0.3](https://www.nuget.org/packages/MSTest.TestAdapter/3.0.3)
-## [3.0.2] - 2022-12-27
+## [3.0.2] - 2022-12-27
See full log [here](https://github.com/microsoft/testfx/compare/v3.0.1...v3.0.2)
@@ -528,7 +619,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.0.1...v3.0.2)
* MSTest.TestFramework: [3.0.2](https://www.nuget.org/packages/MSTest.TestFramework/3.0.2)
* MSTest.TestAdapter: [3.0.2](https://www.nuget.org/packages/MSTest.TestAdapter/3.0.2)
-## [3.0.1] - 2022-12-20
+## [3.0.1] - 2022-12-20
See full log [here](https://github.com/microsoft/testfx/compare/v3.0.0...v3.0.1)
@@ -551,7 +642,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.0.0...v3.0.1)
* MSTest.TestFramework: [3.0.1](https://www.nuget.org/packages/MSTest.TestFramework/3.0.1)
* MSTest.TestAdapter: [3.0.1](https://www.nuget.org/packages/MSTest.TestAdapter/3.0.1)
-## [3.0.0] - 2022-12-06
+## [3.0.0] - 2022-12-06
See full log [here](https://github.com/microsoft/testfx/compare/v2.2.10...v3.0.0)
@@ -608,7 +699,7 @@ Breaking changes announcements [#1274](https://github.com/microsoft/testfx/issue
* MSTest.TestFramework: [3.0.0](https://www.nuget.org/packages/MSTest.TestFramework/3.0.0)
* MSTest.TestAdapter: [3.0.0](https://www.nuget.org/packages/MSTest.TestAdapter/3.0.0)
-## [3.0.0-preview-20221122-01] - 2022-11-23
+## [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)
@@ -652,7 +743,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v3.0.0-preview-2
* MSTest.TestFramework: [3.0.0-preview-20221122-01](https://www.nuget.org/packages/MSTest.TestFramework/3.0.0-preview-20221122-01)
* MSTest.TestAdapter: [3.0.0-preview-20221122-01](https://www.nuget.org/packages/MSTest.TestAdapter/3.0.0-preview-20221122-01)
-## [3.0.0-preview-20221110-04] - 2022-11-11
+## [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)
@@ -785,7 +876,7 @@ See full log [here](https://github.com/microsoft/testfx/compare/v2.3.0-preview-2
* MSTest.TestFramework: [3.0.0-preview-20221110-04](https://www.nuget.org/packages/MSTest.TestFramework/3.0.0-preview-20221110-04)
* MSTest.TestAdapter: [3.0.0-preview-20221110-04](https://www.nuget.org/packages/MSTest.TestAdapter/3.0.0-preview-20221110-04)
-## [2.3.0-preview-20220810-02] 2022-08-10
+## [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)
@@ -818,7 +909,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.3.0-preview-20220810-02](https://www.nuget.org/packages/MSTest.TestFramework/2.3.0-preview-20220810-02)
* MSTest.TestAdapter: [2.3.0-preview-20220810-02](https://www.nuget.org/packages/MSTest.TestAdapter/2.3.0-preview-20220810-02)
-## [2.2.10] - 2022-04-26
+## [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)
@@ -845,7 +936,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.10](https://www.nuget.org/packages/MSTest.TestFramework/2.2.10)
* MSTest.TestAdapter: [2.2.10](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.10)
-## [2.2.10-preview-20220414-01] - 2022-04-14
+## [2.2.10-preview-20220414-01] - 2022-04-14
### Fixed
@@ -858,7 +949,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.10-preview-20220414-01](https://www.nuget.org/packages/MSTest.TestFramework/2.2.10-preview-20220414-01)
* MSTest.TestAdapter: [2.2.10-preview-20220414-01](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.10-preview-20220414-01)
-## [2.2.9] 2022-04-08
+## [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)
@@ -892,7 +983,7 @@ Due to the way that class and assembly initialize, and cleanup are invoked, thei
* MSTest.TestFramework: [2.2.9](https://www.nuget.org/packages/MSTest.TestFramework/2.2.9)
* MSTest.TestAdapter: [2.2.9](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.9)
-## [2.2.8] - 2021-11-23
+## [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)
@@ -924,7 +1015,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.8](https://www.nuget.org/packages/MSTest.TestFramework/2.2.8)
* MSTest.TestAdapter: [2.2.8](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.8)
-## [2.2.7] - 2021-09-03
+## [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)
@@ -941,7 +1032,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.7](https://www.nuget.org/packages/MSTest.TestFramework/2.2.7)
* MSTest.TestAdapter: [2.2.7](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.7)
-## [2.2.6] - 2021-08-25
+## [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)
@@ -959,7 +1050,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.6](https://www.nuget.org/packages/MSTest.TestFramework/2.2.6)
* MSTest.TestAdapter: [2.2.6](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.6)
-## [2.2.5] - 2021-06-28
+## [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)
@@ -984,7 +1075,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.5](https://www.nuget.org/packages/MSTest.TestFramework/2.2.5)
* MSTest.TestAdapter: [2.2.5](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.5)
-## [2.2.4] - 2021-05-25
+## [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)
@@ -993,7 +1084,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.4](https://www.nuget.org/packages/MSTest.TestFramework/2.2.4)
* MSTest.TestAdapter: [2.2.4](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.4)
-## [2.2.4-preview-20210331-02] - 2021-04-02
+## [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)
@@ -1015,7 +1106,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.4-preview-20210331-02](https://www.nuget.org/packages/MSTest.TestFramework/2.2.4-preview-20210331-02)
* MSTest.TestAdapter: [2.2.4-preview-20210331-02](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.4-preview-20210331-02)
-## [2.2.3] - 2021-03-16
+## [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)
@@ -1028,7 +1119,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.3](https://www.nuget.org/packages/MSTest.TestFramework/2.2.3)
* MSTest.TestAdapter: [2.2.3](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.3)
-## [2.2.2] - 2021-03-15
+## [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)
@@ -1047,7 +1138,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.2](https://www.nuget.org/packages/MSTest.TestFramework/2.2.2)
* MSTest.TestAdapter: [2.2.2](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.2)
-## [2.2.1] - 2021-03-01
+## [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)
@@ -1076,7 +1167,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.1](https://www.nuget.org/packages/MSTest.TestFramework/2.2.1)
* MSTest.TestAdapter: [2.2.1](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.1)
-## [2.2.0-preview-20210115-03] - 2021-01-20
+## [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)
@@ -1103,7 +1194,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.0-preview-20210115-03](https://www.nuget.org/packages/MSTest.TestFramework/2.2.0-preview-20210115-03)
* MSTest.TestAdapter: [2.2.0-preview-20210115-03](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.0-preview-20210115-03)
-## [2.2.0-preview-20201126-03] - 2020-11-26
+## [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)
@@ -1133,7 +1224,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.2.0-preview-20201126-03](https://www.nuget.org/packages/MSTest.TestFramework/2.2.0-preview-20201126-03)
* MSTest.TestAdapter: [2.2.0-preview-20201126-03](https://www.nuget.org/packages/MSTest.TestAdapter/2.2.0-preview-20201126-03)
-## [2.1.2] - 2020-06-08
+## [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)
@@ -1154,7 +1245,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.1.2](https://www.nuget.org/packages/MSTest.TestFramework/2.1.2)
* MSTest.TestAdapter: [2.1.2](https://www.nuget.org/packages/MSTest.TestAdapter/2.1.2)
-## [2.1.1] - 2020-04-01
+## [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)
@@ -1181,7 +1272,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.1.1](https://www.nuget.org/packages/MSTest.TestFramework/2.1.1)
* MSTest.TestAdapter: [2.1.1](https://www.nuget.org/packages/MSTest.TestAdapter/2.1.1)
-## [2.1.0] - 2020-02-03
+## [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)
@@ -1199,7 +1290,7 @@ A list of changes since last release are available [here](https://github.com/mic
* MSTest.TestFramework: [2.1.0](https://www.nuget.org/packages/MSTest.TestFramework/2.1.0)
* MSTest.TestAdapter: [2.1.0](https://www.nuget.org/packages/MSTest.TestAdapter/2.1.0)
-## [2.1.0-beta2] - 2019-12-18
+## [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)
@@ -1212,7 +1303,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [2.1.0-beta2](https://www.nuget.org/packages/MSTest.TestFramework/2.1.0-beta2)
* MSTest.TestAdapter: [2.1.0-beta2](https://www.nuget.org/packages/MSTest.TestAdapter/2.1.0-beta2)
-## [2.1.0-beta] - 2019-11-28
+## [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)
@@ -1226,7 +1317,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [2.1.0-beta](https://www.nuget.org/packages/MSTest.TestFramework/2.1.0-beta)
* MSTest.TestAdapter: [2.1.0-beta](https://www.nuget.org/packages/MSTest.TestAdapter/2.1.0-beta)
-## [2.0.0] 2019-09-03
+## [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)
@@ -1250,7 +1341,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [2.0.0](https://www.nuget.org/packages/MSTest.TestFramework/2.0.0)
* MSTest.TestAdapter: [2.0.0](https://www.nuget.org/packages/MSTest.TestAdapter/2.0.0)
-## [2.0.0-beta4] - 2019-04-10
+## [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)
@@ -1265,7 +1356,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [2.0.0-beta4](https://www.nuget.org/packages/MSTest.TestFramework/2.0.0-beta4)
* MSTest.TestAdapter: [2.0.0-beta4](https://www.nuget.org/packages/MSTest.TestAdapter/2.0.0-beta4)
-## [2.0.0-beta2] - 2019-02-15
+## [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)
@@ -1280,7 +1371,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [2.0.0-beta2](https://www.nuget.org/packages/MSTest.TestFramework/2.0.0-beta2)
* MSTest.TestAdapter: [2.0.0-beta2](https://www.nuget.org/packages/MSTest.TestAdapter/2.0.0-beta2)
-## [1.4.0] - 2018-11-26
+## [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)
@@ -1302,7 +1393,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.4.0](https://www.nuget.org/packages/MSTest.TestFramework/1.4.0)
* MSTest.TestAdapter: [1.4.0](https://www.nuget.org/packages/MSTest.TestAdapter/1.4.0)
-## [1.4.0-beta] 2018-10-17
+## [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)
@@ -1320,7 +1411,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.4.0-beta](https://www.nuget.org/packages/MSTest.TestFramework/1.4.0-beta)
* MSTest.TestAdapter: [1.4.0-beta](https://www.nuget.org/packages/MSTest.TestAdapter/1.4.0-beta)
-## [1.3.2] - 2018-06-06
+## [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)
@@ -1333,7 +1424,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.3.2](https://www.nuget.org/packages/MSTest.TestFramework/1.3.2)
* MSTest.TestAdapter: [1.3.2](https://www.nuget.org/packages/MSTest.TestAdapter/1.3.2)
-## [1.3.1] - 2018-05-25
+## [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)
@@ -1347,7 +1438,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.3.1](https://www.nuget.org/packages/MSTest.TestFramework/1.3.1)
* MSTest.TestAdapter: [1.3.1](https://www.nuget.org/packages/MSTest.TestAdapter/1.3.1)
-## [1.3.0] - 2018-05-11
+## [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)
@@ -1369,7 +1460,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.3.0](https://www.nuget.org/packages/MSTest.TestFramework/1.3.0)
* MSTest.TestAdapter: [1.3.0](https://www.nuget.org/packages/MSTest.TestAdapter/1.3.0)
-## [1.3.0-beta2] - 2018-01-15
+## [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)
@@ -1395,7 +1486,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.3.0-beta2](https://www.nuget.org/packages/MSTest.TestFramework/1.3.0-beta2)
* MSTest.TestAdapter: [1.3.0-beta2](https://www.nuget.org/packages/MSTest.TestAdapter/1.3.0-beta2)
-## [1.2.1] - 2018-04-05
+## [1.2.1] - 2018-04-05
### Changed
@@ -1412,7 +1503,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.2.1](https://www.nuget.org/packages/MSTest.TestFramework/1.2.1)
* MSTest.TestAdapter: [1.2.1](https://www.nuget.org/packages/MSTest.TestAdapter/1.2.1)
-## [1.2.0] - 2017-10-11
+## [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)
@@ -1432,7 +1523,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.2.0](https://www.nuget.org/packages/MSTest.TestFramework/1.2.0)
* MSTest.TestAdapter: [1.2.0](https://www.nuget.org/packages/MSTest.TestAdapter/1.2.0)
-## [1.2.0-beta3] - 2017-08-09
+## [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)
@@ -1452,7 +1543,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.2.0-beta3](https://www.nuget.org/packages/MSTest.TestFramework/1.2.0-beta3)
* MSTest.TestAdapter: [1.2.0-beta3](https://www.nuget.org/packages/MSTest.TestAdapter/1.2.0-beta3)
-## [1.2.0-beta] - 2017-06-29
+## [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)
@@ -1467,7 +1558,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.2.0-beta](https://www.nuget.org/packages/MSTest.TestFramework/1.2.0-beta)
* MSTest.TestAdapter: [1.2.0-beta](https://www.nuget.org/packages/MSTest.TestAdapter/1.2.0-beta)
-## [1.1.18] - 2017-06-01
+## [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)
@@ -1485,7 +1576,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.1.18](https://www.nuget.org/packages/MSTest.TestFramework/1.1.18)
* MSTest.TestAdapter: [1.1.18](https://www.nuget.org/packages/MSTest.TestAdapter/1.1.18)
-## [1.1.17] - 2017-04-21
+## [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)
@@ -1503,7 +1594,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.1.17](https://www.nuget.org/packages/MSTest.TestFramework/1.1.17)
* MSTest.TestAdapter: [1.1.17](https://www.nuget.org/packages/MSTest.TestAdapter/1.1.17)
-## [1.1.14] - 2017-03-31
+## [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)
@@ -1520,7 +1611,7 @@ A list of changes since last release are available [here](https://github.com/Mic
* MSTest.TestFramework: [1.1.14](https://www.nuget.org/packages/MSTest.TestFramework/1.1.14)
* MSTest.TestAdapter: [1.1.14](https://www.nuget.org/packages/MSTest.TestAdapter/1.1.14)
-## [1.1.13] - 2017-03-10
+## [1.1.13] - 2017-03-10
This is also the first release from GitHub and with source code building against Dev15 tooling.
@@ -1535,7 +1626,7 @@ This is also the first release from GitHub and with source code building against
* MSTest.TestFramework: [1.1.13](https://www.nuget.org/packages/MSTest.TestFramework/1.1.13)
* MSTest.TestAdapter: [1.1.13](https://www.nuget.org/packages/MSTest.TestAdapter/1.1.13)
-## [1.1.11] - 2017-02-17
+## [1.1.11] - 2017-02-17
Initial release.
diff --git a/docs/testingplatform/Index.md b/docs/testingplatform/Index.md
index 2714611072..34e78d2c84 100644
--- a/docs/testingplatform/Index.md
+++ b/docs/testingplatform/Index.md
@@ -10,6 +10,8 @@
1. [Available requests](irequest.md)
1. [Well known TestNodeUpdateMessage.TestNode properties](testnodeupdatemessage.md)
1. [Capabilities](capabilities.md)
+ 1. [ITestFrameworkCapability](itestframeworkcapability.md)
+ 1. [IBannerMessageOwnerCapability](ibannermessageownercapability.md)
1. Extensions
1. [Introduction](extensionintro.md)
1. In-process & out-of-process
@@ -18,9 +20,13 @@
1. [ITestSessionLifetimeHandler](itestsessionlifetimehandler.md)
1. [ITestApplicationLifecycleCallbacks](itestapplicationlifecyclecallbacks.md)
1. [IDataConsumer](idataconsumer.md)
+ 1. Out-of-process
+ 1. [ITestHostEnvironmentVariableProvider](itesthostenvironmentvariableprovider.md)
+ 1. [ITestHostProcessLifetimeHandler](itesthostprocesslifetimehandler.md)
1. Extensions miscellaneous
1. [IAsyncInitializableExtension & IAsyncCleanableExtension](asyncinitcleanup.md)
1. [CompositeExtensionFactory\](compositeextensionfactory.md)
+1. [Testing framework & extensions execution order](executionorder.md)
1. Services
1. [IServiceProvider](iserviceprovider.md)
1. [IConfiguration](configuration.md)
@@ -28,4 +34,5 @@
1. [IMessageBus](imessagebus.md)
1. [ICommandLineOptions](icommandlineoptions.md)
1. [IOutputDevice](ioutputdevice.md)
+ 1. [IPlatformInformation](iplatforminformation.md)
1. [Code sample](codesample.md)
diff --git a/docs/testingplatform/Source/TestingPlatformExplorer/Out-of-process extensions/MonitorTestHost.cs b/docs/testingplatform/Source/TestingPlatformExplorer/Out-of-process extensions/MonitorTestHost.cs
new file mode 100644
index 0000000000..a685152567
--- /dev/null
+++ b/docs/testingplatform/Source/TestingPlatformExplorer/Out-of-process extensions/MonitorTestHost.cs
@@ -0,0 +1,46 @@
+// 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.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestHostControllers;
+using Microsoft.Testing.Platform.OutputDevice;
+
+namespace TestingPlatformExplorer.OutOfProcess;
+
+internal class MonitorTestHost : ITestHostProcessLifetimeHandler, IOutputDeviceDataProducer
+{
+ private readonly IOutputDevice _outputDevice;
+
+ public MonitorTestHost(IOutputDevice outputDevice)
+ {
+ _outputDevice = outputDevice;
+ }
+
+ public string Uid => nameof(MonitorTestHost);
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => nameof(MonitorTestHost);
+
+ public string Description => "Example of monitoring the test host process.";
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public async Task BeforeTestHostProcessStartAsync(CancellationToken cancellationToken)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData("BeforeTestHostProcessStartAsync")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+
+ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"OnTestHostProcessExitedAsync, test host exited with exit code {testHostProcessInformation.ExitCode}")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+
+ public async Task OnTestHostProcessStartedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"OnTestHostProcessStartedAsync, test host started with PID {testHostProcessInformation.PID}")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+}
diff --git a/docs/testingplatform/Source/TestingPlatformExplorer/Out-of-process extensions/SetEnvironmentVariableForTestHost.cs b/docs/testingplatform/Source/TestingPlatformExplorer/Out-of-process extensions/SetEnvironmentVariableForTestHost.cs
new file mode 100644
index 0000000000..b3b0fb7160
--- /dev/null
+++ b/docs/testingplatform/Source/TestingPlatformExplorer/Out-of-process extensions/SetEnvironmentVariableForTestHost.cs
@@ -0,0 +1,32 @@
+// 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.Extensions.TestHostControllers;
+
+namespace TestingPlatformExplorer.OutOfProcess;
+
+internal class SetEnvironmentVariableForTestHost : ITestHostEnvironmentVariableProvider
+{
+ public string Uid => nameof(SetEnvironmentVariableForTestHost);
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => nameof(SetEnvironmentVariableForTestHost);
+
+ public string Description => "Example of setting environment variables for the test host.";
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public Task UpdateAsync(IEnvironmentVariables environmentVariables)
+ {
+ environmentVariables.SetVariable(new EnvironmentVariable("SAMPLE", "SAMPLE_VALUE", false, true));
+ return Task.CompletedTask;
+ }
+
+ public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnlyEnvironmentVariables environmentVariables)
+ => environmentVariables.TryGetVariable("SAMPLE", out OwnedEnvironmentVariable? value) && value.Value == "SAMPLE_VALUE"
+ ? ValidationResult.ValidTask
+ : ValidationResult.InvalidTask("The environment variable 'SAMPLE' is not set to 'SAMPLE_VALUE'.");
+}
diff --git a/docs/testingplatform/Source/TestingPlatformExplorer/Program.cs b/docs/testingplatform/Source/TestingPlatformExplorer/Program.cs
index 210c037ae2..441c6d7cfd 100644
--- a/docs/testingplatform/Source/TestingPlatformExplorer/Program.cs
+++ b/docs/testingplatform/Source/TestingPlatformExplorer/Program.cs
@@ -8,13 +8,14 @@
using Microsoft.Testing.Platform.Services;
using TestingPlatformExplorer.InProcess;
+using TestingPlatformExplorer.OutOfProcess;
using TestingPlatformExplorer.TestingFramework;
// Create the test application builder
ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args);
// Register the testing framework
-testApplicationBuilder.AddTestingFramework(new[] { Assembly.GetExecutingAssembly() });
+testApplicationBuilder.AddTestingFramework(() => new[] { Assembly.GetExecutingAssembly() });
// In-process & out-of-process extensions
// Register the testing framework command line options
@@ -28,6 +29,12 @@
testApplicationBuilder.TestHost.AddDataConsumer(serviceProvider
=> new DisplayDataConsumer(serviceProvider.GetOutputDevice()));
+// Out-of-process extensions
+testApplicationBuilder.TestHostControllers.AddEnvironmentVariableProvider(_
+ => new SetEnvironmentVariableForTestHost());
+testApplicationBuilder.TestHostControllers.AddProcessLifetimeHandler(serviceProvider =>
+ new MonitorTestHost(serviceProvider.GetOutputDevice()));
+
// In-process composite extension SessionLifeTimeHandler+DataConsumer
CompositeExtensionFactory compositeExtensionFactory = new(serviceProvider => new DisplayCompositeExtensionFactorySample(serviceProvider.GetOutputDevice()));
testApplicationBuilder.TestHost.AddTestSessionLifetimeHandle(compositeExtensionFactory);
diff --git a/docs/testingplatform/Source/TestingPlatformExplorer/TestingFramework/TestingFramework.Registration.cs b/docs/testingplatform/Source/TestingPlatformExplorer/TestingFramework/TestingFramework.Registration.cs
index 46535dc94e..5d2c2ddb9a 100644
--- a/docs/testingplatform/Source/TestingPlatformExplorer/TestingFramework/TestingFramework.Registration.cs
+++ b/docs/testingplatform/Source/TestingPlatformExplorer/TestingFramework/TestingFramework.Registration.cs
@@ -10,7 +10,7 @@ namespace TestingPlatformExplorer.TestingFramework;
public static class TestingFrameworkExtensions
{
- public static void AddTestingFramework(this ITestApplicationBuilder builder, Assembly[] assemblies)
+ public static void AddTestingFramework(this ITestApplicationBuilder builder, Func assemblies)
=> builder.RegisterTestFramework(_ => new TestingFrameworkCapabilities(),
(capabilities, serviceProvider) => new TestingFramework(capabilities,
serviceProvider.GetCommandLineOptions(),
diff --git a/docs/testingplatform/Source/TestingPlatformExplorer/TestingFramework/TestingFramework.cs b/docs/testingplatform/Source/TestingPlatformExplorer/TestingFramework/TestingFramework.cs
index bf74a24698..0176a0c973 100644
--- a/docs/testingplatform/Source/TestingPlatformExplorer/TestingFramework/TestingFramework.cs
+++ b/docs/testingplatform/Source/TestingPlatformExplorer/TestingFramework/TestingFramework.cs
@@ -35,14 +35,14 @@ public TestingFramework(
IConfiguration configuration,
ILogger logger,
IOutputDevice outputDevice,
- Assembly[] assemblies)
+ Func assemblies)
{
_capabilities = (TestingFrameworkCapabilities)capabilities;
_commandLineOptions = commandLineOptions;
_configuration = configuration;
_logger = logger;
_outputDevice = outputDevice;
- _assemblies = assemblies;
+ _assemblies = assemblies();
if (_commandLineOptions.TryGetOptionArgumentList(TestingFrameworkCommandLineOptions.DopOption, out string[]? argumentList))
{
@@ -88,9 +88,9 @@ public Task CreateTestSessionAsync(CreateTestSessionCon
public async Task ExecuteRequestAsync(ExecuteRequestContext context)
{
- if (_logger.IsEnabled(LogLevel.Information))
+ if (_logger.IsEnabled(LogLevel.Debug))
{
- await _logger.LogInformationAsync($"Executing request of type '{context.Request}'");
+ await _logger.LogDebugAsync($"Executing request of type '{context.Request}'");
}
switch (context.Request)
diff --git a/docs/testingplatform/Source/TestingPlatformExplorer/TestingPlatformExplorer.csproj b/docs/testingplatform/Source/TestingPlatformExplorer/TestingPlatformExplorer.csproj
index 70aefdcf34..bb091c54e7 100644
--- a/docs/testingplatform/Source/TestingPlatformExplorer/TestingPlatformExplorer.csproj
+++ b/docs/testingplatform/Source/TestingPlatformExplorer/TestingPlatformExplorer.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/docs/testingplatform/capabilities.md b/docs/testingplatform/capabilities.md
index 08a8b059f1..b723631024 100644
--- a/docs/testingplatform/capabilities.md
+++ b/docs/testingplatform/capabilities.md
@@ -65,7 +65,7 @@ If the testing framework implements this interface and we can query it at runtim
* Determine if the testing framework can supply CPU usage data `CanProvidePerTestCPUConsumption = true`
* Request the testing adapter to activate this mode by invoking the `Enable()` method before the test session commences
-The ipotetical code fragment inside the extension could be something like:
+The hypothetical code fragment inside the extension could be something like:
```cs
IServiceProvider serviceProvider = ...get service provider...
diff --git a/docs/testingplatform/codesample.md b/docs/testingplatform/codesample.md
index f98d0654e8..b740f1a617 100644
--- a/docs/testingplatform/codesample.md
+++ b/docs/testingplatform/codesample.md
@@ -1,6 +1,6 @@
# Code sample
-You can find a practical example of the concepts discussed in this documentation by opening the solution located at `./Source/TestingPlatformSamples.sln`.
+You can find a practical example of the concepts discussed in this documentation by opening the solution located at [./Source/TestingPlatformSamples.sln](Source).
This project demonstrates a basic `TestingFramework` testing framework, showcasing how to utilize the extensibility point and various available services.
diff --git a/docs/testingplatform/executionorder.md b/docs/testingplatform/executionorder.md
new file mode 100644
index 0000000000..115414e530
--- /dev/null
+++ b/docs/testingplatform/executionorder.md
@@ -0,0 +1,21 @@
+# Testing framework & extensions execution order
+
+The testing platform consists of a [testing framework](itestframework.md) and any number of extensions that can operate [*in-process*](extensionintro.md) or [*out-of-process*](extensionintro.md). This document outlines the **sequence of calls** to all potential extensibility points to provide clarity on when a feature is anticipated to be invoked.
+
+While a *sequence* could be used to depict this, we opt for a straightforward order of invocation calls, which allows for a more comprehensive commentary on the workflow.
+
+1. [ITestHostEnvironmentVariableProvider.UpdateAsync](itesthostenvironmentvariableprovider.md) : Out-of-process
+1. [ITestHostEnvironmentVariableProvider.ValidateTestHostEnvironmentVariablesAsync](itesthostenvironmentvariableprovider.md) : Out-of-process
+1. [ITestHostProcessLifetimeHandler.BeforeTestHostProcessStartAsync](itesthostprocesslifetimehandler.md) : Out-of-process
+1. Test host process start
+1. [ITestHostProcessLifetimeHandler.OnTestHostProcessStartedAsync](itesthostprocesslifetimehandler.md) : Out-of-process, this event can intertwine the actions of *in-process* extensions, depending on race conditions.
+1. [ITestApplicationLifecycleCallbacks.BeforeRunAsync](itestsessionlifetimehandler.md): In-process
+1. [ITestSessionLifetimeHandler.OnTestSessionStartingAsync](itestsessionlifetimehandler.md): In-process
+1. [ITestFramework.CreateTestSessionAsync](itestframework.md): In-process
+1. [ITestFramework.ExecuteRequestAsync](itestframework.md): In-process, this method can be called one or more times. At this point, the testing framework will transmit information to the [IMessageBus](imessagebus.md) that can be utilized by the [IDataConsumer](idataconsumer.md).
+1. [ITestFramework.CloseTestSessionAsync](itestframework.md): In-process
+1. [ITestSessionLifetimeHandler.OnTestSessionFinishingAsync](itestsessionlifetimehandler.md): In-process
+1. [ITestApplicationLifecycleCallbacks.AfterRunAsync](itestsessionlifetimehandler.md): In-process
+1. In-process cleanup, involves calling dispose and [IAsyncCleanableExtension](asyncinitcleanup.md) on all extension points.
+1. [ITestHostProcessLifetimeHandler.OnTestHostProcessExitedAsync](itesthostprocesslifetimehandler.md) : Out-of-process
+1. Out-of-process cleanup, involves calling dispose and [IAsyncCleanableExtension](asyncinitcleanup.md) on all extension points.
diff --git a/docs/testingplatform/ibannermessageownercapability.md b/docs/testingplatform/ibannermessageownercapability.md
new file mode 100644
index 0000000000..a30cb68849
--- /dev/null
+++ b/docs/testingplatform/ibannermessageownercapability.md
@@ -0,0 +1,7 @@
+# `IBannerMessageOwnerCapability`
+
+An optional [test framework capability](itestframeworkcapability.md) that allows the test framework to provide the banner message to the platform. If the message is null or if the capability is not present, the platform will use its default banner message.
+
+This capability implementation allows to abstract away the various conditions that the test framework may need to consider to decide whether or not the banner message should be displayed.
+
+The platform exposes the [`IPlatformInformation` service](iplatforminformation.md) to provide some information about the platform that could be useful when building your custom banner message.
diff --git a/docs/testingplatform/idataconsumer.md b/docs/testingplatform/idataconsumer.md
index a6e461d197..b2926f4963 100644
--- a/docs/testingplatform/idataconsumer.md
+++ b/docs/testingplatform/idataconsumer.md
@@ -90,4 +90,9 @@ Finally, the api takes a `CancellationToken` which the extension is expected to
> [!IMPORTANT]
> It's crucial to process the payload directly within the `ConsumeAsync` method. The [IMessageBus](imessagebus.md) can manage both synchronous and asynchronous processing, coordinating the execution with the [testing framework](itestframework.md). Although the consumption process is entirely asynchronous and doesn't block the [IMessageBus.Push](imessagebus.md) at the time of writing, this is an implementation detail that may change in the future due to feature requirements. However, we aim to maintain this interface's simplicity and ensure that this method is always called once, eliminating the need for complex synchronization. Additionally, we automatically manage the scalability of the consumers.
+
+
+> [!WARNING]
+> When using `IDataConsumer` in conjunction with [ITestHostProcessLifetimeHandler](itestsessionlifetimehandler.md) within a [composite extension point](compositeextensionfactory.md), **it's crucial to disregard any data received post the execution of [ITestSessionLifetimeHandler.OnTestSessionFinishingAsync](itestsessionlifetimehandler.md)**. The `OnTestSessionFinishingAsync` is the final opportunity to process accumulated data and transmit new information to the [IMessageBus](imessagebus.md), hence, any data consumed beyond this point will not be *utilizable* by the extension.
+
If your extension requires intensive initialization and you need to use the async/await pattern, you can refer to the [`Async extension initialization and cleanup`](asyncinitcleanup.md). If you need to *share state* between extension points, you can refer to the [`CompositeExtensionFactory`](compositeextensionfactory.md) section.
diff --git a/docs/testingplatform/imessagebus.md b/docs/testingplatform/imessagebus.md
index 1ba3ddc76b..33d1428b35 100644
--- a/docs/testingplatform/imessagebus.md
+++ b/docs/testingplatform/imessagebus.md
@@ -37,7 +37,7 @@ Let's discuss the parameters:
* `IData`: This interface serves as a placeholder where you only need to provide descriptive details such as the name and a description. The interface doesn't reveal much about the data's nature, which is intentional. It implies that the test framework and extensions can push any type of data to the bus, and this data can be consumed by any registered extension or the test framework itself.
This approach facilitates the evolution of the information exchange process, preventing breaking changes when an extension is unfamiliar with new data. **It allows different versions of extensions and the test framework to operate in harmony, based on their mutual understanding**.
-The opposite end of the bus is what we refer to as a [consumer](idataConsumer.md), which is subscribed to a specific type of data and can thus consume it.
+The opposite end of the bus is what we refer to as a [consumer](idataconsumer.md), which is subscribed to a specific type of data and can thus consume it.
> [!IMPORTANT]
> Always use *await* the call to `PublishAsync`. If you don't, the `IData` might not be processed correctly by the testing platform and extensions, which could lead to subtle bugs. It's only after you've returned from the *await* that you can be assured that the `IData` has been queued for processing on the message bus. Regardless of the extension point you're working on, ensure that you've awaited all `PublishAsync` calls before exiting the extension. For example, if you're implementing the [`testing framework`](itestframework.md), you should not call `Complete` on the [requests](irequest.md) until you've awaited all `PublishAsync` calls for that specific request.
diff --git a/docs/testingplatform/iplatforminformation.md b/docs/testingplatform/iplatforminformation.md
new file mode 100644
index 0000000000..bb3510fad2
--- /dev/null
+++ b/docs/testingplatform/iplatforminformation.md
@@ -0,0 +1,3 @@
+# `IPlatformInformation`
+
+Provides information about the platform such as: name, version, commit hash and build date.
diff --git a/docs/testingplatform/itestframework.md b/docs/testingplatform/itestframework.md
index 176ea51192..ae0b1e9b2a 100644
--- a/docs/testingplatform/itestframework.md
+++ b/docs/testingplatform/itestframework.md
@@ -1,4 +1,4 @@
-# Implement the Microsoft.Testing.Platform.Extensions.TestFramework.ITestFramework
+# The `Microsoft.Testing.Platform.Extensions.TestFramework.ITestFramework`
The `Microsoft.Testing.Platform.Extensions.TestFramework.ITestFramework` is implemented by extensions that provide a test framework:
@@ -78,7 +78,7 @@ public sealed class ExecuteRequestContext
```mermaid
sequenceDiagram
Testing platform->>ITestFramework: adapterFactory() from 'RegisterTestFramework'
- ITestFramework-->>Testing platform:
+ ITestFramework-->>Testing platform:
Testing platform->>ITestFramework: CreateTestSessionAsync(CreateTestSessionContext)
ITestFramework-->>Testing platform: CreateTestSessionResult
Testing platform->>ITestFramework: ExecuteRequestAsync(ExecuteRequestContext_1)
@@ -113,8 +113,8 @@ For a comprehensive list of information that can be published to the testing pla
`CancellationToken`: This token is utilized to interrupt the processing of a particular request.
`Complete()`: As depicted in the previous sequence, the `Complete` method notifies the platform that the request has been successfully processed and all relevant information has been transmitted to the [IMessageBus](imessagebus.md).
->> [!WARNING]
->> Neglecting to invoke `Complete()` on the request will result in the test application becoming unresponsive.
+> [!WARNING]
+> Neglecting to invoke `Complete()` on the request will result in the test application becoming unresponsive.
To customize your test framework according to your requirements or those of your users, you can use a personalized section inside the [configuration](configuration.md) file or with custom [command line options](icommandlineoptionsprovider.md).
diff --git a/docs/testingplatform/itestframeworkcapability.md b/docs/testingplatform/itestframeworkcapability.md
new file mode 100644
index 0000000000..1186395fe4
--- /dev/null
+++ b/docs/testingplatform/itestframeworkcapability.md
@@ -0,0 +1,3 @@
+# Test framework capabilities
+
+The platform exposes a specialized interface named `ITestFrameworkCapability` that is the base of all capabilities exposed for test frameworks. These capabilities are provided when [registering the test framework to the platform](registertestframework.md).
diff --git a/docs/testingplatform/itesthostenvironmentvariableprovider.md b/docs/testingplatform/itesthostenvironmentvariableprovider.md
new file mode 100644
index 0000000000..30b5b39f62
--- /dev/null
+++ b/docs/testingplatform/itesthostenvironmentvariableprovider.md
@@ -0,0 +1,71 @@
+# The `ITestHostEnvironmentVariableProvider`
+
+The `ITestHostEnvironmentVariableProvider` is an *out-of-process* extension that enables you to establish custom environment variables for the test host. Utilizing this extension point ensures that the testing platform will initiate a new host with the appropriate environment variables, as detailed in the [architecture](architecture.md) section.
+
+To register a custom `ITestHostEnvironmentVariableProvider`, utilize the following API:
+
+```cs
+ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args);
+...
+testApplicationBuilder.TestHostControllers.AddEnvironmentVariableProvider(serviceProvider =>
+ => new CustomEnvironmentVariableForTestHost());
+...
+```
+
+The factory utilizes the [IServiceProvider](iserviceprovider.md) to gain access to the suite of services offered by the testing platform.
+
+> [!IMPORTANT]
+> The sequence of registration is significant, as the APIs are called in the order they were registered.
+
+The `ITestHostEnvironmentVariableProvider` interface includes the following methods and types:
+
+```cs
+public interface ITestHostEnvironmentVariableProvider : ITestHostControllersExtension, IExtension
+{
+ Task UpdateAsync(IEnvironmentVariables environmentVariables);
+ Task ValidateTestHostEnvironmentVariablesAsync(IReadOnlyEnvironmentVariables environmentVariables);
+}
+
+public interface IEnvironmentVariables : IReadOnlyEnvironmentVariables
+{
+ void SetVariable(EnvironmentVariable environmentVariable);
+ void RemoveVariable(string variable);
+}
+
+public interface IReadOnlyEnvironmentVariables
+{
+ bool TryGetVariable(string variable, [NotNullWhen(true)] out OwnedEnvironmentVariable? environmentVariable);
+}
+
+public sealed class OwnedEnvironmentVariable : EnvironmentVariable
+{
+ public IExtension Owner { get; }
+ public OwnedEnvironmentVariable(IExtension owner, string variable, string? value, bool isSecret, bool isLocked);
+}
+
+public class EnvironmentVariable
+{
+ public string Variable { get; }
+ public string? Value { get; }
+ public bool IsSecret { get; }
+ public bool IsLocked { get; }
+}
+```
+
+The `ITestHostEnvironmentVariableProvider` is a type of `ITestHostControllersExtension`, which serves as a base for all *test host controller* extensions. Like all other extension points, it also inherits from [IExtension](iextension.md). Therefore, like any other extension, you can choose to enable or disable it using the `IExtension.IsEnabledAsync` API.
+
+Let's describe the api:
+
+`UpdateAsync`: This update API provides an instance of the `IEnvironmentVariables` object, from which you can call the `SetVariable` or `RemoveVariable` methods. When using `SetVariable`, you must pass an object of type `EnvironmentVariable`, which requires the following specifications:
+
+* `Variable`: The name of the environment variable.
+* `Value`: The value of the environment variable.
+* `IsSecret`: This indicates whether the environment variable contains sensitive information that should not be logged or accessible via the `TryGetVariable`.
+* `IsLocked`: This determines whether other `ITestHostEnvironmentVariableProvider` extensions can modify this value.
+
+`ValidateTestHostEnvironmentVariablesAsync`: This method is invoked after all the `UpdateAsync` methods of the registered `ITestHostEnvironmentVariableProvider` instances have been called. It allows you to *verify* the correct setup of the environment variables. It takes an object that implements `IReadOnlyEnvironmentVariables`, which provides the `TryGetVariable` method to fetch specific environment variable information with the `OwnedEnvironmentVariable` object type. After validation, you return a `ValidationResult` containing any failure reasons.
+
+> [!NOTE]
+> The testing platform, by default, implements and registers the `SystemEnvironmentVariableProvider`. This provider loads all the *current* environment variables. As the first registered provider, it executes first, granting access to the default environment variables for all other `ITestHostEnvironmentVariableProvider` user extensions.
+
+If your extension requires intensive initialization and you need to use the async/await pattern, you can refer to the [`Async extension initialization and cleanup`](asyncinitcleanup.md). If you need to *share state* between extension points, you can refer to the [`CompositeExtensionFactory`](compositeextensionfactory.md) section.
diff --git a/docs/testingplatform/itesthostprocesslifetimehandler.md b/docs/testingplatform/itesthostprocesslifetimehandler.md
new file mode 100644
index 0000000000..565455eb3e
--- /dev/null
+++ b/docs/testingplatform/itesthostprocesslifetimehandler.md
@@ -0,0 +1,54 @@
+# The `ITestHostProcessLifetimeHandler`
+
+The `ITestHostProcessLifetimeHandler` is an *out-of-process* extension that allows you to observe the test host process from an external standpoint. This ensures that your extension remains unaffected by potential crashes or hangs that could be induced by the code under test. Utilizing this extension point will prompt the testing platform to initiate a new host, as detailed in the [architecture](architecture.md) section.
+
+To register a custom `ITestHostProcessLifetimeHandler`, utilize the following API:
+
+```cs
+ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args);
+...
+testApplicationBuilder.TestHostControllers.AddProcessLifetimeHandler(serviceProvider =>
+ new CustomMonitorTestHost());
+...
+```
+
+The factory utilizes the [IServiceProvider](iserviceprovider.md) to gain access to the suite of services offered by the testing platform.
+
+> [!IMPORTANT]
+> The sequence of registration is significant, as the APIs are called in the order they were registered.
+
+The `ITestHostProcessLifetimeHandler` interface includes the following methods:
+
+```cs
+public interface ITestHostProcessLifetimeHandler : ITestHostControllersExtension
+{
+ Task BeforeTestHostProcessStartAsync(CancellationToken cancellationToken);
+ Task OnTestHostProcessStartedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation);
+ Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation);
+}
+
+public interface ITestHostProcessInformation
+{
+ int PID { get; }
+ int ExitCode { get; }
+ bool HasExitedGracefully { get; }
+}
+```
+
+The `ITestHostProcessLifetimeHandler` is a type of `ITestHostControllersExtension`, which serves as a base for all *test host controller* extensions. Like all other extension points, it also inherits from [IExtension](iextension.md). Therefore, like any other extension, you can choose to enable or disable it using the `IExtension.IsEnabledAsync` API.
+
+Let's describe the api:
+
+`BeforeTestHostProcessStartAsync`: This method is invoked prior to the testing platform initiating the test hosts.
+
+`OnTestHostProcessStartedAsync`: This method is invoked immediately after the test host starts. This method offers an object that implements the `ITestHostProcessInformation` interface, which provides key details about the test host process result.
+> [!IMPORTANT]
+> The invocation of this method does not halt the test host's execution. If you need to pause it, you should register an [*in-process*](extensionintro.md) extension such as [`ITestApplicationLifecycleCallbacks`](itestapplicationlifecyclecallbacks.md) and synchronize it with the *out-of-process* extension.
+
+`OnTestHostProcessExitedAsync`: This method is invoked when the test suite execution is complete. This method supplies an object that adheres to the `ITestHostProcessInformation` interface, which conveys crucial details about the outcome of the test host process.
+
+The `ITestHostProcessInformation` interface provides the following details:
+
+* `PID`: The process ID of the test host.
+* `ExitCode`: The exit code of the process. This value is only available within the `OnTestHostProcessExitedAsync` method. Attempting to access it within the `OnTestHostProcessStartedAsync` method will result in an exception.
+* `HasExitedGracefully`: A boolean value indicating whether the test host has crashed. If true, it signifies that the test host did not exit gracefully.
diff --git a/docs/testingplatform/pillars.md b/docs/testingplatform/pillars.md
index ca75f39a93..5b8463f425 100644
--- a/docs/testingplatform/pillars.md
+++ b/docs/testingplatform/pillars.md
@@ -13,3 +13,14 @@ The main driving factors for the evolution of the new testing platform are:
* **Performant**: Finding the right balance between features and extension points to avoid bloating the runtime with non-fundamental code. The new test platform is designed to "orchestrate" a test run, rather than providing implementation details on how to do it.
* **Extensible enough**: The new platform is built on extensibility points to allow for maximum customization of runtime execution. It allows you to configure the test process host, observe the test process, and consume information from the test framework within the test host process.
* **Single module deploy**: The hostability feature enables a single module deploy model, where a single compilation result can be used to support all extensibility points, both out-of-process and in-process, without the need to ship different executable modules.
+
+The following factors should enhance the overall quality of the testing platform:
+
+* Shifting all to compile time aids in identifying issues prior to runtime.
+* Determinism is beneficial in all aspects, as it reduces bugs and, in the event of a bug, provides a clear, straightforward stack trace that directly indicates the problem.
+* Determinism facilitates straightforward reproduction of issues, independent of the execution context (such as machine setup, local environment, CI, etc.). If the issue is related to the execution context, determinism makes it evident.
+* Dynamic code, often associated with "indirect execution", can result in performance degradation. By avoiding it, performance can be enhanced.
+* Eliminating dynamic code simplifies the logic behind feature development. The code you see is exactly what will be executed at runtime.
+* Eliminating dependencies and dynamic code guarantees compatibility with upcoming runtime features.
+* Eliminating dependencies means we can run everywhere.
+* Operating a self-contained testing platform without dependencies ensures that there's always a mechanism to execute user tests. This is because `Microsoft.Testing.Platform.dll` is viewed as a fundamental part of the runtime itself, ideally `System.Testing.Platform`.
diff --git a/eng/Analyzers.props b/eng/Analyzers.props
index 31d9a3c856..15c8273caf 100644
--- a/eng/Analyzers.props
+++ b/eng/Analyzers.props
@@ -12,7 +12,7 @@
-
+
diff --git a/eng/Build.props b/eng/Build.props
index 460968206c..85cf030782 100644
--- a/eng/Build.props
+++ b/eng/Build.props
@@ -1,15 +1,40 @@
-
+
+ all
+
+
+
+
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 97d3ff2079..14aa5b594d 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,33 +1,29 @@
-
+ https://github.com/dotnet/arcade
- 67d23f4ba1813b315e7e33c71d18b63475f5c5f8
+ c9efa535175049eb9cba06cae1f8c3d5dbe768a9
-
+ https://github.com/dotnet/arcade
- 67d23f4ba1813b315e7e33c71d18b63475f5c5f8
+ c9efa535175049eb9cba06cae1f8c3d5dbe768a9https://github.com/dotnet/arcade2fb543a45580400a559b5ae41c96a815ea14dac5
-
+ https://dev.azure.com/devdiv/DevDiv/_git/vs-code-coverage
- eaff7ae97a30e87a8e5a64e7ff989f4a8de69439
+ fbc5c8316febc4897fe37cb6a1bb20a998917a87
-
+ https://github.com/microsoft/testanywhere
- 445bda5374781f22ebd553dbc5c52d4c9c4176eb
+ 4a12d8fed3ac9892d74bce1b75de8c8a5b21cbd9
-
+ https://github.com/microsoft/testanywhere
- 0e10f1f3c9cd3f306517e037b7560c6cf2ab2e9b
-
-
- https://github.com/microsoft/testanywhere
- 0e10f1f3c9cd3f306517e037b7560c6cf2ab2e9b
+ 4a12d8fed3ac9892d74bce1b75de8c8a5b21cbd9
diff --git a/eng/Versions.props b/eng/Versions.props
index 02eacfb3cb..7342875b96 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -1,14 +1,16 @@
-
- 3.4.0
+
+ 3.5.0
+
+ 1.3.1preview
- 8.0.0-beta.24225.1
- 17.11.1-preview.24257.1
- 1.2.0-preview.24168.3
- 1.2.0-preview.24256.5
- 1.0.0-alpha.24256.5
+ 8.0.0-beta.24360.5
+ 17.11.3
+
+ 1.3.0
+ 1.0.0-alpha.24366.3
diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1
index 5a3a32ea8d..238945cb5a 100644
--- a/eng/common/post-build/publish-using-darc.ps1
+++ b/eng/common/post-build/publish-using-darc.ps1
@@ -2,7 +2,6 @@ param(
[Parameter(Mandatory=$true)][int] $BuildId,
[Parameter(Mandatory=$true)][int] $PublishingInfraVersion,
[Parameter(Mandatory=$true)][string] $AzdoToken,
- [Parameter(Mandatory=$true)][string] $MaestroToken,
[Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro.dot.net',
[Parameter(Mandatory=$true)][string] $WaitPublishingFinish,
[Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters,
@@ -31,13 +30,13 @@ try {
}
& $darc add-build-to-channel `
- --id $buildId `
- --publishing-infra-version $PublishingInfraVersion `
- --default-channels `
- --source-branch main `
- --azdev-pat $AzdoToken `
- --bar-uri $MaestroApiEndPoint `
- --password $MaestroToken `
+ --id $buildId `
+ --publishing-infra-version $PublishingInfraVersion `
+ --default-channels `
+ --source-branch main `
+ --azdev-pat "$AzdoToken" `
+ --bar-uri "$MaestroApiEndPoint" `
+ --ci `
@optionalParams
if ($LastExitCode -ne 0) {
diff --git a/eng/common/templates-official/job/publish-build-assets.yml b/eng/common/templates-official/job/publish-build-assets.yml
index 589ac80a18..ba3e7df815 100644
--- a/eng/common/templates-official/job/publish-build-assets.yml
+++ b/eng/common/templates-official/job/publish-build-assets.yml
@@ -76,13 +76,16 @@ jobs:
- task: NuGetAuthenticate@1
- - task: PowerShell@2
+ - task: AzureCLI@2
displayName: Publish Build Assets
inputs:
- filePath: eng\common\sdk-task.ps1
- arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet
+ azureSubscription: "Darc: Maestro Production"
+ scriptType: ps
+ scriptLocation: scriptPath
+ scriptPath: $(Build.SourcesDirectory)/eng/common/sdk-task.ps1
+ arguments: >
+ -task PublishBuildAssets -restore -msbuildEngine dotnet
/p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests'
- /p:BuildAssetRegistryToken=$(MaestroAccessToken)
/p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com
/p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }}
/p:OfficialBuildId=$(Build.BuildNumber)
@@ -137,14 +140,16 @@ jobs:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
- - task: PowerShell@2
+ - task: AzureCLI@2
displayName: Publish Using Darc
inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
- arguments: -BuildId $(BARBuildId)
+ azureSubscription: "Darc: Maestro Production"
+ scriptType: ps
+ scriptLocation: scriptPath
+ scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+ arguments: -BuildId $(BARBuildId)
-PublishingInfraVersion 3
-AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
- -MaestroToken '$(MaestroApiAccessToken)'
-WaitPublishingFinish true
-ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
-SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
diff --git a/eng/common/templates-official/job/source-build.yml b/eng/common/templates-official/job/source-build.yml
index f193dfbe23..f983033bb0 100644
--- a/eng/common/templates-official/job/source-build.yml
+++ b/eng/common/templates-official/job/source-build.yml
@@ -31,6 +31,12 @@ parameters:
# container and pool.
platform: {}
+ # If set to true and running on a non-public project,
+ # Internal blob storage locations will be enabled.
+ # This is not enabled by default because many repositories do not need internal sources
+ # and do not need to have the required service connections approved in the pipeline.
+ enableInternalSources: false
+
jobs:
- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }}
displayName: Source-Build (${{ parameters.platform.name }})
@@ -62,6 +68,8 @@ jobs:
clean: all
steps:
+ - ${{ if eq(parameters.enableInternalSources, true) }}:
+ - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml
- template: /eng/common/templates-official/steps/source-build.yml
parameters:
platform: ${{ parameters.platform }}
diff --git a/eng/common/templates-official/job/source-index-stage1.yml b/eng/common/templates-official/job/source-index-stage1.yml
index f0513aee5b..60dfb6b2d1 100644
--- a/eng/common/templates-official/job/source-index-stage1.yml
+++ b/eng/common/templates-official/job/source-index-stage1.yml
@@ -1,6 +1,7 @@
parameters:
runAsPublic: false
- sourceIndexPackageVersion: 1.0.1-20230228.2
+ sourceIndexUploadPackageVersion: 2.0.0-20240502.12
+ sourceIndexProcessBinlogPackageVersion: 1.0.1-20240129.2
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
preSteps: []
@@ -14,14 +15,14 @@ jobs:
dependsOn: ${{ parameters.dependsOn }}
condition: ${{ parameters.condition }}
variables:
- - name: SourceIndexPackageVersion
- value: ${{ parameters.sourceIndexPackageVersion }}
+ - name: SourceIndexUploadPackageVersion
+ value: ${{ parameters.sourceIndexUploadPackageVersion }}
+ - name: SourceIndexProcessBinlogPackageVersion
+ value: ${{ parameters.sourceIndexProcessBinlogPackageVersion }}
- name: SourceIndexPackageSource
value: ${{ parameters.sourceIndexPackageSource }}
- name: BinlogPath
value: ${{ parameters.binlogPath }}
- - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - group: source-dot-net stage1 variables
- template: /eng/common/templates-official/variables/pool-providers.yml
${{ if ne(parameters.pool, '') }}:
@@ -41,16 +42,16 @@ jobs:
- ${{ preStep }}
- task: UseDotNet@2
- displayName: Use .NET Core SDK 6
+ displayName: Use .NET 8 SDK
inputs:
packageType: sdk
- version: 6.0.x
+ version: 8.0.x
installationPath: $(Agent.TempDirectory)/dotnet
workingDirectory: $(Agent.TempDirectory)
- script: |
- $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
- $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(sourceIndexProcessBinlogPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(sourceIndexUploadPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
displayName: Download Tools
# Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk.
workingDirectory: $(Agent.TempDirectory)
@@ -62,7 +63,21 @@ jobs:
displayName: Process Binlog into indexable sln
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name)
+ - task: AzureCLI@2
+ displayName: Get stage 1 auth token
+ inputs:
+ azureSubscription: 'SourceDotNet Stage1 Publish'
+ addSpnToEnvironment: true
+ scriptType: 'ps'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ echo "##vso[task.setvariable variable=ARM_CLIENT_ID;issecret=true]$env:servicePrincipalId"
+ echo "##vso[task.setvariable variable=ARM_ID_TOKEN;issecret=true]$env:idToken"
+ echo "##vso[task.setvariable variable=ARM_TENANT_ID;issecret=true]$env:tenantId"
+
+ - script: |
+ az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_ID_TOKEN)
+ displayName: "Login to Azure"
+
+ - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1
displayName: Upload stage1 artifacts to source index
- env:
- BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url)
diff --git a/eng/common/templates-official/jobs/source-build.yml b/eng/common/templates-official/jobs/source-build.yml
index 08e5db9bb1..5cf6a269c0 100644
--- a/eng/common/templates-official/jobs/source-build.yml
+++ b/eng/common/templates-official/jobs/source-build.yml
@@ -21,6 +21,12 @@ parameters:
# one job runs on 'defaultManagedPlatform'.
platforms: []
+ # If set to true and running on a non-public project,
+ # Internal nuget and blob storage locations will be enabled.
+ # This is not enabled by default because many repositories do not need internal sources
+ # and do not need to have the required service connections approved in the pipeline.
+ enableInternalSources: false
+
jobs:
- ${{ if ne(parameters.allCompletedJobId, '') }}:
@@ -38,9 +44,11 @@ jobs:
parameters:
jobNamePrefix: ${{ parameters.jobNamePrefix }}
platform: ${{ platform }}
+ enableInternalSources: ${{ parameters.enableInternalSources }}
- ${{ if eq(length(parameters.platforms), 0) }}:
- template: /eng/common/templates-official/job/source-build.yml
parameters:
jobNamePrefix: ${{ parameters.jobNamePrefix }}
platform: ${{ parameters.defaultManagedPlatform }}
+ enableInternalSources: ${{ parameters.enableInternalSources }}
diff --git a/eng/common/templates-official/post-build/post-build.yml b/eng/common/templates-official/post-build/post-build.yml
index da1f40958b..0dfa387e7b 100644
--- a/eng/common/templates-official/post-build/post-build.yml
+++ b/eng/common/templates-official/post-build/post-build.yml
@@ -272,14 +272,16 @@ stages:
- task: NuGetAuthenticate@1
- - task: PowerShell@2
+ - task: AzureCLI@2
displayName: Publish Using Darc
inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+ azureSubscription: "Darc: Maestro Production"
+ scriptType: ps
+ scriptLocation: scriptPath
+ scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
arguments: -BuildId $(BARBuildId)
-PublishingInfraVersion ${{ parameters.publishingInfraVersion }}
-AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
- -MaestroToken '$(MaestroApiAccessToken)'
-WaitPublishingFinish true
-ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
-SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
diff --git a/eng/common/templates-official/steps/enable-internal-runtimes.yml b/eng/common/templates-official/steps/enable-internal-runtimes.yml
new file mode 100644
index 0000000000..93a8394a66
--- /dev/null
+++ b/eng/common/templates-official/steps/enable-internal-runtimes.yml
@@ -0,0 +1,28 @@
+# Obtains internal runtime download credentials and populates the 'dotnetbuilds-internal-container-read-token-base64'
+# variable with the base64-encoded SAS token, by default
+
+parameters:
+- name: federatedServiceConnection
+ type: string
+ default: 'dotnetbuilds-internal-read'
+- name: outputVariableName
+ type: string
+ default: 'dotnetbuilds-internal-container-read-token-base64'
+- name: expiryInHours
+ type: number
+ default: 1
+- name: base64Encode
+ type: boolean
+ default: true
+
+steps:
+- ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - template: /eng/common/templates-official/steps/get-delegation-sas.yml
+ parameters:
+ federatedServiceConnection: ${{ parameters.federatedServiceConnection }}
+ outputVariableName: ${{ parameters.outputVariableName }}
+ expiryInHours: ${{ parameters.expiryInHours }}
+ base64Encode: ${{ parameters.base64Encode }}
+ storageAccount: dotnetbuilds
+ container: internal
+ permissions: rl
diff --git a/eng/common/templates-official/steps/get-delegation-sas.yml b/eng/common/templates-official/steps/get-delegation-sas.yml
new file mode 100644
index 0000000000..c0e8f91317
--- /dev/null
+++ b/eng/common/templates-official/steps/get-delegation-sas.yml
@@ -0,0 +1,43 @@
+parameters:
+- name: federatedServiceConnection
+ type: string
+- name: outputVariableName
+ type: string
+- name: expiryInHours
+ type: number
+ default: 1
+- name: base64Encode
+ type: boolean
+ default: false
+- name: storageAccount
+ type: string
+- name: container
+ type: string
+- name: permissions
+ type: string
+ default: 'rl'
+
+steps:
+- task: AzureCLI@2
+ displayName: 'Generate delegation SAS Token for ${{ parameters.storageAccount }}/${{ parameters.container }}'
+ inputs:
+ azureSubscription: ${{ parameters.federatedServiceConnection }}
+ scriptType: 'pscore'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ # Calculate the expiration of the SAS token and convert to UTC
+ $expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
+
+ $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error "Failed to generate SAS token."
+ exit 1
+ }
+
+ if ('${{ parameters.base64Encode }}' -eq 'true') {
+ $sas = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($sas))
+ }
+
+ Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value"
+ Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$sas"
diff --git a/eng/common/templates-official/steps/get-federated-access-token.yml b/eng/common/templates-official/steps/get-federated-access-token.yml
new file mode 100644
index 0000000000..e3786cef6d
--- /dev/null
+++ b/eng/common/templates-official/steps/get-federated-access-token.yml
@@ -0,0 +1,28 @@
+parameters:
+- name: federatedServiceConnection
+ type: string
+- name: outputVariableName
+ type: string
+# Resource to get a token for. Common values include:
+# - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps
+# - 'https://storage.azure.com/' for storage
+# Defaults to Azure DevOps
+- name: resource
+ type: string
+ default: '499b84ac-1321-427f-aa17-267ca6975798'
+
+steps:
+- task: AzureCLI@2
+ displayName: 'Getting federated access token for feeds'
+ inputs:
+ azureSubscription: ${{ parameters.federatedServiceConnection }}
+ scriptType: 'pscore'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ $accessToken = az account get-access-token --query accessToken --resource ${{ parameters.resource }} --output tsv
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error "Failed to get access token for resource '${{ parameters.resource }}'"
+ exit 1
+ }
+ Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value"
+ Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$accessToken"
diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml
index 8ec0151def..57a41f0a3e 100644
--- a/eng/common/templates/job/publish-build-assets.yml
+++ b/eng/common/templates/job/publish-build-assets.yml
@@ -74,13 +74,16 @@ jobs:
- task: NuGetAuthenticate@1
- - task: PowerShell@2
+ - task: AzureCLI@2
displayName: Publish Build Assets
inputs:
- filePath: eng\common\sdk-task.ps1
- arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet
+ azureSubscription: "Darc: Maestro Production"
+ scriptType: ps
+ scriptLocation: scriptPath
+ scriptPath: $(Build.SourcesDirectory)/eng/common/sdk-task.ps1
+ arguments: >
+ -task PublishBuildAssets -restore -msbuildEngine dotnet
/p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests'
- /p:BuildAssetRegistryToken=$(MaestroAccessToken)
/p:MaestroApiEndpoint=https://maestro.dot.net
/p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }}
/p:OfficialBuildId=$(Build.BuildNumber)
@@ -133,14 +136,16 @@ jobs:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
- - task: PowerShell@2
+ - task: AzureCLI@2
displayName: Publish Using Darc
inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
- arguments: -BuildId $(BARBuildId)
+ azureSubscription: "Darc: Maestro Production"
+ scriptType: ps
+ scriptLocation: scriptPath
+ scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+ arguments: -BuildId $(BARBuildId)
-PublishingInfraVersion 3
-AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
- -MaestroToken '$(MaestroApiAccessToken)'
-WaitPublishingFinish true
-ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
-SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml
index 8a3deef2b7..c0ff472b69 100644
--- a/eng/common/templates/job/source-build.yml
+++ b/eng/common/templates/job/source-build.yml
@@ -31,6 +31,12 @@ parameters:
# container and pool.
platform: {}
+ # If set to true and running on a non-public project,
+ # Internal blob storage locations will be enabled.
+ # This is not enabled by default because many repositories do not need internal sources
+ # and do not need to have the required service connections approved in the pipeline.
+ enableInternalSources: false
+
jobs:
- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }}
displayName: Source-Build (${{ parameters.platform.name }})
@@ -61,6 +67,8 @@ jobs:
clean: all
steps:
+ - ${{ if eq(parameters.enableInternalSources, true) }}:
+ - template: /eng/common/templates/steps/enable-internal-runtimes.yml
- template: /eng/common/templates/steps/source-build.yml
parameters:
platform: ${{ parameters.platform }}
diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml
index b98202aa02..0b6bb89dc7 100644
--- a/eng/common/templates/job/source-index-stage1.yml
+++ b/eng/common/templates/job/source-index-stage1.yml
@@ -1,6 +1,7 @@
parameters:
runAsPublic: false
- sourceIndexPackageVersion: 1.0.1-20230228.2
+ sourceIndexUploadPackageVersion: 2.0.0-20240502.12
+ sourceIndexProcessBinlogPackageVersion: 1.0.1-20240129.2
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
preSteps: []
@@ -14,14 +15,14 @@ jobs:
dependsOn: ${{ parameters.dependsOn }}
condition: ${{ parameters.condition }}
variables:
- - name: SourceIndexPackageVersion
- value: ${{ parameters.sourceIndexPackageVersion }}
+ - name: SourceIndexUploadPackageVersion
+ value: ${{ parameters.sourceIndexUploadPackageVersion }}
+ - name: SourceIndexProcessBinlogPackageVersion
+ value: ${{ parameters.sourceIndexProcessBinlogPackageVersion }}
- name: SourceIndexPackageSource
value: ${{ parameters.sourceIndexPackageSource }}
- name: BinlogPath
value: ${{ parameters.binlogPath }}
- - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - group: source-dot-net stage1 variables
- template: /eng/common/templates/variables/pool-providers.yml
${{ if ne(parameters.pool, '') }}:
@@ -40,16 +41,16 @@ jobs:
- ${{ preStep }}
- task: UseDotNet@2
- displayName: Use .NET Core SDK 6
+ displayName: Use .NET 8 SDK
inputs:
packageType: sdk
- version: 6.0.x
+ version: 8.0.x
installationPath: $(Agent.TempDirectory)/dotnet
workingDirectory: $(Agent.TempDirectory)
- script: |
- $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
- $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(sourceIndexProcessBinlogPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(sourceIndexUploadPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
displayName: Download Tools
# Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk.
workingDirectory: $(Agent.TempDirectory)
@@ -61,7 +62,21 @@ jobs:
displayName: Process Binlog into indexable sln
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name)
+ - task: AzureCLI@2
+ displayName: Get stage 1 auth token
+ inputs:
+ azureSubscription: 'SourceDotNet Stage1 Publish'
+ addSpnToEnvironment: true
+ scriptType: 'ps'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ echo "##vso[task.setvariable variable=ARM_CLIENT_ID;issecret=true]$env:servicePrincipalId"
+ echo "##vso[task.setvariable variable=ARM_ID_TOKEN;issecret=true]$env:idToken"
+ echo "##vso[task.setvariable variable=ARM_TENANT_ID;issecret=true]$env:tenantId"
+
+ - script: |
+ az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_ID_TOKEN)
+ displayName: "Login to Azure"
+
+ - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1
displayName: Upload stage1 artifacts to source index
- env:
- BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url)
diff --git a/eng/common/templates/jobs/source-build.yml b/eng/common/templates/jobs/source-build.yml
index a15b07eb51..5f46bfa895 100644
--- a/eng/common/templates/jobs/source-build.yml
+++ b/eng/common/templates/jobs/source-build.yml
@@ -21,6 +21,12 @@ parameters:
# one job runs on 'defaultManagedPlatform'.
platforms: []
+ # If set to true and running on a non-public project,
+ # Internal nuget and blob storage locations will be enabled.
+ # This is not enabled by default because many repositories do not need internal sources
+ # and do not need to have the required service connections approved in the pipeline.
+ enableInternalSources: false
+
jobs:
- ${{ if ne(parameters.allCompletedJobId, '') }}:
@@ -38,9 +44,11 @@ jobs:
parameters:
jobNamePrefix: ${{ parameters.jobNamePrefix }}
platform: ${{ platform }}
+ enableInternalSources: ${{ parameters.enableInternalSources }}
- ${{ if eq(length(parameters.platforms), 0) }}:
- template: /eng/common/templates/job/source-build.yml
parameters:
jobNamePrefix: ${{ parameters.jobNamePrefix }}
platform: ${{ parameters.defaultManagedPlatform }}
+ enableInternalSources: ${{ parameters.enableInternalSources }}
diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml
index aba44a25a3..2db4933468 100644
--- a/eng/common/templates/post-build/post-build.yml
+++ b/eng/common/templates/post-build/post-build.yml
@@ -268,14 +268,16 @@ stages:
- task: NuGetAuthenticate@1
- - task: PowerShell@2
+ - task: AzureCLI@2
displayName: Publish Using Darc
inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+ azureSubscription: "Darc: Maestro Production"
+ scriptType: ps
+ scriptLocation: scriptPath
+ scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
arguments: -BuildId $(BARBuildId)
-PublishingInfraVersion ${{ parameters.publishingInfraVersion }}
-AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
- -MaestroToken '$(MaestroApiAccessToken)'
-WaitPublishingFinish true
-ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
-SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml
index 0c87f149a4..64b9abc685 100644
--- a/eng/common/templates/post-build/setup-maestro-vars.yml
+++ b/eng/common/templates/post-build/setup-maestro-vars.yml
@@ -11,13 +11,14 @@ steps:
artifactName: ReleaseConfigs
checkDownloadedFiles: true
- - task: PowerShell@2
+ - task: AzureCLI@2
name: setReleaseVars
displayName: Set Release Configs Vars
inputs:
- targetType: inline
- pwsh: true
- script: |
+ azureSubscription: "Darc: Maestro Production"
+ scriptType: pscore
+ scriptLocation: inlineScript
+ inlineScript: |
try {
if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') {
$Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt
@@ -31,15 +32,16 @@ steps:
$AzureDevOpsBuildId = $Env:Build_BuildId
}
else {
- $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}"
+ . $(Build.SourcesDirectory)\eng\common\tools.ps1
+ $darc = Get-Darc
+ $buildInfo = & $darc get-build `
+ --id ${{ parameters.BARBuildId }} `
+ --extended `
+ --output-format json `
+ --ci `
+ | convertFrom-Json
- $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
- $apiHeaders.Add('Accept', 'application/json')
- $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}")
-
- $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" }
-
- $BarId = $Env:BARBuildId
+ $BarId = ${{ parameters.BARBuildId }}
$Channels = $Env:PromoteToMaestroChannels -split ","
$Channels = $Channels -join "]["
$Channels = "[$Channels]"
@@ -65,6 +67,4 @@ steps:
exit 1
}
env:
- MAESTRO_API_TOKEN: $(MaestroApiAccessToken)
- BARBuildId: ${{ parameters.BARBuildId }}
PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }}
diff --git a/eng/common/templates/steps/enable-internal-runtimes.yml b/eng/common/templates/steps/enable-internal-runtimes.yml
new file mode 100644
index 0000000000..54dc9416c5
--- /dev/null
+++ b/eng/common/templates/steps/enable-internal-runtimes.yml
@@ -0,0 +1,28 @@
+# Obtains internal runtime download credentials and populates the 'dotnetbuilds-internal-container-read-token-base64'
+# variable with the base64-encoded SAS token, by default
+
+parameters:
+- name: federatedServiceConnection
+ type: string
+ default: 'dotnetbuilds-internal-read'
+- name: outputVariableName
+ type: string
+ default: 'dotnetbuilds-internal-container-read-token-base64'
+- name: expiryInHours
+ type: number
+ default: 1
+- name: base64Encode
+ type: boolean
+ default: true
+
+steps:
+- ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - template: /eng/common/templates/steps/get-delegation-sas.yml
+ parameters:
+ federatedServiceConnection: ${{ parameters.federatedServiceConnection }}
+ outputVariableName: ${{ parameters.outputVariableName }}
+ expiryInHours: ${{ parameters.expiryInHours }}
+ base64Encode: ${{ parameters.base64Encode }}
+ storageAccount: dotnetbuilds
+ container: internal
+ permissions: rl
diff --git a/eng/common/templates/steps/get-delegation-sas.yml b/eng/common/templates/steps/get-delegation-sas.yml
new file mode 100644
index 0000000000..c0e8f91317
--- /dev/null
+++ b/eng/common/templates/steps/get-delegation-sas.yml
@@ -0,0 +1,43 @@
+parameters:
+- name: federatedServiceConnection
+ type: string
+- name: outputVariableName
+ type: string
+- name: expiryInHours
+ type: number
+ default: 1
+- name: base64Encode
+ type: boolean
+ default: false
+- name: storageAccount
+ type: string
+- name: container
+ type: string
+- name: permissions
+ type: string
+ default: 'rl'
+
+steps:
+- task: AzureCLI@2
+ displayName: 'Generate delegation SAS Token for ${{ parameters.storageAccount }}/${{ parameters.container }}'
+ inputs:
+ azureSubscription: ${{ parameters.federatedServiceConnection }}
+ scriptType: 'pscore'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ # Calculate the expiration of the SAS token and convert to UTC
+ $expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
+
+ $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error "Failed to generate SAS token."
+ exit 1
+ }
+
+ if ('${{ parameters.base64Encode }}' -eq 'true') {
+ $sas = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($sas))
+ }
+
+ Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value"
+ Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$sas"
diff --git a/eng/common/templates/steps/get-federated-access-token.yml b/eng/common/templates/steps/get-federated-access-token.yml
new file mode 100644
index 0000000000..c8c49cc0e8
--- /dev/null
+++ b/eng/common/templates/steps/get-federated-access-token.yml
@@ -0,0 +1,28 @@
+parameters:
+- name: federatedServiceConnection
+ type: string
+- name: outputVariableName
+ type: string
+# Resource to get a token for. Common values include:
+# - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps
+# - 'https://storage.azure.com/' for storage
+# Defaults to Azure DevOps
+- name: resource
+ type: string
+ default: '499b84ac-1321-427f-aa17-267ca6975798'
+
+steps:
+- task: AzureCLI@2
+ displayName: 'Getting federated access token for feeds'
+ inputs:
+ azureSubscription: ${{ parameters.federatedServiceConnection }}
+ scriptType: 'pscore'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ $accessToken = az account get-access-token --query accessToken --resource ${{ parameters.resource }} --output tsv
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error "Failed to get access token for resource '${{ parameters.resource }}'"
+ exit 1
+ }
+ Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value"
+ Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$accessToken"
\ No newline at end of file
diff --git a/eng/generate-changelog-release.ps1 b/eng/generate-changelog-release.ps1
new file mode 100644
index 0000000000..4c4ab0a3eb
--- /dev/null
+++ b/eng/generate-changelog-release.ps1
@@ -0,0 +1,183 @@
+<#
+.SYNOPSIS
+ Create release notes link and changelog entries for MSTest and Testing Platform.
+
+.EXAMPLE
+ Assuming you are on branch rel/3.4 and you want to create the release notes, run
+ .\write-release-notes -MSTestVersion 3.4.0 -PlatformVersion 1.2.0
+ it will create release notes between last commit of current branch and last release
+#>
+
+[CmdletBinding()]
+param
+(
+ [Parameter(Mandatory=$true)]
+ [ValidatePattern("^\d+\.\d+\.\d+(-preview-\d{8}-\d{2})?$")][string] $MSTestVersion,
+ [Parameter(Mandatory=$true)]
+ [ValidatePattern("^\d+\.\d+\.\d+(-preview-\d{8}-\d{2})?$")][string] $PlatformVersion
+)
+
+$Path = "."
+$repoUrl = $(if ((git -C $Path remote -v) -match "upstream") {
+ git -C $Path remote get-url --push upstream
+ }
+ else {
+ git -C $Path remote get-url --push origin
+ }) -replace "\.git$"
+
+# list all tags on this branch ordered by creator date to get the latest, stable or pre-release tag.
+# For stable release we choose only tags without any dash, for pre-release we choose all tags.
+$tags = git -C $Path tag -l --sort=refname | Where-Object { $_ -match "v\d+\.\d+\.\d+.*" -and (-not $Stable -or $_ -notlike '*-*') }
+
+if ([string]::IsNullOrWhiteSpace($MSTestVersion)) {
+ # normally we show changes between the latest two tags
+ $start, $end = $tags | Select-Object -Last 2
+ Write-Host "$start -- $end"
+ $tag = $end
+}
+else {
+ # in CI we don't have the tag yet, so we show changes between the most recent tag, and this commit
+ # we figure out the tag from the package version that is set by vsts-prebuild
+ $start = $tags | Select-Object -Last 1
+ $end = git -C $Path rev-parse HEAD
+ $tag = "v$MSTestVersion"
+}
+
+# # override the tags to use if you need
+# $start = "v16.8.0-preview-20200812-03"
+# $end = $tag = "v16.8.0-preview-20200921-01"
+
+Write-Host "Generating release notes for $start..$end$(if ($HasPackageVersion) { " (expected tag: $tag)" })"
+
+$sourceBranch = $branch = git -C $Path rev-parse --abbrev-ref HEAD
+if ($sourceBranch -eq "HEAD") {
+ # when CI checks out just the single commit, https://docs.microsoft.com/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml
+ $sourceBranch = $env:BUILD_SOURCEBRANCH -replace "^refs/heads/"
+}
+
+if ([string]::IsNullOrWhiteSpace($branch)) {
+ throw "Branch is null or empty!"
+}
+
+if ([string]::IsNullOrWhiteSpace($sourceBranch)) {
+ throw "SourceBranch is null or empty!"
+}
+
+Write-Host "Branch is $branch"
+Write-Host "SourceBranch is $sourceBranch"
+
+$discard = @(
+ "^Update dependencies from https:\/\/",
+ "^\[.+\] Update dependencies from",
+ "^LEGO: Pull request from lego",
+ "^Localized file check-in by OneLocBuild Task:",
+ "^Juno: check in to lego"
+) -join "|"
+
+$prUrl = "$repoUrl/pull/"
+# $tagVersionNumber = $tag -replace '^v'
+# using .. because I want to know the changes that are on this branch, but don't care about the changes that I don't have https://stackoverflow.com/a/24186641/3065397
+$log = (git -C $Path log "$start..$end" --oneline --pretty="format:%s" --first-parent)
+$issues = $log | ForEach-Object {
+ if ($_ -notmatch $discard) {
+ if ($_ -match '^(?.+)\s\(#(?\d+)\)?$') {
+ $message = "* $($matches.message)"
+ if ($matches.pr) {
+ $pr = $matches.pr
+ $message += " [#$pr]($prUrl$pr)"
+ }
+
+ if ($_ -like 'fix *') {
+ [pscustomobject]@{ category = "fix"; text = $message }
+ } elseif ($_ -like 'add *') {
+ [pscustomobject]@{ category = "add"; text = $message }
+ } else {
+ [pscustomobject]@{ category = "unknown"; text = "* $_" }
+ }
+ }
+ else {
+ [pscustomobject]@{ category = "unknown"; text = "* $_" }
+ }
+ }
+} | Group-Object -Property category -AsHashTable
+$date = Get-Date -Format "yyyy-MM-dd"
+$output = @"
+-------------------------------
+MSTest Version: $MSTestVersion
+-------------------------------
+
+See the release notes [here](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md#$MSTestVersion).
+
+-------------------------------
+
+## [$MSTestVersion] - $date
+
+See full log [here]($repoUrl/compare/$start...$tag)
+
+### Added
+
+$($issues.add.text -join "`n")
+
+### Fixed
+
+$($issues.fix.text -join "`n")
+
+### TO CLASSIFY
+
+$($issues.unknown.text -join "`n")
+
+### Artifacts
+
+* MSTest: [$MSTestVersion](https://www.nuget.org/packages/MSTest/$MSTestVersion)
+* MSTest.TestFramework: [$MSTestVersion](https://www.nuget.org/packages/MSTest.TestFramework/$MSTestVersion)
+* MSTest.TestAdapter: [$MSTestVersion](https://www.nuget.org/packages/MSTest.TestAdapter/$MSTestVersion)
+* MSTest.Analyzers: [$MSTestVersion](https://www.nuget.org/packages/MSTest.Analyzers/$MSTestVersion)
+* MSTest.Sdk: [$MSTestVersion](https://www.nuget.org/packages/MSTest.Sdk/$MSTestVersion)
+* Microsoft.Testing.Extensions.CrashDump: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/$PlatformVersion)
+* Microsoft.Testing.Extensions.HangDump: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/$PlatformVersion)
+* Microsoft.Testing.Extensions.HotReload: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/$PlatformVersion)
+* Microsoft.Testing.Extensions.Retry: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/$PlatformVersion)
+* Microsoft.Testing.Extensions.TrxReport: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/$PlatformVersion)
+
+-------------------------------
+Testing Platform Version: $PlatformVersion
+-------------------------------
+
+See the release notes [here](https://github.com/microsoft/testfx/blob/main/docs/Changelog-TestingPlatform.md#$PlatformVersion).
+
+-------------------------------
+
+## [$PlatformVersion] - $date
+
+See full log [here]($repoUrl/compare/$start...$tag)
+
+### Added
+
+$($issues.add.text -join "`n")
+
+### Fixed
+
+$($issues.fix.text -join "`n")
+
+### TO CLASSIFY
+
+$($issues.unknown.text -join "`n")
+
+### Artifacts
+
+
+* Microsoft.Testing.Extensions.CrashDump: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump/$PlatformVersion)
+* Microsoft.Testing.Extensions.HangDump: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump/$PlatformVersion)
+* Microsoft.Testing.Extensions.HotReload: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload/$PlatformVersion)
+* Microsoft.Testing.Extensions.Retry: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry/$PlatformVersion)
+* Microsoft.Testing.Extensions.Telemetry: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Telemetry/$PlatformVersion)
+* Microsoft.Testing.Extensions.TrxReport: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport/$PlatformVersion)
+* Microsoft.Testing.Extensions.TrxReport.Abstractions: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport.Abstractions/$PlatformVersion)
+* Microsoft.Testing.Extensions.VSTestBridge: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Extensions.VSTestBridge/$PlatformVersion)
+* Microsoft.Testing.Platform: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Platform/$PlatformVersion)
+* Microsoft.Testing.Platform.MSBuild: [$PlatformVersion](https://www.nuget.org/packages/Microsoft.Testing.Platform.MSBuild/$PlatformVersion)
+
+"@
+
+$output
+$output | clip
diff --git a/eng/install-procdump.ps1 b/eng/install-procdump.ps1
new file mode 100644
index 0000000000..f3d5164022
--- /dev/null
+++ b/eng/install-procdump.ps1
@@ -0,0 +1,99 @@
+param(
+ [switch]$Force
+)
+
+function Download {
+ <#
+ .SYNOPSIS
+ Downloads a given uri and saves it to outputFile
+ .DESCRIPTION
+ Downloads a given uri and saves it to outputFile
+ PARAMETER uri
+ The uri to fetch
+.PARAMETER outputFile
+ The outputh file path to save the uri
+#>
+ param(
+ [Parameter(Mandatory = $true)]
+ $uri,
+
+ [Parameter(Mandatory = $true)]
+ $outputFile
+ )
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+ $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit
+
+ $maxRetries = 5
+ $retries = 1
+
+ while ($true) {
+ try {
+ Write-Host "GET $uri"
+ Invoke-WebRequest $uri -OutFile $outputFile
+ break
+ }
+ catch {
+ Write-Host "Failed to download '$uri'"
+ $error = $_.Exception.Message
+ }
+
+ if (++$retries -le $maxRetries) {
+ Write-Warning $error -ErrorAction Continue
+ $delayInSeconds = [math]::Pow(2, $retries) - 1 # Exponential backoff
+ Write-Host "Retrying. Waiting for $delayInSeconds seconds before next attempt ($retries of $maxRetries)."
+ Start-Sleep -Seconds $delayInSeconds
+ }
+ else {
+ Write-Error $error -ErrorAction Continue
+ throw "Unable to download file in $maxRetries attempts."
+ }
+ }
+
+ Write-Host "Download of '$uri' complete, saved to $outputFile..."
+
+}
+
+function Install-Procdump {
+ <#
+.SYNOPSIS
+ Installs ProcDump into a folder in this repo.
+.DESCRIPTION
+ This script downloads and extracts the ProcDump.
+.PARAMETER Force
+ Overwrite the existing installation
+#>
+ param(
+ [switch]$Force
+ )
+ $ErrorActionPreference = 'Stop'
+ $ProgressPreference = 'SilentlyContinue' # Workaround PowerShell/PowerShell#2138
+
+ Set-StrictMode -Version 1
+
+ $repoRoot = Resolve-Path "$PSScriptRoot\..\.."
+ $installDir = "$repoRoot\.tools\ProcDump\"
+
+ if (Test-Path "$installDir\procdump.exe") {
+ if ($Force) {
+ Remove-Item -Force -Recurse $installDir
+ }
+ else {
+ Write-Host "ProcDump already installed to $installDir. Exiting without action. Call this script again with -Force to overwrite."
+ exit 0
+ }
+ }
+
+ mkdir $installDir -ea Ignore | out-null
+ Write-Host "Starting ProcDump download"
+ Download "https://download.sysinternals.com/files/Procdump.zip" "$installDir/ProcDump.zip"
+ Write-Host "Done downloading ProcDump"
+ Expand-Archive "$installDir/ProcDump.zip" -d "$installDir"
+ Write-Host "Expanded ProcDump to $installDir"
+
+ if ($env:TF_BUILD) {
+ Write-Host "##vso[task.setvariable variable=PROCDUMP_PATH]$installDir"
+ Write-Host "##vso[task.prependpath]$installDir"
+ }
+}
+
+Install-Procdump -Force:$Force
\ No newline at end of file
diff --git a/eng/write-release-notes.ps1 b/eng/write-release-notes.ps1
deleted file mode 100644
index 9486f7723c..0000000000
--- a/eng/write-release-notes.ps1
+++ /dev/null
@@ -1,120 +0,0 @@
-<#
-.SYNOPSIS
- Create release notes for current project using either last commit to last tag or between last 2 tags.
-
-.EXAMPLE
- Assuming you are on branch rel/17.4 and you want to create the release notes, run
- .\write-release-notes -PackageVersion 17.4.0
- it will create release notes between last commit of current branch and last release
-
- If you want to generate the release notes between 2 tags, use simply
- .\write-release-notes
-#>
-
-[CmdletBinding()]
-param
-(
- [string] $Path = ".",
- [ValidatePattern("^\d+\.\d+\.\d+(-preview-\d{8}-\d{2})?$")][string] $PackageVersion
-)
-
-$repoUrl = $(if ((git -C $Path remote -v) -match "upstream") {
- git -C $Path remote get-url --push upstream
- }
- else {
- git -C $Path remote get-url --push origin
- }) -replace "\.git$"
-
-# list all tags on this branch ordered by creator date to get the latest, stable or pre-release tag.
-# For stable release we choose only tags without any dash, for pre-release we choose all tags.
-$tags = git -C $Path tag -l --sort=refname | Where-Object { $_ -match "v\d+\.\d+\.\d+.*" -and (-not $Stable -or $_ -notlike '*-*') }
-
-if ([string]::IsNullOrWhiteSpace($PackageVersion)) {
- # normally we show changes between the latest two tags
- $start, $end = $tags | Select-Object -Last 2
- Write-Host "$start -- $end"
- $tag = $end
-}
-else {
- # in CI we don't have the tag yet, so we show changes between the most recent tag, and this commit
- # we figure out the tag from the package version that is set by vsts-prebuild
- $start = $tags | Select-Object -Last 1
- $end = git -C $Path rev-parse HEAD
- $tag = "v$PackageVersion"
-}
-
-# # override the tags to use if you need
-# $start = "v16.8.0-preview-20200812-03"
-# $end = $tag = "v16.8.0-preview-20200921-01"
-
-Write-Host "Generating release notes for $start..$end$(if ($HasPackageVersion) { " (expected tag: $tag)" })"
-
-$sourceBranch = $branch = git -C $Path rev-parse --abbrev-ref HEAD
-if ($sourceBranch -eq "HEAD") {
- # when CI checks out just the single commit, https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml
- $sourceBranch = $env:BUILD_SOURCEBRANCH -replace "^refs/heads/"
-}
-
-if ([string]::IsNullOrWhiteSpace($branch)) {
- throw "Branch is null or empty!"
-}
-
-if ([string]::IsNullOrWhiteSpace($sourceBranch)) {
- throw "SourceBranch is null or empty!"
-}
-
-Write-Host "Branch is $branch"
-Write-Host "SourceBranch is $sourceBranch"
-
-$discard = @(
- "^Update dependencies from https:\/\/",
- "^\[.+\] Update dependencies from",
- "^LEGO: Pull request from lego",
- "^Localized file check-in by OneLocBuild Task:",
- "^Juno: check in to lego"
-) -join "|"
-
-$prUrl = "$repoUrl/pull/"
-$tagVersionNumber = $tag -replace '^v'
-# using .. because I want to know the changes that are on this branch, but don't care about the changes that I don't have https://stackoverflow.com/a/24186641/3065397
-$log = (git -C $Path log "$start..$end" --oneline --pretty="format:%s" --first-parent)
-$date = ([datetime](git -C $path log -1 --format=%ai $end)).ToString("MMMM yyyy")
-$issues = $log | ForEach-Object {
- if ($_ -notmatch $discard) {
- if ($_ -match '^(?.+)\s\(#(?\d+)\)?$') {
- $message = "* $($matches.message)"
- if ($matches.pr) {
- $pr = $matches.pr
- $message += " [#$pr]($prUrl$pr)"
- }
-
- $message
- }
- else {
- "* $_"
- }
- }
-}
-
-$output = @"
-
-See the release notes [here](https://github.com/microsoft/testfx/blob/main/docs/releases.md#$(("$tagVersionNumber $date" -replace "\.", "" -replace "\W", "-").ToLowerInvariant())).
-
--------------------------------
-
-## $tagVersionNumber ($date)
-
-$($issues -join "`n")
-
-See full log [here]($repoUrl/compare/$start...$tag)
-
-### Artifacts
-
-* MSTest: [$tagVersionNumber](https://www.nuget.org/packages/MSTest/$tagVersionNumber)
-* MSTest.TestFramework: [$tagVersionNumber](https://www.nuget.org/packages/MSTest.TestFramework/$tagVersionNumber)
-* MSTest.TestAdapter: [$tagVersionNumber](https://www.nuget.org/packages/MSTest.TestAdapter/$tagVersionNumber)
-
-"@
-
-$output
-$output | clip
diff --git a/global.json b/global.json
index 7d17fddb6b..8ebaf21ce6 100644
--- a/global.json
+++ b/global.json
@@ -4,9 +4,9 @@
"runtimes": {
"dotnet": [
"3.1.32",
- "6.0.29",
- "7.0.18",
- "8.0.4"
+ "6.0.32",
+ "7.0.20",
+ "8.0.7"
]
},
"vs": {
@@ -19,7 +19,7 @@
"rollForward": "latestFeature"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24225.1",
+ "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24360.5",
"MSBuild.Sdk.Extras": "3.0.44"
}
}
diff --git a/samples/DemoMSTestSdk/Directory.Build.props b/samples/DemoMSTestSdk/Directory.Build.props
deleted file mode 100644
index 8c119d5413..0000000000
--- a/samples/DemoMSTestSdk/Directory.Build.props
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/samples/DemoMSTestSdk/ProjectUsingMSTestRunner/Usings.cs b/samples/DemoMSTestSdk/ProjectUsingMSTestRunner/Usings.cs
deleted file mode 100644
index af4ead20be..0000000000
--- a/samples/DemoMSTestSdk/ProjectUsingMSTestRunner/Usings.cs
+++ /dev/null
@@ -1,4 +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.
-
-global using Microsoft.VisualStudio.TestTools.UnitTesting;
\ No newline at end of file
diff --git a/samples/DemoMSTestSdk/ProjectUsingVSTest/Usings.cs b/samples/DemoMSTestSdk/ProjectUsingVSTest/Usings.cs
deleted file mode 100644
index af4ead20be..0000000000
--- a/samples/DemoMSTestSdk/ProjectUsingVSTest/Usings.cs
+++ /dev/null
@@ -1,4 +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.
-
-global using Microsoft.VisualStudio.TestTools.UnitTesting;
\ No newline at end of file
diff --git a/samples/DemoMSTestSdk/ProjectWithNativeAOT/Usings.cs b/samples/DemoMSTestSdk/ProjectWithNativeAOT/Usings.cs
deleted file mode 100644
index af4ead20be..0000000000
--- a/samples/DemoMSTestSdk/ProjectWithNativeAOT/Usings.cs
+++ /dev/null
@@ -1,4 +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.
-
-global using Microsoft.VisualStudio.TestTools.UnitTesting;
\ No newline at end of file
diff --git a/samples/Playground/Playground.csproj b/samples/Playground/Playground.csproj
index 81fcb3d44e..57236d10af 100644
--- a/samples/Playground/Playground.csproj
+++ b/samples/Playground/Playground.csproj
@@ -1,4 +1,4 @@
-
+Exe
@@ -16,7 +16,6 @@
-
diff --git a/samples/Playground/Program.cs b/samples/Playground/Program.cs
index a29b811b5e..1a5cf88f8a 100644
--- a/samples/Playground/Program.cs
+++ b/samples/Playground/Program.cs
@@ -16,7 +16,7 @@ public static async Task Main(string[] args)
Environment.SetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT", "1");
ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args);
- testApplicationBuilder.AddMSTest(() => new[] { Assembly.GetEntryAssembly()! });
+ testApplicationBuilder.AddMSTest(() => [Assembly.GetEntryAssembly()!]);
// Enable Trx
// testApplicationBuilder.AddTrxReportProvider();
diff --git a/samples/mstest-runner/Directory.Build.props b/samples/mstest-runner/Directory.Build.props
deleted file mode 100644
index 8c119d5413..0000000000
--- a/samples/mstest-runner/Directory.Build.props
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/samples/mstest-runner/Directory.Build.targets b/samples/mstest-runner/Directory.Build.targets
deleted file mode 100644
index 8c119d5413..0000000000
--- a/samples/mstest-runner/Directory.Build.targets
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/samples/mstest-runner/Directory.Packages.props b/samples/mstest-runner/Directory.Packages.props
deleted file mode 100644
index 36a2328785..0000000000
--- a/samples/mstest-runner/Directory.Packages.props
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- false
-
-
diff --git a/samples/mstest-runner/NuGet.config b/samples/mstest-runner/NuGet.config
deleted file mode 100644
index 20182a5787..0000000000
--- a/samples/mstest-runner/NuGet.config
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/samples/DemoMSTestSdk/DemoMSTestSdk.sln b/samples/public/DemoMSTestSdk/DemoMSTestSdk.sln
similarity index 64%
rename from samples/DemoMSTestSdk/DemoMSTestSdk.sln
rename to samples/public/DemoMSTestSdk/DemoMSTestSdk.sln
index 7569e194de..34e4049f55 100644
--- a/samples/DemoMSTestSdk/DemoMSTestSdk.sln
+++ b/samples/public/DemoMSTestSdk/DemoMSTestSdk.sln
@@ -3,11 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.34807.42
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectUsingVSTest", "ProjectUsingVSTest\ProjectUsingVSTest.csproj", "{0360A072-0ED6-4A27-9AE5-3C6DD055733E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectUsingVSTest", "ProjectUsingVSTest\ProjectUsingVSTest.csproj", "{0360A072-0ED6-4A27-9AE5-3C6DD055733E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectUsingMSTestRunner", "ProjectUsingMSTestRunner\ProjectUsingMSTestRunner.csproj", "{8DA3F43B-938F-4A1E-BE58-B7F80386187F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectUsingMSTestRunner", "ProjectUsingMSTestRunner\ProjectUsingMSTestRunner.csproj", "{8DA3F43B-938F-4A1E-BE58-B7F80386187F}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectWithNativeAOT", "ProjectWithNativeAOT\ProjectWithNativeAOT.csproj", "{9EA03738-C4AA-4CD7-BF71-BA8E689522D7}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectWithNativeAOT", "ProjectWithNativeAOT\ProjectWithNativeAOT.csproj", "{9EA03738-C4AA-4CD7-BF71-BA8E689522D7}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectUsingPlaywright", "ProjectUsingPlaywright\ProjectUsingPlaywright.csproj", "{D047E30F-BEC1-496A-A84B-D27E0966F7DD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectUsingAspire", "ProjectUsingAspire\ProjectUsingAspire.csproj", "{274001A3-B33E-4235-92D4-1A8F39595F5F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -27,6 +31,14 @@ Global
{9EA03738-C4AA-4CD7-BF71-BA8E689522D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9EA03738-C4AA-4CD7-BF71-BA8E689522D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9EA03738-C4AA-4CD7-BF71-BA8E689522D7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D047E30F-BEC1-496A-A84B-D27E0966F7DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D047E30F-BEC1-496A-A84B-D27E0966F7DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D047E30F-BEC1-496A-A84B-D27E0966F7DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D047E30F-BEC1-496A-A84B-D27E0966F7DD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {274001A3-B33E-4235-92D4-1A8F39595F5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {274001A3-B33E-4235-92D4-1A8F39595F5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {274001A3-B33E-4235-92D4-1A8F39595F5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {274001A3-B33E-4235-92D4-1A8F39595F5F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/samples/public/DemoMSTestSdk/ProjectUsingAspire/IntegrationTest1.cs b/samples/public/DemoMSTestSdk/ProjectUsingAspire/IntegrationTest1.cs
new file mode 100644
index 0000000000..ebe1d15e63
--- /dev/null
+++ b/samples/public/DemoMSTestSdk/ProjectUsingAspire/IntegrationTest1.cs
@@ -0,0 +1,30 @@
+namespace Aspire.Tests1;
+
+[TestClass]
+public class IntegrationTest1
+{
+ // Instructions:
+ // 1. Add a project reference to the target AppHost project, e.g.:
+ //
+ //
+ //
+ //
+ //
+ // 2. Uncomment the following example test and update 'Projects.MyAspireApp_AppHost' to match your AppHost project:
+ //
+ // [TestMethod]
+ // public async Task GetWebResourceRootReturnsOkStatusCode()
+ // {
+ // // Arrange
+ // var appHost = await DistributedApplicationTestingBuilder.CreateAsync();
+ // await using var app = await appHost.BuildAsync();
+ // await app.StartAsync();
+
+ // // Act
+ // var httpClient = app.CreateHttpClient("webfrontend");
+ // var response = await httpClient.GetAsync("/");
+
+ // // Assert
+ // Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ // }
+}
diff --git a/samples/public/DemoMSTestSdk/ProjectUsingAspire/ProjectUsingAspire.csproj b/samples/public/DemoMSTestSdk/ProjectUsingAspire/ProjectUsingAspire.csproj
new file mode 100644
index 0000000000..37f2cb0dab
--- /dev/null
+++ b/samples/public/DemoMSTestSdk/ProjectUsingAspire/ProjectUsingAspire.csproj
@@ -0,0 +1,44 @@
+
+
+
+ net8.0
+ enable
+ enable
+ false
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/DemoMSTestSdk/ProjectUsingMSTestRunner/ProjectUsingMSTestRunner.csproj b/samples/public/DemoMSTestSdk/ProjectUsingMSTestRunner/ProjectUsingMSTestRunner.csproj
similarity index 65%
rename from samples/DemoMSTestSdk/ProjectUsingMSTestRunner/ProjectUsingMSTestRunner.csproj
rename to samples/public/DemoMSTestSdk/ProjectUsingMSTestRunner/ProjectUsingMSTestRunner.csproj
index cf3755359b..18c4574c0d 100644
--- a/samples/DemoMSTestSdk/ProjectUsingMSTestRunner/ProjectUsingMSTestRunner.csproj
+++ b/samples/public/DemoMSTestSdk/ProjectUsingMSTestRunner/ProjectUsingMSTestRunner.csproj
@@ -1,7 +1,7 @@
-
+
@@ -30,12 +30,16 @@ Below is the equivalent project configuration when not using MSTest.Sdk
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DemoMSTestSdk/ProjectUsingMSTestRunner/UnitTest1.cs b/samples/public/DemoMSTestSdk/ProjectUsingMSTestRunner/UnitTest1.cs
similarity index 100%
rename from samples/DemoMSTestSdk/ProjectUsingMSTestRunner/UnitTest1.cs
rename to samples/public/DemoMSTestSdk/ProjectUsingMSTestRunner/UnitTest1.cs
diff --git a/samples/public/DemoMSTestSdk/ProjectUsingPlaywright/ProjectUsingPlaywright.csproj b/samples/public/DemoMSTestSdk/ProjectUsingPlaywright/ProjectUsingPlaywright.csproj
new file mode 100644
index 0000000000..0f40510be0
--- /dev/null
+++ b/samples/public/DemoMSTestSdk/ProjectUsingPlaywright/ProjectUsingPlaywright.csproj
@@ -0,0 +1,45 @@
+
+
+
+ net8.0
+ enable
+ enable
+ false
+
+ true
+
+
+
+
+
+
diff --git a/samples/public/DemoMSTestSdk/ProjectUsingPlaywright/UnitTest1.cs b/samples/public/DemoMSTestSdk/ProjectUsingPlaywright/UnitTest1.cs
new file mode 100644
index 0000000000..8fc7eb00e1
--- /dev/null
+++ b/samples/public/DemoMSTestSdk/ProjectUsingPlaywright/UnitTest1.cs
@@ -0,0 +1,33 @@
+// 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.RegularExpressions;
+
+using Microsoft.Playwright;
+
+namespace ProjectUsingPlaywright;
+
+[TestClass]
+public class UnitTest1 : PageTest
+{
+ [TestMethod]
+ public async Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingToTheIntroPage()
+ {
+ await Page.GotoAsync("https://playwright.dev");
+
+ // Expect a title "to contain" a substring.
+ await Expect(Page).ToHaveTitleAsync(new Regex("Playwright"));
+
+ // create a locator
+ ILocator getStarted = Page.Locator("text=Get Started");
+
+ // Expect an attribute "to be strictly equal" to the value.
+ await Expect(getStarted).ToHaveAttributeAsync("href", "/docs/intro");
+
+ // Click the get started link.
+ await getStarted.ClickAsync();
+
+ // Expects the URL to contain intro.
+ await Expect(Page).ToHaveURLAsync(new Regex(".*intro"));
+ }
+}
diff --git a/samples/DemoMSTestSdk/ProjectUsingVSTest/ProjectUsingVSTest.csproj b/samples/public/DemoMSTestSdk/ProjectUsingVSTest/ProjectUsingVSTest.csproj
similarity index 54%
rename from samples/DemoMSTestSdk/ProjectUsingVSTest/ProjectUsingVSTest.csproj
rename to samples/public/DemoMSTestSdk/ProjectUsingVSTest/ProjectUsingVSTest.csproj
index 4d54735e5f..4b91c6c917 100644
--- a/samples/DemoMSTestSdk/ProjectUsingVSTest/ProjectUsingVSTest.csproj
+++ b/samples/public/DemoMSTestSdk/ProjectUsingVSTest/ProjectUsingVSTest.csproj
@@ -1,7 +1,7 @@
-
+
@@ -29,7 +29,16 @@ Below is the equivalent project configuration when not using MSTest.Sdk
-
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DemoMSTestSdk/ProjectUsingVSTest/UnitTest1.cs b/samples/public/DemoMSTestSdk/ProjectUsingVSTest/UnitTest1.cs
similarity index 100%
rename from samples/DemoMSTestSdk/ProjectUsingVSTest/UnitTest1.cs
rename to samples/public/DemoMSTestSdk/ProjectUsingVSTest/UnitTest1.cs
diff --git a/samples/DemoMSTestSdk/ProjectWithNativeAOT/ProjectWithNativeAOT.csproj b/samples/public/DemoMSTestSdk/ProjectWithNativeAOT/ProjectWithNativeAOT.csproj
similarity index 66%
rename from samples/DemoMSTestSdk/ProjectWithNativeAOT/ProjectWithNativeAOT.csproj
rename to samples/public/DemoMSTestSdk/ProjectWithNativeAOT/ProjectWithNativeAOT.csproj
index 9cb018db53..cdb413b816 100644
--- a/samples/DemoMSTestSdk/ProjectWithNativeAOT/ProjectWithNativeAOT.csproj
+++ b/samples/public/DemoMSTestSdk/ProjectWithNativeAOT/ProjectWithNativeAOT.csproj
@@ -1,7 +1,7 @@
-
+
@@ -31,13 +31,18 @@ Below is the equivalent project configuration when not using MSTest.Sdk
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DemoMSTestSdk/ProjectWithNativeAOT/UnitTest1.cs b/samples/public/DemoMSTestSdk/ProjectWithNativeAOT/UnitTest1.cs
similarity index 100%
rename from samples/DemoMSTestSdk/ProjectWithNativeAOT/UnitTest1.cs
rename to samples/public/DemoMSTestSdk/ProjectWithNativeAOT/UnitTest1.cs
diff --git a/samples/public/Directory.Build.props b/samples/public/Directory.Build.props
new file mode 100644
index 0000000000..1a0be96653
--- /dev/null
+++ b/samples/public/Directory.Build.props
@@ -0,0 +1,13 @@
+
+
+
+ 8.0.1
+ 17.11.3
+ 3.4.3
+ 1.0.0-alpha.24325.1
+ 1.44.0
+ 1.2.1
+ 17.10.0
+
+
+
diff --git a/samples/DemoMSTestSdk/Directory.Build.targets b/samples/public/Directory.Build.targets
similarity index 100%
rename from samples/DemoMSTestSdk/Directory.Build.targets
rename to samples/public/Directory.Build.targets
diff --git a/samples/DemoMSTestSdk/Directory.Packages.props b/samples/public/Directory.Packages.props
similarity index 100%
rename from samples/DemoMSTestSdk/Directory.Packages.props
rename to samples/public/Directory.Packages.props
diff --git a/samples/DemoMSTestSdk/NuGet.config b/samples/public/NuGet.config
similarity index 100%
rename from samples/DemoMSTestSdk/NuGet.config
rename to samples/public/NuGet.config
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/CompositeExtensionFactorySample.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/CompositeExtensionFactorySample.cs
new file mode 100644
index 0000000000..ae0d59ef39
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/CompositeExtensionFactorySample.cs
@@ -0,0 +1,93 @@
+// 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.Messages;
+using Microsoft.Testing.Platform.Extensions.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestHost;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.Testing.Platform.TestHost;
+
+namespace TestingPlatformExplorer.InProcess;
+
+internal class DisplayCompositeExtensionFactorySample : ITestSessionLifetimeHandler, IDataConsumer, IOutputDeviceDataProducer
+{
+ private readonly IOutputDevice _outputDevice;
+ private int _testNodeUpdateMessageCount;
+
+ public Type[] DataTypesConsumed => new[] { typeof(TestNodeUpdateMessage) };
+
+ public string Uid => nameof(DisplayCompositeExtensionFactorySample);
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => nameof(DisplayCompositeExtensionFactorySample);
+
+ public string Description => "";
+
+ public DisplayCompositeExtensionFactorySample(IOutputDevice outputDevice)
+ {
+ _outputDevice = outputDevice;
+ }
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationToken cancellationToken)
+ {
+ _testNodeUpdateMessageCount++;
+ var testNodeUpdateMessage = (TestNodeUpdateMessage)value;
+ string testNodeDisplayName = testNodeUpdateMessage.TestNode.DisplayName;
+ TestNodeUid testNodeId = testNodeUpdateMessage.TestNode.Uid;
+
+ TestNodeStateProperty nodeState = testNodeUpdateMessage.TestNode.Properties.Single();
+
+ switch (nodeState)
+ {
+ case InProgressTestNodeStateProperty _:
+ {
+ await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"[DisplayCompositeExtensionFactorySample]TestNode '{testNodeId}' with display name '{testNodeDisplayName}' is in progress")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+ break;
+ }
+ case PassedTestNodeStateProperty _:
+ {
+ await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"[DisplayCompositeExtensionFactorySample]TestNode '{testNodeId}' with display name '{testNodeDisplayName}' is completed")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+ break;
+ }
+ case FailedTestNodeStateProperty failedTestNodeStateProperty:
+ {
+ await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"[DisplayCompositeExtensionFactorySample]TestNode '{testNodeId}' with display name '{testNodeDisplayName}' is failed with '{failedTestNodeStateProperty?.Exception?.Message}'")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Red }
+ });
+ break;
+ }
+ case SkippedTestNodeStateProperty _:
+ {
+ await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"[DisplayCompositeExtensionFactorySample]TestNode '{testNodeId}' with display name '{testNodeDisplayName}' is skipped")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.White }
+ });
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ public async Task OnTestSessionStartingAsync(SessionUid sessionUid, CancellationToken cancellationToken)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData("[DisplayCompositeExtensionFactorySample]Hello from OnTestSessionStartingAsync")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.DarkGreen }
+ });
+
+ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, CancellationToken cancellationToken)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"[DisplayCompositeExtensionFactorySample]Total received 'TestNodeUpdateMessage': {_testNodeUpdateMessageCount}")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/DisplayDataConsumer.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/DisplayDataConsumer.cs
new file mode 100644
index 0000000000..b8ef1188c3
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/DisplayDataConsumer.cs
@@ -0,0 +1,76 @@
+// 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.Messages;
+using Microsoft.Testing.Platform.Extensions.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestHost;
+using Microsoft.Testing.Platform.OutputDevice;
+
+namespace TestingPlatformExplorer.InProcess;
+internal class DisplayDataConsumer : IDataConsumer, IOutputDeviceDataProducer
+{
+ private readonly IOutputDevice _outputDevice;
+
+ public Type[] DataTypesConsumed => new[] { typeof(TestNodeUpdateMessage) };
+
+ public string Uid => nameof(DisplayDataConsumer);
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => nameof(DisplayDataConsumer);
+
+ public string Description => "This extension display in console the testnode id and display name of TestNodeUpdateMessage data type.";
+
+ public DisplayDataConsumer(IOutputDevice outputDevice)
+ {
+ _outputDevice = outputDevice;
+ }
+
+ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationToken cancellationToken)
+ {
+ var testNodeUpdateMessage = (TestNodeUpdateMessage)value;
+ string testNodeDisplayName = testNodeUpdateMessage.TestNode.DisplayName;
+ TestNodeUid testNodeId = testNodeUpdateMessage.TestNode.Uid;
+
+ TestNodeStateProperty nodeState = testNodeUpdateMessage.TestNode.Properties.Single();
+
+ switch (nodeState)
+ {
+ case InProgressTestNodeStateProperty _:
+ {
+ await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"[DisplayDataConsumer]TestNode '{testNodeId}' with display name '{testNodeDisplayName}' is in progress")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+ break;
+ }
+ case PassedTestNodeStateProperty _:
+ {
+ await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"[DisplayDataConsumer]TestNode '{testNodeId}' with display name '{testNodeDisplayName}' is completed")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+ break;
+ }
+ case FailedTestNodeStateProperty failedTestNodeStateProperty:
+ {
+ await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"[DisplayDataConsumer]TestNode '{testNodeId}' with display name '{testNodeDisplayName}' is failed with '{failedTestNodeStateProperty?.Exception?.Message}'")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Red }
+ });
+ break;
+ }
+ case SkippedTestNodeStateProperty _:
+ {
+ await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"[DisplayDataConsumer]TestNode '{testNodeId}' with display name '{testNodeDisplayName}' is skipped")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.White }
+ });
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ public Task IsEnabledAsync() => Task.FromResult(true);
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/DisplayTestApplicationLifecycleCallbacks.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/DisplayTestApplicationLifecycleCallbacks.cs
new file mode 100644
index 0000000000..20776d3148
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/DisplayTestApplicationLifecycleCallbacks.cs
@@ -0,0 +1,39 @@
+// 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.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestHost;
+using Microsoft.Testing.Platform.OutputDevice;
+
+namespace TestingPlatformExplorer.InProcess;
+internal class DisplayTestApplicationLifecycleCallbacks : ITestApplicationLifecycleCallbacks, IOutputDeviceDataProducer
+{
+ private readonly IOutputDevice _outputDevice;
+
+ public string Uid => nameof(DisplayTestApplicationLifecycleCallbacks);
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => nameof(DisplayTestApplicationLifecycleCallbacks);
+
+ public string Description => "This extension display in console the before/after run";
+
+ public DisplayTestApplicationLifecycleCallbacks(IOutputDevice outputDevice)
+ {
+ _outputDevice = outputDevice;
+ }
+
+ public async Task AfterRunAsync(int exitCode, CancellationToken cancellation)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"Hello from AfterRunAsync, exit code: {exitCode}")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.DarkGreen }
+ });
+
+ public async Task BeforeRunAsync(CancellationToken cancellationToken)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData("Hello from BeforeRunAsync")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.DarkGreen }
+ });
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/DisplayTestSessionLifeTimeHandler.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/DisplayTestSessionLifeTimeHandler.cs
new file mode 100644
index 0000000000..230a3436d8
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/In-process extensions/DisplayTestSessionLifeTimeHandler.cs
@@ -0,0 +1,62 @@
+// 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.Extensions.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestHost;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.Testing.Platform.TestHost;
+
+namespace TestingPlatformExplorer.InProcess;
+internal class DisplayTestSessionLifeTimeHandler : ITestSessionLifetimeHandler,
+ IOutputDeviceDataProducer,
+ IAsyncInitializableExtension,
+ IAsyncCleanableExtension,
+ IAsyncDisposable
+{
+ private readonly IOutputDevice _outputDevice;
+
+ public string Uid => "This extension display in console the session start/end";
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => nameof(DisplayTestSessionLifeTimeHandler);
+
+ public string Description => "This extension display in console the session start/end";
+
+ public DisplayTestSessionLifeTimeHandler(IOutputDevice outputDevice)
+ {
+ _outputDevice = outputDevice;
+ }
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public async Task OnTestSessionStartingAsync(SessionUid sessionUid, CancellationToken cancellationToken)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData("Hello from OnTestSessionStartingAsync")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.DarkGreen }
+ });
+
+ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, CancellationToken cancellationToken)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData("Hello from OnTestSessionFinishingAsync")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.DarkGreen }
+ });
+ public async Task InitializeAsync()
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData("Hello from InitializeAsync")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.DarkGreen }
+ });
+
+ public async Task CleanupAsync()
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData("Hello from CleanupAsync")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.DarkGreen }
+ });
+
+ public async ValueTask DisposeAsync()
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData("Hello from DisposeAsync")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.DarkGreen }
+ });
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Out-of-process extensions/MonitorTestHost.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Out-of-process extensions/MonitorTestHost.cs
new file mode 100644
index 0000000000..a685152567
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Out-of-process extensions/MonitorTestHost.cs
@@ -0,0 +1,46 @@
+// 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.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestHostControllers;
+using Microsoft.Testing.Platform.OutputDevice;
+
+namespace TestingPlatformExplorer.OutOfProcess;
+
+internal class MonitorTestHost : ITestHostProcessLifetimeHandler, IOutputDeviceDataProducer
+{
+ private readonly IOutputDevice _outputDevice;
+
+ public MonitorTestHost(IOutputDevice outputDevice)
+ {
+ _outputDevice = outputDevice;
+ }
+
+ public string Uid => nameof(MonitorTestHost);
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => nameof(MonitorTestHost);
+
+ public string Description => "Example of monitoring the test host process.";
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public async Task BeforeTestHostProcessStartAsync(CancellationToken cancellationToken)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData("BeforeTestHostProcessStartAsync")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+
+ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"OnTestHostProcessExitedAsync, test host exited with exit code {testHostProcessInformation.ExitCode}")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+
+ public async Task OnTestHostProcessStartedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation)
+ => await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"OnTestHostProcessStartedAsync, test host started with PID {testHostProcessInformation.PID}")
+ {
+ ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green }
+ });
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Out-of-process extensions/SetEnvironmentVariableForTestHost.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Out-of-process extensions/SetEnvironmentVariableForTestHost.cs
new file mode 100644
index 0000000000..b3b0fb7160
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Out-of-process extensions/SetEnvironmentVariableForTestHost.cs
@@ -0,0 +1,32 @@
+// 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.Extensions.TestHostControllers;
+
+namespace TestingPlatformExplorer.OutOfProcess;
+
+internal class SetEnvironmentVariableForTestHost : ITestHostEnvironmentVariableProvider
+{
+ public string Uid => nameof(SetEnvironmentVariableForTestHost);
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => nameof(SetEnvironmentVariableForTestHost);
+
+ public string Description => "Example of setting environment variables for the test host.";
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public Task UpdateAsync(IEnvironmentVariables environmentVariables)
+ {
+ environmentVariables.SetVariable(new EnvironmentVariable("SAMPLE", "SAMPLE_VALUE", false, true));
+ return Task.CompletedTask;
+ }
+
+ public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnlyEnvironmentVariables environmentVariables)
+ => environmentVariables.TryGetVariable("SAMPLE", out OwnedEnvironmentVariable? value) && value.Value == "SAMPLE_VALUE"
+ ? ValidationResult.ValidTask
+ : ValidationResult.InvalidTask("The environment variable 'SAMPLE' is not set to 'SAMPLE_VALUE'.");
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Program.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Program.cs
new file mode 100644
index 0000000000..441c6d7cfd
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Program.cs
@@ -0,0 +1,44 @@
+// 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.Reflection;
+
+using Microsoft.Testing.Platform.Builder;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Services;
+
+using TestingPlatformExplorer.InProcess;
+using TestingPlatformExplorer.OutOfProcess;
+using TestingPlatformExplorer.TestingFramework;
+
+// Create the test application builder
+ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args);
+
+// Register the testing framework
+testApplicationBuilder.AddTestingFramework(() => new[] { Assembly.GetExecutingAssembly() });
+
+// In-process & out-of-process extensions
+// Register the testing framework command line options
+testApplicationBuilder.CommandLine.AddProvider(() => new TestingFrameworkCommandLineOptions());
+
+// In-process extensions
+testApplicationBuilder.TestHost.AddTestApplicationLifecycleCallbacks(serviceProvider
+ => new DisplayTestApplicationLifecycleCallbacks(serviceProvider.GetOutputDevice()));
+testApplicationBuilder.TestHost.AddTestSessionLifetimeHandle(serviceProvider
+ => new DisplayTestSessionLifeTimeHandler(serviceProvider.GetOutputDevice()));
+testApplicationBuilder.TestHost.AddDataConsumer(serviceProvider
+ => new DisplayDataConsumer(serviceProvider.GetOutputDevice()));
+
+// Out-of-process extensions
+testApplicationBuilder.TestHostControllers.AddEnvironmentVariableProvider(_
+ => new SetEnvironmentVariableForTestHost());
+testApplicationBuilder.TestHostControllers.AddProcessLifetimeHandler(serviceProvider =>
+ new MonitorTestHost(serviceProvider.GetOutputDevice()));
+
+// In-process composite extension SessionLifeTimeHandler+DataConsumer
+CompositeExtensionFactory compositeExtensionFactory = new(serviceProvider => new DisplayCompositeExtensionFactorySample(serviceProvider.GetOutputDevice()));
+testApplicationBuilder.TestHost.AddTestSessionLifetimeHandle(compositeExtensionFactory);
+testApplicationBuilder.TestHost.AddDataConsumer(compositeExtensionFactory);
+
+using ITestApplication testApplication = await testApplicationBuilder.BuildAsync();
+return await testApplication.RunAsync();
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Properties/launchSettings.json b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Properties/launchSettings.json
new file mode 100644
index 0000000000..696dc6823e
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/Properties/launchSettings.json
@@ -0,0 +1,9 @@
+{
+ "profiles": {
+ "TestingPlatformExplorer": {
+ "commandName": "Project",
+ "commandLineArgs": "--dop 1 --generatereport --reportfilename testframeworkreport.txt --diagnostic",
+ "environmentVariables": { "TestingFramework__DisableParallelism": "True" }
+ }
+ }
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/AssertionException.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/AssertionException.cs
new file mode 100644
index 0000000000..a42aab42e2
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/AssertionException.cs
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace TestingPlatformExplorer.TestingFramework;
+
+[Serializable]
+public class AssertionException : Exception
+{
+ public AssertionException()
+ {
+ }
+
+ public AssertionException(string? message)
+ : base(message)
+ {
+ }
+
+ public AssertionException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.Assertions.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.Assertions.cs
new file mode 100644
index 0000000000..5330e13656
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.Assertions.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 TestingPlatformExplorer.TestingFramework;
+
+public static class Assert
+{
+ public static void AreEqual(T expected, T actual)
+ {
+ if (expected is null)
+ {
+ throw new ArgumentException("'expected' cannot be null", nameof(expected));
+ }
+
+ if (actual is null)
+ {
+ throw new ArgumentException("'actual' cannot be null", nameof(actual));
+ }
+
+ if (!expected.Equals(actual))
+ {
+ throw new AssertionException($"Expected: {expected}, Actual: {actual}");
+ }
+ }
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.Attributes.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.Attributes.cs
new file mode 100644
index 0000000000..c1c83b63a1
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.Attributes.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 TestingPlatformExplorer.TestingFramework;
+
+[AttributeUsage(AttributeTargets.Method)]
+public class SkipAttribute : Attribute
+{
+}
+
+[AttributeUsage(AttributeTargets.Method)]
+public class TestMethodAttribute : Attribute
+{
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.CommandLineOptions.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.CommandLineOptions.cs
new file mode 100644
index 0000000000..788efe5c75
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.CommandLineOptions.cs
@@ -0,0 +1,55 @@
+// 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.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.CommandLine;
+
+namespace TestingPlatformExplorer.TestingFramework;
+
+internal sealed class TestingFrameworkCommandLineOptions : ICommandLineOptionsProvider
+{
+ public const string DopOption = "dop";
+ public const string GenerateReportOption = "generatereport";
+ public const string ReportFilenameOption = "reportfilename";
+
+ public string Uid => nameof(TestingFrameworkCommandLineOptions);
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => nameof(TestingFrameworkCommandLineOptions);
+
+ public string Description => "Testing framework command line options";
+
+ public IReadOnlyCollection GetCommandLineOptions() => new[]
+ {
+ new CommandLineOption(DopOption,"Degree of parallelism", ArgumentArity.ExactlyOne, false),
+ new CommandLineOption(GenerateReportOption,"Generate a test report file", ArgumentArity.Zero, false),
+ new CommandLineOption(ReportFilenameOption,"Report file name to use together with --generatereport", ArgumentArity.ExactlyOne, false),
+ };
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
+ {
+ if (commandOption.Name == DopOption)
+ {
+ if (!int.TryParse(arguments[0], out int dopValue) || dopValue <= 0)
+ {
+ return ValidationResult.InvalidTask("Dop must be a positive integer");
+ }
+ }
+
+ return ValidationResult.ValidTask;
+ }
+
+ public Task ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
+ {
+ bool generateReportEnabled = commandLineOptions.IsOptionSet(GenerateReportOption);
+ bool reportFileName = commandLineOptions.TryGetOptionArgumentList(ReportFilenameOption, out string[]? _);
+
+ return (generateReportEnabled || reportFileName) && !(generateReportEnabled && reportFileName)
+ ? ValidationResult.InvalidTask("--generatereport and --reportfilename must be specified together")
+ : ValidationResult.ValidTask;
+ }
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.Registration.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.Registration.cs
new file mode 100644
index 0000000000..5d2c2ddb9a
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.Registration.cs
@@ -0,0 +1,21 @@
+// 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.Reflection;
+using Microsoft.Testing.Platform.Builder;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.Services;
+
+namespace TestingPlatformExplorer.TestingFramework;
+
+public static class TestingFrameworkExtensions
+{
+ public static void AddTestingFramework(this ITestApplicationBuilder builder, Func assemblies)
+ => builder.RegisterTestFramework(_ => new TestingFrameworkCapabilities(),
+ (capabilities, serviceProvider) => new TestingFramework(capabilities,
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetConfiguration(),
+ serviceProvider.GetLoggerFactory().CreateLogger(),
+ serviceProvider.GetOutputDevice(),
+ assemblies));
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.cs
new file mode 100644
index 0000000000..0176a0c973
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFramework.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 System.Globalization;
+using System.Reflection;
+using System.Text;
+
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Extensions.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestFramework;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.Testing.Platform.Requests;
+
+namespace TestingPlatformExplorer.TestingFramework;
+
+internal sealed class TestingFramework : ITestFramework, IDataProducer, IDisposable, IOutputDeviceDataProducer
+{
+ private readonly TestingFrameworkCapabilities _capabilities;
+ private readonly ICommandLineOptions _commandLineOptions;
+ private readonly IConfiguration _configuration;
+ private readonly ILogger _logger;
+ private readonly IOutputDevice _outputDevice;
+ private readonly Assembly[] _assemblies;
+ private readonly SemaphoreSlim _dop;
+ private readonly string _reportFile = string.Empty;
+ private readonly int _dopValue;
+
+ public TestingFramework(
+ ITestFrameworkCapabilities capabilities,
+ ICommandLineOptions commandLineOptions,
+ IConfiguration configuration,
+ ILogger logger,
+ IOutputDevice outputDevice,
+ Func assemblies)
+ {
+ _capabilities = (TestingFrameworkCapabilities)capabilities;
+ _commandLineOptions = commandLineOptions;
+ _configuration = configuration;
+ _logger = logger;
+ _outputDevice = outputDevice;
+ _assemblies = assemblies();
+
+ if (_commandLineOptions.TryGetOptionArgumentList(TestingFrameworkCommandLineOptions.DopOption, out string[]? argumentList))
+ {
+ _dopValue = int.Parse(argumentList[0], CultureInfo.InvariantCulture);
+ _dop = new SemaphoreSlim(_dopValue, _dopValue);
+ }
+ else
+ {
+ _dop = new SemaphoreSlim(int.MaxValue, int.MaxValue);
+ }
+
+ if (_configuration["TestingFramework:DisableParallelism"] == bool.TrueString)
+ {
+ _dop?.Dispose();
+ _dop = new SemaphoreSlim(1, 1);
+ _dopValue = 1;
+ }
+
+ if (_commandLineOptions.IsOptionSet(TestingFrameworkCommandLineOptions.GenerateReportOption))
+ {
+ if (_commandLineOptions.TryGetOptionArgumentList(TestingFrameworkCommandLineOptions.ReportFilenameOption, out string[]? reportFile))
+ {
+ _reportFile = reportFile[0];
+ }
+ }
+ }
+
+ public string Uid => nameof(TestingFramework);
+
+ public string Version => "1.0.0";
+
+ public string DisplayName => "TestingFramework";
+
+ public string Description => "Testing framework sample";
+
+ public Type[] DataTypesProduced => new[] { typeof(TestNodeUpdateMessage), typeof(SessionFileArtifact) };
+
+ public Task CloseTestSessionAsync(CloseTestSessionContext context)
+ => Task.FromResult(new CloseTestSessionResult() { IsSuccess = true });
+
+ public Task CreateTestSessionAsync(CreateTestSessionContext context)
+ => Task.FromResult(new CreateTestSessionResult() { IsSuccess = true });
+
+ public async Task ExecuteRequestAsync(ExecuteRequestContext context)
+ {
+ if (_logger.IsEnabled(LogLevel.Debug))
+ {
+ await _logger.LogDebugAsync($"Executing request of type '{context.Request}'");
+ }
+
+ switch (context.Request)
+ {
+ case DiscoverTestExecutionRequest discoverTestExecutionRequest:
+ {
+ try
+ {
+ MethodInfo[] tests = GetTestsMethodFromAssemblies();
+ foreach (MethodInfo test in tests)
+ {
+ var testNode = new TestNode()
+ {
+ Uid = $"{test.DeclaringType!.FullName}.{test.Name}",
+ DisplayName = test.Name,
+ Properties = new PropertyBag(DiscoveredTestNodeStateProperty.CachedInstance),
+ };
+
+ await context.MessageBus.PublishAsync(this, new TestNodeUpdateMessage(discoverTestExecutionRequest.Session.SessionUid, testNode));
+ }
+ }
+ finally
+ {
+ // Ensure to complete the request also in case of exception
+ context.Complete();
+ }
+
+ break;
+ }
+
+ case RunTestExecutionRequest runTestExecutionRequest:
+ {
+ try
+ {
+ await _outputDevice.DisplayAsync(this, new FormattedTextOutputDeviceData($"TestingFramework version '{Version}' running tests with parallelism of {_dopValue}") { ForegroundColor = new SystemConsoleColor() { ConsoleColor = ConsoleColor.Green } });
+
+ StringBuilder reportBody = new();
+ MethodInfo[] tests = GetTestsMethodFromAssemblies();
+ List results = new();
+ foreach (MethodInfo test in tests)
+ {
+ if (test.GetCustomAttribute() != null)
+ {
+ var skippedTestNode = new TestNode()
+ {
+ Uid = $"{test.DeclaringType!.FullName}.{test.Name}",
+ DisplayName = test.Name,
+ Properties = new PropertyBag(SkippedTestNodeStateProperty.CachedInstance),
+ };
+
+ await context.MessageBus.PublishAsync(this, new TestNodeUpdateMessage(runTestExecutionRequest.Session.SessionUid, skippedTestNode));
+
+ lock (reportBody)
+ {
+ reportBody.AppendLine(CultureInfo.InvariantCulture, $"Test {skippedTestNode.Uid} skipped");
+ }
+
+ continue;
+ }
+
+ results.Add(Task.Run(async () =>
+ {
+ await _dop.WaitAsync();
+ try
+ {
+ object? instance = Activator.CreateInstance(test.DeclaringType!);
+ try
+ {
+ test.Invoke(instance, null);
+
+ var successfulTestNode = new TestNode()
+ {
+ Uid = $"{test.DeclaringType!.FullName}.{test.Name}",
+ DisplayName = test.Name,
+ Properties = new PropertyBag(PassedTestNodeStateProperty.CachedInstance),
+ };
+
+ await context.MessageBus.PublishAsync(this, new TestNodeUpdateMessage(runTestExecutionRequest.Session.SessionUid, successfulTestNode));
+
+ lock (reportBody)
+ {
+ reportBody.AppendLine(CultureInfo.InvariantCulture, $"Test {successfulTestNode.Uid} succeeded");
+ }
+ }
+ catch (TargetInvocationException ex) when (ex.InnerException is AssertionException assertionException)
+ {
+ var assertionFailedTestNode = new TestNode()
+ {
+ Uid = $"{test.DeclaringType!.FullName}.{test.Name}",
+ DisplayName = test.Name,
+ Properties = new PropertyBag(new FailedTestNodeStateProperty(assertionException)),
+ };
+
+ await context.MessageBus.PublishAsync(this, new TestNodeUpdateMessage(runTestExecutionRequest.Session.SessionUid, assertionFailedTestNode));
+
+ reportBody.AppendLine(CultureInfo.InvariantCulture, $"Test {assertionFailedTestNode.Uid} failed");
+ }
+ catch (TargetInvocationException ex)
+ {
+ var failedTestNode = new TestNode()
+ {
+ Uid = $"{test.DeclaringType!.FullName}.{test.Name}",
+ DisplayName = test.Name,
+ Properties = new PropertyBag(new ErrorTestNodeStateProperty(ex.InnerException!)),
+ };
+
+ await context.MessageBus.PublishAsync(this, new TestNodeUpdateMessage(runTestExecutionRequest.Session.SessionUid, failedTestNode));
+
+ lock (reportBody)
+ {
+ reportBody.AppendLine(CultureInfo.InvariantCulture, $"Test {failedTestNode.Uid} failed");
+ }
+ }
+ }
+ finally
+ {
+ _dop.Release();
+ }
+ }));
+ }
+
+ await Task.WhenAll(results);
+
+ if (!string.IsNullOrEmpty(_reportFile))
+ {
+ File.WriteAllText(_reportFile, reportBody.ToString());
+ await context.MessageBus.PublishAsync(this, new SessionFileArtifact(runTestExecutionRequest.Session.SessionUid, new FileInfo(_reportFile), "Testing framework report"));
+ }
+ }
+ finally
+ {
+ // Ensure to complete the request also in case of exception
+ context.Complete();
+ }
+
+ break;
+ }
+
+ default:
+ throw new NotSupportedException($"Request {context.GetType()} not supported");
+ }
+ }
+
+ private MethodInfo[] GetTestsMethodFromAssemblies()
+ => _assemblies
+ .SelectMany(x => x.GetTypes())
+ .SelectMany(x => x.GetMethods())
+ .Where(x => x.GetCustomAttributes().Any())
+ .ToArray();
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+ public void Dispose()
+ {
+ _dop.Dispose();
+ }
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFrameworkCapabilities.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFrameworkCapabilities.cs
new file mode 100644
index 0000000000..1b110c3dbd
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingFramework/TestingFrameworkCapabilities.cs
@@ -0,0 +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.
+
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+
+namespace TestingPlatformExplorer.TestingFramework;
+
+internal sealed class TestingFrameworkCapabilities : ITestFrameworkCapabilities
+{
+ public IReadOnlyCollection Capabilities => [];
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingPlatformExplorer.csproj b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingPlatformExplorer.csproj
new file mode 100644
index 0000000000..bebb9ba07e
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingPlatformExplorer.csproj
@@ -0,0 +1,22 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ TestingPlatformExplorer
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingPlatformExplorer.testingplatformconfig.json b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingPlatformExplorer.testingplatformconfig.json
new file mode 100644
index 0000000000..193b3111e0
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/TestingPlatformExplorer.testingplatformconfig.json
@@ -0,0 +1,5 @@
+{
+ "TestingFramework": {
+ "DisableParallelism": false
+ }
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformExplorer/UnitTests.cs b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/UnitTests.cs
new file mode 100644
index 0000000000..5c676ccbc7
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformExplorer/UnitTests.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using TestingPlatformExplorer.TestingFramework;
+
+namespace TestingPlatformExplorer.UnitTests;
+
+public class SomeTests
+{
+ [TestMethod]
+ public static void TestMethod1() => Assert.AreEqual(1, 1);
+
+ [TestMethod]
+ public static void TestMethod2() => Assert.AreEqual(1, 2);
+
+ [TestMethod]
+ public static void TestMethod3()
+ {
+ int a = 1;
+ int b = 0;
+ int c = a / b;
+
+ Assert.AreEqual(c, 2);
+ }
+
+ [Skip]
+ [TestMethod]
+ public static void TestMethod4() => Assert.AreEqual(1, 1);
+}
diff --git a/samples/public/TestingPlatformExamples/TestingPlatformSamples.sln b/samples/public/TestingPlatformExamples/TestingPlatformSamples.sln
new file mode 100644
index 0000000000..d385c6012e
--- /dev/null
+++ b/samples/public/TestingPlatformExamples/TestingPlatformSamples.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestingPlatformExplorer", "TestingPlatformExplorer\TestingPlatformExplorer.csproj", "{0BC2CCB3-993F-4FEB-8BB6-E2F310C3AD0D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0BC2CCB3-993F-4FEB-8BB6-E2F310C3AD0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0BC2CCB3-993F-4FEB-8BB6-E2F310C3AD0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0BC2CCB3-993F-4FEB-8BB6-E2F310C3AD0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0BC2CCB3-993F-4FEB-8BB6-E2F310C3AD0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/samples/DemoMSTestSdk/global.json b/samples/public/global.json
similarity index 51%
rename from samples/DemoMSTestSdk/global.json
rename to samples/public/global.json
index 1561c043d4..766ec37273 100644
--- a/samples/DemoMSTestSdk/global.json
+++ b/samples/public/global.json
@@ -1,5 +1,5 @@
{
"msbuild-sdks": {
- "MSTest.Sdk": "3.3.1"
+ "MSTest.Sdk": "3.4.3"
}
}
diff --git a/samples/mstest-runner/CustomReportExtension/CustomReportExtension.sln b/samples/public/mstest-runner/CustomReportExtension/CustomReportExtension.sln
similarity index 100%
rename from samples/mstest-runner/CustomReportExtension/CustomReportExtension.sln
rename to samples/public/mstest-runner/CustomReportExtension/CustomReportExtension.sln
diff --git a/samples/mstest-runner/CustomReportExtension/CustomReportExtension/CustomReportExtension.csproj b/samples/public/mstest-runner/CustomReportExtension/CustomReportExtension/CustomReportExtension.csproj
similarity index 85%
rename from samples/mstest-runner/CustomReportExtension/CustomReportExtension/CustomReportExtension.csproj
rename to samples/public/mstest-runner/CustomReportExtension/CustomReportExtension/CustomReportExtension.csproj
index 70f3d1322f..0df68e8798 100644
--- a/samples/mstest-runner/CustomReportExtension/CustomReportExtension/CustomReportExtension.csproj
+++ b/samples/public/mstest-runner/CustomReportExtension/CustomReportExtension/CustomReportExtension.csproj
@@ -15,8 +15,8 @@
-
-
+
+
diff --git a/samples/mstest-runner/CustomReportExtension/CustomReportExtension/Program.cs b/samples/public/mstest-runner/CustomReportExtension/CustomReportExtension/Program.cs
similarity index 100%
rename from samples/mstest-runner/CustomReportExtension/CustomReportExtension/Program.cs
rename to samples/public/mstest-runner/CustomReportExtension/CustomReportExtension/Program.cs
diff --git a/samples/mstest-runner/CustomReportExtension/CustomReportExtension/TestResultConsoleLogger.cs b/samples/public/mstest-runner/CustomReportExtension/CustomReportExtension/TestResultConsoleLogger.cs
similarity index 100%
rename from samples/mstest-runner/CustomReportExtension/CustomReportExtension/TestResultConsoleLogger.cs
rename to samples/public/mstest-runner/CustomReportExtension/CustomReportExtension/TestResultConsoleLogger.cs
diff --git a/samples/mstest-runner/CustomReportExtension/CustomReportExtension/UnitTest1.cs b/samples/public/mstest-runner/CustomReportExtension/CustomReportExtension/UnitTest1.cs
similarity index 100%
rename from samples/mstest-runner/CustomReportExtension/CustomReportExtension/UnitTest1.cs
rename to samples/public/mstest-runner/CustomReportExtension/CustomReportExtension/UnitTest1.cs
diff --git a/samples/mstest-runner/EnsureTestFramework/EnsureTestFramework.sln b/samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework.sln
similarity index 100%
rename from samples/mstest-runner/EnsureTestFramework/EnsureTestFramework.sln
rename to samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework.sln
diff --git a/samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.cs b/samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.cs
similarity index 100%
rename from samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.cs
rename to samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.cs
diff --git a/samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.csproj b/samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.csproj
similarity index 89%
rename from samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.csproj
rename to samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.csproj
index df9e3a4340..56679174f2 100644
--- a/samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.csproj
+++ b/samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFramework.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFrameworkCapabilities.cs b/samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFrameworkCapabilities.cs
similarity index 100%
rename from samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFrameworkCapabilities.cs
rename to samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFrameworkCapabilities.cs
diff --git a/samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFrameworkExtension.cs b/samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFrameworkExtension.cs
similarity index 100%
rename from samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFrameworkExtension.cs
rename to samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/EnsureTestFrameworkExtension.cs
diff --git a/samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/TestApplicationBuilderExtensions.cs b/samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/TestApplicationBuilderExtensions.cs
similarity index 100%
rename from samples/mstest-runner/EnsureTestFramework/EnsureTestFramework/TestApplicationBuilderExtensions.cs
rename to samples/public/mstest-runner/EnsureTestFramework/EnsureTestFramework/TestApplicationBuilderExtensions.cs
diff --git a/samples/mstest-runner/EnsureTestFramework/MyTestProject/MyTestProject.csproj b/samples/public/mstest-runner/EnsureTestFramework/MyTestProject/MyTestProject.csproj
similarity index 100%
rename from samples/mstest-runner/EnsureTestFramework/MyTestProject/MyTestProject.csproj
rename to samples/public/mstest-runner/EnsureTestFramework/MyTestProject/MyTestProject.csproj
diff --git a/samples/mstest-runner/EnsureTestFramework/MyTestProject/Program.cs b/samples/public/mstest-runner/EnsureTestFramework/MyTestProject/Program.cs
similarity index 100%
rename from samples/mstest-runner/EnsureTestFramework/MyTestProject/Program.cs
rename to samples/public/mstest-runner/EnsureTestFramework/MyTestProject/Program.cs
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/MSTestRunnerWinUI.sln b/samples/public/mstest-runner/MSTestRunnerWinUI/MSTestRunnerWinUI.sln
new file mode 100644
index 0000000000..eec4ac626e
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/MSTestRunnerWinUI.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33627.172
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTest", "UnitTest\UnitTest.csproj", "{E9CD5A8E-3214-46AE-AD52-6102A3987E97}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Debug|ARM64.Build.0 = Debug|ARM64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Debug|x64.ActiveCfg = Debug|x64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Debug|x64.Build.0 = Debug|x64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Debug|x64.Deploy.0 = Debug|x64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Debug|x86.ActiveCfg = Debug|x86
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Debug|x86.Build.0 = Debug|x86
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Debug|x86.Deploy.0 = Debug|x86
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Release|ARM64.ActiveCfg = Release|ARM64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Release|ARM64.Build.0 = Release|ARM64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Release|ARM64.Deploy.0 = Release|ARM64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Release|x64.ActiveCfg = Release|x64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Release|x64.Build.0 = Release|x64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Release|x64.Deploy.0 = Release|x64
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Release|x86.ActiveCfg = Release|x86
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Release|x86.Build.0 = Release|x86
+ {E9CD5A8E-3214-46AE-AD52-6102A3987E97}.Release|x86.Deploy.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {1FBE0D4D-1701-4F9B-8010-2460A18F36C0}
+ EndGlobalSection
+EndGlobal
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/App.xaml b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/App.xaml
new file mode 100644
index 0000000000..e0b0e782d8
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/App.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/App.xaml.cs b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/App.xaml.cs
new file mode 100644
index 0000000000..cf9026f54e
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/App.xaml.cs
@@ -0,0 +1,77 @@
+// 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.Builder;
+using Microsoft.UI.Dispatching;
+using Microsoft.UI.Xaml;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace UnitTest;
+
+///
+/// Provides application-specific behavior to supplement the default Application class.
+///
+public partial class App : Application
+{
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// Invoked when the application is launched.
+ ///
+ /// Details about the launch request and process.
+ protected override
+#if MSTEST_RUNNER
+ async
+#endif
+ void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
+ {
+#if !MSTEST_RUNNER
+ Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI();
+#endif
+
+ _window = new MainWindow();
+ _window.Activate();
+ UITestMethodAttribute.DispatcherQueue = DispatcherQueue.GetForCurrentThread();
+
+ // Replace back with e.Arguments when https://github.com/microsoft/microsoft-ui-xaml/issues/3368 is fixed
+#if MSTEST_RUNNER
+ // Ideally we would want to reuse the generated main so we don't have to manually handle all dependencies
+ // but this type is generated too late in the build process so we fail before.
+ // You can build, inspect the generated type to copy its content if you want.
+ // await TestingPlatformEntryPoint.Main(Environment.GetCommandLineArgs().Skip(1).ToArray());
+ try
+ {
+
+ string[] cliArgs = Environment.GetCommandLineArgs().Skip(1).ToArray();
+ ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(cliArgs);
+ Microsoft.Testing.Platform.MSBuild.TestingPlatformBuilderHook.AddExtensions(builder, cliArgs);
+ Microsoft.Testing.Extensions.Telemetry.TestingPlatformBuilderHook.AddExtensions(builder, cliArgs);
+ TestingPlatformBuilderHook.AddExtensions(builder, cliArgs);
+ using ITestApplication app = await builder.BuildAsync();
+ await app.RunAsync();
+ }
+ finally
+ {
+ _window.Close();
+ }
+#else
+ Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(Environment.CommandLine);
+#endif
+ }
+
+ private Window _window;
+}
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/LockScreenLogo.scale-200.png b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/LockScreenLogo.scale-200.png
new file mode 100644
index 0000000000..7440f0d4bf
Binary files /dev/null and b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/LockScreenLogo.scale-200.png differ
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/SplashScreen.scale-200.png b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/SplashScreen.scale-200.png
new file mode 100644
index 0000000000..32f486a867
Binary files /dev/null and b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/SplashScreen.scale-200.png differ
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Square150x150Logo.scale-200.png b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Square150x150Logo.scale-200.png
new file mode 100644
index 0000000000..53ee3777ea
Binary files /dev/null and b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Square150x150Logo.scale-200.png differ
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Square44x44Logo.scale-200.png b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Square44x44Logo.scale-200.png
new file mode 100644
index 0000000000..f713bba67f
Binary files /dev/null and b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Square44x44Logo.scale-200.png differ
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 0000000000..dc9f5bea0c
Binary files /dev/null and b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/StoreLogo.png b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/StoreLogo.png
new file mode 100644
index 0000000000..a4586f26bd
Binary files /dev/null and b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/StoreLogo.png differ
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Wide310x150Logo.scale-200.png b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Wide310x150Logo.scale-200.png
new file mode 100644
index 0000000000..8b4a5d0dd5
Binary files /dev/null and b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/MainWindow.xaml b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/MainWindow.xaml
new file mode 100644
index 0000000000..a139c9fb1d
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/MainWindow.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/MainWindow.xaml.cs b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/MainWindow.xaml.cs
new file mode 100644
index 0000000000..58e846bcb5
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/MainWindow.xaml.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.
+
+using Microsoft.UI.Xaml;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace UnitTest;
+
+///
+/// An empty window that can be used on its own or navigated to within a Frame.
+///
+public sealed partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Package.appxmanifest b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Package.appxmanifest
new file mode 100644
index 0000000000..b86d7f7bc0
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Package.appxmanifest
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+ UnitTest
+ naver
+ Assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/PublishProfiles/win10-arm64.pubxml b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/PublishProfiles/win10-arm64.pubxml
new file mode 100644
index 0000000000..a7fdd16b67
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/PublishProfiles/win10-arm64.pubxml
@@ -0,0 +1,20 @@
+
+
+
+
+ FileSystem
+ ARM64
+ win10-arm64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/PublishProfiles/win10-x64.pubxml b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/PublishProfiles/win10-x64.pubxml
new file mode 100644
index 0000000000..26ea7e55c1
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/PublishProfiles/win10-x64.pubxml
@@ -0,0 +1,20 @@
+
+
+
+
+ FileSystem
+ x64
+ win10-x64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/PublishProfiles/win10-x86.pubxml b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/PublishProfiles/win10-x86.pubxml
new file mode 100644
index 0000000000..34d14d4d4a
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/PublishProfiles/win10-x86.pubxml
@@ -0,0 +1,20 @@
+
+
+
+
+ FileSystem
+ x86
+ win10-x86
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/launchSettings.json b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/launchSettings.json
new file mode 100644
index 0000000000..5f98bdda88
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/Properties/launchSettings.json
@@ -0,0 +1,20 @@
+{
+ "profiles": {
+ "UnitTest MSTest Runner (Package)": {
+ "commandName": "MsixPackage",
+ "commandLineArgs": "/p:EnableMSTestRunner=true"
+ },
+ "UnitTest MSTest Runner (Unpackaged)": {
+ "commandName": "Project",
+ "commandLineArgs": "/p:EnableMSTestRunner=true"
+ },
+ "UnitTest VSTest (Package)": {
+ "commandName": "MsixPackage",
+ "commandLineArgs": "/p:EnableMSTestRunner=false"
+ },
+ "UnitTest VSTest (Unpackaged)": {
+ "commandName": "Project",
+ "commandLineArgs": "/p:EnableMSTestRunner=false"
+ }
+ }
+}
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/TestClass.cs b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/TestClass.cs
new file mode 100644
index 0000000000..9762a23be6
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/TestClass.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.UI.Xaml.Controls;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+
+namespace UnitTest;
+
+[TestClass]
+public class TestClass
+{
+ [UITestMethod]
+ public void TestMethod1()
+ {
+ var grid = new Grid();
+ Assert.IsNotNull(grid);
+ }
+}
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/UnitTest.csproj b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/UnitTest.csproj
new file mode 100644
index 0000000000..f76ed4a78c
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/UnitTest.csproj
@@ -0,0 +1,65 @@
+
+
+ WinExe
+ net6.0-windows10.0.19041.0
+ 10.0.17763.0
+ UnitTest
+ app.manifest
+ x86;x64;ARM64
+ win10-x86;win10-x64;win10-arm64
+ win10-$(Platform).pubxml
+ true
+ true
+
+
+
+
+ true
+ false
+ $(DefineConstants);MSTEST_RUNNER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
diff --git a/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/app.manifest b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/app.manifest
new file mode 100644
index 0000000000..d8d425fd90
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestRunnerWinUI/UnitTest/app.manifest
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
\ No newline at end of file
diff --git a/samples/mstest-runner/NativeAotRunner/ClassLibrary1/Class1.cs b/samples/public/mstest-runner/NativeAotRunner/ClassLibrary1/Class1.cs
similarity index 100%
rename from samples/mstest-runner/NativeAotRunner/ClassLibrary1/Class1.cs
rename to samples/public/mstest-runner/NativeAotRunner/ClassLibrary1/Class1.cs
diff --git a/samples/mstest-runner/NativeAotRunner/ClassLibrary1/ClassLibrary1.csproj b/samples/public/mstest-runner/NativeAotRunner/ClassLibrary1/ClassLibrary1.csproj
similarity index 100%
rename from samples/mstest-runner/NativeAotRunner/ClassLibrary1/ClassLibrary1.csproj
rename to samples/public/mstest-runner/NativeAotRunner/ClassLibrary1/ClassLibrary1.csproj
diff --git a/samples/mstest-runner/NativeAotRunner/TestProject1.sln b/samples/public/mstest-runner/NativeAotRunner/TestProject1.sln
similarity index 100%
rename from samples/mstest-runner/NativeAotRunner/TestProject1.sln
rename to samples/public/mstest-runner/NativeAotRunner/TestProject1.sln
diff --git a/samples/mstest-runner/NativeAotRunner/TestProject1/TestProject1.csproj b/samples/public/mstest-runner/NativeAotRunner/TestProject1/TestProject1.csproj
similarity index 63%
rename from samples/mstest-runner/NativeAotRunner/TestProject1/TestProject1.csproj
rename to samples/public/mstest-runner/NativeAotRunner/TestProject1/TestProject1.csproj
index 8445454ea3..89b1a96a9f 100644
--- a/samples/mstest-runner/NativeAotRunner/TestProject1/TestProject1.csproj
+++ b/samples/public/mstest-runner/NativeAotRunner/TestProject1/TestProject1.csproj
@@ -1,4 +1,4 @@
-
+net8.0
@@ -10,25 +10,25 @@
-
-
-
+
+
-
-
+
+
-
-
-
-
+
+
+
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/samples/mstest-runner/NativeAotRunner/TestProject1/UnitTest1.cs b/samples/public/mstest-runner/NativeAotRunner/TestProject1/UnitTest1.cs
similarity index 100%
rename from samples/mstest-runner/NativeAotRunner/TestProject1/UnitTest1.cs
rename to samples/public/mstest-runner/NativeAotRunner/TestProject1/UnitTest1.cs
diff --git a/samples/mstest-runner/RunInDocker/.dockerignore b/samples/public/mstest-runner/RunInDocker/.dockerignore
similarity index 100%
rename from samples/mstest-runner/RunInDocker/.dockerignore
rename to samples/public/mstest-runner/RunInDocker/.dockerignore
diff --git a/samples/mstest-runner/RunInDocker/Dockerfile b/samples/public/mstest-runner/RunInDocker/Dockerfile
similarity index 100%
rename from samples/mstest-runner/RunInDocker/Dockerfile
rename to samples/public/mstest-runner/RunInDocker/Dockerfile
diff --git a/samples/mstest-runner/RunInDocker/MyServer.Tests/MyServer.Tests.csproj b/samples/public/mstest-runner/RunInDocker/MyServer.Tests/MyServer.Tests.csproj
similarity index 86%
rename from samples/mstest-runner/RunInDocker/MyServer.Tests/MyServer.Tests.csproj
rename to samples/public/mstest-runner/RunInDocker/MyServer.Tests/MyServer.Tests.csproj
index 87917d25ff..f60c60fc7b 100644
--- a/samples/mstest-runner/RunInDocker/MyServer.Tests/MyServer.Tests.csproj
+++ b/samples/public/mstest-runner/RunInDocker/MyServer.Tests/MyServer.Tests.csproj
@@ -3,7 +3,7 @@
trueExe
-
+
net8.0enableenable
@@ -12,7 +12,7 @@
-
+
diff --git a/samples/mstest-runner/RunInDocker/MyServer.Tests/UnitTest1.cs b/samples/public/mstest-runner/RunInDocker/MyServer.Tests/UnitTest1.cs
similarity index 100%
rename from samples/mstest-runner/RunInDocker/MyServer.Tests/UnitTest1.cs
rename to samples/public/mstest-runner/RunInDocker/MyServer.Tests/UnitTest1.cs
diff --git a/samples/mstest-runner/RunInDocker/MyServer/MyServer.csproj b/samples/public/mstest-runner/RunInDocker/MyServer/MyServer.csproj
similarity index 100%
rename from samples/mstest-runner/RunInDocker/MyServer/MyServer.csproj
rename to samples/public/mstest-runner/RunInDocker/MyServer/MyServer.csproj
diff --git a/samples/mstest-runner/RunInDocker/MyServer/Program.cs b/samples/public/mstest-runner/RunInDocker/MyServer/Program.cs
similarity index 100%
rename from samples/mstest-runner/RunInDocker/MyServer/Program.cs
rename to samples/public/mstest-runner/RunInDocker/MyServer/Program.cs
diff --git a/samples/mstest-runner/RunInDocker/MyServer/Properties/launchSettings.json b/samples/public/mstest-runner/RunInDocker/MyServer/Properties/launchSettings.json
similarity index 100%
rename from samples/mstest-runner/RunInDocker/MyServer/Properties/launchSettings.json
rename to samples/public/mstest-runner/RunInDocker/MyServer/Properties/launchSettings.json
diff --git a/samples/mstest-runner/RunInDocker/MyServer/appsettings.Development.json b/samples/public/mstest-runner/RunInDocker/MyServer/appsettings.Development.json
similarity index 100%
rename from samples/mstest-runner/RunInDocker/MyServer/appsettings.Development.json
rename to samples/public/mstest-runner/RunInDocker/MyServer/appsettings.Development.json
diff --git a/samples/mstest-runner/RunInDocker/MyServer/appsettings.json b/samples/public/mstest-runner/RunInDocker/MyServer/appsettings.json
similarity index 100%
rename from samples/mstest-runner/RunInDocker/MyServer/appsettings.json
rename to samples/public/mstest-runner/RunInDocker/MyServer/appsettings.json
diff --git a/samples/mstest-runner/RunInDocker/README.md b/samples/public/mstest-runner/RunInDocker/README.md
similarity index 100%
rename from samples/mstest-runner/RunInDocker/README.md
rename to samples/public/mstest-runner/RunInDocker/README.md
diff --git a/samples/mstest-runner/RunInDocker/RunInDocker.sln b/samples/public/mstest-runner/RunInDocker/RunInDocker.sln
similarity index 100%
rename from samples/mstest-runner/RunInDocker/RunInDocker.sln
rename to samples/public/mstest-runner/RunInDocker/RunInDocker.sln
diff --git a/samples/mstest-runner/RunInDocker/global.json b/samples/public/mstest-runner/RunInDocker/global.json
similarity index 100%
rename from samples/mstest-runner/RunInDocker/global.json
rename to samples/public/mstest-runner/RunInDocker/global.json
diff --git a/samples/mstest-runner/Simple1/Simple1.csproj b/samples/public/mstest-runner/Simple1/Simple1.csproj
similarity index 90%
rename from samples/mstest-runner/Simple1/Simple1.csproj
rename to samples/public/mstest-runner/Simple1/Simple1.csproj
index 2830d71a7c..b3e6042830 100644
--- a/samples/mstest-runner/Simple1/Simple1.csproj
+++ b/samples/public/mstest-runner/Simple1/Simple1.csproj
@@ -21,7 +21,7 @@
MSTest.TestFramework
MSTest.Analyzers
-->
-
+
-
+
diff --git a/samples/mstest-runner/Simple1/TestConfiguration.cs b/samples/public/mstest-runner/Simple1/TestConfiguration.cs
similarity index 100%
rename from samples/mstest-runner/Simple1/TestConfiguration.cs
rename to samples/public/mstest-runner/Simple1/TestConfiguration.cs
diff --git a/samples/mstest-runner/Simple1/UnitTest1.cs b/samples/public/mstest-runner/Simple1/UnitTest1.cs
similarity index 100%
rename from samples/mstest-runner/Simple1/UnitTest1.cs
rename to samples/public/mstest-runner/Simple1/UnitTest1.cs
diff --git a/samples/mstest-runner/Simple1/global.json b/samples/public/mstest-runner/Simple1/global.json
similarity index 100%
rename from samples/mstest-runner/Simple1/global.json
rename to samples/public/mstest-runner/Simple1/global.json
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/1000C100M.csproj b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/1000C100M.csproj
similarity index 75%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/1000C100M.csproj
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/1000C100M.csproj
index 0e20449f63..41d0a5b53d 100644
--- a/samples/mstest-runner/runner_vs_vstest/1000C_100M/1000C100M.csproj
+++ b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/1000C100M.csproj
@@ -12,9 +12,9 @@
-
-
-
+
+
+
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MSTestConfiguration.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MSTestConfiguration.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MSTestConfiguration.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MSTestConfiguration.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0001.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0001.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0001.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0001.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0002.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0002.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0002.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0002.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0003.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0003.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0003.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0003.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0004.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0004.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0004.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0004.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0005.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0005.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0005.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0005.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0006.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0006.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0006.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0006.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0007.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0007.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0007.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0007.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0008.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0008.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0008.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0008.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0009.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0009.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0009.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0009.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0010.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0010.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0010.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0010.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0011.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0011.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0011.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0011.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0012.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0012.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0012.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0012.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0013.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0013.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0013.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0013.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0014.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0014.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0014.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0014.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0015.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0015.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0015.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0015.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0016.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0016.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0016.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0016.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0017.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0017.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0017.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0017.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0018.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0018.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0018.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0018.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0019.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0019.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0019.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0019.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0020.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0020.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0020.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0020.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0021.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0021.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0021.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0021.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0022.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0022.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0022.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0022.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0023.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0023.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0023.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0023.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0024.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0024.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0024.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0024.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0025.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0025.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0025.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0025.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0026.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0026.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0026.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0026.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0027.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0027.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0027.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0027.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0028.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0028.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0028.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0028.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0029.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0029.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0029.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0029.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0030.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0030.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0030.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0030.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0031.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0031.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0031.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0031.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0032.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0032.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0032.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0032.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0033.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0033.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0033.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0033.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0034.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0034.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0034.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0034.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0035.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0035.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0035.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0035.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0036.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0036.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0036.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0036.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0037.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0037.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0037.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0037.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0038.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0038.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0038.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0038.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0039.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0039.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0039.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0039.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0040.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0040.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0040.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0040.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0041.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0041.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0041.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0041.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0042.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0042.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0042.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0042.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0043.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0043.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0043.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0043.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0044.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0044.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0044.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0044.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0045.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0045.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0045.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0045.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0046.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0046.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0046.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0046.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0047.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0047.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0047.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0047.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0048.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0048.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0048.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0048.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0049.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0049.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0049.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0049.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0050.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0050.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0050.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0050.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0051.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0051.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0051.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0051.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0052.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0052.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0052.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0052.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0053.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0053.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0053.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0053.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0054.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0054.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0054.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0054.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0055.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0055.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0055.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0055.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0056.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0056.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0056.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0056.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0057.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0057.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0057.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0057.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0058.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0058.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0058.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0058.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0059.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0059.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0059.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0059.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0060.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0060.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0060.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0060.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0061.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0061.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0061.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0061.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0062.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0062.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0062.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0062.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0063.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0063.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0063.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0063.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0064.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0064.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0064.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0064.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0065.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0065.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0065.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0065.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0066.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0066.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0066.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0066.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0067.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0067.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0067.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0067.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0068.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0068.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0068.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0068.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0069.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0069.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0069.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0069.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0070.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0070.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0070.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0070.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0071.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0071.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0071.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0071.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0072.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0072.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0072.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0072.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0073.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0073.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0073.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0073.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0074.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0074.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0074.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0074.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0075.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0075.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0075.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0075.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0076.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0076.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0076.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0076.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0077.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0077.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0077.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0077.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0078.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0078.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0078.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0078.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0079.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0079.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0079.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0079.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0080.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0080.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0080.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0080.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0081.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0081.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0081.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0081.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0082.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0082.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0082.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0082.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0083.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0083.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0083.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0083.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0084.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0084.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0084.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0084.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0085.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0085.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0085.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0085.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0086.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0086.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0086.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0086.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0087.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0087.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0087.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0087.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0088.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0088.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0088.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0088.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0089.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0089.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0089.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0089.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0090.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0090.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0090.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0090.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0091.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0091.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0091.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0091.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0092.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0092.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0092.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0092.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0093.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0093.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0093.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0093.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0094.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0094.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0094.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0094.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0095.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0095.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0095.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0095.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0096.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0096.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0096.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0096.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0097.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0097.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0097.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0097.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0098.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0098.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0098.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0098.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0099.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0099.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0099.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0099.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0100.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0100.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0100.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0100.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0101.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0101.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0101.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0101.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0102.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0102.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0102.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0102.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0103.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0103.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0103.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0103.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0104.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0104.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0104.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0104.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0105.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0105.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0105.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0105.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0106.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0106.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0106.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0106.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0107.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0107.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0107.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0107.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0108.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0108.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0108.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0108.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0109.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0109.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0109.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0109.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0110.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0110.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0110.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0110.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0111.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0111.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0111.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0111.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0112.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0112.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0112.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0112.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0113.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0113.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0113.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0113.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0114.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0114.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0114.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0114.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0115.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0115.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0115.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0115.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0116.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0116.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0116.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0116.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0117.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0117.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0117.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0117.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0118.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0118.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0118.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0118.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0119.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0119.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0119.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0119.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0120.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0120.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0120.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0120.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0121.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0121.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0121.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0121.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0122.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0122.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0122.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0122.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0123.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0123.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0123.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0123.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0124.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0124.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0124.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0124.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0125.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0125.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0125.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0125.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0126.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0126.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0126.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0126.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0127.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0127.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0127.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0127.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0128.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0128.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0128.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0128.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0129.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0129.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0129.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0129.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0130.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0130.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0130.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0130.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0131.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0131.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0131.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0131.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0132.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0132.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0132.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0132.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0133.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0133.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0133.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0133.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0134.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0134.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0134.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0134.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0135.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0135.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0135.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0135.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0136.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0136.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0136.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0136.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0137.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0137.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0137.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0137.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0138.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0138.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0138.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0138.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0139.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0139.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0139.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0139.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0140.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0140.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0140.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0140.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0141.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0141.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0141.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0141.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0142.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0142.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0142.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0142.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0143.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0143.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0143.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0143.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0144.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0144.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0144.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0144.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0145.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0145.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0145.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0145.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0146.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0146.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0146.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0146.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0147.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0147.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0147.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0147.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0148.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0148.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0148.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0148.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0149.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0149.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0149.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0149.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0150.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0150.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0150.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0150.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0151.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0151.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0151.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0151.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0152.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0152.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0152.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0152.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0153.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0153.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0153.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0153.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0154.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0154.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0154.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0154.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0155.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0155.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0155.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0155.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0156.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0156.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0156.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0156.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0157.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0157.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0157.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0157.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0158.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0158.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0158.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0158.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0159.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0159.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0159.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0159.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0160.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0160.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0160.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0160.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0161.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0161.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0161.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0161.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0162.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0162.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0162.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0162.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0163.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0163.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0163.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0163.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0164.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0164.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0164.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0164.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0165.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0165.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0165.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0165.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0166.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0166.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0166.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0166.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0167.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0167.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0167.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0167.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0168.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0168.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0168.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0168.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0169.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0169.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0169.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0169.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0170.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0170.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0170.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0170.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0171.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0171.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0171.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0171.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0172.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0172.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0172.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0172.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0173.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0173.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0173.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0173.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0174.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0174.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0174.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0174.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0175.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0175.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0175.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0175.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0176.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0176.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0176.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0176.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0177.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0177.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0177.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0177.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0178.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0178.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0178.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0178.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0179.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0179.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0179.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0179.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0180.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0180.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0180.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0180.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0181.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0181.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0181.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0181.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0182.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0182.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0182.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0182.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0183.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0183.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0183.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0183.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0184.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0184.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0184.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0184.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0185.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0185.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0185.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0185.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0186.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0186.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0186.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0186.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0187.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0187.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0187.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0187.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0188.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0188.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0188.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0188.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0189.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0189.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0189.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0189.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0190.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0190.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0190.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0190.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0191.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0191.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0191.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0191.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0192.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0192.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0192.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0192.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0193.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0193.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0193.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0193.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0194.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0194.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0194.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0194.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0195.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0195.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0195.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0195.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0196.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0196.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0196.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0196.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0197.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0197.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0197.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0197.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0198.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0198.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0198.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0198.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0199.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0199.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0199.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0199.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0200.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0200.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0200.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0200.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0201.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0201.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0201.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0201.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0202.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0202.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0202.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0202.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0203.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0203.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0203.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0203.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0204.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0204.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0204.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0204.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0205.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0205.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0205.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0205.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0206.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0206.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0206.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0206.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0207.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0207.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0207.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0207.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0208.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0208.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0208.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0208.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0209.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0209.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0209.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0209.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0210.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0210.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0210.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0210.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0211.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0211.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0211.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0211.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0212.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0212.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0212.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0212.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0213.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0213.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0213.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0213.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0214.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0214.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0214.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0214.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0215.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0215.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0215.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0215.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0216.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0216.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0216.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0216.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0217.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0217.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0217.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0217.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0218.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0218.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0218.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0218.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0219.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0219.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0219.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0219.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0220.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0220.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0220.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0220.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0221.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0221.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0221.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0221.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0222.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0222.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0222.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0222.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0223.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0223.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0223.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0223.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0224.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0224.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0224.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0224.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0225.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0225.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0225.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0225.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0226.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0226.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0226.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0226.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0227.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0227.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0227.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0227.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0228.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0228.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0228.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0228.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0229.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0229.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0229.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0229.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0230.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0230.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0230.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0230.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0231.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0231.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0231.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0231.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0232.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0232.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0232.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0232.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0233.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0233.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0233.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0233.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0234.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0234.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0234.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0234.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0235.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0235.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0235.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0235.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0236.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0236.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0236.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0236.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0237.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0237.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0237.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0237.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0238.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0238.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0238.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0238.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0239.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0239.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0239.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0239.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0240.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0240.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0240.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0240.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0241.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0241.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0241.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0241.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0242.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0242.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0242.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0242.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0243.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0243.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0243.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0243.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0244.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0244.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0244.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0244.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0245.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0245.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0245.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0245.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0246.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0246.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0246.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0246.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0247.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0247.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0247.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0247.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0248.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0248.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0248.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0248.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0249.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0249.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0249.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0249.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0250.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0250.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0250.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0250.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0251.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0251.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0251.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0251.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0252.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0252.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0252.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0252.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0253.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0253.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0253.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0253.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0254.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0254.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0254.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0254.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0255.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0255.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0255.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0255.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0256.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0256.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0256.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0256.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0257.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0257.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0257.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0257.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0258.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0258.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0258.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0258.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0259.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0259.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0259.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0259.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0260.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0260.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0260.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0260.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0261.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0261.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0261.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0261.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0262.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0262.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0262.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0262.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0263.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0263.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0263.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0263.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0264.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0264.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0264.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0264.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0265.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0265.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0265.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0265.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0266.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0266.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0266.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0266.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0267.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0267.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0267.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0267.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0268.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0268.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0268.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0268.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0269.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0269.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0269.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0269.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0270.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0270.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0270.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0270.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0271.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0271.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0271.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0271.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0272.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0272.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0272.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0272.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0273.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0273.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0273.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0273.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0274.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0274.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0274.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0274.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0275.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0275.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0275.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0275.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0276.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0276.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0276.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0276.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0277.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0277.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0277.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0277.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0278.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0278.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0278.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0278.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0279.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0279.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0279.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0279.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0280.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0280.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0280.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0280.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0281.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0281.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0281.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0281.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0282.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0282.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0282.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0282.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0283.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0283.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0283.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0283.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0284.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0284.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0284.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0284.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0285.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0285.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0285.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0285.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0286.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0286.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0286.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0286.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0287.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0287.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0287.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0287.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0288.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0288.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0288.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0288.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0289.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0289.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0289.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0289.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0290.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0290.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0290.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0290.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0291.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0291.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0291.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0291.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0292.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0292.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0292.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0292.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0293.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0293.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0293.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0293.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0294.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0294.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0294.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0294.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0295.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0295.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0295.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0295.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0296.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0296.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0296.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0296.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0297.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0297.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0297.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0297.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0298.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0298.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0298.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0298.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0299.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0299.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0299.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0299.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0300.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0300.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0300.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0300.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0301.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0301.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0301.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0301.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0302.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0302.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0302.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0302.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0303.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0303.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0303.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0303.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0304.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0304.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0304.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0304.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0305.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0305.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0305.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0305.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0306.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0306.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0306.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0306.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0307.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0307.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0307.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0307.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0308.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0308.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0308.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0308.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0309.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0309.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0309.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0309.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0310.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0310.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0310.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0310.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0311.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0311.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0311.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0311.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0312.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0312.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0312.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0312.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0313.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0313.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0313.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0313.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0314.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0314.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0314.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0314.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0315.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0315.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0315.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0315.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0316.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0316.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0316.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0316.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0317.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0317.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0317.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0317.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0318.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0318.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0318.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0318.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0319.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0319.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0319.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0319.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0320.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0320.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0320.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0320.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0321.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0321.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0321.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0321.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0322.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0322.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0322.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0322.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0323.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0323.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0323.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0323.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0324.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0324.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0324.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0324.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0325.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0325.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0325.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0325.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0326.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0326.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0326.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0326.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0327.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0327.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0327.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0327.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0328.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0328.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0328.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0328.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0329.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0329.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0329.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0329.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0330.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0330.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0330.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0330.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0331.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0331.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0331.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0331.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0332.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0332.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0332.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0332.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0333.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0333.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0333.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0333.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0334.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0334.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0334.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0334.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0335.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0335.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0335.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0335.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0336.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0336.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0336.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0336.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0337.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0337.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0337.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0337.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0338.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0338.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0338.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0338.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0339.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0339.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0339.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0339.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0340.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0340.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0340.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0340.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0341.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0341.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0341.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0341.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0342.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0342.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0342.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0342.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0343.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0343.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0343.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0343.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0344.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0344.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0344.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0344.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0345.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0345.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0345.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0345.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0346.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0346.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0346.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0346.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0347.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0347.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0347.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0347.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0348.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0348.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0348.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0348.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0349.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0349.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0349.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0349.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0350.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0350.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0350.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0350.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0351.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0351.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0351.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0351.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0352.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0352.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0352.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0352.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0353.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0353.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0353.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0353.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0354.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0354.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0354.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0354.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0355.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0355.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0355.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0355.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0356.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0356.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0356.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0356.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0357.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0357.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0357.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0357.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0358.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0358.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0358.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0358.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0359.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0359.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0359.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0359.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0360.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0360.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0360.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0360.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0361.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0361.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0361.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0361.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0362.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0362.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0362.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0362.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0363.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0363.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0363.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0363.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0364.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0364.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0364.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0364.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0365.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0365.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0365.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0365.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0366.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0366.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0366.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0366.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0367.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0367.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0367.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0367.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0368.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0368.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0368.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0368.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0369.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0369.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0369.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0369.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0370.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0370.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0370.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0370.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0371.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0371.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0371.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0371.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0372.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0372.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0372.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0372.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0373.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0373.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0373.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0373.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0374.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0374.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0374.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0374.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0375.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0375.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0375.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0375.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0376.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0376.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0376.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0376.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0377.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0377.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0377.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0377.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0378.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0378.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0378.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0378.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0379.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0379.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0379.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0379.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0380.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0380.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0380.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0380.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0381.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0381.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0381.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0381.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0382.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0382.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0382.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0382.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0383.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0383.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0383.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0383.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0384.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0384.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0384.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0384.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0385.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0385.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0385.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0385.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0386.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0386.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0386.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0386.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0387.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0387.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0387.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0387.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0388.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0388.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0388.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0388.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0389.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0389.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0389.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0389.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0390.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0390.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0390.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0390.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0391.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0391.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0391.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0391.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0392.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0392.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0392.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0392.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0393.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0393.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0393.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0393.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0394.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0394.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0394.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0394.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0395.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0395.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0395.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0395.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0396.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0396.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0396.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0396.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0397.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0397.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0397.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0397.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0398.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0398.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0398.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0398.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0399.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0399.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0399.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0399.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0400.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0400.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0400.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0400.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0401.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0401.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0401.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0401.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0402.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0402.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0402.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0402.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0403.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0403.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0403.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0403.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0404.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0404.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0404.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0404.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0405.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0405.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0405.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0405.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0406.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0406.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0406.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0406.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0407.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0407.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0407.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0407.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0408.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0408.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0408.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0408.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0409.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0409.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0409.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0409.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0410.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0410.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0410.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0410.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0411.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0411.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0411.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0411.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0412.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0412.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0412.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0412.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0413.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0413.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0413.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0413.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0414.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0414.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0414.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0414.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0415.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0415.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0415.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0415.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0416.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0416.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0416.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0416.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0417.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0417.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0417.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0417.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0418.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0418.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0418.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0418.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0419.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0419.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0419.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0419.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0420.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0420.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0420.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0420.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0421.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0421.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0421.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0421.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0422.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0422.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0422.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0422.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0423.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0423.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0423.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0423.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0424.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0424.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0424.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0424.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0425.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0425.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0425.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0425.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0426.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0426.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0426.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0426.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0427.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0427.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0427.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0427.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0428.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0428.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0428.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0428.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0429.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0429.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0429.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0429.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0430.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0430.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0430.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0430.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0431.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0431.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0431.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0431.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0432.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0432.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0432.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0432.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0433.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0433.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0433.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0433.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0434.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0434.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0434.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0434.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0435.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0435.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0435.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0435.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0436.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0436.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0436.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0436.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0437.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0437.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0437.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0437.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0438.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0438.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0438.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0438.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0439.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0439.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0439.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0439.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0440.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0440.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0440.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0440.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0441.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0441.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0441.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0441.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0442.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0442.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0442.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0442.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0443.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0443.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0443.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0443.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0444.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0444.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0444.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0444.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0445.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0445.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0445.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0445.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0446.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0446.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0446.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0446.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0447.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0447.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0447.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0447.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0448.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0448.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0448.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0448.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0449.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0449.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0449.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0449.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0450.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0450.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0450.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0450.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0451.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0451.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0451.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0451.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0452.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0452.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0452.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0452.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0453.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0453.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0453.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0453.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0454.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0454.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0454.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0454.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0455.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0455.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0455.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0455.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0456.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0456.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0456.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0456.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0457.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0457.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0457.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0457.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0458.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0458.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0458.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0458.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0459.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0459.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0459.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0459.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0460.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0460.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0460.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0460.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0461.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0461.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0461.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0461.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0462.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0462.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0462.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0462.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0463.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0463.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0463.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0463.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0464.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0464.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0464.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0464.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0465.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0465.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0465.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0465.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0466.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0466.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0466.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0466.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0467.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0467.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0467.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0467.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0468.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0468.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0468.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0468.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0469.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0469.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0469.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0469.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0470.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0470.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0470.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0470.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0471.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0471.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0471.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0471.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0472.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0472.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0472.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0472.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0473.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0473.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0473.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0473.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0474.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0474.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0474.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0474.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0475.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0475.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0475.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0475.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0476.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0476.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0476.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0476.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0477.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0477.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0477.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0477.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0478.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0478.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0478.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0478.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0479.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0479.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0479.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0479.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0480.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0480.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0480.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0480.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0481.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0481.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0481.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0481.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0482.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0482.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0482.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0482.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0483.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0483.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0483.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0483.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0484.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0484.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0484.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0484.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0485.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0485.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0485.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0485.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0486.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0486.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0486.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0486.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0487.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0487.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0487.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0487.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0488.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0488.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0488.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0488.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0489.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0489.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0489.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0489.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0490.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0490.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0490.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0490.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0491.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0491.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0491.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0491.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0492.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0492.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0492.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0492.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0493.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0493.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0493.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0493.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0494.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0494.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0494.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0494.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0495.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0495.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0495.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0495.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0496.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0496.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0496.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0496.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0497.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0497.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0497.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0497.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0498.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0498.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0498.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0498.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0499.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0499.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0499.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0499.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0500.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0500.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0500.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0500.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0501.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0501.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0501.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0501.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0502.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0502.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0502.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0502.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0503.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0503.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0503.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0503.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0504.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0504.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0504.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0504.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0505.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0505.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0505.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0505.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0506.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0506.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0506.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0506.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0507.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0507.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0507.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0507.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0508.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0508.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0508.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0508.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0509.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0509.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0509.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0509.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0510.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0510.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0510.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0510.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0511.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0511.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0511.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0511.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0512.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0512.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0512.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0512.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0513.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0513.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0513.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0513.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0514.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0514.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0514.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0514.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0515.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0515.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0515.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0515.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0516.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0516.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0516.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0516.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0517.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0517.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0517.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0517.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0518.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0518.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0518.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0518.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0519.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0519.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0519.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0519.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0520.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0520.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0520.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0520.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0521.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0521.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0521.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0521.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0522.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0522.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0522.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0522.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0523.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0523.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0523.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0523.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0524.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0524.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0524.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0524.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0525.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0525.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0525.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0525.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0526.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0526.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0526.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0526.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0527.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0527.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0527.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0527.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0528.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0528.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0528.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0528.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0529.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0529.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0529.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0529.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0530.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0530.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0530.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0530.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0531.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0531.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0531.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0531.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0532.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0532.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0532.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0532.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0533.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0533.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0533.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0533.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0534.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0534.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0534.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0534.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0535.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0535.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0535.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0535.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0536.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0536.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0536.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0536.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0537.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0537.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0537.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0537.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0538.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0538.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0538.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0538.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0539.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0539.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0539.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0539.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0540.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0540.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0540.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0540.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0541.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0541.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0541.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0541.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0542.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0542.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0542.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0542.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0543.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0543.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0543.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0543.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0544.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0544.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0544.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0544.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0545.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0545.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0545.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0545.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0546.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0546.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0546.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0546.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0547.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0547.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0547.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0547.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0548.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0548.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0548.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0548.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0549.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0549.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0549.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0549.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0550.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0550.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0550.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0550.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0551.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0551.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0551.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0551.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0552.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0552.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0552.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0552.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0553.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0553.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0553.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0553.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0554.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0554.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0554.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0554.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0555.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0555.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0555.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0555.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0556.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0556.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0556.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0556.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0557.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0557.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0557.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0557.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0558.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0558.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0558.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0558.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0559.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0559.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0559.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0559.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0560.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0560.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0560.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0560.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0561.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0561.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0561.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0561.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0562.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0562.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0562.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0562.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0563.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0563.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0563.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0563.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0564.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0564.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0564.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0564.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0565.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0565.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0565.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0565.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0566.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0566.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0566.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0566.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0567.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0567.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0567.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0567.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0568.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0568.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0568.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0568.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0569.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0569.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0569.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0569.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0570.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0570.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0570.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0570.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0571.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0571.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0571.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0571.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0572.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0572.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0572.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0572.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0573.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0573.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0573.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0573.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0574.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0574.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0574.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0574.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0575.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0575.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0575.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0575.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0576.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0576.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0576.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0576.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0577.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0577.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0577.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0577.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0578.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0578.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0578.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0578.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0579.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0579.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0579.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0579.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0580.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0580.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0580.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0580.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0581.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0581.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0581.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0581.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0582.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0582.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0582.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0582.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0583.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0583.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0583.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0583.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0584.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0584.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0584.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0584.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0585.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0585.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0585.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0585.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0586.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0586.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0586.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0586.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0587.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0587.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0587.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0587.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0588.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0588.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0588.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0588.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0589.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0589.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0589.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0589.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0590.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0590.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0590.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0590.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0591.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0591.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0591.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0591.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0592.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0592.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0592.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0592.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0593.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0593.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0593.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0593.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0594.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0594.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0594.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0594.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0595.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0595.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0595.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0595.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0596.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0596.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0596.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0596.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0597.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0597.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0597.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0597.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0598.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0598.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0598.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0598.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0599.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0599.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0599.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0599.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0600.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0600.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0600.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0600.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0601.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0601.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0601.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0601.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0602.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0602.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0602.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0602.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0603.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0603.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0603.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0603.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0604.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0604.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0604.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0604.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0605.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0605.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0605.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0605.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0606.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0606.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0606.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0606.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0607.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0607.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0607.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0607.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0608.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0608.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0608.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0608.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0609.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0609.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0609.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0609.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0610.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0610.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0610.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0610.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0611.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0611.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0611.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0611.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0612.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0612.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0612.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0612.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0613.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0613.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0613.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0613.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0614.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0614.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0614.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0614.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0615.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0615.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0615.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0615.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0616.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0616.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0616.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0616.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0617.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0617.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0617.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0617.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0618.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0618.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0618.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0618.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0619.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0619.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0619.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0619.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0620.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0620.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0620.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0620.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0621.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0621.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0621.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0621.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0622.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0622.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0622.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0622.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0623.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0623.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0623.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0623.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0624.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0624.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0624.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0624.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0625.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0625.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0625.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0625.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0626.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0626.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0626.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0626.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0627.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0627.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0627.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0627.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0628.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0628.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0628.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0628.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0629.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0629.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0629.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0629.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0630.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0630.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0630.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0630.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0631.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0631.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0631.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0631.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0632.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0632.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0632.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0632.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0633.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0633.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0633.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0633.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0634.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0634.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0634.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0634.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0635.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0635.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0635.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0635.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0636.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0636.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0636.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0636.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0637.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0637.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0637.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0637.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0638.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0638.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0638.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0638.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0639.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0639.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0639.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0639.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0640.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0640.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0640.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0640.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0641.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0641.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0641.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0641.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0642.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0642.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0642.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0642.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0643.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0643.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0643.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0643.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0644.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0644.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0644.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0644.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0645.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0645.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0645.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0645.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0646.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0646.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0646.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0646.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0647.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0647.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0647.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0647.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0648.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0648.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0648.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0648.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0649.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0649.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0649.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0649.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0650.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0650.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0650.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0650.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0651.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0651.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0651.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0651.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0652.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0652.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0652.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0652.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0653.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0653.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0653.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0653.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0654.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0654.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0654.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0654.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0655.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0655.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0655.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0655.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0656.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0656.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0656.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0656.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0657.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0657.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0657.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0657.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0658.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0658.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0658.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0658.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0659.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0659.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0659.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0659.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0660.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0660.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0660.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0660.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0661.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0661.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0661.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0661.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0662.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0662.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0662.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0662.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0663.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0663.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0663.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0663.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0664.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0664.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0664.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0664.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0665.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0665.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0665.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0665.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0666.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0666.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0666.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0666.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0667.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0667.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0667.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0667.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0668.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0668.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0668.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0668.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0669.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0669.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0669.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0669.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0670.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0670.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0670.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0670.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0671.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0671.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0671.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0671.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0672.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0672.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0672.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0672.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0673.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0673.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0673.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0673.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0674.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0674.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0674.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0674.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0675.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0675.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0675.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0675.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0676.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0676.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0676.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0676.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0677.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0677.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0677.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0677.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0678.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0678.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0678.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0678.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0679.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0679.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0679.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0679.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0680.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0680.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0680.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0680.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0681.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0681.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0681.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0681.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0682.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0682.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0682.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0682.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0683.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0683.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0683.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0683.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0684.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0684.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0684.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0684.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0685.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0685.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0685.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0685.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0686.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0686.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0686.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0686.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0687.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0687.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0687.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0687.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0688.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0688.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0688.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0688.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0689.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0689.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0689.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0689.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0690.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0690.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0690.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0690.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0691.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0691.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0691.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0691.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0692.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0692.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0692.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0692.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0693.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0693.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0693.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0693.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0694.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0694.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0694.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0694.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0695.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0695.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0695.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0695.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0696.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0696.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0696.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0696.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0697.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0697.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0697.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0697.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0698.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0698.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0698.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0698.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0699.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0699.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0699.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0699.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0700.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0700.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0700.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0700.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0701.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0701.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0701.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0701.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0702.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0702.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0702.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0702.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0703.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0703.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0703.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0703.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0704.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0704.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0704.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0704.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0705.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0705.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0705.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0705.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0706.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0706.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0706.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0706.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0707.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0707.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0707.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0707.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0708.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0708.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0708.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0708.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0709.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0709.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0709.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0709.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0710.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0710.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0710.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0710.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0711.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0711.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0711.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0711.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0712.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0712.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0712.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0712.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0713.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0713.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0713.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0713.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0714.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0714.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0714.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0714.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0715.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0715.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0715.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0715.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0716.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0716.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0716.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0716.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0717.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0717.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0717.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0717.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0718.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0718.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0718.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0718.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0719.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0719.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0719.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0719.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0720.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0720.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0720.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0720.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0721.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0721.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0721.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0721.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0722.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0722.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0722.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0722.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0723.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0723.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0723.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0723.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0724.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0724.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0724.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0724.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0725.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0725.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0725.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0725.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0726.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0726.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0726.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0726.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0727.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0727.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0727.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0727.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0728.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0728.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0728.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0728.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0729.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0729.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0729.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0729.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0730.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0730.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0730.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0730.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0731.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0731.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0731.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0731.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0732.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0732.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0732.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0732.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0733.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0733.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0733.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0733.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0734.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0734.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0734.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0734.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0735.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0735.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0735.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0735.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0736.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0736.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0736.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0736.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0737.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0737.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0737.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0737.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0738.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0738.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0738.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0738.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0739.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0739.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0739.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0739.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0740.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0740.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0740.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0740.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0741.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0741.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0741.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0741.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0742.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0742.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0742.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0742.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0743.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0743.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0743.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0743.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0744.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0744.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0744.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0744.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0745.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0745.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0745.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0745.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0746.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0746.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0746.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0746.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0747.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0747.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0747.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0747.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0748.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0748.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0748.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0748.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0749.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0749.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0749.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0749.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0750.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0750.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0750.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0750.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0751.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0751.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0751.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0751.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0752.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0752.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0752.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0752.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0753.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0753.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0753.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0753.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0754.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0754.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0754.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0754.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0755.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0755.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0755.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0755.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0756.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0756.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0756.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0756.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0757.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0757.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0757.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0757.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0758.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0758.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0758.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0758.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0759.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0759.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0759.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0759.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0760.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0760.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0760.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0760.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0761.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0761.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0761.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0761.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0762.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0762.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0762.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0762.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0763.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0763.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0763.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0763.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0764.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0764.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0764.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0764.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0765.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0765.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0765.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0765.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0766.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0766.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0766.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0766.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0767.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0767.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0767.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0767.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0768.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0768.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0768.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0768.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0769.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0769.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0769.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0769.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0770.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0770.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0770.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0770.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0771.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0771.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0771.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0771.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0772.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0772.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0772.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0772.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0773.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0773.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0773.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0773.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0774.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0774.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0774.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0774.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0775.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0775.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0775.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0775.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0776.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0776.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0776.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0776.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0777.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0777.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0777.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0777.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0778.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0778.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0778.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0778.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0779.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0779.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0779.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0779.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0780.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0780.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0780.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0780.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0781.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0781.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0781.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0781.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0782.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0782.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0782.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0782.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0783.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0783.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0783.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0783.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0784.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0784.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0784.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0784.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0785.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0785.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0785.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0785.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0786.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0786.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0786.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0786.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0787.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0787.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0787.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0787.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0788.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0788.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0788.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0788.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0789.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0789.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0789.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0789.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0790.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0790.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0790.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0790.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0791.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0791.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0791.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0791.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0792.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0792.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0792.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0792.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0793.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0793.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0793.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0793.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0794.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0794.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0794.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0794.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0795.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0795.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0795.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0795.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0796.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0796.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0796.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0796.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0797.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0797.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0797.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0797.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0798.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0798.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0798.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0798.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0799.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0799.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0799.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0799.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0800.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0800.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0800.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0800.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0801.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0801.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0801.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0801.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0802.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0802.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0802.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0802.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0803.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0803.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0803.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0803.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0804.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0804.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0804.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0804.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0805.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0805.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0805.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0805.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0806.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0806.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0806.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0806.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0807.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0807.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0807.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0807.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0808.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0808.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0808.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0808.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0809.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0809.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0809.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0809.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0810.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0810.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0810.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0810.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0811.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0811.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0811.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0811.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0812.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0812.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0812.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0812.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0813.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0813.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0813.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0813.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0814.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0814.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0814.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0814.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0815.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0815.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0815.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0815.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0816.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0816.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0816.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0816.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0817.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0817.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0817.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0817.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0818.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0818.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0818.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0818.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0819.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0819.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0819.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0819.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0820.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0820.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0820.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0820.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0821.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0821.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0821.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0821.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0822.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0822.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0822.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0822.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0823.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0823.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0823.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0823.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0824.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0824.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0824.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0824.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0825.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0825.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0825.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0825.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0826.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0826.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0826.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0826.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0827.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0827.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0827.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0827.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0828.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0828.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0828.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0828.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0829.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0829.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0829.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0829.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0830.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0830.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0830.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0830.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0831.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0831.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0831.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0831.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0832.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0832.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0832.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0832.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0833.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0833.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0833.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0833.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0834.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0834.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0834.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0834.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0835.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0835.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0835.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0835.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0836.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0836.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0836.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0836.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0837.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0837.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0837.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0837.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0838.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0838.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0838.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0838.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0839.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0839.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0839.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0839.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0840.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0840.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0840.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0840.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0841.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0841.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0841.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0841.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0842.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0842.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0842.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0842.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0843.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0843.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0843.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0843.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0844.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0844.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0844.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0844.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0845.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0845.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0845.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0845.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0846.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0846.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0846.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0846.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0847.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0847.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0847.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0847.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0848.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0848.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0848.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0848.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0849.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0849.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0849.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0849.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0850.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0850.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0850.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0850.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0851.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0851.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0851.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0851.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0852.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0852.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0852.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0852.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0853.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0853.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0853.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0853.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0854.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0854.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0854.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0854.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0855.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0855.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0855.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0855.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0856.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0856.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0856.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0856.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0857.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0857.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0857.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0857.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0858.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0858.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0858.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0858.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0859.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0859.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0859.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0859.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0860.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0860.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0860.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0860.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0861.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0861.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0861.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0861.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0862.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0862.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0862.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0862.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0863.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0863.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0863.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0863.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0864.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0864.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0864.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0864.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0865.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0865.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0865.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0865.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0866.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0866.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0866.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0866.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0867.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0867.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0867.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0867.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0868.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0868.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0868.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0868.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0869.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0869.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0869.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0869.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0870.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0870.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0870.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0870.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0871.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0871.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0871.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0871.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0872.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0872.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0872.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0872.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0873.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0873.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0873.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0873.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0874.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0874.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0874.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0874.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0875.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0875.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0875.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0875.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0876.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0876.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0876.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0876.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0877.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0877.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0877.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0877.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0878.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0878.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0878.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0878.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0879.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0879.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0879.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0879.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0880.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0880.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0880.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0880.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0881.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0881.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0881.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0881.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0882.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0882.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0882.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0882.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0883.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0883.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0883.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0883.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0884.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0884.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0884.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0884.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0885.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0885.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0885.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0885.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0886.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0886.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0886.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0886.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0887.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0887.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0887.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0887.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0888.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0888.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0888.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0888.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0889.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0889.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0889.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0889.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0890.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0890.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0890.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0890.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0891.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0891.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0891.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0891.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0892.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0892.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0892.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0892.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0893.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0893.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0893.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0893.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0894.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0894.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0894.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0894.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0895.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0895.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0895.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0895.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0896.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0896.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0896.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0896.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0897.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0897.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0897.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0897.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0898.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0898.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0898.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0898.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0899.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0899.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0899.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0899.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0900.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0900.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0900.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0900.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0901.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0901.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0901.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0901.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0902.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0902.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0902.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0902.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0903.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0903.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0903.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0903.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0904.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0904.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0904.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0904.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0905.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0905.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0905.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0905.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0906.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0906.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0906.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0906.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0907.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0907.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0907.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0907.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0908.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0908.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0908.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0908.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0909.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0909.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0909.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0909.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0910.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0910.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0910.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0910.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0911.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0911.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0911.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0911.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0912.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0912.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0912.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0912.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0913.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0913.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0913.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0913.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0914.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0914.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0914.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0914.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0915.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0915.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0915.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0915.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0916.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0916.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0916.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0916.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0917.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0917.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0917.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0917.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0918.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0918.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0918.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0918.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0919.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0919.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0919.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0919.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0920.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0920.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0920.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0920.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0921.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0921.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0921.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0921.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0922.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0922.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0922.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0922.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0923.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0923.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0923.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0923.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0924.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0924.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0924.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0924.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0925.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0925.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0925.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0925.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0926.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0926.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0926.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0926.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0927.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0927.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0927.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0927.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0928.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0928.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0928.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0928.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0929.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0929.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0929.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0929.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0930.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0930.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0930.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0930.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0931.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0931.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0931.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0931.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0932.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0932.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0932.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0932.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0933.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0933.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0933.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0933.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0934.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0934.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0934.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0934.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0935.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0935.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0935.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0935.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0936.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0936.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0936.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0936.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0937.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0937.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0937.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0937.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0938.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0938.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0938.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0938.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0939.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0939.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0939.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0939.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0940.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0940.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0940.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0940.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0941.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0941.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0941.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0941.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0942.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0942.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0942.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0942.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0943.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0943.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0943.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0943.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0944.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0944.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0944.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0944.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0945.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0945.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0945.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0945.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0946.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0946.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0946.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0946.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0947.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0947.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0947.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0947.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0948.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0948.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0948.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0948.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0949.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0949.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0949.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0949.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0950.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0950.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0950.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0950.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0951.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0951.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0951.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0951.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0952.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0952.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0952.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0952.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0953.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0953.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0953.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0953.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0954.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0954.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0954.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0954.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0955.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0955.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0955.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0955.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0956.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0956.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0956.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0956.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0957.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0957.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0957.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0957.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0958.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0958.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0958.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0958.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0959.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0959.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0959.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0959.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0960.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0960.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0960.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0960.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0961.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0961.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0961.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0961.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0962.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0962.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0962.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0962.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0963.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0963.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0963.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0963.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0964.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0964.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0964.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0964.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0965.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0965.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0965.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0965.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0966.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0966.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0966.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0966.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0967.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0967.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0967.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0967.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0968.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0968.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0968.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0968.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0969.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0969.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0969.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0969.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0970.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0970.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0970.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0970.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0971.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0971.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0971.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0971.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0972.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0972.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0972.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0972.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0973.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0973.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0973.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0973.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0974.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0974.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0974.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0974.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0975.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0975.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0975.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0975.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0976.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0976.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0976.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0976.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0977.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0977.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0977.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0977.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0978.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0978.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0978.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0978.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0979.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0979.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0979.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0979.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0980.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0980.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0980.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0980.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0981.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0981.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0981.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0981.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0982.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0982.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0982.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0982.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0983.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0983.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0983.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0983.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0984.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0984.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0984.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0984.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0985.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0985.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0985.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0985.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0986.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0986.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0986.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0986.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0987.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0987.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0987.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0987.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0988.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0988.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0988.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0988.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0989.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0989.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0989.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0989.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0990.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0990.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0990.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0990.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0991.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0991.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0991.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0991.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0992.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0992.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0992.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0992.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0993.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0993.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0993.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0993.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0994.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0994.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0994.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0994.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0995.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0995.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0995.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0995.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0996.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0996.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0996.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0996.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0997.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0997.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0997.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0997.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0998.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0998.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0998.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0998.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0999.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0999.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0999.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass0999.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass1000.cs b/samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass1000.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass1000.cs
rename to samples/public/mstest-runner/runner_vs_vstest/1000C_100M/MyTestClass1000.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/100C100M.csproj b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/100C100M.csproj
similarity index 75%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/100C100M.csproj
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/100C100M.csproj
index 0e20449f63..41d0a5b53d 100644
--- a/samples/mstest-runner/runner_vs_vstest/100C_100M/100C100M.csproj
+++ b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/100C100M.csproj
@@ -12,9 +12,9 @@
-
-
-
+
+
+
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MSTestConfiguration.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MSTestConfiguration.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MSTestConfiguration.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MSTestConfiguration.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass001.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass001.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass001.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass001.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass002.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass002.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass002.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass002.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass003.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass003.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass003.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass003.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass004.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass004.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass004.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass004.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass005.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass005.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass005.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass005.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass006.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass006.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass006.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass006.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass007.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass007.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass007.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass007.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass008.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass008.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass008.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass008.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass009.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass009.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass009.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass009.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass010.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass010.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass010.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass010.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass011.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass011.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass011.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass011.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass012.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass012.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass012.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass012.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass013.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass013.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass013.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass013.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass014.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass014.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass014.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass014.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass015.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass015.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass015.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass015.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass016.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass016.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass016.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass016.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass017.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass017.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass017.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass017.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass018.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass018.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass018.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass018.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass019.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass019.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass019.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass019.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass020.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass020.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass020.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass020.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass021.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass021.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass021.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass021.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass022.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass022.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass022.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass022.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass023.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass023.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass023.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass023.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass024.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass024.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass024.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass024.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass025.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass025.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass025.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass025.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass026.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass026.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass026.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass026.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass027.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass027.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass027.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass027.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass028.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass028.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass028.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass028.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass029.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass029.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass029.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass029.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass030.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass030.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass030.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass030.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass031.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass031.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass031.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass031.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass032.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass032.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass032.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass032.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass033.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass033.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass033.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass033.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass034.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass034.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass034.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass034.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass035.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass035.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass035.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass035.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass036.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass036.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass036.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass036.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass037.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass037.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass037.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass037.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass038.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass038.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass038.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass038.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass039.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass039.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass039.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass039.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass040.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass040.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass040.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass040.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass041.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass041.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass041.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass041.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass042.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass042.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass042.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass042.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass043.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass043.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass043.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass043.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass044.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass044.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass044.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass044.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass045.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass045.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass045.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass045.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass046.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass046.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass046.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass046.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass047.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass047.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass047.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass047.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass048.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass048.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass048.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass048.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass049.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass049.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass049.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass049.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass050.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass050.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass050.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass050.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass051.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass051.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass051.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass051.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass052.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass052.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass052.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass052.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass053.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass053.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass053.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass053.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass054.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass054.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass054.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass054.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass055.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass055.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass055.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass055.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass056.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass056.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass056.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass056.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass057.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass057.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass057.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass057.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass058.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass058.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass058.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass058.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass059.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass059.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass059.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass059.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass060.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass060.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass060.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass060.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass061.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass061.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass061.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass061.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass062.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass062.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass062.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass062.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass063.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass063.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass063.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass063.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass064.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass064.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass064.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass064.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass065.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass065.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass065.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass065.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass066.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass066.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass066.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass066.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass067.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass067.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass067.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass067.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass068.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass068.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass068.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass068.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass069.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass069.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass069.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass069.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass070.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass070.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass070.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass070.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass071.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass071.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass071.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass071.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass072.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass072.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass072.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass072.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass073.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass073.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass073.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass073.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass074.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass074.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass074.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass074.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass075.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass075.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass075.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass075.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass076.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass076.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass076.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass076.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass077.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass077.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass077.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass077.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass078.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass078.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass078.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass078.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass079.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass079.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass079.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass079.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass080.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass080.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass080.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass080.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass081.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass081.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass081.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass081.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass082.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass082.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass082.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass082.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass083.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass083.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass083.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass083.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass084.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass084.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass084.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass084.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass085.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass085.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass085.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass085.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass086.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass086.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass086.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass086.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass087.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass087.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass087.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass087.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass088.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass088.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass088.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass088.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass089.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass089.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass089.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass089.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass090.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass090.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass090.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass090.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass091.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass091.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass091.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass091.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass092.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass092.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass092.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass092.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass093.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass093.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass093.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass093.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass094.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass094.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass094.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass094.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass095.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass095.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass095.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass095.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass096.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass096.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass096.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass096.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass097.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass097.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass097.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass097.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass098.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass098.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass098.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass098.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass099.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass099.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass099.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass099.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass100.cs b/samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass100.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass100.cs
rename to samples/public/mstest-runner/runner_vs_vstest/100C_100M/MyTestClass100.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/10C100M.csproj b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/10C100M.csproj
similarity index 75%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/10C100M.csproj
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/10C100M.csproj
index 0e20449f63..41d0a5b53d 100644
--- a/samples/mstest-runner/runner_vs_vstest/10C_100M/10C100M.csproj
+++ b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/10C100M.csproj
@@ -12,9 +12,9 @@
-
-
-
+
+
+
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MSTestConfiguration.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MSTestConfiguration.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MSTestConfiguration.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MSTestConfiguration.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass01.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass01.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass01.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass01.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass02.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass02.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass02.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass02.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass03.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass03.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass03.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass03.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass04.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass04.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass04.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass04.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass05.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass05.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass05.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass05.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass06.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass06.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass06.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass06.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass07.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass07.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass07.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass07.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass08.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass08.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass08.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass08.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass09.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass09.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass09.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass09.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass10.cs b/samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass10.cs
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass10.cs
rename to samples/public/mstest-runner/runner_vs_vstest/10C_100M/MyTestClass10.cs
diff --git a/samples/mstest-runner/runner_vs_vstest/README.md b/samples/public/mstest-runner/runner_vs_vstest/README.md
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/README.md
rename to samples/public/mstest-runner/runner_vs_vstest/README.md
diff --git a/samples/mstest-runner/runner_vs_vstest/measure.ps1 b/samples/public/mstest-runner/runner_vs_vstest/measure.ps1
similarity index 100%
rename from samples/mstest-runner/runner_vs_vstest/measure.ps1
rename to samples/public/mstest-runner/runner_vs_vstest/measure.ps1
diff --git a/src/Adapter/MSTest.TestAdapter/BannedSymbols.txt b/src/Adapter/MSTest.TestAdapter/BannedSymbols.txt
new file mode 100644
index 0000000000..91178cbc64
--- /dev/null
+++ b/src/Adapter/MSTest.TestAdapter/BannedSymbols.txt
@@ -0,0 +1 @@
+M:Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers.ReflectHelper.#ctor; This is allowed only for tests.
diff --git a/src/Adapter/MSTest.TestAdapter/Constants.cs b/src/Adapter/MSTest.TestAdapter/Constants.cs
index f8f0c0bb54..057ebb6bfa 100644
--- a/src/Adapter/MSTest.TestAdapter/Constants.cs
+++ b/src/Adapter/MSTest.TestAdapter/Constants.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// 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;
@@ -10,6 +10,36 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
///
internal static class Constants
{
+ ///
+ /// The 3rd level entry (class) name in the hierarchy array.
+ ///
+ internal const string AssemblyFixturesHierarchyClassName = "[Assembly]";
+
+ ///
+ /// Discover fixtures or not.
+ ///
+ internal const string FixturesTestTrait = "FixturesTrait";
+
+ ///
+ /// Assembly initialize.
+ ///
+ internal const string AssemblyInitializeFixtureTrait = "AssemblyInitialize";
+
+ ///
+ /// Assembly cleanup.
+ ///
+ internal const string AssemblyCleanupFixtureTrait = "AssemblyCleanup";
+
+ ///
+ /// Class initialize.
+ ///
+ internal const string ClassInitializeFixtureTrait = "ClassInitialize";
+
+ ///
+ /// Class cleanup.
+ ///
+ internal const string ClassCleanupFixtureTrait = "ClassCleanup";
+
///
/// Uri of the MSTest executor.
///
diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs
index bf0ec5d305..e2a2668ffd 100644
--- a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs
+++ b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.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 System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Runtime.Serialization;
@@ -10,6 +11,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.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FrameworkITestDataSource = Microsoft.VisualStudio.TestTools.UnitTesting.ITestDataSource;
@@ -43,12 +45,10 @@ public AssemblyEnumerator()
///
/// The settings for the session.
/// Use this constructor when creating this object in a new app domain so the settings for this app domain are set.
- public AssemblyEnumerator(MSTestSettings settings)
- {
+ public AssemblyEnumerator(MSTestSettings settings) =>
// Populate the settings into the domain(Desktop workflow) performing discovery.
// This would just be resetting the settings to itself in non desktop workflows.
MSTestSettings.PopulateSettings(settings);
- }
///
/// Gets or sets the run settings to use for current discovery session.
@@ -76,9 +76,10 @@ public AssemblyEnumerator(MSTestSettings settings)
internal ICollection EnumerateAssembly(string assemblyFileName, out ICollection warnings)
{
DebugEx.Assert(!StringEx.IsNullOrWhiteSpace(assemblyFileName), "Invalid assembly file name.");
-
var warningMessages = new List();
var tests = new List();
+ // Contains list of assembly/class names for which we have already added fixture tests.
+ var fixturesTests = new HashSet();
Assembly assembly = PlatformServiceProvider.Instance.FileOperations.LoadAssembly(assemblyFileName, isReflectionOnly: false);
@@ -87,6 +88,10 @@ internal ICollection EnumerateAssembly(string assemblyFileName,
TestIdGenerationStrategy testIdGenerationStrategy = assembly.GetCustomAttribute()?.Strategy
?? TestIdGenerationStrategy.FullyQualified;
+ // Set the test ID generation strategy for the data row attribute so we can improve display name without causing
+ // a breaking change.
+ DataRowAttribute.TestIdGenerationStrategy = testIdGenerationStrategy;
+
TestDataSourceDiscoveryOption testDataSourceDiscovery = assembly.GetCustomAttribute()?.DiscoveryOption
#pragma warning disable CS0618 // Type or member is obsolete
@@ -104,7 +109,7 @@ internal ICollection EnumerateAssembly(string assemblyFileName,
}
List testsInType = DiscoverTestsInType(assemblyFileName, RunSettingsXml, type, warningMessages, discoverInternals,
- testDataSourceDiscovery, testIdGenerationStrategy);
+ testDataSourceDiscovery, testIdGenerationStrategy, fixturesTests);
tests.AddRange(testsInType);
}
@@ -119,12 +124,11 @@ internal ICollection EnumerateAssembly(string assemblyFileName,
/// The file name of the assembly.
/// Contains warnings if any, that need to be passed back to the caller.
/// Gets the types defined in the provided assembly.
- internal static IReadOnlyList GetTypes(Assembly assembly, string assemblyFileName, ICollection? warningMessages)
+ internal static Type[] GetTypes(Assembly assembly, string assemblyFileName, ICollection? warningMessages)
{
- var types = new List();
try
{
- types.AddRange(assembly.DefinedTypes.Select(typeInfo => typeInfo.AsType()));
+ return assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
@@ -146,8 +150,6 @@ internal static IReadOnlyList GetTypes(Assembly assembly, string assemblyF
return ex.Types!;
}
-
- return types;
}
///
@@ -191,19 +193,26 @@ internal static string GetLoadExceptionDetails(ReflectionTypeLoadException ex)
/// The reflected assembly name.
/// True to discover test classes which are declared internal in
/// addition to test classes which are declared public.
+ /// to use when generating tests.
/// to use when generating TestId.
/// a TypeEnumerator instance.
- internal virtual TypeEnumerator GetTypeEnumerator(Type type, string assemblyFileName, bool discoverInternals, TestIdGenerationStrategy testIdGenerationStrategy)
+ internal virtual TypeEnumerator GetTypeEnumerator(Type type, string assemblyFileName, bool discoverInternals, TestDataSourceDiscoveryOption discoveryOption, TestIdGenerationStrategy testIdGenerationStrategy)
{
var typeValidator = new TypeValidator(ReflectHelper, discoverInternals);
var testMethodValidator = new TestMethodValidator(ReflectHelper, discoverInternals);
- return new TypeEnumerator(type, assemblyFileName, ReflectHelper, typeValidator, testMethodValidator, testIdGenerationStrategy);
+ return new TypeEnumerator(type, assemblyFileName, ReflectHelper, typeValidator, testMethodValidator, discoveryOption, testIdGenerationStrategy);
}
- private List DiscoverTestsInType(string assemblyFileName, string? runSettingsXml, Type type,
- List warningMessages, bool discoverInternals, TestDataSourceDiscoveryOption discoveryOption,
- TestIdGenerationStrategy testIdGenerationStrategy)
+ private List DiscoverTestsInType(
+ string assemblyFileName,
+ [StringSyntax(StringSyntaxAttribute.Xml, nameof(runSettingsXml))] string? runSettingsXml,
+ Type type,
+ List warningMessages,
+ bool discoverInternals,
+ TestDataSourceDiscoveryOption discoveryOption,
+ TestIdGenerationStrategy testIdGenerationStrategy,
+ HashSet fixturesTests)
{
IDictionary tempSourceLevelParameters = PlatformServiceProvider.Instance.SettingsProvider.GetProperties(assemblyFileName);
tempSourceLevelParameters = RunSettingsUtilities.GetTestRunParameters(runSettingsXml)?.ConcatWithOverwrites(tempSourceLevelParameters)
@@ -217,14 +226,9 @@ private List DiscoverTestsInType(string assemblyFileName, strin
try
{
typeFullName = type.FullName;
- TypeEnumerator testTypeEnumerator = GetTypeEnumerator(type, assemblyFileName, discoverInternals, testIdGenerationStrategy);
- ICollection? unitTestCases = testTypeEnumerator.Enumerate(out ICollection? warningsFromTypeEnumerator);
- bool typeIgnored = ReflectHelper.IsAttributeDefined(type, false);
-
- if (warningsFromTypeEnumerator != null)
- {
- warningMessages.AddRange(warningsFromTypeEnumerator);
- }
+ TypeEnumerator testTypeEnumerator = GetTypeEnumerator(type, assemblyFileName, discoverInternals, discoveryOption, testIdGenerationStrategy);
+ ICollection? unitTestCases = testTypeEnumerator.Enumerate(out ICollection warningsFromTypeEnumerator);
+ warningMessages.AddRange(warningsFromTypeEnumerator);
if (unitTestCases != null)
{
@@ -232,7 +236,15 @@ private List DiscoverTestsInType(string assemblyFileName, strin
{
if (discoveryOption == TestDataSourceDiscoveryOption.DuringDiscovery)
{
- if (DynamicDataAttached(sourceLevelParameters, test, tests))
+ Lazy testMethodInfo = GetTestMethodInfo(sourceLevelParameters, test);
+
+ // Add fixture tests like AssemblyInitialize, AssemblyCleanup, ClassInitialize, ClassCleanup.
+ if (MSTestSettings.CurrentSettings.ConsiderFixturesAsSpecialTests && testMethodInfo.Value is not null)
+ {
+ AddFixtureTests(testMethodInfo.Value, tests, fixturesTests);
+ }
+
+ if (DynamicDataAttached(test, testMethodInfo, tests))
{
continue;
}
@@ -254,7 +266,18 @@ private List DiscoverTestsInType(string assemblyFileName, strin
return tests;
}
- private bool DynamicDataAttached(IDictionary sourceLevelParameters, UnitTestElement test, List tests)
+ private Lazy GetTestMethodInfo(IDictionary sourceLevelParameters, UnitTestElement test) =>
+ new(() =>
+ {
+ // NOTE: From this place we don't have any path that would let the user write a message on the TestContext and we don't do
+ // anything with what would be printed anyway so we can simply use a simple StringWriter.
+ using var writer = new StringWriter();
+ TestMethod testMethod = test.TestMethod;
+ MSTestAdapter.PlatformServices.Interface.ITestContext testContext = PlatformServiceProvider.Instance.GetTestContext(testMethod, writer, sourceLevelParameters);
+ return _typeCache.GetTestMethodInfo(testMethod, testContext, MSTestSettings.CurrentSettings.CaptureDebugTraces);
+ });
+
+ private static bool DynamicDataAttached(UnitTestElement test, Lazy testMethodInfo, List tests)
{
// It should always be `true`, but if any part of the chain is obsolete; it might not contain those.
// Since we depend on those properties, if they don't exist, we bail out early.
@@ -263,24 +286,113 @@ private bool DynamicDataAttached(IDictionary sourceLevelParamet
return false;
}
- // NOTE: From this place we don't have any path that would let the user write a message on the TestContext and we don't do
- // anything with what would be printed anyway so we can simply use a simple StringWriter.
- using var writer = new StringWriter();
- TestMethod testMethod = test.TestMethod;
- MSTestAdapter.PlatformServices.Interface.ITestContext testContext = PlatformServiceProvider.Instance.GetTestContext(testMethod, writer, sourceLevelParameters);
- TestMethodInfo? testMethodInfo = _typeCache.GetTestMethodInfo(testMethod, testContext, MSTestSettings.CurrentSettings.CaptureDebugTraces);
- return testMethodInfo != null && TryProcessTestDataSourceTests(test, testMethodInfo, tests);
+ if (test.TestMethod.DataType == DynamicDataType.None)
+ {
+ return false;
+ }
+
+ // PERF: For perf we started setting DataType in TypeEnumerator, so when it is None we will not reach this line.
+ // But if we do run this code, we still reset it to None, because the code that determines if this is data drive test expects the value to be None
+ // and only sets it when needed.
+ //
+ // If you remove this line and acceptance tests still pass you are okay.
+ test.TestMethod.DataType = DynamicDataType.None;
+
+ return testMethodInfo.Value != null && TryProcessTestDataSourceTests(test, testMethodInfo.Value, tests);
}
- private static bool TryProcessTestDataSourceTests(UnitTestElement test, TestMethodInfo testMethodInfo, List tests)
+ private static void AddFixtureTests(TestMethodInfo testMethodInfo, List tests, HashSet fixtureTests)
{
- MethodInfo methodInfo = testMethodInfo.MethodInfo;
- IEnumerable? testDataSources = ReflectHelper.GetAttributes(methodInfo, false)?.OfType();
- if (testDataSources == null || !testDataSources.Any())
+ string assemblyName = testMethodInfo.Parent.Parent.Assembly.GetName().Name!;
+ string assemblyLocation = testMethodInfo.Parent.Parent.Assembly.Location;
+ string className = testMethodInfo.Parent.ClassType.Name;
+ string classFullName = testMethodInfo.Parent.ClassType.FullName!;
+
+ // Check if fixtures for this assembly has already been added.
+ if (!fixtureTests.Contains(assemblyLocation))
{
- return false;
+ _ = fixtureTests.Add(assemblyLocation);
+
+ // Add AssemblyInitialize and AssemblyCleanup fixture tests if they exist.
+ if (testMethodInfo.Parent.Parent.AssemblyInitializeMethod is not null)
+ {
+ tests.Add(GetAssemblyFixtureTest(testMethodInfo.Parent.Parent.AssemblyInitializeMethod, assemblyName, className,
+ classFullName, assemblyLocation, Constants.AssemblyInitializeFixtureTrait));
+ }
+
+ if (testMethodInfo.Parent.Parent.AssemblyCleanupMethod is not null)
+ {
+ tests.Add(GetAssemblyFixtureTest(testMethodInfo.Parent.Parent.AssemblyCleanupMethod, assemblyName, className,
+ classFullName, assemblyLocation, Constants.AssemblyCleanupFixtureTrait));
+ }
}
+ // Check if fixtures for this class has already been added.
+ if (!fixtureTests.Contains(assemblyLocation + classFullName))
+ {
+ _ = fixtureTests.Add(assemblyLocation + classFullName);
+
+ // Add ClassInitialize and ClassCleanup fixture tests if they exist.
+ if (testMethodInfo.Parent.ClassInitializeMethod is not null)
+ {
+ tests.Add(GetClassFixtureTest(testMethodInfo.Parent.ClassInitializeMethod, assemblyName, className, classFullName,
+ assemblyLocation, Constants.ClassInitializeFixtureTrait));
+ }
+
+ if (testMethodInfo.Parent.ClassCleanupMethod is not null)
+ {
+ tests.Add(GetClassFixtureTest(testMethodInfo.Parent.ClassCleanupMethod, assemblyName, className, classFullName,
+ assemblyLocation, Constants.ClassCleanupFixtureTrait));
+ }
+ }
+
+ static UnitTestElement GetAssemblyFixtureTest(MethodInfo methodInfo, string assemblyName, string className, string classFullName,
+ string assemblyLocation, string fixtureType)
+ {
+ string methodName = GetMethodName(methodInfo);
+ string[] hierarchy = [null!, assemblyName, Constants.AssemblyFixturesHierarchyClassName, methodName];
+ return GetFixtureTest(classFullName, assemblyLocation, fixtureType, methodName, hierarchy);
+ }
+
+ static UnitTestElement GetClassFixtureTest(MethodInfo methodInfo, string assemblyName, string className, string classFullName,
+ string assemblyLocation, string fixtureType)
+ {
+ string methodName = GetMethodName(methodInfo);
+ string[] hierarchy = [null!, classFullName, methodName];
+ return GetFixtureTest(classFullName, assemblyLocation, fixtureType, methodName, hierarchy);
+ }
+
+ 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;
+ }
+
+ static UnitTestElement GetFixtureTest(string classFullName, string assemblyLocation, string fixtureType, string methodName, string[] hierarchy)
+ {
+ var method = new TestMethod(classFullName, methodName,
+ hierarchy, methodName, classFullName, assemblyLocation, false,
+ TestIdGenerationStrategy.FullyQualified);
+ return new UnitTestElement(method)
+ {
+ DisplayName = $"[{fixtureType}] {methodName}",
+ Ignored = true,
+ Traits = [new Trait(Constants.FixturesTestTrait, fixtureType)],
+ };
+ }
+ }
+
+ private static bool TryProcessTestDataSourceTests(UnitTestElement test, TestMethodInfo testMethodInfo, List tests)
+ {
+ MethodInfo methodInfo = testMethodInfo.MethodInfo;
+
+ // 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(methodInfo, inherit: false).OfType();
+
try
{
return ProcessTestDataSourceTests(test, methodInfo, testDataSources, tests);
@@ -298,14 +410,24 @@ private static bool ProcessTestDataSourceTests(UnitTestElement test, MethodInfo
{
foreach (FrameworkITestDataSource dataSource in testDataSources)
{
- IEnumerable
-
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/RoslynAnalyzerHelpers/.editorconfig b/src/Analyzers/MSTest.Analyzers.CodeFixes/RoslynAnalyzerHelpers/.editorconfig
new file mode 100644
index 0000000000..89b66eaea7
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/RoslynAnalyzerHelpers/.editorconfig
@@ -0,0 +1,36 @@
+root = false
+
+[*.cs]
+
+dotnet_diagnostic.IDE0003.severity = none
+dotnet_diagnostic.IDE0005.severity = none
+dotnet_diagnostic.IDE0008.severity = none
+dotnet_diagnostic.IDE0011.severity = none
+dotnet_diagnostic.IDE0045.severity = none
+dotnet_diagnostic.IDE0046.severity = none
+dotnet_diagnostic.IDE0073.severity = none
+dotnet_diagnostic.IDE0161.severity = none
+dotnet_diagnostic.IDE1006.severity = none
+
+dotnet_diagnostic.SA1025.severity = none
+dotnet_diagnostic.SA1028.severity = none
+dotnet_diagnostic.SA1108.severity = none
+dotnet_diagnostic.SA1116.severity = none
+dotnet_diagnostic.SA1127.severity = none
+dotnet_diagnostic.SA1201.severity = none
+dotnet_diagnostic.SA1214.severity = none
+dotnet_diagnostic.SA1311.severity = none
+dotnet_diagnostic.SA1314.severity = none
+dotnet_diagnostic.SA1405.severity = none
+dotnet_diagnostic.SA1413.severity = none
+dotnet_diagnostic.SA1502.severity = none
+dotnet_diagnostic.SA1503.severity = none
+dotnet_diagnostic.SA1512.severity = none
+dotnet_diagnostic.SA1516.severity = none
+dotnet_diagnostic.SA1602.severity = none
+dotnet_diagnostic.SA1604.severity = none
+dotnet_diagnostic.SA1618.severity = none
+dotnet_diagnostic.SA1629.severity = none
+dotnet_diagnostic.SA1636.severity = none
+
+dotnet_diagnostic.RS1035.severity = none
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/RoslynAnalyzerHelpers/DocumentExtensions.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/RoslynAnalyzerHelpers/DocumentExtensions.cs
new file mode 100644
index 0000000000..e85c187589
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/RoslynAnalyzerHelpers/DocumentExtensions.cs
@@ -0,0 +1,44 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+#if !MICROSOFT_CODEANALYSIS_PUBLIC_API_ANALYZERS
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Microsoft.CodeAnalysis;
+
+namespace Analyzer.Utilities
+{
+ internal static class DocumentExtensions
+ {
+ public static async ValueTask GetRequiredSemanticModelAsync(this Document document, CancellationToken cancellationToken)
+ {
+ if (document.TryGetSemanticModel(out var semanticModel))
+ return semanticModel;
+
+ semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
+ return semanticModel ?? throw new InvalidOperationException("SyntaxTree is required to accomplish the task but is not supported by document");
+ }
+
+ public static async ValueTask GetRequiredSyntaxTreeAsync(this Document document, CancellationToken cancellationToken)
+ {
+ if (document.TryGetSyntaxTree(out var syntaxTree))
+ return syntaxTree;
+
+ syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
+ return syntaxTree ?? throw new InvalidOperationException("SyntaxTree is required to accomplish the task but is not supported by document");
+ }
+
+ public static async ValueTask GetRequiredSyntaxRootAsync(this Document document, CancellationToken cancellationToken)
+ {
+ if (document.TryGetSyntaxRoot(out var root))
+ return root;
+
+ root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+ return root ?? throw new InvalidOperationException("SyntaxTree is required to accomplish the task but is not supported by document");
+ }
+ }
+}
+
+#endif
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/TestCleanupShouldBeValidFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/TestCleanupShouldBeValidFixer.cs
new file mode 100644
index 0000000000..bad2decb21
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/TestCleanupShouldBeValidFixer.cs
@@ -0,0 +1,47 @@
+// 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 MSTest.Analyzers.Helpers;
+
+namespace MSTest.Analyzers;
+
+[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(TestCleanupShouldBeValidFixer))]
+[Shared]
+public sealed class TestCleanupShouldBeValidFixer : CodeFixProvider
+{
+ public sealed override ImmutableArray FixableDiagnosticIds { get; }
+ = ImmutableArray.Create(DiagnosticIds.TestCleanupShouldBeValidRuleId);
+
+ 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 override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ SyntaxNode root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ SyntaxNode node = root.FindNode(context.Span);
+ if (node == null)
+ {
+ return;
+ }
+
+ if (context.Diagnostics.Any(d => !d.Properties.ContainsKey(DiagnosticDescriptorHelper.CannotFixPropertyKey)))
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ CodeFixResources.FixSignatureCodeFix,
+ ct => FixtureMethodFixer.FixSignatureAsync(context.Document, root, node, isParameterLess: true, shouldBeStatic: false, ct),
+ nameof(TestCleanupShouldBeValidFixer)),
+ context.Diagnostics);
+ }
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/TestInitializeShouldBeValidFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/TestInitializeShouldBeValidFixer.cs
new file mode 100644
index 0000000000..dec0fe9cee
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/TestInitializeShouldBeValidFixer.cs
@@ -0,0 +1,47 @@
+// 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 MSTest.Analyzers.Helpers;
+
+namespace MSTest.Analyzers;
+
+[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(TestInitializeShouldBeValidFixer))]
+[Shared]
+public sealed class TestInitializeShouldBeValidFixer : CodeFixProvider
+{
+ public sealed override ImmutableArray FixableDiagnosticIds { get; }
+ = ImmutableArray.Create(DiagnosticIds.TestInitializeShouldBeValidRuleId);
+
+ 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 override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ SyntaxNode root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ SyntaxNode node = root.FindNode(context.Span);
+ if (node == null)
+ {
+ return;
+ }
+
+ if (context.Diagnostics.Any(d => !d.Properties.ContainsKey(DiagnosticDescriptorHelper.CannotFixPropertyKey)))
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ CodeFixResources.FixSignatureCodeFix,
+ ct => FixtureMethodFixer.FixSignatureAsync(context.Document, root, node, isParameterLess: true, shouldBeStatic: false, ct),
+ nameof(TestInitializeShouldBeValidFixer)),
+ context.Diagnostics);
+ }
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/UseParallelizeAttributeFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/UseParallelizeAttributeFixer.cs
deleted file mode 100644
index 09881605ea..0000000000
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/UseParallelizeAttributeFixer.cs
+++ /dev/null
@@ -1,25 +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.Collections.Immutable;
-using System.Composition;
-
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CodeFixes;
-
-namespace MSTest.Analyzers;
-
-[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseParallelizeAttributeFixer))]
-[Shared]
-public sealed class UseParallelizeAttributeFixer : CodeFixProvider
-{
- public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Empty;
-
- 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 override Task RegisterCodeFixesAsync(CodeFixContext context) =>
- // Fixer not yet implemented.
- Task.CompletedTask;
-}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf
index d7844f6b33..4c7b6c42df 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- Převést na velká písmena
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ Opravit pořadí skutečných/očekávaných argumentů
+
+
+
+ Fix signature
+ Opravit podpis
+
+
+
+ Fix signature
+ Opravit podpis
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.de.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.de.xlf
index 895ba0a996..cfbe1881b8 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.de.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.de.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- In Großbuchstaben umwandeln
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ Reihenfolge der tatsächlichen/erwarteten Argumente korrigieren
+
+
+
+ Fix signature
+ Signatur korrigieren
+
+
+
+ Fix signature
+ Signatur korrigieren
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.es.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.es.xlf
index 44ee0ef015..267f7a3ff9 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.es.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.es.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- Poner en mayúsculas
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ Corregir el orden de los argumentos reales o esperados
+
+
+
+ Fix signature
+ Corregir firma
+
+
+
+ Fix signature
+ Corregir firma
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.fr.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.fr.xlf
index 2edae75093..7ff9b41620 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.fr.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.fr.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- Mettre en majuscules
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ Corriger l’ordre des arguments réels/attendus
+
+
+
+ Fix signature
+ Corriger la signature numérique
+
+
+
+ Fix signature
+ Corriger la signature numérique
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.it.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.it.xlf
index d5cdfbbf88..60c8f6be20 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.it.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.it.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- Rendi maiuscola
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ Correggi l'ordine degli argomenti effettivi/previsti
+
+
+
+ Fix signature
+ Correggi firma
+
+
+
+ Fix signature
+ Correggi firma
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ja.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ja.xlf
index 0f8364dbc2..3712abe1d2 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ja.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ja.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- 大文字に変換
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ 実際の引数と予想される引数の順序を修正する
+
+
+
+ Fix signature
+ 署名の修正
+
+
+
+ Fix signature
+ 署名の修正
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ko.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ko.xlf
index e062c13e77..ec3b6d4afe 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ko.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ko.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- 대문자 만들기
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ 실제/예상 인수 순서 수정
+
+
+
+ Fix signature
+ 서명 수정
+
+
+
+ Fix signature
+ 서명 수정
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pl.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pl.xlf
index 5886202787..79426e9b66 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pl.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pl.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- Zmiana na wielkie litery
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ Napraw rzeczywistą/oczekiwaną kolejność argumentów
+
+
+
+ Fix signature
+ Popraw podpis
+
+
+
+ Fix signature
+ Popraw podpis
+
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 af006c5f64..0d39f1845c 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pt-BR.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.pt-BR.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- Tornar maiúsculas
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ Corrigir ordem de argumentos real/esperada
+
+
+
+ Fix signature
+ Corrigir assinatura
+
+
+
+ Fix signature
+ Corrigir assinatura
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ru.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ru.xlf
index a6ac452e67..2a7f059394 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ru.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.ru.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- Сделать прописными
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ Исправить порядок фактических и ожидаемых аргументов
+
+
+
+ Fix signature
+ Исправить подпись
+
+
+
+ Fix signature
+ Исправить подпись
+
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.tr.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.tr.xlf
index a4ed406fa9..379fd8b09e 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.tr.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.tr.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- Büyük harfe dönüştür
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ Fiili/beklenen bağımsız değişken sırasını düzelt
+
+
+
+ Fix signature
+ İmzayı düzelt
+
+
+
+ Fix signature
+ İmzayı düzelt
+
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 9b59710b58..6109110c83 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hans.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hans.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- 转换为大写
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ 修复实际/预期参数顺序
+
+
+
+ Fix signature
+ 修复签名
+
+
+
+ Fix signature
+ 修复签名
+
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 c0121ba11a..cb1527e569 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hant.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.zh-Hant.xlf
@@ -2,10 +2,20 @@
-
- Make uppercase
- 設成大寫
- The title of the code fix.
+
+ Fix actual/expected arguments order
+ 修正實際/預期的引數順序
+
+
+
+ Fix signature
+ 修正簽章
+
+
+
+ Fix signature
+ 修正簽章
+
diff --git a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Shipped.md b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Shipped.md
index a253cdd0b6..efd829aa0c 100644
--- a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Shipped.md
+++ b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Shipped.md
@@ -1,4 +1,19 @@
-## Release 3.3.0
+## Release 3.4.0
+
+### New Rules
+
+Rule ID | Category | Severity | Notes
+--------|----------|----------|-------
+MSTEST0017 | Usage | Info | AssertionArgsShouldBePassedInCorrectOrder, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0017)
+MSTEST0019 | Design | Disabled | PreferTestInitializeOverConstructorAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0019)
+MSTEST0020 | Design | Disabled | PreferConstructorOverTestInitializeAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0020)
+MSTEST0021 | Design | Disabled | PreferDisposeOverTestCleanupAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0021)
+MSTEST0022 | Design | Disabled | PreferTestCleanupOverDisposeAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0022)
+MSTEST0023 | Usage | Info | DoNotNegateBooleanAssertionAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0023)
+MSTEST0024 | Usage | Info | DoNotStoreStaticTestContextAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0024)
+MSTEST0025 | Usage | Info | PreferAssertFailOverAlwaysFalseConditionsAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0025)
+
+## Release 3.3.0
### New Rules
diff --git a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md
index 6f9452a4df..18a88eed2e 100644
--- a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md
+++ b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md
@@ -1,14 +1,12 @@
; Unshipped analyzer release
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
+
### New Rules
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
-MSTEST0017 | Usage | Info | AssertionArgsShouldBePassedInCorrectOrder, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0017)
-MSTEST0019 | Design | Disabled | PreferTestInitializeOverConstructorAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0019)
-MSTEST0020 | Design | Disabled | PreferConstructorOverTestInitializeAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0020)
-MSTEST0021 | Design | Disabled | PreferDisposeOverTestCleanupAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0021)
-MSTEST0022 | Design | Disabled | PreferTestCleanupOverDisposeAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0022)
-MSTEST0023 | Usage | Info | DoNotNegateBooleanAssertionAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0023)
-MSTEST0024 | Usage | Info | DoNotStoreStaticTestContextAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0024)
-MSTEST0025 | Usage | Info | PreferAssertFailOverAlwaysFalseConditionsAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0025)
+MSTEST0026 | Usage | Info | AssertionArgsShouldAvoidConditionalAccessRuleId, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0026)
+MSTEST0029 | Design | Disabled | PublicMethodShouldBeTestMethodAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0029)
+MSTEST0030 | Usage | Info | TypeContainingTestMethodShouldBeATestClassAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0030)
+MSTEST0031 | Usage | Info | DoNotUseSystemDescriptionAttributeAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0031)
+MSTEST0032 | Usage | Info | ReviewAlwaysTrueAssertConditionAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0032)
diff --git a/src/Analyzers/MSTest.Analyzers/AssemblyCleanupShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AssemblyCleanupShouldBeValidAnalyzer.cs
index 6073570a56..df919b1b36 100644
--- a/src/Analyzers/MSTest.Analyzers/AssemblyCleanupShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/AssemblyCleanupShouldBeValidAnalyzer.cs
@@ -12,32 +12,22 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0013: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AssemblyCleanupShouldBeValidAnalyzer : DiagnosticAnalyzer
{
- private static readonly LocalizableResourceString Title = new(nameof(Resources.AssemblyCleanupShouldBeValidTitle), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString Description = new(nameof(Resources.AssemblyCleanupShouldBeValidDescription), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.AssemblyCleanupShouldBeValidMessageFormat_Public), Resources.ResourceManager, typeof(Resources));
-
- internal static readonly DiagnosticDescriptor PublicRule = DiagnosticDescriptorHelper.Create(
+ internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
DiagnosticIds.AssemblyCleanupShouldBeValidRuleId,
- Title,
- MessageFormat,
- Description,
+ new LocalizableResourceString(nameof(Resources.AssemblyCleanupShouldBeValidTitle), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.AssemblyCleanupShouldBeValidMessageFormat), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.AssemblyCleanupShouldBeValidDescription), Resources.ResourceManager, typeof(Resources)),
Category.Usage,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
- internal static readonly DiagnosticDescriptor StaticRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyCleanupShouldBeValidMessageFormat_Static), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NoParametersRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyCleanupShouldBeValidMessageFormat_NoParameters), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor ReturnTypeRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyCleanupShouldBeValidMessageFormat_ReturnType), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAsyncVoidRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyCleanupShouldBeValidMessageFormat_NotAsyncVoid), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotGenericRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyCleanupShouldBeValidMessageFormat_NotGeneric), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor OrdinaryRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyCleanupShouldBeValidMessageFormat_Ordinary), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAGenericClassRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyCleanupShouldBeValidMessageFormat_NotAGenericClass), Resources.ResourceManager, typeof(Resources)));
-
- public override ImmutableArray SupportedDiagnostics { get; }
- = ImmutableArray.Create(PublicRule);
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
@@ -46,20 +36,20 @@ public override void Initialize(AnalysisContext context)
context.RegisterCompilationStartAction(context =>
{
- if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyCleanupAttribute, out INamedTypeSymbol? assemblyCleanupAttributeSymbol))
+ if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyCleanupAttribute, out INamedTypeSymbol? assemblyCleanupAttributeSymbol)
+ && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol))
{
INamedTypeSymbol? taskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask);
INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask);
bool canDiscoverInternals = context.Compilation.CanDiscoverInternals();
context.RegisterSymbolAction(
- context => AnalyzeSymbol(context, assemblyCleanupAttributeSymbol, taskSymbol, valueTaskSymbol, canDiscoverInternals),
+ context => AnalyzeSymbol(context, assemblyCleanupAttributeSymbol, testClassAttributeSymbol, taskSymbol, valueTaskSymbol, canDiscoverInternals),
SymbolKind.Method);
}
});
}
- private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol assemblyCleanupAttributeSymbol, INamedTypeSymbol? taskSymbol,
- INamedTypeSymbol? valueTaskSymbol, bool canDiscoverInternals)
+ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol assemblyCleanupAttributeSymbol, INamedTypeSymbol testClassAttributeSymbol, INamedTypeSymbol? taskSymbol, INamedTypeSymbol? valueTaskSymbol, bool canDiscoverInternals)
{
var methodSymbol = (IMethodSymbol)context.Symbol;
@@ -68,49 +58,11 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo
return;
}
- if (methodSymbol.MethodKind != MethodKind.Ordinary)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(OrdinaryRule, methodSymbol.Name));
-
- // Do not check the other criteria, users should fix the method kind first.
- return;
- }
-
- if (context.Symbol.ContainingType.IsGenericType)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAGenericClassRule, methodSymbol.Name));
- }
-
- if (methodSymbol.Parameters.Length > 0)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NoParametersRule, methodSymbol.Name));
- }
-
- if (methodSymbol.IsGenericMethod)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotGenericRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsStatic)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(StaticRule, methodSymbol.Name));
- }
-
- if (methodSymbol.ReturnsVoid && methodSymbol.IsAsync)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAsyncVoidRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsPublicAndHasCorrectResultantVisibility(canDiscoverInternals))
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(PublicRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.ReturnsVoid
- && (taskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, taskSymbol))
- && (valueTaskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, valueTaskSymbol)))
+ if (!methodSymbol.HasValidFixtureMethodSignature(taskSymbol, valueTaskSymbol, canDiscoverInternals, shouldBeStatic: true, allowGenericType: false, testContextSymbol: null, testClassAttributeSymbol, fixtureAllowInheritedTestClass: false, out bool isFixable))
{
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(ReturnTypeRule, methodSymbol.Name));
+ context.ReportDiagnostic(isFixable
+ ? methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name)
+ : methodSymbol.CreateDiagnostic(Rule, DiagnosticDescriptorHelper.CannotFixProperties, methodSymbol.Name));
}
}
}
diff --git a/src/Analyzers/MSTest.Analyzers/AssemblyInitializeShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AssemblyInitializeShouldBeValidAnalyzer.cs
index b0f2e90a05..b547b9b71a 100644
--- a/src/Analyzers/MSTest.Analyzers/AssemblyInitializeShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/AssemblyInitializeShouldBeValidAnalyzer.cs
@@ -12,32 +12,22 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0012: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AssemblyInitializeShouldBeValidAnalyzer : DiagnosticAnalyzer
{
- private static readonly LocalizableResourceString Title = new(nameof(Resources.AssemblyInitializeShouldBeValidTitle), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString Description = new(nameof(Resources.AssemblyInitializeShouldBeValidDescription), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.AssemblyInitializeShouldBeValidMessageFormat_Public), Resources.ResourceManager, typeof(Resources));
-
- internal static readonly DiagnosticDescriptor PublicRule = DiagnosticDescriptorHelper.Create(
+ internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
DiagnosticIds.AssemblyInitializeShouldBeValidRuleId,
- Title,
- MessageFormat,
- Description,
+ new LocalizableResourceString(nameof(Resources.AssemblyInitializeShouldBeValidTitle), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.AssemblyInitializeShouldBeValidMessageFormat), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.AssemblyInitializeShouldBeValidDescription), Resources.ResourceManager, typeof(Resources)),
Category.Usage,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
- internal static readonly DiagnosticDescriptor StaticRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyInitializeShouldBeValidMessageFormat_Static), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor SingleContextParameterRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyInitializeShouldBeValidMessageFormat_SingleContextParameter), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor ReturnTypeRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyInitializeShouldBeValidMessageFormat_ReturnType), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAsyncVoidRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyInitializeShouldBeValidMessageFormat_NotAsyncVoid), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotGenericRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyInitializeShouldBeValidMessageFormat_NotGeneric), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor OrdinaryRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyInitializeShouldBeValidMessageFormat_Ordinary), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAGenericClassRule = PublicRule.WithMessage(new(nameof(Resources.AssemblyInitializeShouldBeValidMessageFormat_NotAGenericClass), Resources.ResourceManager, typeof(Resources)));
-
- public override ImmutableArray SupportedDiagnostics { get; }
- = ImmutableArray.Create(PublicRule);
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
@@ -47,72 +37,31 @@ public override void Initialize(AnalysisContext context)
context.RegisterCompilationStartAction(context =>
{
if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyInitializeAttribute, out INamedTypeSymbol? assemblyInitializeAttributeSymbol)
- && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestContext, out INamedTypeSymbol? testContextSymbol))
+ && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestContext, out INamedTypeSymbol? testContextSymbol)
+ && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol))
{
INamedTypeSymbol? taskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask);
INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask);
bool canDiscoverInternals = context.Compilation.CanDiscoverInternals();
context.RegisterSymbolAction(
- context => AnalyzeSymbol(context, assemblyInitializeAttributeSymbol, taskSymbol, valueTaskSymbol, testContextSymbol, canDiscoverInternals),
+ context => AnalyzeSymbol(context, assemblyInitializeAttributeSymbol, taskSymbol, valueTaskSymbol, testContextSymbol, testClassAttributeSymbol, canDiscoverInternals),
SymbolKind.Method);
}
});
}
private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol assemblyInitializeAttributeSymbol, INamedTypeSymbol? taskSymbol,
- INamedTypeSymbol? valueTaskSymbol, INamedTypeSymbol? testContextSymbol, bool canDiscoverInternals)
+ INamedTypeSymbol? valueTaskSymbol, INamedTypeSymbol testContextSymbol, INamedTypeSymbol testClassAttributeSymbol, bool canDiscoverInternals)
{
var methodSymbol = (IMethodSymbol)context.Symbol;
- if (!methodSymbol.IsAssemblyInitializeMethod(assemblyInitializeAttributeSymbol))
- {
- return;
- }
-
- if (methodSymbol.MethodKind != MethodKind.Ordinary)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(OrdinaryRule, methodSymbol.Name));
-
- // Do not check the other criteria, users should fix the method kind first.
- return;
- }
-
- if (context.Symbol.ContainingType.IsGenericType)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAGenericClassRule, methodSymbol.Name));
- }
-
- if (methodSymbol.Parameters.Length != 1 || testContextSymbol is null ||
- !SymbolEqualityComparer.Default.Equals(methodSymbol.Parameters[0].Type, testContextSymbol))
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(SingleContextParameterRule, methodSymbol.Name));
- }
-
- if (methodSymbol.IsGenericMethod)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotGenericRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsStatic)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(StaticRule, methodSymbol.Name));
- }
-
- if (methodSymbol.ReturnsVoid && methodSymbol.IsAsync)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAsyncVoidRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsPublicAndHasCorrectResultantVisibility(canDiscoverInternals))
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(PublicRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.ReturnsVoid
- && (taskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, taskSymbol))
- && (valueTaskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, valueTaskSymbol)))
+ if (methodSymbol.IsAssemblyInitializeMethod(assemblyInitializeAttributeSymbol)
+ && !methodSymbol.HasValidFixtureMethodSignature(taskSymbol, valueTaskSymbol, canDiscoverInternals, shouldBeStatic: true,
+ allowGenericType: false, testContextSymbol, testClassAttributeSymbol, fixtureAllowInheritedTestClass: false, out bool isFixable))
{
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(ReturnTypeRule, methodSymbol.Name));
+ context.ReportDiagnostic(isFixable
+ ? methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name)
+ : methodSymbol.CreateDiagnostic(Rule, DiagnosticDescriptorHelper.CannotFixProperties, methodSymbol.Name));
}
}
}
diff --git a/src/Analyzers/MSTest.Analyzers/AssertionArgsShouldAvoidConditionalAccessAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AssertionArgsShouldAvoidConditionalAccessAnalyzer.cs
new file mode 100644
index 0000000000..6cfe536e07
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/AssertionArgsShouldAvoidConditionalAccessAnalyzer.cs
@@ -0,0 +1,140 @@
+// 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;
+
+///
+/// MSTEST0026: .
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+public sealed class AssertionArgsShouldAvoidConditionalAccessAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly ImmutableArray AssertSupportedMethodNames = ImmutableArray.Create([
+ "IsTrue",
+ "IsFalse",
+ "AreEqual",
+ "AreNotEqual",
+ "AreSame",
+ "AreNotSame"
+ ]);
+
+ private static readonly ImmutableArray CollectionAssertSupportedMethodNames = ImmutableArray.Create([
+ "IsTrue",
+ "IsFalse",
+ "AreEqual",
+ "AreNotEqual",
+ "AreEquivalent",
+ "AreNotEquivalent",
+ "Contains",
+ "DoesNotContain",
+ "AllItemsAreNotNull",
+ "AllItemsAreUnique",
+ "IsSubsetOf",
+ "IsNotSubsetOf",
+ "AllItemsAreInstancesOfType"
+ ]);
+
+ private static readonly ImmutableArray StringAssertSupportedMethodNames = ImmutableArray.Create([
+ "Contains",
+ "StartsWith",
+ "EndsWith",
+ "Matches",
+ "DoesNotMatch"
+ ]);
+
+ private static readonly LocalizableResourceString Title = new(nameof(Resources.AssertionArgsShouldAvoidConditionalAccessTitle), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.AssertionArgsShouldAvoidConditionalAccessMessageFormat), Resources.ResourceManager, typeof(Resources));
+
+ internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
+ DiagnosticIds.AssertionArgsShouldAvoidConditionalAccessRuleId,
+ Title,
+ MessageFormat,
+ description: 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.MicrosoftVisualStudioTestToolsUnitTestingAssert, out INamedTypeSymbol? assertSymbol))
+ {
+ context.RegisterOperationAction(context => AnalyzeOperation(context, assertSymbol, AssertSupportedMethodNames), OperationKind.Invocation);
+ }
+
+ if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingCollectionAssert, out INamedTypeSymbol? collectionAssertSymbol))
+ {
+ context.RegisterOperationAction(context => AnalyzeOperation(context, collectionAssertSymbol, CollectionAssertSupportedMethodNames), OperationKind.Invocation);
+ }
+
+ if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingStringAssert, out INamedTypeSymbol? stringAssertSymbol))
+ {
+ context.RegisterOperationAction(context => AnalyzeOperation(context, stringAssertSymbol, StringAssertSupportedMethodNames), OperationKind.Invocation);
+ }
+ });
+ }
+
+ private static void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol assertSymbol, ImmutableArray supportedMethodNames)
+ {
+ var invocationOperation = (IInvocationOperation)context.Operation;
+
+ // This is not an invocation of the expected assertion methods.
+ if (!supportedMethodNames.Contains(invocationOperation.TargetMethod.Name)
+ || !SymbolEqualityComparer.Default.Equals(assertSymbol, invocationOperation.TargetMethod.ContainingType)
+ || !HasAnyConditionalAccessOperationChild(invocationOperation))
+ {
+ return;
+ }
+
+ context.ReportDiagnostic(invocationOperation.CreateDiagnostic(Rule));
+ }
+
+ private static bool HasAnyConditionalAccessOperationChild(IInvocationOperation invocationOperation)
+ {
+ foreach (IArgumentOperation argument in invocationOperation.Arguments)
+ {
+ // Check for conditional access
+ // a?.b
+ // a?.b?.c
+ // a.b?.c
+ if (argument.Value is IConditionalAccessOperation { Kind: OperationKind.ConditionalAccess })
+ {
+ return true;
+ }
+
+ // Check for binary operations with conditional access => s?.Length > 1.
+ if (argument.Value is IBinaryOperation binaryOperation)
+ {
+ if (binaryOperation.LeftOperand.Kind == OperationKind.ConditionalAccess || binaryOperation.RightOperand.Kind == OperationKind.ConditionalAccess)
+ {
+ return true;
+ }
+ }
+
+ // Check for conversion operations with conditional access => (s?.Length).
+ if (argument.Value is IConversionOperation { Operand.Kind: OperationKind.ConditionalAccess })
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers/AssertionArgsShouldBePassedInCorrectOrderAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AssertionArgsShouldBePassedInCorrectOrderAnalyzer.cs
index f4ea7a905a..a675d0fc33 100644
--- a/src/Analyzers/MSTest.Analyzers/AssertionArgsShouldBePassedInCorrectOrderAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/AssertionArgsShouldBePassedInCorrectOrderAnalyzer.cs
@@ -14,16 +14,18 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0017: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AssertionArgsShouldBePassedInCorrectOrderAnalyzer : DiagnosticAnalyzer
{
- private static readonly ImmutableArray SupportedMethodNames = ImmutableArray.Create(new[]
- {
+ private static readonly ImmutableArray SupportedMethodNames = ImmutableArray.Create([
"AreEqual",
"AreNotEqual",
"AreSame",
- "AreNotSame",
- });
+ "AreNotSame"
+ ]);
private static readonly LocalizableResourceString Title = new(nameof(Resources.AssertionArgsShouldBePassedInCorrectOrderTitle), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableResourceString Description = new(nameof(Resources.AssertionArgsShouldBePassedInCorrectOrderDescription), Resources.ResourceManager, typeof(Resources));
diff --git a/src/Analyzers/MSTest.Analyzers/AvoidExpectedExceptionAttributeAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AvoidExpectedExceptionAttributeAnalyzer.cs
index f9a30f6644..bf99f5e79f 100644
--- a/src/Analyzers/MSTest.Analyzers/AvoidExpectedExceptionAttributeAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/AvoidExpectedExceptionAttributeAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0006: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AvoidExpectedExceptionAttributeAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/ClassCleanupShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/ClassCleanupShouldBeValidAnalyzer.cs
index b21d47b333..bbee86ef59 100644
--- a/src/Analyzers/MSTest.Analyzers/ClassCleanupShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/ClassCleanupShouldBeValidAnalyzer.cs
@@ -3,7 +3,6 @@
using System.Collections.Immutable;
-using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
@@ -13,32 +12,22 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0011: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class ClassCleanupShouldBeValidAnalyzer : DiagnosticAnalyzer
{
- private static readonly LocalizableResourceString Title = new(nameof(Resources.ClassCleanupShouldBeValidTitle), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString Description = new(nameof(Resources.ClassCleanupShouldBeValidDescription), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.ClassCleanupShouldBeValidMessageFormat_Public), Resources.ResourceManager, typeof(Resources));
-
- internal static readonly DiagnosticDescriptor PublicRule = DiagnosticDescriptorHelper.Create(
+ internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
DiagnosticIds.ClassCleanupShouldBeValidRuleId,
- Title,
- MessageFormat,
- Description,
+ new LocalizableResourceString(nameof(Resources.ClassCleanupShouldBeValidTitle), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.ClassCleanupShouldBeValidMessageFormat), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.ClassCleanupShouldBeValidDescription), Resources.ResourceManager, typeof(Resources)),
Category.Usage,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
- internal static readonly DiagnosticDescriptor StaticRule = PublicRule.WithMessage(new(nameof(Resources.ClassCleanupShouldBeValidMessageFormat_Static), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NoParametersRule = PublicRule.WithMessage(new(nameof(Resources.ClassCleanupShouldBeValidMessageFormat_NoParameters), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor ReturnTypeRule = PublicRule.WithMessage(new(nameof(Resources.ClassCleanupShouldBeValidMessageFormat_ReturnType), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAsyncVoidRule = PublicRule.WithMessage(new(nameof(Resources.ClassCleanupShouldBeValidMessageFormat_NotAsyncVoid), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotGenericRule = PublicRule.WithMessage(new(nameof(Resources.ClassCleanupShouldBeValidMessageFormat_NotGeneric), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor OrdinaryRule = PublicRule.WithMessage(new(nameof(Resources.ClassCleanupShouldBeValidMessageFormat_Ordinary), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAGenericClassUnlessInheritanceModeSetRule = PublicRule.WithMessage(new(nameof(Resources.ClassCleanupShouldBeValidMessageFormat_NotAGenericClassUnlessInheritanceModeSet), Resources.ResourceManager, typeof(Resources)));
-
- public override ImmutableArray SupportedDiagnostics { get; }
- = ImmutableArray.Create(PublicRule);
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
@@ -47,103 +36,33 @@ public override void Initialize(AnalysisContext context)
context.RegisterCompilationStartAction(context =>
{
- if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassCleanupAttribute, out INamedTypeSymbol? classCleanupAttributeSymbol))
+ if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassCleanupAttribute, out INamedTypeSymbol? classCleanupAttributeSymbol)
+ && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol))
{
INamedTypeSymbol? taskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask);
INamedTypeSymbol? inheritanceBehaviorSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingInheritanceBehavior);
INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask);
bool canDiscoverInternals = context.Compilation.CanDiscoverInternals();
context.RegisterSymbolAction(
- context => AnalyzeSymbol(context, classCleanupAttributeSymbol, taskSymbol, valueTaskSymbol, inheritanceBehaviorSymbol, canDiscoverInternals),
+ context => AnalyzeSymbol(context, classCleanupAttributeSymbol, taskSymbol, valueTaskSymbol, inheritanceBehaviorSymbol, testClassAttributeSymbol, canDiscoverInternals),
SymbolKind.Method);
}
});
}
private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol classCleanupAttributeSymbol, INamedTypeSymbol? taskSymbol,
- INamedTypeSymbol? valueTaskSymbol, INamedTypeSymbol? inheritanceBehaviorSymbol, bool canDiscoverInternals)
+ INamedTypeSymbol? valueTaskSymbol, INamedTypeSymbol? inheritanceBehaviorSymbol, INamedTypeSymbol testClassAttributeSymbol, bool canDiscoverInternals)
{
var methodSymbol = (IMethodSymbol)context.Symbol;
- if (!methodSymbol.IsClassCleanupMethod(classCleanupAttributeSymbol))
- {
- return;
- }
-
- if (methodSymbol.MethodKind != MethodKind.Ordinary)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(OrdinaryRule, methodSymbol.Name));
-
- // Do not check the other criteria, users should fix the method kind first.
- return;
- }
-
- if (context.Symbol.ContainingType.IsGenericType)
- {
- bool isInheritanceModeSet = false;
- foreach (AttributeData attr in methodSymbol.GetAttributes())
- {
- if (!SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classCleanupAttributeSymbol))
- {
- continue;
- }
-
- ImmutableArray constructorArguments = attr.ConstructorArguments;
- foreach (TypedConstant constructorArgument in constructorArguments)
- {
- if (!SymbolEqualityComparer.Default.Equals(constructorArgument.Type, inheritanceBehaviorSymbol))
- {
- continue;
- }
-
- // It's an enum so it can't be null
- RoslynDebug.Assert(constructorArgument.Value is not null);
-
- // We need to check that the inheritanceBehavior is not set to none and it's value inside the enum is zero
- if ((int)constructorArgument.Value != 0)
- {
- isInheritanceModeSet = true;
- break;
- }
- }
- }
-
- if (!isInheritanceModeSet)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAGenericClassUnlessInheritanceModeSetRule, methodSymbol.Name));
- }
- }
-
- if (methodSymbol.Parameters.Length > 0)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NoParametersRule, methodSymbol.Name));
- }
-
- if (methodSymbol.IsGenericMethod)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotGenericRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsStatic)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(StaticRule, methodSymbol.Name));
- }
-
- if (methodSymbol.ReturnsVoid && methodSymbol.IsAsync)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAsyncVoidRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsPublicAndHasCorrectResultantVisibility(canDiscoverInternals))
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(PublicRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.ReturnsVoid
- && (taskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, taskSymbol))
- && (valueTaskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, valueTaskSymbol)))
+ if (methodSymbol.IsClassInitializeMethod(classCleanupAttributeSymbol)
+ && !methodSymbol.HasValidFixtureMethodSignature(taskSymbol, valueTaskSymbol, canDiscoverInternals, shouldBeStatic: true,
+ allowGenericType: methodSymbol.IsInheritanceModeSet(inheritanceBehaviorSymbol, classCleanupAttributeSymbol), testContextSymbol: null,
+ testClassAttributeSymbol, fixtureAllowInheritedTestClass: true, out bool isFixable))
{
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(ReturnTypeRule, methodSymbol.Name));
+ context.ReportDiagnostic(isFixable
+ ? methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name)
+ : methodSymbol.CreateDiagnostic(Rule, DiagnosticDescriptorHelper.CannotFixProperties, methodSymbol.Name));
}
}
}
diff --git a/src/Analyzers/MSTest.Analyzers/ClassInitializeShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/ClassInitializeShouldBeValidAnalyzer.cs
index 0805cde6c2..d99a209785 100644
--- a/src/Analyzers/MSTest.Analyzers/ClassInitializeShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/ClassInitializeShouldBeValidAnalyzer.cs
@@ -3,7 +3,6 @@
using System.Collections.Immutable;
-using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
@@ -13,32 +12,22 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0010: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class ClassInitializeShouldBeValidAnalyzer : DiagnosticAnalyzer
{
- private static readonly LocalizableResourceString Title = new(nameof(Resources.ClassInitializeShouldBeValidTitle), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString Description = new(nameof(Resources.ClassInitializeShouldBeValidDescription), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.ClassInitializeShouldBeValidMessageFormat_Public), Resources.ResourceManager, typeof(Resources));
-
- internal static readonly DiagnosticDescriptor PublicRule = DiagnosticDescriptorHelper.Create(
+ internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
DiagnosticIds.ClassInitializeShouldBeValidRuleId,
- Title,
- MessageFormat,
- Description,
+ new LocalizableResourceString(nameof(Resources.ClassInitializeShouldBeValidTitle), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.ClassInitializeShouldBeValidMessageFormat), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.ClassInitializeShouldBeValidDescription), Resources.ResourceManager, typeof(Resources)),
Category.Usage,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
- internal static readonly DiagnosticDescriptor StaticRule = PublicRule.WithMessage(new(nameof(Resources.ClassInitializeShouldBeValidMessageFormat_Static), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor SingleContextParameterRule = PublicRule.WithMessage(new(nameof(Resources.ClassInitializeShouldBeValidMessageFormat_SingleContextParameter), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor ReturnTypeRule = PublicRule.WithMessage(new(nameof(Resources.ClassInitializeShouldBeValidMessageFormat_ReturnType), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAsyncVoidRule = PublicRule.WithMessage(new(nameof(Resources.ClassInitializeShouldBeValidMessageFormat_NotAsyncVoid), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotGenericRule = PublicRule.WithMessage(new(nameof(Resources.ClassInitializeShouldBeValidMessageFormat_NotGeneric), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor OrdinaryRule = PublicRule.WithMessage(new(nameof(Resources.ClassInitializeShouldBeValidMessageFormat_Ordinary), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAGenericClassUnlessInheritanceModeSetRule = PublicRule.WithMessage(new(nameof(Resources.ClassInitializeShouldBeValidMessageFormat_NotAGenericClassUnlessInheritanceModeSet), Resources.ResourceManager, typeof(Resources)));
-
- public override ImmutableArray SupportedDiagnostics { get; }
- = ImmutableArray.Create(PublicRule);
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
@@ -47,105 +36,37 @@ public override void Initialize(AnalysisContext context)
context.RegisterCompilationStartAction(context =>
{
- if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassInitializeAttribute, out INamedTypeSymbol? classInitializeAttributeSymbol)
- && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestContext, out INamedTypeSymbol? testContextSymbol))
+ if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassInitializeAttribute, out INamedTypeSymbol? classInitializeAttributeSymbol)
+ || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestContext, out INamedTypeSymbol? testContextSymbol)
+ || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol))
{
- INamedTypeSymbol? taskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask);
- INamedTypeSymbol? inheritanceBehaviorSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingInheritanceBehavior);
- INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask);
- bool canDiscoverInternals = context.Compilation.CanDiscoverInternals();
- context.RegisterSymbolAction(
- context => AnalyzeSymbol(context, classInitializeAttributeSymbol, taskSymbol, valueTaskSymbol, testContextSymbol, inheritanceBehaviorSymbol, canDiscoverInternals),
- SymbolKind.Method);
+ return;
}
+
+ INamedTypeSymbol? taskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask);
+ INamedTypeSymbol? inheritanceBehaviorSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingInheritanceBehavior);
+ INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask);
+ bool canDiscoverInternals = context.Compilation.CanDiscoverInternals();
+ context.RegisterSymbolAction(
+ context => AnalyzeSymbol(context, classInitializeAttributeSymbol, taskSymbol, valueTaskSymbol, testContextSymbol, inheritanceBehaviorSymbol, testClassAttributeSymbol, canDiscoverInternals),
+ SymbolKind.Method);
});
}
private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol classInitializeAttributeSymbol, INamedTypeSymbol? taskSymbol,
- INamedTypeSymbol? valueTaskSymbol, INamedTypeSymbol? testContextSymbol, INamedTypeSymbol? inheritanceBehaviorSymbol, bool canDiscoverInternals)
+ INamedTypeSymbol? valueTaskSymbol, INamedTypeSymbol testContextSymbol, INamedTypeSymbol? inheritanceBehaviorSymbol, INamedTypeSymbol testClassAttributeSymbol,
+ bool canDiscoverInternals)
{
var methodSymbol = (IMethodSymbol)context.Symbol;
- if (!methodSymbol.IsClassInitializeMethod(classInitializeAttributeSymbol))
- {
- return;
- }
-
- if (methodSymbol.MethodKind != MethodKind.Ordinary)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(OrdinaryRule, methodSymbol.Name));
-
- // Do not check the other criteria, users should fix the method kind first.
- return;
- }
-
- if (context.Symbol.ContainingType.IsGenericType)
- {
- bool isInheritanceModeSet = false;
- foreach (AttributeData attr in methodSymbol.GetAttributes())
- {
- if (!SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classInitializeAttributeSymbol))
- {
- continue;
- }
-
- ImmutableArray constructorArguments = attr.ConstructorArguments;
- foreach (TypedConstant constructorArgument in constructorArguments)
- {
- if (!SymbolEqualityComparer.Default.Equals(constructorArgument.Type, inheritanceBehaviorSymbol))
- {
- continue;
- }
-
- // It's an enum so it can't be null
- RoslynDebug.Assert(constructorArgument.Value is not null);
-
- // We need to check that the inheritanceBehavior is not set to none and it's value inside the enum is zero
- if ((int)constructorArgument.Value != 0)
- {
- isInheritanceModeSet = true;
- break;
- }
- }
- }
-
- if (!isInheritanceModeSet)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAGenericClassUnlessInheritanceModeSetRule, methodSymbol.Name));
- }
- }
-
- if (methodSymbol.Parameters.Length != 1 || testContextSymbol is null ||
- !SymbolEqualityComparer.Default.Equals(methodSymbol.Parameters[0].Type, testContextSymbol))
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(SingleContextParameterRule, methodSymbol.Name));
- }
-
- if (methodSymbol.IsGenericMethod)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotGenericRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsStatic)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(StaticRule, methodSymbol.Name));
- }
-
- if (methodSymbol.ReturnsVoid && methodSymbol.IsAsync)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAsyncVoidRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsPublicAndHasCorrectResultantVisibility(canDiscoverInternals))
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(PublicRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.ReturnsVoid
- && (taskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, taskSymbol))
- && (valueTaskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, valueTaskSymbol)))
+ if (methodSymbol.IsClassInitializeMethod(classInitializeAttributeSymbol)
+ && !methodSymbol.HasValidFixtureMethodSignature(taskSymbol, valueTaskSymbol, canDiscoverInternals, shouldBeStatic: true,
+ allowGenericType: methodSymbol.IsInheritanceModeSet(inheritanceBehaviorSymbol, classInitializeAttributeSymbol), testContextSymbol,
+ testClassAttributeSymbol, fixtureAllowInheritedTestClass: true, out bool isFixable))
{
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(ReturnTypeRule, methodSymbol.Name));
+ context.ReportDiagnostic(isFixable
+ ? methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name)
+ : methodSymbol.CreateDiagnostic(Rule, DiagnosticDescriptorHelper.CannotFixProperties, methodSymbol.Name));
}
}
}
diff --git a/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs
index 73ac939edd..3c63f35202 100644
--- a/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0014: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class DataRowShouldBeValidAnalyzer : DiagnosticAnalyzer
{
@@ -151,7 +154,7 @@ private static void AnalyzeAttribute(SymbolAnalysisContext context, AttributeDat
// on the one argument case. Check if we match either of the array argument constructors
// and expand the array argument if we do.
ImmutableArray constructorArguments = attribute.ConstructorArguments;
- if (constructorArguments[0].Kind is TypedConstantKind.Array && !constructorArguments[0].IsNull)
+ if (attribute.AttributeConstructor?.Parameters.FirstOrDefault()?.IsParams == true)
{
constructorArguments = constructorArguments[0].Values;
}
@@ -219,7 +222,7 @@ private static bool IsArgumentCountMismatch(int constructorArgumentsLength, Immu
{
int optionalParametersCount = methodParameters.Count(x => x.HasExplicitDefaultValue);
bool isLastParameterParams = methodParameters[^1].IsParams;
- bool isOnlyParameterAndIsArray = methodParameters.Length == 1 && methodParameters[0].Type.Kind == SymbolKind.ArrayType;
+ bool isOnlyParameterAndIsArray = methodParameters is [{ Type.Kind: SymbolKind.ArrayType }];
if (isOnlyParameterAndIsArray)
{
diff --git a/src/Analyzers/MSTest.Analyzers/DoNotNegateBooleanAssertionAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DoNotNegateBooleanAssertionAnalyzer.cs
index 5ae94cc96e..e46bf0cb56 100644
--- a/src/Analyzers/MSTest.Analyzers/DoNotNegateBooleanAssertionAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/DoNotNegateBooleanAssertionAnalyzer.cs
@@ -13,6 +13,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0023: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class DoNotNegateBooleanAssertionAnalyzer : DiagnosticAnalyzer
{
@@ -56,7 +59,7 @@ private static void AnalyzeOperation(OperationAnalysisContext context, INamedTyp
IArgumentOperation? conditionArgument = invocationOperation.Arguments.FirstOrDefault(x => x.Parameter?.Name == "condition");
if (conditionArgument != null
- && conditionArgument.Children.Any(op => op is IUnaryOperation unary && unary.OperatorKind == UnaryOperatorKind.Not))
+ && conditionArgument.Children.Any(op => op is IUnaryOperation { OperatorKind: UnaryOperatorKind.Not }))
{
context.ReportDiagnostic(invocationOperation.CreateDiagnostic(Rule));
}
diff --git a/src/Analyzers/MSTest.Analyzers/DoNotStoreStaticTestContextAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DoNotStoreStaticTestContextAnalyzer.cs
index 97b17a88e4..2f298796fa 100644
--- a/src/Analyzers/MSTest.Analyzers/DoNotStoreStaticTestContextAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/DoNotStoreStaticTestContextAnalyzer.cs
@@ -13,6 +13,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0024: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class DoNotStoreStaticTestContextAnalyzer : DiagnosticAnalyzer
{
@@ -49,9 +52,7 @@ private static void AnalyzeOperation(OperationAnalysisContext context, INamedTyp
{
var assignmentOperation = (ISimpleAssignmentOperation)context.Operation;
- if (assignmentOperation.Target is IMemberReferenceOperation memberReferenceOperation
- && memberReferenceOperation.Instance is null
- && assignmentOperation.Value is IParameterReferenceOperation parameterReferenceOperation
+ if (assignmentOperation is { Target: IMemberReferenceOperation { Instance: null }, Value: IParameterReferenceOperation parameterReferenceOperation }
&& SymbolEqualityComparer.Default.Equals(parameterReferenceOperation.Type, testContextSymbol))
{
context.ReportDiagnostic(assignmentOperation.CreateDiagnostic(Rule));
diff --git a/src/Analyzers/MSTest.Analyzers/DoNotUseSystemDescriptionAttributeAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DoNotUseSystemDescriptionAttributeAnalyzer.cs
new file mode 100644
index 0000000000..934ff5a22c
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/DoNotUseSystemDescriptionAttributeAnalyzer.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;
+
+///
+/// MSTEST0031: .
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+public sealed class DoNotUseSystemDescriptionAttributeAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly LocalizableResourceString Title = new(nameof(Resources.DoNotUseSystemDescriptionAttributeTitle), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableResourceString Description = new(nameof(Resources.DoNotUseSystemDescriptionAttributeDescription), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.DoNotUseSystemDescriptionAttributeMessageFormat), Resources.ResourceManager, typeof(Resources));
+
+ internal static readonly DiagnosticDescriptor DoNotUseSystemDescriptionAttributeRule = DiagnosticDescriptorHelper.Create(
+ DiagnosticIds.DoNotUseSystemDescriptionAttributeRuleId,
+ Title,
+ MessageFormat,
+ Description,
+ Category.Usage,
+ DiagnosticSeverity.Info,
+ isEnabledByDefault: true);
+
+ public override ImmutableArray SupportedDiagnostics { get; }
+ = ImmutableArray.Create(DoNotUseSystemDescriptionAttributeRule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+
+ context.RegisterCompilationStartAction(context =>
+ {
+ if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestMethodAttribute, out INamedTypeSymbol? testMethodAttributeSymbol)
+ && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDescriptionAttribute, out INamedTypeSymbol? systemDescriptionAttributeSymbol))
+ {
+ context.RegisterSymbolAction(
+ context => AnalyzeSymbol(context, testMethodAttributeSymbol, systemDescriptionAttributeSymbol),
+ SymbolKind.Method);
+ }
+ });
+ }
+
+ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol testMethodAttributeSymbol, INamedTypeSymbol systemDescriptionAttributeSymbol)
+ {
+ var methodSymbol = (IMethodSymbol)context.Symbol;
+
+ bool hasTestMethodAttribute = false;
+ bool hasSystemDescriptionAttribute = false;
+ foreach (AttributeData attribute in methodSymbol.GetAttributes())
+ {
+ if (attribute.AttributeClass.Inherits(testMethodAttributeSymbol))
+ {
+ hasTestMethodAttribute = true;
+ }
+
+ if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, systemDescriptionAttributeSymbol))
+ {
+ hasSystemDescriptionAttribute = true;
+ }
+
+ if (hasTestMethodAttribute && hasSystemDescriptionAttribute)
+ {
+ context.ReportDiagnostic(methodSymbol.CreateDiagnostic(DoNotUseSystemDescriptionAttributeRule, methodSymbol.Name));
+ break;
+ }
+ }
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticDescriptorHelper.cs b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticDescriptorHelper.cs
index 9d3bb759d6..999c777eb9 100644
--- a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticDescriptorHelper.cs
+++ b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticDescriptorHelper.cs
@@ -1,12 +1,18 @@
// 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;
namespace MSTest.Analyzers.Helpers;
internal static class DiagnosticDescriptorHelper
{
+ public const string CannotFixPropertyKey = "CannotFix";
+ public static readonly ImmutableDictionary CannotFixProperties
+ = ImmutableDictionary.Empty.Add(CannotFixPropertyKey, null);
+
public static DiagnosticDescriptor Create(
string id,
LocalizableString title,
diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs
index 48f07cfc7f..6d5ff9211e 100644
--- a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs
+++ b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs
@@ -29,4 +29,11 @@ internal static class DiagnosticIds
public const string DoNotNegateBooleanAssertionRuleId = "MSTEST0023";
public const string DoNotStoreStaticTestContextAnalyzerRuleId = "MSTEST0024";
public const string PreferAssertFailOverAlwaysFalseConditionsRuleId = "MSTEST0025";
+ public const string AssertionArgsShouldAvoidConditionalAccessRuleId = "MSTEST0026";
+ public const string UseAsyncSuffixTestMethodSuppressorRuleId = "MSTEST0027";
+ public const string UseAsyncSuffixTestFixtureMethodSuppressorRuleId = "MSTEST0028";
+ public const string PublicMethodShouldBeTestMethodRuleId = "MSTEST0029";
+ public const string TypeContainingTestMethodShouldBeATestClassRuleId = "MSTEST0030";
+ public const string DoNotUseSystemDescriptionAttributeRuleId = "MSTEST0031";
+ public const string ReviewAlwaysTrueAssertConditionAnalyzerRuleId = "MSTEST0032";
}
diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/FixtureUtils.cs b/src/Analyzers/MSTest.Analyzers/Helpers/FixtureUtils.cs
new file mode 100644
index 0000000000..4f79378743
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/Helpers/FixtureUtils.cs
@@ -0,0 +1,137 @@
+// 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;
+using Analyzer.Utilities.Extensions;
+
+using Microsoft.CodeAnalysis;
+
+namespace MSTest.Analyzers.Helpers;
+
+internal static class FixtureUtils
+{
+ public static bool IsAssemblyInitializeMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol assemblyInitializeAttributeSymbol)
+ => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, assemblyInitializeAttributeSymbol));
+
+ public static bool IsAssemblyCleanupMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol assemblyCleanupAttributeSymbol)
+ => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, assemblyCleanupAttributeSymbol));
+
+ public static bool IsClassInitializeMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol classInitializeAttributeSymbol)
+ => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classInitializeAttributeSymbol));
+
+ public static bool IsClassCleanupMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol classCleanupAttributeSymbol)
+ => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classCleanupAttributeSymbol));
+
+ public static bool IsTestInitializeMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol testInitializeAttributeSymbol)
+ => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testInitializeAttributeSymbol));
+
+ public static bool IsTestCleanupMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol testCleanupAttributeSymbol)
+ => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testCleanupAttributeSymbol));
+
+ public static bool HasValidFixtureMethodSignature(this IMethodSymbol methodSymbol, INamedTypeSymbol? taskSymbol,
+ INamedTypeSymbol? valueTaskSymbol, bool canDiscoverInternals, bool shouldBeStatic, bool allowGenericType,
+ INamedTypeSymbol? testContextSymbol, INamedTypeSymbol testClassAttributeSymbol, bool fixtureAllowInheritedTestClass, out bool isFixable)
+ {
+ isFixable = false;
+ if (methodSymbol.MethodKind != MethodKind.Ordinary
+ || (methodSymbol.ContainingType.IsGenericType && !allowGenericType))
+ {
+ return false;
+ }
+
+ // Fixtures are only supported on classes
+ if (methodSymbol.ContainingType.TypeKind != TypeKind.Class)
+ {
+ return false;
+ }
+
+ // For AssemblyInitialize and AssemblyCleanup methods, the containing class should be marked with TestClassAttribute.
+ // For the other fixtures, it's only required if the type is not sealed.
+ if ((!fixtureAllowInheritedTestClass || methodSymbol.ContainingType.IsSealed)
+ && !methodSymbol.ContainingType.GetAttributes().Any(x => x.AttributeClass.Inherits(testClassAttributeSymbol)))
+ {
+ return false;
+ }
+
+ // Validate the method signature
+ isFixable = true;
+ return !methodSymbol.IsGenericMethod
+ && methodSymbol.IsStatic == shouldBeStatic
+ && !methodSymbol.IsAbstract
+ && HasCorrectParameters(methodSymbol, testContextSymbol)
+ && methodSymbol.IsPublicAndHasCorrectResultantVisibility(canDiscoverInternals)
+ && HasValidReturnType(methodSymbol, taskSymbol, valueTaskSymbol);
+ }
+
+ public static bool HasValidTestMethodSignature(this IMethodSymbol methodSymbol, INamedTypeSymbol? taskSymbol,
+ INamedTypeSymbol? valueTaskSymbol, bool canDiscoverInternals)
+ {
+ if (methodSymbol.MethodKind != MethodKind.Ordinary
+ || methodSymbol.IsGenericMethod
+ || methodSymbol.IsStatic
+ || methodSymbol.IsAbstract)
+ {
+ return false;
+ }
+
+ if (methodSymbol.GetResultantVisibility() is { } resultantVisibility)
+ {
+ if (!canDiscoverInternals && (resultantVisibility != SymbolVisibility.Public || methodSymbol.DeclaredAccessibility != Accessibility.Public))
+ {
+ return false;
+ }
+ else if (canDiscoverInternals && resultantVisibility == SymbolVisibility.Private)
+ {
+ return false;
+ }
+ }
+
+ return methodSymbol is { ReturnsVoid: true, IsAsync: false }
+ || SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, taskSymbol)
+ || SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, valueTaskSymbol);
+ }
+
+ public static bool IsInheritanceModeSet(this IMethodSymbol methodSymbol, INamedTypeSymbol? inheritanceBehaviorSymbol,
+ INamedTypeSymbol? classInitializeOrCleanupAttributeSymbol)
+ {
+ foreach (AttributeData attr in methodSymbol.GetAttributes())
+ {
+ if (!SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classInitializeOrCleanupAttributeSymbol))
+ {
+ continue;
+ }
+
+ ImmutableArray constructorArguments = attr.ConstructorArguments;
+ foreach (TypedConstant constructorArgument in constructorArguments)
+ {
+ if (!SymbolEqualityComparer.Default.Equals(constructorArgument.Type, inheritanceBehaviorSymbol))
+ {
+ continue;
+ }
+
+ // It's an enum so it can't be null
+ RoslynDebug.Assert(constructorArgument.Value is not null);
+
+ // We need to check that the inheritanceBehavior is not set to none and it's value inside the enum is zero
+ if ((int)constructorArgument.Value != 0)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static bool HasCorrectParameters(IMethodSymbol methodSymbol, INamedTypeSymbol? testContextSymbol)
+ => testContextSymbol is null
+ ? methodSymbol.Parameters.Length == 0
+ : methodSymbol.Parameters.Length == 1 && SymbolEqualityComparer.Default.Equals(methodSymbol.Parameters[0].Type, testContextSymbol);
+
+ private static bool HasValidReturnType(IMethodSymbol methodSymbol, INamedTypeSymbol? taskSymbol, INamedTypeSymbol? valueTaskSymbol)
+ => methodSymbol is { ReturnsVoid: true, IsAsync: false }
+ || (taskSymbol is not null && SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, taskSymbol))
+ || (valueTaskSymbol is not null && SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, valueTaskSymbol));
+}
diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/IMethodSymbolExtensions.cs b/src/Analyzers/MSTest.Analyzers/Helpers/IMethodSymbolExtensions.cs
index a249c1e385..6d58c445e5 100644
--- a/src/Analyzers/MSTest.Analyzers/Helpers/IMethodSymbolExtensions.cs
+++ b/src/Analyzers/MSTest.Analyzers/Helpers/IMethodSymbolExtensions.cs
@@ -22,22 +22,4 @@ public static bool IsPublicAndHasCorrectResultantVisibility(this IMethodSymbol m
? resultantVisibility is SymbolVisibility.Public or SymbolVisibility.Internal
: resultantVisibility is SymbolVisibility.Public;
}
-
- public static bool IsAssemblyInitializeMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol assemblyInitializeAttributeSymbol)
- => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, assemblyInitializeAttributeSymbol));
-
- public static bool IsAssemblyCleanupMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol assemblyCleanupAttributeSymbol)
- => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, assemblyCleanupAttributeSymbol));
-
- public static bool IsClassInitializeMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol classInitializeAttributeSymbol)
- => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classInitializeAttributeSymbol));
-
- public static bool IsClassCleanupMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol classCleanupAttributeSymbol)
- => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classCleanupAttributeSymbol));
-
- public static bool IsTestInitializeMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol testInitializeAttributeSymbol)
- => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testInitializeAttributeSymbol));
-
- public static bool IsTestCleanupMethod(this IMethodSymbol methodSymbol, INamedTypeSymbol testCleanupAttributeSymbol)
- => methodSymbol.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testCleanupAttributeSymbol));
}
diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/ISymbolExtensions.cs b/src/Analyzers/MSTest.Analyzers/Helpers/ISymbolExtensions.cs
new file mode 100644
index 0000000000..041990ae0b
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/Helpers/ISymbolExtensions.cs
@@ -0,0 +1,24 @@
+// 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.CodeAnalysis;
+
+namespace MSTest.Analyzers.Helpers;
+
+internal static class ISymbolExtensions
+{
+ public static ITypeSymbol? GetReferencedMemberOrLocalOrParameter(this ISymbol? symbol) => symbol switch
+ {
+ IEventSymbol eventSymbol => eventSymbol.Type,
+
+ IFieldSymbol fieldSymbol => fieldSymbol.Type,
+
+ IMethodSymbol methodSymbol => methodSymbol.ReturnType,
+
+ IPropertySymbol propertySymbol => propertySymbol.Type,
+
+ ILocalSymbol localSymbol => localSymbol.Type,
+
+ _ => null,
+ };
+}
diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs b/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs
index e4d17ffffd..1cfd24c9e6 100644
--- a/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs
+++ b/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs
@@ -11,6 +11,7 @@ internal static class WellKnownTypeNames
public const string MicrosoftVisualStudioTestToolsUnitTestingAssert = "Microsoft.VisualStudio.TestTools.UnitTesting.Assert";
public const string MicrosoftVisualStudioTestToolsUnitTestingClassCleanupAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupAttribute";
public const string MicrosoftVisualStudioTestToolsUnitTestingClassInitializeAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.ClassInitializeAttribute";
+ public const string MicrosoftVisualStudioTestToolsUnitTestingCollectionAssert = "Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert";
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";
@@ -23,6 +24,7 @@ internal static class WellKnownTypeNames
public const string MicrosoftVisualStudioTestToolsUnitTestingOwnerAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.OwnerAttribute";
public const string MicrosoftVisualStudioTestToolsUnitTestingParallelizeAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.ParallelizeAttribute";
public const string MicrosoftVisualStudioTestToolsUnitTestingPriorityAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.PriorityAttribute";
+ public const string MicrosoftVisualStudioTestToolsUnitTestingStringAssert = "Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert";
public const string MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute";
public const string MicrosoftVisualStudioTestToolsUnitTestingTestCleanupAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.TestCleanupAttribute";
public const string MicrosoftVisualStudioTestToolsUnitTestingTestContext = "Microsoft.VisualStudio.TestTools.UnitTesting.TestContext";
@@ -31,9 +33,12 @@ internal static class WellKnownTypeNames
public const string MicrosoftVisualStudioTestToolsUnitTestingTestPropertyAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute";
public const string MicrosoftVisualStudioTestToolsUnitTestingWorkItemAttribute = "Microsoft.VisualStudio.TestTools.UnitTesting.WorkItemAttribute";
+ public const string SystemDescriptionAttribute = "System.ComponentModel.DescriptionAttribute";
public const string SystemIAsyncDisposable = "System.IAsyncDisposable";
public const string SystemIDisposable = "System.IDisposable";
+ public const string SystemNullable = "System.Nullable`1";
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";
+ public const string SystemThreadingTasksValueTask1 = "System.Threading.Tasks.ValueTask`1";
}
diff --git a/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj b/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj
index 652a5e0775..b7ded067c4 100644
--- a/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj
+++ b/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj
@@ -1,4 +1,4 @@
-
+netstandard2.0
@@ -11,17 +11,18 @@
-
-
+
+
+
diff --git a/src/Analyzers/MSTest.Analyzers/PreferAssertFailOverAlwaysFalseConditionsAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/PreferAssertFailOverAlwaysFalseConditionsAnalyzer.cs
index 1a689e87ec..ec11b318ed 100644
--- a/src/Analyzers/MSTest.Analyzers/PreferAssertFailOverAlwaysFalseConditionsAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/PreferAssertFailOverAlwaysFalseConditionsAnalyzer.cs
@@ -10,9 +10,13 @@
using Microsoft.CodeAnalysis.Operations;
using MSTest.Analyzers.Helpers;
+using MSTest.Analyzers.RoslynAnalyzerHelpers;
namespace MSTest.Analyzers;
+///
+/// MSTEST0025: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class PreferAssertFailOverAlwaysFalseConditionsAnalyzer : DiagnosticAnalyzer
{
@@ -53,24 +57,26 @@ public override void Initialize(AnalysisContext context)
{
Compilation compilation = context.Compilation;
INamedTypeSymbol? assertSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssert);
+ INamedTypeSymbol? nullableSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemNullable);
if (assertSymbol is not null)
{
- context.RegisterOperationAction(context => AnalyzeOperation(context, assertSymbol), OperationKind.Invocation);
+ context.RegisterOperationAction(context => AnalyzeOperation(context, assertSymbol, nullableSymbol), OperationKind.Invocation);
}
});
}
- private static void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol assertSymbol)
+ private static void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol assertSymbol, INamedTypeSymbol? nullableSymbol)
{
var operation = (IInvocationOperation)context.Operation;
- if (assertSymbol.Equals(operation.TargetMethod?.ContainingType, SymbolEqualityComparer.Default) &&
- IsAlwaysFalse(operation))
+
+ if (assertSymbol.Equals(operation.TargetMethod.ContainingType, SymbolEqualityComparer.Default) &&
+ IsAlwaysFalse(operation, nullableSymbol))
{
context.ReportDiagnostic(operation.CreateDiagnostic(Rule, operation.TargetMethod.Name));
}
}
- private static bool IsAlwaysFalse(IInvocationOperation operation)
+ private static bool IsAlwaysFalse(IInvocationOperation operation, INamedTypeSymbol? nullableSymbol)
=> operation.TargetMethod.Name switch
{
"IsTrue" => GetConditionArgument(operation) is { Value.ConstantValue: { HasValue: true, Value: false } },
@@ -78,9 +84,18 @@ private static bool IsAlwaysFalse(IInvocationOperation operation)
"AreEqual" => GetEqualityStatus(operation, ExpectedParameterName) == EqualityStatus.NotEqual,
"AreNotEqual" => GetEqualityStatus(operation, NotExpectedParameterName) == EqualityStatus.Equal,
"IsNotNull" => GetValueArgument(operation) is { Value.ConstantValue: { HasValue: true, Value: null } },
+ "IsNull" => GetValueArgument(operation) is { } valueArgumentOperation && IsNotNullableType(valueArgumentOperation, nullableSymbol),
_ => false,
};
+ private static bool IsNotNullableType(IArgumentOperation valueArgumentOperation, INamedTypeSymbol? nullableSymbol)
+ {
+ ITypeSymbol? valueArgType = valueArgumentOperation.Value.GetReferencedMemberOrLocalOrParameter().GetReferencedMemberOrLocalOrParameter();
+ return valueArgType is not null
+ && valueArgType.NullableAnnotation == NullableAnnotation.NotAnnotated
+ && !SymbolEqualityComparer.IncludeNullability.Equals(valueArgType.OriginalDefinition, nullableSymbol);
+ }
+
private static IArgumentOperation? GetArgumentWithName(IInvocationOperation operation, string name)
=> operation.Arguments.FirstOrDefault(arg => arg.Parameter?.Name == name);
diff --git a/src/Analyzers/MSTest.Analyzers/PreferConstructorOverTestInitializeAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/PreferConstructorOverTestInitializeAnalyzer.cs
index 32c8bce9c1..61d03d2294 100644
--- a/src/Analyzers/MSTest.Analyzers/PreferConstructorOverTestInitializeAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/PreferConstructorOverTestInitializeAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0020: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class PreferConstructorOverTestInitializeAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/PreferDisposeOverTestCleanupAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/PreferDisposeOverTestCleanupAnalyzer.cs
index f2b35cbb47..404d4cf7ca 100644
--- a/src/Analyzers/MSTest.Analyzers/PreferDisposeOverTestCleanupAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/PreferDisposeOverTestCleanupAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0021: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class PreferDisposeOverTestCleanupAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/PreferTestCleanupOverDisposeAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/PreferTestCleanupOverDisposeAnalyzer.cs
index 3c8f092d9d..1e22fec61a 100644
--- a/src/Analyzers/MSTest.Analyzers/PreferTestCleanupOverDisposeAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/PreferTestCleanupOverDisposeAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0022: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class PreferTestCleanupOverDisposeAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/PreferTestInitializeOverConstructorAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/PreferTestInitializeOverConstructorAnalyzer.cs
index 48635e25b1..676125627e 100644
--- a/src/Analyzers/MSTest.Analyzers/PreferTestInitializeOverConstructorAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/PreferTestInitializeOverConstructorAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0019: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class PreferTestInitializeOverConstructorAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/PublicAPI.Shipped.txt b/src/Analyzers/MSTest.Analyzers/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..ab058de62d
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/PublicAPI.Shipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/Analyzers/MSTest.Analyzers/PublicAPI.Unshipped.txt b/src/Analyzers/MSTest.Analyzers/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..4d8fce9705
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/PublicAPI.Unshipped.txt
@@ -0,0 +1,130 @@
+#nullable enable
+Analyzer.Utilities.WellKnownTypeProvider
+Analyzer.Utilities.WellKnownTypeProvider.Compilation.get -> Microsoft.CodeAnalysis.Compilation!
+Analyzer.Utilities.WellKnownTypeProvider.GetOrCreateTypeByMetadataName(string! fullTypeName) -> Microsoft.CodeAnalysis.INamedTypeSymbol?
+Analyzer.Utilities.WellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(string! fullTypeName, out Microsoft.CodeAnalysis.INamedTypeSymbol? namedTypeSymbol) -> bool
+MSTest.Analyzers.AssemblyCleanupShouldBeValidAnalyzer
+MSTest.Analyzers.AssemblyCleanupShouldBeValidAnalyzer.AssemblyCleanupShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.AssemblyInitializeShouldBeValidAnalyzer
+MSTest.Analyzers.AssemblyInitializeShouldBeValidAnalyzer.AssemblyInitializeShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.AssertionArgsShouldAvoidConditionalAccessAnalyzer
+MSTest.Analyzers.AssertionArgsShouldAvoidConditionalAccessAnalyzer.AssertionArgsShouldAvoidConditionalAccessAnalyzer() -> void
+MSTest.Analyzers.AssertionArgsShouldBePassedInCorrectOrderAnalyzer
+MSTest.Analyzers.AssertionArgsShouldBePassedInCorrectOrderAnalyzer.AssertionArgsShouldBePassedInCorrectOrderAnalyzer() -> void
+MSTest.Analyzers.AvoidExpectedExceptionAttributeAnalyzer
+MSTest.Analyzers.AvoidExpectedExceptionAttributeAnalyzer.AvoidExpectedExceptionAttributeAnalyzer() -> void
+MSTest.Analyzers.ClassCleanupShouldBeValidAnalyzer
+MSTest.Analyzers.ClassCleanupShouldBeValidAnalyzer.ClassCleanupShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.ClassInitializeShouldBeValidAnalyzer
+MSTest.Analyzers.ClassInitializeShouldBeValidAnalyzer.ClassInitializeShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.DataRowShouldBeValidAnalyzer
+MSTest.Analyzers.DataRowShouldBeValidAnalyzer.DataRowShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.DoNotNegateBooleanAssertionAnalyzer
+MSTest.Analyzers.DoNotNegateBooleanAssertionAnalyzer.DoNotNegateBooleanAssertionAnalyzer() -> void
+MSTest.Analyzers.DoNotStoreStaticTestContextAnalyzer
+MSTest.Analyzers.DoNotStoreStaticTestContextAnalyzer.DoNotStoreStaticTestContextAnalyzer() -> void
+MSTest.Analyzers.DoNotUseSystemDescriptionAttributeAnalyzer
+MSTest.Analyzers.DoNotUseSystemDescriptionAttributeAnalyzer.DoNotUseSystemDescriptionAttributeAnalyzer() -> void
+MSTest.Analyzers.PreferAssertFailOverAlwaysFalseConditionsAnalyzer
+MSTest.Analyzers.PreferAssertFailOverAlwaysFalseConditionsAnalyzer.PreferAssertFailOverAlwaysFalseConditionsAnalyzer() -> void
+MSTest.Analyzers.PreferConstructorOverTestInitializeAnalyzer
+MSTest.Analyzers.PreferConstructorOverTestInitializeAnalyzer.PreferConstructorOverTestInitializeAnalyzer() -> void
+MSTest.Analyzers.PreferDisposeOverTestCleanupAnalyzer
+MSTest.Analyzers.PreferDisposeOverTestCleanupAnalyzer.PreferDisposeOverTestCleanupAnalyzer() -> void
+MSTest.Analyzers.ReviewAlwaysTrueAssertConditionAnalyzer
+MSTest.Analyzers.ReviewAlwaysTrueAssertConditionAnalyzer.ReviewAlwaysTrueAssertConditionAnalyzer() -> void
+MSTest.Analyzers.PreferTestCleanupOverDisposeAnalyzer
+MSTest.Analyzers.PreferTestCleanupOverDisposeAnalyzer.PreferTestCleanupOverDisposeAnalyzer() -> void
+MSTest.Analyzers.PreferTestInitializeOverConstructorAnalyzer
+MSTest.Analyzers.PreferTestInitializeOverConstructorAnalyzer.PreferTestInitializeOverConstructorAnalyzer() -> void
+MSTest.Analyzers.PublicMethodShouldBeTestMethodAnalyzer
+MSTest.Analyzers.PublicMethodShouldBeTestMethodAnalyzer.PublicMethodShouldBeTestMethodAnalyzer() -> void
+MSTest.Analyzers.PublicTypeShouldBeTestClassAnalyzer
+MSTest.Analyzers.PublicTypeShouldBeTestClassAnalyzer.PublicTypeShouldBeTestClassAnalyzer() -> void
+MSTest.Analyzers.TestClassShouldBeValidAnalyzer
+MSTest.Analyzers.TestClassShouldBeValidAnalyzer.TestClassShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.TestClassShouldHaveTestMethodAnalyzer
+MSTest.Analyzers.TestClassShouldHaveTestMethodAnalyzer.TestClassShouldHaveTestMethodAnalyzer() -> void
+MSTest.Analyzers.TestCleanupShouldBeValidAnalyzer
+MSTest.Analyzers.TestCleanupShouldBeValidAnalyzer.TestCleanupShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.TestContextShouldBeValidAnalyzer
+MSTest.Analyzers.TestContextShouldBeValidAnalyzer.TestContextShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.TestInitializeShouldBeValidAnalyzer
+MSTest.Analyzers.TestInitializeShouldBeValidAnalyzer.TestInitializeShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.TestMethodShouldBeValidAnalyzer
+MSTest.Analyzers.TestMethodShouldBeValidAnalyzer.TestMethodShouldBeValidAnalyzer() -> void
+MSTest.Analyzers.TestMethodShouldNotBeIgnoredAnalyzer
+MSTest.Analyzers.TestMethodShouldNotBeIgnoredAnalyzer.TestMethodShouldNotBeIgnoredAnalyzer() -> void
+MSTest.Analyzers.TypeContainingTestMethodShouldBeATestClassAnalyzer
+MSTest.Analyzers.TypeContainingTestMethodShouldBeATestClassAnalyzer.TypeContainingTestMethodShouldBeATestClassAnalyzer() -> void
+MSTest.Analyzers.UseAsyncSuffixTestFixtureMethodSuppressor
+MSTest.Analyzers.UseAsyncSuffixTestFixtureMethodSuppressor.UseAsyncSuffixTestFixtureMethodSuppressor() -> void
+MSTest.Analyzers.UseAsyncSuffixTestMethodSuppressor
+MSTest.Analyzers.UseAsyncSuffixTestMethodSuppressor.UseAsyncSuffixTestMethodSuppressor() -> void
+MSTest.Analyzers.UseAttributeOnTestMethodAnalyzer
+MSTest.Analyzers.UseAttributeOnTestMethodAnalyzer.UseAttributeOnTestMethodAnalyzer() -> void
+MSTest.Analyzers.UseParallelizeAttributeAnalyzer
+MSTest.Analyzers.UseParallelizeAttributeAnalyzer.UseParallelizeAttributeAnalyzer() -> 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
+override MSTest.Analyzers.AssemblyInitializeShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.AssertionArgsShouldAvoidConditionalAccessAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.AssertionArgsShouldAvoidConditionalAccessAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.AssertionArgsShouldBePassedInCorrectOrderAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.AssertionArgsShouldBePassedInCorrectOrderAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.AvoidExpectedExceptionAttributeAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.AvoidExpectedExceptionAttributeAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.ClassCleanupShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.ClassCleanupShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.ClassInitializeShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.ClassInitializeShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.DataRowShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.DataRowShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.DoNotNegateBooleanAssertionAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.DoNotNegateBooleanAssertionAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.DoNotStoreStaticTestContextAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.DoNotStoreStaticTestContextAnalyzer.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.PreferAssertFailOverAlwaysFalseConditionsAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.PreferAssertFailOverAlwaysFalseConditionsAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.PreferConstructorOverTestInitializeAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.PreferConstructorOverTestInitializeAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.PreferDisposeOverTestCleanupAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.PreferDisposeOverTestCleanupAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.ReviewAlwaysTrueAssertConditionAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.ReviewAlwaysTrueAssertConditionAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.PreferTestCleanupOverDisposeAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.PreferTestCleanupOverDisposeAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.PreferTestInitializeOverConstructorAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.PreferTestInitializeOverConstructorAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.PublicMethodShouldBeTestMethodAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.PublicMethodShouldBeTestMethodAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.PublicTypeShouldBeTestClassAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.PublicTypeShouldBeTestClassAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.TestClassShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.TestClassShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.TestClassShouldHaveTestMethodAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.TestClassShouldHaveTestMethodAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.TestCleanupShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.TestCleanupShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.TestContextShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.TestContextShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.TestInitializeShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.TestInitializeShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.TestMethodShouldBeValidAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.TestMethodShouldBeValidAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.TestMethodShouldNotBeIgnoredAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.TestMethodShouldNotBeIgnoredAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.TypeContainingTestMethodShouldBeATestClassAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.TypeContainingTestMethodShouldBeATestClassAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.UseAsyncSuffixTestFixtureMethodSuppressor.ReportSuppressions(Microsoft.CodeAnalysis.Diagnostics.SuppressionAnalysisContext context) -> void
+override MSTest.Analyzers.UseAsyncSuffixTestFixtureMethodSuppressor.SupportedSuppressions.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.UseAsyncSuffixTestMethodSuppressor.ReportSuppressions(Microsoft.CodeAnalysis.Diagnostics.SuppressionAnalysisContext context) -> void
+override MSTest.Analyzers.UseAsyncSuffixTestMethodSuppressor.SupportedSuppressions.get -> System.Collections.Immutable.ImmutableArray
+override MSTest.Analyzers.UseAttributeOnTestMethodAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext! context) -> void
+override MSTest.Analyzers.UseAttributeOnTestMethodAnalyzer.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
+static Analyzer.Utilities.WellKnownTypeProvider.GetOrCreate(Microsoft.CodeAnalysis.Compilation! compilation) -> Analyzer.Utilities.WellKnownTypeProvider!
diff --git a/src/Analyzers/MSTest.Analyzers/PublicMethodShouldBeTestMethodAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/PublicMethodShouldBeTestMethodAnalyzer.cs
new file mode 100644
index 0000000000..f971868a17
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/PublicMethodShouldBeTestMethodAnalyzer.cs
@@ -0,0 +1,104 @@
+// 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;
+
+///
+/// MSTEST0029: .
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+public sealed class PublicMethodShouldBeTestMethodAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly LocalizableResourceString Title = new(nameof(Resources.PublicMethodShouldBeTestMethodAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableResourceString Description = new(nameof(Resources.PublicMethodShouldBeTestMethodAnalyzerDescription), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.PublicMethodShouldBeTestMethodAnalyzerFormat), Resources.ResourceManager, typeof(Resources));
+
+ internal static readonly DiagnosticDescriptor PublicMethodShouldBeTestMethodRule = DiagnosticDescriptorHelper.Create(
+ DiagnosticIds.PublicMethodShouldBeTestMethodRuleId,
+ Title,
+ MessageFormat,
+ Description,
+ Category.Design,
+ DiagnosticSeverity.Info,
+ isEnabledByDefault: false);
+
+ public override ImmutableArray SupportedDiagnostics { get; }
+ = ImmutableArray.Create(PublicMethodShouldBeTestMethodRule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+ context.RegisterCompilationStartAction(context =>
+ {
+ if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestMethodAttribute, out INamedTypeSymbol? testMethodAttributeSymbol)
+ && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol))
+ {
+ bool canDiscoverInternals = context.Compilation.CanDiscoverInternals();
+ INamedTypeSymbol? taskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask);
+ INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask);
+ context.RegisterSymbolAction(
+ context => AnalyzeSymbol(context, testMethodAttributeSymbol, testClassAttributeSymbol, taskSymbol, valueTaskSymbol, canDiscoverInternals),
+ SymbolKind.Method);
+ }
+ });
+ }
+
+ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol testMethodAttributeSymbol, INamedTypeSymbol testClassAttributeSymbol, INamedTypeSymbol? taskSymbol,
+ INamedTypeSymbol? valueTaskSymbol, bool canDiscoverInternals)
+ {
+ var methodSymbol = (IMethodSymbol)context.Symbol;
+ if (methodSymbol.GetResultantVisibility() != SymbolVisibility.Public)
+ {
+ return;
+ }
+
+ if (!methodSymbol.HasValidTestMethodSignature(taskSymbol, valueTaskSymbol, canDiscoverInternals))
+ {
+ return;
+ }
+
+ INamedTypeSymbol containingTypeSymbol = context.Symbol.ContainingType;
+ bool isTestClass = false;
+ foreach (AttributeData classAttribute in containingTypeSymbol.GetAttributes())
+ {
+ if (classAttribute.AttributeClass.Inherits(testClassAttributeSymbol))
+ {
+ isTestClass = true;
+ break;
+ }
+ }
+
+ if (!isTestClass)
+ {
+ return;
+ }
+
+ ImmutableArray methodAttributes = methodSymbol.GetAttributes();
+ bool isTestMethod = false;
+ foreach (AttributeData methodAttribute in methodAttributes)
+ {
+ // Check if method is a test method or inherit from the TestMethod attribute.
+ if (methodAttribute.AttributeClass.Inherits(testMethodAttributeSymbol))
+ {
+ isTestMethod = true;
+ }
+ }
+
+ if (isTestMethod)
+ {
+ return;
+ }
+
+ context.ReportDiagnostic(methodSymbol.CreateDiagnostic(PublicMethodShouldBeTestMethodRule, methodSymbol.Name));
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers/PublicTypeShouldBeTestClassAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/PublicTypeShouldBeTestClassAnalyzer.cs
index ba7a9ff32e..07d03b206c 100644
--- a/src/Analyzers/MSTest.Analyzers/PublicTypeShouldBeTestClassAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/PublicTypeShouldBeTestClassAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0004: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class PublicTypeShouldBeTestClassAnalyzer : DiagnosticAnalyzer
{
@@ -48,7 +51,10 @@ public override void Initialize(AnalysisContext context)
private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol testClassAttributeSymbol)
{
var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
- if (namedTypeSymbol.DeclaredAccessibility != Accessibility.Public
+ if (namedTypeSymbol.IsAbstract
+ || namedTypeSymbol.IsStatic
+ || namedTypeSymbol.TypeKind != TypeKind.Class
+ || namedTypeSymbol.DeclaredAccessibility != Accessibility.Public
|| namedTypeSymbol.GetResultantVisibility() != SymbolVisibility.Public)
{
return;
diff --git a/src/Analyzers/MSTest.Analyzers/Resources.Designer.cs b/src/Analyzers/MSTest.Analyzers/Resources.Designer.cs
index c01c7554c8..1543495a4a 100644
--- a/src/Analyzers/MSTest.Analyzers/Resources.Designer.cs
+++ b/src/Analyzers/MSTest.Analyzers/Resources.Designer.cs
@@ -62,13 +62,13 @@ internal Resources() {
///
/// Looks up a localized string similar to Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
- ///- it should be 'public'
- ///- it should be 'static'
- ///- it should not be generic
- ///- it should not take any parameter
+ ///- be 'public'
+ ///- be 'static'
+ ///- not be generic nor defined on a generic class
+ ///- not take any parameter
///- return type should be 'void', 'Task' or 'ValueTask'
- ///- it should not be 'async void'
- ///- it should not be a special method (finalizer, operator...)..
+ ///- not be 'async void'
+ ///- not be a special method (finalizer, operator...)..
///
internal static string AssemblyCleanupShouldBeValidDescription {
get {
@@ -77,74 +77,11 @@ internal static string AssemblyCleanupShouldBeValidDescription {
}
///
- /// Looks up a localized string similar to AssemblyCleanup method '{0}' should not take any parameter.
- ///
- internal static string AssemblyCleanupShouldBeValidMessageFormat_NoParameters {
- get {
- return ResourceManager.GetString("AssemblyCleanupShouldBeValidMessageFormat_NoParameters", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyCleanup method '{0}' can't be declared on a generic class.
- ///
- internal static string AssemblyCleanupShouldBeValidMessageFormat_NotAGenericClass {
- get {
- return ResourceManager.GetString("AssemblyCleanupShouldBeValidMessageFormat_NotAGenericClass", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'.
- ///
- internal static string AssemblyCleanupShouldBeValidMessageFormat_NotAsyncVoid {
- get {
- return ResourceManager.GetString("AssemblyCleanupShouldBeValidMessageFormat_NotAsyncVoid", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyCleanup method '{0}' should not be generic.
- ///
- internal static string AssemblyCleanupShouldBeValidMessageFormat_NotGeneric {
- get {
- return ResourceManager.GetString("AssemblyCleanupShouldBeValidMessageFormat_NotGeneric", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyCleanup method '{0}' should be an 'ordinary' method.
- ///
- internal static string AssemblyCleanupShouldBeValidMessageFormat_Ordinary {
- get {
- return ResourceManager.GetString("AssemblyCleanupShouldBeValidMessageFormat_Ordinary", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyCleanup method '{0}' should be 'public'.
+ /// Looks up a localized string similar to AssemblyCleanup method '{0}' signature is invalid.
///
- internal static string AssemblyCleanupShouldBeValidMessageFormat_Public {
+ internal static string AssemblyCleanupShouldBeValidMessageFormat {
get {
- return ResourceManager.GetString("AssemblyCleanupShouldBeValidMessageFormat_Public", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'.
- ///
- internal static string AssemblyCleanupShouldBeValidMessageFormat_ReturnType {
- get {
- return ResourceManager.GetString("AssemblyCleanupShouldBeValidMessageFormat_ReturnType", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyCleanup method '{0}' should be 'static'.
- ///
- internal static string AssemblyCleanupShouldBeValidMessageFormat_Static {
- get {
- return ResourceManager.GetString("AssemblyCleanupShouldBeValidMessageFormat_Static", resourceCulture);
+ return ResourceManager.GetString("AssemblyCleanupShouldBeValidMessageFormat", resourceCulture);
}
}
@@ -159,13 +96,13 @@ internal static string AssemblyCleanupShouldBeValidTitle {
///
/// Looks up a localized string similar to Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
- ///- it should be 'public'
- ///- it should be 'static'
- ///- it should not be generic
- ///- it should take one parameter of type 'TestContext'
+ ///- be 'public'
+ ///- be 'static'
+ ///- not be generic nor be defined on a generic class
+ ///- take a single parameter of type 'TestContext'
///- return type should be 'void', 'Task' or 'ValueTask'
- ///- it should not be 'async void'
- ///- it should not be a special method (finalizer, operator...)..
+ ///- not be 'async void'
+ ///- not be a special method (finalizer, operator...)..
///
internal static string AssemblyInitializeShouldBeValidDescription {
get {
@@ -174,83 +111,38 @@ internal static string AssemblyInitializeShouldBeValidDescription {
}
///
- /// Looks up a localized string similar to AssemblyInitialize method '{0}' can't be declared on a generic class.
- ///
- internal static string AssemblyInitializeShouldBeValidMessageFormat_NotAGenericClass {
- get {
- return ResourceManager.GetString("AssemblyInitializeShouldBeValidMessageFormat_NotAGenericClass", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'.
- ///
- internal static string AssemblyInitializeShouldBeValidMessageFormat_NotAsyncVoid {
- get {
- return ResourceManager.GetString("AssemblyInitializeShouldBeValidMessageFormat_NotAsyncVoid", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyInitialize method '{0}' should not be generic.
- ///
- internal static string AssemblyInitializeShouldBeValidMessageFormat_NotGeneric {
- get {
- return ResourceManager.GetString("AssemblyInitializeShouldBeValidMessageFormat_NotGeneric", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyInitialize method '{0}' should be an 'ordinary' method.
+ /// Looks up a localized string similar to AssemblyInitialize method '{0}' signature is invalid.
///
- internal static string AssemblyInitializeShouldBeValidMessageFormat_Ordinary {
+ internal static string AssemblyInitializeShouldBeValidMessageFormat {
get {
- return ResourceManager.GetString("AssemblyInitializeShouldBeValidMessageFormat_Ordinary", resourceCulture);
+ return ResourceManager.GetString("AssemblyInitializeShouldBeValidMessageFormat", resourceCulture);
}
}
///
- /// Looks up a localized string similar to AssemblyInitialize method '{0}' should be 'public'.
- ///
- internal static string AssemblyInitializeShouldBeValidMessageFormat_Public {
- get {
- return ResourceManager.GetString("AssemblyInitializeShouldBeValidMessageFormat_Public", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'.
- ///
- internal static string AssemblyInitializeShouldBeValidMessageFormat_ReturnType {
- get {
- return ResourceManager.GetString("AssemblyInitializeShouldBeValidMessageFormat_ReturnType", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'.
+ /// Looks up a localized string similar to AssemblyInitialize methods should have valid layout.
///
- internal static string AssemblyInitializeShouldBeValidMessageFormat_SingleContextParameter {
+ internal static string AssemblyInitializeShouldBeValidTitle {
get {
- return ResourceManager.GetString("AssemblyInitializeShouldBeValidMessageFormat_SingleContextParameter", resourceCulture);
+ return ResourceManager.GetString("AssemblyInitializeShouldBeValidTitle", resourceCulture);
}
}
///
- /// Looks up a localized string similar to AssemblyInitialize method '{0}' should be 'static'.
+ /// Looks up a localized string similar to Prefer adding an additional assertion that checks for null.
///
- internal static string AssemblyInitializeShouldBeValidMessageFormat_Static {
+ internal static string AssertionArgsShouldAvoidConditionalAccessMessageFormat {
get {
- return ResourceManager.GetString("AssemblyInitializeShouldBeValidMessageFormat_Static", resourceCulture);
+ return ResourceManager.GetString("AssertionArgsShouldAvoidConditionalAccessMessageFormat", resourceCulture);
}
}
///
- /// Looks up a localized string similar to AssemblyInitialize methods should have valid layout.
+ /// Looks up a localized string similar to Avoid conditional access in assertions.
///
- internal static string AssemblyInitializeShouldBeValidTitle {
+ internal static string AssertionArgsShouldAvoidConditionalAccessTitle {
get {
- return ResourceManager.GetString("AssemblyInitializeShouldBeValidTitle", resourceCulture);
+ return ResourceManager.GetString("AssertionArgsShouldAvoidConditionalAccessTitle", resourceCulture);
}
}
@@ -310,13 +202,13 @@ internal static string AvoidExpectedExceptionAttributeTitle {
///
/// Looks up a localized string similar to Methods marked with [ClassCleanup] should follow the following layout to be valid:
- ///- it should be 'public'
- ///- it should not 'static'
- ///- it should not be generic
- ///- it should not take any parameter
+ ///- be 'public'
+ ///- not be 'static'
+ ///- not be generic nor defined on a generic class
+ ///- not take any parameter
///- return type should be 'void', 'Task' or 'ValueTask'
- ///- it should not be 'async void'
- ///- it should not be a special method (finalizer, operator...)..
+ ///- not be 'async void'
+ ///- not be a special method (finalizer, operator...)..
///
internal static string ClassCleanupShouldBeValidDescription {
get {
@@ -325,74 +217,11 @@ internal static string ClassCleanupShouldBeValidDescription {
}
///
- /// Looks up a localized string similar to ClassCleanup method '{0}' should not take any parameter.
+ /// Looks up a localized string similar to ClassCleanup method '{0}' signature is invalid.
///
- internal static string ClassCleanupShouldBeValidMessageFormat_NoParameters {
+ internal static string ClassCleanupShouldBeValidMessageFormat {
get {
- return ResourceManager.GetString("ClassCleanupShouldBeValidMessageFormat_NoParameters", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set.
- ///
- internal static string ClassCleanupShouldBeValidMessageFormat_NotAGenericClassUnlessInheritanceModeSet {
- get {
- return ResourceManager.GetString("ClassCleanupShouldBeValidMessageFormat_NotAGenericClassUnlessInheritanceModeSet", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'.
- ///
- internal static string ClassCleanupShouldBeValidMessageFormat_NotAsyncVoid {
- get {
- return ResourceManager.GetString("ClassCleanupShouldBeValidMessageFormat_NotAsyncVoid", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassCleanup method '{0}' should not be generic.
- ///
- internal static string ClassCleanupShouldBeValidMessageFormat_NotGeneric {
- get {
- return ResourceManager.GetString("ClassCleanupShouldBeValidMessageFormat_NotGeneric", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassCleanup method '{0}' should be an 'ordinary' method.
- ///
- internal static string ClassCleanupShouldBeValidMessageFormat_Ordinary {
- get {
- return ResourceManager.GetString("ClassCleanupShouldBeValidMessageFormat_Ordinary", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassCleanup method '{0}' should be 'public'.
- ///
- internal static string ClassCleanupShouldBeValidMessageFormat_Public {
- get {
- return ResourceManager.GetString("ClassCleanupShouldBeValidMessageFormat_Public", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'.
- ///
- internal static string ClassCleanupShouldBeValidMessageFormat_ReturnType {
- get {
- return ResourceManager.GetString("ClassCleanupShouldBeValidMessageFormat_ReturnType", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassCleanup method '{0}' should be 'static'.
- ///
- internal static string ClassCleanupShouldBeValidMessageFormat_Static {
- get {
- return ResourceManager.GetString("ClassCleanupShouldBeValidMessageFormat_Static", resourceCulture);
+ return ResourceManager.GetString("ClassCleanupShouldBeValidMessageFormat", resourceCulture);
}
}
@@ -407,13 +236,13 @@ internal static string ClassCleanupShouldBeValidTitle {
///
/// Looks up a localized string similar to Methods marked with [ClassInitialize] should follow the following layout to be valid:
- ///- it should be 'public'
- ///- it should be 'static'
- ///- it should not be generic
- ///- it should take one parameter of type 'TestContext'
+ ///- be 'public'
+ ///- be 'static'
+ ///- not be generic nor be defined on a generic class
+ ///- take a single parameter of type 'TestContext'
///- return type should be 'void', 'Task' or 'ValueTask'
- ///- it should not be 'async void'
- ///- it should not be a special method (finalizer, operator...)..
+ ///- not be 'async void'
+ ///- not be a special method (finalizer, operator...)..
///
internal static string ClassInitializeShouldBeValidDescription {
get {
@@ -422,75 +251,11 @@ internal static string ClassInitializeShouldBeValidDescription {
}
///
- /// Looks up a localized string similar to ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set.
- ///
- internal static string ClassInitializeShouldBeValidMessageFormat_NotAGenericClassUnlessInheritanceModeSet {
- get {
- return ResourceManager.GetString("ClassInitializeShouldBeValidMessageFormat_NotAGenericClassUnlessInheritanceModeSe" +
- "t", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'.
- ///
- internal static string ClassInitializeShouldBeValidMessageFormat_NotAsyncVoid {
- get {
- return ResourceManager.GetString("ClassInitializeShouldBeValidMessageFormat_NotAsyncVoid", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassInitialize method '{0}' should not be generic.
- ///
- internal static string ClassInitializeShouldBeValidMessageFormat_NotGeneric {
- get {
- return ResourceManager.GetString("ClassInitializeShouldBeValidMessageFormat_NotGeneric", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassInitialize method '{0}' should be an 'ordinary' method.
- ///
- internal static string ClassInitializeShouldBeValidMessageFormat_Ordinary {
- get {
- return ResourceManager.GetString("ClassInitializeShouldBeValidMessageFormat_Ordinary", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassInitialize method '{0}' should be 'public'.
- ///
- internal static string ClassInitializeShouldBeValidMessageFormat_Public {
- get {
- return ResourceManager.GetString("ClassInitializeShouldBeValidMessageFormat_Public", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'.
- ///
- internal static string ClassInitializeShouldBeValidMessageFormat_ReturnType {
- get {
- return ResourceManager.GetString("ClassInitializeShouldBeValidMessageFormat_ReturnType", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassInitialize method '{0}' should take a single parameter of type 'TestContext'.
- ///
- internal static string ClassInitializeShouldBeValidMessageFormat_SingleContextParameter {
- get {
- return ResourceManager.GetString("ClassInitializeShouldBeValidMessageFormat_SingleContextParameter", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClassInitialize method '{0}' should be 'static'.
+ /// Looks up a localized string similar to ClassInitialize method '{0}' signature is invalid.
///
- internal static string ClassInitializeShouldBeValidMessageFormat_Static {
+ internal static string ClassInitializeShouldBeValidMessageFormat {
get {
- return ResourceManager.GetString("ClassInitializeShouldBeValidMessageFormat_Static", resourceCulture);
+ return ResourceManager.GetString("ClassInitializeShouldBeValidMessageFormat", resourceCulture);
}
}
@@ -587,6 +352,33 @@ internal static string DoNotStoreStaticTestContextAnalyzerTitle {
}
}
+ ///
+ /// Looks up a localized string similar to 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead..
+ ///
+ internal static string DoNotUseSystemDescriptionAttributeDescription {
+ get {
+ return ResourceManager.GetString("DoNotUseSystemDescriptionAttributeDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?.
+ ///
+ internal static string DoNotUseSystemDescriptionAttributeMessageFormat {
+ get {
+ return ResourceManager.GetString("DoNotUseSystemDescriptionAttributeMessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to 'System.ComponentModel.DescriptionAttribute' has no effect on test methods.
+ ///
+ internal static string DoNotUseSystemDescriptionAttributeTitle {
+ get {
+ return ResourceManager.GetString("DoNotUseSystemDescriptionAttributeTitle", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert.
///
@@ -677,6 +469,33 @@ internal static string PreferTestInitializeOverConstructorTitle {
}
}
+ ///
+ /// Looks up a localized string similar to Public methods should be test methods (marked with `[TestMethod]`)..
+ ///
+ internal static string PublicMethodShouldBeTestMethodAnalyzerDescription {
+ get {
+ return ResourceManager.GetString("PublicMethodShouldBeTestMethodAnalyzerDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Public method '{0}' should be a test method.
+ ///
+ internal static string PublicMethodShouldBeTestMethodAnalyzerFormat {
+ get {
+ return ResourceManager.GetString("PublicMethodShouldBeTestMethodAnalyzerFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Public methods should be test methods.
+ ///
+ internal static string PublicMethodShouldBeTestMethodAnalyzerTitle {
+ get {
+ return ResourceManager.GetString("PublicMethodShouldBeTestMethodAnalyzerTitle", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to It's considered a good practice to have only test classes marked public in a test project..
///
@@ -704,6 +523,24 @@ internal static string PublicTypeShouldBeTestClassTitle {
}
}
+ ///
+ /// Looks up a localized string similar to Review or remove the assertion as its condition is known to be always true.
+ ///
+ internal static string ReviewAlwaysTrueAssertConditionAnalyzerMessageFormat {
+ get {
+ return ResourceManager.GetString("ReviewAlwaysTrueAssertConditionAnalyzerMessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Assertion condition is always true.
+ ///
+ internal static string ReviewAlwaysTrueAssertConditionAnalyzerTitle {
+ get {
+ return ResourceManager.GetString("ReviewAlwaysTrueAssertConditionAnalyzerTitle", 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)
@@ -781,14 +618,14 @@ internal static string TestClassShouldHaveTestMethodTitle {
///
/// Looks up a localized string similar to Methods marked with [TestCleanup] should follow the following layout to be valid:
- ///- it should be 'public'
- ///- it should not be 'static'
- ///- it should not be generic
- ///- it should not be 'abstract'
- ///- it should not take any parameter
+ ///- be 'public'
+ ///- not be 'static'
+ ///- not be generic or be defined on a generic class
+ ///- not be 'abstract'
+ ///- not take any parameter
///- return type should be 'void', 'Task' or 'ValueTask'
- ///- it should not be 'async void'
- ///- it should not be a special method (finalizer, operator...)..
+ ///- not be 'async void'
+ ///- not be a special method (finalizer, operator...)..
///
internal static string TestCleanupShouldBeValidDescription {
get {
@@ -797,74 +634,11 @@ internal static string TestCleanupShouldBeValidDescription {
}
///
- /// Looks up a localized string similar to TestCleanup method '{0}' should not take any parameter.
- ///
- internal static string TestCleanupShouldBeValidMessageFormat_NoParameters {
- get {
- return ResourceManager.GetString("TestCleanupShouldBeValidMessageFormat_NoParameters", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestCleanup method '{0}' should not be 'abstract'.
- ///
- internal static string TestCleanupShouldBeValidMessageFormat_NotAbstract {
- get {
- return ResourceManager.GetString("TestCleanupShouldBeValidMessageFormat_NotAbstract", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestCleanup method '{0}' should not be 'async void'.
+ /// Looks up a localized string similar to TestCleanup method '{0}' signature is invalid.
///
- internal static string TestCleanupShouldBeValidMessageFormat_NotAsyncVoid {
+ internal static string TestCleanupShouldBeValidMessageFormat {
get {
- return ResourceManager.GetString("TestCleanupShouldBeValidMessageFormat_NotAsyncVoid", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestCleanup method '{0}' should not be generic.
- ///
- internal static string TestCleanupShouldBeValidMessageFormat_NotGeneric {
- get {
- return ResourceManager.GetString("TestCleanupShouldBeValidMessageFormat_NotGeneric", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestCleanup method '{0}' should not be 'static'.
- ///
- internal static string TestCleanupShouldBeValidMessageFormat_NotStatic {
- get {
- return ResourceManager.GetString("TestCleanupShouldBeValidMessageFormat_NotStatic", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestCleanup method '{0}' should be an 'ordinary' method.
- ///
- internal static string TestCleanupShouldBeValidMessageFormat_Ordinary {
- get {
- return ResourceManager.GetString("TestCleanupShouldBeValidMessageFormat_Ordinary", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestCleanup method '{0}' should be 'public'.
- ///
- internal static string TestCleanupShouldBeValidMessageFormat_Public {
- get {
- return ResourceManager.GetString("TestCleanupShouldBeValidMessageFormat_Public", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'.
- ///
- internal static string TestCleanupShouldBeValidMessageFormat_ReturnType {
- get {
- return ResourceManager.GetString("TestCleanupShouldBeValidMessageFormat_ReturnType", resourceCulture);
+ return ResourceManager.GetString("TestCleanupShouldBeValidMessageFormat", resourceCulture);
}
}
@@ -946,14 +720,14 @@ internal static string TestContextShouldBeValidTitle {
///
/// Looks up a localized string similar to Methods marked with [TestInitialize] should follow the following layout to be valid:
- ///- it should be 'public'
- ///- it should not be 'static'
- ///- it should not be generic
- ///- it should not be 'abstract'
- ///- it should not take any parameter
+ ///- be 'public'
+ ///- not be 'static'
+ ///- not be generic nor defined on a generic class
+ ///- not be 'abstract'
+ ///- not take any parameter
///- return type should be 'void', 'Task' or 'ValueTask'
- ///- it should not be 'async void'
- ///- it should not be a special method (finalizer, operator...)..
+ ///- not be 'async void'
+ ///- not be a special method (finalizer, operator...)..
///
internal static string TestInitializeShouldBeValidDescription {
get {
@@ -962,74 +736,11 @@ internal static string TestInitializeShouldBeValidDescription {
}
///
- /// Looks up a localized string similar to TestInitialize method '{0}' should not take any parameter.
- ///
- internal static string TestInitializeShouldBeValidMessageFormat_NoParameters {
- get {
- return ResourceManager.GetString("TestInitializeShouldBeValidMessageFormat_NoParameters", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestInitialize method '{0}' should not be 'abstract'.
- ///
- internal static string TestInitializeShouldBeValidMessageFormat_NotAbstract {
- get {
- return ResourceManager.GetString("TestInitializeShouldBeValidMessageFormat_NotAbstract", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestInitialize method '{0}' should not be 'async void'.
- ///
- internal static string TestInitializeShouldBeValidMessageFormat_NotAsyncVoid {
- get {
- return ResourceManager.GetString("TestInitializeShouldBeValidMessageFormat_NotAsyncVoid", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestInitialize method '{0}' should not be generic.
- ///
- internal static string TestInitializeShouldBeValidMessageFormat_NotGeneric {
- get {
- return ResourceManager.GetString("TestInitializeShouldBeValidMessageFormat_NotGeneric", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestInitialize method '{0}' should not be 'static'.
- ///
- internal static string TestInitializeShouldBeValidMessageFormat_NotStatic {
- get {
- return ResourceManager.GetString("TestInitializeShouldBeValidMessageFormat_NotStatic", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestInitialize method '{0}' should be an 'ordinary' method.
- ///
- internal static string TestInitializeShouldBeValidMessageFormat_Ordinary {
- get {
- return ResourceManager.GetString("TestInitializeShouldBeValidMessageFormat_Ordinary", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestInitialize method '{0}' should be 'public'.
- ///
- internal static string TestInitializeShouldBeValidMessageFormat_Public {
- get {
- return ResourceManager.GetString("TestInitializeShouldBeValidMessageFormat_Public", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'.
+ /// Looks up a localized string similar to TestInitialize method '{0}' signature is invalid.
///
- internal static string TestInitializeShouldBeValidMessageFormat_ReturnType {
+ internal static string TestInitializeShouldBeValidMessageFormat {
get {
- return ResourceManager.GetString("TestInitializeShouldBeValidMessageFormat_ReturnType", resourceCulture);
+ return ResourceManager.GetString("TestInitializeShouldBeValidMessageFormat", resourceCulture);
}
}
@@ -1166,6 +877,51 @@ 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..
+ ///
+ internal static string TypeContainingTestMethodShouldBeATestClassDescription {
+ get {
+ return ResourceManager.GetString("TypeContainingTestMethodShouldBeATestClassDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Class '{0}' contains test methods and should be marked with '[TestClass]'.
+ ///
+ internal static string TypeContainingTestMethodShouldBeATestClassMessageFormat {
+ get {
+ return ResourceManager.GetString("TypeContainingTestMethodShouldBeATestClassMessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Type containing '[TestMethod]' should be marked with '[TestClass]'.
+ ///
+ internal static string TypeContainingTestMethodShouldBeATestClassTitle {
+ get {
+ return ResourceManager.GetString("TypeContainingTestMethodShouldBeATestClassTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Asynchronous test fixture methods do not require the 'Async' suffix.
+ ///
+ internal static string UseAsyncSuffixTestFixtureMethodSuppressorJustification {
+ get {
+ return ResourceManager.GetString("UseAsyncSuffixTestFixtureMethodSuppressorJustification", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Asynchronous test methods do not require the 'Async' suffix.
+ ///
+ internal static string UseAsyncSuffixTestMethodSuppressorJustification {
+ get {
+ return ResourceManager.GetString("UseAsyncSuffixTestMethodSuppressorJustification", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to [{0}] can only be set on methods marked with [TestMethod].
///
diff --git a/src/Analyzers/MSTest.Analyzers/Resources.resx b/src/Analyzers/MSTest.Analyzers/Resources.resx
index 17607ff84d..df12f9b58a 100644
--- a/src/Analyzers/MSTest.Analyzers/Resources.resx
+++ b/src/Analyzers/MSTest.Analyzers/Resources.resx
@@ -119,78 +119,42 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
-
-
- AssemblyCleanup method '{0}' should not take any parameter
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
-
-
- AssemblyCleanup method '{0}' should not be generic
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
-
-
- AssemblyCleanup method '{0}' should be 'public'
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
+- not be 'async void'
+- not be a special method (finalizer, operator...).
-
- AssemblyCleanup method '{0}' should be 'static'
+
+ AssemblyCleanup method '{0}' signature is invalidAssemblyCleanup methods should have valid layoutMethods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
-
-
- AssemblyInitialize method '{0}' should not be generic
-
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
-
-
- AssemblyInitialize method '{0}' should be 'public'
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
-
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
+- not be 'async void'
+- not be a special method (finalizer, operator...).
-
- AssemblyInitialize method '{0}' should be 'static'
+
+ AssemblyInitialize method '{0}' signature is invalidAssemblyInitialize methods should have valid layout
+
+ Prefer adding an additional assertion that checks for null
+
+
+ Avoid conditional access in assertions
+
'Assert.AreEqual', 'Assert.AreNotEqual', 'Assert.AreSame' and 'Assert.AreNotSame' expects the expected value to be passed first and the actual value to be passed as second argument.
@@ -211,74 +175,32 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
-
-
- ClassCleanup method '{0}' should not take any parameter
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
-
-
- ClassCleanup method '{0}' should not be generic
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
+- not be 'async void'
+- not be a special method (finalizer, operator...).
-
- ClassCleanup method '{0}' should be 'public'
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
-
-
- ClassCleanup method '{0}' should be 'static'
+
+ ClassCleanup method '{0}' signature is invalidClassCleanup methods should have valid layoutMethods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
-
-
- ClassInitialize method '{0}' should not be generic
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
-
-
- ClassInitialize method '{0}' should be 'public'
+- not be 'async void'
+- not be a special method (finalizer, operator...).
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
-
-
- ClassInitialize method '{0}' should be 'static'
+
+ ClassInitialize method '{0}' signature is invalidClassInitialize methods should have valid layout
@@ -343,6 +265,15 @@
Prefer TestInitialize methods over constructors
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+ Public method '{0}' should be a test method
+
+
+ Public methods should be test methods
+
It's considered a good practice to have only test classes marked public in a test project.
@@ -381,38 +312,17 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
-
- TestCleanup method '{0}' should not take any parameter
-
-
- TestCleanup method '{0}' should not be 'abstract'
-
-
- TestCleanup method '{0}' should not be 'async void'
-
-
- TestCleanup method '{0}' should not be generic
-
-
- TestCleanup method '{0}' should not be 'static'
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
-
-
- TestCleanup method '{0}' should be 'public'
-
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
+
+ TestCleanup method '{0}' signature is invalidTestCleanup method should have valid layout
@@ -444,38 +354,17 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
-
-
- TestInitialize method '{0}' should not take any parameter
-
-
- TestInitialize method '{0}' should not be 'abstract'
-
-
- TestInitialize method '{0}' should not be 'async void'
+- not be 'async void'
+- not be a special method (finalizer, operator...).
-
- TestInitialize method '{0}' should not be generic
-
-
- TestInitialize method '{0}' should not be 'static'
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
-
-
- TestInitialize method '{0}' should be 'public'
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
+
+ TestInitialize method '{0}' signature is invalidTestInitialize method should have valid layout
@@ -526,6 +415,12 @@
Test method should not be ignored
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+
[{0}] can only be set on methods marked with [TestMethod]
@@ -541,4 +436,28 @@
Explicitly enable or disable tests parallelization
+
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+
+
+ Type contaning '[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]'
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+
+
+ Assertion condition is always true
+
+
+ Review or remove the assertion as its condition is known to be always true
+
\ No newline at end of file
diff --git a/src/Analyzers/MSTest.Analyzers/ReviewAlwaysTrueAssertConditionAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/ReviewAlwaysTrueAssertConditionAnalyzer.cs
new file mode 100644
index 0000000000..662877724d
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/ReviewAlwaysTrueAssertConditionAnalyzer.cs
@@ -0,0 +1,120 @@
+// 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;
+using MSTest.Analyzers.RoslynAnalyzerHelpers;
+
+namespace MSTest.Analyzers;
+
+///
+/// MSTEST0032: .
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+public sealed class ReviewAlwaysTrueAssertConditionAnalyzer : DiagnosticAnalyzer
+{
+ private enum EqualityStatus
+ {
+ Unknown,
+ Equal,
+ NotEqual,
+ }
+
+ private const string ExpectedParameterName = "expected";
+ private const string NotExpectedParameterName = "notExpected";
+ private const string ActualParameterName = "actual";
+ private const string ConditionParameterName = "condition";
+ private const string ValueParameterName = "value";
+
+ private static readonly LocalizableResourceString Title = new(nameof(Resources.ReviewAlwaysTrueAssertConditionAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.ReviewAlwaysTrueAssertConditionAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
+
+ internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
+ DiagnosticIds.ReviewAlwaysTrueAssertConditionAnalyzerRuleId,
+ Title,
+ MessageFormat,
+ null,
+ Category.Design,
+ DiagnosticSeverity.Info,
+ isEnabledByDefault: true);
+
+ public override ImmutableArray SupportedDiagnostics { get; }
+ = ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.EnableConcurrentExecution();
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
+
+ context.RegisterCompilationStartAction(context =>
+ {
+ Compilation compilation = context.Compilation;
+ INamedTypeSymbol? assertSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssert);
+ INamedTypeSymbol? nullableSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemNullable);
+ if (assertSymbol is not null)
+ {
+ context.RegisterOperationAction(context => AnalyzeOperation(context, assertSymbol, nullableSymbol), OperationKind.Invocation);
+ }
+ });
+ }
+
+ private static void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol assertSymbol, INamedTypeSymbol? nullableSymbol)
+ {
+ var operation = (IInvocationOperation)context.Operation;
+ if (assertSymbol.Equals(operation.TargetMethod.ContainingType, SymbolEqualityComparer.Default) &&
+ IsAlwaysTrue(operation, nullableSymbol))
+ {
+ context.ReportDiagnostic(operation.CreateDiagnostic(Rule));
+ }
+ }
+
+ private static bool IsAlwaysTrue(IInvocationOperation operation, INamedTypeSymbol? nullableSymbol)
+ => operation.TargetMethod.Name switch
+ {
+ "IsTrue" => GetConditionArgument(operation) is { Value.ConstantValue: { HasValue: true, Value: true } },
+ "IsFalse" => GetConditionArgument(operation) is { Value.ConstantValue: { HasValue: true, Value: false } },
+ "AreEqual" => GetEqualityStatus(operation, ExpectedParameterName) == EqualityStatus.Equal,
+ "AreNotEqual" => GetEqualityStatus(operation, NotExpectedParameterName) == EqualityStatus.NotEqual,
+ "IsNull" => GetValueArgument(operation) is { Value.ConstantValue: { HasValue: true, Value: null } },
+ "IsNotNull" => GetValueArgument(operation) is { } valueArgumentOperation && IsNotNullableType(valueArgumentOperation, nullableSymbol),
+ _ => false,
+ };
+
+ private static bool IsNotNullableType(IArgumentOperation valueArgumentOperation, INamedTypeSymbol? nullableSymbol)
+ {
+ ITypeSymbol? valueArgType = valueArgumentOperation.Value.GetReferencedMemberOrLocalOrParameter().GetReferencedMemberOrLocalOrParameter();
+ return valueArgType is not null
+ && valueArgType.NullableAnnotation == NullableAnnotation.NotAnnotated
+ && !SymbolEqualityComparer.IncludeNullability.Equals(valueArgType.OriginalDefinition, nullableSymbol);
+ }
+
+ private static IArgumentOperation? GetArgumentWithName(IInvocationOperation operation, string name)
+ => operation.Arguments.FirstOrDefault(arg => arg.Parameter?.Name == name);
+
+ private static IArgumentOperation? GetConditionArgument(IInvocationOperation operation)
+ => GetArgumentWithName(operation, ConditionParameterName);
+
+ private static IArgumentOperation? GetValueArgument(IInvocationOperation operation)
+ => GetArgumentWithName(operation, ValueParameterName);
+
+ private static EqualityStatus GetEqualityStatus(IInvocationOperation operation, string expectedOrNotExpectedParameterName)
+ {
+ if (GetArgumentWithName(operation, expectedOrNotExpectedParameterName) is { } expectedOrNotExpectedArgument &&
+ GetArgumentWithName(operation, ActualParameterName) is { } actualArgument &&
+ expectedOrNotExpectedArgument.Value.ConstantValue.HasValue &&
+ actualArgument.Value.ConstantValue.HasValue)
+ {
+ return Equals(expectedOrNotExpectedArgument.Value.ConstantValue.Value, actualArgument.Value.ConstantValue.Value) ? EqualityStatus.Equal : EqualityStatus.NotEqual;
+ }
+
+ // We are not sure about the equality status
+ return EqualityStatus.Unknown;
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/BoundedCacheWithFactory.cs b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/BoundedCacheWithFactory.cs
index 18ef7d5999..70cd5b5113 100644
--- a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/BoundedCacheWithFactory.cs
+++ b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/BoundedCacheWithFactory.cs
@@ -12,14 +12,14 @@ internal class BoundedCacheWithFactory
{
// Bounded weak reference cache.
// Size 5 is an arbitrarily chosen bound, which can be tuned in future as required.
- private readonly List> _weakReferencedEntries = new()
- {
- new WeakReference(null),
+ private readonly List> _weakReferencedEntries =
+ [
new WeakReference(null),
new WeakReference(null),
new WeakReference(null),
new WeakReference(null),
- };
+ new WeakReference(null)
+ ];
public TValue GetOrCreateValue(TKey key, Func valueFactory)
{
diff --git a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/DiagnosticExtensions.cs b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/DiagnosticExtensions.cs
index b3b3dbe380..be456a6521 100644
--- a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/DiagnosticExtensions.cs
+++ b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/DiagnosticExtensions.cs
@@ -8,7 +8,7 @@
namespace Analyzer.Utilities.Extensions
{
- internal static class DiagnosticExtensions
+ internal static class FixtureUtils
{
public static Diagnostic CreateDiagnostic(
this SyntaxNode node,
@@ -207,11 +207,11 @@ public static void ReportNoLocationDiagnostic(
object?[] parameters;
if (syntaxTreeOptionsProviderTryGetDiagnosticValueMethod.GetParameters().Length == 3)
{
- parameters = new object?[] { tree, rule.Id, null };
+ parameters = [tree, rule.Id, null];
}
else
{
- parameters = new object?[] { tree, rule.Id, CancellationToken.None, null };
+ parameters = [tree, rule.Id, CancellationToken.None, null];
}
if (syntaxTreeOptionsProviderTryGetDiagnosticValueMethod.Invoke(syntaxTreeOptionsProvider, parameters) is true &&
diff --git a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/WellKnownTypeProvider.cs b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/WellKnownTypeProvider.cs
index 71cbc2f86a..b994f452f5 100644
--- a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/WellKnownTypeProvider.cs
+++ b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/WellKnownTypeProvider.cs
@@ -26,7 +26,7 @@ public class WellKnownTypeProvider
private WellKnownTypeProvider(Compilation compilation)
{
Compilation = compilation;
- _fullNameToTypeMap = new ConcurrentDictionary(StringComparer.Ordinal);
+ _fullNameToTypeMap = new ConcurrentDictionary();
_referencedAssemblies = new Lazy>(
() => Compilation.Assembly.Modules
.SelectMany(m => m.ReferencedAssemblySymbols)
@@ -60,21 +60,19 @@ public static WellKnownTypeProvider GetOrCreate(Compilation compilation)
///
private readonly ConcurrentDictionary _fullNameToTypeMap;
-#if !NETSTANDARD1_3 // Assuming we're on .NET Standard 2.0 or later, cache the type names that are probably compile time constants.
///
/// Static cache of full type names (with namespaces) to namespace name parts,
/// so we can query .
///
///
+ ///
/// Example: "System.Collections.Generic.List`1" => [ "System", "Collections", "Generic" ]
///
/// https://github.com/dotnet/roslyn/blob/9e786147b8cb884af454db081bb747a5bd36a086/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs#L455
/// suggests the TypeNames collection can be checked to avoid expensive operations. But realizing TypeNames seems to be
/// as memory intensive as unnecessary calls GetTypeByMetadataName() in some cases. So we'll go with namespace names.
///
- private static readonly ConcurrentDictionary> _fullTypeNameToNamespaceNames =
- new(StringComparer.Ordinal);
-#endif
+ private static readonly ConcurrentDictionary> _fullTypeNameToNamespaceNames = new();
///
/// Attempts to get the type by the full type name.
@@ -112,9 +110,7 @@ private bool TryGetOrCreateTypeByMetadataNameSlow(
INamedTypeSymbol? type = null;
ImmutableArray namespaceNames;
-#if NETSTANDARD1_3 // Probably in 2.9.x branch; just don't cache.
- namespaceNames = GetNamespaceNamesFromFullTypeName(fullTypeName);
-#else // Assuming we're on .NET Standard 2.0 or later, cache the type names that are probably compile time constants.
+ // Assuming we're on .NET Standard 2.0 or later, cache the type names that are probably compile time constants.
if (string.IsInterned(fullTypeName) != null)
{
namespaceNames = _fullTypeNameToNamespaceNames.GetOrAdd(
@@ -125,7 +121,6 @@ private bool TryGetOrCreateTypeByMetadataNameSlow(
{
namespaceNames = GetNamespaceNamesFromFullTypeName(fullTypeName);
}
-#endif
if (IsSubsetOfCollection(namespaceNames, Compilation.Assembly.NamespaceNames))
{
@@ -261,12 +256,6 @@ private static bool IsIdentifierPartCharacter(char ch)
UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory(ch);
- ////return IsLetterChar(cat)
- //// || IsDecimalDigitChar(cat)
- //// || IsConnectingChar(cat)
- //// || IsCombiningChar(cat)
- //// || IsFormattingChar(cat);
-
return cat switch
{
// Letter
diff --git a/src/Analyzers/MSTest.Analyzers/TestClassShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestClassShouldBeValidAnalyzer.cs
index b03d4feeb5..6b1c146d20 100644
--- a/src/Analyzers/MSTest.Analyzers/TestClassShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/TestClassShouldBeValidAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0002: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class TestClassShouldBeValidAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/TestClassShouldHaveTestMethodAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestClassShouldHaveTestMethodAnalyzer.cs
index c8a27326a6..3f8b36c49a 100644
--- a/src/Analyzers/MSTest.Analyzers/TestClassShouldHaveTestMethodAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/TestClassShouldHaveTestMethodAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0016: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class TestClassShouldHaveTestMethodAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/TestCleanupShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestCleanupShouldBeValidAnalyzer.cs
index cd21ce8595..8c3c74b4e9 100644
--- a/src/Analyzers/MSTest.Analyzers/TestCleanupShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/TestCleanupShouldBeValidAnalyzer.cs
@@ -12,32 +12,22 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0009: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class TestCleanupShouldBeValidAnalyzer : DiagnosticAnalyzer
{
- private static readonly LocalizableResourceString Title = new(nameof(Resources.TestCleanupShouldBeValidTitle), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString Description = new(nameof(Resources.TestCleanupShouldBeValidDescription), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.TestCleanupShouldBeValidMessageFormat_Public), Resources.ResourceManager, typeof(Resources));
-
- internal static readonly DiagnosticDescriptor PublicRule = DiagnosticDescriptorHelper.Create(
+ internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
DiagnosticIds.TestCleanupShouldBeValidRuleId,
- Title,
- MessageFormat,
- Description,
+ new LocalizableResourceString(nameof(Resources.TestCleanupShouldBeValidTitle), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.TestCleanupShouldBeValidMessageFormat), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.TestCleanupShouldBeValidDescription), Resources.ResourceManager, typeof(Resources)),
Category.Usage,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
- internal static readonly DiagnosticDescriptor NotStaticRule = PublicRule.WithMessage(new(nameof(Resources.TestCleanupShouldBeValidMessageFormat_NotStatic), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NoParametersRule = PublicRule.WithMessage(new(nameof(Resources.TestCleanupShouldBeValidMessageFormat_NoParameters), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor ReturnTypeRule = PublicRule.WithMessage(new(nameof(Resources.TestCleanupShouldBeValidMessageFormat_ReturnType), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAsyncVoidRule = PublicRule.WithMessage(new(nameof(Resources.TestCleanupShouldBeValidMessageFormat_NotAsyncVoid), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAbstractRule = PublicRule.WithMessage(new(nameof(Resources.TestCleanupShouldBeValidMessageFormat_NotAbstract), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotGenericRule = PublicRule.WithMessage(new(nameof(Resources.TestCleanupShouldBeValidMessageFormat_NotGeneric), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor OrdinaryRule = PublicRule.WithMessage(new(nameof(Resources.TestCleanupShouldBeValidMessageFormat_Ordinary), Resources.ResourceManager, typeof(Resources)));
-
- public override ImmutableArray SupportedDiagnostics { get; }
- = ImmutableArray.Create(PublicRule);
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
@@ -46,70 +36,30 @@ public override void Initialize(AnalysisContext context)
context.RegisterCompilationStartAction(context =>
{
- if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestCleanupAttribute, out INamedTypeSymbol? testCleanupAttributeSymbol))
+ if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestCleanupAttribute, out INamedTypeSymbol? testCleanupAttributeSymbol)
+ && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol))
{
INamedTypeSymbol? taskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask);
INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask);
bool canDiscoverInternals = context.Compilation.CanDiscoverInternals();
context.RegisterSymbolAction(
- context => AnalyzeSymbol(context, testCleanupAttributeSymbol, taskSymbol, valueTaskSymbol, canDiscoverInternals),
+ context => AnalyzeSymbol(context, testCleanupAttributeSymbol, taskSymbol, valueTaskSymbol, testClassAttributeSymbol, canDiscoverInternals),
SymbolKind.Method);
}
});
}
private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol testCleanupAttributeSymbol, INamedTypeSymbol? taskSymbol,
- INamedTypeSymbol? valueTaskSymbol, bool canDiscoverInternals)
+ INamedTypeSymbol? valueTaskSymbol, INamedTypeSymbol testClassAttributeSymbol, bool canDiscoverInternals)
{
var methodSymbol = (IMethodSymbol)context.Symbol;
- if (!methodSymbol.IsTestCleanupMethod(testCleanupAttributeSymbol))
- {
- return;
- }
-
- if (methodSymbol.MethodKind != MethodKind.Ordinary)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(OrdinaryRule, methodSymbol.Name));
-
- // Do not check the other criteria, users should fix the method kind first.
- return;
- }
-
- if (methodSymbol.IsAbstract)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAbstractRule, methodSymbol.Name));
- }
-
- if (methodSymbol.IsGenericMethod)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotGenericRule, methodSymbol.Name));
- }
-
- if (methodSymbol.Parameters.Length > 0)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NoParametersRule, methodSymbol.Name));
- }
-
- if (methodSymbol.IsStatic)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotStaticRule, methodSymbol.Name));
- }
-
- if (methodSymbol.ReturnsVoid && methodSymbol.IsAsync)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAsyncVoidRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsPublicAndHasCorrectResultantVisibility(canDiscoverInternals))
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(PublicRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.ReturnsVoid
- && (taskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, taskSymbol))
- && (valueTaskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, valueTaskSymbol)))
+ if (methodSymbol.IsTestCleanupMethod(testCleanupAttributeSymbol)
+ && !methodSymbol.HasValidFixtureMethodSignature(taskSymbol, valueTaskSymbol, canDiscoverInternals, shouldBeStatic: false,
+ allowGenericType: false, testContextSymbol: null, testClassAttributeSymbol, fixtureAllowInheritedTestClass: true, out bool isFixable))
{
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(ReturnTypeRule, methodSymbol.Name));
+ context.ReportDiagnostic(isFixable
+ ? methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name)
+ : methodSymbol.CreateDiagnostic(Rule, DiagnosticDescriptorHelper.CannotFixProperties, methodSymbol.Name));
}
}
}
diff --git a/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs
index 94107b3b74..3e1163b3d4 100644
--- a/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0005: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class TestContextShouldBeValidAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/TestInitializeShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestInitializeShouldBeValidAnalyzer.cs
index c7bdf3139f..ccecb936af 100644
--- a/src/Analyzers/MSTest.Analyzers/TestInitializeShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/TestInitializeShouldBeValidAnalyzer.cs
@@ -12,32 +12,22 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0008: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class TestInitializeShouldBeValidAnalyzer : DiagnosticAnalyzer
{
- private static readonly LocalizableResourceString Title = new(nameof(Resources.TestInitializeShouldBeValidTitle), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString Description = new(nameof(Resources.TestInitializeShouldBeValidDescription), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.TestInitializeShouldBeValidMessageFormat_Public), Resources.ResourceManager, typeof(Resources));
-
- internal static readonly DiagnosticDescriptor PublicRule = DiagnosticDescriptorHelper.Create(
+ internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
DiagnosticIds.TestInitializeShouldBeValidRuleId,
- Title,
- MessageFormat,
- Description,
+ new LocalizableResourceString(nameof(Resources.TestInitializeShouldBeValidTitle), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.TestInitializeShouldBeValidMessageFormat), Resources.ResourceManager, typeof(Resources)),
+ new LocalizableResourceString(nameof(Resources.TestInitializeShouldBeValidDescription), Resources.ResourceManager, typeof(Resources)),
Category.Usage,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
- internal static readonly DiagnosticDescriptor NotStaticRule = PublicRule.WithMessage(new(nameof(Resources.TestInitializeShouldBeValidMessageFormat_NotStatic), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NoParametersRule = PublicRule.WithMessage(new(nameof(Resources.TestInitializeShouldBeValidMessageFormat_NoParameters), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor ReturnTypeRule = PublicRule.WithMessage(new(nameof(Resources.TestInitializeShouldBeValidMessageFormat_ReturnType), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAsyncVoidRule = PublicRule.WithMessage(new(nameof(Resources.TestInitializeShouldBeValidMessageFormat_NotAsyncVoid), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotAbstractRule = PublicRule.WithMessage(new(nameof(Resources.TestInitializeShouldBeValidMessageFormat_NotAbstract), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor NotGenericRule = PublicRule.WithMessage(new(nameof(Resources.TestInitializeShouldBeValidMessageFormat_NotGeneric), Resources.ResourceManager, typeof(Resources)));
- internal static readonly DiagnosticDescriptor OrdinaryRule = PublicRule.WithMessage(new(nameof(Resources.TestInitializeShouldBeValidMessageFormat_Ordinary), Resources.ResourceManager, typeof(Resources)));
-
- public override ImmutableArray SupportedDiagnostics { get; }
- = ImmutableArray.Create(PublicRule);
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
@@ -46,70 +36,30 @@ public override void Initialize(AnalysisContext context)
context.RegisterCompilationStartAction(context =>
{
- if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestInitializeAttribute, out INamedTypeSymbol? testInitializeAttributeSymbol))
+ if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestInitializeAttribute, out INamedTypeSymbol? testInitializeAttributeSymbol)
+ && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol))
{
INamedTypeSymbol? taskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask);
INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask);
bool canDiscoverInternals = context.Compilation.CanDiscoverInternals();
context.RegisterSymbolAction(
- context => AnalyzeSymbol(context, testInitializeAttributeSymbol, taskSymbol, valueTaskSymbol, canDiscoverInternals),
+ context => AnalyzeSymbol(context, testInitializeAttributeSymbol, taskSymbol, valueTaskSymbol, testClassAttributeSymbol, canDiscoverInternals),
SymbolKind.Method);
}
});
}
private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol testInitializeAttributeSymbol, INamedTypeSymbol? taskSymbol,
- INamedTypeSymbol? valueTaskSymbol, bool canDiscoverInternals)
+ INamedTypeSymbol? valueTaskSymbol, INamedTypeSymbol testClassAttributeSymbol, bool canDiscoverInternals)
{
var methodSymbol = (IMethodSymbol)context.Symbol;
- if (!methodSymbol.IsTestInitializeMethod(testInitializeAttributeSymbol))
- {
- return;
- }
-
- if (methodSymbol.MethodKind != MethodKind.Ordinary)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(OrdinaryRule, methodSymbol.Name));
-
- // Do not check the other criteria, users should fix the method kind first.
- return;
- }
-
- if (methodSymbol.IsAbstract)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAbstractRule, methodSymbol.Name));
- }
-
- if (methodSymbol.IsGenericMethod)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotGenericRule, methodSymbol.Name));
- }
-
- if (methodSymbol.Parameters.Length > 0)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NoParametersRule, methodSymbol.Name));
- }
-
- if (methodSymbol.IsStatic)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotStaticRule, methodSymbol.Name));
- }
-
- if (methodSymbol.ReturnsVoid && methodSymbol.IsAsync)
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAsyncVoidRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.IsPublicAndHasCorrectResultantVisibility(canDiscoverInternals))
- {
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(PublicRule, methodSymbol.Name));
- }
-
- if (!methodSymbol.ReturnsVoid
- && (taskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, taskSymbol))
- && (valueTaskSymbol is null || !SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, valueTaskSymbol)))
+ if (methodSymbol.IsTestInitializeMethod(testInitializeAttributeSymbol)
+ && !methodSymbol.HasValidFixtureMethodSignature(taskSymbol, valueTaskSymbol, canDiscoverInternals, shouldBeStatic: false,
+ allowGenericType: false, testContextSymbol: null, testClassAttributeSymbol, fixtureAllowInheritedTestClass: true, out bool isFixable))
{
- context.ReportDiagnostic(methodSymbol.CreateDiagnostic(ReturnTypeRule, methodSymbol.Name));
+ context.ReportDiagnostic(isFixable
+ ? methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name)
+ : methodSymbol.CreateDiagnostic(Rule, DiagnosticDescriptorHelper.CannotFixProperties, methodSymbol.Name));
}
}
}
diff --git a/src/Analyzers/MSTest.Analyzers/TestMethodShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestMethodShouldBeValidAnalyzer.cs
index a6ede1d760..fb4cd2e5fe 100644
--- a/src/Analyzers/MSTest.Analyzers/TestMethodShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/TestMethodShouldBeValidAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0003: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class TestMethodShouldBeValidAnalyzer : DiagnosticAnalyzer
{
@@ -102,7 +105,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo
}
}
- if (methodSymbol.ReturnsVoid && methodSymbol.IsAsync)
+ if (methodSymbol is { ReturnsVoid: true, IsAsync: true })
{
context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotAsyncVoidRule, methodSymbol.Name));
}
diff --git a/src/Analyzers/MSTest.Analyzers/TestMethodShouldNotBeIgnoredAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestMethodShouldNotBeIgnoredAnalyzer.cs
index 82505600fd..c1bd4ae1fd 100644
--- a/src/Analyzers/MSTest.Analyzers/TestMethodShouldNotBeIgnoredAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/TestMethodShouldNotBeIgnoredAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0015: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class TestMethodShouldNotBeIgnoredAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs
new file mode 100644
index 0000000000..f89aa288f8
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/TypeContainingTestMethodShouldBeATestClassAnalyzer.cs
@@ -0,0 +1,115 @@
+// 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;
+
+///
+/// MSTEST0030: .
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+public sealed class TypeContainingTestMethodShouldBeATestClassAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly LocalizableResourceString Title = new(nameof(Resources.TypeContainingTestMethodShouldBeATestClassTitle), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableResourceString Description = new(nameof(Resources.TypeContainingTestMethodShouldBeATestClassDescription), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.TypeContainingTestMethodShouldBeATestClassMessageFormat), Resources.ResourceManager, typeof(Resources));
+
+ internal static readonly DiagnosticDescriptor TypeContainingTestMethodShouldBeATestClassRule = DiagnosticDescriptorHelper.Create(
+ DiagnosticIds.TypeContainingTestMethodShouldBeATestClassRuleId,
+ Title,
+ MessageFormat,
+ Description,
+ Category.Usage,
+ DiagnosticSeverity.Info,
+ isEnabledByDefault: true);
+
+ public override ImmutableArray SupportedDiagnostics { get; }
+ = ImmutableArray.Create(TypeContainingTestMethodShouldBeATestClassRule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+
+ context.RegisterCompilationStartAction(context =>
+ {
+ if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestMethodAttribute, out INamedTypeSymbol? testMethodAttributeSymbol)
+ && context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol))
+ {
+ context.RegisterSymbolAction(
+ context => AnalyzeSymbol(context, testClassAttributeSymbol, testMethodAttributeSymbol),
+ SymbolKind.NamedType);
+ }
+ });
+ }
+
+ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol testClassAttributeSymbol, INamedTypeSymbol testMethodAttributeSymbol)
+ {
+ var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
+ if (namedTypeSymbol.TypeKind != TypeKind.Class
+ || namedTypeSymbol.IsAbstract)
+ {
+ return;
+ }
+
+ bool isTestClass = false;
+ foreach (AttributeData classAttribute in namedTypeSymbol.GetAttributes())
+ {
+ if (classAttribute.AttributeClass.Inherits(testClassAttributeSymbol))
+ {
+ isTestClass = true;
+ break;
+ }
+ }
+
+ if (isTestClass)
+ {
+ return;
+ }
+
+ bool hasTestMethod = false;
+ INamedTypeSymbol? currentType = namedTypeSymbol;
+ do
+ {
+ foreach (ISymbol classMember in currentType.GetMembers())
+ {
+ if (classMember.Kind != SymbolKind.Method)
+ {
+ continue;
+ }
+
+ foreach (AttributeData attribute in classMember.GetAttributes())
+ {
+ if (attribute.AttributeClass.Inherits(testMethodAttributeSymbol))
+ {
+ hasTestMethod = true;
+ break;
+ }
+ }
+
+ if (!hasTestMethod)
+ {
+ break;
+ }
+ }
+
+ currentType = currentType.BaseType;
+ }
+ while (currentType is not null && !hasTestMethod);
+
+ if (!hasTestMethod)
+ {
+ return;
+ }
+
+ context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(TypeContainingTestMethodShouldBeATestClassRule, namedTypeSymbol.Name));
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestFixtureMethodSuppressor.cs b/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestFixtureMethodSuppressor.cs
new file mode 100644
index 0000000000..9ad047e912
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestFixtureMethodSuppressor.cs
@@ -0,0 +1,68 @@
+// 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;
+
+///
+/// MSTEST0028: .
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+public sealed class UseAsyncSuffixTestFixtureMethodSuppressor : DiagnosticSuppressor
+{
+ // VSTHRD200: Use Async suffix for async methods
+ // https://github.com/microsoft/vs-threading/blob/main/doc/analyzers/VSTHRD200.md
+ private const string SuppressedDiagnosticId = "VSTHRD200";
+
+ internal static readonly SuppressionDescriptor Rule =
+ new(DiagnosticIds.UseAsyncSuffixTestFixtureMethodSuppressorRuleId, SuppressedDiagnosticId, Resources.UseAsyncSuffixTestFixtureMethodSuppressorJustification);
+
+ 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.MicrosoftVisualStudioTestToolsUnitTestingAssemblyCleanupAttribute, out INamedTypeSymbol? assemblyCleanupAttributeSymbol)
+ || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassInitializeAttribute, out INamedTypeSymbol? classInitializeAttributeSymbol)
+ || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassCleanupAttribute, out INamedTypeSymbol? classCleanupAttributeSymbol)
+ || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestInitializeAttribute, out INamedTypeSymbol? testInitializeAttributeSymbol)
+ || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestCleanupAttribute, out INamedTypeSymbol? testCleanupAttributeSymbol))
+ {
+ return;
+ }
+
+ foreach (Diagnostic diagnostic in context.ReportedDiagnostics)
+ {
+ // The diagnostic is reported on the test method
+ 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 IMethodSymbol method
+ && method.GetAttributes().Any(attr =>
+ SymbolEqualityComparer.Default.Equals(attr.AttributeClass, assemblyInitializeAttributeSymbol)
+ || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, assemblyCleanupAttributeSymbol)
+ || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classInitializeAttributeSymbol)
+ || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, classCleanupAttributeSymbol)
+ || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testInitializeAttributeSymbol)
+ || SymbolEqualityComparer.Default.Equals(attr.AttributeClass, testCleanupAttributeSymbol)))
+ {
+ context.ReportSuppression(Suppression.Create(Rule, diagnostic));
+ }
+ }
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestMethodSuppressor.cs b/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestMethodSuppressor.cs
new file mode 100644
index 0000000000..048c1a8bc0
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers/UseAsyncSuffixTestMethodSuppressor.cs
@@ -0,0 +1,57 @@
+// 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;
+
+///
+/// MSTEST0027: .
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+public sealed class UseAsyncSuffixTestMethodSuppressor : DiagnosticSuppressor
+{
+ // VSTHRD200: Use Async suffix for async methods
+ // https://github.com/microsoft/vs-threading/blob/main/doc/analyzers/VSTHRD200.md
+ private const string SuppressedDiagnosticId = "VSTHRD200";
+
+ internal static readonly SuppressionDescriptor Rule =
+ new(DiagnosticIds.UseAsyncSuffixTestMethodSuppressorRuleId, SuppressedDiagnosticId, Resources.UseAsyncSuffixTestMethodSuppressorJustification);
+
+ public override ImmutableArray SupportedSuppressions { get; } = ImmutableArray.Create(Rule);
+
+ public override void ReportSuppressions(SuppressionAnalysisContext context)
+ {
+ if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestMethodAttribute, out INamedTypeSymbol? testMethodAttributeSymbol))
+ {
+ return;
+ }
+
+ foreach (Diagnostic diagnostic in context.ReportedDiagnostics)
+ {
+ // The diagnostic is reported on the test method
+ 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 IMethodSymbol method
+ && method.GetAttributes().Any(attr => attr.AttributeClass.Inherits(testMethodAttributeSymbol)))
+ {
+ context.ReportSuppression(Suppression.Create(Rule, diagnostic));
+ }
+ }
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers/UseAttributeOnTestMethodAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/UseAttributeOnTestMethodAnalyzer.cs
index 1fc2dfbf73..95a2f17e09 100644
--- a/src/Analyzers/MSTest.Analyzers/UseAttributeOnTestMethodAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/UseAttributeOnTestMethodAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0007: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class UseAttributeOnTestMethodAnalyzer : DiagnosticAnalyzer
{
@@ -112,8 +115,8 @@ public sealed class UseAttributeOnTestMethodAnalyzer : DiagnosticAnalyzer
isEnabledByDefault: true);
// IMPORTANT: Remember to add any new rule to the rule tuple.
- private static readonly List<(string AttributeFullyQualifiedName, DiagnosticDescriptor Rule)> RuleTuples = new()
- {
+ private static readonly List<(string AttributeFullyQualifiedName, DiagnosticDescriptor Rule)> RuleTuples =
+ [
(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingOwnerAttribute, OwnerRule),
(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingPriorityAttribute, PriorityRule),
(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestPropertyAttribute, TestPropertyRule),
@@ -121,8 +124,8 @@ public sealed class UseAttributeOnTestMethodAnalyzer : DiagnosticAnalyzer
(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingDescriptionAttribute, DescriptionRule),
(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingExpectedExceptionAttribute, ExpectedExceptionRule),
(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingCssIterationAttribute, CssIterationRule),
- (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingCssProjectStructureAttribute, CssProjectStructureRule),
- };
+ (WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingCssProjectStructureAttribute, CssProjectStructureRule)
+ ];
public override ImmutableArray SupportedDiagnostics { get; }
= ImmutableArray.Create(OwnerRule);
@@ -146,7 +149,7 @@ public override void Initialize(AnalysisContext context)
// Get a list of attributes and associated rules that are found in the current compilation
// context.
- List<(INamedTypeSymbol AttributeSymbol, DiagnosticDescriptor Rule)> attributeRuleTuples = new();
+ List<(INamedTypeSymbol AttributeSymbol, DiagnosticDescriptor Rule)> attributeRuleTuples = [];
foreach ((string attributeFullyQualifiedName, DiagnosticDescriptor rule) in RuleTuples)
{
if (context.Compilation.TryGetOrCreateTypeByMetadataName(attributeFullyQualifiedName, out INamedTypeSymbol? attributeSymbol))
@@ -172,7 +175,7 @@ private static void AnalyzeSymbol(
{
var methodSymbol = (IMethodSymbol)context.Symbol;
- List<(AttributeData AttributeData, DiagnosticDescriptor Rule)> attributes = new();
+ List<(AttributeData AttributeData, DiagnosticDescriptor Rule)> attributes = [];
foreach (AttributeData methodAttribute in methodSymbol.GetAttributes())
{
// Current method should be a test method or should inherit from the TestMethod attribute.
diff --git a/src/Analyzers/MSTest.Analyzers/UseParallelizeAttributeAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/UseParallelizeAttributeAnalyzer.cs
index fc43cc423c..b3295b921e 100644
--- a/src/Analyzers/MSTest.Analyzers/UseParallelizeAttributeAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/UseParallelizeAttributeAnalyzer.cs
@@ -12,6 +12,9 @@
namespace MSTest.Analyzers;
+///
+/// MSTEST0001: .
+///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class UseParallelizeAttributeAnalyzer : DiagnosticAnalyzer
{
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf
index d38f1a1d56..870e1193e1 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf
@@ -4,62 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Aby byly metody s označením [AssemblyCleanup] platné, musí se řídit následujícím rozložením:
-.
-– musí být public,
-– musí být static,
-– nesmí být obecné,
-– nesmí přijímat žádný parametr,
+– být „public“
+– být „static“
+– nesmí být obecné ani definované pro obecnou třídu
+– nesmí přijímat žádné parametry
– návratový typ musí být void, Task nebo ValueTask,
-– nesmí být async void,
-– nesmí být speciální metodou (finalizační metoda, operátor...).
+– nesmí být „async void“
+– nesmí se jednat o speciální metodu (finalizační metoda, operátor...).
-
- AssemblyCleanup method '{0}' should not take any parameter
- Metoda AssemblyCleanup {0} by neměla přijímat žádný parametr.
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- Metodu AssemblyCleanup {0} nelze deklarovat pro obecnou třídu.
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda AssemblyCleanup {0} by měla vracet hodnoty void, Task nebo ValueTask.
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- Metoda AssemblyCleanup {0} by neměla být obecná.
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- Metoda AssemblyCleanup {0} by měla být metoda ordinary.
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- Metoda AssemblyCleanup {0} by měla být public.
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda AssemblyCleanup {0} by měla vracet hodnoty void, Task nebo ValueTask.
-
-
-
- AssemblyCleanup method '{0}' should be 'static'
- Metoda AssemblyCleanup {0} by neměla být static.
+
+ AssemblyCleanup method '{0}' signature is invalid
+ Signatura „{0}“ metody AssemblyCleanup je neplatná
@@ -69,67 +33,42 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Aby byly metody s označením [AssemblyInitialize] platné, musí se řídit následujícím rozložením:
.
-– musí být public,
-– musí být static,
-– nesmí být obecné,
-– musí mít jeden parametr typu TestContext,
+– být „public“
+– být „static“
+– nesmí být obecné ani definované pro obecnou třídu
+– převzít jeden parametr typu TestContext
– návratový typ musí být void, Task nebo ValueTask,
-– nesmí být async void,
-– nesmí být speciální metodou (finalizační metoda, operátor...).
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- Metodu AssemblyInitialize {0} nelze deklarovat pro obecnou třídu.
+– nesmí být „async void“
+– nesmí se jednat o speciální metodu (finalizační metoda, operátor...).
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda AssemblyInitialize {0} by měla vracet hodnoty void, Task nebo ValueTask.
+
+ AssemblyInitialize method '{0}' signature is invalid
+ Signatura „{0}“ metody AssemblyInitialize je neplatná
-
- AssemblyInitialize method '{0}' should not be generic
- Metoda AssemblyInitialize {0} by neměla být obecná.
-
-
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- Metoda AssemblyInitialize {0} by měla být metoda ordinary.
-
-
-
- AssemblyInitialize method '{0}' should be 'public'
- Metoda AssemblyInitialize {0} by měla být public.
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda AssemblyInitialize {0} by měla vracet hodnoty void, Task nebo ValueTask.
-
-
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- Metoda AssemblyInitialize {0} by měla mít jeden parametr typu TestContext.
+
+ AssemblyInitialize methods should have valid layout
+ Metody AssemblyInitialize musí mít platné rozložení
-
- AssemblyInitialize method '{0}' should be 'static'
- Metoda AssemblyInitialize {0} by měla být static.
+
+ Prefer adding an additional assertion that checks for null
+ Preferovat přidání dalšího kontrolního výrazu, který kontroluje hodnotu null
-
- AssemblyInitialize methods should have valid layout
- Metody AssemblyInitialize musí mít platné rozložení
+
+ Avoid conditional access in assertions
+ Vyhnout se podmíněnému přístupu v kontrolních výrazech
@@ -164,62 +103,27 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Aby byly metody s označením [ClassCleanup] platné, musí se řídit následujícím rozložením:
.
-– musí být public,
-– nesmí být static,
-– nesmí být obecné,
-– nesmí přijímat žádný parametr,
+– být „public“
+– nesmí být „static“
+– nesmí být obecné ani definované pro obecnou třídu
+– nesmí přijímat žádné parametry
– návratový typ musí být void, Task nebo ValueTask,
-– nesmí být async void,
-– nesmí být speciální metodou (finalizační metoda, operátor...).
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- Metoda ClassCleanup {0} by neměla přijímat žádný parametr.
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Metodu ClassCleanup {0} nelze deklarovat pro obecnou třídu bez nastavení režimu InheritanceBehavior.
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda ClassCleanup {0} by měla vracet hodnoty void, Task nebo ValueTask.
-
-
-
- ClassCleanup method '{0}' should not be generic
- Metoda ClassCleanup {0} by neměla být obecná.
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- Metoda ClassCleanup {0} by měla být metoda ordinary.
+– nesmí být „async void“
+– nesmí se jednat o speciální metodu (finalizační metoda, operátor...).
-
- ClassCleanup method '{0}' should be 'public'
- Metoda ClassCleanup {0} by měla být public.
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda ClassCleanup {0} by měla vracet hodnoty void, Task nebo ValueTask.
-
-
-
- ClassCleanup method '{0}' should be 'static'
- Metoda ClassCleanup {0} by měla být static.
+
+ ClassCleanup method '{0}' signature is invalid
+ Signatura „{0}“ metody ClassCleanup je neplatná
@@ -229,62 +133,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Aby byly metody s označením [ClassInitialize] platné, musí se řídit následujícím rozložením:
-.
-– musí být public,
-– musí být static,
-– nesmí být obecné,
-– musí mít jeden parametr typu TestContext,
+– být „public“
+– být „static“
+– nesmí být obecné ani definované pro obecnou třídu
+– převzít jeden parametr typu TestContext
– návratový typ musí být void, Task nebo ValueTask,
-– nesmí být async void,
-– nesmí být speciální metodou (finalizační metoda, operátor...).
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Metodu ClassInitialize {0} nelze deklarovat pro obecnou třídu bez nastavení režimu InheritanceBehavior.
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda ClassInitialize {0} by měla vracet hodnoty void, Task nebo ValueTask.
-
-
-
- ClassInitialize method '{0}' should not be generic
- Metoda ClassInitialize {0} by neměla být obecná.
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- Metoda ClassInitialize {0} by měla být metoda ordinary.
+– nesmí být „async void“
+– nesmí se jednat o speciální metodu (finalizační metoda, operátor...).
-
- ClassInitialize method '{0}' should be 'public'
- Metoda ClassInitialize {0} by měla být public.
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda ClassInitialize {0} by měla vracet hodnoty void, Task nebo ValueTask.
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- Metoda ClassInitialize {0} by měla mít jeden parametr typu TestContext.
-
-
-
- ClassInitialize method '{0}' should be 'static'
- Metoda ClassInitialize {0} by měla být static.
+
+ ClassInitialize method '{0}' signature is invalid
+ Signatura „{0}“ metody ClassInitialize je neplatná
@@ -343,6 +211,21 @@
Neukládejte TestContext ve statickém členu
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assertMísto trvalého neúspěšného vyhodnocovacího výrazu „Assert.{0}“ použijte „Assert.Fail“.
@@ -353,6 +236,16 @@
Místo trvalého neúspěšného vyhodnocovacího výrazu použijte „Assert.Fail“.
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsUpřednostňovat konstruktory před metodami TestInitialize
@@ -393,6 +286,21 @@
Upřednostňovat metody TestInitialize před konstruktory
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Veřejné metody by měly být testovací metody (označené jako [TestMethod]).
+
+
+
+ Public method '{0}' should be a test method
+ Veřejná metoda {0} by měla být testovací metoda.
+
+
+
+ Public methods should be test methods
+ Veřejné metody by měly být testovací metody
+
+ It's considered a good practice to have only test classes marked public in a test project.Osvědčeným postupem je označit jako veřejné v testovacím projektu jen testovací třídy.
@@ -456,64 +364,29 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Aby byly metody s označením [TestCleanup] platné, musí se řídit následujícím rozložením:
.
-– musí být public,
-– nesmí být static,
-– nesmí být obecné,
-– nesmí být abstract,
-– nesmí přijímat žádný parametr,
-– návratový typ musí být void, Task nebo ValueTask,
-– nesmí být async void,
-– nesmí být speciální metodou (finalizační metoda, operátor...).
-
-
-
- TestCleanup method '{0}' should not take any parameter
- Metoda TestCleanup {0} by neměla přijímat žádný parametr.
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- Metoda TestCleanup {0} by neměla být abstract.
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- Metoda TestCleanup {0} by neměla být async void.
-
-
-
- TestCleanup method '{0}' should not be generic
- Metoda TestCleanup {0} by neměla být obecná.
+– být „public“
+– nesmí být „static“
+– nesmí být obecné nebo definované pro obecnou třídu
+– nesmí být „abstract“
+– nesmí přijímat žádné parametry
+– návratový typ musí být „void“, „Task“ nebo „ValueTask“
+– nesmí být „async void“
+– nesmí se jednat o speciální metodu (finalizační metoda, operátor...).
-
- TestCleanup method '{0}' should not be 'static'
- Metoda TestCleanup {0} by neměla být static.
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- Metoda TestCleanup {0} by měla být metoda ordinary.
-
-
-
- TestCleanup method '{0}' should be 'public'
- Metoda TestCleanup {0} by měla být public.
-
-
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda TestCleanup {0} by měla vracet hodnoty void, Task nebo ValueTask.
+
+ TestCleanup method '{0}' signature is invalid
+ Signatura „{0}“ metody TestCleanup je neplatná
@@ -566,64 +439,29 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Aby byly metody s označením [TestInitialize] platné, musí se řídit následujícím rozložením:
.
-– musí být public,
-– nesmí být static,
-– nesmí být obecné,
-– nesmí být abstract,
-– nesmí přijímat žádný parametr,
-– návratový typ musí být void, Task nebo ValueTask,
-– nesmí být async void,
-– nesmí být speciální metodou (finalizační metoda, operátor...).
-
-
-
- TestInitialize method '{0}' should not take any parameter
- Metoda TestInitialize {0} by neměla přijímat žádný parametr.
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- Metoda TestInitialize {0} by neměla být abstract.
+– být „public“
+– nesmí být „static“
+– nesmí být obecné ani definované pro obecnou třídu
+– nesmí být „abstract“
+– nesmí přijímat žádné parametry
+– návratový typ musí být „void“, „Task“ nebo „ValueTask“
+– nesmí být „async void“
+– nesmí se jednat o speciální metodu (finalizační metoda, operátor...).
-
- TestInitialize method '{0}' should not be 'async void'
- Metoda TestInitialize {0} by neměla být async void.
-
-
-
- TestInitialize method '{0}' should not be generic
- Metoda TestInitialize {0} by neměla být obecná.
-
-
-
- TestInitialize method '{0}' should not be 'static'
- Metoda TestInitialize {0} by neměla být static.
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- Metoda TestInitialize {0} by měla být metoda ordinary.
-
-
-
- TestInitialize method '{0}' should be 'public'
- Metoda TestInitialize {0} by neměla být public.
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda TestInitialize {0} by měla vracet hodnoty void, Task nebo ValueTask.
+
+ TestInitialize method '{0}' signature is invalid
+ Signatura „{0}“ metody TestInitialize je neplatná
@@ -710,6 +548,31 @@
Testovací metoda by se neměla ignorovat.
+
+ Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored.
+ Type contaning '[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]'
+ Class '{0}' contains test methods and should be marked with '[TestClass]'
+
+
+
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ Asynchronní metody testovacích přípravků nevyžadují příponu Async.
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ Asynchronní testovací metody nevyžadují příponu Async.
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] lze nastavit pouze u metod označených pomocí metody [TestMethod].
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf
index caab1e4786..d8d8b2cbb3 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Methoden, die mit [AssemblyCleanup] gekennzeichnet sind, müssen dem folgenden Layout folgen, um gültig zu sein:
-– Muss „public“ sein
-– Muss „static“ sein
-– Darf nicht „generic“ sein
-– Darf keinen Parameter annehmen
-– Der Rückgabetyp muss „void“, „Task“ oder „ValueTask“ sein.
-– Darf nicht „async void“ sein
-– Darf keine spezielle Methode sein (Finalizer, Operator...)
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- Die AssemblyCleanup-Methode „{0}“ darf keinen Parameter annehmen.
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- Die AssemblyCleanup-Methode „{0}“ kann nicht in einer generischen Klasse deklariert werden.
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die AssemblyCleanup-Methode „{0}“ muss „void“, „Task“ oder „ValueTask“ zurückgeben.
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- Die AssemblyCleanup-Methode „{0}“ darf nicht generisch sein.
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- Die AssemblyCleanup-Methode „{0}“ muss eine „ordinary“ Methode sein.
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- Die AssemblyCleanup-Methode „{0}“ muss „public“ sein.
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die AssemblyCleanup-Methode „{0}“ muss „void“, „Task“ oder „ValueTask“ zurückgeben.
+– "öffentlich" sein
+– "statisch" sein
+– nicht generisch oder für eine generische Klasse definiert sein
+– keinen Parameter annehmen
+– der Rückgabetyp muss "void", "Task" oder "ValueTask" sein
+– nicht "async void" sein
+– keine spezielle Methode sein (Finalizer, Operator...)
-
- AssemblyCleanup method '{0}' should be 'static'
- Die AssemblyCleanup-Methode „{0}“ muss „static“ sein.
+
+ AssemblyCleanup method '{0}' signature is invalid
+ Signatur der AssemblyCleanup-Methode "{0}" ist ungültig
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Methoden, die mit [AssemblyInitialize] gekennzeichnet sind, müssen dem folgenden Layout folgen, um gültig zu sein:
-– Muss „public“ sein
-– Muss „static“ sein
-– Darf nicht „generic“ sein
-– Muss einen Parameter vom Typ „TestContext“ annehmen
-– Der Rückgabetyp muss „void“, „Task“ oder „ValueTask“ sein.
-– Darf nicht „async void“ sein
-– Darf keine spezielle Methode sein (Finalizer, Operator...)
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- Die AssemblyInitialize-Methode „{0}“ kann nicht in einer generischen Klasse deklariert werden.
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die AssemblyInitialize-Methode „{0}“ muss „void“, „Task“ oder „ValueTask“ zurückgeben.
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- Die AssemblyInitialize-Methode „{0}“ darf nicht „generic“ sein.
-
-
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- Die AssemblyInitialize-Methode „{0}“ muss eine „ordinary“-Methode sein.
-
-
-
- AssemblyInitialize method '{0}' should be 'public'
- Die AssemblyInitialize-Methode „{0}“ muss „public“ sein.
+– "öffentlich" sein
+– "statisch" sein
+– nicht generisch oder für eine generische Klasse definiert sein
+– einen einfachen Parameter vom Typ „TestContext“ annehmen
+– der Rückgabetyp muss "void", "Task" oder "ValueTask" sein
+– nicht "async void" sein
+– keine spezielle Methode sein (Finalizer, Operator...)
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die AssemblyInitialize-Methode „{0}“ muss „void“, „Task“ oder „ValueTask“ zurückgeben.
+
+ AssemblyInitialize method '{0}' signature is invalid
+ Signatur der AssemblyInitialize-Methode "{0}" ist ungültig
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- Die AssemblyInitialize-Methode „{0}“ muss einen einzelnen Parameter vom Typ „TestContext“ annehmen.
+
+ AssemblyInitialize methods should have valid layout
+ AssemblyInitialize-Methoden müssen über ein gültiges Layout verfügen.
-
- AssemblyInitialize method '{0}' should be 'static'
- Die AssemblyInitialize-Methode „{0}“ muss „static“ sein.
+
+ Prefer adding an additional assertion that checks for null
+ Lieber eine zusätzliche Assertion hinzufügen, die auf NULL überprüft
-
- AssemblyInitialize methods should have valid layout
- AssemblyInitialize-Methoden müssen über ein gültiges Layout verfügen.
+
+ Avoid conditional access in assertions
+ Bedingten Zugriff in Assertionen vermeiden
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Methoden, die mit [ClassCleanup] gekennzeichnet sind, müssen dem folgenden Layout folgen, um gültig zu sein:
-– Muss „public“ sein
-– Darf nicht „static“ sein
-– Darf nicht „generic“ sein
-– Darf keinen Parameter annehmen
-– Der Rückgabetyp muss „void“, „Task“ oder „ValueTask“ sein.
-– Darf nicht „async void“ sein
-– Darf keine spezielle Methode sein (Finalizer, Operator...)
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- Die ClassCleanup-Methode „{0}“ darf keinen Parameter annehmen.
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Die ClassCleanup-Methode „{0}“ kann sich nicht in einer generischen Klasse deklariert werden, ohne dass der InheritanceBehavior-Modus festgelegt ist.
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die ClassCleanup-Methode „{0}“ muss „void“, „Task“ oder „ValueTask“ zurückgeben.
-
-
-
- ClassCleanup method '{0}' should not be generic
- Die ClassCleanup-Methode „{0}“ darf nicht generisch sein.
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- Die ClassCleanup-Methode „{0}“ muss eine „ordinary“ Methode sein.
-
-
-
- ClassCleanup method '{0}' should be 'public'
- Die ClassCleanup-Methode „{0}“ muss „public“ sein.
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die ClassCleanup-Methode „{0}“ muss „void“, „Task“ oder „ValueTask“ zurückgeben.
+– "öffentlich" sein
+– nicht "statisch" sein
+– nicht generisch oder für eine generische Klasse definiert sein
+– keinen Parameter annehmen
+– der Rückgabetyp muss "void", "Task" oder "ValueTask" sein
+– nicht "async void" sein
+– keine spezielle Methode sein (Finalizer, Operator...)
-
- ClassCleanup method '{0}' should be 'static'
- Die ClassCleanup-Methode „{0}“ muss „static“ sein.
+
+ ClassCleanup method '{0}' signature is invalid
+ Signatur der ClassCleanup-Methode "{0}" ist ungültig
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Methoden, die mit [ClassInitialize] gekennzeichnet sind, müssen dem folgenden Layout folgen, um gültig zu sein:
-– Muss „public“ sein
-– Muss „static“ sein
-– Darf nicht „generic“ sein
-– Muss einen Parameter vom Typ „TestContext“ annehmen
-– Der Rückgabetyp muss „void“, „Task“ oder „ValueTask“ sein.
-– Darf nicht „async void“ sein
-– Darf keine spezielle Methode sein (Finalizer, Operator...)
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Die ClassInitialize-Methode „{0}“ kann sich nicht in einer generischen Klasse deklariert werden, ohne dass der InheritanceBehavior-Modus festgelegt ist.
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die ClassInitialize-Methode „{0}“ muss „void“, „Task“ oder „ValueTask“ zurückgeben.
-
-
-
- ClassInitialize method '{0}' should not be generic
- Die ClassInitialize-Methode „{0}“ darf nicht „generic“ sein.
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- Die ClassInitialize-Methode „{0}“ muss eine „ordinary“-Methode sein.
-
-
-
- ClassInitialize method '{0}' should be 'public'
- Die ClassInitialize-Methode „{0}“ muss „public“ sein.
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die ClassInitialize-Methode „{0}“ muss „void“, „Task“ oder „ValueTask“ zurückgeben.
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- Die ClassInitialize-Methode „{0}“ muss einen einzelnen Parameter vom Typ „TestContext“ annehmen.
+– "öffentlich" sein
+– "statisch" sein
+– nicht generisch oder für eine generische Klasse definiert sein
+– einen einfachen Parameter vom Typ „TestContext“ annehmen
+– der Rückgabetyp muss "void", "Task" oder "ValueTask" sein
+– nicht "async void" sein
+– keine spezielle Methode sein (Finalizer, Operator...)
-
- ClassInitialize method '{0}' should be 'static'
- Die ClassInitialize-Methode „{0}“ muss „static“ sein.
+
+ ClassInitialize method '{0}' signature is invalid
+ Signatur der ClassInitialize-Methode "{0}" ist ungültig
@@ -339,6 +209,21 @@
TestContext nicht in einem statischen Member speichern
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assertVerwenden Sie „Assert.Fail“ anstelle einer Assert-Anweisung „Assert.{0}“, bei der immer ein Fehler auftritt.
@@ -349,6 +234,16 @@
Verwenden Sie „Assert.Fail“ anstelle einer Assert-Anweisung, bei der immer ein Fehler auftritt.
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsKonstruktoren gegenüber TestInitialize-Methoden bevorzugen
@@ -389,6 +284,21 @@
TestInitialize-Methoden gegenüber Konstruktoren bevorzugen
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.Es wird als bewährte Methode angesehen, nur Testklassen in einem Testprojekt als öffentlich gekennzeichnet zu lassen.
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Methoden, die mit [TestCleanup] gekennzeichnet sind, sollten dem folgenden Layout folgen, um gültig zu sein:
-– es sollte "public" sein
-– es darf nicht "static" sein
-– es darf nicht "generic" sein
-– es darf nicht "abstract" sein
-– es sollte keinen Parameter verwenden
+– "öffentlich" sein
+– nicht "statisch" sein
+– nicht generisch oder für eine generische Klasse definiert sein
+– nicht "abstrakt" sein
+– keinen Parameter annehmen
– der Rückgabetyp muss "void", "Task" oder "ValueTask" sein
-– es darf nicht "async void" sein
-– es darf keine spezielle Methode (Finalizer, Operator...) sein.
-
-
-
- TestCleanup method '{0}' should not take any parameter
- Die TestCleanup-Methode "{0}" darf keinen Parameter annehmen.
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- Die TestCleanup-Methode "{0}" darf nicht "abstract" sein.
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- Die TestCleanup-Methode "{0}" darf nicht "sync void" sein.
-
-
-
- TestCleanup method '{0}' should not be generic
- Die TestCleanup-Methode "{0}" darf nicht generisch sein.
-
-
-
- TestCleanup method '{0}' should not be 'static'
- Die TestCleanup-Methode "{0}" darf nicht "static" sein.
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- Die TestCleanup-Methode "{0}" darf eine "ordinary" Methode sein.
-
-
-
- TestCleanup method '{0}' should be 'public'
- Die TestCleanup-Methode "{0}" muss "public" sein.
+– nicht "async void" sein
+– keine spezielle Methode sein (Finalizer, Operator...)
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die TestCleanup-Methode "{0}" sollte "void", "Task" oder "ValueTask" zurückgeben.
+
+ TestCleanup method '{0}' signature is invalid
+ Signatur der TestCleanup-Methode "{0}" ist ungültig
@@ -561,63 +436,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Methoden, die mit [TestInitialize] gekennzeichnet sind, sollten dem folgenden Layout folgen, um gültig zu sein:
-– es sollte "public" sein
-– es darf nicht "static" sein
-– es darf nicht "generic" sein
-– es darf nicht "abstract" sein
-– es sollte keinen Parameter verwenden
+– "öffentlich" sein
+– nicht "statisch" sein
+– nicht generisch oder für eine generische Klasse definiert sein
+– nicht "abstrakt" sein
+– keinen Parameter annehmen
– der Rückgabetyp muss "void", "Task" oder "ValueTask" sein
-– es darf nicht "async void" sein
-– es darf keine spezielle Methode (Finalizer, Operator...) sein.
+– nicht "async void" sein
+– keine spezielle Methode sein (Finalizer, Operator...)
-
- TestInitialize method '{0}' should not take any parameter
- Die TestInitialize-Methode "{0}" darf keinen Parameter annehmen.
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- Die TestInitialize-Methode "{0}" darf nicht "abstract" sein.
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- Die TestInitialize-Methode "{0}" darf nicht "async void" sein.
-
-
-
- TestInitialize method '{0}' should not be generic
- Die TestInitialize-Methode "{0}" darf nicht "generic" sein.
-
-
-
- TestInitialize method '{0}' should not be 'static'
- Die TestInitialize-Methode "{0}" darf nicht "static" sein.
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- Die TestInitialize-Methode "{0}" darf eine "ordinary" Methode sein.
-
-
-
- TestInitialize method '{0}' should be 'public'
- Die TestInitialize-Methode "{0}" sollte "public" sein.
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Die TestInitialize-Methode "{0}" sollte "void", "Task" oder "ValueTask" zurückgeben.
+
+ TestInitialize method '{0}' signature is invalid
+ Signatur der TestInitialize-Methode "{0}" ist ungültig
@@ -704,6 +544,31 @@
Die Testmethode darf nicht ignoriert werden.
+
+ Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored.
+ Type contaning '[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]'
+ Class '{0}' contains test methods and should be marked with '[TestClass]'
+
+
+
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ Für asynchrone Testfixture-Methoden ist das Suffix "Async" nicht erforderlich.
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ Für asynchrone Testmethoden ist das Suffix "Async" nicht erforderlich.
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] kann nur für Methoden festgelegt werden, die mit [TestMethod] markiert sind.
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf
index 6548d1cb5b..53663d480b 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Los métodos marcados con [AssemblyCleanup] deben seguir el siguiente diseño para ser válidos:
-- debería ser 'público'
-- debería estar 'estático'
-- no debería ser genérico
-- no debería tomar ningún parámetro
-- el tipo de valor devuelto debería ser 'void', 'Task' o 'ValueTask'
-- no debería ser 'async void'
-- no debería ser un método especial (finalizador, operador...).
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- El método AssemblyCleanup '{0}' no debería tomar ningún parámetro
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- El método AssemblyCleanup "{0}" no puede ser declarado en una clase genérica
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método AssemblyCleanup '{0}' debería devolver 'void', 'Task' o 'ValueTask'
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- El método AssemblyCleanup '{0}' no debería ser genérico
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- El método AssemblyCleanup '{0}' debería ser un método 'normal'
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- El método AssemblyCleanup '{0}' debería ser 'público'
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método AssemblyCleanup '{0}' debería devolver 'void', 'Task' o 'ValueTask'
+- ser "public"
+- ser "static"
+- no ser genérico ni estar definido en una clase genérica
+- no tomar ningún parámetro
+- el tipo de valor devuelto debería ser "void", "Task" o "ValueTask"
+- no ser "async void"
+- no ser un método especial (finalizador, operador...).
-
- AssemblyCleanup method '{0}' should be 'static'
- El método AssemblyCleanup '{0}' debería ser 'estático'
+
+ AssemblyCleanup method '{0}' signature is invalid
+ La signatura "{0}" del método AssemblyCleanup no es válida
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Los métodos marcados con [AssemblyInitialize] deberían seguir el siguiente diseño para ser válidos:
-- debería ser 'público'
-- debería estar 'estático'
-- no debería ser genérico
-- debería tomar un parámetro de tipo 'TestContext'
-- el tipo de valor devuelto debería ser 'void', 'Task' o 'ValueTask'
-- no debería ser 'async void'
-- no debería ser un método especial (finalizador, operador...).
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- El método AssemblyInitialize "{0}" no puede declararse en una clase genérica
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método AssemblyInitialize '{0}' debería devolver 'void', 'Task' o 'ValueTask'
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- El método AssemblyInitialize '{0}' no debería ser genérico
+- ser "public"
+- ser "static"
+- no ser genérico ni estar definido en una clase genérica
+- tome un único parámetro de tipo "TestContext".
+- el tipo de valor devuelto debería ser "void", "Task" o "ValueTask"
+- no ser "async void"
+- no ser un método especial (finalizador, operador...).
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- El método AssemblyInitialize '{0}' debería ser un método 'ordinario'
+
+ AssemblyInitialize method '{0}' signature is invalid
+ La signatura "{0}" del método AssemblyInitialize no es válida
-
- AssemblyInitialize method '{0}' should be 'public'
- El método AssemblyInitialize '{0}' debería ser 'público'
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método AssemblyInitialize '{0}' debería devolver 'void', 'Task' o 'ValueTask'
+
+ AssemblyInitialize methods should have valid layout
+ Los métodos AssemblyInitialize deben tener un diseño válido
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- El método AssemblyInitialize '{0}' debería tomar un único parámetro de tipo 'TestContext'
+
+ Prefer adding an additional assertion that checks for null
+ Preferir agregar una aserción adicional que compruebe si hay valores NULL
-
- AssemblyInitialize method '{0}' should be 'static'
- El método AssemblyInitialize '{0}' debería ser 'estático'
-
-
-
- AssemblyInitialize methods should have valid layout
- Los métodos AssemblyInitialize deben tener un diseño válido
+
+ Avoid conditional access in assertions
+ Evitar el acceso condicional en las aserciones
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Los métodos marcados con [ClassCleanup] deben seguir el siguiente diseño para ser válidos:
-- debería ser 'público'
-- no debería ser 'estático'
-- no debería ser genérico
-- no debería tomar ningún parámetro
-- el tipo de valor devuelto debería ser 'void', 'Task' o 'ValueTask'
-- no debería ser 'async void'
-- no debería ser un método especial (finalizador, operador...).
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- El método ClassCleanup '{0}' no debería tomar ningún parámetro
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- El método ClassCleanup "{0}" no puede ser declarado en una clase genérica sin que el modo "InheritanceBehavior" esté configurado.
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método ClassCleanup '{0}' debería devolver 'void', 'Task' o 'ValueTask'
-
-
-
- ClassCleanup method '{0}' should not be generic
- El método ClassCleanup '{0}' no debería ser genérico
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- El método ClassCleanup '{0}' debería ser un método 'normal'
-
-
-
- ClassCleanup method '{0}' should be 'public'
- El método ClassCleanup '{0}' debería ser 'público'
+- ser "public"
+- no ser "static"
+- no ser genérico ni estar definido en una clase genérica
+- no tomar ningún parámetro
+- el tipo de valor devuelto debería ser "void", "Task" o "ValueTask"
+- no ser "async void"
+- no ser un método especial (finalizador, operador...).
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método ClassCleanup '{0}' debería devolver 'void', 'Task' o 'ValueTask'
-
-
-
- ClassCleanup method '{0}' should be 'static'
- El método ClassCleanup '{0}' debería ser 'estático'
+
+ ClassCleanup method '{0}' signature is invalid
+ La signatura "{0}" del método ClassCleanup no es válida
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Los métodos marcados con [ClassInitialize] deberían seguir el siguiente diseño para ser válidos:
-- debería ser 'público'
-- debería estar 'estático'
-- no debería ser genérico
-- debería tomar un parámetro de tipo 'TestContext'
-- el tipo de valor devuelto debería ser 'void', 'Task' o 'ValueTask'
-- no debería ser 'async void'
-- no debería ser un método especial (finalizador, operador...).
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- El método ClassInitialize "{0}" no puede ser declarado en una clase genérica sin que el modo "InheritanceBehavior" esté configurado.
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método ClassInitialize '{0}' debería devolver 'void', 'Task' o 'ValueTask'
-
-
-
- ClassInitialize method '{0}' should not be generic
- El método ClassInitialize '{0}' no debería ser genérico
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- El método ClassInitialize '{0}' debería ser un método 'ordinario'
-
-
-
- ClassInitialize method '{0}' should be 'public'
- El método ClassInitialize '{0}' debería ser 'público'
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método ClassInitialize '{0}' debería devolver 'void', 'Task' o 'ValueTask'
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- El método ClassInitialize '{0}' debe tomar un único parámetro de tipo 'TestContext'
+- ser "public"
+- ser "static"
+- no ser genérico ni estar definido en una clase genérica
+- tome un único parámetro de tipo "TestContext".
+- el tipo de valor devuelto debería ser "void", "Task" o "ValueTask"
+- no ser "async void"
+- no ser un método especial (finalizador, operador...).
-
- ClassInitialize method '{0}' should be 'static'
- El método ClassInitialize '{0}' debería ser 'estático'
+
+ ClassInitialize method '{0}' signature is invalid
+ La signatura "{0}" del método ClassInitialize no es válida
@@ -339,6 +209,21 @@
No almacenar TestContext en un miembro estático
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assertUsar "Assert.Fail" en lugar de una aserción 'Assert.{0}' que siempre tiene errores
@@ -349,6 +234,16 @@
Usar "Assert.Fail" en lugar de una aserción que siempre tiene errores
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsPreferir constructores en lugar de métodos TestInitialize
@@ -389,6 +284,21 @@
Preferir métodos TestInitialize en lugar de constructores
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.Se considera una buena práctica tener solo clases de prueba marcadas como públicas en un proyecto de prueba.
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Los métodos marcados con [TestCleanup] deberían seguir el siguiente diseño para ser válidos:
-- debería ser 'public'
-- no debería ser 'static'
-- no debería ser genérico
-- no debería ser 'abstract'
-- no debería tomar ningún parámetro
-- el tipo de valor devuelto debería ser 'void', 'Task' o 'ValueTask'
-- no debería ser 'async void'
-- no debería ser un método especial (finalizador, operador...).
-
-
-
- TestCleanup method '{0}' should not take any parameter
- El método TestCleanup "{0}" no debería tomar ningún parámetro
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- El método TestCleanup "{0}" no debe ser "abstract"
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- El método TestCleanup "{0}" no debe ser "async void"
-
-
-
- TestCleanup method '{0}' should not be generic
- El método TestCleanup "{0}" no debe ser genérico
-
-
-
- TestCleanup method '{0}' should not be 'static'
- El método TestCleanup "{0}" no debe ser "static"
+- ser "public"
+- no ser "static"
+- no ser genérico ni estar definido en una clase genérica
+- no ser "abstract"
+- no tomar ningún parámetro
+- el tipo de valor devuelto debería ser "void", "Task" o "ValueTask"
+- no ser "async void"
+- no ser un método especial (finalizador, operador...).
-
- TestCleanup method '{0}' should be an 'ordinary' method
- El método TestCleanup "{0}" debe ser un método "normal"
-
-
-
- TestCleanup method '{0}' should be 'public'
- El método TestCleanup "{0}" debe ser "public"
-
-
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método TestCleanup "{0}" debe devolver "void", "Task" o "ValueTask"
+
+ TestCleanup method '{0}' signature is invalid
+ La signatura "{0}" del método TestCleanup no es válida
@@ -561,63 +436,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Los métodos marcados con [TestInitialize] deberían seguir el siguiente diseño para ser válidos:
-- debería ser 'public'
-- no debería ser 'static'
-- no debería ser genérico
-- no debería ser 'abstract'
-- no debería tomar ningún parámetro
-- el tipo de valor devuelto debería ser 'void', 'Task' o 'ValueTask'
-- no debería ser 'async void'
-- no debería ser un método especial (finalizador, operador...).
-
-
-
- TestInitialize method '{0}' should not take any parameter
- El método TestInitialize "{0}" no debería tomar ningún parámetro
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- El método TestInitialize "{0}" no debe ser "abstract"
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- El método TestInitialize "{0}" no debe ser "async void"
-
-
-
- TestInitialize method '{0}' should not be generic
- El método TestInitialize "{0}" no debe ser genérico
+- ser "public"
+- no ser "static"
+- no ser genérico ni estar definido en una clase genérica
+- no ser "abstract"
+- no tomar ningún parámetro
+- el tipo de valor devuelto debería ser "void", "Task" o "ValueTask"
+- no ser "async void"
+- no ser un método especial (finalizador, operador...).
-
- TestInitialize method '{0}' should not be 'static'
- El método TestInitialize "{0}" no debe ser "static"
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- El método TestInitialize "{0}" debe ser un método "normal"
-
-
-
- TestInitialize method '{0}' should be 'public'
- El método TestInitialize "{0}" debe ser "public"
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- El método TestInitialize "{0}" debe devolver "void", "Task" o "ValueTask"
+
+ TestInitialize method '{0}' signature is invalid
+ La signatura "{0}" del método TestInitialize no es válida
@@ -704,6 +544,31 @@
El método de prueba no debería ignorarse
+
+ Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored.
+ Type contaning '[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]'
+ Class '{0}' contains test methods and should be marked with '[TestClass]'
+
+
+
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ Los métodos asincrónicos de accesorio de prueba no requieren el sufijo "Async".
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ Los métodos de prueba asincrónicos no requieren el sufijo "Async".
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] solo se puede establecer en métodos marcados con [TestMethod]
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf
index 95152f3832..59b6845b30 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Les méthodes marquées par [AssemblyCleanup] doivent respecter le schéma suivant pour être valides :
-– Elle doit être « public »
-– Elle doit être « static »
-– Elle ne doit pas être générique
-– Elle ne doit accepter aucun paramètre
-– Elle doit renvoyer « void », « Task » ou « ValueTask »
-– Elle ne doit pas être « async void »
-– Il ne doit pas s’agir d’une méthode spéciale (finaliseur, opérateur...).
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- La méthode AssemblyCleanup « {0} » ne doit accepter aucun paramètre
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- La méthode AssemblyCleanup « {0} » ne peut pas être déclarée sur une classe générique
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode AssemblyCleanup « {0} » doit retourner « void », « Task » ou « ValueTask »
+- être « public »
+- être "statique"
+- ne pas être générique ni défini sur une classe générique
+- ne pas prendre de paramètre
+- le type de retour doit être « void », « Task » ou « ValueTask »
+- ne pas être "vide asynchrone"
+- ne pas être une méthode particulière (finaliseur, opérateur...).
-
- AssemblyCleanup method '{0}' should not be generic
- La méthode AssemblyCleanup « {0} » ne doit pas être générique
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- La méthode AssemblyCleanup« {0} » doit être une méthode « ordinary »
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- La méthode AssemblyCleanup « {0} » doit être « public »
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode AssemblyCleanup « {0} » doit retourner « void », « Task » ou « ValueTask »
-
-
-
- AssemblyCleanup method '{0}' should be 'static'
- La méthode AssemblyCleanup « {0} » doit être « static »
+
+ AssemblyCleanup method '{0}' signature is invalid
+ La signature de la méthode AssemblyCleanup '{0}' n’est pas valide
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Les méthodes marquées par [AssemblyInitialize] doivent respecter le schéma suivant pour être valides :
-– Elle doit être « public »
-– Elle doit être « static »
-– Elle ne doit pas être générique
-– Elle doit prendre un paramètre de type « TestContext »
-– Elle doit renvoyer « void », « Task » ou « ValueTask »
-– Elle ne doit pas être « async void »
-– Il ne doit pas s’agir d’une méthode spéciale (finaliseur, opérateur...).
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- La méthode AssemblyInitialize « {0} » ne peut pas être déclarée sur une classe générique
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode AssemblyInitialize « {0} » doit retourner « void », « Task » ou « Value Task »
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- La méthode AssemblyInitialize « {0} » ne doit pas être générique
-
-
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- La méthode AssemblyInitialize « {0} » doit être une méthode « ordinary »
-
-
-
- AssemblyInitialize method '{0}' should be 'public'
- La méthode AssemblyInitialize « {0} » doit être « public »
+- être « public »
+- être "statique"
+- ne pas être générique ni être défini sur une classe générique
+- prendre un paramètre unique de type 'TestContext'
+- le type de retour doit être « void », « Task » ou « ValueTask »
+- ne pas être "vide asynchrone"
+- ne pas être une méthode particulière (finaliseur, opérateur...).
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode AssemblyInitialize « {0} » doit retourner « void », « Task » ou « Value Task »
+
+ AssemblyInitialize method '{0}' signature is invalid
+ La signature de la méthode AssemblyInitialize '{0}' n’est pas valide
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- La méthode AssemblyInitialize « {0} » doit prendre un seul paramètre de type « TestContext »
+
+ AssemblyInitialize methods should have valid layout
+ La méthode AssemblyInitialize doit avoir une disposition valide
-
- AssemblyInitialize method '{0}' should be 'static'
- La méthode AssemblyInitialize « {0} » doit être « static »
+
+ Prefer adding an additional assertion that checks for null
+ Préférer l’ajout d’une assertion supplémentaire qui recherche la valeur null
-
- AssemblyInitialize methods should have valid layout
- La méthode AssemblyInitialize doit avoir une disposition valide
+
+ Avoid conditional access in assertions
+ Éviter l’accès conditionnel dans les assertions
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Les méthodes marquées par [ClassCleanup] doivent respecter le schéma suivant pour être valides :
-– Elle doit être « public »
-– Elle ne doit pas être « static »
-– Elle ne doit pas être générique
-– Elle ne doit accepter aucun paramètre
-– Elle doit renvoyer « void », « Task » ou « ValueTask »
-– Elle ne doit pas être « async void »
-– Il ne doit pas s’agir d’une méthode spéciale (finaliseur, opérateur...).
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- La méthode ClassCleanup « {0} » ne doit accepter aucun paramètre
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- La méthode ClassCleanup « {0} » ne peut pas être déclarée sur une classe générique sans que le mode `InheritanceBehavior` soit défini
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode ClassCleanup « {0} » doit retourner « void », « Task » ou « ValueTask »
+- être « public »
+- ne pas être 'statique'
+- ne pas être générique ni défini sur une classe générique
+- ne pas prendre de paramètre
+- le type de retour doit être « void », « Task » ou « ValueTask »
+- ne pas être "vide asynchrone"
+- ne pas être une méthode particulière (finaliseur, opérateur...).
-
- ClassCleanup method '{0}' should not be generic
- La méthode ClassCleanup « {0} » ne doit pas être générique
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- La méthode ClassCleanup « {0} » doit être une méthode « ordinary »
-
-
-
- ClassCleanup method '{0}' should be 'public'
- La méthode ClassCleanup « {0} » doit être « public »
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode ClassCleanup « {0} » doit retourner « void », « Task » ou « ValueTask »
-
-
-
- ClassCleanup method '{0}' should be 'static'
- La méthode ClassCleanup « {0} » doit être « static »
+
+ ClassCleanup method '{0}' signature is invalid
+ La signature de la méthode ClassCleanup '{0}' n’est pas valide
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Les méthodes marquées par [ClassInitialize] doivent respecter le schéma suivant pour être valides :
-– Elle doit être « public »
-– Elle doit être « static »
-– Elle ne doit pas être générique
-– Elle doit prendre un paramètre de type « TestContext »
-– Elle doit renvoyer « void », « Task » ou « ValueTask »
-– Elle ne doit pas être « async void »
-– Il ne doit pas s’agir d’une méthode spéciale (finaliseur, opérateur...).
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- La méthode ClassInitialize « {0} » ne peut pas être déclarée sur une classe générique sans que le mode `InheritanceBehavior` soit défini
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode ClassInitialize « {0} » doit retourner « void », « Task » ou « ValueTask »
-
-
-
- ClassInitialize method '{0}' should not be generic
- La méthode ClassInitialize « {0} » ne doit pas être générique
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- La méthode ClassInitialize « {0} » doit être une méthode « ordinary »
-
-
-
- ClassInitialize method '{0}' should be 'public'
- La méthode ClassInitialize « {0} » doit être « public »
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode ClassInitialize « {0} » doit retourner « void », « Task » ou « ValueTask »
+- être « public »
+- être "statique"
+- ne pas être générique ni être défini sur une classe générique
+- prendre un paramètre unique de type 'TestContext'
+- le type de retour doit être « void », « Task » ou « ValueTask »
+- ne pas être "vide asynchrone"
+- ne pas être une méthode particulière (finaliseur, opérateur...).
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- La méthode ClassInitialize « {0} » doit prendre un seul paramètre de type « TestContext »
-
-
-
- ClassInitialize method '{0}' should be 'static'
- La méthode ClassInitialize « {0} » doit être « static »
+
+ ClassInitialize method '{0}' signature is invalid
+ La signature de la méthode ClassInitialize '{0}' n’est pas valide
@@ -339,6 +209,21 @@
Ne pas stocker TestContext dans un membre statique
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ « System.ComponentModel.DescriptionAttribute » n’a aucun effet dans le contexte des tests et vous vouliez probablement utiliser « Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute » à la place.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ Vous vouliez utiliser « Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute » ?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ « System.ComponentModel.DescriptionAttribute » n’a aucun effet sur les méthodes de test
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assertUtilisez « Assert.Fail » à la place d’une assertion « Assert.{0} » toujours en échec
@@ -349,6 +234,16 @@
Utilisez « Assert.Fail » à la place d’une assertion toujours en échec
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsPréférer les constructeurs aux méthodes TestInitialize
@@ -389,6 +284,21 @@
Préférer les méthodes TestInitialize aux constructeurs
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.C’est considéré comme une bonne pratique d’avoir uniquement des classes de test marquées comme publiques dans un projet de test.
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Les méthodes marquées par [TestCleanup] doivent respecter le schéma suivant pour être valides :
-– Il doit être « public »
-– il ne devrait pas être « static »
-– il ne doit pas être générique
-– il ne doit pas être « abstract »
-– il ne doit accepter aucun paramètre
-- doit être « void » ou renvoyer « Task » ou « ValueTask »
-– il ne doit pas être « async void »
-- il ne doit pas s’agir d’une méthode spéciale (finaliseur, opérateur...).
-
-
-
- TestCleanup method '{0}' should not take any parameter
- La méthode TestCleanup « {0} » ne doit accepter aucun paramètre
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- La méthode TestCleanup « {0} » ne doit pas être « abstract »
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- La méthode TestCleanup « {0} » ne doit pas être « asynch void »
-
-
-
- TestCleanup method '{0}' should not be generic
- La méthode TestCleanup « {0} » ne doit pas être générique
-
-
-
- TestCleanup method '{0}' should not be 'static'
- La méthode TestCleanup « {0} » ne doit pas être « static »
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- La méthode TestCleanup « {0} » doit être une méthode « ordinary »
+- être « public »
+- ne pas être 'statique'
+- ne pas être générique ou être défini sur une classe générique
+- ne pas être 'abstract'
+- ne pas prendre de paramètre
+- le type de retour doit être « void », « Task » ou « ValueTask »
+- ne pas être "vide asynchrone"
+- ne pas être une méthode particulière (finaliseur, opérateur...).
-
- TestCleanup method '{0}' should be 'public'
- La méthode TestCleanup « {0} » doit être « public »
-
-
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode TestCleanup « {0} » doit retourner « void », « Task » ou « Value Task »
+
+ TestCleanup method '{0}' signature is invalid
+ La signature «{0}» de la méthode TestCleanup n’est pas valide
@@ -561,63 +436,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Les méthodes marquées par [TestInitialize] doivent respecter le schéma suivant pour être valides :
-– Il doit être « public »
-– il ne devrait pas être « static »
-– il ne doit pas être générique
-– il ne doit pas être « abstract »
-– il ne doit accepter aucun paramètre
-- doit être « void » ou renvoyer « Task » ou « ValueTask »
-– il ne doit pas être « async void »
-- il ne doit pas s’agir d’une méthode spéciale (finaliseur, opérateur...).
-
-
-
- TestInitialize method '{0}' should not take any parameter
- La méthode TestInitialize « {0} » ne doit accepter aucun paramètre
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- La méthode TestInitialize « {0} » ne doit pas être « abstract »
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- La méthode TestInitialize « {0} » ne doit pas être « asynch void »
+- être « public »
+- ne pas être 'statique'
+- ne pas être générique ni défini sur une classe générique
+- ne pas être 'abstract'
+- ne pas prendre de paramètre
+- le type de retour doit être « void », « Task » ou « ValueTask »
+- ne pas être "vide asynchrone"
+- ne pas être une méthode particulière (finaliseur, opérateur...).
-
- TestInitialize method '{0}' should not be generic
- La méthode TestInitialize « {0} » ne doit pas être générique
-
-
-
- TestInitialize method '{0}' should not be 'static'
- La méthode TestInitialize « {0} » ne doit pas être « static »
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- La méthode TestInitialize « {0} » doit être une méthode « ordinary »
-
-
-
- TestInitialize method '{0}' should be 'public'
- La méthode TestInitialize « {0} » doit être « public »
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- La méthode TestInitialize « {0} » doit retourner « void », « Task » ou « Value Task »
+
+ TestInitialize method '{0}' signature is invalid
+ La signature de la méthode TestInitialize '{0}' n’est pas valide
@@ -704,6 +544,31 @@
La méthode de test doit être ignorée
+
+ Type contaning '[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 containing '[TestMethod]' should be marked with '[TestClass]'
+ Le type contenant « [TestMethod] » doit être marqué avec « [TestClass] »
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ Les méthodes de fixture de test asynchrones ne nécessitent pas le suffixe « Async »
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ Les méthodes de test asynchrones ne nécessitent pas le suffixe 'Async'
+
+ [{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]
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf
index 654cb4ca02..1bda4e4e12 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
I metodi contrassegnati con [AssemblyCleanup] devono seguire il layout seguente per essere validi:
-- Deve essere 'public'
-- Deve essere 'static'
-- Non deve essere generico
-- Non deve accettare alcun parametro
-- Il tipo restituito deve essere "void", "Task" o "ValueTask"
-- Non deve essere 'async void'
-- Non deve essere un metodo speciale (finalizzatore, operatore...).
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- Il metodo AssemblyCleanup '{0}' non deve accettare alcun parametro
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- Il metodo AssemblyCleanup '{0}' non può essere dichiarato in una classe generica
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo AssemblyCleanup '{0}' deve restituire 'void', 'Task' o 'ValueTask'
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- Il metodo AssemblyCleanup '{0}' non deve essere generico
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- Il metodo AssemblyCleanup '{0}' deve essere un metodo 'ordinary'
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- Il metodo TestCleanup '{0}' deve essere 'public'
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo AssemblyCleanup '{0}' deve restituire 'void', 'Task' o 'ValueTask'
+- devono essere 'public'
+- devono essere 'static'
+- non devono essere generici né definiti in una classe generica
+- non devono accettare alcun parametro
+- il tipo restituito deve essere 'void', 'Task' o 'ValueTask'
+- non devono essere 'async void'
+- non devono essere un metodo speciale (finalizzatore, operatore...).
-
- AssemblyCleanup method '{0}' should be 'static'
- Il metodo AssemblyCleanup '{0}' deve essere 'static'
+
+ AssemblyCleanup method '{0}' signature is invalid
+ La firma del metodo AssemblyCleanup '{0}' non è valida
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
I metodi contrassegnati con [AssemblyInitialize] devono seguire il layout seguente per essere validi:
-- Deve essere 'public'
-- Deve essere 'static'
-- Non deve essere generico
-- deve accettare un parametro di tipo 'TestContext'
-- Il tipo restituito deve essere "void", "Task" o "ValueTask"
-- Non deve essere 'async void'
-- Non deve essere un metodo speciale (finalizzatore, operatore...).
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- Il metodo AssemblyInitialize '{0}' non può essere dichiarato in una classe generica
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo AssemblyInitialize '{0}' deve restituire 'void', 'Task' o 'ValueTask'
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- Il metodo AssemblyInitialize '{0}' non deve essere generico
-
-
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- Il metodo AssemblyInitialize '{0}' deve essere un metodo 'ordinary'
-
-
-
- AssemblyInitialize method '{0}' should be 'public'
- Il metodo AssemblyInitialize '{0}' deve essere 'public'
+- devono essere 'public'
+- devono essere 'static'
+- non devono essere generici né essere definiti in una classe generica
+- devono accettare un singolo parametro di tipo 'TestContext'
+- il tipo restituito deve essere 'void', 'Task' o 'ValueTask'
+- non devono essere 'async void'
+- non devono essere un metodo speciale (finalizzatore, operatore...).
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo AssemblyInitialize '{0}' deve restituire 'void', 'Task' o 'ValueTask'
+
+ AssemblyInitialize method '{0}' signature is invalid
+ La firma del metodo AssemblyInitialize '{0}' non è valida
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- Il metodo AssemblyInitialize '{0}' deve accettare un singolo parametro di tipo 'TestContext'
+
+ AssemblyInitialize methods should have valid layout
+ Il metodo AssemblyInitialize deve avere un layout valido
-
- AssemblyInitialize method '{0}' should be 'static'
- Il metodo AssemblyInitialize '{0}' deve essere 'static'
+
+ Prefer adding an additional assertion that checks for null
+ Preferire l'aggiunta di un'ulteriore asserzione che controlli la presenza di valori null
-
- AssemblyInitialize methods should have valid layout
- Il metodo AssemblyInitialize deve avere un layout valido
+
+ Avoid conditional access in assertions
+ Evitare l'accesso condizionale nelle asserzioni
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
I metodi contrassegnati con [ClassCleanup] devono seguire il layout seguente per essere validi:
-- Deve essere 'public'
-- Non deve essere 'static'
-- Non deve essere generico
-- Non deve accettare alcun parametro
-- Il tipo restituito deve essere "void", "Task" o "ValueTask"
-- Non deve essere 'async void'
-- Non deve essere un metodo speciale (finalizzatore, operatore...).
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- Il metodo ClassCleanup '{0}' non deve accettare alcun parametro
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Il metodo ClassCleanup '{0}' non può essere dichiarato in una classe generica senza la modalità 'InheritanceBehavior' impostata
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo ClassCleanup '{0}' deve restituire 'void', 'Task' o 'ValueTask'
-
-
-
- ClassCleanup method '{0}' should not be generic
- Il metodo ClassCleanup '{0}' non deve essere generico
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- Il metodo ClassCleanup '{0}' deve essere un metodo 'ordinary'
-
-
-
- ClassCleanup method '{0}' should be 'public'
- Il metodo ClassCleanup '{0}' deve essere 'public'
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo ClassCleanup '{0}' deve restituire 'void', 'Task' o 'ValueTask'
+- devono essere 'public'
+- non devono essere 'static'
+- non devono essere generici né definiti in una classe generica
+- non devono accettare alcun parametro
+- il tipo restituito deve essere 'void', 'Task' o 'ValueTask'
+- non devono essere 'async void'
+- non devono essere un metodo speciale (finalizzatore, operatore...).
-
- ClassCleanup method '{0}' should be 'static'
- Il metodo ClassCleanup '{0}' deve essere 'static'
+
+ ClassCleanup method '{0}' signature is invalid
+ La firma del metodo ClassCleanup '{0}' non è valida
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
I metodi contrassegnati con [ClassInitialize] devono seguire il layout seguente per essere validi:
-- Deve essere 'public'
-- Deve essere 'static'
-- Non deve essere generico
-- deve accettare un parametro di tipo 'TestContext'
-- Il tipo restituito deve essere "void", "Task" o "ValueTask"
-- Non deve essere 'async void'
-- Non deve essere un metodo speciale (finalizzatore, operatore...).
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Il metodo ClassInitialize '{0}' non può essere dichiarato in una classe generica senza la modalità 'InheritanceBehavior' impostata
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo ClassInitialize '{0}' deve restituire 'void', 'Task' o 'ValueTask'
-
-
-
- ClassInitialize method '{0}' should not be generic
- Il metodo ClassInitialize '{0}' non deve essere generico
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- Il metodo ClassInitialize '{0}' deve essere un metodo 'ordinary'
-
-
-
- ClassInitialize method '{0}' should be 'public'
- Il metodo ClassInitialize '{0}' deve essere 'public'
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo ClassInitialize '{0}' deve restituire 'void', 'Task' o 'ValueTask'
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- Il metodo ClassInitialize '{0}' deve accettare un singolo parametro di tipo 'TestContext'
+- devono essere 'public'
+- devono essere 'static'
+- non devono essere generici né essere definiti in una classe generica
+- devono accettare un singolo parametro di tipo 'TestContext'
+- il tipo restituito deve essere 'void', 'Task' o 'ValueTask'
+- non devono essere 'async void'
+- non devono essere un metodo speciale (finalizzatore, operatore...).
-
- ClassInitialize method '{0}' should be 'static'
- Il metodo ClassInitialize '{0}' deve essere 'static'
+
+ ClassInitialize method '{0}' signature is invalid
+ La firma del metodo ClassInitialize '{0}' non è valida
@@ -339,6 +209,21 @@
Non archiviare TestContext in un membro statico
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute' non ha alcun effetto in un contesto di test ed è probabile che si intendesse usare 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ Si intendeva usare 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute' non ha alcun effetto sui metodi di test.
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assertUsare 'Assert.Fail' invece di un'asserzione 'Assert.{0}' che ha sempre esito negativo.
@@ -349,6 +234,16 @@
Usare 'Assert.Fail' invece di un'asserzione che ha sempre esito negativo
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsPreferisci costruttori rispetto ai metodi TestInitialize
@@ -389,6 +284,21 @@
Preferisci i metodi TestInitialize rispetto ai costruttori
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.È consigliabile che solo le classi di test siano contrassegnate come pubbliche in un progetto di test.
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
I metodi contrassegnati con [TestCleanup] devono seguire il layout seguente per essere validi:
-- Deve essere 'public'
-- Non deve essere 'static'
-- Non deve essere generico
-- Non deve essere 'abstract'
-- Non deve accettare alcun parametro
-- Il tipo restituito deve essere "void", "Task" o "ValueTask"
-- Non deve essere 'async void'
-- Non deve essere un metodo speciale (finalizzatore, operatore...).
-
-
-
- TestCleanup method '{0}' should not take any parameter
- Il metodo TestCleanup '{0}' non deve accettare alcun parametro
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- Il metodo TestCleanup '{0}' non deve essere 'abstract'
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- Il metodo TestCleanup '{0}' non deve essere 'async void'
-
-
-
- TestCleanup method '{0}' should not be generic
- Il metodo TestCleanup '{0}' non deve essere generico
-
-
-
- TestCleanup method '{0}' should not be 'static'
- Il metodo TestCleanup '{0}' non deve essere 'static'
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- Il metodo TestCleanup '{0}' deve essere un metodo 'ordinary'
-
-
-
- TestCleanup method '{0}' should be 'public'
- Il metodo TestCleanup '{0}' deve essere 'public'
+- devono essere 'public'
+- non devono essere 'static'
+- non devono essere generici o definiti in una classe generica
+- non devono essere 'abstract'
+- non devono accettare alcun parametro
+- il tipo restituito deve essere 'void', 'Task' o 'ValueTask'
+- non devono essere 'async void'
+- non devono essere un metodo speciale (finalizzatore, operatore...).
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo TestCleanup '{0}' deve restituire 'void', 'Task' o 'ValueTask'
+
+ TestCleanup method '{0}' signature is invalid
+ La firma del metodo TestCleanup '{0}' non è valida
@@ -561,63 +436,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
I metodi contrassegnati con [TestInitialize] devono seguire il layout seguente per essere validi:
-- Deve essere 'public'
-- Non deve essere 'static'
-- Non deve essere generico
-- Non deve essere 'abstract'
-- Non deve accettare alcun parametro
-- Il tipo restituito deve essere "void", "Task" o "ValueTask"
-- Non deve essere 'async void'
-- Non deve essere un metodo speciale (finalizzatore, operatore...).
-
-
-
- TestInitialize method '{0}' should not take any parameter
- Il metodo TestInitialize '{0}' non deve accettare alcun parametro
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- Il metodo TestInitialize '{0}' non deve essere 'abstract'
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- Il metodo TestInitialize '{0}' non deve essere 'async void'
-
-
-
- TestInitialize method '{0}' should not be generic
- Il metodo TestInitialize '{0}' non deve essere generico
-
-
-
- TestInitialize method '{0}' should not be 'static'
- Il metodo TestInitialize '{0}' non deve essere 'static'
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- Il metodo TestInitialize '{0}' deve essere un metodo 'ordinary'
-
-
-
- TestInitialize method '{0}' should be 'public'
- Il metodo TestInitialize '{0}' deve essere 'public'
+- devono essere 'public'
+- non devono essere 'static'
+- non devono essere generici né definiti in una classe generica
+- non devono essere 'abstract'
+- non devono accettare alcun parametro
+- il tipo restituito deve essere 'void', 'Task' o 'ValueTask'
+- non devono essere 'async void'
+- non devono essere un metodo speciale (finalizzatore, operatore...).
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Il metodo TestInitialize '{0}' deve restituire 'void', 'Task' o 'ValueTask'
+
+ TestInitialize method '{0}' signature is invalid
+ La firma del metodo TestInitialize '{0}' non è valida
@@ -704,6 +544,31 @@
Il metodo di test non deve essere ignorato
+
+ Type contaning '[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 containing '[TestMethod]' should be marked with '[TestClass]'
+ Il tipo contenente '[TestMethod]' deve essere contrassegnato con '[TestClass]'
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ I metodi di fixture di test asincroni non richiedono il suffisso 'Async'
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ I metodi di test asincroni non richiedono il suffisso 'Async'
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] può essere impostato solo su metodi contrassegnati con [TestMethod]
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf
index cfafb72773..6462b9ee61 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[AssemblyCleanup] でマークされたメソッドを有効にするには、次のレイアウトに従う必要があります:
-- 'public' である必要があります
-- 'static' である必要があります
-- ジェネリックにすることはできません
-- パラメーターを受け取ることができません
+- 'public' である
+- 'static' である
+- ジェネリックではなく、ジェネリック クラスでも定義されていない
+- パラメーターを受け取りません
- 戻り値の型が 'void'、'Task'、または 'ValueTask' である必要があります
-- 'async void' にすることはできません
-- 特殊なメソッド (ファイナライザー、演算子...) にすることはできません。
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- AssemblyCleanup メソッド '{0}' はパラメーターを受け取ることができません
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- AssemblyCleanup メソッド '{0}' をジェネリック クラスで宣言することはできません
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyCleanup メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- AssemblyCleanup メソッド '{0}' をジェネリックにすることはできません
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- AssemblyCleanup メソッド '{0}' は 'ordinary' メソッドである必要があります
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- AssemblyCleanup メソッド '{0}' は 'public' である必要があります
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyCleanup メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
+- 'async void' ではありません
+- 特殊なメソッド (ファイナライザー、演算子...) ではありません。
-
- AssemblyCleanup method '{0}' should be 'static'
- AssemblyCleanup メソッド '{0}' を 'static' にすることはできません
+
+ AssemblyCleanup method '{0}' signature is invalid
+ AssemblyCleanup メソッド '{0}' シグネチャが無効です
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[AssemblyInitialize] でマークされたメソッドを有効にするには、次のレイアウトに従う必要があります:
-- 'public' である必要があります
-- 'static' である必要があります
-- ジェネリックにすることはできません
-- 'TestContext' 型のパラメーターを 1 つ受け取る必要があります
+- 'public' である
+- 'static' である
+- ジェネリックではなく、ジェネリック クラスでも定義されていない
+- 'TestContext' 型のパラメーターを 1 つ受け取ります
- 戻り値の型が 'void'、'Task'、または 'ValueTask' である必要があります
-- 'async void' にすることはできません
-- 特殊なメソッド (ファイナライザー、演算子...) にすることはできません。
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- AssemblyInitialize メソッド '{0}' をジェネリック クラスで宣言することはできません
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyInitialize メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
+- 'async void' ではありません
+- 特殊なメソッド (ファイナライザー、演算子...) ではありません。
-
- AssemblyInitialize method '{0}' should not be generic
- AssemblyInitialize メソッド '{0}' をジェネリックにすることはできません
+
+ AssemblyInitialize method '{0}' signature is invalid
+ AssemblyInitialize メソッド '{0}' シグネチャが無効です
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- AssemblyInitialize メソッド '{0}' は 'ordinary' メソッドである必要があります
-
-
-
- AssemblyInitialize method '{0}' should be 'public'
- AssemblyInitialize メソッド '{0}' は 'public' である必要があります
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyInitialize メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
+
+ AssemblyInitialize methods should have valid layout
+ AssemblyInitialize メソッドには有効なレイアウトが必要です
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- AssemblyInitialize メソッド '{0}' は、'TestContext' 型の単一パラメーターを受け取る必要があります
+
+ Prefer adding an additional assertion that checks for null
+ 追加のアサーションによる null チェックを推奨する
-
- AssemblyInitialize method '{0}' should be 'static'
- AssemblyInitialize メソッド '{0}' は 'static' にする必要があります
-
-
-
- AssemblyInitialize methods should have valid layout
- AssemblyInitialize メソッドには有効なレイアウトが必要です
+
+ Avoid conditional access in assertions
+ アサーションの中で条件付きアクセスの使用を避ける
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[ClassCleanup] でマークされたメソッドを有効にするには、次のレイアウトに従う必要があります:
-- 'public' である必要があります
-- 'static' にすることはできません
-- ジェネリックにすることはできません
-- パラメーターを受け取ることができません
+- 'public' である
+- 'static' ではありません
+- ジェネリックではなく、ジェネリック クラスでも定義されていない
+- パラメーターを受け取りません
- 戻り値の型が 'void'、'Task'、または 'ValueTask' である必要があります
-- 'async void' にすることはできません
-- 特殊なメソッド (ファイナライザー、演算子...) にすることはできません。
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- ClassCleanup メソッド '{0}' はパラメーターを受け取ることができません
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- ClassCleanup メソッド '{0}' は、`InheritanceBehavior` モードが設定されていないと、ジェネリック クラスで宣言できません
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassCleanup メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
+- 'async void' ではありません
+- 特殊なメソッド (ファイナライザー、演算子...) ではありません。
-
- ClassCleanup method '{0}' should not be generic
- ClassCleanup メソッド '{0}' をジェネリックにすることはできません
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- ClassCleanup メソッド '{0}' は 'ordinary' メソッドである必要があります
-
-
-
- ClassCleanup method '{0}' should be 'public'
- ClassCleanup メソッド '{0}' は 'public' である必要があります
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassCleanup メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
-
-
-
- ClassCleanup method '{0}' should be 'static'
- ClassCleanup メソッド '{0}' は 'static' である必要があります
+
+ ClassCleanup method '{0}' signature is invalid
+ ClassCleanup メソッド '{0}' シグネチャが無効です
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[ClassInitialize] でマークされたメソッドを有効にするには、次のレイアウトに従う必要があります:
-- 'public' である必要があります
-- 'static' である必要があります
-- ジェネリックにすることはできません
-- 'TestContext' 型のパラメーターを 1 つ受け取る必要があります
+- 'public' である
+- 'static' である
+- ジェネリックではなく、ジェネリック クラスでも定義されていない
+- 'TestContext' 型のパラメーターを 1 つ受け取ります
- 戻り値の型が 'void'、'Task'、または 'ValueTask' である必要があります
-- 'async void' にすることはできません
-- 特殊なメソッド (ファイナライザー、演算子...) にすることはできません。
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- ClassInitialize メソッド '{0}' は、`InheritanceBehavior` モードが設定されていないと、 ジェネリック クラスで宣言できません
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassInitialize メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
-
-
-
- ClassInitialize method '{0}' should not be generic
- ClassInitialize メソッド '{0}' をジェネリックにすることはできません
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- ClassInitialize メソッド '{0}' は 'ordinary' メソッドである必要があります
-
-
-
- ClassInitialize method '{0}' should be 'public'
- ClassInitialize メソッド '{0}' は 'public' である必要があります
+- 'async void' ではありません
+- 特殊なメソッド (ファイナライザー、演算子...) ではありません。
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassInitialize メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- ClassInitialize メソッド '{0}' は、'TestContext' 型の単一パラメーターを受け取る必要があります
-
-
-
- ClassInitialize method '{0}' should be 'static'
- AssemblyInitialize メソッド '{0}' は 'static' である必要があります
+
+ ClassInitialize method '{0}' signature is invalid
+ ClassInitialize メソッド '{0}' シグネチャが無効です
@@ -339,6 +209,21 @@
静的メンバーに TestContext を格納しない
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute' はテストのコンテキストでは効果がないため、代わりに 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' を使用する必要がある可能性があります。
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' を使用する予定でしたか?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute' はテスト メソッドに影響しません
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert常に失敗している 'Assert.{0}' アサートの代わりに 'Assert.Fail' を使用する。
@@ -349,6 +234,16 @@
常に失敗しているアサートの代わりに 'Assert.Fail' を使用する
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsTestInitialize メソッドよりもコンストラクターを優先する
@@ -389,6 +284,21 @@
コンストラクターよりも TestInitialize メソッドを優先する
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.テスト プロジェクトでは、テスト クラスのみをパブリックとしてマークすることをお勧めします。
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[TestCleanup] でマークされたメソッドを有効にするには、次のレイアウトに従う必要があります:
-- 'public' である必要があります
-- 'static' にすることはできません
-- ジェネリックにすることはできません
-- 'abstract' にすることはできません
-- パラメーターを受け取ることができません
+- 'public' である
+- 'static' ではありません
+- ジェネリックではないか、ジェネリック クラスで定義されている
+- 'abstract' ではありません
+- パラメーターを受け取りません
- 戻り値の型が 'void'、'Task'、または 'ValueTask' である必要があります
-- 'async void' にすることはできません
-- 特殊なメソッド (ファイナライザー、演算子...) にすることはできません。
-
-
-
- TestCleanup method '{0}' should not take any parameter
- TestCleanup メソッド '{0}' はパラメーターを受け取ることができません
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- TestCleanup メソッド '{0}' を 'abstract' にすることはできません
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- TestCleanup メソッド '{0}' を 'async void' にすることはできません
-
-
-
- TestCleanup method '{0}' should not be generic
- TestCleanup メソッド '{0}' をジェネリックにすることはできません
-
-
-
- TestCleanup method '{0}' should not be 'static'
- TestCleanup メソッド '{0}' を 'static' にすることはできません
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- TestCleanup メソッド '{0}' は '通常' メソッドである必要があります
-
-
-
- TestCleanup method '{0}' should be 'public'
- TestCleanup メソッド '{0}' は 'public' である必要があります
+- 'async void' ではありません
+- 特殊なメソッド (ファイナライザー、演算子...) ではありません。
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- TestCleanup メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
+
+ TestCleanup method '{0}' signature is invalid
+ TestCleanup メソッド '{0}' シグネチャが無効です
@@ -562,63 +437,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[TestInitialize] でマークされたメソッドを有効にするには、次のレイアウトに従う必要があります:
-- 'public' である必要があります
-- 'static' にすることはできません
-- ジェネリックにすることはできません
-- 'abstract' にすることはできません
-- パラメーターを受け取ることができません
+- 'public' である
+- 'static' ではありません
+- ジェネリックではなく、ジェネリック クラスでも定義されていない
+- 'abstract' ではありません
+- パラメーターを受け取りません
- 戻り値の型が 'void'、'Task'、または 'ValueTask' である必要があります
-- 'async void' にすることはできません
-- 特殊なメソッド (ファイナライザー、演算子...) にすることはできません。
+- 'async void' ではありません
+- 特殊なメソッド (ファイナライザー、演算子...) ではありません。
-
- TestInitialize method '{0}' should not take any parameter
- TestInitialize メソッド '{0}' はパラメーターを受け取ることができません
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- TestInitialize メソッド '{0}' を 'abstract' にすることはできません
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- TestInitialize メソッド '{0}' を 'async void' にすることはできません
-
-
-
- TestInitialize method '{0}' should not be generic
- TestInitialize メソッド '{0}' をジェネリックにすることはできません
-
-
-
- TestInitialize method '{0}' should not be 'static'
- TestInitialize メソッド '{0}' を 'static' にすることはできません
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- TestInitialize メソッド '{0}' は 'ordinary' メソッドである必要があります
-
-
-
- TestInitialize method '{0}' should be 'public'
- TestInitialize メソッド '{0}' は 'public' である必要があります
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- TestInitialize メソッド '{0}' は 'void'、'Task'、または 'ValueTask' を返す必要があります
+
+ TestInitialize method '{0}' signature is invalid
+ TestInitialize メソッド '{0}' シグネチャが無効です
@@ -705,6 +545,31 @@
テスト メソッドを無視することはできません
+
+ Type contaning '[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 containing '[TestMethod]' should be marked with '[TestClass]'
+ '[TestMethod]' を含む型は '[TestClass]' でマークする必要があります
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ 非同期テスト フィクスチャには 'Async' サフィックスは不要です
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ 非同期テスト メソッドには 'Async' サフィックスは不要です
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] は、[TestMethod] でマークされたメソッドにのみ設定できます
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf
index ea8ed6f160..2bbcb164a9 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[AssemblyCleanup]으로 표시된 메서드가 유효하려면 다음 레이아웃을 따라야 합니다.
-- 'public'이어야 합니다.
+- 'public'이어야 합니다.
- 'static'이어야 합니다.
-- 제네릭이 아니어야 합니다.
-- 매개 변수를 사용하지 않아야 합니다.
+- 제네릭이 아니거나 제네릭 클래스에 정의되지 않음
+- 매개 변수를 사용하지 않음
- 반환 형식은 'void', 'Task' 또는 'ValueTask'여야 합니다.
- 'async void'가 아니어야 합니다.
-- 특수 메서드(종료자, 연산자...)가 아니어야 합니다.
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- AssemblyCleanup 메서드 '{0}'은(는) 매개 변수를 사용하지 않아야 합니다.
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- '{0}' AssemblyCleanup 메서드는 제네릭 클래스에서 선언할 수 없습니다.
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyCleanup 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- AssemblyCleanup 메서드 '{0}'은(는) 제네릭이 아니어야 합니다.
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- AssemblyCleanup 메서드 '{0}'은(는) 'ordinary' 메서드여야 합니다.
+- 특수 메서드(종료자, 연산자...)가 아님.
-
- AssemblyCleanup method '{0}' should be 'public'
- AssemblyCleanup 메서드 '{0}'은(는) 'public'이어야 합니다.
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyCleanup 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
-
-
-
- AssemblyCleanup method '{0}' should be 'static'
- AssemblyCleanup 메서드 '{0}'은(는) 'static'이어야 합니다.
+
+ AssemblyCleanup method '{0}' signature is invalid
+ AssemblyCleanup 메서드 '{0}' 시그니처가 잘못되었습니다.
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[AssemblyInitialize]로 표시된 메서드가 유효하려면 다음 레이아웃을 따라야 합니다.
-- 'public'이어야 합니다.
+- 'public'이어야 합니다.
- 'static'이어야 합니다.
-- 제네릭이 아니어야 합니다.
-- 'TestContext' 형식의 매개 변수를 하나 사용해야 합니다.
+- 제네릭이 아니거나 제네릭 클래스에 정의되지 않음
+- 'TestContext' 형식의 단일 매개 변수 사용
- 반환 형식은 'void', 'Task' 또는 'ValueTask'여야 합니다.
- 'async void'가 아니어야 합니다.
-- 특수 메서드(종료자, 연산자...)가 아니어야 합니다.
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- '{0}' AssemblyInitialize 메서드는 제네릭 클래스에서 선언할 수 없습니다.
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyInitialize 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- AssemblyInitialize 메서드 '{0}'은(는) 제네릭이 아니어야 합니다.
+- 특수 메서드(종료자, 연산자...)가 아님.
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- AssemblyInitialize 메서드 '{0}'은(는) 'ordinary' 메서드여야 합니다.
+
+ AssemblyInitialize method '{0}' signature is invalid
+ AssemblyInitialize 메서드 '{0}' 시그니처가 잘못되었습니다.
-
- AssemblyInitialize method '{0}' should be 'public'
- AssemblyInitialize 메서드 '{0}'은(는) 'public'이어야 합니다.
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyInitialize 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
-
-
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- AssemblyInitialize 메서드 '{0}'은(는) 'TestContext' 형식의 단일 매개 변수를 사용해야 합니다.
+
+ AssemblyInitialize methods should have valid layout
+ AssemblyInitialize 메서드에는 유효한 레이아웃이 있어야 합니다.
-
- AssemblyInitialize method '{0}' should be 'static'
- AssemblyInitialize 메서드 '{0}'은(는) 'static'이어야 합니다.
+
+ Prefer adding an additional assertion that checks for null
+ null을 확인하는 추가 어설션을 추가하는 것이 좋습니다.
-
- AssemblyInitialize methods should have valid layout
- AssemblyInitialize 메서드에는 유효한 레이아웃이 있어야 합니다.
+
+ Avoid conditional access in assertions
+ 어설션에서 조건부 액세스 방지
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[ClassCleanup]으로 표시된 메서드가 유효하려면 다음 레이아웃을 따라야 합니다.
-- 'public'이어야 합니다.
+- 'public'이어야 합니다.
- 'static'이 아니어야 합니다.
-- 제네릭이 아니어야 합니다.
-- 매개 변수를 사용하지 않아야 합니다.
+- 제네릭이 아니거나 제네릭 클래스에 정의되지 않음
+- 매개 변수를 사용하지 않음
- 반환 형식은 'void', 'Task' 또는 'ValueTask'여야 합니다.
- 'async void'가 아니어야 합니다.
-- 특수 메서드(종료자, 연산자...)가 아니어야 합니다.
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- ClassCleanup 메서드 '{0}'은(는) 매개 변수를 사용하지 않아야 합니다.
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- '{0}' ClassCleanup 메서드는 'InheritanceBehavior' 모드가 설정되지 않은 제네릭 클래스에서 선언할 수 없습니다.
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassCleanup 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
-
-
-
- ClassCleanup method '{0}' should not be generic
- ClassCleanup 메서드 '{0}'은(는) 제네릭이 아니어야 합니다.
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- ClassCleanup 메서드 '{0}'은(는) 'ordinary' 메서드여야 합니다.
+- 특수 메서드(종료자, 연산자...)가 아님.
-
- ClassCleanup method '{0}' should be 'public'
- ClassCleanup 메서드 '{0}'은(는) 'public'이어야 합니다.
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassCleanup 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
-
-
-
- ClassCleanup method '{0}' should be 'static'
- ClassCleanup 메서드 '{0}'은(는) 'static'이어야 합니다.
+
+ ClassCleanup method '{0}' signature is invalid
+ ClassCleanup 메서드 '{0}' 시그니처가 잘못되었습니다.
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[ClassInitialize]로 표시된 메서드가 유효하려면 다음 레이아웃을 따라야 합니다.
-- 'public'이어야 합니다.
+- 'public'이어야 합니다.
- 'static'이어야 합니다.
-- 제네릭이 아니어야 합니다.
-- 'TestContext' 형식의 매개 변수를 하나 사용해야 합니다.
+- 제네릭이 아니거나 제네릭 클래스에 정의되지 않음
+- 'TestContext' 형식의 단일 매개 변수 사용
- 반환 형식은 'void', 'Task' 또는 'ValueTask'여야 합니다.
- 'async void'가 아니어야 합니다.
-- 특수 메서드(종료자, 연산자...)가 아니어야 합니다.
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- '{0}' ClassInitialize 메서드는 'InheritanceBehavior' 모드가 설정되지 않은 제네릭 클래스에서 선언할 수 없습니다.
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassInitialize 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
-
-
-
- ClassInitialize method '{0}' should not be generic
- ClassInitialize 메서드 '{0}'은(는) 제네릭이 아니어야 합니다.
+- 특수 메서드(종료자, 연산자...)가 아님.
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- ClassInitialize 메서드 '{0}'은(는) 'ordinary' 메서드여야 합니다.
-
-
-
- ClassInitialize method '{0}' should be 'public'
- ClassInitialize 메서드 '{0}'은(는) 'public'이어야 합니다.
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassInitialize 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- ClassInitialize 메서드 '{0}'은(는) 'TestContext' 형식의 단일 매개 변수를 사용해야 합니다.
-
-
-
- ClassInitialize method '{0}' should be 'static'
- ClassInitialize 메서드 '{0}'은(는) 'static'이어야 합니다.
+
+ ClassInitialize method '{0}' signature is invalid
+ ClassInitialize 메서드 '{0}' 시그니처가 잘못되었습니다.
@@ -339,6 +209,21 @@
TestContext를 정적 멤버에 저장하지 마세요
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute'는 테스트 컨텍스트에 영향을 주지 않으며 대신 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'를 사용하려고 한 것 같습니다.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'를 사용하려고 했나요?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute'는 테스트 메서드에 영향을 주지 않습니다.
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert항상 실패하는 'Assert.{0}' 어설션 대신 'Assert.Fail'을 사용합니다.
@@ -349,6 +234,16 @@
항상 실패하는 어설션 대신 'Assert.Fail' 사용
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsTestInitialize 메서드보다 생성자 선호
@@ -389,6 +284,21 @@
생성자보다 TestInitialize 메서드 선호
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.테스트 프로젝트에서 공용으로 표시된 테스트 클래스만 사용하는 것이 좋습니다.
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
-- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
-
-
-
- TestCleanup method '{0}' should not take any parameter
- TestCleanup 메서드 '{0}'은(는) 매개 변수를 사용하지 않아야 합니다.
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- TestCleanup 메서드 '{0}'은(는) 'abstract'가 아니어야 합니다.
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- TestCleanup 메서드 '{0}'은(는) 'async void'가 아니어야 합니다.
-
-
-
- TestCleanup method '{0}' should not be generic
- TestCleanup 메서드 '{0}'은(는) 제네릭이 아니어야 합니다.
-
-
-
- TestCleanup method '{0}' should not be 'static'
- TestCleanup 메서드 '{0}'은(는) 'static'이 아니어야 합니다.
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- TestCleanup 메서드 '{0}'은(는) 'ordinary' 메서드여야 합니다.
-
-
-
- TestCleanup method '{0}' should be 'public'
- TestCleanup 메서드 '{0}'은(는) 'public'이어야 합니다.
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ [TestCleanup]으로 표시된 메서드가 유효하려면 다음 레이아웃을 따라야 합니다.
+- 'public'이어야 합니다.
+- 'static'이 아니어야 합니다.
+- 제네릭이 아니거나 제네릭 클래스에 정의되지 않음
+- 'abstract'가 아니어야 합니다.
+- 매개 변수를 사용하지 않음
+- 반환 형식은 'void', 'Task' 또는 'ValueTask'여야 합니다.
+- 'async void'가 아니어야 합니다.
+- 특수 메서드(종료자, 연산자...)가 아님.
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- TestCleanup 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
+
+ TestCleanup method '{0}' signature is invalid
+ TestCleanup 메서드 '{0}' 시그니처가 잘못되었습니다.
@@ -562,63 +437,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
-- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
-
-
-
- TestInitialize method '{0}' should not take any parameter
- TestInitialize 메서드 '{0}'은(는) 매개 변수를 사용하지 않아야 합니다.
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- TestInitialize 메서드 '{0}'은(는) 'abstract'가 아니어야 합니다.
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- TestInitialize 메서드 '{0}'은(는) 'async void'가 아니어야 합니다.
-
-
-
- TestInitialize method '{0}' should not be generic
- TestInitialize 메서드 '{0}'은(는) 제네릭이 아니어야 합니다.
-
-
-
- TestInitialize method '{0}' should not be 'static'
- TestInitialize 메서드 '{0}'은(는) 'static'이 아니어야 합니다.
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- TestInitialize 메서드 '{0}'은(는) 'ordinary' 메서드여야 합니다.
-
-
-
- TestInitialize method '{0}' should be 'public'
- TestInitialize 메서드 '{0}'은(는) 'public'이어야 합니다.
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ [TestInitialize]로 표시된 메서드가 유효하려면 다음 레이아웃을 따라야 합니다.
+- 'public'이어야 합니다.
+- 'static'이 아니어야 합니다.
+- 제네릭이 아니거나 제네릭 클래스에 정의되지 않음
+- 'abstract'가 아니어야 합니다.
+- 매개 변수를 사용하지 않음
+- 반환 형식은 'void', 'Task' 또는 'ValueTask'여야 합니다.
+- 'async void'가 아니어야 합니다.
+- 특수 메서드(종료자, 연산자...)가 아님.
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- TestInitialize 메서드 '{0}'은(는) 'void', 'Task' 또는 'ValueTask'를 반환해야 합니다.
+
+ TestInitialize method '{0}' signature is invalid
+ TestInitialize 메서드 '{0}' 시그니처가 잘못되었습니다.
@@ -705,6 +545,31 @@
테스트 메서드는 무시하면 안 됩니다.
+
+ Type contaning '[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 containing '[TestMethod]' should be marked with '[TestClass]'
+ '[TestMethod]'를 포함하는 유형은 '[TestClass]'로 표시되어야 합니다.
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ 비동기 테스트 fixture 메서드에는 'Async' 접미사가 필요하지 않습니다.
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ 비동기 테스트 메서드에는 'Async' 접미사가 필요하지 않습니다.
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}]은(는) [TestMethod] 표시된 메서드에만 설정할 수 있습니다.
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf
index e6e61ecf52..52f3ac53bc 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Metody oznaczone za pomocą [AssemblyCleanup] powinny być zgodne z następującym układem, aby były prawidłowe:
-— Powinna być „publiczna”
-— Powinna być „statyczna”
-— Nie powinna być ogólna
-— Nie powinna przyjmować żadnego parametru
+— być „publiczne”
+— być "statyczne"
+— nie być ogólne ani zdefiniowane w klasie ogólnej
+— nie przyjmować żadnego parametru
— Zwracany typ powinien mieć wartość „void”, „Taks” lub „ValueTask”
-— Nie powinna to być wartość „async void”
-— Nie powinna to być metoda specjalna (finalizator, operator...).
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- Metoda AssemblyCleanup „{0}” nie powinna przyjmować żadnego parametru
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- Metody AssemblyCleanup „{0}” nie można zadeklarować w klasie ogólnej
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda AssemblyCleanup „{0}” powinna zwracać wartość „void”, „Task” lub „ValueTask”
+— nie być „async void”
+— powinna to być metoda specjalna (finalizator, operator itd.).
-
- AssemblyCleanup method '{0}' should not be generic
- Metoda AssemblyCleanup „{0}” nie powinna być ogólna
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- Metoda AssemblyCleanup „{0}” powinna być metodą „zwykłą”
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- Metoda AssemblyCleanup „{0}” powinna być „publiczna”
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda AssemblyCleanup „{0}” powinna zwracać wartość „void”, „Task” lub „ValueTask”
-
-
-
- AssemblyCleanup method '{0}' should be 'static'
- Metoda AssemblyCleanup „{0}” powinna być „statyczna”
+
+ AssemblyCleanup method '{0}' signature is invalid
+ Podpis metody AssemblyCleanup „{0}” jest nieprawidłowy
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Metody oznaczone za pomocą [AssemblyInitialize] powinny być zgodne z następującym układem, aby były prawidłowe:
-— Powinna być „publiczna”
-— Powinna być „statyczna”
-— Nie powinna być ogólna
-— Powinna przyjmować jeden parametr typu „TestContext”
+— być „publiczne”
+— być "statyczne"
+- nie być ogólne ani być zdefiniowane w klasie ogólnej
+— przyjmować pojedynczy parametr typu „TestContext”
— Zwracany typ powinien mieć wartość „void”, „Taks” lub „ValueTask”
-— Nie powinna to być wartość „async void”
-— Nie powinna to być metoda specjalna (finalizator, operator...).
+— nie być „async void”
+— powinna to być metoda specjalna (finalizator, operator itd.).
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- Metody AssemblyInitialize „{0}” nie można zadeklarować w klasie ogólnej
+
+ AssemblyInitialize method '{0}' signature is invalid
+ Podpis metody AssemblyInitialize „{0}” jest nieprawidłowy
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda AssemblyInitialize „{0}” powinna zwracać wartość „void”, „Task” lub „ValueTask”
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- Metoda AssemblyInitialize „{0}” nie powinna być ogólna
-
-
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- Metoda AssemblyInitialize „{0}” powinna być metodą „zwykłą”
-
-
-
- AssemblyInitialize method '{0}' should be 'public'
- Metoda AssemblyInitialize „{0}” powinna być „publiczna”
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda AssemblyInitialize „{0}” powinna zwracać wartość „void”, „Task” lub „ValueTask”
-
-
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- Metoda AssemblyInitialize „{0}” powinna przyjmować jeden parametr typu „TestContext”
+
+ AssemblyInitialize methods should have valid layout
+ Metody AssemblyInitialize powinny mieć prawidłowy układ
-
- AssemblyInitialize method '{0}' should be 'static'
- Metoda AssemblyInitialize „{0}” nie powinna być „statyczna”
+
+ Prefer adding an additional assertion that checks for null
+ Preferuj dodawanie dodatkowej asercji, która sprawdza pod kątem wartości null
-
- AssemblyInitialize methods should have valid layout
- Metody AssemblyInitialize powinny mieć prawidłowy układ
+
+ Avoid conditional access in assertions
+ Unikaj dostępu warunkowego w asercjach
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Metody oznaczone za pomocą [ClassCleanup] powinny być zgodne z następującym układem, aby były prawidłowe:
-— Powinna być „publiczna”
-— Nie powinna być „statyczna”
-— Nie powinna być ogólna
-— Nie powinna przyjmować żadnego parametru
+— być „publiczne”
+— nie być „statyczne”
+— nie być ogólne ani zdefiniowane w klasie ogólnej
+— nie przyjmować żadnego parametru
— Zwracany typ powinien mieć wartość „void”, „Taks” lub „ValueTask”
-— Nie powinna to być wartość „async void”
-— Nie powinna to być metoda specjalna (finalizator, operator...).
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- Metoda ClassCleanup „{0}” nie powinna przyjmować żadnego parametru
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Metody ClassCleanup „{0}” nie można zadeklarować w klasie ogólnej bez ustawionego trybu „InheritanceBehavior”
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda ClassCleanup „{0}” powinna zwracać wartość „void”, „Task” lub „ValueTask”
-
-
-
- ClassCleanup method '{0}' should not be generic
- Metoda ClassCleanup „{0}” nie powinna być ogólna
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- Metoda ClassCleanup „{0}” powinna być metodą „zwykłą”
-
-
-
- ClassCleanup method '{0}' should be 'public'
- Metoda ClassCleanup „{0}” powinna być „publiczna”
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda ClassCleanup „{0}” powinna zwracać wartość „void”, „Task” lub „ValueTask”
+— nie być „async void”
+— powinna to być metoda specjalna (finalizator, operator itd.).
-
- ClassCleanup method '{0}' should be 'static'
- Metoda ClassCleanup „{0}” powinna być „statyczna”
+
+ ClassCleanup method '{0}' signature is invalid
+ Podpis metody ClassCleanup „{0}” jest nieprawidłowy
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Metody oznaczone za pomocą [ClassInitialize] powinny być zgodne z następującym układem, aby były prawidłowe:
-— Powinna być „publiczna”
-— Powinna być „statyczna”
-— Nie powinna być ogólna
-— Powinna przyjmować jeden parametr typu „TestContext”
+— być „publiczne”
+— być "statyczne"
+- nie być ogólne ani być zdefiniowane w klasie ogólnej
+— przyjmować pojedynczy parametr typu „TestContext”
— Zwracany typ powinien mieć wartość „void”, „Taks” lub „ValueTask”
-— Nie powinna to być wartość „async void”
-— Nie powinna to być metoda specjalna (finalizator, operator...).
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Metody ClassInitialize „{0}” nie można zadeklarować w klasie ogólnej bez ustawionego trybu „InheritanceBehavior”
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda ClassInitialize „{0}” powinna zwracać wartość „void”, „Task” lub „ValueTask”
-
-
-
- ClassInitialize method '{0}' should not be generic
- Metoda ClassInitialize „{0}” nie powinna być ogólna
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- Metoda ClassInitialize „{0}” powinna być metodą „zwykłą”
-
-
-
- ClassInitialize method '{0}' should be 'public'
- Metoda ClassInitialize „{0}” powinna być „publiczna”
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda ClassInitialize „{0}” powinna zwracać wartość „void”, „Task” lub „ValueTask”
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- Metoda ClassInitialize „{0}” powinna przyjmować jeden parametr typu „TestContext”
+— nie być „async void”
+— powinna to być metoda specjalna (finalizator, operator itd.).
-
- ClassInitialize method '{0}' should be 'static'
- Metoda ClassInitialize „{0}” powinna być „'statyczna”
+
+ ClassInitialize method '{0}' signature is invalid
+ Podpis metody ClassInitialize „{0}” jest nieprawidłowy
@@ -339,6 +209,21 @@
Nie przechowuj elementu TestContext w statycznym elemencie członkowskim
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ Element „System.ComponentModel.DescriptionAttribute” nie ma żadnego efektu w kontekście testów i prawdopodobnie chcesz użyć elementu „Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute”.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ Czy chodziło Ci o użycie elementu „Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute”?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ Element „System.ComponentModel.DescriptionAttribute” nie ma wpływu na metody testowe
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assertUżyj trybu „Assert.Fail” zamiast kończącej się zawsze niepowodzeniem instrukcji „Assert.{0}”
@@ -349,6 +234,16 @@
Użyj trybu „Assert.Fail” zamiast kończącej się zawsze niepowodzeniem instrukcji asercji
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsPreferowanie konstruktorów niż metod TestInitialize
@@ -389,6 +284,21 @@
Preferowanie metod TestInitialize niż konstruktorów
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.Uważa się, że dobrą praktyką jest oznaczanie tylko klas testowych jako publicznych w projekcie testowym.
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- Metody oznaczone znakiem [TestCleanup] powinny być zgodne z następującym układem, aby były prawidłowe:
-— powinna być „publiczna”
-— nie powinna być „statyczna”
-— nie powinna być ogólna
-— nie powinna być „abstrakcyjna”
-— nie powinna przyjmować żadnego parametru
-— zwracany typ powinien mieć wartość „unieważniono”, „Zadanie” lub „ValueTask”
-— nie powinna to być wartość „async void”
-— nie powinna to być metoda specjalna (finalizator, operator...).
-
-
-
- TestCleanup method '{0}' should not take any parameter
- Metoda TestCleanup „{0}” nie powinna przyjmować żadnego parametru
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- Metoda TestCleanup „{0}” nie powinna być „abstrakcyjna”
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- Metoda TestCleanup „{0}” nie powinna mieć wartości „async void”
-
-
-
- TestCleanup method '{0}' should not be generic
- Metoda TestCleanup „{0}” nie powinna być ogólna
-
-
-
- TestCleanup method '{0}' should not be 'static'
- Metoda TestCleanup „{0}” nie powinna być „statyczna”
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- Metoda TestCleanup „{0}” powinna być metodą „zwykłą”
-
-
-
- TestCleanup method '{0}' should be 'public'
- Metoda TestCleanup „{0}” powinna być „publiczna”
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ Metody oznaczone jako [TestCleanup] powinny być zgodne z następującym układem, aby były prawidłowe:
+— być „publiczne”
+— nie być „statyczne”
+— nie być ogólne lub być zdefiniowane w klasie ogólnej
+nie być „abstrakcyjne”
+— nie przyjmować żadnego parametru
+— zwracany typ powinien mieć wartość „void”, „Task” lub „ValueTask”
+— nie być „async void”
+— powinna to być metoda specjalna (finalizator, operator itd.).
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda TestCleanup „{0}” powinna zwracać wartość „unieważniono”, „Zadanie” lub „ValueTask”
+
+ TestCleanup method '{0}' signature is invalid
+ Podpis metody TestCleanup „{0}” jest nieprawidłowy
@@ -561,63 +436,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Metody oznaczone znakiem [TestInitialize] powinny być zgodne z następującym układem, aby były prawidłowe:
-— powinna być „publiczna”
-— nie powinna być „statyczna”
-— nie powinna być ogólna
-— nie powinna być „abstrakcyjna”
-— nie powinna przyjmować żadnego parametru
-— zwracany typ powinien mieć wartość „unieważniono”, „Zadanie” lub „ValueTask”
-— nie powinna to być wartość „async void”
-— nie powinna to być metoda specjalna (finalizator, operator...).
-
-
-
- TestInitialize method '{0}' should not take any parameter
- Metoda TestInitialize „{0}” nie powinna przyjmować żadnego parametru
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- Metoda TestInitialize „{0}” nie powinna być „abstrakcyjna”
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- Metoda TestInitialize „{0}” nie powinna mieć wartości "async void"
-
-
-
- TestInitialize method '{0}' should not be generic
- Metoda TestInitialize „{0}” nie powinna być ogólna
-
-
-
- TestInitialize method '{0}' should not be 'static'
- Metoda TestInitialize „{0}” nie powinna być „statyczna”
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- Metoda TestInitialize „{0}” powinna być metodą „zwykłą”
-
-
-
- TestInitialize method '{0}' should be 'public'
- Metoda TestInitialize „{0}” powinna być „publiczna”
+— być „publiczne”
+— nie być „statyczne”
+— nie być ogólne ani zdefiniowane w klasie ogólnej
+nie być „abstrakcyjne”
+— nie przyjmować żadnego parametru
+— zwracany typ powinien mieć wartość „void”, „Task” lub „ValueTask”
+— nie być „async void”
+— powinna to być metoda specjalna (finalizator, operator itd.).
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Metoda TestInitialize „{0}” powinna zwracać wartość „unieważniono”, „Zadanie” lub „ValueTask”
+
+ TestInitialize method '{0}' signature is invalid
+ Podpis metody TestInitialize „{0}” jest nieprawidłowy
@@ -704,6 +544,31 @@
Metoda testowa nie powinna być ignorowana
+
+ 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.
+
+
+
+ Class '{0}' contains test methods and should be marked with '[TestClass]'
+ Klasa „{0}” zawiera metody testowe i powinna być oznaczona klasą „[TestClass]”
+
+
+
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+ Typ zawierający metodę „[TestMethod]” powinien być oznaczony klasą „[TestClass]”
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ Asynchroniczne metody testowe nie wymagają sufiksu „Async”
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ Asynchroniczne metody testowe nie wymagają sufiksu „Async”
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] można ustawić tylko dla metod oznaczonych znakiem [TestMethod]
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf
index e6f0e2ca20..533a692523 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Os métodos marcados com [AssemblyCleanup] devem seguir o seguinte layout para serem válidos:
-— deve ser "público"
-– ele deve ser "estático"
-— não deve ser genérico
-— não deve aceitar nenhum parâmetro
+— ser "público"
+— ser "estático"
+— não ser genérico nem definido em uma classe genérica
+— não aceitar nenhum parâmetro
— o tipo de retorno deve ser "nulo", "Tarefa" ou "ValueTask"
-— não deve ser "nulo assíncrono"
-— não deve ser um método especial (finalizador, operador...).
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- O método AssemblyCleanup "{0}" não deve usar nenhum parâmetro
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- O método AssemblyCleanup '{0}' não pode ser declarado em uma classe genérica
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método AssemblyCleanup "{0}" deve retornar "void", "Task" ou "ValueTask"
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- O método AssemblyCleanup "{0}" não deve ser genérico
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- O método AssemblyCleanup "{0}" deve ser um método "comum"
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- O método AssemblyCleanup "{0}" deve ser "público"
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método AssemblyCleanup "{0}" deve retornar "void", "Task" ou "ValueTask"
+— não ser "nulo assíncrono"
+— não ser um método especial (finalizador, operador...).
-
- AssemblyCleanup method '{0}' should be 'static'
- O método AssemblyCleanup "{0}" deve ser "estático"
+
+ AssemblyCleanup method '{0}' signature is invalid
+ A assinatura do método AssemblyCleanup "{0}" é inválida
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Os métodos marcados com [AssemblyInitialize] devem seguir o seguinte layout para serem válidos:
-— deve ser "público"
-– ele deve ser "estático"
-— não deve ser genérico
-– ele deve usar um parâmetro do tipo "TestContext"
+— ser "público"
+— ser "estático"
+— não ser genérico nem ser definido em uma classe genérica
+— aceitar um único parâmetro do tipo "TestContext"
— o tipo de retorno deve ser "nulo", "Tarefa" ou "ValueTask"
-— não deve ser "nulo assíncrono"
-— não deve ser um método especial (finalizador, operador...).
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- O método AssemblyInitialize '{0}' não pode ser declarado em uma classe genérica
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método AssemblyInitialize "{0}" deve retornar "void", "Task" ou "ValueTask"
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- O método AssemblyInitialize "{0}" não deve ser genérico
+— não ser "nulo assíncrono"
+— não ser um método especial (finalizador, operador...).
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- O método AssemblyInitialize "{0}" deve ser um método "comum"
+
+ AssemblyInitialize method '{0}' signature is invalid
+ A assinatura do método AssemblyInitialize "{0}" é inválida
-
- AssemblyInitialize method '{0}' should be 'public'
- O método AssemblyInitialize "{0}" deve ser "público"
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método AssemblyInitialize "{0}" deve retornar "void", "Task" ou "ValueTask"
+
+ AssemblyInitialize methods should have valid layout
+ Os métodos AssemblyInitialize devem ter um layout válido
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- O método AssemblyInitialize "{0}" deve usar um único parâmetro do tipo "TestContext"
+
+ Prefer adding an additional assertion that checks for null
+ Preferir adicionar uma declaração adicional que verifica se existe um nulo
-
- AssemblyInitialize method '{0}' should be 'static'
- O método AssemblyInitialize "{0}" deve ser "estático"
-
-
-
- AssemblyInitialize methods should have valid layout
- Os métodos AssemblyInitialize devem ter um layout válido
+
+ Avoid conditional access in assertions
+ Evitar o acesso condicional nas declarações
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Os métodos marcados com [ClassCleanup] devem seguir o seguinte layout para serem válidos:
-— deve ser "público"
-– ele não deve ser "estático"
-— não deve ser genérico
-— não deve aceitar nenhum parâmetro
+— ser "público"
+— não ser "estático"
+— não ser genérico nem definido em uma classe genérica
+— não aceitar nenhum parâmetro
— o tipo de retorno deve ser "nulo", "Tarefa" ou "ValueTask"
-— não deve ser "nulo assíncrono"
-— não deve ser um método especial (finalizador, operador...).
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- O método ClassCleanup "{0}" não deve usar nenhum parâmetro
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- O método ClassCleanup '{0}' não pode ser declarado em uma classe genérica sem que o modo "InheritanceBehavior" esteja definido
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método ClassCleanup "{0}" deve retornar "void", "Task" ou "ValueTask"
-
-
-
- ClassCleanup method '{0}' should not be generic
- O método ClassCleanup "{0}" não deve ser genérico
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- O método ClassCleanup "{0}" deve ser um método "comum"
-
-
-
- ClassCleanup method '{0}' should be 'public'
- O método ClassCleanup "{0}" deve ser "público"
+— não ser "nulo assíncrono"
+— não ser um método especial (finalizador, operador...).
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método ClassCleanup "{0}" deve retornar "void", "Task" ou "ValueTask"
-
-
-
- ClassCleanup method '{0}' should be 'static'
- O método ClassCleanup "{0}" deve ser "estático"
+
+ ClassCleanup method '{0}' signature is invalid
+ A assinatura do método ClassCleanup "{0}" é inválida
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Os métodos marcados com [ClassInitialize] devem seguir o seguinte layout para serem válidos:
-— deve ser "público"
-– ele deve ser "estático"
-— não deve ser genérico
-– ele deve usar um parâmetro do tipo "TestContext"
+— ser "público"
+— ser "estático"
+— não ser genérico nem ser definido em uma classe genérica
+— aceitar um único parâmetro do tipo "TestContext"
— o tipo de retorno deve ser "nulo", "Tarefa" ou "ValueTask"
-— não deve ser "nulo assíncrono"
-— não deve ser um método especial (finalizador, operador...).
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- O método ClassInitialize '{0}' não pode ser declarado em uma classe genérica sem que o modo "InheritanceBehavior" esteja definido
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método ClassInitialize "{0}" deve retornar "void", "Task" ou "ValueTask"
-
-
-
- ClassInitialize method '{0}' should not be generic
- O método ClassInitialize "{0}" não deve ser genérico
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- O método ClassInitialize "{0}" deve ser um método "comum"
-
-
-
- ClassInitialize method '{0}' should be 'public'
- O método ClassInitialize "{0}" deve ser "público"
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método ClassInitialize "{0}" deve retornar "void", "Task" ou "ValueTask"
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- O método ClassInitialize "{0}" deve usar um único parâmetro do tipo "TestContext"
+— não ser "nulo assíncrono"
+— não ser um método especial (finalizador, operador...).
-
- ClassInitialize method '{0}' should be 'static'
- O método ClassInitialize "{0}" deve ser "estático"
+
+ ClassInitialize method '{0}' signature is invalid
+ A assinatura do método ClassInitialize "{0}" é inválida
@@ -339,6 +209,21 @@
Não armazene TestContext em um membro estático
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute' não tem efeito no contexto de testes e você provavelmente quis usar 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ Você pretendia usar 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute' não tem efeito sobre métodos de teste
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assertUse "Assert.Fail" em vez de uma asserção "Assert.{0}" sempre com falha
@@ -349,6 +234,16 @@
Usar "Assert.Fail" em vez de uma asserção sempre com falha
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsPreferir construtores em vez de métodos TestInitialize
@@ -389,6 +284,21 @@
Preferir métodos TestInitialize em vez de construtores
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.É considerado uma boa prática ter somente classes de teste marcadas como públicas em um projeto de teste.
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- Os métodos marcados com [TestCleanup] devem seguir o seguinte layout para serem válidos:
-— deve ser "público"
-— não deve ser "estático"
-— não deve ser genérico
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ Os métodos marcados com [TestCleanup] devem seguir o seguinte layout para serem válidos:
+— ser "público"
+— não ser "estático"
+— não ser genérico ou ser definido em uma classe genérica
— não deve ser "abstrato"
-— não deve aceitar nenhum parâmetro
+— não aceitar nenhum parâmetro
— o tipo de retorno deve ser "nulo", "Tarefa" ou "ValueTask"
-— não deve ser "nulo assíncrono"
-— não deve ser um método especial (finalizador, operador...).
-
-
-
- TestCleanup method '{0}' should not take any parameter
- O método de TestCleanup "{0}" não deve aceitar nenhum parâmetro
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- O método de TestCleanup "{0}" não deve ser "abstrato"
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- O método de TestCleanup "{0}" não deve ser "nulo assíncrono"
-
-
-
- TestCleanup method '{0}' should not be generic
- O método de TestCleanup "{0}" não deve ser genérico
-
-
-
- TestCleanup method '{0}' should not be 'static'
- O método de TestCleanup "{0}" não deve ser "estático"
+— não ser "nulo assíncrono"
+— não ser um método especial (finalizador, operador...).
-
- TestCleanup method '{0}' should be an 'ordinary' method
- O método de TestCleanup "{0}" deve ser um método "comum"
-
-
-
- TestCleanup method '{0}' should be 'public'
- O método de TestCleanup "{0}" deve ser "público"
-
-
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método de TestCleanup "{0}" deve retornar "nulo", "Tarefa" ou "ValueTask"
+
+ TestCleanup method '{0}' signature is invalid
+ A assinatura do método TestCleanup "{0}" é inválida
@@ -561,63 +436,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- Os métodos marcados com [TestInitialize] devem seguir o seguinte layout para serem válidos:
-— deve ser "público"
-— não deve ser "estático"
-— não deve ser genérico
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ Os métodos marcados com [TestInitialize] devem seguir o seguinte layout para serem válidos:
+— ser "público"
+— não ser "estático"
+— não ser genérico nem definido em uma classe genérica
— não deve ser "abstrato"
-— não deve aceitar nenhum parâmetro
+— não aceitar nenhum parâmetro
— o tipo de retorno deve ser "nulo", "Tarefa" ou "ValueTask"
-— não deve ser "nulo assíncrono"
-— não deve ser um método especial (finalizador, operador...).
-
-
-
- TestInitialize method '{0}' should not take any parameter
- O método de TestInitialize "{0}" não deve aceitar nenhum parâmetro
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- O método de TestInitialize "{0}" não deve ser "abstrato"
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- O método de TestInitialize "{0}" não deve ser "nulo assíncrono"
-
-
-
- TestInitialize method '{0}' should not be generic
- O método de TestInitialize "{0}" não deve ser genérico
+— não ser "nulo assíncrono"
+— não ser um método especial (finalizador, operador...).
-
- TestInitialize method '{0}' should not be 'static'
- O método de TestInitialize "{0}" não deve ser "estático"
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- O método de TestInitialize "{0}" deve ser um método "comum"
-
-
-
- TestInitialize method '{0}' should be 'public'
- O método de TestInitialize "{0}" deve ser "público"
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- O método de TestInitialize "{0}" deve retornar "nulo", "Tarefa" ou "ValueTask"
+
+ TestInitialize method '{0}' signature is invalid
+ A assinatura do método TestInitialize "{0}" é inválida
@@ -704,6 +544,31 @@
O método de teste não deve ser ignorado
+
+ 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.
+
+
+
+ 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 containing '[TestMethod]' should be marked with '[TestClass]'
+ O tipo contendo '[TestMethod]' deve ser marcado com '[TestClass]'
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ Os métodos de acessório de teste assíncronos não exigem o sufixo "Async"
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ Os métodos de teste assíncronos não exigem o sufixo 'Async'
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] só pode ser definido em métodos marcados com [TestMethod]
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf
index 5f4772de0d..3a3ed98288 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Чтобы методы, отмеченные [AssemblyCleanup], были допустимыми, они должны соответствовать следующему макету:
-– метод должен быть общедоступным ("public")
-– метод должен быть статическим ("static")
-– метод не должен быть общим ("generic")
-– метод не должен принимать никаких параметров
-– метод должен возвращать значение типа "void", "Task" или "ValueTask"
-– метод не должен быть асинхронным и не возвращающим значения ("async void")
-– метод не должен быть специальным (метод завершения, оператор…).
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- Метод AssemblyCleanup "{0}" не должен принимать никаких параметров
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- Метод AssemblyCleanup "{0}" не может быть объявлен для универсального класса
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод AssemblyCleanup "{0}" должен возвращать значение "void", "Task" или "ValueTask"
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- Метод AssemblyCleanup "{0}" не должен быть общим ("generic")
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- Метод AssemblyCleanup "{0}" должен быть ординарным ("ordinary")
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- Метод AssemblyCleanup "{0}" должен быть общедоступным ("public")
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод AssemblyCleanup "{0}" должен возвращать значение "void", "Task" или "ValueTask"
+– должны быть "общедоступными"
+– должны быть "статическими"
+– не должны быть универсальным и не должны определяться в универсальном классе
+– не должны принимать никаких параметров
+– тип возвращаемого значения должен быть "void", "Task" или "ValueTask"
+– не должны быть асинхронными и не возвращающими значения ("async void")
+– не должны быть специальными методом (метод завершения, оператор...).
-
- AssemblyCleanup method '{0}' should be 'static'
- Метод AssemblyCleanup "{0}" должен быть статическим ("static")
+
+ AssemblyCleanup method '{0}' signature is invalid
+ Подпись метода AssemblyCleanup "{0}" недопустима
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Чтобы методы, отмеченные [AssemblyInitialize], были допустимыми, они должны соответствовать следующему макету:
-– метод должен быть общедоступным ("public")
-– метод должен быть статическим ("static")
-– метод не должен быть общим ("generic")
-– метод должен принимать один параметр типа "TestContext"
-– метод должен возвращать значение типа "void", "Task" или "ValueTask"
-– метод не должен быть асинхронным и не возвращающим значения ("async void")
-– метод не должен быть специальным (метод завершения, оператор…).
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- Метод AssemblyInitialize "{0}" не может быть объявлен для универсального класса
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод AssemblyInitialize "{0}" должен возвращать значение "void", "Task" или "ValueTask"
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- Метод AssemblyInitialize "{0}" не должен быть общим ("generic")
-
-
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- Метод AssemblyInitialize "{0}" должен быть ординарным ("ordinary")
-
-
-
- AssemblyInitialize method '{0}' should be 'public'
- Метод AssemblyInitialize "{0}" должен быть общедоступным ("public")
+– должны быть "общедоступными"
+– должны быть "статическими"
+– не должны быть универсальным и не должны определяться в универсальном классе
+– должны принимать один параметр типа "TestContext"
+– тип возвращаемого значения должен быть "void", "Task" или "ValueTask"
+– не должны быть асинхронными и не возвращающими значения ("async void")
+– не должны быть специальными методом (метод завершения, оператор...).
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод AssemblyInitialize "{0}" должен возвращать значение "void", "Task" или "ValueTask"
+
+ AssemblyInitialize method '{0}' signature is invalid
+ Подпись метода AssemblyInitialize "{0}" недопустима
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- Метод AssemblyInitialize "{0}" должен принимать один параметр типа "TestContext"
+
+ AssemblyInitialize methods should have valid layout
+ Методы AssemblyInitialize должны использовать допустимый макет
-
- AssemblyInitialize method '{0}' should be 'static'
- Метод AssemblyInitialize "{0}" должен быть статическим ("static")
+
+ Prefer adding an additional assertion that checks for null
+ Предпочитайте добавление дополнительного утверждения, проверяющего наличие значения NULL
-
- AssemblyInitialize methods should have valid layout
- Методы AssemblyInitialize должны использовать допустимый макет
+
+ Avoid conditional access in assertions
+ Избегайте условного доступа в утверждениях
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Чтобы методы, отмеченные [ClassCleanup], были допустимыми, они должны соответствовать следующему макету:
-– метод должен быть общедоступным ("public")
-– метод не должен быть статическим ("static")
-– метод не должен быть общим ("generic")
-– метод не должен принимать никаких параметров
-– метод должен возвращать значение типа "void", "Task" или "ValueTask"
-– метод не должен быть асинхронным и не возвращающим значения ("async void")
-– метод не должен быть специальным (метод завершения, оператор…).
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- Метод ClassCleanup "{0}" не должен принимать никаких параметров
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Метод ClassCleanup "{0}" не может быть объявлен для универсального класса, если не установлен режим InheritanceBehavior
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод ClassCleanup "{0}" должен возвращать значение "void", "Task" или "ValueTask"
-
-
-
- ClassCleanup method '{0}' should not be generic
- Метод ClassCleanup "{0}" не должен быть общим ("generic")
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- Метод ClassCleanup "{0}" должен быть ординарным ("ordinary")
-
-
-
- ClassCleanup method '{0}' should be 'public'
- Метод ClassCleanup "{0}" должен быть общедоступным ("public")
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод ClassCleanup "{0}" должен возвращать значение "void", "Task" или "ValueTask"
+– должны быть "общедоступными"
+– не должны быть "статическими"
+– не должны быть универсальным и не должны определяться в универсальном классе
+– не должны принимать никаких параметров
+– тип возвращаемого значения должен быть "void", "Task" или "ValueTask"
+– не должны быть асинхронными и не возвращающими значения ("async void")
+– не должны быть специальными методом (метод завершения, оператор...).
-
- ClassCleanup method '{0}' should be 'static'
- Метод ClassCleanup "{0}" должен быть статическим ("static")
+
+ ClassCleanup method '{0}' signature is invalid
+ Подпись метода ClassCleanup "{0}" недопустима
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Чтобы методы, отмеченные [ClassInitialize], были допустимыми, они должны соответствовать следующему макету:
-– метод должен быть общедоступным ("public")
-– метод должен быть статическим ("static")
-– метод не должен быть общим ("generic")
-– метод должен принимать один параметр типа "TestContext"
-– метод должен возвращать значение типа "void", "Task" или "ValueTask"
-– метод не должен быть асинхронным и не возвращающим значения ("async void")
-– метод не должен быть специальным (метод завершения, оператор…).
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- Метод ClassInitialize "{0}" не может быть объявлен для универсального класса, если не установлен режим InheritanceBehavior
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод ClassInitialize "{0}" должен возвращать значение "void", "Task" или "ValueTask"
-
-
-
- ClassInitialize method '{0}' should not be generic
- Метод ClassInitialize "{0}" не должен быть общим ("generic")
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- Метод ClassInitialize "{0}" должен быть ординарным ("ordinary")
-
-
-
- ClassInitialize method '{0}' should be 'public'
- Метод ClassInitialize "{0}" должен быть общедоступным ("public")
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод ClassInitialize "{0}" должен возвращать значение "void", "Task" или "ValueTask"
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- Метод ClassInitialize "{0}" должен принимать один параметр типа "TestContext"
+– должны быть "общедоступными"
+– должны быть "статическими"
+– не должны быть универсальным и не должны определяться в универсальном классе
+– должны принимать один параметр типа "TestContext"
+– тип возвращаемого значения должен быть "void", "Task" или "ValueTask"
+– не должны быть асинхронными и не возвращающими значения ("async void")
+– не должны быть специальными методом (метод завершения, оператор...).
-
- ClassInitialize method '{0}' should be 'static'
- Метод ClassInitialize "{0}" должен быть статическим ("static")
+
+ ClassInitialize method '{0}' signature is invalid
+ Подпись метода ClassInitialize "{0}" недопустима
@@ -339,6 +209,21 @@
Не хранить TestContext в статическом элементе
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assertИспользуйте "Assert.Fail" вместо утверждения с постоянным сбоем "Assert.{0}"
@@ -349,6 +234,16 @@
Используйте "Assert.Fail" вместо утверждения с постоянным сбоем
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsПредпочитать конструкторы методам TestInitialize
@@ -389,6 +284,21 @@
Предпочитать методы TestInitialize конструкторам
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.Рекомендуется использовать только тестовые классы, помеченные как общедоступные в тестовом проекте.
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- Чтобы методы, отмеченные [TestCleanup], были действительными, они должны соответствовать следующему методу:
-– должно быть присвоено значение "public"
-– должно быть присвоено значение, отличное от "static"
-– должно быть присвоено значение, отличное от "generic"
-– должно быть присвоено значение, отличное от "abstract"
-– не должны присваиваться параметры
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ Чтобы методы, отмеченные [TestCleanup], были действительными, они должны соответствовать следующему макету:
+– должны быть "общедоступными"
+– не должны быть "статическими"
+– не должны быть универсальным и не должны определяться в универсальном классе
+– не должны быть "абстрактными"
+– не должны принимать никаких параметров
– тип возвращаемого значения должен быть "void", "Task" или "ValueTask"
-– должно быть присвоено значение, отличное от "async void"
-– это должен быть специальный метод (метод завершения, оператор...).
-
-
-
- TestCleanup method '{0}' should not take any parameter
- Методу TestCleanup "{0}" не должны присваиваться параметры
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- Методу TestCleanup "{0}" должно быть присвоено значение, отличное от "abstract"
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- Методу TestCleanup "{0}" не должно присваиваться значение "async void"
-
-
-
- TestCleanup method '{0}' should not be generic
- Методу TestCleanup "{0}" не должно присваиваться значение "generic"
-
-
-
- TestCleanup method '{0}' should not be 'static'
- Методу TestCleanup "{0}" не должно присваиваться значение "static"
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- Методу TestCleanup "{0}" должно быть присвоено значение "ordinary"
-
-
-
- TestCleanup method '{0}' should be 'public'
- Методу TestCleanup "{0}" должно быть присвоено значение "public"
+– не должны быть асинхронными и не возвращающими значения ("async void")
+– не должны быть специальными методом (метод завершения, оператор...).
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод TestCleanup "{0}" должен возвращать значение "void", "Task" или "ValueTask"
+
+ TestCleanup method '{0}' signature is invalid
+ Подпись метода TestCleanup "{0}" недопустима
@@ -561,63 +436,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
Чтобы методы, отмеченные [TestInitialize], были допустимыми, они должны соответствовать следующему макету:
-– должно быть присвоено значение "public"
-– должно быть присвоено значение, отличное от "static"
-– должно быть присвоено значение, отличное от "generic"
-– должно быть присвоено значение, отличное от "abstract"
-– не должны присваиваться параметры
+– должны быть "общедоступными"
+– не должны быть "статическими"
+– не должны быть универсальным и не должны определяться в универсальном классе
+– не должны быть "абстрактными"
+– не должны принимать никаких параметров
– тип возвращаемого значения должен быть "void", "Task" или "ValueTask"
-– должно быть присвоено значение, отличное от "async void"
-– это должен быть специальный метод (метод завершения, оператор...).
+– не должны быть асинхронными и не возвращающими значения ("async void")
+– не должны быть специальными методом (метод завершения, оператор...).
-
- TestInitialize method '{0}' should not take any parameter
- Методу TestInitialize "{0}" не должны присваиваться параметры
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- Методу TestInitialize "{0}" не должно присваиваться значение "abstract"
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- Методу TestInitialize "{0}" не должно присваиваться значение "async void"
-
-
-
- TestInitialize method '{0}' should not be generic
- Методу TestInitialize "{0}" не должно присваиваться значение "generic"
-
-
-
- TestInitialize method '{0}' should not be 'static'
- Методу TestInitialize "{0}" не должно присваиваться значение "static"
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- Методу TestInitialize "{0}" должно быть присвоено значение "ordinary"
-
-
-
- TestInitialize method '{0}' should be 'public'
- Методу TestInitialize "{0}" должно быть присвоено значение "public"
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- Метод TestInitialize "{0}" должен возвращать значение "void", "Task" или "ValueTask"
+
+ TestInitialize method '{0}' signature is invalid
+ Подпись метода TestInitialize "{0}" недопустима
@@ -704,6 +544,31 @@
Метод теста не должен игнорироваться
+
+ Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored.
+ Type contaning '[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]'
+ Class '{0}' contains test methods and should be marked with '[TestClass]'
+
+
+
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ Методы асинхронных средств тестирования не требуют суффикса "Async".
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ Асинхронные методы теста не требуют суффикса Async
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] можно задать только для методов с пометкой [TestMethod]
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf
index 371e1218f4..6dc3b10499 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[AssemblyCleanup] ile işaretlenen yöntemlerin geçerli olması için aşağıdaki düzeni takip etmesi gerekir:
-- 'public' olmalıdır
-- 'static' olmalıdır
-- genel olmamalıdır
-- herhangi bir parametre almamalıdır
+- 'public' olmalı
+- 'static' olmalı
+- genel olamaz veya genel bir sınıf üzerinde tanımlanamaz
+- herhangi bir parametre alamaz
- dönüş türü 'void', 'Task' veya 'ValueTask' olmalıdır
-- 'async void' olmamalıdır
-- özel bir yöntem (sonlandırıcı, işleç...) olmamalıdır.
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- '{0}' AssemblyCleanup yöntemi herhangi bir parametre almamalıdır
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- '{0}' AssemblyCleanup metodu genel bir sınıfta bildirilemez
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' AssemblyCleanup yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- '{0}' AssemblyCleanup yöntemi genel olmamalıdır
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- '{0}' AssemblyCleanup yöntemi 'ordinary' bir yöntem olmalıdır
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- AssemblyCleanup yöntemi '{0}' 'public' olmalıdır
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' AssemblyCleanup yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
+- 'async void' olamaz
+- özel bir yöntem (sonlandırıcı, işleç...) olamaz.
-
- AssemblyCleanup method '{0}' should be 'static'
- AssemblyCleanup yöntemi '{0}' 'static' olmalıdır
+
+ AssemblyCleanup method '{0}' signature is invalid
+ AssemblyCleanup yöntemi '{0}' imzası geçersiz
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[AssemblyInitialize] ile işaretlenen yöntemlerin geçerli olması için aşağıdaki düzeni takip etmesi gerekir:
-- 'public' olmalıdır
-- 'static' olmalıdır
-- genel olmamalıdır
-- 'TestContext' türünden bir parametre almalıdır
+- 'public' olmalı
+- 'static' olmalı
+- genel olamaz veya genel bir sınıf üzerinde tanımlanamaz
+- 'TestContext' türünde tek bir parametre almalıdır
- dönüş türü 'void', 'Task' veya 'ValueTask' olmalıdır
-- 'async void' olmamalıdır
-- özel bir yöntem (sonlandırıcı, işleç...) olmamalıdır.
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- '{0}' AssemblyInitialize metodu genel bir sınıfta bildirilemez
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' AssemblyInitialize yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
+- 'async void' olamaz
+- özel bir yöntem (sonlandırıcı, işleç...) olamaz.
-
- AssemblyInitialize method '{0}' should not be generic
- '{0}' AssemblyInitialize yöntemi genel olmamalıdır
+
+ AssemblyInitialize method '{0}' signature is invalid
+ AssemblyInitialize yöntemi '{0}' imzası geçersiz
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- '{0}' AssemblyInitialize yöntemi 'ordinary' bir yöntem olmalıdır
-
-
-
- AssemblyInitialize method '{0}' should be 'public'
- '{0}' AssemblyInitialize yöntemi 'public' olmalıdır
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' AssemblyInitialize yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
-
-
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- '{0}' AssemblyInitialize yöntemi, 'TestContext' türünde tek bir parametre almalıdır
+
+ AssemblyInitialize methods should have valid layout
+ AssemblyInitialize yöntemleri geçerli bir düzene sahip olmalıdır
-
- AssemblyInitialize method '{0}' should be 'static'
- AssemblyInitialize yöntemi '{0}' 'static' olmalıdır
+
+ Prefer adding an additional assertion that checks for null
+ Null değerini denetlerken ek bir onaylama eklemeyi tercih et
-
- AssemblyInitialize methods should have valid layout
- AssemblyInitialize yöntemleri geçerli bir düzene sahip olmalıdır
+
+ Avoid conditional access in assertions
+ Onaylamalarda koşullu erişimden kaçın
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[ClassCleanup] ile işaretlenen yöntemlerin geçerli olması için aşağıdaki düzeni takip etmesi gerekir:
-- 'public' olmalıdır
-- 'static' olmamalıdır
-- genel olmamalıdır
-- herhangi bir parametre almamalıdır
+- 'public' olmalı
+- 'static' olamaz
+- genel olamaz veya genel bir sınıf üzerinde tanımlanamaz
+- herhangi bir parametre alamaz
- dönüş türü 'void', 'Task' veya 'ValueTask' olmalıdır
-- 'async void' olmamalıdır
-- özel bir yöntem (sonlandırıcı, işleç...) olmamalıdır.
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- '{0}' ClassCleanup yöntemi herhangi bir parametre almamalıdır
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- '{0}' ClassCleanup metodu 'InheritanceBehavior' modu ayarlanmamış genel bir sınıfta bildirilemez
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' ClassCleanup yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
-
-
-
- ClassCleanup method '{0}' should not be generic
- '{0}' ClassCleanup yöntemi genel olmamalıdır
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- '{0}' ClassCleanup yöntemi 'ordinary' bir yöntem olmalıdır
-
-
-
- ClassCleanup method '{0}' should be 'public'
- '{0}' ClassCleanup yöntemi 'public' olmalıdır
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' ClassCleanup yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
+- 'async void' olamaz
+- özel bir yöntem (sonlandırıcı, işleç...) olamaz.
-
- ClassCleanup method '{0}' should be 'static'
- '{0}' ClassCleanup yöntemi 'static' olmalıdır
+
+ ClassCleanup method '{0}' signature is invalid
+ ClassCleanup yöntemi '{0}' imzası geçersiz
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[ClassInitialize] ile işaretlenen yöntemlerin geçerli olması için aşağıdaki düzeni takip etmesi gerekir:
-- 'public' olmalıdır
-- 'static' olmalıdır
-- genel olmamalıdır
-- 'TestContext' türünden bir parametre almalıdır
+- 'public' olmalı
+- 'static' olmalı
+- genel olamaz veya genel bir sınıf üzerinde tanımlanamaz
+- 'TestContext' türünde tek bir parametre almalıdır
- dönüş türü 'void', 'Task' veya 'ValueTask' olmalıdır
-- 'async void' olmamalıdır
-- özel bir yöntem (sonlandırıcı, işleç...) olmamalıdır.
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- '{0}' ClassInitialize metodu 'InheritanceBehavior' modu ayarlanmamış genel bir sınıfta bildirilemez
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' ClassInitialize yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
-
-
-
- ClassInitialize method '{0}' should not be generic
- '{0}' ClassInitialize yöntemi genel olmamalıdır
+- 'async void' olamaz
+- özel bir yöntem (sonlandırıcı, işleç...) olamaz.
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- '{0}' ClassInitialize yöntemi 'ordinary' bir yöntem olmalıdır
-
-
-
- ClassInitialize method '{0}' should be 'public'
- ClassInitialize yöntemi '{0}' 'public' olmalıdır
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' ClassInitialize yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- '{0}' ClassInitialize yöntemi, 'TestContext' türünde tek bir parametre almalıdır
-
-
-
- ClassInitialize method '{0}' should be 'static'
- ClassInitialize yöntemi '{0}' 'static' olmalıdır
+
+ ClassInitialize method '{0}' signature is invalid
+ ClassInitialize yöntemi '{0}' imzası geçersiz
@@ -339,6 +209,21 @@
TestContext'i statik üyede depolama
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute'un testler bağlamında hiçbir etkisi yoktur ve muhtemelen bunun yerine 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' kullanmak istediniz.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' kullanmayı mı düşündünüz?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute' test yöntemlerini etkilemez
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assertHer zaman başarısız olan 'Assert.{0}' onaylaması yerine 'Assert.Fail' seçeneğini kullanın
@@ -349,6 +234,16 @@
Her zaman başarısız olan onaylama yerine 'Assert.Fail' seçeneğini kullanın
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methodsOluşturucuları TestInitialize yöntemlerine tercih et
@@ -389,6 +284,21 @@
TestInitialize yöntemlerini oluşturuculara tercih et
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.Test projesinde yalnızca public olarak işaretlenmiş test sınıflarının olması iyi bir uygulama olarak kabul edilir.
@@ -453,63 +363,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[TestCleanup] ile işaretlenen yöntemlerin geçerli olması için aşağıdaki düzeni takip etmesi gerekir:
-- 'public' olmalıdır
-- 'static' olmamalıdır
-- genel olmamalıdır
-- 'abstract' olmamalıdır
-- herhangi bir parametre almamalıdır
-- dönüş türü 'void', 'Task' veya 'ValueTask' olmalıdır
-- 'async void' olmamalıdır
-- özel bir yöntem (sonlandırıcı, işleç...) olmamalıdır.
-
-
-
- TestCleanup method '{0}' should not take any parameter
- '{0}' TestCleanup yöntemi herhangi bir parametre almamalıdır
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- '{0}' TestCleanup yöntemi 'abstract' olmamalıdır
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- '{0}' TestCleanup yöntemi 'async void' olmamalıdır
-
-
-
- TestCleanup method '{0}' should not be generic
- '{0}' TestCleanup yöntemi genel olmamalıdır
-
-
-
- TestCleanup method '{0}' should not be 'static'
- '{0}' TestCleanup yöntemi 'static' olmamalıdır
+- 'public' olmalı
+- 'static' olamaz
+- genel olamaz veya genel bir sınıf üzerinde tanımlanamaz
+- 'abstract' olamaz
+- herhangi bir parametre almaz
+- dönüş türü 'void', 'Task' veya 'ValueTask' olmalı
+- 'async void' olamaz
+- özel bir yöntem (sonlandırıcı, işleç...) olamaz.
-
- TestCleanup method '{0}' should be an 'ordinary' method
- '{0}' TestCleanup yöntemi 'ordinary' bir yöntem olmalıdır
-
-
-
- TestCleanup method '{0}' should be 'public'
- '{0}' TestCleanup yöntemi 'public' olmalıdır
-
-
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' TestCleanup yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
+
+ TestCleanup method '{0}' signature is invalid
+ TestCleanup yöntemi '{0}' imzası geçersiz
@@ -562,63 +437,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
+- not be 'async void'
+- not be a special method (finalizer, operator...).
[TestInitialize] ile işaretlenen yöntemlerin geçerli olması için aşağıdaki düzeni takip etmesi gerekir:
-- 'public' olmalıdır
-- 'static' olmamalıdır
-- genel olmamalıdır
-- 'abstract' olmamalıdır
-- herhangi bir parametre almamalıdır
-- dönüş türü 'void', 'Task' veya 'ValueTask' olmalıdır
-- 'async void' olmamalıdır
-- özel bir yöntem (sonlandırıcı, işleç...) olmamalıdır.
+- 'public' olmalı
+- 'static' olamaz
+- genel olamaz veya genel bir sınıf üzerinde tanımlanamaz
+- 'abstract' olamaz
+- herhangi bir parametre almaz
+- dönüş türü 'void', 'Task' veya 'ValueTask' olmalı
+- 'async void' olamaz
+- özel bir yöntem (sonlandırıcı, işleç...) olamaz.
-
- TestInitialize method '{0}' should not take any parameter
- '{0}' TestCleanup yöntemi herhangi bir parametre almamalıdır
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- '{0}' TestInitialize yöntemi 'abstract' olmamalıdır
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- '{0}' TestInitialize yöntemi 'async void' olmamalıdır
-
-
-
- TestInitialize method '{0}' should not be generic
- '{0}' TestInitialize yöntemi genel olmamalıdır
-
-
-
- TestInitialize method '{0}' should not be 'static'
- '{0}' TestInitialize yöntemi 'static' olmamalıdır
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- '{0}' TestInitialize yöntemi 'ordinary' bir yöntem olmalıdır
-
-
-
- TestInitialize method '{0}' should be 'public'
- '{0}' TestInitialize yöntemi 'public' olmalıdır
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- '{0}' TestCleanup yöntemi 'void', 'Task' veya 'ValueTask' döndürmelidir
+
+ TestInitialize method '{0}' signature is invalid
+ TestInitialize yöntemi '{0}' imzası geçersiz
@@ -706,6 +546,31 @@
Test metodu yoksayılmamalıdır
+
+ Type contaning '[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 containing '[TestMethod]' should be marked with '[TestClass]'
+ '[TestMethod]' içeren tür '[TestClass]' ile işaretlenmelidir
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ Zaman uyumsuz test düzeni metotları için 'Async' soneki gerekmez
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ Asenkron test metotları için 'Async' soneki gerekmez
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] yalnızca [TestMethod] ile işaretli yöntemlerde ayarlanabilir
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf
index c17aa68ed1..97ed33cd7b 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 标记有 [AssemblyCleanup] 的方法应遵循以下布局才有效:
-- 它应为“public”
-- 它应为“static”
-- 它不应是泛型的
-- 它不应采用任何参数
-- 返回类型应为“void”、“Task”或“ValueTask”
-- 它不应为“async void”
-- 它不应是特殊方法(终结器、运算符...)。
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- AssemblyCleanup 方法“{0}”不应采用任何参数
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- 不能在泛型类上声明 AssemblyCleanup 方法“{0}”
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyCleanup 方法“{0}”应返回“void”、“Task”或“ValueTask”
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- AssemblyCleanup 方法“{0}”不应是泛型的
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- AssemblyCleanup 方法“{0}”应为“普通”方法
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- AssemblyCleanup 方法“{0}”应是“public”
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyCleanup 方法“{0}”应返回“void”、“Task”或“ValueTask”
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 标记有 [AssemblyCleanup] 的方法应遵循以下布局才会有效:
+- 是 “public”
+- 是 “static”
+- 不是泛型的,也不是在泛型类上定义的
+- 不采用任何参数
+- 返回类型应为 "void"、"Task" 或 "ValueTask"
+- 不是 “async void”
+- 不是特殊方法(终结器、运算符...)。
-
- AssemblyCleanup method '{0}' should be 'static'
- AssemblyCleanup 方法“{0}”不应是“static”
+
+ AssemblyCleanup method '{0}' signature is invalid
+ AssemblyCleanup 方法“{0}”签名无效
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 标记有 [AssemblyInitialize] 的方法应遵循以下布局才有效:
-- 它应为“public”
-- 它应为“static”
-- 它不应是泛型的
-- 它应采用“TestContext”类型的一个参数
-- 返回类型应为“void”、“Task”或“ValueTask”
-- 它不应为“async void”
-- 它不应是特殊方法(终结器、运算符...)。
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- 不能在泛型类上声明 AssemblyInitialize 方法“{0}”
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyInitialize 方法“{0}”应返回“void”、“Task”或“ValueTask”
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- AssemblyInitialize 方法“{0}”不应是泛型的
-
-
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- AssemblyInitialize 方法“{0}”应为“普通”方法
-
-
-
- AssemblyInitialize method '{0}' should be 'public'
- AssemblyInitialize 方法“{0}”不应是“public”
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 标记有 [AssemblyInitialize] 的方法应遵循以下布局才会有效:
+- 是 “public”
+- 是 “static”
+- 不是泛型的,也不是在泛型类上定义的
+- 采用 “TestContext” 类型的单个参数
+- 返回类型应为 "void"、"Task" 或 "ValueTask"
+- 不是 “async void”
+- 不是特殊方法(终结器、运算符...)。
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyInitialize 方法“{0}”应返回“void”、“Task”或“ValueTask”
+
+ AssemblyInitialize method '{0}' signature is invalid
+ AssemblyInitialize 方法“{0}”签名无效
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- AssemblyInitialize 方法“{0}”应采用类型为“TestContext”的单个参数
+
+ AssemblyInitialize methods should have valid layout
+ AssemblyInitialize 方法应具有有效的布局
-
- AssemblyInitialize method '{0}' should be 'static'
- AssemblyInitialize 方法“{0}”不应是“static”
+
+ Prefer adding an additional assertion that checks for null
+ 首选添加检查 null 的其他断言
-
- AssemblyInitialize methods should have valid layout
- AssemblyInitialize 方法应具有有效的布局
+
+ Avoid conditional access in assertions
+ 避免断言中的条件访问
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 标记有 [ClassCleanup] 的方法应遵循以下布局才有效:
-- 它应为“public”
-- 它不应为“static”
-- 它不应是泛型的
-- 它不应采用任何参数
-- 返回类型应为“void”、“Task”或“ValueTask”
-- 它不应为“async void”
-- 它不应是特殊方法(终结器、运算符...)。
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- ClassCleanup 方法“{0}”不应采用任何参数
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- 如果未设置 `InheritanceBehavior` 模式,则无法在泛型类上声明 ClassCleanup 方法“{0}”
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassCleanup 方法“{0}”应返回“void”、“Task” 或“ValueTask”
-
-
-
- ClassCleanup method '{0}' should not be generic
- ClassCleanup 方法“{0}”不应是泛型的
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- ClassCleanup 方法“{0}”应为一种“普通”方法
-
-
-
- ClassCleanup method '{0}' should be 'public'
- ClassCleanup 方法“{0}”应为“public”
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassCleanup 方法“{0}”应返回“void”、“Task” 或“ValueTask”
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 标记有 [ClassCleanup] 的方法应遵循以下布局才会有效:
+- 是 “public”
+- 不是 “static”
+- 不是泛型的,也不是在泛型类上定义的
+- 不采用任何参数
+- 返回类型应为 "void"、"Task" 或 "ValueTask"
+- 不是 “async void”
+- 不是特殊方法(终结器、运算符...)。
-
- ClassCleanup method '{0}' should be 'static'
- ClassCleanup 方法“{0}”应为“static”
+
+ ClassCleanup method '{0}' signature is invalid
+ ClassCleanup 方法“{0}”签名无效
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 标记有 [ClassInitialize] 的方法应遵循以下布局才有效:
-- 它应为“public”
-- 它应为“static”
-- 它不应是泛型的
-- 它应采用“TestContext”类型的一个参数
-- 返回类型应为“void”、“Task”或“ValueTask”
-- 它不应为“async void”
-- 它不应是特殊方法(终结器、运算符...)。
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- 如果未设置 `InheritanceBehavior` 模式,则无法在泛型类上声明 ClassInitialize 方法“{0}”
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassInitialize 方法“{0}”应返回“void”、“Task”或“ValueTask”
-
-
-
- ClassInitialize method '{0}' should not be generic
- ClassInitialize 方法“{0}”不应是泛型的
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- ClassInitialize 方法“{0}”应为“普通”方法
-
-
-
- ClassInitialize method '{0}' should be 'public'
- ClassInitialize 方法“{0}”不应是“public”
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassInitialize 方法“{0}”应返回“void”、“Task”或“ValueTask”
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- ClassInitialize 方法“{0}”应采用类型为“TestContext”的单个参数
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 标记有 [ClassInitialize] 的方法应遵循以下布局才会有效:
+- 是 “public”
+- 是 “static”
+- 不是泛型的,也不是在泛型类上定义的
+- 采用 “TestContext” 类型的单个参数
+- 返回类型应为 "void"、"Task" 或 "ValueTask"
+- 不是 “async void”
+- 不是特殊方法(终结器、运算符...)。
-
- ClassInitialize method '{0}' should be 'static'
- ClassInitialize 方法“{0}”不应是“static”
+
+ ClassInitialize method '{0}' signature is invalid
+ ClassInitialize 方法“{0}”签名无效
@@ -339,6 +209,21 @@
不要将 TestContext 存储在静态成员中
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ “System.ComponentModel.DescriptionAttribute” 在测试上下文中无效,你可能想要改用 “Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute”。
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ 是否打算使用 “Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute”?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ “System.ComponentModel.DescriptionAttribute” 对测试方法没有影响
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert使用 “Assert.Fail” 而不是始终失败的 “Assert.{0}” 断言
@@ -349,6 +234,16 @@
使用 “Assert.Fail” 而不是始终失败的断言
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methods首选构造函数而不是 TestInitialize 方法
@@ -389,6 +284,21 @@
首选 TestInitialize 方法而不是构造函数
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.在测试项目中仅将测试类标记为“公开”是一种不错的做法。
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 标记有 [TestCleanup] 的方法应遵循以下布局才有效:
-- 它应为 "public"
-- 它不应为 "static"
-- 它不应是泛型的
-- 它不应为 "abstract"
-- 它不应采用任何参数
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 标记有 [TestCleanup] 的方法应遵循以下布局才会有效:
+- 是 “public”
+- 不是 “static”
+- 不是泛型的,也不是在泛型类上定义的
+- 不是 “abstract”
+- 不采用任何参数
- 返回类型应为 "void"、"Task" 或 "ValueTask"
-- 它不应为 "async void"
-- 它不应是特殊方法(终结器、运算符...)。
-
-
-
- TestCleanup method '{0}' should not take any parameter
- TestCleanup 方法“{0}”不应采用任何参数
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- TestCleanup 方法“{0}”不应为 "abstract"
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- TestCleanup 方法“{0}”不应为 "async void"
+- 不是 “async void”
+- 不是特殊方法(终结器、运算符...)。
-
- TestCleanup method '{0}' should not be generic
- TestCleanup 方法“{0}”不应是泛型的
-
-
-
- TestCleanup method '{0}' should not be 'static'
- TestCleanup 方法“{0}”不应为 "static"
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- TestCleanup 方法“{0}”应为一种“普通”方法
-
-
-
- TestCleanup method '{0}' should be 'public'
- TestCleanup 方法“{0}”应为 "public"
-
-
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- TestCleanup 方法“{0}”应返回 "void"、"Task" 或 "ValueTask"
+
+ TestCleanup method '{0}' signature is invalid
+ TestCleanup 方法“{0}”签名无效
@@ -561,63 +436,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 标记有 [TestInitialize] 的方法应遵循以下布局才有效:
-- 它应为 "public"
-- 它不应为 "static"
-- 它不应是泛型的
-- 它不应为 "abstract"
-- 它不应采用任何参数
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 标记有 [TestInitialize] 的方法应遵循以下布局才会有效:
+- 是 “public”
+- 不是 “static”
+- 不是泛型的,也不是在泛型类上定义的
+- 不是 “abstract”
+- 不采用任何参数
- 返回类型应为 "void"、"Task" 或 "ValueTask"
-- 它不应为 "async void"
-- 它不应是特殊方法(终结器、运算符...)。
-
-
-
- TestInitialize method '{0}' should not take any parameter
- TestInitialize 方法“{0}”不应采用任何参数
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- TestInitialize 方法“{0}”不应为 "abstract"
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- TestInitialize 方法“{0}”不应为 "async void"
-
-
-
- TestInitialize method '{0}' should not be generic
- TestInitialize 方法“{0}”不应是泛型的
-
-
-
- TestInitialize method '{0}' should not be 'static'
- TestInitialize 方法“{0}”不应为 "static"
+- 不是 “async void”
+- 不是特殊方法(终结器、运算符...)。
-
- TestInitialize method '{0}' should be an 'ordinary' method
- TestInitialize 方法“{0}”应为一种“普通”方法
-
-
-
- TestInitialize method '{0}' should be 'public'
- TestInitialize 方法“{0}”应为 "public"
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- TestInitialize 方法“{0}”应返回 "void"、"Task" 或 "ValueTask"
+
+ TestInitialize method '{0}' signature is invalid
+ TestInitialize 方法“{0}”签名无效
@@ -704,6 +544,31 @@
不应忽略测试方法
+
+ Type contaning '[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 containing '[TestMethod]' should be marked with '[TestClass]'
+ 应使用“[TestClass]”标记包含“[TestMethod]”的类型
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ 异步测试固定例程方法不需要 "Async" 后缀
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ 异步测试方法不需要 "Async" 后缀
+
+ [{0}] can only be set on methods marked with [TestMethod]只能对标记了 [TestMethod] 的方法设置 [{0}]
diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf
index 9f4f424e6b..c982e6b28d 100644
--- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf
+++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf
@@ -4,61 +4,26 @@
Methods marked with [AssemblyCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 標示為 [AssemblyCleanup] 的方法應該遵循下列配置才能有效:
-- 其應為 'public'
-- 其應為 'static'
-- 其不應為泛型
-- 其不應接受任何參數
-- 傳回類型應為 'void'、'Task' 或 'ValueTask'
-- 其不應為 'async void'
-- 其不應為特殊方法 (完成項、運算子...)。
-
-
-
- AssemblyCleanup method '{0}' should not take any parameter
- AssemblyCleanup 方法 '{0}' 不應該接受任何參數
-
-
-
- AssemblyCleanup method '{0}' can't be declared on a generic class
- AssemblyCleanup 方法 '{0}' 不能在泛型類上宣告
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyCleanup 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
-
-
-
- AssemblyCleanup method '{0}' should not be generic
- AssemblyCleanup 方法 '{0}' 不應為泛型
-
-
-
- AssemblyCleanup method '{0}' should be an 'ordinary' method
- AssemblyCleanup 方法 '{0}' 應為 'ordinary' 方法
-
-
-
- AssemblyCleanup method '{0}' should be 'public'
- AssemblyCleanup 方法 '{0}' 應為 'public'
-
-
-
- AssemblyCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyCleanup 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 標示為 [AssemblyCleanup] 的方法應該遵循下列配置才能有效:
+- 為 'public'
+- 為 'static'
+- 非為泛型,也不是在泛型類別上所定義
+- 不接受任何參數
+- 傳回型別應為 'void'、'Task' 或 'ValueTask'
+- 非為 'async void'
+- 非為特殊方法 (完成項、運算子...)。
-
- AssemblyCleanup method '{0}' should be 'static'
- AssemblyCleanup 方法 '{0}' 應為 'static'
+
+ AssemblyCleanup method '{0}' signature is invalid
+ AssemblyCleanup 方法 '{0}' 簽章無效
@@ -68,66 +33,41 @@
Methods marked with [AssemblyInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 標示為 [AssemblyInitialize] 的方法應該遵循下列配置才能有效:
-- 其應為 'public'
-- 其應為 'static'
-- 其不應為泛型
-- 其應該接受類型為 'TestContext' 的一個參數
-- 傳回類型應為 'void'、'Task' 或 'ValueTask'
-- 其不應為 'async void'
-- 其不應為特殊方法 (完成項、運算子...)。
-
-
-
- AssemblyInitialize method '{0}' can't be declared on a generic class
- AssemblyInitialize 方法 '{0}' 不能在泛型類上宣告
-
-
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyInitialize 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
-
-
-
- AssemblyInitialize method '{0}' should not be generic
- AssemblyInitialize 方法 '{0}' 不應為泛型
-
-
-
- AssemblyInitialize method '{0}' should be an 'ordinary' method
- AssemblyInitialize 方法 '{0}' 應為 'ordinary' 方法
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 標示為 [AssemblyInitialize] 的方法應該遵循下列配置才能有效:
+- 為 'public'
+- 為 'static'
+- 非為泛型也不是在泛型類別上所定義
+- 接受型別為 'TestContext' 的單一參數
+- 傳回型別應為 'void'、'Task' 或 'ValueTask'
+- 非為 'async void'
+- 非為特殊方法 (完成項、運算子...)。
-
- AssemblyInitialize method '{0}' should be 'public'
- AssemblyInitialize 方法 '{0}' 應為 'public'
+
+ AssemblyInitialize method '{0}' signature is invalid
+ AssemblyInitialize 方法 '{0}' 簽章無效
-
- AssemblyInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- AssemblyInitialize 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
+
+ AssemblyInitialize methods should have valid layout
+ AssemblyInitialize 方法應該具有有效的配置
-
- AssemblyInitialize method '{0}' should take a single parameter of type 'TestContext'
- AssemblyInitialize 方法 '{0}' 應該接受類型 'TestContext' 的單一參數
+
+ Prefer adding an additional assertion that checks for null
+ 偏好新增檢查 Null 的其他判斷提示
-
- AssemblyInitialize method '{0}' should be 'static'
- AssemblyInitialize 方法 '{0}' 應為 'static'
-
-
-
- AssemblyInitialize methods should have valid layout
- AssemblyInitialize 方法應該具有有效的配置
+
+ Avoid conditional access in assertions
+ 避免判斷提示中的條件式存取
@@ -162,61 +102,26 @@
Methods marked with [ClassCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not 'static'
-- it should not be generic
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 標示為 [ClassCleanup] 的方法應該遵循下列配置才能有效:
-- 其應為 'public'
-- 其不應為 'static'
-- 其不應為泛型
-- 其不應接受任何參數
-- 傳回類型應為 'void'、'Task' 或 'ValueTask'
-- 其不應為 'async void'
-- 其不應為特殊方法 (完成項、運算子...)。
-
-
-
- ClassCleanup method '{0}' should not take any parameter
- ClassCleanup 方法 '{0}' 不應該接受任何參數
-
-
-
- ClassCleanup method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- 未設定 `InheritanceBehavior` 模式,則 ClassCleanup 方法 '{0}' 不能在泛型類別上宣告
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassCleanup 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
-
-
-
- ClassCleanup method '{0}' should not be generic
- ClassCleanup 方法 '{0}' 不應為泛型
-
-
-
- ClassCleanup method '{0}' should be an 'ordinary' method
- ClassCleanup 方法 '{0}' 應為 'ordinary' 方法
-
-
-
- ClassCleanup method '{0}' should be 'public'
- ClassCleanup 方法 '{0}' 應為 'public'
-
-
-
- ClassCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassCleanup 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 標示為 [ClassCleanup] 的方法應該遵循下列配置才能有效:
+- 為 'public'
+- 非為 'static'
+- 非為泛型,也不是在泛型類別上所定義
+- 不接受任何參數
+- 傳回型別應為 'void'、'Task' 或 'ValueTask'
+- 非為 'async void'
+- 非為特殊方法 (完成項、運算子...)。
-
- ClassCleanup method '{0}' should be 'static'
- ClassCleanup 方法 '{0}' 應為 'static'
+
+ ClassCleanup method '{0}' signature is invalid
+ ClassCleanup 方法 '{0}' 簽章無效
@@ -226,61 +131,26 @@
Methods marked with [ClassInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should be 'static'
-- it should not be generic
-- it should take one parameter of type 'TestContext'
+- be 'public'
+- be 'static'
+- not be generic nor be defined on a generic class
+- take a single parameter of type 'TestContext'
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 標示為 [ClassInitialize] 的方法應該遵循下列配置才能有效:
-- 其應為 'public'
-- 其應為 'static'
-- 其不應為泛型
-- 其應該接受類型為 'TestContext' 的一個參數
-- 傳回類型應為 'void'、'Task' 或 'ValueTask'
-- 其不應為 'async void'
-- 其不應為特殊方法 (完成項、運算子...)。
-
-
-
- ClassInitialize method '{0}' can't be declared on a generic class without the `InheritanceBehavior` mode is set
- 未設定 `InheritanceBehavior` 模式,則 ClassInitialize 方法 '{0}' 不能在泛型類別上宣告
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassInitialize 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
-
-
-
- ClassInitialize method '{0}' should not be generic
- ClassInitialize 方法 '{0}' 不應為泛型
-
-
-
- ClassInitialize method '{0}' should be an 'ordinary' method
- ClassInitialize 方法 '{0}' 應為 'ordinary' 方法
-
-
-
- ClassInitialize method '{0}' should be 'public'
- ClassInitialize 方法 '{0}' 應為 'public'
-
-
-
- ClassInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- ClassInitialize 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
-
-
-
- ClassInitialize method '{0}' should take a single parameter of type 'TestContext'
- ClassInitialize 方法 '{0}' 應該接受類型 'TestContext' 的單一參數
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 標示為 [ClassInitialize] 的方法應該遵循下列配置才能有效:
+- 為 'public'
+- 為 'static'
+- 非為泛型也不是在泛型類別上所定義
+- 接受型別為 'TestContext' 的單一參數
+- 傳回型別應為 'void'、'Task' 或 'ValueTask'
+- 非為 'async void'
+- 非為特殊方法 (完成項、運算子...)。
-
- ClassInitialize method '{0}' should be 'static'
- ClassInitialize 方法 '{0}' 應為 'static'
+
+ ClassInitialize method '{0}' signature is invalid
+ ClassInitialize 方法 '{0}' 簽章無效
@@ -339,6 +209,21 @@
請勿將 TestContext 儲存在靜態成員中
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+ 'System.ComponentModel.DescriptionAttribute' has no effect in the context of tests and you likely wanted to use 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute' instead.
+
+
+
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+ Did you mean to be using 'Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute'?
+
+
+
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+ 'System.ComponentModel.DescriptionAttribute' has no effect on test methods
+
+ Use 'Assert.Fail' instead of an always-failing 'Assert.{0}' assert使用 'Assert.Fail',而不是一直失敗的 'Assert.{0}' 聲明
@@ -349,6 +234,16 @@
使用 'Assert.Fail',而不是一直失敗的聲明
+
+ Review or remove the assertion as its condition is known to be always true
+ Review or remove the assertion as its condition is known to be always true
+
+
+
+ Assertion condition is always true
+ Assertion condition is always true
+
+ Prefer constructors over TestInitialize methods偏好建構函式勝於 TestInitialize 方法
@@ -389,6 +284,21 @@
偏好 TestInitialize 方法勝於建構函式
+
+ Public methods should be test methods (marked with `[TestMethod]`).
+ Public methods should be test methods (marked with `[TestMethod]`).
+
+
+
+ Public method '{0}' should be a test method
+ Public method '{0}' should be a test method
+
+
+
+ Public methods should be test methods
+ Public methods should be test methods
+
+ It's considered a good practice to have only test classes marked public in a test project.在測試專案中僅將測試類別標記為公開被認為是一種很好的做法。
@@ -452,63 +362,28 @@
Methods marked with [TestCleanup] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic or be defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 標示為 [TestCleanup] 的方法應該遵循下列配置才能有效:
-- 其應為 'public'
-- 其不應為 'static'
-- 其不應為泛型
-- 其不應為 'abstract'
-- 其不應接受任何參數
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 標示為 [TestCleanup] 的方法應該遵循下列配置才能有效:
+- 為 'public'
+- 非為 'static'
+- 非為泛型或不是在泛型類別上所定義
+- 非為 'abstract'
+- 不接受任何參數
- 傳回型別應為 'void'、'Task' 或 'ValueTask'
-- 其不應為 'async void'
-- 其不應為特殊方法 (完成項、運算子...)。
+- 非為 'async void'
+- 非為特殊方法 (完成項、運算子...)。
-
- TestCleanup method '{0}' should not take any parameter
- TestCleanup 方法 '{0}' 不應該接受任何參數
-
-
-
- TestCleanup method '{0}' should not be 'abstract'
- TestCleanup 方法 '{0}' 不應為 'abstract'
-
-
-
- TestCleanup method '{0}' should not be 'async void'
- TestCleanup 方法 '{0}' 不應為 'async void'
-
-
-
- TestCleanup method '{0}' should not be generic
- TestCleanup 方法 '{0}' 不應為泛型
-
-
-
- TestCleanup method '{0}' should not be 'static'
- TestCleanup 方法 '{0}' 不應為 'static'
-
-
-
- TestCleanup method '{0}' should be an 'ordinary' method
- TestCleanup 方法 '{0}' 應為 'ordinary' 方法
-
-
-
- TestCleanup method '{0}' should be 'public'
- TestCleanup 方法 '{0}' 應為 'public'
-
-
-
- TestCleanup method '{0}' should return 'void', 'Task' or 'ValueTask'
- TestCleanup 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
+
+ TestCleanup method '{0}' signature is invalid
+ TestCleanup 方法 '{0}' 簽章無效
@@ -561,63 +436,28 @@
Methods marked with [TestInitialize] should follow the following layout to be valid:
-- it should be 'public'
-- it should not be 'static'
-- it should not be generic
-- it should not be 'abstract'
-- it should not take any parameter
+- be 'public'
+- not be 'static'
+- not be generic nor defined on a generic class
+- not be 'abstract'
+- not take any parameter
- return type should be 'void', 'Task' or 'ValueTask'
-- it should not be 'async void'
-- it should not be a special method (finalizer, operator...).
- 標示為 [TestInitialize] 的方法應該遵循下列配置才能有效:
-- 其應為 'public'
-- 其不應為 'static'
-- 其不應為泛型
-- 其不應為 'abstract'
-- 其不應接受任何參數
+- not be 'async void'
+- not be a special method (finalizer, operator...).
+ 標示為 [TestInitialize] 的方法應該遵循下列配置才能有效:
+- 為 'public'
+- 非為 'static'
+- 非為泛型,也不是在泛型類別上所定義
+- 非為 'abstract'
+- 不接受任何參數
- 傳回型別應為 'void'、'Task' 或 'ValueTask'
-- 其不應為 'async void'
-- 其不應為特殊方法 (完成項、運算子...)。
-
-
-
- TestInitialize method '{0}' should not take any parameter
- TestInitialize 方法 '{0}' 不應使用任何參數
-
-
-
- TestInitialize method '{0}' should not be 'abstract'
- TestInitialize 方法 '{0}' 不應為 'abstract'
-
-
-
- TestInitialize method '{0}' should not be 'async void'
- TestInitialize 方法 '{0}' 不應為 'async void'
-
-
-
- TestInitialize method '{0}' should not be generic
- TestInitialize 方法 '{0}' 不應為泛型
-
-
-
- TestInitialize method '{0}' should not be 'static'
- TestInitialize 方法 '{0}' 不應為 'static'
-
-
-
- TestInitialize method '{0}' should be an 'ordinary' method
- TestInitialize 方法 '{0}' 應為 'ordinary' 方法
+- 非為 'async void'
+- 非為特殊方法 (完成項、運算子...)。
-
- TestInitialize method '{0}' should be 'public'
- TestInitialize 方法 '{0}' 不應為 'public'
-
-
-
- TestInitialize method '{0}' should return 'void', 'Task' or 'ValueTask'
- TestInitialize 方法 '{0}' 應傳回 'void'、'Task' 或 'ValueTask'
+
+ TestInitialize method '{0}' signature is invalid
+ TestInitialize 方法 '{0}' 簽章無效
@@ -704,6 +544,31 @@
不應略過測試方法
+
+ Type contaning '[TestMethod]' should be marked with '[TestClass]', otherwise the test method will be silently ignored.
+ Type contaning '[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]'
+ Class '{0}' contains test methods and should be marked with '[TestClass]'
+
+
+
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+ Type containing '[TestMethod]' should be marked with '[TestClass]'
+
+
+
+ Asynchronous test fixture methods do not require the 'Async' suffix
+ 非同步測試固件方法不需要 'Async' 尾碼
+
+
+
+ Asynchronous test methods do not require the 'Async' suffix
+ 非同步測試方法不需要 'Async' 尾碼
+
+ [{0}] can only be set on methods marked with [TestMethod][{0}] 只能在標示為 [TestMethod] 的方法上設定
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 59fd384fa2..848f42e441 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -5,4 +5,5 @@
enable
+
diff --git a/src/Package/MSTest.Sdk/MSTest.Sdk.csproj b/src/Package/MSTest.Sdk/MSTest.Sdk.csproj
index 4e2ecf5e53..9df47c1e9a 100644
--- a/src/Package/MSTest.Sdk/MSTest.Sdk.csproj
+++ b/src/Package/MSTest.Sdk/MSTest.Sdk.csproj
@@ -35,7 +35,7 @@
- <_TemplateProperties>MSTestEngineVersion=$(MSTestEngineVersion);MSTestVersion=$(Version);MicrosoftTestingPlatformVersion=$(MicrosoftTestingPlatformVersion);MicrosoftNETTestSdkVersion=$(MicrosoftNETTestSdkVersion);MicrosoftTestingExtensionsCodeCoverageVersion=$(MicrosoftTestingExtensionsCodeCoverageVersion);MicrosoftPlaywrightVersion=$(MicrosoftPlaywrightVersion);AspireHostingTestingVersion=$(AspireHostingTestingVersion)
+ <_TemplateProperties>MSTestEngineVersion=$(MSTestEngineVersion);MSTestVersion=$(Version);MicrosoftTestingPlatformVersion=$(Version.Replace('$(VersionPrefix)', '$(TestingPlatformVersionPrefix)'));MicrosoftTestingEntrepriseExtensionsVersion=$(MicrosoftTestingInternalFrameworkVersion);MicrosoftNETTestSdkVersion=$(MicrosoftNETTestSdkVersion);MicrosoftTestingExtensionsCodeCoverageVersion=$(MicrosoftTestingExtensionsCodeCoverageVersion);MicrosoftPlaywrightVersion=$(MicrosoftPlaywrightVersion);AspireHostingTestingVersion=$(AspireHostingTestingVersion)
true
- $(MicrosoftTestingExtensionsCommonVersion)
+ $(MicrosoftTestingEntrepriseExtensionsVersion)true
- $(MicrosoftTestingExtensionsCommonVersion)
+ $(MicrosoftTestingEntrepriseExtensionsVersion)true
@@ -28,20 +28,29 @@
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/src/Package/MSTest.Sdk/Sdk/Runner/NativeAOT.targets b/src/Package/MSTest.Sdk/Sdk/Runner/NativeAOT.targets
index a765c99fdc..5f9fe83b83 100644
--- a/src/Package/MSTest.Sdk/Sdk/Runner/NativeAOT.targets
+++ b/src/Package/MSTest.Sdk/Sdk/Runner/NativeAOT.targets
@@ -8,23 +8,23 @@
-
+
-
-
-
-
+
+
+
+
-
-
+
+
-
+
diff --git a/src/Package/MSTest.Sdk/Sdk/Sdk.props.template b/src/Package/MSTest.Sdk/Sdk/Sdk.props.template
index 4506356bd1..d5a76d1f15 100644
--- a/src/Package/MSTest.Sdk/Sdk/Sdk.props.template
+++ b/src/Package/MSTest.Sdk/Sdk/Sdk.props.template
@@ -5,7 +5,7 @@
- false
+ falsefalsefalse
@@ -16,6 +16,7 @@
${MicrosoftPlaywrightVersion}${MicrosoftTestingExtensionsCodeCoverageVersion}${MicrosoftTestingPlatformVersion}
+ ${MicrosoftTestingEntrepriseExtensionsVersion}
diff --git a/src/Package/MSTest.Sdk/Sdk/VSTest/VSTest.targets b/src/Package/MSTest.Sdk/Sdk/VSTest/VSTest.targets
index fbec4b4afa..63cd0fb644 100644
--- a/src/Package/MSTest.Sdk/Sdk/VSTest/VSTest.targets
+++ b/src/Package/MSTest.Sdk/Sdk/VSTest/VSTest.targets
@@ -2,10 +2,10 @@
-
-
-
-
+
+
+
+
+ $(TestingPlatformVersionPrefix)
+
+
+
+
+ true
+ true
+ true
+
+
+
+
+ Microsoft test testing unittest unittesting unit-testing tdd
+
+
+
diff --git a/src/Platform/Directory.Build.targets b/src/Platform/Directory.Build.targets
new file mode 100644
index 0000000000..d7a29489b3
--- /dev/null
+++ b/src/Platform/Directory.Build.targets
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ $(CommonPackageTags)
+ PACKAGE.md
+
+
+
+
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt
new file mode 100644
index 0000000000..ea8617fcb0
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt
@@ -0,0 +1,10 @@
+T:System.ArgumentNullException; Use 'ArgumentGuard' instead
+P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.UtcNow; Use 'IClock' instead
+M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
+M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
+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,System.String); Use 'RoslynDebug.Assert' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpCommandLineOptions.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpCommandLineOptions.cs
new file mode 100644
index 0000000000..cb003f5027
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpCommandLineOptions.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#if USE_TRX_NAMESPACE
+namespace Microsoft.Testing.Extensions.TrxReport;
+#else
+namespace Microsoft.Testing.Extensions.Diagnostics;
+#endif
+
+internal static class CrashDumpCommandLineOptions
+{
+ public const string CrashDumpOptionName = "crashdump";
+ public const string CrashDumpFileNameOptionName = "crashdump-filename";
+ public const string CrashDumpTypeOptionName = "crashdump-type";
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpCommandLineProvider.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpCommandLineProvider.cs
new file mode 100644
index 0000000000..7bed8e2ec8
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpCommandLineProvider.cs
@@ -0,0 +1,51 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.Diagnostics.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.CommandLine;
+using Microsoft.Testing.Platform.Helpers;
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal sealed class CrashDumpCommandLineProvider : ICommandLineOptionsProvider
+{
+ private static readonly string[] DumpTypeOptions = ["Mini", "Heap", "Triage", "Full"];
+
+ public string Uid => nameof(CrashDumpCommandLineProvider);
+
+ public string Version => AppVersion.DefaultSemVer;
+
+ public string DisplayName => CrashDumpResources.CrashDumpDisplayName;
+
+ public string Description => CrashDumpResources.CrashDumpDescription;
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public IReadOnlyCollection GetCommandLineOptions()
+ =>
+ [
+ new CommandLineOption(CrashDumpCommandLineOptions.CrashDumpOptionName, CrashDumpResources.CrashDumpOptionDescription, ArgumentArity.Zero, false),
+ new CommandLineOption(CrashDumpCommandLineOptions.CrashDumpFileNameOptionName, CrashDumpResources.CrashDumpFileNameOptionDescription, ArgumentArity.ExactlyOne, false),
+ new CommandLineOption(CrashDumpCommandLineOptions.CrashDumpTypeOptionName, CrashDumpResources.CrashDumpTypeOptionDescription, ArgumentArity.ExactlyOne, false)
+ ];
+
+ public Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
+ {
+ if (commandOption.Name == CrashDumpCommandLineOptions.CrashDumpTypeOptionName)
+ {
+ if (!DumpTypeOptions.Contains(arguments[0], StringComparer.OrdinalIgnoreCase))
+ {
+ return ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, CrashDumpResources.CrashDumpTypeOptionInvalidType, arguments[0]));
+ }
+ }
+
+ return ValidationResult.ValidTask;
+ }
+
+ public Task ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
+ => ValidationResult.ValidTask;
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpConfiguration.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpConfiguration.cs
new file mode 100644
index 0000000000..b2d64c75d5
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpConfiguration.cs
@@ -0,0 +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.
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal sealed class CrashDumpConfiguration
+{
+ public string? DumpFileNamePattern { get; set; }
+
+ public bool Enable { get; set; } = true;
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpEnvironmentVariableProvider.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpEnvironmentVariableProvider.cs
new file mode 100644
index 0000000000..3826dacf6b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpEnvironmentVariableProvider.cs
@@ -0,0 +1,214 @@
+// 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;
+
+using Microsoft.Testing.Extensions.Diagnostics.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.TestHostControllers;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.Messages;
+using Microsoft.Testing.Platform.Services;
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal sealed class CrashDumpEnvironmentVariableProvider : ITestHostEnvironmentVariableProvider
+{
+ private const string EnableMiniDumpVariable = "DbgEnableMiniDump";
+ private const string MiniDumpTypeVariable = "DbgMiniDumpType";
+ private const string MiniDumpNameVariable = "DbgMiniDumpName";
+ private const string CreateDumpDiagnosticsVariable = "CreateDumpDiagnostics";
+ private const string CreateDumpVerboseDiagnosticsVariable = "CreateDumpVerboseDiagnostics";
+ private const string EnableMiniDumpValue = "1";
+
+ private readonly string[] _prefixes = ["DOTNET_", "COMPlus_"];
+ private readonly IConfiguration _configuration;
+ private readonly IMessageBus _messageBus;
+ private readonly ICommandLineOptions _commandLineOptions;
+ private readonly ITestApplicationModuleInfo _testApplicationModuleInfo;
+ private readonly CrashDumpConfiguration _crashDumpGeneratorConfiguration;
+ private readonly ILogger _logger;
+
+ private string? _miniDumpNameValue;
+
+ public CrashDumpEnvironmentVariableProvider(
+ IConfiguration configuration,
+ IMessageBus messageBus,
+ ICommandLineOptions commandLineOptions,
+ ITestApplicationModuleInfo testApplicationModuleInfo,
+ CrashDumpConfiguration crashDumpGeneratorConfiguration,
+ ILoggerFactory loggerFactory)
+ {
+ _logger = loggerFactory.CreateLogger();
+ _configuration = configuration;
+ _messageBus = messageBus;
+ _commandLineOptions = commandLineOptions;
+ _testApplicationModuleInfo = testApplicationModuleInfo;
+ _crashDumpGeneratorConfiguration = crashDumpGeneratorConfiguration;
+ }
+
+ ///
+ public string Uid => nameof(CrashDumpEnvironmentVariableProvider);
+
+ ///
+ public string Version => AppVersion.DefaultSemVer;
+
+ ///
+ public string DisplayName => CrashDumpResources.CrashDumpDisplayName;
+
+ ///
+ public string Description => CrashDumpResources.CrashDumpDescription;
+
+ ///
+ public Task IsEnabledAsync()
+ => Task.FromResult(_commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName) && _crashDumpGeneratorConfiguration.Enable);
+
+ public Task UpdateAsync(IEnvironmentVariables environmentVariables)
+ {
+ foreach (string prefix in _prefixes)
+ {
+ environmentVariables.SetVariable(new($"{prefix}{EnableMiniDumpVariable}", EnableMiniDumpValue, false, true));
+ environmentVariables.SetVariable(new($"{prefix}{CreateDumpDiagnosticsVariable}", EnableMiniDumpValue, false, true));
+ environmentVariables.SetVariable(new($"{prefix}{CreateDumpVerboseDiagnosticsVariable}", EnableMiniDumpValue, false, true));
+ }
+
+ string miniDumpTypeValue = "4";
+
+ if (_commandLineOptions.TryGetOptionArgumentList(CrashDumpCommandLineOptions.CrashDumpTypeOptionName, out string[]? dumpTypeString))
+ {
+ switch (dumpTypeString[0].ToLowerInvariant().Trim())
+ {
+ case "mini":
+ {
+ miniDumpTypeValue = "1";
+ break;
+ }
+
+ case "heap":
+ {
+ miniDumpTypeValue = "2";
+ break;
+ }
+
+ case "triage":
+ {
+ miniDumpTypeValue = "3";
+ break;
+ }
+
+ case "full":
+ {
+ miniDumpTypeValue = "4";
+ break;
+ }
+
+ default:
+ {
+ miniDumpTypeValue = dumpTypeString[0];
+ break;
+ }
+ }
+ }
+
+ foreach (string prefix in _prefixes)
+ {
+ environmentVariables.SetVariable(new($"{prefix}{MiniDumpTypeVariable}", miniDumpTypeValue, false, true));
+ }
+
+ _miniDumpNameValue = _commandLineOptions.TryGetOptionArgumentList(CrashDumpCommandLineOptions.CrashDumpFileNameOptionName, out string[]? dumpFileName)
+ ? Path.Combine(_configuration.GetTestResultDirectory(), dumpFileName[0])
+ : Path.Combine(_configuration.GetTestResultDirectory(), $"{Path.GetFileName(_testApplicationModuleInfo.GetCurrentTestApplicationFullPath())}_%p_crash.dmp");
+ _crashDumpGeneratorConfiguration.DumpFileNamePattern = _miniDumpNameValue;
+ foreach (string prefix in _prefixes)
+ {
+ environmentVariables.SetVariable(new($"{prefix}{MiniDumpNameVariable}", _miniDumpNameValue, false, true));
+ }
+
+ if (_logger.IsEnabled(LogLevel.Trace))
+ {
+ _logger.LogTrace($"{MiniDumpNameVariable}: {_miniDumpNameValue}");
+ _logger.LogTrace($"{MiniDumpTypeVariable}: {miniDumpTypeValue}");
+ }
+
+ return Task.CompletedTask;
+ }
+
+ public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnlyEnvironmentVariables environmentVariables)
+ {
+ StringBuilder errors = new();
+
+#if !NETCOREAPP
+ return ValidationResult.InvalidTask(CrashDumpResources.CrashDumpNotSupportedInNonNetCoreErrorMessage);
+#else
+ foreach (string prefix in _prefixes)
+ {
+ if (!environmentVariables.TryGetVariable($"{prefix}{EnableMiniDumpVariable}", out OwnedEnvironmentVariable? enableMiniDump)
+ || enableMiniDump.Value != EnableMiniDumpValue)
+ {
+ AddError(errors, $"{prefix}{EnableMiniDumpVariable}", EnableMiniDumpValue, enableMiniDump?.Value);
+ }
+ }
+
+ foreach (string prefix in _prefixes)
+ {
+ if (!environmentVariables.TryGetVariable($"{prefix}{CreateDumpDiagnosticsVariable}", out OwnedEnvironmentVariable? enableMiniDump)
+ || enableMiniDump.Value != EnableMiniDumpValue)
+ {
+ AddError(errors, $"{prefix}{CreateDumpDiagnosticsVariable}", EnableMiniDumpValue, enableMiniDump?.Value);
+ }
+ }
+
+ foreach (string prefix in _prefixes)
+ {
+ if (!environmentVariables.TryGetVariable($"{prefix}{CreateDumpVerboseDiagnosticsVariable}", out OwnedEnvironmentVariable? enableMiniDump)
+ || enableMiniDump.Value != EnableMiniDumpValue)
+ {
+ AddError(errors, $"{prefix}{CreateDumpVerboseDiagnosticsVariable}", EnableMiniDumpValue, enableMiniDump?.Value);
+ }
+ }
+
+ foreach (string prefix in _prefixes)
+ {
+ if (!environmentVariables.TryGetVariable($"{prefix}{MiniDumpTypeVariable}", out OwnedEnvironmentVariable? miniDumpType))
+ {
+ AddError(errors, $"{prefix}{MiniDumpTypeVariable}", "Valid values are 1, 2, 3, 4", miniDumpType?.Value);
+ }
+ else
+ {
+ if (miniDumpType is null || miniDumpType.Value is null)
+ {
+ throw new InvalidOperationException("Unexpected missing MiniDumpTypeVariable variable");
+ }
+
+ if (!miniDumpType.Value.Equals("1", StringComparison.OrdinalIgnoreCase) &&
+ !miniDumpType.Value.Equals("2", StringComparison.OrdinalIgnoreCase) &&
+ !miniDumpType.Value.Equals("3", StringComparison.OrdinalIgnoreCase) &&
+ !miniDumpType.Value.Equals("4", StringComparison.OrdinalIgnoreCase))
+ {
+ AddError(errors, $"{prefix}{MiniDumpTypeVariable}", "Valid values are 1, 2, 3, 4", miniDumpType.Value);
+ }
+ }
+ }
+
+ foreach (string prefix in _prefixes)
+ {
+ if (!environmentVariables.TryGetVariable($"{prefix}{MiniDumpNameVariable}", out OwnedEnvironmentVariable? miniDumpName)
+ || miniDumpName.Value != _miniDumpNameValue)
+ {
+ AddError(errors, $"{prefix}{MiniDumpNameVariable}", _miniDumpNameValue, miniDumpName?.Value);
+ }
+ }
+
+ return Task.FromResult(errors.Length > 0 ? ValidationResult.Invalid(errors.ToString()) : ValidationResult.Valid());
+
+ static void AddError(StringBuilder errors, string variableName, string? expectedValue, string? actualValue)
+ {
+ string actualValueString = actualValue ?? "";
+ errors.AppendLine(string.Format(System.Globalization.CultureInfo.InvariantCulture, CrashDumpResources.CrashDumpInvalidEnvironmentVariableValueErrorMessage, variableName, expectedValue, actualValueString));
+ }
+#endif
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpExtensions.cs
new file mode 100644
index 0000000000..2a5cc2f338
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpExtensions.cs
@@ -0,0 +1,41 @@
+// 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.Diagnostics;
+using Microsoft.Testing.Platform.Builder;
+using Microsoft.Testing.Platform.Services;
+
+namespace Microsoft.Testing.Extensions;
+
+public static class CrashDumpExtensions
+{
+ public static void AddCrashDumpProvider(this ITestApplicationBuilder builder, bool ignoreIfNotSupported = false)
+ {
+ CrashDumpConfiguration crashDumpGeneratorConfiguration = new();
+
+ if (ignoreIfNotSupported)
+ {
+#if !NETCOREAPP
+ crashDumpGeneratorConfiguration.Enable = false;
+#endif
+ }
+
+ builder.TestHostControllers.AddEnvironmentVariableProvider(serviceProvider
+ => new CrashDumpEnvironmentVariableProvider(
+ serviceProvider.GetConfiguration(),
+ serviceProvider.GetMessageBus(),
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetTestApplicationModuleInfo(),
+ crashDumpGeneratorConfiguration,
+ serviceProvider.GetLoggerFactory()));
+
+ builder.TestHostControllers.AddProcessLifetimeHandler(serviceProvider
+ => new CrashDumpProcessLifetimeHandler(
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetMessageBus(),
+ serviceProvider.GetOutputDevice(),
+ crashDumpGeneratorConfiguration));
+
+ builder.CommandLine.AddProvider(() => new CrashDumpCommandLineProvider());
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpProcessLifetimeHandler.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpProcessLifetimeHandler.cs
new file mode 100644
index 0000000000..9fdcbf8e24
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpProcessLifetimeHandler.cs
@@ -0,0 +1,84 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.Diagnostics.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Extensions.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestHostControllers;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.Messages;
+using Microsoft.Testing.Platform.OutputDevice;
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal sealed class CrashDumpProcessLifetimeHandler : ITestHostProcessLifetimeHandler, IDataProducer, IOutputDeviceDataProducer
+{
+ private readonly ICommandLineOptions _commandLineOptions;
+ private readonly IMessageBus _messageBus;
+ private readonly IOutputDevice _outputDisplay;
+ private readonly CrashDumpConfiguration _netCoreCrashDumpGeneratorConfiguration;
+
+ public CrashDumpProcessLifetimeHandler(
+ ICommandLineOptions commandLineOptions,
+ IMessageBus messageBus,
+ IOutputDevice outputDisplay,
+ CrashDumpConfiguration netCoreCrashDumpGeneratorConfiguration)
+ {
+ _commandLineOptions = commandLineOptions;
+ _messageBus = messageBus;
+ _outputDisplay = outputDisplay;
+ _netCoreCrashDumpGeneratorConfiguration = netCoreCrashDumpGeneratorConfiguration;
+ }
+
+ ///
+ public string Uid => nameof(CrashDumpProcessLifetimeHandler);
+
+ ///
+ public string Version => AppVersion.DefaultSemVer;
+
+ ///
+ public string DisplayName => CrashDumpResources.CrashDumpDisplayName;
+
+ ///
+ public string Description => CrashDumpResources.CrashDumpDescription;
+
+ public Type[] DataTypesProduced => [typeof(FileArtifact)];
+
+ public Task IsEnabledAsync()
+ => Task.FromResult(_commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName)
+ && _netCoreCrashDumpGeneratorConfiguration.Enable);
+
+ public Task BeforeTestHostProcessStartAsync(CancellationToken _) => Task.CompletedTask;
+
+ public Task OnTestHostProcessStartedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation) => Task.CompletedTask;
+
+ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation)
+ {
+ if (cancellation.IsCancellationRequested
+ || testHostProcessInformation.HasExitedGracefully
+ || (AppDomain.CurrentDomain.GetData("ProcessKilledByHangDump") is string processKilledByHangDump && processKilledByHangDump == "true"))
+ {
+ return;
+ }
+
+ ApplicationStateGuard.Ensure(_netCoreCrashDumpGeneratorConfiguration.DumpFileNamePattern is not null);
+ await _outputDisplay.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(string.Format(CultureInfo.InvariantCulture, CrashDumpResources.CrashDumpProcessCrashedDumpFileCreated, testHostProcessInformation.PID)));
+
+ 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));
+ }
+ else
+ {
+ await _outputDisplay.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(string.Format(CultureInfo.InvariantCulture, CrashDumpResources.CannotFindExpectedCrashDumpFile, expectedDumpFile)));
+ foreach (string dumpFile in Directory.GetFiles(Path.GetDirectoryName(expectedDumpFile)!, "*.dmp"))
+ {
+ await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(dumpFile), CrashDumpResources.CrashDumpDisplayName, CrashDumpResources.CrashDumpArtifactDescription));
+ }
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Microsoft.Testing.Extensions.CrashDump.csproj b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Microsoft.Testing.Extensions.CrashDump.csproj
new file mode 100644
index 0000000000..9ab987f07a
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Microsoft.Testing.Extensions.CrashDump.csproj
@@ -0,0 +1,65 @@
+
+
+
+ netstandard2.0;$(MicrosoftTestingTargetFrameworks)
+ Microsoft.Testing.Extensions.Diagnostics
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ buildMultiTargeting
+
+
+ buildTransitive/$(TargetFramework)
+
+
+ build/$(TargetFramework)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ CrashDumpResources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ CrashDumpResources.Designer.cs
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/PACKAGE.md b/src/Platform/Microsoft.Testing.Extensions.CrashDump/PACKAGE.md
new file mode 100644
index 0000000000..88c8efbf23
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/PACKAGE.md
@@ -0,0 +1,9 @@
+# Microsoft.Testing
+
+Microsoft Testing is a set of platform, framework and protocol intended to make it possible to run any test on any target or device.
+
+Documentation can be found at .
+
+## About
+
+This package extends Microsoft Testing Platform to provide a crash dump functionality.
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/PublicAPI/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.CrashDump/PublicAPI/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..4dccf2ae97
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/PublicAPI/PublicAPI.Shipped.txt
@@ -0,0 +1,5 @@
+#nullable enable
+Microsoft.Testing.Extensions.CrashDump.TestingPlatformBuilderHook
+Microsoft.Testing.Extensions.CrashDumpExtensions
+static Microsoft.Testing.Extensions.CrashDump.TestingPlatformBuilderHook.AddExtensions(Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! testApplicationBuilder, string![]! _) -> void
+static Microsoft.Testing.Extensions.CrashDumpExtensions.AddCrashDumpProvider(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder, bool ignoreIfNotSupported = false) -> void
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/PublicAPI/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.CrashDump/PublicAPI/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..7dc5c58110
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/PublicAPI/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/CrashDumpResources.Designer.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/CrashDumpResources.Designer.cs
new file mode 100644
index 0000000000..c316012e7d
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/CrashDumpResources.Designer.cs
@@ -0,0 +1,189 @@
+//------------------------------------------------------------------------------
+//
+// 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.Testing.Extensions.Diagnostics.Resources {
+ 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 CrashDumpResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal CrashDumpResources() {
+ }
+
+ ///
+ /// 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.Testing.Extensions.Diagnostics.Resources.CrashDumpResources", typeof(CrashDumpResources).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 Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder.
+ ///
+ internal static string CannotFindExpectedCrashDumpFile {
+ get {
+ return ResourceManager.GetString("CannotFindExpectedCrashDumpFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The testhost process crash dump file.
+ ///
+ internal static string CrashDumpArtifactDescription {
+ get {
+ return ResourceManager.GetString("CrashDumpArtifactDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Crash dump file.
+ ///
+ internal static string CrashDumpArtifactDisplayName {
+ get {
+ return ResourceManager.GetString("CrashDumpArtifactDisplayName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly.
+ ///
+ internal static string CrashDumpDescription {
+ get {
+ return ResourceManager.GetString("CrashDumpDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Crash dump.
+ ///
+ internal static string CrashDumpDisplayName {
+ get {
+ return ResourceManager.GetString("CrashDumpDisplayName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specify the name of the dump file.
+ ///
+ internal static string CrashDumpFileNameOptionDescription {
+ get {
+ return ResourceManager.GetString("CrashDumpFileNameOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Environment variable '{0}' should have been set to '{1}' but value is '{2}'.
+ ///
+ internal static string CrashDumpInvalidEnvironmentVariableValueErrorMessage {
+ get {
+ return ResourceManager.GetString("CrashDumpInvalidEnvironmentVariableValueErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Crash dump feature is only available in .NET (Core).
+ ///
+ internal static string CrashDumpNotSupportedInNonNetCoreErrorMessage {
+ get {
+ return ResourceManager.GetString("CrashDumpNotSupportedInNonNetCoreErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to [net6.0+ only] Generate a dump file if the test process crashes.
+ ///
+ internal static string CrashDumpOptionDescription {
+ get {
+ return ResourceManager.GetString("CrashDumpOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Test host process with PID '{0}' crashed, a dump file was generated.
+ ///
+ internal static string CrashDumpProcessCrashedDumpFileCreated {
+ get {
+ return ResourceManager.GetString("CrashDumpProcessCrashedDumpFileCreated", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps.
+ ///
+ internal static string CrashDumpTypeOptionDescription {
+ get {
+ return ResourceManager.GetString("CrashDumpTypeOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'.
+ ///
+ internal static string CrashDumpTypeOptionInvalidType {
+ get {
+ return ResourceManager.GetString("CrashDumpTypeOptionInvalidType", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap').
+ ///
+ internal static string CrashDumpTypeOptionTooManyArguments {
+ get {
+ return ResourceManager.GetString("CrashDumpTypeOptionTooManyArguments", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Requests of type '{0}' is not supported.
+ ///
+ internal static string UnsupportedRequestTypeErrorMessage {
+ get {
+ return ResourceManager.GetString("UnsupportedRequestTypeErrorMessage", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/CrashDumpResources.resx b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/CrashDumpResources.resx
new file mode 100644
index 0000000000..c97e098e10
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/CrashDumpResources.resx
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+
+
+ The testhost process crash dump file
+
+
+ Crash dump file
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+
+
+ Crash dump
+
+
+ Specify the name of the dump file
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+
+
+ Crash dump feature is only available in .NET (Core)
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+
+
+ Requests of type '{0}' is not supported
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.cs.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.cs.xlf
new file mode 100644
index 0000000000..785df2fe2e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.cs.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ Nebyl nalezen očekávaný soubor výpisu stavu systému {0}. Všechny soubory odpovídající vzoru *.dmp budou zkopírovány do složky výsledků.
+
+
+
+ The testhost process crash dump file
+ Soubor výpisu stavu systému procesu testhost
+
+
+
+ Crash dump file
+ Soubor výpisu stavu systému
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [Pouze net6.0+ ] Vytvořit soubory výpisu stavu systému při neočekávaném chybovém ukončení procesu provádění testu
+
+
+
+ Crash dump
+ Výpis stavu systému
+
+
+
+ Specify the name of the dump file
+ Zadejte název souboru výpisu paměti.
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ Proměnná prostředí {0} by měla být nastavená na {1}, ale hodnota je {2}.
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ Funkce výpisu stavu systému je k dispozici pouze v rozhraní .NET (Core).
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [Pouze net6.0+ ] Vygenerovat soubor výpisu paměti v případě chybového ukončení procesu testu
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ Hostitelský proces testu s identifikátorem PID {0} byl chybově ukončen. Byl vygenerován soubor výpisu paměti.
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ Zadejte typ výpisu paměti. Platné hodnoty jsou Mini, Heap, Triage nebo Full. Výchozí typ je Full. Další informace najdete na https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ {0} není platný typ výpisu paměti. Platné možnosti jsou Mini, Heap, Triage a Full.
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ --hangdump-type očekává jako argument jeden typ výpisu paměti (například --hangdump-type Heap).
+
+
+
+ Requests of type '{0}' is not supported
+ Žádosti typu {0} nejsou podporovány.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.de.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.de.xlf
new file mode 100644
index 0000000000..acd0d66c37
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.de.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ Die erwartete Absturzabbilddatei "{0}" wurde nicht gefunden. Alle Dateien, die dem Muster "*.dmp" entsprechen, werden in den Ergebnisordner kopiert
+
+
+
+ The testhost process crash dump file
+ Die Absturzabbilddatei für den Testhostprozess
+
+
+
+ Crash dump file
+ Absturzabbilddatei
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [nur net6.0+] Erstellen von Absturzabbilddateien, wenn der Testausführungsprozess unerwartet abstürzt
+
+
+
+ Crash dump
+ Absturzspeicherabbild
+
+
+
+ Specify the name of the dump file
+ Namen der Speicherabbilddatei angeben
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ Die Umgebungsvariable "{0}" hätte auf "{1}" festgelegt werden sollen, aber der Wert ist "{2}"
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ Das Absturzabbildfeature ist nur in .NET (Core) verfügbar
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [nur net6.0+] Speicherabbilddatei generieren, wenn der Testprozess abstürzt
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ Der Testhostprozess mit PID "{0}" ist abgestürzt. Es wurde eine Abbilddatei generiert
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ Geben Sie den Typ des Speicherabbilds an. Gültige Werte sind „Mini“, „Heap“, „Triage“ oder „Full“. Der Standardtyp ist „Full“. Weitere Informationen finden Sie unter https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ "{0}" ist kein gültiger Speicherabbildtyp. Gültige Optionen sind "Mini", "Heap", "Triage" und "Full"
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ "--crashdump-type" erwartet einen einzelnen Speicherabbildtyp als Argument (z. B. "--crashdump-type Heap")
+
+
+
+ Requests of type '{0}' is not supported
+ Anforderungen vom Typ "{0}" werden nicht unterstützt
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.es.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.es.xlf
new file mode 100644
index 0000000000..df69ed55fb
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.es.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ No se encontró el '{0}' de archivo de volcado esperado. Todos los archivos que coincidan con el patrón "*.dmp" se copiarán en la carpeta de resultados.
+
+
+
+ The testhost process crash dump file
+ Archivo de volcado de memoria del proceso del host de pruebas
+
+
+
+ Crash dump file
+ Archivo de volcado de memoria
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [solo net6.0+ ] Generar archivos de volcado de memoria cuando el proceso de ejecución de pruebas se bloquea inesperadamente
+
+
+
+ Crash dump
+ Volcado de memoria
+
+
+
+ Specify the name of the dump file
+ Especificar el nombre del archivo de volcado
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ La variable de entorno '{0}' debe haberse establecido en '{1}' pero el valor es '{2}'
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ La característica de volcado de memoria solo está disponible en .NET (Core)
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [solo net6.0+ ] Generar un archivo de volcado si el proceso de prueba se bloquea
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ Se bloqueó el proceso de host de prueba con PID '{0}' y se generó un archivo de volcado
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ Especifique el tipo de volcado. Los valores válidos son "Mini", "Heap", "Evaluación de prioridades" o "Completo". El tipo predeterminado es 'Completo'. Para obtener más información, visite https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ '{0}' no es un tipo de volcado válido. Las opciones válidas son "Mini", "Montón", "Evaluación de prioridades" y "Completa"
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ '--crashdump-type' espera un único tipo de volcado como argumento (por ejemplo, '--crashdump-type Heap')
+
+
+
+ Requests of type '{0}' is not supported
+ No se admiten solicitudes de tipo '{0}'
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.fr.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.fr.xlf
new file mode 100644
index 0000000000..11cd3acf39
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.fr.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ Le fichier de vidage sur incident attendu « {0} » n'a pas été trouvé, tous les fichiers correspondant au modèle « *.dmp » seront copiés dans le dossier de résultats.
+
+
+
+ The testhost process crash dump file
+ Le fichier de vidage sur incident du processus testhost
+
+
+
+ Crash dump file
+ Fichier de vidage sur incident
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [net6.0+ uniquement] Produire des fichiers de vidage sur incident lorsque le processus d’exécution des tests se bloque de manière inattendue
+
+
+
+ Crash dump
+ Vidage sur incident
+
+
+
+ Specify the name of the dump file
+ Spécifier le nom du fichier de vidage
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ La variable d’environnement «{0}» doit avoir la valeur «{1}», mais la valeur est «{2}»
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ La fonctionnalité de vidage sur incident est disponible uniquement dans .NET (Core)
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [net6.0+ uniquement] Générer un fichier de vidage si le processus de test se bloque
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ Le processus hôte de test avec le PID «{0}» s’est arrêté, un fichier de vidage a été généré
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ Spécifiez le type de l’image mémoire. Les valeurs valides sont « Mini », « Heap », « Triage » ou « Full ». Le type par défaut est « Full ». Pour plus d’informations, visitez https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ '{0}' n’est pas un type de vidage valide. Les options valides sont « Mini », « Heap », « Triage » et « Full »
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ '--crashdump-type' attend un seul type de dump comme argument (par exemple '--crashdump-type Heap')
+
+
+
+ Requests of type '{0}' is not supported
+ Les demandes de type «{0}» ne sont pas prises en charge
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.it.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.it.xlf
new file mode 100644
index 0000000000..c0c7a2cf77
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.it.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ Il file di dump di arresto anomalo '{0}' previsto non è stato trovato. Tutti i file corrispondenti al criterio '*.dmp' verranno copiati nella cartella dei risultati.
+
+
+
+ The testhost process crash dump file
+ File di dump di arresto anomalo del processo testhost
+
+
+
+ Crash dump file
+ File di dump di arresto anomalo del sistema
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [solo net6.0+] Generazione di file di dump di arresto anomalo quando il processo di esecuzione del test si arresta in modo imprevisto
+
+
+
+ Crash dump
+ Dump di arresto anomalo del sistema
+
+
+
+ Specify the name of the dump file
+ Specificare il nome del file di dump
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ La variabile di ambiente '{0}' avrebbe dovuto essere impostata su '{1}' ma il valore è '{2}'
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ La funzionalità dump di arresto anomalo del sistema è disponibile solo in .NET (Core)
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [solo net6.0+ ] Generazione di un file di dump in caso di arresto anomalo del processo di test
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ Il processo host di test con PID '{0}' si è arrestato in modo anomalo. È stato generato un file di dump
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ Specificare il tipo di dump. I valori validi sono "Mini", "Heap", "Valutazione" o "Completo". Il tipo predefinito è "Completo". Per altre informazioni, visitare https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ '{0}' non è un tipo di dump valido. Le opzioni valide sono 'Mini', 'Heap', 'Triage' e 'Full'
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ '--crashdump-type' prevede un singolo tipo di dump come argomento (ad esempio '--crashdump-type Heap')
+
+
+
+ Requests of type '{0}' is not supported
+ Le richieste di tipo '{0}' non sono supportate
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.ja.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.ja.xlf
new file mode 100644
index 0000000000..b0a6687ff4
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.ja.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ 予期されたクラッシュ ダンプ ファイル '{0}' が見つかりませんでした。'*.dmp' パターンに一致するすべてのファイルが結果フォルダーにコピーされます
+
+
+
+ The testhost process crash dump file
+ testhost プロセスのクラッシュ ダンプ ファイル
+
+
+
+ Crash dump file
+ クラッシュ ダンプ ファイル
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [net6.0+ のみ] テストの実行プロセスが予期せずクラッシュしたときにクラッシュ ダンプ ファイルを生成する
+
+
+
+ Crash dump
+ クラッシュ ダンプ
+
+
+
+ Specify the name of the dump file
+ ダンプ ファイルの名前を指定する
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ 環境変数 '{0}' は '{1}' に設定する必要がありますが、値は '{2}' です
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ クラッシュ ダンプ機能は .NET (Core) でのみ使用できます
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [net6.0+ のみ] テスト プロセスがクラッシュした場合にダンプ ファイルを生成する
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ PID '{0}' のテスト ホスト プロセスがクラッシュしました。ダンプ ファイルが生成されました
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ ダンプの型を指定します。有効な値は、'Mini'、'Heap'、'Triage'、または 'Full' です。既定の型は 'Full' です。詳細については、https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps を参照してください
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ '{0}' は有効なダンプの種類ではありません。有効なオプションは、'Mini'、'Heap'、'Triage'、'Full' です
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ '--crashdump-type' には、引数として 1 つのダンプの型が必要です (例: '--crashdump-type Heap')
+
+
+
+ Requests of type '{0}' is not supported
+ 型 '{0}' の要求はサポートされていません
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.ko.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.ko.xlf
new file mode 100644
index 0000000000..3f226f41bf
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.ko.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ 필요한 크래시 덤프 파일 '{0}'을(를) 찾을 수 없습니다. '*.dmp' 패턴과 일치하는 모든 파일이 결과 폴더에 복사됩니다.
+
+
+
+ The testhost process crash dump file
+ testhost 프로세스 크래시 덤프 파일
+
+
+
+ Crash dump file
+ 크래시 덤프 파일
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [net6.0 이상만] 테스트 실행 프로세스가 예기치 않게 충돌할 때 크래시 덤프 파일 생성
+
+
+
+ Crash dump
+ 크래시 덤프
+
+
+
+ Specify the name of the dump file
+ 덤프 파일의 이름 지정
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ 환경 변수 '{0}'은(는) '{1}'로 설정해야 하지만 값이 '{2}'입니다.
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ 크래시 덤프 기능은 .NET(Core)에서만 사용할 수 있습니다.
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [net6.0 이상만] 테스트 프로세스가 충돌하는 경우 덤프 파일 생성
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ PID가 '{0}'인 테스트 호스트 프로세스가 충돌했습니다. 덤프 파일이 생성되었습니다.
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ 덤프 유형을 지정합니다. 유효한 값은 'Mini', 'Heap', 'Triage' 또는 'Full'입니다. 기본 유형은 'Full'입니다. 자세한 내용은 https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps를 방문하세요.
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ '{0}'은(는) 올바른 덤프 유형이 아닙니다. 유효한 옵션은 'Mini', 'Heap', 'Triage' 및 'Full'입니다.
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ '--crashdump-type'에는 단일 덤프 유형이 인수로 필요합니다(예: '--crashdump-type Heap').
+
+
+
+ Requests of type '{0}' is not supported
+ '{0}' 유형의 요청은 지원되지 않습니다.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.pl.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.pl.xlf
new file mode 100644
index 0000000000..09a62f5adb
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.pl.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ Nie można odnaleźć oczekiwanego pliku zrzutu awaryjnego „{0}”. Wszystkie pliki zgodne ze wzorcem „*.dmp” zostaną skopiowane do folderu wyników
+
+
+
+ The testhost process crash dump file
+ Plik zrzutu awaryjnego procesu testhost
+
+
+
+ Crash dump file
+ Plik zrzutu awaryjnego
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [tylko net6.0+ ] Tworzenie plików zrzutu awaryjnego w przypadku nieoczekiwanej awarii procesu wykonywania testu
+
+
+
+ Crash dump
+ Zrzut awaryjny
+
+
+
+ Specify the name of the dump file
+ Określ nazwę pliku zrzutu
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ Zmienna środowiskowa „{0}” powinna być ustawiona na „{1}”, ale wartość to „{2}”
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ Funkcja zrzutu awaryjnego jest dostępna tylko na platformie .NET (Core)
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [tylko net6.0+ ] Wygeneruj plik zrzutu w przypadku awarii procesu testowego
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ Proces hosta testowego o identyfikatorze PID „{0}{0}” uległ awarii, wygenerowano plik zrzutu
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ Określ typ zrzutu. Prawidłowe wartości to „Mini”, „Sterta”, „Klasyfikacja” i „Pełne”. Typ domyślny to „Pełne”. Aby uzyskać więcej informacji, odwiedź stronę https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ Typ „{0}” nie jest prawidłowym typem zrzutu. Prawidłowe opcje to „Mini”, „Sterta”, „Klasyfikacja” i „Pełne”
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ Element „--crashdump-type” oczekuje pojedynczego typu zrzutu jako argumentu (np. „--crashdump-type Heap”)
+
+
+
+ Requests of type '{0}' is not supported
+ Żądania typu „{0}” nie są obsługiwane
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.pt-BR.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.pt-BR.xlf
new file mode 100644
index 0000000000..1361a936e1
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.pt-BR.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ O arquivo de despejo de memória ''{0}'' não pôde ser encontrado. Todos os arquivos correspondentes ao padrão ''*.dmp'' serão copiados para a pasta de resultados
+
+
+
+ The testhost process crash dump file
+ O arquivo de despejo de memória do processo testhost
+
+
+
+ Crash dump file
+ Arquivo de despejo de memória
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [somente net6.0+] Produzir arquivos de despejo de memória quando o processo de execução de teste falhar inesperadamente
+
+
+
+ Crash dump
+ Despejo de memória
+
+
+
+ Specify the name of the dump file
+ Especifique o nome do arquivo de despejo
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ A variável de ambiente ''{0}'' deveria ter sido definida como ''{1}'', mas o valor é ''{2}''
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ O recurso de despejo de memória só está disponível no .NET (Core)
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [somente net6.0+] Gerar um arquivo de despejo se o processo de teste falhar
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ O processo de host de teste com PID ''{0}'' falhou e um arquivo de despejo foi gerado
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ Especifique o tipo de despejo. Os valores válidos são ''Mini'', ''Heap'', ''Triage'' ou ''Full''. O tipo padrão é ''Full''. Para obter mais informações, visite https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ ''{0}'' não é um tipo de despejo válido. As opções válidas são ''Mini'', ''Heap'', ''Triage'' e ''Full''
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ ''--crashdump-type'' espera um único tipo de despejo como argumento (por exemplo, ''--crashdump-type Heap'')
+
+
+
+ Requests of type '{0}' is not supported
+ Não há suporte para solicitações de tipo ''{0}''
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.ru.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.ru.xlf
new file mode 100644
index 0000000000..c1c1c92d71
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.ru.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ Не удалось найти ожидаемый файл аварийного дампа "{0}". Все файлы, соответствующие шаблону "*.dmp", будут скопированы в папку результатов.
+
+
+
+ The testhost process crash dump file
+ Файл аварийного дампа тестового хост-процесса
+
+
+
+ Crash dump file
+ Файл аварийного дампа
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [только net6.0 и выше] Создавать файлы аварийного дампа при неожиданном сбое процесса выполнения теста
+
+
+
+ Crash dump
+ Аварийный дамп
+
+
+
+ Specify the name of the dump file
+ Укажите имя файла дампа зависания
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ Для переменной среды "{0}" должно быть задано значение "{1}", но задано значение "{2}"
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ Функция аварийного дампа доступна только в .NET (Core)
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [только net6.0 и выше] Создавать файл дампа в случае сбоя тестового процесса
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ Произошло аварийное завершение тестового хост-процесса с идентификатором процесса "{0}". Создан файл дампа
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ Укажите тип дампа. Допустимые значения: "Mini", "Heap", "Triage" или "Full". Тип по умолчанию — "Full". Дополнительные сведения см. на странице https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ "{0}" не является допустимым типом дампа. Допустимые параметры: "Mini", "Heap", "Triage" и "Full"
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ "--hangdump-type" ожидает в качестве аргумента один тип дампа (например, "--crashdump-type Heap")
+
+
+
+ Requests of type '{0}' is not supported
+ Запросы типа "{0}" не поддерживаются
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.tr.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.tr.xlf
new file mode 100644
index 0000000000..c1e302d08c
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.tr.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ Beklenen kilitlenme dökümü dosyası '{0}' bulunamadı, '*.dmp' düzeniyle eşleşen tüm dosyalar sonuç klasörüne kopyalanacak
+
+
+
+ The testhost process crash dump file
+ Test ana bilgisayarı işlemi kilitlenme bilgi dökümü dosyası
+
+
+
+ Crash dump file
+ Kilitlenme bilgi dökümü dosyası
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [yalnızca net6.0+] Test yürütme işlemi beklenmedik bir şekilde çöktüğünde kilitlenme dökümü dosyaları oluştur
+
+
+
+ Crash dump
+ Kilitlenme bilgi dökümü
+
+
+
+ Specify the name of the dump file
+ Döküm dosyasının adını belirtin
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ Ortam değişkeni '{0}', '{1}' olarak ayarlanmalıydı ancak değer '{2}'
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ Kilitlenme dökümü özelliği yalnızca .NET'te (Core) mevcuttur
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [yalnızca net6.0+] Test işlemi çökerse bir döküm dosyası oluşturun
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ PID'li test ana işlemi ‘{0}' kilitlendi, bir döküm dosyası oluşturuldu
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ Dökümün türünü belirtin. Geçerli değerler: 'Mini', 'Heap', 'Triage' veya 'Full'. Varsayılan tür: 'Full'. Daha fazla bilgi için https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps adresini ziyaret edin
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ '{0}' geçerli bir döküm türü değil. Geçerli seçenekler 'Mini', 'Heap', 'Triage' ve 'Full’dur
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ '--crashdump-type' argüman olarak tek bir döküm tipini bekler (örneğin, '--crashdump-type Heap')
+
+
+
+ Requests of type '{0}' is not supported
+ '{0}' türündeki istek desteklenmiyor
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.zh-Hans.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.zh-Hans.xlf
new file mode 100644
index 0000000000..230f96271b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.zh-Hans.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ 找不到预期的故障转储文件“{0}”,与“*.dmp”模式匹配的所有文件都将复制到结果文件夹
+
+
+
+ The testhost process crash dump file
+ testhost 进程故障转储文件
+
+
+
+ Crash dump file
+ 故障转储文件
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [仅限 net6.0+]在测试执行进程意外崩溃时生成故障转储文件
+
+
+
+ Crash dump
+ 故障转储
+
+
+
+ Specify the name of the dump file
+ 指定转储文件的名称
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ 环境变量“{0}”应设置为“{1}”,但值为“{2}”
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ 故障转储功能仅在 .NET (Core) 中可用
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [仅限 net6.0+]如果测试进程崩溃,则生成转储文件
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ PID 为“{0}”的测试主机进程崩溃,生成了转储文件
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ 指定转储的类型。有效值为 "Mini"、"Heap"、"Triage" 或 "Full"。默认类型为 "Full"。有关详细信息,请访问 https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ “{0}”不是有效的转储类型。有效选项为“Mini”、“Heap”、“Triage”和“Full”
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ “--crashdump-type”需要将单一转储类型作为参数(例如“--crashdump-type Heap”)
+
+
+
+ Requests of type '{0}' is not supported
+ 不支持类型为“{0}”的请求
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.zh-Hant.xlf b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.zh-Hant.xlf
new file mode 100644
index 0000000000..63cf43aed5
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/CrashDumpResources.zh-Hant.xlf
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Expected crash dump file '{0}' could not be found, all files matching the '*.dmp' pattern will be copied to the result folder
+ 找不到預期的損毀傾印檔案 '{0}',符合 '*.dmp' 模式的所有檔案都將複製到結果資料夾
+
+
+
+ The testhost process crash dump file
+ testhost 處理常式損毀傾印檔案
+
+
+
+ Crash dump file
+ 損毀傾印檔案
+
+
+
+ [net6.0+ only] Produce crash dump files when the test execution process crashes unexpectedly
+ [net6.0+ only] 測試執行流程意外損毀時會產生損毀傾印檔案
+
+
+
+ Crash dump
+ 損毀傾印
+
+
+
+ Specify the name of the dump file
+ 指定傾印檔案的名稱
+
+
+
+ Environment variable '{0}' should have been set to '{1}' but value is '{2}'
+ 環境變數 '{0}' 應該設定為 '{1}' 但值為 '{2}'
+
+
+
+ Crash dump feature is only available in .NET (Core)
+ 只有 .NET (Core) 才可使用損毀傾印功能
+
+
+
+ [net6.0+ only] Generate a dump file if the test process crashes
+ [net6.0+ only] 如果測試流程損毀,則產生傾印檔案
+
+
+
+ Test host process with PID '{0}' crashed, a dump file was generated
+ PID '{0}' 損毀的測試主機處理常式,已產生傾印檔案
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' or 'Full'. Default type is 'Full'. For more information visit https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+ 指定傾印的類型。有效值為 'Mini'、'Heap'、'Triage' 或 'Full'。預設類型為 'Full'。如需詳細資訊,請瀏覽 https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash#types-of-mini-dumps
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'
+ '{0}' 不是有效的傾印類型。有效的選項為 'Mini'、'Heap'、'Triage' 和 'Full'
+
+
+
+ '--crashdump-type' expects a single dump type as argument (e.g. '--crashdump-type Heap')
+ '--crashdump-type' 需要單一傾印類型做為引數 (例如 '--crashdump-type Heap')
+
+
+
+ Requests of type '{0}' is not supported
+ 不支援類型 '{0}' 的要求
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/TestingPlatformBuilderHook.cs b/src/Platform/Microsoft.Testing.Extensions.CrashDump/TestingPlatformBuilderHook.cs
new file mode 100644
index 0000000000..dc583349ff
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/TestingPlatformBuilderHook.cs
@@ -0,0 +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.Testing.Platform.Builder;
+
+namespace Microsoft.Testing.Extensions.CrashDump;
+
+public static class TestingPlatformBuilderHook
+{
+ public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] _)
+ => testApplicationBuilder.AddCrashDumpProvider(ignoreIfNotSupported: true);
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/build/Microsoft.Testing.Extensions.CrashDump.props b/src/Platform/Microsoft.Testing.Extensions.CrashDump/build/Microsoft.Testing.Extensions.CrashDump.props
new file mode 100644
index 0000000000..80d9f6fe11
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/build/Microsoft.Testing.Extensions.CrashDump.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/buildMultiTargeting/Microsoft.Testing.Extensions.CrashDump.props b/src/Platform/Microsoft.Testing.Extensions.CrashDump/buildMultiTargeting/Microsoft.Testing.Extensions.CrashDump.props
new file mode 100644
index 0000000000..d94b2a763e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/buildMultiTargeting/Microsoft.Testing.Extensions.CrashDump.props
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Microsoft.Testing.Extensions.CrashDump
+ Microsoft.Testing.Extensions.CrashDump.TestingPlatformBuilderHook
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/buildTransitive/Microsoft.Testing.Extensions.CrashDump.props b/src/Platform/Microsoft.Testing.Extensions.CrashDump/buildTransitive/Microsoft.Testing.Extensions.CrashDump.props
new file mode 100644
index 0000000000..80d9f6fe11
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/buildTransitive/Microsoft.Testing.Extensions.CrashDump.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt
new file mode 100644
index 0000000000..ea8617fcb0
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt
@@ -0,0 +1,10 @@
+T:System.ArgumentNullException; Use 'ArgumentGuard' instead
+P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.UtcNow; Use 'IClock' instead
+M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
+M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
+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,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
new file mode 100644
index 0000000000..bde5b6043b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpActivityIndicator.cs
@@ -0,0 +1,305 @@
+// 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.Concurrent;
+using System.Globalization;
+
+using Microsoft.Testing.Extensions.Diagnostics.Resources;
+using Microsoft.Testing.Extensions.HangDump.Serializers;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Extensions.TestHost;
+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.Logging;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.Testing.Platform.TestHost;
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal sealed class HangDumpActivityIndicator : IDataConsumer, ITestSessionLifetimeHandler,
+#if NETCOREAPP
+ IAsyncDisposable
+#else
+ IDisposable
+#endif
+{
+ private readonly ICommandLineOptions _commandLineOptions;
+ private readonly IEnvironment _environment;
+ private readonly ITask _task;
+ private readonly IClock _clock;
+ private readonly ILogger _logger;
+ private readonly NamedPipeClient? _namedPipeClient;
+ private readonly ManualResetEventSlim _signalActivity = new(false);
+ private readonly ManualResetEventSlim _mutexCreated = new(false);
+ private readonly bool _traceLevelEnabled;
+ private readonly ConcurrentDictionary _testsCurrentExecutionState = new();
+
+ private Task? _signalActivityIndicatorTask;
+ private Mutex? _activityIndicatorMutex;
+ private string? _mutexName;
+ private bool _exitSignalActivityIndicatorAsync;
+ private NamedPipeServer? _singleConnectionNamedPipeServer;
+ private PipeNameDescription? _pipeNameDescription;
+ private bool _sessionEndCalled;
+
+ public HangDumpActivityIndicator(
+ ICommandLineOptions commandLineOptions,
+ IEnvironment environment,
+ ITask task,
+ ITestApplicationModuleInfo testApplicationModuleInfo,
+ ILoggerFactory loggerFactory,
+ IClock clock)
+ {
+ _logger = loggerFactory.CreateLogger();
+ _traceLevelEnabled = _logger.IsEnabled(LogLevel.Trace);
+ _commandLineOptions = commandLineOptions;
+ _environment = environment;
+ _task = task;
+ _clock = clock;
+ if (_commandLineOptions.IsOptionSet(HangDumpCommandLineProvider.HangDumpOptionName) &&
+ !_commandLineOptions.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey))
+ {
+ string namedPipeSuffix = _environment.GetEnvironmentVariable(HangDumpConfiguration.MutexNameSuffix)
+ ?? throw new InvalidOperationException($"Expected {HangDumpConfiguration.MutexNameSuffix} environment variable set.");
+ // @Marco: Why do we need to duplicate logic here instead of using HangDumpConfiguration.PipeNameKey?
+ string pipeNameEnvironmentVariable = $"{HangDumpConfiguration.PipeName}_{FNV_1aHashHelper.ComputeStringHash(testApplicationModuleInfo.GetCurrentTestApplicationFullPath())}_{namedPipeSuffix}";
+ string namedPipeName = _environment.GetEnvironmentVariable(pipeNameEnvironmentVariable)
+ ?? throw new InvalidOperationException($"Expected {pipeNameEnvironmentVariable} environment variable set.");
+ _namedPipeClient = new NamedPipeClient(namedPipeName);
+ _namedPipeClient.RegisterSerializer(new ActivityIndicatorMutexNameRequestSerializer(), typeof(ActivityIndicatorMutexNameRequest));
+ _namedPipeClient.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse));
+ _namedPipeClient.RegisterSerializer(new SessionEndSerializerRequestSerializer(), typeof(SessionEndSerializerRequest));
+ _namedPipeClient.RegisterSerializer(new ConsumerPipeNameRequestSerializer(), typeof(ConsumerPipeNameRequest));
+ }
+ }
+
+ public Type[] DataTypesConsumed => [typeof(TestNodeUpdateMessage)];
+
+ public string Uid => nameof(HangDumpActivityIndicator);
+
+ public string Version => AppVersion.DefaultSemVer;
+
+ public string DisplayName => ExtensionResources.HangDumpExtensionDisplayName;
+
+ public string Description => ExtensionResources.HangDumpExtensionDescription;
+
+ public Task IsEnabledAsync() => Task.FromResult(_commandLineOptions.IsOptionSet(HangDumpCommandLineProvider.HangDumpOptionName) &&
+ !_commandLineOptions.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey));
+
+ public async Task OnTestSessionStartingAsync(SessionUid sessionUid, CancellationToken cancellationToken)
+ {
+ ApplicationStateGuard.Ensure(_namedPipeClient is not null);
+
+ if (!await IsEnabledAsync() || cancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ 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);
+ await _logger.LogTraceAsync("Connected to the process lifetime handler");
+ _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");
+ _mutexCreated.Wait(cancellationToken);
+ await _logger.LogTraceAsync($"Mutex '{_mutexName}' created");
+ await _namedPipeClient.RequestReplyAsync(new ActivityIndicatorMutexNameRequest(_mutexName), cancellationToken)
+ .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout);
+ await _logger.LogTraceAsync($"Mutex '{_mutexName}' sent to the process lifetime handler");
+
+ // Setup the server channel with the testhost controller
+ _pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"));
+ _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 _namedPipeClient.RequestReplyAsync(new ConsumerPipeNameRequest(_pipeNameDescription.Name), cancellationToken)
+ .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout);
+
+ // Wait the connection from the testhost controller
+ await _singleConnectionNamedPipeServer.WaitConnectionAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout);
+ await _logger.LogTraceAsync($"Test host controller connected");
+ }
+ catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken)
+ {
+ // Do nothing, we're stopping
+ }
+ }
+
+ private async Task CallbackAsync(IRequest request)
+ {
+ if (request is GetInProgressTestsRequest)
+ {
+ await _logger.LogDebugAsync($"Received '{nameof(GetInProgressTestsRequest)}'");
+ return new GetInProgressTestsResponse(_testsCurrentExecutionState.Select(x => (x.Key, (int)_clock.UtcNow.Subtract(x.Value.Item2).TotalSeconds)).ToArray());
+ }
+ else if (request is ExitSignalActivityIndicatorTaskRequest)
+ {
+ await _logger.LogDebugAsync($"Received '{nameof(ExitSignalActivityIndicatorTaskRequest)}'");
+ await ExitSignalActivityIndicatorTaskAsync();
+ return VoidResponse.CachedInstance;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpUnsupportedRequestTypeErrorMessage, request.GetType().FullName));
+ }
+ }
+
+ public async Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested
+ || value is not TestNodeUpdateMessage nodeChangedMessage)
+ {
+ return;
+ }
+
+ TestNodeStateProperty? state = nodeChangedMessage.TestNode.Properties.SingleOrDefault();
+ if (state is InProgressTestNodeStateProperty)
+ {
+ if (_traceLevelEnabled)
+ {
+ await _logger.LogTraceAsync($"New in-progress test '{nodeChangedMessage.TestNode.DisplayName}'");
+ }
+
+ _testsCurrentExecutionState.TryAdd(nodeChangedMessage.TestNode.DisplayName, (typeof(InProgressTestNodeStateProperty), _clock.UtcNow));
+ }
+ else if (state is PassedTestNodeStateProperty or ErrorTestNodeStateProperty or CancelledTestNodeStateProperty
+ or FailedTestNodeStateProperty or TimeoutTestNodeStateProperty or SkippedTestNodeStateProperty
+ && _testsCurrentExecutionState.TryRemove(nodeChangedMessage.TestNode.DisplayName, out (Type, DateTimeOffset) record)
+ && _traceLevelEnabled)
+ {
+ await _logger.LogTraceAsync($"Test removed from in-progress list '{nodeChangedMessage.TestNode.DisplayName}' after '{_clock.UtcNow.Subtract(record.Item2)}', total in-progress '{_testsCurrentExecutionState.Count}'");
+ }
+
+ // Optimization, we're interested in test progression and eventually in the discovery progression
+ if (state is not InProgressTestNodeStateProperty)
+ {
+ if (_traceLevelEnabled)
+ {
+ await _logger.LogTraceAsync($"Signal for action node {nodeChangedMessage.TestNode.DisplayName} - '{state}'");
+ }
+
+ // Signal the activity if it's not set
+ if (!_signalActivity.IsSet)
+ {
+ _signalActivity.Set();
+ }
+ }
+ }
+
+ private Task SignalActivityIndicatorAsync()
+ {
+ _activityIndicatorMutex = new Mutex(true, _mutexName);
+ _mutexCreated.Set();
+
+ while (!_exitSignalActivityIndicatorAsync)
+ {
+ // Wait for the signal
+ // We don't add the timeout here because depends on the user value specified with the --hangdump-timeout option
+ _signalActivity.Wait();
+
+ if (_traceLevelEnabled)
+ {
+ _logger.LogTrace($"Signal process lifetime handler, exitSignalActivityIndicatorAsync {_exitSignalActivityIndicatorAsync}");
+ }
+
+ _activityIndicatorMutex.ReleaseMutex();
+ _activityIndicatorMutex.WaitOne(TimeoutHelper.DefaultHangTimeSpanTimeout);
+
+ if (_traceLevelEnabled)
+ {
+ _logger.LogTrace($"Signaled by process lifetime handler, exitSignalActivityIndicatorAsync {_exitSignalActivityIndicatorAsync}");
+ }
+
+ // Reset the signal
+ _signalActivity.Reset();
+ }
+
+ _logger.LogDebug($"Exit 'SignalActivityIndicatorAsync'");
+
+ return Task.CompletedTask;
+ }
+
+ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, CancellationToken cancellationToken)
+ {
+ ApplicationStateGuard.Ensure(_namedPipeClient is not null);
+ ApplicationStateGuard.Ensure(_activityIndicatorMutex is not null);
+
+ if (!await IsEnabledAsync())
+ {
+ return;
+ }
+
+ await _namedPipeClient.RequestReplyAsync(new SessionEndSerializerRequest(), cancellationToken)
+ .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout);
+
+ await _logger.LogDebugAsync($"Signal for test session end'");
+ await ExitSignalActivityIndicatorTaskAsync();
+
+ await _logger.LogTraceAsync($"Signaled by process for it's exit");
+ _sessionEndCalled = true;
+ }
+
+ private async Task ExitSignalActivityIndicatorTaskAsync()
+ {
+ if (_exitSignalActivityIndicatorAsync)
+ {
+ return;
+ }
+
+ ApplicationStateGuard.Ensure(_signalActivityIndicatorTask is not null);
+ _exitSignalActivityIndicatorAsync = true;
+ _signalActivity.Set();
+ await _signalActivityIndicatorTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout);
+ }
+
+#if NETCOREAPP
+ public async ValueTask DisposeAsync()
+ {
+ await DisposeHelper.DisposeAsync(_namedPipeClient);
+
+ // 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);
+ }
+
+ _pipeNameDescription?.Dispose();
+ _mutexCreated.Dispose();
+ _signalActivity.Dispose();
+ _activityIndicatorMutex?.Dispose();
+ }
+#else
+ public void Dispose()
+ {
+ _namedPipeClient?.Dispose();
+
+ // 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)
+ {
+ _singleConnectionNamedPipeServer?.Dispose();
+ }
+
+ _pipeNameDescription?.Dispose();
+ _mutexCreated.Dispose();
+ _signalActivity.Dispose();
+ _activityIndicatorMutex?.Dispose();
+ }
+#endif
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpCommandLineProvider.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpCommandLineProvider.cs
new file mode 100644
index 0000000000..823de1e328
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpCommandLineProvider.cs
@@ -0,0 +1,76 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.Diagnostics.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.CommandLine;
+using Microsoft.Testing.Platform.Helpers;
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal sealed class HangDumpCommandLineProvider : ICommandLineOptionsProvider
+{
+ public const string HangDumpOptionName = "hangdump";
+ public const string HangDumpFileNameOptionName = "hangdump-filename";
+ public const string HangDumpTimeoutOptionName = "hangdump-timeout";
+ public const string HangDumpTypeOptionName = "hangdump-type";
+
+#if NETCOREAPP
+ private static readonly string[] HangDumpTypeOptions = ["Mini", "Heap", "Full", "Triage"];
+#else
+ private static readonly string[] HangDumpTypeOptions = ["Mini", "Heap", "Full"];
+#endif
+
+ private static readonly IReadOnlyCollection CachedCommandLineOptions =
+ [
+ new(HangDumpOptionName, ExtensionResources.HangDumpOptionDescription, ArgumentArity.Zero, false),
+ new(HangDumpTimeoutOptionName, ExtensionResources.HangDumpTimeoutOptionDescription, ArgumentArity.ExactlyOne, false),
+ new(HangDumpFileNameOptionName, ExtensionResources.HangDumpFileNameOptionDescription, ArgumentArity.ExactlyOne, false),
+ new(HangDumpTypeOptionName, ExtensionResources.HangDumpTypeOptionDescription, ArgumentArity.ExactlyOne, false)
+ ];
+
+ private readonly HangDumpConfiguration _hangDumpConfiguration;
+
+ public HangDumpCommandLineProvider(HangDumpConfiguration hangDumpConfiguration) => _hangDumpConfiguration = hangDumpConfiguration;
+
+ public string Uid => nameof(HangDumpCommandLineProvider);
+
+ public string Version => AppVersion.DefaultSemVer;
+
+ public string DisplayName => ExtensionResources.HangDumpExtensionDisplayName;
+
+ public string Description => ExtensionResources.HangDumpExtensionDescription;
+
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public IReadOnlyCollection GetCommandLineOptions() => CachedCommandLineOptions;
+
+ public Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
+ {
+ if (commandOption.Name == HangDumpTimeoutOptionName && !TimeSpanParser.TryParse(arguments[0], out TimeSpan _))
+ {
+ return ValidationResult.InvalidTask(ExtensionResources.HangDumpTimeoutOptionInvalidArgument);
+ }
+
+ if (commandOption.Name == HangDumpTypeOptionName)
+ {
+ if (!HangDumpTypeOptions.Contains(arguments[0], StringComparer.OrdinalIgnoreCase))
+ {
+ return ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpTypeOptionInvalidType, arguments[0]));
+ }
+ }
+
+ return ValidationResult.ValidTask;
+ }
+
+ public Task ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
+ => (commandLineOptions.IsOptionSet(HangDumpTimeoutOptionName) ||
+ commandLineOptions.IsOptionSet(HangDumpFileNameOptionName) ||
+ commandLineOptions.IsOptionSet(HangDumpTypeOptionName)) &&
+ !commandLineOptions.IsOptionSet(HangDumpOptionName)
+ ? ValidationResult.InvalidTask(ExtensionResources.MissingHangDumpMainOption)
+ : ValidationResult.ValidTask;
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpConfiguration.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpConfiguration.cs
new file mode 100644
index 0000000000..00b2633bf2
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpConfiguration.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.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.IPC;
+using Microsoft.Testing.Platform.Services;
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal sealed class HangDumpConfiguration
+{
+ public const string PipeName = "TESTINGPLATFORM_HANGDUMP_PIPENAME";
+ public const string MutexName = "TESTINGPLATFORM_HANGDUMP_MUTEXNAME";
+ public const string MutexNameSuffix = "TESTINGPLATFORM_HANGDUMP_MUTEXNAME_SUFFIX";
+
+ public HangDumpConfiguration(ITestApplicationModuleInfo testApplicationModuleInfo, PipeNameDescription pipeNameDescription, string mutexSuffix)
+ {
+ PipeNameValue = pipeNameDescription.Name;
+ PipeNameKey = $"{PipeName}_{FNV_1aHashHelper.ComputeStringHash(testApplicationModuleInfo.GetCurrentTestApplicationFullPath())}_{mutexSuffix}";
+ MutexSuffix = mutexSuffix;
+ }
+
+ public string PipeNameKey { get; }
+
+ public string PipeNameValue { get; }
+
+ public string MutexSuffix { get; }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpEnvironmentVariableProvider.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpEnvironmentVariableProvider.cs
new file mode 100644
index 0000000000..6c855167bf
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpEnvironmentVariableProvider.cs
@@ -0,0 +1,78 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.Diagnostics.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.TestHostControllers;
+using Microsoft.Testing.Platform.Helpers;
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal sealed class HangDumpEnvironmentVariableProvider : ITestHostEnvironmentVariableProvider
+{
+ private readonly ICommandLineOptions _commandLineOptions;
+ private readonly HangDumpConfiguration _hangDumpConfiguration;
+
+ public HangDumpEnvironmentVariableProvider(ICommandLineOptions commandLineOptions, HangDumpConfiguration hangDumpConfiguration)
+ {
+ _commandLineOptions = commandLineOptions;
+ _hangDumpConfiguration = hangDumpConfiguration;
+ }
+
+ public string Uid => nameof(HangDumpEnvironmentVariableProvider);
+
+ public string Version => AppVersion.DefaultSemVer;
+
+ public string DisplayName => ExtensionResources.HangDumpExtensionDisplayName;
+
+ public string Description => ExtensionResources.HangDumpExtensionDescription;
+
+ public Task IsEnabledAsync() => Task.FromResult(_commandLineOptions.IsOptionSet(HangDumpCommandLineProvider.HangDumpOptionName) &&
+ !_commandLineOptions.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey));
+
+ public Task UpdateAsync(IEnvironmentVariables environmentVariables)
+ {
+ environmentVariables.SetVariable(
+ new(_hangDumpConfiguration.PipeNameKey, _hangDumpConfiguration.PipeNameValue, false, true));
+ environmentVariables.SetVariable(
+ new(HangDumpConfiguration.MutexNameSuffix, _hangDumpConfiguration.MutexSuffix, false, true));
+ return Task.CompletedTask;
+ }
+
+ public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnlyEnvironmentVariables environmentVariables)
+ {
+ if (!environmentVariables.TryGetVariable(_hangDumpConfiguration.PipeNameKey, out OwnedEnvironmentVariable? envVar))
+ {
+ return Task.FromResult(
+ ValidationResult.Invalid(
+ string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpEnvironmentVariableIsMissingErrorMessage, _hangDumpConfiguration.PipeNameKey)));
+ }
+
+ if (envVar.Value != _hangDumpConfiguration.PipeNameValue)
+ {
+ return Task.FromResult(
+ ValidationResult.Invalid(
+ string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpEnvironmentVariableInvalidValueErrorMessage, _hangDumpConfiguration.PipeNameKey, envVar.Value, _hangDumpConfiguration.PipeNameKey)));
+ }
+
+ if (!environmentVariables.TryGetVariable(HangDumpConfiguration.MutexNameSuffix, out envVar))
+ {
+ return Task.FromResult(
+ ValidationResult.Invalid(
+ string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpEnvironmentVariableIsMissingErrorMessage, HangDumpConfiguration.MutexNameSuffix)));
+ }
+
+ if (envVar.Value != _hangDumpConfiguration.MutexSuffix)
+ {
+ return Task.FromResult(
+ ValidationResult.Invalid(
+ string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpEnvironmentVariableInvalidValueErrorMessage, HangDumpConfiguration.MutexNameSuffix, envVar.Value, _hangDumpConfiguration.MutexSuffix)));
+ }
+
+ // No problem found
+ return ValidationResult.ValidTask;
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs
new file mode 100644
index 0000000000..8e3fa6d96d
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs
@@ -0,0 +1,56 @@
+// 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.Diagnostics;
+using Microsoft.Testing.Platform.Builder;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.IPC;
+using Microsoft.Testing.Platform.Services;
+
+namespace Microsoft.Testing.Extensions;
+
+public static class HangDumpExtensions
+{
+ public static void AddHangDumpProvider(this ITestApplicationBuilder builder)
+ {
+ CurrentTestApplicationModuleInfo testApplicationModuleInfo = new(new SystemEnvironment(), new SystemProcessHandler());
+ string mutexSuffix = Guid.NewGuid().ToString("N");
+ PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"));
+ HangDumpConfiguration hangDumpConfiguration = new(testApplicationModuleInfo, pipeNameDescription, mutexSuffix);
+
+ builder.TestHostControllers.AddProcessLifetimeHandler(serviceProvider
+ => new HangDumpProcessLifetimeHandler(
+ hangDumpConfiguration,
+ pipeNameDescription,
+ serviceProvider.GetMessageBus(),
+ serviceProvider.GetOutputDevice(),
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetTask(),
+ serviceProvider.GetEnvironment(),
+ serviceProvider.GetLoggerFactory(),
+ serviceProvider.GetTestApplicationModuleInfo(),
+ serviceProvider.GetConfiguration(),
+ serviceProvider.GetProcessHandler(),
+ serviceProvider,
+ serviceProvider.GetClock()));
+
+ builder.TestHostControllers.AddEnvironmentVariableProvider(serviceProvider
+ => new HangDumpEnvironmentVariableProvider(serviceProvider.GetCommandLineOptions(), hangDumpConfiguration));
+
+ builder.CommandLine.AddProvider(()
+ => new HangDumpCommandLineProvider(hangDumpConfiguration));
+
+ var hangDumpActivityIndicatorComposite
+ = new CompositeExtensionFactory(serviceProvider => new HangDumpActivityIndicator(
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetEnvironment(),
+ serviceProvider.GetTask(),
+ serviceProvider.GetTestApplicationModuleInfo(),
+ serviceProvider.GetLoggerFactory(),
+ serviceProvider.GetClock()));
+
+ builder.TestHost.AddDataConsumer(hangDumpActivityIndicatorComposite);
+ builder.TestHost.AddTestSessionLifetimeHandle(hangDumpActivityIndicatorComposite);
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpProcessLifetimeHandler.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpProcessLifetimeHandler.cs
new file mode 100644
index 0000000000..9a4a823a32
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpProcessLifetimeHandler.cs
@@ -0,0 +1,429 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.Diagnostics.Resources;
+using Microsoft.Testing.Extensions.HangDump.Serializers;
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Extensions.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestHostControllers;
+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.Logging;
+using Microsoft.Testing.Platform.Messages;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.Testing.Platform.Services;
+
+#if NETCOREAPP
+using Microsoft.Diagnostics.NETCore.Client;
+#endif
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal sealed class HangDumpProcessLifetimeHandler : ITestHostProcessLifetimeHandler, IOutputDeviceDataProducer, IDataProducer,
+#if NETCOREAPP
+ IAsyncDisposable
+#else
+ IDisposable
+#endif
+{
+ private readonly HangDumpConfiguration _hangDumpConfiguration;
+ private readonly IMessageBus _messageBus;
+ private readonly IOutputDevice _outputDisplay;
+ private readonly ICommandLineOptions _commandLineOptions;
+ private readonly ITask _task;
+ private readonly IEnvironment _environment;
+ private readonly IConfiguration _configuration;
+ private readonly IProcessHandler _processHandler;
+ private readonly IServiceProvider _serviceProvider;
+ private readonly IClock _clock;
+ private readonly ITestApplicationCancellationTokenSource _testApplicationCancellationTokenSource;
+ private readonly PipeNameDescription _pipeNameDescription;
+ private readonly bool _traceEnabled;
+ private readonly ILogger _logger;
+ private readonly ManualResetEventSlim _mutexNameReceived = new(false);
+ private readonly ManualResetEventSlim _waitConsumerPipeName = new(false);
+
+ private TimeSpan _activityTimerValue = TimeSpan.FromMinutes(30);
+ private Task? _waitConnectionTask;
+ private Task? _activityIndicatorTask;
+ private NamedPipeServer? _singleConnectionNamedPipeServer;
+ private string? _activityTimerMutexName;
+ private bool _exitActivityIndicatorTask;
+ private string _dumpType = "Full";
+ private string _dumpFileNamePattern;
+ private Mutex? _activityIndicatorMutex;
+ private ITestHostProcessInformation? _testHostProcessInformation;
+ private string _dumpFileTaken = string.Empty;
+ private NamedPipeClient? _namedPipeClient;
+
+ public HangDumpProcessLifetimeHandler(
+ HangDumpConfiguration hangDumpConfiguration,
+ PipeNameDescription pipeNameDescription,
+ IMessageBus messageBus,
+ IOutputDevice outputDisplay,
+ ICommandLineOptions commandLineOptions,
+ ITask task,
+ IEnvironment environment,
+ ILoggerFactory loggerFactory,
+ ITestApplicationModuleInfo testApplicationModuleInfo,
+ IConfiguration configuration,
+ IProcessHandler processHandler,
+ IServiceProvider serviceProvider,
+ IClock clock)
+ {
+ _logger = loggerFactory.CreateLogger();
+ _traceEnabled = _logger.IsEnabled(LogLevel.Trace);
+ _hangDumpConfiguration = hangDumpConfiguration;
+ _pipeNameDescription = pipeNameDescription;
+ _messageBus = messageBus;
+ _outputDisplay = outputDisplay;
+ _commandLineOptions = commandLineOptions;
+ _task = task;
+ _environment = environment;
+ _configuration = configuration;
+ _processHandler = processHandler;
+ _serviceProvider = serviceProvider;
+ _clock = clock;
+ _testApplicationCancellationTokenSource = serviceProvider.GetTestApplicationCancellationTokenSource();
+ _dumpFileNamePattern = $"{Path.GetFileNameWithoutExtension(testApplicationModuleInfo.GetCurrentTestApplicationFullPath())}_%p_hang.dmp";
+ }
+
+ public string Uid => nameof(HangDumpProcessLifetimeHandler);
+
+ public string Version => AppVersion.DefaultSemVer;
+
+ public string DisplayName => ExtensionResources.HangDumpExtensionDisplayName;
+
+ public string Description => ExtensionResources.HangDumpExtensionDescription;
+
+ public Type[] DataTypesProduced => [typeof(FileArtifact)];
+
+ public Task IsEnabledAsync() => Task.FromResult(_commandLineOptions.IsOptionSet(HangDumpCommandLineProvider.HangDumpOptionName) &&
+ !_commandLineOptions.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey));
+
+ public async Task BeforeTestHostProcessStartAsync(CancellationToken cancellationToken)
+ {
+ if (_commandLineOptions.TryGetOptionArgumentList(HangDumpCommandLineProvider.HangDumpTimeoutOptionName, out string[]? timeout))
+ {
+ _activityTimerValue = TimeSpanParser.Parse(timeout[0]);
+ }
+
+ if (_commandLineOptions.TryGetOptionArgumentList(HangDumpCommandLineProvider.HangDumpTypeOptionName, out string[]? dumpType))
+ {
+ _dumpType = dumpType[0];
+ }
+
+ if (_commandLineOptions.TryGetOptionArgumentList(HangDumpCommandLineProvider.HangDumpFileNameOptionName, out string[]? fileName))
+ {
+ _dumpFileNamePattern = fileName[0];
+ }
+
+ await _logger.LogInformationAsync($"Hang dump timeout setup {_activityTimerValue}.");
+
+ _waitConnectionTask = _task.Run(
+ async () =>
+ {
+ _singleConnectionNamedPipeServer = new(_pipeNameDescription, CallbackAsync, _environment, _logger, _task, cancellationToken);
+ _singleConnectionNamedPipeServer.RegisterSerializer(new ActivityIndicatorMutexNameRequestSerializer(), typeof(ActivityIndicatorMutexNameRequest));
+ _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);
+ }
+
+ private async Task CallbackAsync(IRequest request)
+ {
+ if (request is ActivityIndicatorMutexNameRequest activityIndicatorMutexNameRequest)
+ {
+ await _logger.LogDebugAsync($"Mutex name received by the test host, '{activityIndicatorMutexNameRequest.MutexName}'");
+ _activityTimerMutexName = activityIndicatorMutexNameRequest.MutexName;
+ _mutexNameReceived.Set();
+ return VoidResponse.CachedInstance;
+ }
+ else if (request is SessionEndSerializerRequest)
+ {
+ await _logger.LogDebugAsync($"Session end received by the test host");
+ _exitActivityIndicatorTask = true;
+#if NET
+ if (_namedPipeClient is not null)
+ {
+ await _namedPipeClient.DisposeAsync();
+ }
+#else
+ _namedPipeClient?.Dispose();
+#endif
+ return VoidResponse.CachedInstance;
+ }
+ else if (request is ConsumerPipeNameRequest consumerPipeNameRequest)
+ {
+ await _logger.LogDebugAsync($"Consumer pipe name received '{consumerPipeNameRequest.PipeName}'");
+ _namedPipeClient = new NamedPipeClient(consumerPipeNameRequest.PipeName);
+ _namedPipeClient.RegisterSerializer(new GetInProgressTestsResponseSerializer(), typeof(GetInProgressTestsResponse));
+ _namedPipeClient.RegisterSerializer(new GetInProgressTestsRequestSerializer(), typeof(GetInProgressTestsRequest));
+ _namedPipeClient.RegisterSerializer(new ExitSignalActivityIndicatorTaskRequestSerializer(), typeof(ExitSignalActivityIndicatorTaskRequest));
+ _namedPipeClient.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse));
+ _waitConsumerPipeName.Set();
+ return VoidResponse.CachedInstance;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpUnsupportedRequestTypeErrorMessage, request));
+ }
+ }
+
+ public async Task OnTestHostProcessStartedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation)
+ {
+ ApplicationStateGuard.Ensure(_waitConnectionTask is not null);
+ ApplicationStateGuard.Ensure(_singleConnectionNamedPipeServer is not null);
+ try
+ {
+ _testHostProcessInformation = testHostProcessInformation;
+
+ await _logger.LogDebugAsync($"Wait for test host connection to the server pipe '{_singleConnectionNamedPipeServer.PipeName.Name}'");
+ await _waitConnectionTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout);
+ 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}'");
+
+ // Keep the custom thread to avoid to waste one from thread pool.
+ _activityIndicatorTask = _task.RunLongRunning(ActivityTimerAsync, "[HangDump] ActivityTimerAsync", cancellation);
+ }
+ catch (OperationCanceledException) when (cancellation.IsCancellationRequested)
+ {
+ return;
+ }
+ }
+
+ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation)
+ {
+ if (cancellation.IsCancellationRequested)
+ {
+ return;
+ }
+
+ if (!testHostProcessInformation.HasExitedGracefully)
+ {
+ _logger.LogDebug($"Testhost didn't exit gracefully '{testHostProcessInformation.ExitCode}', disposing _activityIndicatorMutex(is null: '{_activityIndicatorMutex is null}')");
+ _activityIndicatorMutex?.Dispose();
+ }
+
+ if (!RoslynString.IsNullOrEmpty(_dumpFileTaken))
+ {
+ await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(_dumpFileTaken), ExtensionResources.HangDumpArtifactDisplayName, ExtensionResources.HangDumpArtifactDescription));
+ }
+ }
+
+ private async Task ActivityTimerAsync()
+ {
+ _logger.LogDebug($"Wait for mutex name from the test host");
+
+ if (!_mutexNameReceived.Wait(TimeoutHelper.DefaultHangTimeSpanTimeout))
+ {
+ throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.MutexNameReceptionTimeoutErrorMessage, TimeoutHelper.DefaultHangTimeoutSeconds));
+ }
+
+ ApplicationStateGuard.Ensure(_activityTimerMutexName is not null);
+
+ _logger.LogDebug($"Open activity mutex '{_activityTimerMutexName}'");
+
+ if (!Mutex.TryOpenExisting(_activityTimerMutexName, out _activityIndicatorMutex))
+ {
+ throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.MutexDoesNotExistErrorMessage, _activityTimerMutexName));
+ }
+
+ bool timeoutFired = false;
+ try
+ {
+ // Don't wait in async in the while, we need thread affinity for the mutex
+ while (true)
+ {
+ if (_traceEnabled)
+ {
+ _logger.LogTrace($"Wait for activity signal");
+ }
+
+ if (!_activityIndicatorMutex.WaitOne(_activityTimerValue))
+ {
+ timeoutFired = true;
+ break;
+ }
+
+ if (_traceEnabled)
+ {
+ _logger.LogTrace($"Activity signal received by the test host '{_clock.UtcNow}'");
+ }
+
+ // We don't release in case of exit because we will release after the timeout check to unblock the client and exit the task
+ if (_exitActivityIndicatorTask)
+ {
+ break;
+ }
+ else
+ {
+ _activityIndicatorMutex.ReleaseMutex();
+ }
+ }
+
+ if (_traceEnabled)
+ {
+ _logger.LogTrace($"Exit 'ActivityTimerAsync'");
+ }
+ }
+ catch (AbandonedMutexException)
+ {
+ // If the mutex is abandoned from the test host crash we will get an exception
+ _logger.LogDebug($"Mutex '{_activityTimerMutexName}' is abandoned");
+ }
+ catch (ObjectDisposedException)
+ {
+ // If test host exit in a non gracefully way on process exit we dispose the mutex to unlock the activity timer.
+ // In this way we release also the dispose.
+ _logger.LogDebug($"Mutex '{_activityTimerMutexName}' is disposed");
+ }
+
+ if (!timeoutFired)
+ {
+ try
+ {
+ _logger.LogDebug($"Timeout is not fired release activity mutex handle to allow test host to close");
+ _activityIndicatorMutex.ReleaseMutex();
+ }
+ catch (AbandonedMutexException)
+ {
+ // If the mutex is abandoned from the test host crash we will get an exception
+ _logger.LogDebug($"Mutex '{_activityTimerMutexName}' is abandoned, during last release");
+ }
+ catch (ObjectDisposedException)
+ {
+ // If test host exit in a non gracefully way on process exit we dispose the mutex to unlock the activity timer.
+ _logger.LogDebug($"Mutex '{_activityTimerMutexName}' is disposed, during last release");
+ }
+ }
+
+ _activityIndicatorMutex.Dispose();
+ _logger.LogDebug($"Activity indicator disposed");
+
+ if (timeoutFired)
+ {
+ await TakeDumpAsync();
+ }
+ }
+
+ 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, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(string.Format(CultureInfo.InvariantCulture, ExtensionResources.HangDumpTimeoutExpired, _activityTimerValue)));
+
+ 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);
+ 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, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(ExtensionResources.RunningTestsWhileDumping));
+ foreach ((string testName, int seconds) in tests.Tests)
+ {
+ await sw.WriteLineAsync($"[{TimeSpan.FromSeconds(seconds)}] {testName}");
+ await _outputDisplay.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText($"[{TimeSpan.FromSeconds(seconds)}] {testName}"));
+ }
+ }
+
+ await _messageBus.PublishAsync(this, new FileArtifact(new FileInfo(hangTestsFileName), ExtensionResources.HangTestListArtifactDisplayName, ExtensionResources.HangTestListArtifactDescription));
+ }
+
+ await _logger.LogInformationAsync($"Creating dump filename {finalDumpFileName}");
+
+ await _outputDisplay.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(string.Format(CultureInfo.InvariantCulture, ExtensionResources.CreatingDumpFile, finalDumpFileName)));
+
+#if NETCOREAPP
+ DiagnosticsClient diagnosticsClient = new(_testHostProcessInformation.PID);
+ DumpType dumpType = _dumpType.ToLowerInvariant().Trim() switch
+ {
+ "mini" => DumpType.Normal,
+ "heap" => DumpType.WithHeap,
+ "triage" => DumpType.Triage,
+ "full" => DumpType.Full,
+ _ => throw ApplicationStateGuard.Unreachable(),
+ };
+
+ diagnosticsClient.WriteDump(dumpType, finalDumpFileName, true);
+ NotifyCrashDumpServiceIfEnabled();
+ using IProcess process = _processHandler.GetProcessById(_testHostProcessInformation.PID);
+ process.Kill();
+ await process.WaitForExitAsync();
+
+#else
+ MiniDumpWriteDump.MiniDumpTypeOption miniDumpTypeOption = _dumpType.ToLowerInvariant().Trim() switch
+ {
+ "mini" => MiniDumpWriteDump.MiniDumpTypeOption.Mini,
+ "heap" => MiniDumpWriteDump.MiniDumpTypeOption.Heap,
+ "full" => MiniDumpWriteDump.MiniDumpTypeOption.Full,
+ _ => throw ApplicationStateGuard.Unreachable(),
+ };
+
+ MiniDumpWriteDump.CollectDumpUsingMiniDumpWriteDump(_testHostProcessInformation.PID, finalDumpFileName, miniDumpTypeOption);
+ NotifyCrashDumpServiceIfEnabled();
+ using IProcess process = _processHandler.GetProcessById(_testHostProcessInformation.PID);
+ process.Kill();
+ process.WaitForExit();
+#endif
+ _dumpFileTaken = finalDumpFileName;
+ }
+
+ private static void NotifyCrashDumpServiceIfEnabled()
+ => AppDomain.CurrentDomain.SetData("ProcessKilledByHangDump", "true");
+
+ public void Dispose()
+ {
+ if (_activityIndicatorTask is not null)
+ {
+ if (!_activityIndicatorTask.Wait(TimeoutHelper.DefaultHangTimeSpanTimeout))
+ {
+ throw new InvalidOperationException($"_activityIndicatorTask didn't exit in {TimeoutHelper.DefaultHangTimeSpanTimeout} seconds");
+ }
+ }
+
+ _namedPipeClient?.Dispose();
+ _waitConsumerPipeName.Dispose();
+ _mutexNameReceived.Dispose();
+ _singleConnectionNamedPipeServer?.Dispose();
+ _pipeNameDescription.Dispose();
+ }
+
+#if NETCOREAPP
+ public async ValueTask DisposeAsync()
+ {
+ if (_activityIndicatorTask is not null)
+ {
+ await _activityIndicatorTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout);
+ }
+
+ _namedPipeClient?.Dispose();
+ _waitConsumerPipeName.Dispose();
+ _mutexNameReceived.Dispose();
+ _singleConnectionNamedPipeServer?.Dispose();
+ _pipeNameDescription.Dispose();
+ }
+#endif
+}
diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/FNV1HashHelper.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Helpers/FNV1HashHelper.cs
similarity index 100%
rename from src/Platform/Microsoft.Testing.Platform/Helpers/FNV1HashHelper.cs
rename to src/Platform/Microsoft.Testing.Extensions.HangDump/Helpers/FNV1HashHelper.cs
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Microsoft.Testing.Extensions.HangDump.csproj b/src/Platform/Microsoft.Testing.Extensions.HangDump/Microsoft.Testing.Extensions.HangDump.csproj
new file mode 100644
index 0000000000..9abaf2d2d5
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Microsoft.Testing.Extensions.HangDump.csproj
@@ -0,0 +1,70 @@
+
+
+
+ netstandard2.0;$(MicrosoftTestingTargetFrameworks)
+ Microsoft.Testing.Extensions.Diagnostics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ buildMultiTargeting
+
+
+ buildTransitive/$(TargetFramework)
+
+
+ build/$(TargetFramework)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ ExtensionResources.resx
+
+
+ True
+ True
+ ExtensionResources.resx
+
+
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ ExtensionResources.Designer.cs
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/PACKAGE.md b/src/Platform/Microsoft.Testing.Extensions.HangDump/PACKAGE.md
new file mode 100644
index 0000000000..776c34d531
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/PACKAGE.md
@@ -0,0 +1,9 @@
+# Microsoft.Testing
+
+Microsoft Testing is a set of platform, framework and protocol intended to make it possible to run any test on any target or device.
+
+Documentation can be found at .
+
+## About
+
+This package provides Windows Hang dump extensions to Microsoft Testing Platform.
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/PublicAPI/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.HangDump/PublicAPI/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..9a6866965b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/PublicAPI/PublicAPI.Shipped.txt
@@ -0,0 +1,5 @@
+#nullable enable
+Microsoft.Testing.Extensions.HangDumpExtensions
+Microsoft.Testing.Extensions.HangDump.TestingPlatformBuilderHook
+static Microsoft.Testing.Extensions.HangDump.TestingPlatformBuilderHook.AddExtensions(Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! testApplicationBuilder, string![]! _) -> void
+static Microsoft.Testing.Extensions.HangDumpExtensions.AddHangDumpProvider(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder) -> void
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/PublicAPI/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.HangDump/PublicAPI/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..7dc5c58110
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/PublicAPI/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/ExtensionResources.Designer.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/ExtensionResources.Designer.cs
new file mode 100644
index 0000000000..c96af79b89
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/ExtensionResources.Designer.cs
@@ -0,0 +1,252 @@
+//------------------------------------------------------------------------------
+//
+// 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.Testing.Extensions.Diagnostics.Resources {
+ 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 ExtensionResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal ExtensionResources() {
+ }
+
+ ///
+ /// 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.Testing.Extensions.Diagnostics.Resources.ExtensionResources", typeof(ExtensionResources).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 Creating dump file '{0}'.
+ ///
+ internal static string CreatingDumpFile {
+ get {
+ return ResourceManager.GetString("CreatingDumpFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The hang dump file.
+ ///
+ internal static string HangDumpArtifactDescription {
+ get {
+ return ResourceManager.GetString("HangDumpArtifactDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Hang dump file.
+ ///
+ internal static string HangDumpArtifactDisplayName {
+ get {
+ return ResourceManager.GetString("HangDumpArtifactDisplayName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Environment variable '{0}' is set to '{1}' instead of '{2}'.
+ ///
+ internal static string HangDumpEnvironmentVariableInvalidValueErrorMessage {
+ get {
+ return ResourceManager.GetString("HangDumpEnvironmentVariableInvalidValueErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Environment variable '{0}' is not set.
+ ///
+ internal static string HangDumpEnvironmentVariableIsMissingErrorMessage {
+ get {
+ return ResourceManager.GetString("HangDumpEnvironmentVariableIsMissingErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Produce hang dump files when a test execution exceed a given time..
+ ///
+ internal static string HangDumpExtensionDescription {
+ get {
+ return ResourceManager.GetString("HangDumpExtensionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Hang dump.
+ ///
+ internal static string HangDumpExtensionDisplayName {
+ get {
+ return ResourceManager.GetString("HangDumpExtensionDisplayName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specify the name of the dump file.
+ ///
+ internal static string HangDumpFileNameOptionDescription {
+ get {
+ return ResourceManager.GetString("HangDumpFileNameOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Generate a dump file if the test process hangs.
+ ///
+ internal static string HangDumpOptionDescription {
+ get {
+ return ResourceManager.GetString("HangDumpOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Hang dump timeout of '{0}' expired.
+ ///
+ internal static string HangDumpTimeoutExpired {
+ get {
+ return ResourceManager.GetString("HangDumpTimeoutExpired", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m..
+ ///
+ internal static string HangDumpTimeoutOptionDescription {
+ get {
+ return ResourceManager.GetString("HangDumpTimeoutOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to '--hangdump-timeout' expects a single timeout argument.
+ ///
+ internal static string HangDumpTimeoutOptionInvalidArgument {
+ get {
+ return ResourceManager.GetString("HangDumpTimeoutOptionInvalidArgument", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'.
+ ///
+ internal static string HangDumpTypeOptionDescription {
+ get {
+ return ResourceManager.GetString("HangDumpTypeOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'.
+ ///
+ internal static string HangDumpTypeOptionInvalidType {
+ get {
+ return ResourceManager.GetString("HangDumpTypeOptionInvalidType", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Request of type '{0}' is not supported.
+ ///
+ internal static string HangDumpUnsupportedRequestTypeErrorMessage {
+ get {
+ return ResourceManager.GetString("HangDumpUnsupportedRequestTypeErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The list of tests that were running at the time of the hang.
+ ///
+ internal static string HangTestListArtifactDescription {
+ get {
+ return ResourceManager.GetString("HangTestListArtifactDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Hang test list.
+ ///
+ internal static string HangTestListArtifactDisplayName {
+ get {
+ return ResourceManager.GetString("HangTestListArtifactDisplayName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line.
+ ///
+ internal static string MissingHangDumpMainOption {
+ get {
+ return ResourceManager.GetString("MissingHangDumpMainOption", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot find mutex '{0}'.
+ ///
+ internal static string MutexDoesNotExistErrorMessage {
+ get {
+ return ResourceManager.GetString("MutexDoesNotExistErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Mutex name wasn't received after '{0}' seconds.
+ ///
+ internal static string MutexNameReceptionTimeoutErrorMessage {
+ get {
+ return ResourceManager.GetString("MutexNameReceptionTimeoutErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):.
+ ///
+ internal static string RunningTestsWhileDumping {
+ get {
+ return ResourceManager.GetString("RunningTestsWhileDumping", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/ExtensionResources.resx b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/ExtensionResources.resx
new file mode 100644
index 0000000000..f45192fefc
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/ExtensionResources.resx
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Creating dump file '{0}'
+
+
+ The hang dump file
+
+
+ Hang dump file
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+
+
+ Environment variable '{0}' is not set
+
+
+ Produce hang dump files when a test execution exceed a given time.
+
+
+ Hang dump
+
+
+ Specify the name of the dump file
+
+
+ Generate a dump file if the test process hangs
+
+
+ Hang dump timeout of '{0}' expired
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+
+
+ '--hangdump-timeout' expects a single timeout argument
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+
+
+ Request of type '{0}' is not supported
+
+
+ The list of tests that were running at the time of the hang
+
+
+ Hang test list
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+
+
+ Cannot find mutex '{0}'
+
+
+ Mutex name wasn't received after '{0}' seconds
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.cs.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.cs.xlf
new file mode 100644
index 0000000000..112c1e3635
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.cs.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ Vytváří se soubor výpisu paměti {0}.
+
+
+
+ The hang dump file
+ Soubor výpisu paměti při zablokování
+
+
+
+ Hang dump file
+ Soubor výpisu paměti při zablokování
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ Proměnná prostředí {0} je nastavená na {1} místo na {2}.
+
+
+
+ Environment variable '{0}' is not set
+ Není nastavená proměnná prostředí {0}.
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ Vytvoří soubory výpisu paměti při zablokování, když provádění testu překročí danou dobu.
+
+
+
+ Hang dump
+ Výpis paměti při zablokování
+
+
+
+ Specify the name of the dump file
+ Zadejte název souboru výpisu paměti.
+
+
+
+ Generate a dump file if the test process hangs
+ Vygeneruje soubor výpisu paměti, pokud testovací proces přestane reagovat.
+
+
+
+ Hang dump timeout of '{0}' expired
+ Vypršel časový limit {0} pro výpis paměti při zablokování.
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ Zadejte časový limit, po kterém bude vygenerován výpis paměti. Hodnota časového limitu se zadává v jednom z následujících formátů: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Výchozí hodnota je 30m.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ --hangdump-timeout očekává jeden argument časového limitu.
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ Zadejte typ výpisu paměti. Platné hodnoty jsou Mini, Heap, Triage (dostupné pouze v .NET 6+) nebo Full. Výchozí typ je Full.
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ {0} není platný typ výpisu paměti. Platné možnosti jsou Mini, Heap, Triage (k dispozici pouze v .NET 6+) a Full.
+
+
+
+ Request of type '{0}' is not supported
+ Žádost typu {0} není podporována.
+
+
+
+ The list of tests that were running at the time of the hang
+ Seznam testů spuštěných v době zablokování
+
+
+
+ Hang test list
+ Seznam testů při zablokování
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ Zadali jste jeden nebo více parametrů výpisu stavu systému, ale nepovolili jste ho. Přidejte do příkazového řádku parametr --hangdump
+
+
+
+ Cannot find mutex '{0}'
+ Objekt mutex {0} nebyl nalezen.
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ Název objektu mutex nebyl přijat po {0} s.
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ Při pořízení výpisu paměti stále běžely následující testy (formát: [<čas-uplynulý-od-spuštění>] <název>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.de.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.de.xlf
new file mode 100644
index 0000000000..05215a521e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.de.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ Speicherabbilddatei "{0}" wird erstellt
+
+
+
+ The hang dump file
+ Die Absturzspeicherabbilddatei
+
+
+
+ Hang dump file
+ Absturzspeicherabbilddatei
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ Umgebungsvariable "{0}" ist auf "{1}" anstatt auf "{2}" festgelegt.
+
+
+
+ Environment variable '{0}' is not set
+ Die Umgebungsvariable "{0}" wurde nicht festgelegt
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ Absturzspeicherabbilddateien erstellen, wenn eine Testausführung eine angegebene Zeit überschreitet.
+
+
+
+ Hang dump
+ Absturzspeicherabbild
+
+
+
+ Specify the name of the dump file
+ Namen der Speicherabbilddatei angeben
+
+
+
+ Generate a dump file if the test process hangs
+ Speicherabbilddatei generieren, wenn der Testprozess abstürzt
+
+
+
+ Hang dump timeout of '{0}' expired
+ Timeout für Absturzspeicherabbild von "{0}" abgelaufen
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ Geben Sie das Timeout an, nach dem das Speicherabbild generiert wird. Der Timeoutwert wird in einem der folgenden Formate angegeben: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Der Standardwert ist 30m.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ "--hangdump-timeout" erwartet ein einzelnes Timeoutargument.
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ Geben Sie den Typ des Speicherabbilds an. Gültige Werte sind "Mini", "Heap", "Triage" (nur in .NET 6 und höher verfügbar) oder "Full". Der Standardtyp ist "Full".
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ "{0}" ist kein gültiger Speicherabbildtyp. Gültige Optionen sind "Mini", "Heap", "Triage" (nur in .NET 6 und höher verfügbar) und "Full".
+
+
+
+ Request of type '{0}' is not supported
+ Anforderung vom Typ "{0}" wird nicht unterstützt
+
+
+
+ The list of tests that were running at the time of the hang
+ Die Liste der Tests, die zum Zeitpunkt des Absturzes ausgeführt wurden.
+
+
+
+ Hang test list
+ Liste der Tests bei Absturz
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ Sie haben mindestens einen Parameter für das Absturzabbild angegeben, aber nicht aktiviert. Fügen Sie der Befehlszeile „--hangdump“ hinzu.
+
+
+
+ Cannot find mutex '{0}'
+ Mutex "{0}" wurde nicht gefunden
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ Der Mutexname wurde nach "{0}" Sekunden nicht empfangen.
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ Die folgenden Tests wurden noch ausgeführt, als das Speicherabbild erstellt wurde (Format: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.es.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.es.xlf
new file mode 100644
index 0000000000..8425c1a4a4
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.es.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ Creando archivo de volcado '{0}'
+
+
+
+ The hang dump file
+ El archivo de volcado de memoria
+
+
+
+ Hang dump file
+ Archivo de volcado de bloqueo
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ La variable de entorno '{0}' se establece en '{1}' en lugar de '{2}'
+
+
+
+ Environment variable '{0}' is not set
+ La variable de entorno '{0}' no está establecida
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ Genere archivos de volcado de memoria cuando una ejecución de prueba supere un tiempo determinado.
+
+
+
+ Hang dump
+ Volcado de memoria
+
+
+
+ Specify the name of the dump file
+ Especificar el nombre del archivo de volcado
+
+
+
+ Generate a dump file if the test process hangs
+ Generar un archivo de volcado si el proceso de prueba se bloquea
+
+
+
+ Hang dump timeout of '{0}' expired
+ Tiempo de espera de volcado de bloqueo de '{0}' expirado
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ Especifique el tiempo de espera después del cual se generará el volcado. El valor de tiempo de espera se especifica en uno de los formatos siguientes: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. El valor predeterminado es 30 m.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ '--hangdump-timeout' espera un único argumento de tiempo de espera
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ Especifique el tipo de volcado. Los valores válidos son "Mini", "Heap", "Triage" (solo disponible en .NET 6+) o "Full". El tipo predeterminado es 'Full'
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ '{0}' no es un tipo de volcado válido. Las opciones válidas son "Mini", "Montón", "Evaluación de prioridades" (solo disponible en .NET 6+) y "Full"
+
+
+
+ Request of type '{0}' is not supported
+ No se admite la solicitud de tipo '{0}'
+
+
+
+ The list of tests that were running at the time of the hang
+ Lista de pruebas que se estaban ejecutando en el momento del bloqueo
+
+
+
+ Hang test list
+ Lista de pruebas de bloqueo
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ Ha especificado uno o varios parámetros de volcado de memoria, pero no los ha habilitado. Agregue --hangdump a la línea de comandos.
+
+
+
+ Cannot find mutex '{0}'
+ No se encuentra la exclusión mutua '{0}'
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ No se recibió el nombre de exclusión mutua después de '{0}' segundos
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ Las siguientes pruebas aún se estaban ejecutando cuando se realizó el volcado (formato: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.fr.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.fr.xlf
new file mode 100644
index 0000000000..93e8e8ab43
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.fr.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ Création du fichier de vidage «{0}»
+
+
+
+ The hang dump file
+ Fichier de vidage de blocage
+
+
+
+ Hang dump file
+ Bloquer le fichier de vidage
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ La variable d’environnement «{0}» a la valeur «{1}» au lieu de «{2}»
+
+
+
+ Environment variable '{0}' is not set
+ La variable d’environnement '{0}' n’est pas définie
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ Produire des fichiers de vidage de blocage lorsqu’une exécution de test dépasse un délai donné.
+
+
+
+ Hang dump
+ Blocage de l’image mémoire
+
+
+
+ Specify the name of the dump file
+ Spécifier le nom du fichier de vidage
+
+
+
+ Generate a dump file if the test process hangs
+ Générer un fichier de vidage si le processus de test se bloque
+
+
+
+ Hang dump timeout of '{0}' expired
+ Expiration du délai d’expiration du vidage du blocage de «{0}»
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ Spécifiez le délai d’expiration après lequel le vidage sera généré. La valeur du délai d'attente est spécifiée dans l'un des formats suivants : 1,5 h, 1,5 heure, 1,5 heure, 90 m, 90 min, 90 minutes, 90 minutes 5 400 s, 5 400 s, 5 400 secondes, 5 400 secondes. La valeur par défaut est 30 m.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ '--hangdump-timeout' attend un seul argument de délai d'attente
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ Spécifiez le type de l’image mémoire. Les valeurs valides sont « Mini », « Heap », « Triage » (uniquement disponible dans .NET 6+) ou « Full ». Le type par défaut est ' Full'
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ '{0}' n’est pas un type de vidage valide. Les options valides sont « Mini », « Heap », « Triage » (uniquement disponible dans .NET 6+) et « Full »
+
+
+
+ Request of type '{0}' is not supported
+ La requête de type '{0}' n’est pas prise en charge
+
+
+
+ The list of tests that were running at the time of the hang
+ Liste des tests en cours d’exécution au moment du blocage
+
+
+
+ Hang test list
+ Bloquer la liste de tests
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ Vous avez spécifié un ou plusieurs paramètres de vidage sur blocage, mais vous ne l’avez pas activé. Ajoutez --hangdump à la ligne de commande
+
+
+
+ Cannot find mutex '{0}'
+ Impossible de trouver le mutex '{0}'
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ Le nom du mutex n'a pas été reçu après « {0} » secondes
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ Les tests suivants étaient toujours en cours d'exécution au moment du vidage (format : [<time-elapsed-since-start>] <name>) :
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.it.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.it.xlf
new file mode 100644
index 0000000000..380c07d2a5
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.it.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ Creazione del file di dump '{0}'
+
+
+
+ The hang dump file
+ Il file di dump di blocco
+
+
+
+ Hang dump file
+ File dump di blocco
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ La variabile di ambiente '{0}' è impostata su '{1}' anziché su '{2}'
+
+
+
+ Environment variable '{0}' is not set
+ La variabile di ambiente '{0}' non è impostata
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ Genera file di dump di blocco quando l'esecuzione di un test supera un determinato periodo di tempo.
+
+
+
+ Hang dump
+ Dump di blocco
+
+
+
+ Specify the name of the dump file
+ Specificare il nome del file di dump
+
+
+
+ Generate a dump file if the test process hangs
+ Generare un file di dump se il processo di test si blocca
+
+
+
+ Hang dump timeout of '{0}' expired
+ Timeout dump di blocco di '{0}' scaduto
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ Specificare il timeout dopo il quale verrà generato il dump. Il valore di timeout è specificato in uno dei seguenti formati: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Il valore predefinito è 30m.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ '--hangdump-timeout' prevede un singolo argomento di timeout
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ Specificare il tipo di dump. I valori ammessi sono 'Mini', 'Heap', 'Triage' (disponibile solo in .NET 6+) o 'Full'. Il tipo predefinito è 'Full'
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ '{0}' non è un tipo di dump valido. Le opzioni valide sono 'Mini', 'Heap', 'Triage' (disponibile solo in .NET 6+) e 'Full'.
+
+
+
+ Request of type '{0}' is not supported
+ La richiesta di tipo '{0}' non è supportata
+
+
+
+ The list of tests that were running at the time of the hang
+ Elenco di test in esecuzione al momento del blocco
+
+
+
+ Hang test list
+ Blocca elenco dei test
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ Sono stati specificati uno o più parametri del dump di blocco ma non sono stati abilitati. Aggiungere --hangdump alla riga di comando
+
+
+
+ Cannot find mutex '{0}'
+ Non è possibile trovare il mutex '{0}'
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ Il nome del mutex non è stato ricevuto dopo '{0}' secondi
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ I seguenti test erano ancora in esecuzione quando è stato eseguito il dump (formato: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.ja.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.ja.xlf
new file mode 100644
index 0000000000..94c5b0ac56
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.ja.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ ダンプ ファイル '{0}' を作成しています
+
+
+
+ The hang dump file
+ ハング ダンプ ファイル
+
+
+
+ Hang dump file
+ ハング ダンプ ファイル
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ 環境変数 '{0}' は '{2}' ではなく '{1}' に設定されています
+
+
+
+ Environment variable '{0}' is not set
+ 環境変数 '{0}' が設定されていません
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ テストの実行が指定された時間を超えたときにハング ダンプ ファイルを生成します。
+
+
+
+ Hang dump
+ ハング ダンプ
+
+
+
+ Specify the name of the dump file
+ ダンプ ファイルの名前を指定する
+
+
+
+ Generate a dump file if the test process hangs
+ テスト プロセスがハングした場合にダンプ ファイルを生成する
+
+
+
+ Hang dump timeout of '{0}' expired
+ '{0}' のハング ダンプ タイムアウトの有効期限が切れました
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ ダンプが生成されるまでのタイムアウトを指定します。タイムアウト値は、次のいずれかの形式で指定されます 1.5h、1.5hour、1.5hours、90m、90min、90minute、90minutes、5400s、5400sec、5400second、5400seconds.。既定値は 30m です。
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ '--hangdump-timeout' には 1 つのタイムアウト引数が必要です
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ ダンプの型を指定します。有効な値は、'Mini'、'Heap'、'Triage' (.NET 6 以降でのみ利用可能)、または 'Full' です。既定の型は 'Full' です
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ '{0}' は有効なダンプの種類ではありません。有効なオプションは、'Mini'、'Heap'、'Triage' (.NET 6 以降でのみ利用可能)、'Full' です
+
+
+
+ Request of type '{0}' is not supported
+ 型 '{0}' の要求はサポートされていません
+
+
+
+ The list of tests that were running at the time of the hang
+ ハング時に実行されていたテストの一覧
+
+
+
+ Hang test list
+ ハング テスト リスト
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ 1 つ以上のハング ダンプ パラメーターを指定しましたが、有効にしませんでした。コマンド ラインに --hangdump を追加してください
+
+
+
+ Cannot find mutex '{0}'
+ ミューテックス '{0}' が見つかりません
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ '{0}' 秒後にミューテックス名が受信されませんでした
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ ダンプの取得時に次のテストがまだ実行されていました (形式: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.ko.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.ko.xlf
new file mode 100644
index 0000000000..6180f67109
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.ko.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ 덤프 파일 '{0}'을(를) 만드는 중
+
+
+
+ The hang dump file
+ 중단 덤프 파일
+
+
+
+ Hang dump file
+ 중단 덤프 파일
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ 환경 변수 '{0}'이(가) '{2}' 대신 '{1}'로 설정되어 있습니다.
+
+
+
+ Environment variable '{0}' is not set
+ 환경 변수 ‘{0}’이(가) 설정되지 않았습니다.
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ 테스트 실행이 지정된 시간을 초과하면 중단 덤프 파일을 생성합니다.
+
+
+
+ Hang dump
+ 덤프 중단
+
+
+
+ Specify the name of the dump file
+ 덤프 파일의 이름 지정
+
+
+
+ Generate a dump file if the test process hangs
+ 테스트 프로세스가 중단되면 덤프 파일 생성
+
+
+
+ Hang dump timeout of '{0}' expired
+ '{0}'의 중단 덤프 시간 제한이 만료되었습니다.
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ 덤프가 생성되기 전까지의 시간 제한을 지정합니다. 시간 제한 값은 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds 형식 중 하나로 지정됩니다. 기본값은 30m입니다.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ '--hangdump-timeout'에는 단일 시간 제한 인수가 필요합니다.
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ 덤프 유형을 지정하십시오. 유효한 값은 'Mini', 'Heap', 'Triage'(.NET 6 이상에서만 사용 가능) 또는 'Full'입니다. 기본 유형은 'Full'입니다.
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ '{0}'은(는) 올바른 덤프 유형이 아닙니다. 유효한 옵션은 'Mini', 'Heap', 'Triage'(.NET 6 이상에서만 사용 가능) 및 'Full'입니다.
+
+
+
+ Request of type '{0}' is not supported
+ '{0}' 유형의 요청은 지원되지 않습니다.
+
+
+
+ The list of tests that were running at the time of the hang
+ 중단 시 실행된 테스트 목록입니다.
+
+
+
+ Hang test list
+ 테스트 목록 중단
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ 하나 이상의 중단 덤프 매개 변수를 지정했지만 사용하도록 설정하지 않았습니다. 명령줄에 --hangdump를 추가하세요.
+
+
+
+ Cannot find mutex '{0}'
+ 뮤텍스 '{0}'을(를) 찾을 수 없습니다.
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ '{0}' 초 후에 뮤텍스 이름을 받지 못했습니다.
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ 덤프를 수행할 때 다음 테스트가 계속 실행되고 있었습니다(형식: [<time-elapsed-since-start>] <name>).
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.pl.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.pl.xlf
new file mode 100644
index 0000000000..3490170209
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.pl.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ Tworzenie pliku zrzutu „{0}”
+
+
+
+ The hang dump file
+ Plik zrzutu zawieszenia
+
+
+
+ Hang dump file
+ Zawieszanie pliku zrzutu
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ Zmienna środowiskowa „{0}” jest ustawiona na wartość „{1}” zamiast „{2}”
+
+
+
+ Environment variable '{0}' is not set
+ Zmienna środowiskowa „{0}” nie jest ustawiona
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ Utwórz pliki zrzutu zawieszenia, gdy wykonanie testu przekroczy dany czas.
+
+
+
+ Hang dump
+ Zrzut zawieszenia
+
+
+
+ Specify the name of the dump file
+ Określ nazwę pliku zrzutu
+
+
+
+ Generate a dump file if the test process hangs
+ Wygeneruj plik zrzutu, jeśli proces testowy zawiesza się
+
+
+
+ Hang dump timeout of '{0}' expired
+ Upłynął limit czasu zrzutu zawieszenia „{0}”
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ Określ limit czasu, po którym zostanie wygenerowany zrzut. Wartość limitu czasu jest określona w jednym z następujących formatów: 1,5 godziny, 1,5 godziny, 90 m, 90 min, 90 minut, 90 minut 5400 s, 5400 s, 5400 sekund, 5400 sekund, 5400 sekund. Wartość domyślna to 30 m.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ Element „--hangdump-timeout” oczekuje pojedynczego argumentu limitu czasu
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ Określ typ zrzutu. Prawidłowe wartości to "Mini", "Heap", "Triage" (dostępne tylko na platformie .NET 6+) lub „Pełne”. Domyślny typ to „Pełne”
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ Typ „{0}” nie jest prawidłowym typem zrzutu. Prawidłowe opcje to „Mini”, „Sterta", "Klasyfikacja" (dostępne tylko na platformie .NET 6+) i „Pełne”
+
+
+
+ Request of type '{0}' is not supported
+ Żądanie typu „{0}” nie jest obsługiwane
+
+
+
+ The list of tests that were running at the time of the hang
+ Lista testów, które były uruchamiane w czasie zawieszenia
+
+
+
+ Hang test list
+ Lista testów zawieszenia
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ Określono co najmniej jeden parametr zrzutu zawieszenia, ale go nie włączono. Dodaj parametr --hangdump do wiersza polecenia
+
+
+
+ Cannot find mutex '{0}'
+ Nie można odnaleźć obiektu mutex „{0}”
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ Nazwa obiektu Mutex nie została odebrana po „{0}” s
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ Następujące testy były nadal uruchomione podczas wykonywania zrzutu (format: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.pt-BR.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.pt-BR.xlf
new file mode 100644
index 0000000000..8c09bfb0f4
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.pt-BR.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ Criando arquivo de despejo ''{0}''
+
+
+
+ The hang dump file
+ O arquivo de despejo de travamento
+
+
+
+ Hang dump file
+ Arquivo de despejo de travamento
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ A variável de ambiente ''{0}'' ambiente está definida como ''{1}'' em vez de ''{2}''
+
+
+
+ Environment variable '{0}' is not set
+ A variável de ambiente ''{0}'' não está definida
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ Produzir arquivos de despejo de travamento quando uma execução de teste exceder um determinado tempo.
+
+
+
+ Hang dump
+ Despejo de travamento
+
+
+
+ Specify the name of the dump file
+ Especifique o nome do arquivo de despejo
+
+
+
+ Generate a dump file if the test process hangs
+ Gerar um arquivo de despejo se o processo de teste travar
+
+
+
+ Hang dump timeout of '{0}' expired
+ Tempo limite de despejo de travamento de ''{0}'' expirado
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ Especifique o tempo limite após o qual o despejo será gerado. O valor de tempo limite é especificado em um dos seguintes formatos: 1.5h, 1,5hora, 1,5horas, 90m, 90min, 90minuto, 90minutos 5400s, 5400seg, 5400segundo, 5400segundos. O padrão é 30m.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ ''--hangdump-timeout'' espera um único argumento de tempo limite
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ Especifique o tipo de despejo. Os valores válidos são ''Mini'', ''Heap'', ''Triage'' (disponível somente no .NET 6+) e ''Full'' O tipo padrão é ''Full''
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ ''{0}'' não é um tipo de despejo válido. As opções válidas são ''Mini'', ''Heap'', ''Triage'' (disponível somente no .NET 6+) e ''Full''
+
+
+
+ Request of type '{0}' is not supported
+ Não há suporte para a solicitação do tipo ''{0}''
+
+
+
+ The list of tests that were running at the time of the hang
+ A lista de testes que estavam sendo executados no momento do travamento
+
+
+
+ Hang test list
+ Lista de testes de travamento
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ Você especificou um ou mais parâmetros de hang dump, mas não os ativou, adicione --hangdump à linha de comando
+
+
+
+ Cannot find mutex '{0}'
+ Não é possível localizar o mutex ''{0}''
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ O nome do mutex não foi recebido após ''{0}'' segundos
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ Os testes a seguir ainda estavam em execução quando o despejo foi realizado (formato: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.ru.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.ru.xlf
new file mode 100644
index 0000000000..77323c6f4d
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.ru.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ Создание файла дампа "{0}"
+
+
+
+ The hang dump file
+ Файл дампа зависания
+
+
+
+ Hang dump file
+ Файл дампа зависания
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ Переменной среды "{0}" присвоено значение "{1}" вместо "{2}"
+
+
+
+ Environment variable '{0}' is not set
+ Переменная среды "{0}" не задана
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ Создавать файлы дампа зависания при превышении заданного времени выполнения теста.
+
+
+
+ Hang dump
+ Дамп зависания
+
+
+
+ Specify the name of the dump file
+ Укажите имя файла дампа зависания
+
+
+
+ Generate a dump file if the test process hangs
+ Создавать файл дампа, если тестовый процесс завис
+
+
+
+ Hang dump timeout of '{0}' expired
+ Истекло время ожидания дампа зависания "{0}"
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ Укажите время ожидания, по истечении которого будет создан дамп. Значение времени ожидания указано в одном из следующих форматов: 1,5 ч, 1,5 часа, 90 м, 90 мин, 90 минут, 5400 с, 5400 сек, 5400 секунд. Значение по умолчанию — 30 м.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ "--hangdump-timeout" ожидает один аргумент времени ожидания
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ Укажите тип дампа. Допустимые значения: "Mini", "Heap", "Triage" (доступно только в .NET 6+) или "Full". Тип по умолчанию — "Full"
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ "{0}" не является допустимым типом дампа. Допустимые параметры: "Mini", "Heap", "Triage" (доступно только в .NET 6+) и "Full"
+
+
+
+ Request of type '{0}' is not supported
+ Запрос типа "{0}" не поддерживается
+
+
+
+ The list of tests that were running at the time of the hang
+ Список тестов, которые были запущены во время зависания
+
+
+
+ Hang test list
+ Список тестов зависаний
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ Вы указали один или несколько параметров дампа зависания, но не включили его. Добавьте --hangdump в командную строку
+
+
+
+ Cannot find mutex '{0}'
+ Не удается найти мьютекс "{0}".
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ Имя мьютекса не было получено через "{0}" секунд
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ При создании дампа все еще выполнялись следующие тесты (формат: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.tr.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.tr.xlf
new file mode 100644
index 0000000000..0d24f38d3c
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.tr.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ Döküm dosyası '{0}' oluşturuluyor
+
+
+
+ The hang dump file
+ Askıda kalma dökümü dosyası
+
+
+
+ Hang dump file
+ Döküm dosyasını as
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ '{0}' ortam değişkeni '{1}' yerine '{2}' olarak ayarlandı
+
+
+
+ Environment variable '{0}' is not set
+ '{0}' ortam değişkeni ayarlı değil
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ Bir test yürütmesi belirli bir süreyi aştığında askıda kalan döküm dosyaları üretin.
+
+
+
+ Hang dump
+ Askı dökümü
+
+
+
+ Specify the name of the dump file
+ Döküm dosyasının adını belirtin
+
+
+
+ Generate a dump file if the test process hangs
+ Test işlemi kilitlenirse bir döküm dosyası oluşturun
+
+
+
+ Hang dump timeout of '{0}' expired
+ '{0}' dökümünün askıda kalma zaman aşımı süresi doldu
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ Dökümün oluşturulacağı zaman aşımını belirtin. Zaman aşımı değeri şu formatlardan birinde belirtilir: 1,5 saat, 1,5 saat, 1,5 saat, 90 dakika, 90 dakika, 90 dakika, 90 dakika 5400s, 5400sn, 5400saniye, 5400saniye. Varsayılan değer 30m.
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ '--hangdump-timeout' tek bir zaman aşımı bağımsız değişkeni bekliyor
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ Dökümün türünü belirtin. Geçerli değerler 'Mini', 'Heap', 'Triage' (yalnızca .NET 6+'da mevcuttur) veya 'Full'dur. Varsayılan tür 'Tam'dır
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ '{0}' geçerli bir döküm türü değil. Geçerli seçenekler 'Mini', 'Heap', 'Triage' (yalnızca .NET 6+'da mevcuttur) ve 'Full’dur
+
+
+
+ Request of type '{0}' is not supported
+ '{0}' türündeki istek desteklenmiyor
+
+
+
+ The list of tests that were running at the time of the hang
+ Askıya alınma anında çalışan testlerin listesi
+
+
+
+ Hang test list
+ Askıda kalma test listesi
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ Bir veya daha fazla askıda kalma dökümü parametresi belirtmenize rağmen bunu etkinleştirmediyseniz komut satırına --hangdump ekleyin
+
+
+
+ Cannot find mutex '{0}'
+ Muteks '{0}' bulunamıyor
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ Mutex adı '{0}' saniyeden sonra alınamadı
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ Döküm alındığında aşağıdaki testler hâlâ çalışıyordu (biçim: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.zh-Hans.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.zh-Hans.xlf
new file mode 100644
index 0000000000..451533eabd
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.zh-Hans.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ 正在创建转储文件“{0}”
+
+
+
+ The hang dump file
+ 挂起转储文件
+
+
+
+ Hang dump file
+ 挂起转储文件
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ 环境变量“{0}”设置为“{1}”,而不是“{2}”
+
+
+
+ Environment variable '{0}' is not set
+ 未设置环境变量“{0}”
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ 当测试执行超过给定时间时生成挂起转储文件。
+
+
+
+ Hang dump
+ 挂起转储
+
+
+
+ Specify the name of the dump file
+ 指定转储文件的名称
+
+
+
+ Generate a dump file if the test process hangs
+ 如果测试进程挂起,则生成转储文件
+
+
+
+ Hang dump timeout of '{0}' expired
+ 挂起转储超时“{0}”已过期
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ 指定生成转储后的超时。超时值以以下格式之一指定: 1.5h、1.5hour、1.5hours、90m、90min、90minute、90minutes 5400s、5400sec、5400second、5400seconds。默认值为 30m。
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ “--hangdump-timeout”需要单一超时参数
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ 指定转储的类型。有效值为“Mini”、“Heap”、“Triage”(仅适用于 .NET 6+)或“Full”。默认类型为“Full”
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ “{0}”不是有效的转储类型。有效选项为“Mini”、“Heap”、“Triage”(仅适用于 .NET 6+)和“Full”
+
+
+
+ Request of type '{0}' is not supported
+ 不支持类型为“{0}”的请求
+
+
+
+ The list of tests that were running at the time of the hang
+ 挂起时运行的测试列表
+
+
+
+ Hang test list
+ 挂起测试列表
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ 你指定了一个或多个挂起转储参数,但未启用它,请将 --hangdump 添加到命令行
+
+
+
+ Cannot find mutex '{0}'
+ 找不到互斥“{0}”
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ “{0}”秒后未收到互斥名称
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ 执行转储时,以下测试仍在运行(格式: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.zh-Hant.xlf b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.zh-Hant.xlf
new file mode 100644
index 0000000000..e3b064eab3
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Resources/xlf/ExtensionResources.zh-Hant.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Creating dump file '{0}'
+ 正在建立傾印檔案 '{0}'
+
+
+
+ The hang dump file
+ 擱置傾印檔案
+
+
+
+ Hang dump file
+ 擱置傾印檔案
+
+
+
+ Environment variable '{0}' is set to '{1}' instead of '{2}'
+ 環境變數 '{0}' 已設定為 '{1}' 而不是 '{2}'
+
+
+
+ Environment variable '{0}' is not set
+ 未設定環境變數 '{0}'
+
+
+
+ Produce hang dump files when a test execution exceed a given time.
+ 當測試執行超過指定時間時,產生擱置傾印檔案。
+
+
+
+ Hang dump
+ 擱置傾印
+
+
+
+ Specify the name of the dump file
+ 指定傾印檔案的名稱
+
+
+
+ Generate a dump file if the test process hangs
+ 如果測試程序擱置,則產生傾印檔案
+
+
+
+ Hang dump timeout of '{0}' expired
+ '{0}' 的擱置傾印逾時已過期
+
+
+
+ Specify the timeout after which the dump will be generated. The timeout value is specified in one of the following formats: 1.5h, 1.5hour, 1.5hours, 90m, 90min, 90minute, 90minutes 5400s, 5400sec, 5400second, 5400seconds. Default is 30m.
+ 指定產生傾印前的逾時時間。逾時值會以下列其中一種格式顯示: 1.5h、1.5hour、1.5hours、90m、90min、90minute、90minutes 5400s、5400sec、5400second、5400seconds。預設為 30m。
+
+
+
+ '--hangdump-timeout' expects a single timeout argument
+ '--hangdump-timeout' 需要單一逾時引數
+
+
+
+ Specify the type of the dump. Valid values are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) or 'Full'. Default type is 'Full'
+ 指定傾印的類型。有效值為 'Mini'、'Heap'、'Triage' (只有在 .NET 6+ 可供使用) 或 'Full'。預設類型為 'Full'
+
+
+
+ '{0}' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' (only available in .NET 6+) and 'Full'
+ '{0}' 不是有效的傾印類型。有效的選項為 'Mini'、'Heap'、'Triage' (只有在 .NET 6+ 可供使用) 和 'Full'
+
+
+
+ Request of type '{0}' is not supported
+ 不支援類型 '{0}' 的要求
+
+
+
+ The list of tests that were running at the time of the hang
+ 擱置時正在執行的測試清單
+
+
+
+ Hang test list
+ 擱置測試清單
+
+
+
+ You specified one or more hang dump parameters but did not enable it, add --hangdump to the command line
+ 您指定了一或多個停留傾印參數但並未加以啟用,請將 --hangdump 新增至命令列中
+
+
+
+ Cannot find mutex '{0}'
+ 找不到 Mutex '{0}'
+
+
+
+ Mutex name wasn't received after '{0}' seconds
+ '{0}' 秒後未收到 Mutex 名稱
+
+
+
+ The following tests were still running when dump was taken (format: [<time-elapsed-since-start>] <name>):
+ 執行傾印時,下列測試仍在執行 (格式: [<time-elapsed-since-start>] <name>):
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ActivityIndicatorMutexNameSerializer.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ActivityIndicatorMutexNameSerializer.cs
new file mode 100644
index 0000000000..c46d16b03c
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ActivityIndicatorMutexNameSerializer.cs
@@ -0,0 +1,29 @@
+// 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.IPC;
+using Microsoft.Testing.Platform.IPC.Serializers;
+
+namespace Microsoft.Testing.Extensions.HangDump.Serializers;
+
+internal sealed class ActivityIndicatorMutexNameRequest(string mutexName) : IRequest
+{
+ public string MutexName { get; } = mutexName;
+}
+
+internal sealed class ActivityIndicatorMutexNameRequestSerializer : BaseSerializer, INamedPipeSerializer
+{
+ public int Id => 1;
+
+ public object Deserialize(Stream stream)
+ {
+ string mutexName = ReadString(stream);
+ return new ActivityIndicatorMutexNameRequest(mutexName);
+ }
+
+ public void Serialize(object objectToSerialize, Stream stream)
+ {
+ var request = (ActivityIndicatorMutexNameRequest)objectToSerialize;
+ WriteString(stream, request.MutexName);
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ConsumerPipeNameSerializer.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ConsumerPipeNameSerializer.cs
new file mode 100644
index 0000000000..a2f5949803
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ConsumerPipeNameSerializer.cs
@@ -0,0 +1,29 @@
+// 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.IPC;
+using Microsoft.Testing.Platform.IPC.Serializers;
+
+namespace Microsoft.Testing.Extensions.HangDump.Serializers;
+
+internal sealed class ConsumerPipeNameRequest(string pipeName) : IRequest
+{
+ public string PipeName { get; } = pipeName;
+}
+
+internal sealed class ConsumerPipeNameRequestSerializer : BaseSerializer, INamedPipeSerializer
+{
+ public int Id => 3;
+
+ public object Deserialize(Stream stream)
+ {
+ string mutexName = ReadString(stream);
+ return new ConsumerPipeNameRequest(mutexName);
+ }
+
+ public void Serialize(object objectToSerialize, Stream stream)
+ {
+ var request = (ConsumerPipeNameRequest)objectToSerialize;
+ WriteString(stream, request.PipeName);
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ExitSignalActivityIndicatorTaskRequest.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ExitSignalActivityIndicatorTaskRequest.cs
new file mode 100644
index 0000000000..a1f76cf3b9
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ExitSignalActivityIndicatorTaskRequest.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.
+
+using Microsoft.Testing.Platform.IPC;
+using Microsoft.Testing.Platform.IPC.Serializers;
+
+namespace Microsoft.Testing.Extensions.HangDump.Serializers;
+
+internal sealed class ExitSignalActivityIndicatorTaskRequest() : IRequest;
+
+internal sealed class ExitSignalActivityIndicatorTaskRequestSerializer : BaseSerializer, INamedPipeSerializer
+{
+ public int Id => 6;
+
+ public object Deserialize(Stream stream) => new ExitSignalActivityIndicatorTaskRequest();
+
+ public void Serialize(object objectToSerialize, Stream stream)
+ {
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsRequest.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsRequest.cs
new file mode 100644
index 0000000000..2a68a98905
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsRequest.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.
+
+using Microsoft.Testing.Platform.IPC;
+using Microsoft.Testing.Platform.IPC.Serializers;
+
+namespace Microsoft.Testing.Extensions.HangDump.Serializers;
+
+internal sealed class GetInProgressTestsRequest() : IRequest;
+
+internal sealed class GetInProgressTestsRequestSerializer : BaseSerializer, INamedPipeSerializer
+{
+ public int Id => 4;
+
+ public object Deserialize(Stream stream) => new GetInProgressTestsRequest();
+
+ public void Serialize(object objectToSerialize, Stream stream)
+ {
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsResponse.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsResponse.cs
new file mode 100644
index 0000000000..d393963ca6
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/GetInProgressTestsResponse.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.IPC;
+using Microsoft.Testing.Platform.IPC.Serializers;
+
+namespace Microsoft.Testing.Extensions.HangDump.Serializers;
+
+internal sealed class GetInProgressTestsResponse((string, int)[] tests) : IResponse
+{
+ public (string, int)[] Tests { get; } = tests;
+}
+
+internal sealed class GetInProgressTestsResponseSerializer : BaseSerializer, INamedPipeSerializer
+{
+ public int Id => 5;
+
+ public object Deserialize(Stream stream)
+ {
+ int readCount = ReadInt(stream);
+ List<(string, int)> tests = new();
+ for (int i = 0; i < readCount; i++)
+ {
+ string testName = ReadString(stream);
+ int unixTimeSeconds = ReadInt(stream);
+ tests.Add((testName, unixTimeSeconds));
+ }
+
+ return new GetInProgressTestsResponse(tests.ToArray());
+ }
+
+ public void Serialize(object objectToSerialize, Stream stream)
+ {
+ var getInProgressTestsResponse = (GetInProgressTestsResponse)objectToSerialize;
+ WriteInt(stream, getInProgressTestsResponse.Tests.Length);
+ foreach ((string testName, int seconds) in getInProgressTestsResponse.Tests)
+ {
+ WriteString(stream, testName);
+ WriteInt(stream, seconds);
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/SessionEndSerializer.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/SessionEndSerializer.cs
new file mode 100644
index 0000000000..23cd132c19
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/SessionEndSerializer.cs
@@ -0,0 +1,21 @@
+// 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.IPC;
+using Microsoft.Testing.Platform.IPC.Serializers;
+
+namespace Microsoft.Testing.Extensions.HangDump.Serializers;
+
+internal sealed class SessionEndSerializerRequest() : IRequest;
+
+internal sealed class SessionEndSerializerRequestSerializer : BaseSerializer, INamedPipeSerializer
+{
+ public int Id => 2;
+
+ public object Deserialize(Stream stream)
+ => new SessionEndSerializerRequest();
+
+ public void Serialize(object _, Stream __)
+ {
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/TestingPlatformBuilderHook.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/TestingPlatformBuilderHook.cs
new file mode 100644
index 0000000000..9b5089054a
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/TestingPlatformBuilderHook.cs
@@ -0,0 +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.Testing.Platform.Builder;
+
+namespace Microsoft.Testing.Extensions.HangDump;
+
+public static class TestingPlatformBuilderHook
+{
+ public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] _)
+ => testApplicationBuilder.AddHangDumpProvider();
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs
new file mode 100644
index 0000000000..7217148459
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs
@@ -0,0 +1,117 @@
+// 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.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+
+using Microsoft.Win32.SafeHandles;
+
+namespace Microsoft.Testing.Extensions.Diagnostics;
+
+internal static class MiniDumpWriteDump
+{
+ public static void CollectDumpUsingMiniDumpWriteDump(int pid, string outputFile, MiniDumpTypeOption type)
+ {
+ var process = Process.GetProcessById(pid);
+
+ // Open the file for writing
+ using var stream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
+ NativeMethods.MinidumpExceptionInformation exceptionInfo = default;
+
+ NativeMethods.MinidumpType dumpType = type switch
+ {
+ MiniDumpTypeOption.Full =>
+ NativeMethods.MinidumpType.MiniDumpWithFullMemory
+ | NativeMethods.MinidumpType.MiniDumpWithDataSegs
+ | NativeMethods.MinidumpType.MiniDumpWithHandleData
+ | NativeMethods.MinidumpType.MiniDumpWithUnloadedModules
+ | NativeMethods.MinidumpType.MiniDumpWithFullMemoryInfo
+ | NativeMethods.MinidumpType.MiniDumpWithThreadInfo
+ | NativeMethods.MinidumpType.MiniDumpWithTokenInformation,
+ MiniDumpTypeOption.Heap =>
+ NativeMethods.MinidumpType.MiniDumpWithPrivateReadWriteMemory
+ | NativeMethods.MinidumpType.MiniDumpWithDataSegs
+ | NativeMethods.MinidumpType.MiniDumpWithHandleData
+ | NativeMethods.MinidumpType.MiniDumpWithUnloadedModules
+ | NativeMethods.MinidumpType.MiniDumpWithFullMemoryInfo
+ | NativeMethods.MinidumpType.MiniDumpWithThreadInfo
+ | NativeMethods.MinidumpType.MiniDumpWithTokenInformation,
+ MiniDumpTypeOption.Mini => NativeMethods.MinidumpType.MiniDumpWithThreadInfo,
+ _ => NativeMethods.MinidumpType.MiniDumpNormal,
+ };
+
+ // Retry the write dump on ERROR_PARTIAL_COPY
+ for (int i = 0; i < 5; i++)
+ {
+ // Dump the process!
+ if (NativeMethods.MiniDumpWriteDump(process.Handle, (uint)process.Id, stream.SafeFileHandle, dumpType, ref exceptionInfo, IntPtr.Zero, IntPtr.Zero))
+ {
+ break;
+ }
+
+ int err = Marshal.GetHRForLastWin32Error();
+ if (err != NativeMethods.ErrorPartialCopy)
+ {
+ Marshal.ThrowExceptionForHR(err);
+ }
+ }
+ }
+
+ private static class NativeMethods
+ {
+ public const int ErrorPartialCopy = unchecked((int)0x8007012b);
+
+ [DllImport("Dbghelp.dll", SetLastError = true)]
+ public static extern bool MiniDumpWriteDump(IntPtr hProcess, uint processId, SafeFileHandle hFile, MinidumpType dumpType, ref MinidumpExceptionInformation exceptionParam, IntPtr userStreamParam, IntPtr callbackParam);
+
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public readonly struct MinidumpExceptionInformation
+ {
+ public readonly uint ThreadId;
+ public readonly IntPtr ExceptionPointers;
+ public readonly int ClientPointers;
+ }
+
+ [Flags]
+ public enum MinidumpType : uint
+ {
+ MiniDumpNormal = 0,
+ MiniDumpWithDataSegs = 1 << 0,
+ MiniDumpWithFullMemory = 1 << 1,
+ MiniDumpWithHandleData = 1 << 2,
+ MiniDumpFilterMemory = 1 << 3,
+ MiniDumpScanMemory = 1 << 4,
+ MiniDumpWithUnloadedModules = 1 << 5,
+ MiniDumpWithIndirectlyReferencedMemory = 1 << 6,
+ MiniDumpFilterModulePaths = 1 << 7,
+ MiniDumpWithProcessThreadData = 1 << 8,
+ MiniDumpWithPrivateReadWriteMemory = 1 << 9,
+ MiniDumpWithoutOptionalData = 1 << 10,
+ MiniDumpWithFullMemoryInfo = 1 << 11,
+ MiniDumpWithThreadInfo = 1 << 12,
+ MiniDumpWithCodeSegs = 1 << 13,
+ MiniDumpWithoutAuxiliaryState = 1 << 14,
+ MiniDumpWithFullAuxiliaryState = 1 << 15,
+ MiniDumpWithPrivateWriteCopyMemory = 1 << 16,
+ MiniDumpIgnoreInaccessibleMemory = 1 << 17,
+ MiniDumpWithTokenInformation = 1 << 18,
+ MiniDumpWithModuleHeaders = 1 << 19,
+ MiniDumpFilterTriage = 1 << 20,
+ MiniDumpWithAvxXStateContext = 1 << 21,
+ MiniDumpWithIptTrace = 1 << 22,
+ MiniDumpValidTypeFlags = (-1) ^ ((~1) << 22),
+ }
+ }
+
+ [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1602:Enumeration items should be documented", Justification = "Copy-paste")]
+ internal enum MiniDumpTypeOption
+ {
+ // This is a copy of DumpTypeOption, we need both of those types, because this
+ // dumper is included as file in both MiniDumpTool, and BlameDataCollector, and
+ // blame references MiniDumpTool, so we get the enum defined twice otherwise.
+ Full,
+ Heap,
+ Mini,
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/build/Microsoft.Testing.Extensions.HangDump.props b/src/Platform/Microsoft.Testing.Extensions.HangDump/build/Microsoft.Testing.Extensions.HangDump.props
new file mode 100644
index 0000000000..fb4e05c801
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/build/Microsoft.Testing.Extensions.HangDump.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/buildMultiTargeting/Microsoft.Testing.Extensions.HangDump.props b/src/Platform/Microsoft.Testing.Extensions.HangDump/buildMultiTargeting/Microsoft.Testing.Extensions.HangDump.props
new file mode 100644
index 0000000000..400685711e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/buildMultiTargeting/Microsoft.Testing.Extensions.HangDump.props
@@ -0,0 +1,9 @@
+
+
+
+
+ Microsoft.Testing.Extensions.HangDump
+ Microsoft.Testing.Extensions.HangDump.TestingPlatformBuilderHook
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/buildTransitive/Microsoft.Testing.Extensions.HangDump.props b/src/Platform/Microsoft.Testing.Extensions.HangDump/buildTransitive/Microsoft.Testing.Extensions.HangDump.props
new file mode 100644
index 0000000000..fb4e05c801
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/buildTransitive/Microsoft.Testing.Extensions.HangDump.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClient.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClient.cs
new file mode 100644
index 0000000000..9fa6fa9296
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClient.cs
@@ -0,0 +1,32 @@
+// 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.ApplicationInsights;
+using Microsoft.ApplicationInsights.Extensibility;
+
+namespace Microsoft.Testing.Extensions.Telemetry;
+
+internal class AppInsightTelemetryClient : ITelemetryClient
+{
+ // Note: The InstrumentationKey should match the one of dotnet cli.
+ 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);
+ _telemetryClient.Context.Session.Id = currentSessionId;
+ _telemetryClient.Context.Device.OperatingSystem = osVersion;
+ }
+
+ public void TrackEvent(string eventName, Dictionary properties, Dictionary metrics)
+ {
+ _telemetryClient.TrackEvent(eventName, properties, metrics);
+ _telemetryClient.Flush();
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClientFactory.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClientFactory.cs
new file mode 100644
index 0000000000..8e3665349c
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightTelemetryClientFactory.cs
@@ -0,0 +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.
+
+namespace Microsoft.Testing.Extensions.Telemetry;
+
+internal class AppInsightTelemetryClientFactory : ITelemetryClientFactory
+{
+ public ITelemetryClient Create(string? currentSessionId, string osVersion)
+ => new AppInsightTelemetryClient(currentSessionId, osVersion);
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs
new file mode 100644
index 0000000000..99d8e15d4a
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs
@@ -0,0 +1,336 @@
+// 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.Threading.Channels;
+#else
+using System.Collections.Concurrent;
+#endif
+using System.Globalization;
+using System.Text;
+
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.Testing.Platform.Telemetry;
+
+namespace Microsoft.Testing.Extensions.Telemetry;
+
+///
+/// Allows to log telemetry events via AppInsights.
+///
+internal sealed partial class AppInsightsProvider :
+ ITelemetryCollector
+#pragma warning disable SA1001 // Commas should be spaced correctly
+#if NETCOREAPP
+ , IAsyncDisposable
+#else
+ , IDisposable
+#endif
+#pragma warning restore SA1001 // Commas should be spaced correctly
+{
+ // Note: We're currently using the same environment variable as dotnet CLI.
+ public static readonly string SessionIdEnvVar = "TESTINGPLATFORM_APPINSIGHTS_SESSIONID";
+
+ // Allows us to correlate events produced from the same process.
+ // Not calling this ProcessId, because it has a different meaning.
+ private static readonly string CurrentReporterId = Guid.NewGuid().ToString();
+ private readonly string _currentSessionId;
+ private readonly bool _isCi;
+ private readonly IEnvironment _environment;
+ private readonly ITestApplicationCancellationTokenSource _testApplicationCancellationTokenSource;
+ private readonly ITask _task;
+ private readonly IClock _clock;
+ private readonly ITelemetryInformation _telemetryInformation;
+ private readonly ITelemetryClientFactory _telemetryClientFactory;
+ private readonly bool _isDevelopmentRepository;
+ private readonly ILogger _logger;
+ private readonly Task? _telemetryTask;
+ private readonly CancellationTokenSource _flushTimeoutOrStop = new();
+#if NETCOREAPP
+ private readonly Channel<(string EventName, IDictionary ParamsMap)> _payloads;
+#else
+ private readonly BlockingCollection<(string EventName, IDictionary ParamsMap)> _payloads;
+#endif
+#if DEBUG
+ // Telemetry properties that are allowed to contain unhashed information.
+ private static readonly HashSet StringWhitelist =
+ [
+ TelemetryProperties.VersionPropertyName,
+ TelemetryProperties.ReporterIdPropertyName,
+ TelemetryProperties.SessionId,
+ TelemetryProperties.HostProperties.TestingPlatformVersionPropertyName,
+ TelemetryProperties.HostProperties.FrameworkDescriptionPropertyName,
+ TelemetryProperties.HostProperties.OSDescriptionPropertyName,
+ TelemetryProperties.HostProperties.RuntimeIdentifierPropertyName,
+ TelemetryProperties.HostProperties.ApplicationModePropertyName,
+ TelemetryProperties.HostProperties.ExitCodePropertyName,
+ TelemetryProperties.HostProperties.ExtensionsPropertyName
+ ];
+#endif
+
+ private ITelemetryClient? _client;
+ private bool _isDisposed;
+
+ public AppInsightsProvider(
+ IEnvironment environment,
+ ITestApplicationCancellationTokenSource testApplicationCancellationTokenSource,
+ ITask task,
+ ILoggerFactory loggerFactory,
+ IClock clock,
+ IConfiguration configuration,
+ ITelemetryInformation telemetryInformation,
+ ITelemetryClientFactory telemetryClientFactory,
+ string sessionId)
+ {
+ _ = bool.TryParse(configuration[PlatformConfigurationConstants.PlatformTelemetryIsDevelopmentRepository], out _isDevelopmentRepository);
+ _isCi = CIEnvironmentDetectorForTelemetry.IsCIEnvironment();
+ _environment = environment;
+ _currentSessionId = sessionId;
+ _testApplicationCancellationTokenSource = testApplicationCancellationTokenSource;
+ _task = task;
+ _clock = clock;
+ _telemetryInformation = telemetryInformation;
+ _telemetryClientFactory = telemetryClientFactory;
+
+#if NETCOREAPP
+ _payloads = Channel.CreateUnbounded<(string EventName, IDictionary ParamsMap)>(new UnboundedChannelOptions()
+ {
+ // We process only 1 data at a time
+ SingleReader = true,
+
+ // We don't know how many threads will call the Log method
+ SingleWriter = false,
+
+ // We want to unlink the caller from the consumer
+ AllowSynchronousContinuations = false,
+ });
+
+ _telemetryTask = task.Run(IngestLoopAsync, _testApplicationCancellationTokenSource.CancellationToken);
+#else
+ // Keep the custom thread to avoid to waste one from thread pool.
+ // We have some await but we should stay on custom one if not for special needs like trace log or exception.
+ _payloads = new();
+ _telemetryTask = _task.RunLongRunning(IngestLoopAsync, "Telemetry AppInsightsProvider", _testApplicationCancellationTokenSource.CancellationToken);
+#endif
+
+ _logger = loggerFactory.CreateLogger();
+ }
+
+ // Initialize the telemetry client and start ingesting events.
+ private async Task IngestLoopAsync()
+ {
+ if (_testApplicationCancellationTokenSource.CancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ try
+ {
+ _client = _telemetryClientFactory.Create(_currentSessionId, _environment.OsVersion);
+ }
+ catch (Exception e)
+ {
+ _client = null;
+
+ await _logger.LogErrorAsync($"Failed to initialize telemetry client", e);
+ return;
+ }
+
+ DateTimeOffset? lastLoggedError = null;
+ _testApplicationCancellationTokenSource.CancellationToken.Register(() => _flushTimeoutOrStop.Cancel());
+ try
+ {
+#if NETCOREAPP
+ while (await _payloads.Reader.WaitToReadAsync(_flushTimeoutOrStop.Token))
+ {
+ (string eventName, IDictionary paramsMap) = await _payloads.Reader.ReadAsync();
+#else
+ foreach ((string eventName, IDictionary paramsMap) in _payloads.GetConsumingEnumerable(_flushTimeoutOrStop.Token))
+ {
+#endif
+
+ // Add common properties.
+ paramsMap.Add(TelemetryProperties.VersionPropertyName, _telemetryInformation.Version);
+ paramsMap.Add(TelemetryProperties.SessionId, _currentSessionId);
+ paramsMap.Add(TelemetryProperties.ReporterIdPropertyName, CurrentReporterId);
+ paramsMap.Add(TelemetryProperties.IsCIPropertyName, _isCi.AsTelemetryBool());
+
+ if (_isDevelopmentRepository)
+ {
+ paramsMap.Add(TelemetryProperties.HostProperties.IsDevelopmentRepositoryPropertyName, TelemetryProperties.True);
+ }
+
+ var metrics = new Dictionary();
+ var properties = new Dictionary();
+
+ foreach (KeyValuePair pair in paramsMap)
+ {
+ switch (pair.Value)
+ {
+ // Metrics:
+ case double value:
+ metrics.Add(pair.Key, value);
+ break;
+ case DateTimeOffset value:
+ metrics.Add(pair.Key, ToUnixTimeNanoseconds(value));
+ break;
+
+ // Properties:
+#if DEBUG
+ case string value:
+ AssertHashed(pair.Key, value);
+ properties.Add(pair.Key, value);
+ break;
+#endif
+ case bool value:
+ RoslynDebug.Assert(false, $"Telemetry entry '{pair.Key}' contains a boolean value, boolean values should always be converted to string using: .{nameof(TelemetryExtensions.AsTelemetryBool)}()");
+ properties.Add(pair.Key, value.AsTelemetryBool());
+ break;
+ default:
+ properties.Add(pair.Key, pair.Value?.ToString() ?? string.Empty);
+ break;
+ }
+ }
+
+ if (_logger.IsEnabled(LogLevel.Trace))
+ {
+ StringBuilder builder = new();
+ builder.AppendLine(CultureInfo.InvariantCulture, $"Send telemetry event: {eventName}");
+ foreach (KeyValuePair keyValue in properties)
+ {
+ builder.AppendLine(CultureInfo.InvariantCulture, $" {keyValue.Key}: {keyValue.Value}");
+ }
+
+ foreach (KeyValuePair keyValue in metrics)
+ {
+ builder.AppendLine(CultureInfo.InvariantCulture, $" {keyValue.Key}: {keyValue.Value.ToString("f", CultureInfo.InvariantCulture)}");
+ }
+
+ await _logger.LogTraceAsync(builder.ToString());
+ }
+
+ try
+ {
+ _client.TrackEvent(eventName, properties, metrics);
+ }
+ catch (Exception ex)
+ {
+ // If we have a lot of issues with the network we could have a lot of logs here.
+ // We log one error every 3 seconds.
+ // We could do better backpressure.
+ if (_logger.IsEnabled(LogLevel.Error) && (!lastLoggedError.HasValue || (lastLoggedError.Value - _clock.UtcNow).TotalSeconds > 3))
+ {
+ await _logger.LogErrorAsync($"Error during telemetry report.", ex);
+ lastLoggedError = _clock.UtcNow;
+ }
+ }
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ // This is expected when the test application is shutting down or if flush timeout.
+ return;
+ }
+ }
+
+ private static double ToUnixTimeNanoseconds(DateTimeOffset value) =>
+
+ // The magic number is DateTimeOffset.UnixEpoch.Ticks in newer TFMs.
+ // We multiply by 100 because Ticks are 100 ns, and we want to report ns.
+ (value.UtcTicks - 621355968000000000L) * 100;
+
+#if DEBUG
+ private static void AssertHashed(string key, string value)
+ {
+ if (value is TelemetryProperties.True or TelemetryProperties.False)
+ {
+ return;
+ }
+
+ // Full qualification of Regex to avoid adding conditional 'using' on top of the file.
+ if (value.Length == 64 && GetValidHashPattern().IsMatch(value))
+ {
+ return;
+ }
+
+ if (StringWhitelist.Contains(key))
+ {
+ return;
+ }
+
+ RoslynDebug.Assert(false, $"Telemetry entry '{key}' contains an unhashed string value '{value}'. Strings need to be hashed using {nameof(Sha256Hasher)}.{nameof(Sha256Hasher.HashWithNormalizedCasing)}(), or whitelisted.");
+ }
+
+#if NET7_0_OR_GREATER
+ [System.Text.RegularExpressions.GeneratedRegex("[a-f0-9]{64}")]
+ private static partial System.Text.RegularExpressions.Regex GetValidHashPattern();
+#else
+ private static System.Text.RegularExpressions.Regex GetValidHashPattern()
+ => new("[a-f0-9]{64}");
+#endif
+#endif
+
+ public async Task LogEventAsync(string eventName, IDictionary paramsMap)
+ {
+#if NETCOREAPP
+ await _payloads.Writer.WriteAsync((eventName, paramsMap));
+#else
+ _payloads.Add((eventName, paramsMap));
+ await Task.CompletedTask;
+#endif
+ }
+
+#if !NETCOREAPP
+ // Adding dispose on graceful shutdown per https://github.com/microsoft/ApplicationInsights-dotnet/issues/1152#issuecomment-518742922
+ public void Dispose()
+ {
+ _payloads.CompleteAdding();
+ if (!_isDisposed)
+ {
+ if (_telemetryTask is null)
+ {
+ throw new InvalidOperationException("Unexpected null _telemetryTask");
+ }
+
+ int flushForSeconds = 3;
+ if (!_telemetryTask.Wait(TimeSpan.FromSeconds(flushForSeconds)))
+ {
+ _flushTimeoutOrStop.Cancel();
+ _logger.LogWarning($"Telemetry task didn't flush after '{flushForSeconds}', some payload could be lost");
+ }
+
+ _isDisposed = true;
+ }
+ }
+#endif
+
+#if NETCOREAPP
+ public async ValueTask DisposeAsync()
+ {
+ _payloads.Writer.Complete();
+ if (!_isDisposed)
+ {
+ if (_telemetryTask is null)
+ {
+ throw new InvalidOperationException("Unexpected null _telemetryTask");
+ }
+
+ int flushForSeconds = 3;
+ try
+ {
+ await _telemetryTask.TimeoutAfterAsync(TimeSpan.FromSeconds(flushForSeconds));
+ }
+ catch (TimeoutException)
+ {
+ await _flushTimeoutOrStop.CancelAsync();
+ await _logger.LogWarningAsync($"Telemetry task didn't flush after '{flushForSeconds}', some payload could be lost");
+ }
+
+ _isDisposed = true;
+ }
+ }
+#endif
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsTelemetryProviderExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsTelemetryProviderExtensions.cs
new file mode 100644
index 0000000000..29f0e0ea24
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsTelemetryProviderExtensions.cs
@@ -0,0 +1,57 @@
+// 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.Telemetry;
+using Microsoft.Testing.Extensions.Telemetry.Resources;
+using Microsoft.Testing.Platform.Builder;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.Testing.Platform.Telemetry;
+
+#if NETCOREAPP
+using System.Runtime.CompilerServices;
+#endif
+
+namespace Microsoft.Testing.Extensions;
+
+public static class AppInsightsTelemetryProviderExtensions
+{
+ public static void AddAppInsightsTelemetryProvider(this ITestApplicationBuilder builder)
+ {
+#if NETCOREAPP
+ // AppInsights is not supported on platforms that do not support dynamic code generation.
+ if (!RuntimeFeature.IsDynamicCodeSupported)
+ {
+ return;
+ }
+#endif
+#pragma warning disable IDE0022 // Use expression body for method
+
+ if (builder is not TestApplicationBuilder testApplicationBuilder)
+ {
+ throw new ArgumentException(ExtensionResources.AddAppInsightsTelemetryProviderInvalidBuilder);
+ }
+
+ testApplicationBuilder.TelemetryManager.AddTelemetryCollectorProvider(services =>
+ {
+ IEnvironment environment = services.GetRequiredService();
+
+ // Session ID that is inherited across processes.
+ string sessionId = environment.GetEnvironmentVariable(AppInsightsProvider.SessionIdEnvVar) ?? Guid.NewGuid().ToString();
+
+ // We want to flow down the processes the same session id for correlation purposes.
+ environment.SetEnvironmentVariable(AppInsightsProvider.SessionIdEnvVar, sessionId);
+ return new AppInsightsProvider(
+ services.GetRequiredService(),
+ services.GetTestApplicationCancellationTokenSource(),
+ services.GetTask(),
+ services.GetLoggerFactory(),
+ services.GetClock(),
+ services.GetConfiguration(),
+ services.GetRequiredService(),
+ new AppInsightTelemetryClientFactory(),
+ sessionId);
+ });
+#pragma warning restore IDE0022 // Use expression body for method
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.Telemetry/BannedSymbols.txt
new file mode 100644
index 0000000000..469bd16cf9
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/BannedSymbols.txt
@@ -0,0 +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,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
new file mode 100644
index 0000000000..ee4c5a7f2e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/CIEnvironmentDetectorForTelemetry.cs
@@ -0,0 +1,86 @@
+// 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;
+
+namespace Microsoft.Testing.Extensions.Telemetry;
+
+// Detection of CI: 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
+internal class CIEnvironmentDetectorForTelemetry
+{
+ // Systems that provide boolean values only, so we can simply parse and check for true
+ private static readonly 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.
+ // Given this, we could potentially remove all of these other options?
+ "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
+ private static readonly string[][] AllNotNullVariables = new string[][]
+ {
+ // 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
+ private static readonly 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"
+ ];
+
+ public static bool IsCIEnvironment()
+ {
+ foreach (string booleanVariable in BooleanVariables)
+ {
+ if (bool.TryParse(Environment.GetEnvironmentVariable(booleanVariable), out bool envVar) && envVar)
+ {
+ return true;
+ }
+ }
+
+ foreach (string[] variables in AllNotNullVariables)
+ {
+ if (variables.All((variable) => !RoslynString.IsNullOrEmpty(Environment.GetEnvironmentVariable(variable))))
+ {
+ return true;
+ }
+ }
+
+ foreach (string variable in IfNonNullVariables)
+ {
+ if (!RoslynString.IsNullOrEmpty(Environment.GetEnvironmentVariable(variable)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/ITelemetryClient.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/ITelemetryClient.cs
new file mode 100644
index 0000000000..4cb3c606c0
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/ITelemetryClient.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.Extensions.Telemetry;
+
+internal interface ITelemetryClient
+{
+ void TrackEvent(string eventName, Dictionary properties, Dictionary metrics);
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/ITelemetryClientFactory.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/ITelemetryClientFactory.cs
new file mode 100644
index 0000000000..b7651bdfad
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/ITelemetryClientFactory.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.Extensions.Telemetry;
+
+internal interface ITelemetryClientFactory
+{
+ ITelemetryClient Create(string? currentSessionId, string osVersion);
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj
new file mode 100644
index 0000000000..30c5d20049
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj
@@ -0,0 +1,66 @@
+
+
+
+ netstandard2.0;$(MicrosoftTestingTargetFrameworks)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ buildMultiTargeting
+
+
+ buildTransitive/$(TargetFramework)
+
+
+ build/$(TargetFramework)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ ExtensionResources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ ExtensionResources.Designer.cs
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/PACKAGE.md b/src/Platform/Microsoft.Testing.Extensions.Telemetry/PACKAGE.md
new file mode 100644
index 0000000000..46232617ad
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/PACKAGE.md
@@ -0,0 +1,9 @@
+# Microsoft.Testing
+
+Microsoft Testing is a set of platform, framework and protocol intended to make it possible to run any test on any target or device.
+
+Documentation can be found at .
+
+## About
+
+This package provides telemetry extensions to Microsoft Testing Platform.
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/PublicAPI/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.Telemetry/PublicAPI/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..fd2242e298
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/PublicAPI/PublicAPI.Shipped.txt
@@ -0,0 +1,5 @@
+#nullable enable
+Microsoft.Testing.Extensions.AppInsightsTelemetryProviderExtensions
+Microsoft.Testing.Extensions.Telemetry.TestingPlatformBuilderHook
+static Microsoft.Testing.Extensions.AppInsightsTelemetryProviderExtensions.AddAppInsightsTelemetryProvider(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder) -> void
+static Microsoft.Testing.Extensions.Telemetry.TestingPlatformBuilderHook.AddExtensions(Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! testApplicationBuilder, string![]! _) -> void
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/PublicAPI/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.Telemetry/PublicAPI/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..7dc5c58110
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/PublicAPI/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/ExtensionResources.Designer.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/ExtensionResources.Designer.cs
new file mode 100644
index 0000000000..b9acf27546
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/ExtensionResources.Designer.cs
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+//
+// 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.Testing.Extensions.Telemetry.Resources {
+ 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 ExtensionResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal ExtensionResources() {
+ }
+
+ ///
+ /// 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.Testing.Extensions.Telemetry.Resources.ExtensionResources", typeof(ExtensionResources).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 AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders.
+ ///
+ internal static string AddAppInsightsTelemetryProviderInvalidBuilder {
+ get {
+ return ResourceManager.GetString("AddAppInsightsTelemetryProviderInvalidBuilder", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/ExtensionResources.resx b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/ExtensionResources.resx
new file mode 100644
index 0000000000..7a0e29405e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/ExtensionResources.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.cs.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.cs.xlf
new file mode 100644
index 0000000000..c76b3dfbad
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.cs.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ Zprostředkovatele telemetrie AppInsights jde zaregistrovat jenom do tvůrců Microsoft.Testing.Platform.Builder.TestApplicationBuilder.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.de.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.de.xlf
new file mode 100644
index 0000000000..1dc6dae7ed
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.de.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ Der AppInsights-Telemetrieanbieter kann nur bei Microsoft.Testing.Platform.Builder.TestApplicationBuilder-Builders registriert werden.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.es.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.es.xlf
new file mode 100644
index 0000000000..eb509d882d
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.es.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ El proveedor de telemetría AppInsights solo se puede registrar en los generadores Microsoft.Testing.Platform.Builder.TestApplicationBuilder.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.fr.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.fr.xlf
new file mode 100644
index 0000000000..8c88c9a474
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.fr.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ Le fournisseur de données de télémétrie AppInsights ne peut être inscrit qu’auprès des générateurs Microsoft.Testing.Platform.Builder.TestApplicationBuilder
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.it.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.it.xlf
new file mode 100644
index 0000000000..fc4bb6ca2c
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.it.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ Il provider di telemetria AppInsights può essere registrato solo nei generatori Microsoft.Testing.Platform.Builder.TestApplicationBuilder
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.ja.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.ja.xlf
new file mode 100644
index 0000000000..4bc11711f0
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.ja.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ AppInsights テレメトリ プロバイダーは、Microsoft.Testing.Platform.Builder.TestApplicationBuilder ビルダーにのみ登録できます
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.ko.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.ko.xlf
new file mode 100644
index 0000000000..da0bd7b768
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.ko.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ AppInsights 원격 분석 공급자는 Microsoft.Testing.Platform.Builder.TestApplicationBuilder 빌더에만 등록할 수 있습니다.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.pl.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.pl.xlf
new file mode 100644
index 0000000000..3ba5637fb1
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.pl.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ Dostawcę telemetrii usługi AppInsights można zarejestrować tylko w konstruktorach Microsoft.Testing.Platform.Builder.TestApplicationBuilder
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.pt-BR.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.pt-BR.xlf
new file mode 100644
index 0000000000..465eb1bd5e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.pt-BR.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ O provedor de telemetria do AppInsights só pode ser registrado nos construtores Microsoft.Testing.Platform.Builder.TestApplicationBuilder
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.ru.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.ru.xlf
new file mode 100644
index 0000000000..aaaf1e7601
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.ru.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ Поставщик телеметрии AppInsights можно зарегистрировать только в построителях Microsoft.Testing.Platform.Builder.TestApplicationBuilder.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.tr.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.tr.xlf
new file mode 100644
index 0000000000..7a81b867a7
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.tr.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ AppInsights telemetri sağlayıcısı yalnızca Microsoft.Testing.Platform.Builder.TestApplicationBuilder oluşturucularına kaydedilebilir
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.zh-Hans.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.zh-Hans.xlf
new file mode 100644
index 0000000000..0647a34712
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.zh-Hans.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ AppInsights 遥测提供程序只能注册到 Microsoft.Testing.Platform.Builder.TestApplicationBuilder 生成器
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.zh-Hant.xlf b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.zh-Hant.xlf
new file mode 100644
index 0000000000..235c789cda
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Resources/xlf/ExtensionResources.zh-Hant.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AppInsights telemetry provider can only be registered onto Microsoft.Testing.Platform.Builder.TestApplicationBuilder builders
+ AppInsights 遙測提供者只能註冊到 Microsoft.Testing.Platform.Builder.TestApplicationBuilder 建立器
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/TestingPlatformBuilderHook.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/TestingPlatformBuilderHook.cs
new file mode 100644
index 0000000000..3de2580d6a
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/TestingPlatformBuilderHook.cs
@@ -0,0 +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.Testing.Platform.Builder;
+
+namespace Microsoft.Testing.Extensions.Telemetry;
+
+public static class TestingPlatformBuilderHook
+{
+ public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] _)
+ => testApplicationBuilder.AddAppInsightsTelemetryProvider();
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/build/Microsoft.Testing.Extensions.Telemetry.props b/src/Platform/Microsoft.Testing.Extensions.Telemetry/build/Microsoft.Testing.Extensions.Telemetry.props
new file mode 100644
index 0000000000..db2f9e299b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/build/Microsoft.Testing.Extensions.Telemetry.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/buildMultiTargeting/Microsoft.Testing.Extensions.Telemetry.props b/src/Platform/Microsoft.Testing.Extensions.Telemetry/buildMultiTargeting/Microsoft.Testing.Extensions.Telemetry.props
new file mode 100644
index 0000000000..b3ffdb0d68
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/buildMultiTargeting/Microsoft.Testing.Extensions.Telemetry.props
@@ -0,0 +1,9 @@
+
+
+
+
+ Microsoft.Testing.Extensions.Telemetry
+ Microsoft.Testing.Extensions.Telemetry.TestingPlatformBuilderHook
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/buildTransitive/Microsoft.Testing.Extensions.Telemetry.props b/src/Platform/Microsoft.Testing.Extensions.Telemetry/buildTransitive/Microsoft.Testing.Extensions.Telemetry.props
new file mode 100644
index 0000000000..db2f9e299b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/buildTransitive/Microsoft.Testing.Extensions.Telemetry.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt
new file mode 100644
index 0000000000..ea8617fcb0
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt
@@ -0,0 +1,10 @@
+T:System.ArgumentNullException; Use 'ArgumentGuard' instead
+P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.UtcNow; Use 'IClock' instead
+M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
+M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
+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,System.String); Use 'RoslynDebug.Assert' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/GlobalSuppressions.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/GlobalSuppressions.cs
new file mode 100644
index 0000000000..91e972bf72
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/GlobalSuppressions.cs
@@ -0,0 +1,15 @@
+// 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.Diagnostics.CodeAnalysis;
+
+// We usually do not want to suppress issues through GlobalSuppressions file but in this case we have to do it because
+// we are not able to suppress the issue differently.
+#pragma warning disable IDE0076
+[assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:Polyfill.CancelAsync(System.Threading.CancellationTokenSource)~System.Threading.Tasks.Task")]
+[assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:System.Reflection.NullabilityInfoContext.CheckParameterMetadataType(System.Reflection.ParameterInfo,System.Reflection.NullabilityInfo)")]
+[assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:System.Reflection.NullabilityInfoContext.Create(System.Reflection.EventInfo)~System.Reflection.NullabilityInfo")]
+[assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:System.Reflection.NullabilityInfoContext.Create(System.Reflection.FieldInfo)~System.Reflection.NullabilityInfo")]
+[assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:System.Reflection.NullabilityInfoContext.Create(System.Reflection.ParameterInfo)~System.Reflection.NullabilityInfo")]
+[assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:System.Reflection.NullabilityInfoContext.Create(System.Reflection.PropertyInfo)~System.Reflection.NullabilityInfo")]
+#pragma warning restore IDE0076
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/ITrxReportCapability.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/ITrxReportCapability.cs
new file mode 100644
index 0000000000..77d33fb35a
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/ITrxReportCapability.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.Testing.Platform.Capabilities.TestFramework;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+///
+/// This capability is used to indicate whether or not the test framework supports trx report generation.
+/// By supporting trx generation, the test adapter should ensure that some required properties are available
+/// for all the nodes.
+/// We expect these properties in the node bag:
+/// - 1 trxreport.classname
+/// - 0..n trxreport.testcategory
+/// And, in case of exception, the following extra properties:
+/// - trxreport.exceptionmessage
+/// - trxreport.exceptionstacktrace.
+///
+public interface ITrxReportCapability : ITestFrameworkCapability
+{
+ ///
+ /// Gets a value indicating whether indicates if the test framework supports trx report properties enrichment.
+ ///
+ bool IsSupported { get; }
+
+ ///
+ /// Notifies the test framework that the trx report is enabled and trx report properties should be added to the test nodes.
+ ///
+ void Enable();
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj
new file mode 100644
index 0000000000..3846c32606
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj
@@ -0,0 +1,30 @@
+
+
+
+ netstandard2.0;$(MicrosoftTestingTargetFrameworks)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PACKAGE.md b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PACKAGE.md
new file mode 100644
index 0000000000..19953e6fef
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PACKAGE.md
@@ -0,0 +1,11 @@
+# Microsoft.Testing
+
+Microsoft Testing is a set of platform, framework and protocol intended to make it possible to run any test on any target or device.
+
+Documentation can be found at .
+
+## About
+
+This package provides interfaces and data objects used by extensions willing to interoperate with TRX functionality.
+
+This package does not bring support for telemetry, for this you would need to install Microsoft.Testing.Extensions.TrxReport package.
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..a841a60ade
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/PublicAPI.Shipped.txt
@@ -0,0 +1,99 @@
+#nullable enable
+Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage
+Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.DebugOrTraceTrxMessage(string? Message) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.Deconstruct(out string? Message) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage? other) -> bool
+Microsoft.Testing.Extensions.TrxReport.Abstractions.ITrxReportCapability
+Microsoft.Testing.Extensions.TrxReport.Abstractions.ITrxReportCapability.Enable() -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.ITrxReportCapability.IsSupported.get -> bool
+Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage
+Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.Deconstruct(out string? Message) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage? other) -> bool
+Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.StandardErrorTrxMessage(string? Message) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage
+Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.Deconstruct(out string? Message) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage? other) -> bool
+Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.StandardOutputTrxMessage(string? Message) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty!
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.Categories.get -> string![]!
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.Categories.init -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.Deconstruct(out string![]! Categories) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty? other) -> bool
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.TrxCategoriesProperty(string![]! Categories) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty!
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.Deconstruct(out string? Message, out string? StackTrace) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty? other) -> bool
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.Message.get -> string?
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.Message.init -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.StackTrace.get -> string?
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.StackTrace.init -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.TrxExceptionProperty(string? Message, string? StackTrace) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty!
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.Deconstruct(out string! FullyQualifiedTypeName) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty? other) -> bool
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.FullyQualifiedTypeName.get -> string!
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.FullyQualifiedTypeName.init -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.TrxFullyQualifiedTypeNameProperty(string! FullyQualifiedTypeName) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.Deconstruct(out string? Message) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.Message.get -> string?
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.Message.init -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.TrxMessage(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage! original) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.TrxMessage(string? Message) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty!
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.Deconstruct(out Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage![]! Messages) -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty? other) -> bool
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.Messages.get -> Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage![]!
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.Messages.init -> void
+Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.TrxMessagesProperty(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage![]! Messages) -> void
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.Equals(object? obj) -> bool
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.GetHashCode() -> int
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.ToString() -> string!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.Equals(object? obj) -> bool
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.GetHashCode() -> int
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.ToString() -> string!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.Equals(object? obj) -> bool
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.GetHashCode() -> int
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.ToString() -> string!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.Equals(object? obj) -> bool
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.GetHashCode() -> int
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.ToString() -> string!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.Equals(object? obj) -> bool
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.GetHashCode() -> int
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.ToString() -> string!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.Equals(object? obj) -> bool
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.GetHashCode() -> int
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.ToString() -> string!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.Equals(object? obj) -> bool
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.GetHashCode() -> int
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.ToString() -> string!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.Equals(object? obj) -> bool
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.GetHashCode() -> int
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.ToString() -> string!
+override sealed Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage? other) -> bool
+override sealed Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage? other) -> bool
+override sealed Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage? other) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.operator !=(Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.operator ==(Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.operator !=(Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.operator ==(Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.operator !=(Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.operator ==(Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.operator !=(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty.operator ==(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxCategoriesProperty? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.operator !=(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty.operator ==(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxExceptionProperty? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.operator !=(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty.operator ==(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxFullyQualifiedTypeNameProperty? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.operator !=(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.operator ==(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.operator !=(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty? right) -> bool
+static Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty.operator ==(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty? left, Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessagesProperty? right) -> bool
+virtual Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage!
+virtual Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.EqualityContract.get -> System.Type!
+virtual Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.Equals(Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage? other) -> bool
+virtual Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage.PrintMembers(System.Text.StringBuilder! builder) -> bool
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..7dc5c58110
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/net/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/net/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..c9a999b27e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/net/PublicAPI.Shipped.txt
@@ -0,0 +1,4 @@
+#nullable enable
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage!
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/net/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..7dc5c58110
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..af59c85a51
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt
@@ -0,0 +1,4 @@
+#nullable enable
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.DebugOrTraceTrxMessage.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardErrorTrxMessage.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage!
+override Microsoft.Testing.Extensions.TrxReport.Abstractions.StandardOutputTrxMessage.$() -> Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxMessage!
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..7dc5c58110
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/TrxReportProperties.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/TrxReportProperties.cs
new file mode 100644
index 0000000000..13566d2228
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/TrxReportProperties.cs
@@ -0,0 +1,22 @@
+// 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.Messages;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+public sealed record class TrxExceptionProperty(string? Message, string? StackTrace) : IProperty;
+
+public sealed record class TrxFullyQualifiedTypeNameProperty(string FullyQualifiedTypeName) : IProperty;
+
+public record class TrxMessage(string? Message);
+
+public sealed record class StandardErrorTrxMessage(string? Message) : TrxMessage(Message);
+
+public sealed record class StandardOutputTrxMessage(string? Message) : TrxMessage(Message);
+
+public sealed record class DebugOrTraceTrxMessage(string? Message) : TrxMessage(Message);
+
+public sealed record class TrxMessagesProperty(TrxMessage[] Messages) : IProperty;
+
+public sealed record class TrxCategoriesProperty(string[] Categories) : IProperty;
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt
new file mode 100644
index 0000000000..ea8617fcb0
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt
@@ -0,0 +1,10 @@
+T:System.ArgumentNullException; Use 'ArgumentGuard' instead
+P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.UtcNow; Use 'IClock' instead
+M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
+M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
+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,System.String); Use 'RoslynDebug.Assert' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Microsoft.Testing.Extensions.TrxReport.csproj b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Microsoft.Testing.Extensions.TrxReport.csproj
new file mode 100644
index 0000000000..63dfed24c7
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Microsoft.Testing.Extensions.TrxReport.csproj
@@ -0,0 +1,73 @@
+
+
+
+ netstandard2.0;$(MicrosoftTestingTargetFrameworks)
+ Microsoft.Testing.Extensions.TestReports
+
+ $(DefineConstants);USE_TRX_NAMESPACE
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ buildMultiTargeting
+
+
+ buildTransitive/$(TargetFramework)
+
+
+ build/$(TargetFramework)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ ExtensionResources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ ExtensionResources.Designer.cs
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/PACKAGE.md b/src/Platform/Microsoft.Testing.Extensions.TrxReport/PACKAGE.md
new file mode 100644
index 0000000000..69685e9b2b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/PACKAGE.md
@@ -0,0 +1,9 @@
+# Microsoft.Testing
+
+Microsoft Testing is a set of platform, framework and protocol intended to make it possible to run any test on any target or device.
+
+Documentation can be found at .
+
+## About
+
+This package extends Microsoft Testing Platform to provide TRX test reports.
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/PublicAPI/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport/PublicAPI/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..ef7f0a192d
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/PublicAPI/PublicAPI.Shipped.txt
@@ -0,0 +1,5 @@
+#nullable enable
+Microsoft.Testing.Extensions.TrxReport.TestingPlatformBuilderHook
+Microsoft.Testing.Extensions.TrxReportExtensions
+static Microsoft.Testing.Extensions.TrxReport.TestingPlatformBuilderHook.AddExtensions(Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! testApplicationBuilder, string![]! _) -> void
+static Microsoft.Testing.Extensions.TrxReportExtensions.AddTrxReportProvider(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder) -> void
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/PublicAPI/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport/PublicAPI/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..7dc5c58110
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/PublicAPI/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/ExtensionResources.Designer.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/ExtensionResources.Designer.cs
new file mode 100644
index 0000000000..55793cbf17
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/ExtensionResources.Designer.cs
@@ -0,0 +1,252 @@
+//------------------------------------------------------------------------------
+//
+// 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.Testing.Extensions.TestReports.Resources {
+ 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 ExtensionResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal ExtensionResources() {
+ }
+
+ ///
+ /// 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.Testing.Extensions.TestReports.Resources.ExtensionResources", typeof(ExtensionResources).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 TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'.
+ ///
+ internal static string InvalidTestApplicationBuilderType {
+ get {
+ return ResourceManager.GetString("InvalidTestApplicationBuilderType", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The baseline TRX file.
+ ///
+ internal static string TrxComparerToolBaselineFileOptionDescription {
+ get {
+ return ResourceManager.GetString("TrxComparerToolBaselineFileOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to '--{0}' and '--{1}' must both be specified.
+ ///
+ internal static string TrxComparerToolBothFilesMustBeSpecified {
+ get {
+ return ResourceManager.GetString("TrxComparerToolBothFilesMustBeSpecified", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to This tool allows to compare and highights differences between 2 TRX reports.
+ ///
+ internal static string TrxComparerToolDescription {
+ get {
+ return ResourceManager.GetString("TrxComparerToolDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to TRX comparer tool.
+ ///
+ internal static string TrxComparerToolDisplayName {
+ get {
+ return ResourceManager.GetString("TrxComparerToolDisplayName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to '--{0}' expects a single trx file path as argument.
+ ///
+ internal static string TrxComparerToolOptionExpectsSingleArgument {
+ get {
+ return ResourceManager.GetString("TrxComparerToolOptionExpectsSingleArgument", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The TRX file to compare with the baseline.
+ ///
+ internal static string TrxComparerToolOtherFileOptionDescription {
+ get {
+ return ResourceManager.GetString("TrxComparerToolOtherFileOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Test session.
+ ///
+ internal static string TrxReportArtifactDescription {
+ get {
+ return ResourceManager.GetString("TrxReportArtifactDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to TRX Report.
+ ///
+ internal static string TrxReportArtifactDisplayName {
+ get {
+ return ResourceManager.GetString("TrxReportArtifactDisplayName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx).
+ ///
+ internal static string TrxReportFileNameExtensionIsNotTrx {
+ get {
+ return ResourceManager.GetString("TrxReportFileNameExtensionIsNotTrx", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The name of the generated TRX report.
+ ///
+ internal static string TrxReportFileNameOptionDescription {
+ get {
+ return ResourceManager.GetString("TrxReportFileNameOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to '--report-trx-filename' requires '--report-trx' to be enabled.
+ ///
+ internal static string TrxReportFileNameRequiresTrxReport {
+ get {
+ return ResourceManager.GetString("TrxReportFileNameRequiresTrxReport", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to file name argument must not contain path (e.g. --report-trx-filename myreport.trx).
+ ///
+ internal static string TrxReportFileNameShouldNotContainPath {
+ get {
+ return ResourceManager.GetString("TrxReportFileNameShouldNotContainPath", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports.
+ ///
+ internal static string TrxReportFrameworkDoesNotSupportTrxReportCapability {
+ get {
+ return ResourceManager.GetString("TrxReportFrameworkDoesNotSupportTrxReportCapability", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'.
+ ///
+ internal static string TrxReportGeneratorBeforeTestHostProcessStartAsyncNotCalled {
+ get {
+ return ResourceManager.GetString("TrxReportGeneratorBeforeTestHostProcessStartAsyncNotCalled", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Produce a TRX report for the current test session.
+ ///
+ internal static string TrxReportGeneratorDescription {
+ get {
+ return ResourceManager.GetString("TrxReportGeneratorDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to TRX report generator.
+ ///
+ internal static string TrxReportGeneratorDisplayName {
+ get {
+ return ResourceManager.GetString("TrxReportGeneratorDisplayName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Required environment variable '{0}' is missing for TRX report generator.
+ ///
+ internal static string TrxReportGeneratorMissingTrxNamedPipeEnvironmentVariable {
+ get {
+ return ResourceManager.GetString("TrxReportGeneratorMissingTrxNamedPipeEnvironmentVariable", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to '--report-trx' cannot be enabled when using '--list-tests'.
+ ///
+ internal static string TrxReportIsNotValidForDiscovery {
+ get {
+ return ResourceManager.GetString("TrxReportIsNotValidForDiscovery", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Enable generating TRX report.
+ ///
+ internal static string TrxReportOptionDescription {
+ get {
+ return ResourceManager.GetString("TrxReportOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Requests of type '{0}' is not supported.
+ ///
+ internal static string UnsupportedRequestTypeErrorMessage {
+ get {
+ return ResourceManager.GetString("UnsupportedRequestTypeErrorMessage", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/ExtensionResources.resx b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/ExtensionResources.resx
new file mode 100644
index 0000000000..08ffbb226f
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/ExtensionResources.resx
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+
+
+ The baseline TRX file
+
+
+ '--{0}' and '--{1}' must both be specified
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+
+
+ TRX comparer tool
+
+
+ '--{0}' expects a single trx file path as argument
+
+
+ The TRX file to compare with the baseline
+
+
+ Test session
+
+
+ TRX Report
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+
+
+ The name of the generated TRX report
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+
+
+ Produce a TRX report for the current test session
+
+
+ TRX report generator
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+
+
+ Enable generating TRX report
+
+
+ Requests of type '{0}' is not supported
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.cs.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.cs.xlf
new file mode 100644
index 0000000000..240d84bd22
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.cs.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ Generátor sestav TRX funguje pouze s tvůrci typu Microsoft.Testing.Platform.Builder.TestApplicationBuilder.
+
+
+
+ The baseline TRX file
+ Soubor TRX standardních hodnot
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ Musí být zadaná jak možnost --{0}, tak možnost --{1}.
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ Tento nástroj umožňuje porovnat rozdíly mezi 2 sestavami TRX a zobrazit přehled těchto rozdílů.
+
+
+
+ TRX comparer tool
+ Porovnávač souborů TRX
+
+
+
+ '--{0}' expects a single trx file path as argument
+ --{0} očekává jako argument jednu cestu k souboru trx.
+
+
+
+ The TRX file to compare with the baseline
+ Soubor TRX, který se má porovnat se standardními hodnotami
+
+
+
+ Test session
+ Relace testu
+
+
+
+ TRX Report
+ Sestava TRX
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ Argument názvu souboru --report-trx-filename musí končit na .trx (například --report-trx-filename myreport.trx).
+
+
+
+ The name of the generated TRX report
+ Název vygenerované sestavy TRX
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ --report-trx-filename vyžaduje, aby byla povolená možnost --report-trx.
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ Argument názvu souboru nesmí obsahovat cestu (například --report-trx-filename myreport.trx).
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ Testovací architektura {0} s UID {1} nepodporuje ITrxReportCapability, což vede k chybějícím nebo neúplným sestavám TRX.
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ Před metodou OnTestHostProcessStartedAsync musí být volána metoda BeforeTestHostProcessStartAsync.
+
+
+
+ Produce a TRX report for the current test session
+ Vytvořit sestavu TRX pro aktuální testovací relaci
+
+
+
+ TRX report generator
+ Generátor sestav TRX
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ Chybí požadovaná proměnná prostředí {0} pro generátor sestav TRX.
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ Možnost --report-trx nejde povolit, pokud se používá možnost --list-tests.
+
+
+
+ Enable generating TRX report
+ Povolit vygenerování sestavy TRX
+
+
+
+ Requests of type '{0}' is not supported
+ Žádosti typu {0} nejsou podporovány.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.de.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.de.xlf
new file mode 100644
index 0000000000..9765711f6f
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.de.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ Der TRX-Bericht-Generator funktioniert nur mit Generatoren vom Typ "Microsoft.Testing.Platform.Builder.TestApplicationBuilder"
+
+
+
+ The baseline TRX file
+ Die Baseline-TRX-Datei
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ "--{0}" und "--{1}" müssen beide angegeben werden
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ Dieses Tool ermöglicht Vergleichs- und Highights-Unterschiede zwischen 2 TRX-Berichten
+
+
+
+ TRX comparer tool
+ TRX-Vergleichstool
+
+
+
+ '--{0}' expects a single trx file path as argument
+ "--{0}" erwartet einen einzelnen TRX-Dateipfad als Argument
+
+
+
+ The TRX file to compare with the baseline
+ Die TRX-Datei, die mit der Baseline verglichen werden soll
+
+
+
+ Test session
+ Testsitzung
+
+
+
+ TRX Report
+ TRX-Bericht
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ Das Dateinamenargument "--report-trx-filename" muss auf ".trx" enden (z. B. "--report-trx-filename myreport.trx")
+
+
+
+ The name of the generated TRX report
+ Der Name des generierten TRX-Berichts
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ "--report-trx-filename" muss "--report-trx" muss aktiviert sein
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ Das Dateinamenargument darf keinen Pfad enthalten (z. B. --report-trx-filename myreport.trx).
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ Das Testframework "{0}" mit UID "{1}" unterstützt "ITrxReportCapability" nicht, was zu fehlenden oder unvollständigen TRX-Berichten führt.
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ Die Methode "BeforeTestHostProcessStartAsync" muss vor "OnTestHostProcessStartedAsync" aufgerufen werden
+
+
+
+ Produce a TRX report for the current test session
+ Erstellt einen TRX-Bericht für die aktuelle Testsitzung
+
+
+
+ TRX report generator
+ TRX-Bericht-Generator
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ Die erforderliche Umgebungsvariable "{0}" fehlt für den TRX-Bericht-Generator.
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ "--report-trx" kann bei Verwendung von "--list-tests" nicht aktiviert werden
+
+
+
+ Enable generating TRX report
+ Generieren des TRX-Berichts aktivieren
+
+
+
+ Requests of type '{0}' is not supported
+ Anforderungen vom Typ "{0}" werden nicht unterstützt
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.es.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.es.xlf
new file mode 100644
index 0000000000..2a9d69ee4b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.es.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ El generador de informes TRX solo funciona con generadores de tipo "Microsoft.Testing.Platform.Builder.TestApplicationBuilder".
+
+
+
+ The baseline TRX file
+ El archivo TRX de línea de base
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ '--{0}' y '--{1}' deben especificarse
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ Esta herramienta permite comparar y comparar las diferencias entre 2 informes TRX
+
+
+
+ TRX comparer tool
+ Herramienta de comparador TRX
+
+
+
+ '--{0}' expects a single trx file path as argument
+ '--{0}' espera una única ruta de acceso de archivo trx como argumento
+
+
+
+ The TRX file to compare with the baseline
+ Archivo TRX que se va a comparar con la línea base
+
+
+
+ Test session
+ Sesión de prueba
+
+
+
+ TRX Report
+ Informe TRX
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ El argumento de nombre de archivo '--report-trx-filename' debe terminar con '.trx' (por ejemplo, --report-trx-filename myreport.trx)
+
+
+
+ The name of the generated TRX report
+ Nombre del informe TRX generado
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ '--report-trx-filename' requiere que se habilite '--report-trx'
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ el argumento de nombre de archivo no debe contener la ruta de acceso (por ejemplo, --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ El marco de pruebas '{0}' con UID '{1}' no admite 'ITrxReportCapability' que conduce a informes TRX que faltan o están incompletos
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ Se debe llamar al método 'BeforeTestHostProcessStartAsync' antes de 'OnTestHostProcessStartedAsync'
+
+
+
+ Produce a TRX report for the current test session
+ Generar un informe TRX para la sesión de prueba actual
+
+
+
+ TRX report generator
+ Generador de informes TRX
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ Falta la variable de entorno necesaria '{0}' para el generador de informes TRX
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ '--report-trx' no se puede habilitar cuando se usa '--list-tests'
+
+
+
+ Enable generating TRX report
+ Habilitación de la generación de informes TRX
+
+
+
+ Requests of type '{0}' is not supported
+ No se admiten solicitudes de tipo '{0}'
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.fr.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.fr.xlf
new file mode 100644
index 0000000000..d13aa67023
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.fr.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ Le générateur de rapports TRX fonctionne uniquement avec les générateurs de type « Microsoft.Testing.Platform.Builder.TestApplicationBuilder »
+
+
+
+ The baseline TRX file
+ Fichier TRX de référence
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ '--{0}' et '--{1}' doivent tous deux être spécifiés
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ Cet outil permet de comparer et d’afficher des différences élevées entre 2 rapports TRX
+
+
+
+ TRX comparer tool
+ Outil comparateur TRX
+
+
+
+ '--{0}' expects a single trx file path as argument
+ '--{0}' attend un seul chemin de fichier trx comme argument
+
+
+
+ The TRX file to compare with the baseline
+ Fichier TRX à comparer à la ligne de base
+
+
+
+ Test session
+ Session de test
+
+
+
+ TRX Report
+ Rapport TRX
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ L'argument du nom de fichier '--report-trx-filename' doit se terminer par '.trx' (par exemple --report-trx-filename myreport.trx)
+
+
+
+ The name of the generated TRX report
+ Nom du rapport TRX généré
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ '--report-trx-filename' nécessite que '--report-trx' soit activé
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ L'argument du nom de fichier ne doit pas contenir de chemin (par exemple --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ Le framework de test '{0}' avec l'UID '{1}' ne prend pas en charge 'ITrxReportCapability', ce qui entraîne des rapports TRX manquants ou incomplets
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ La méthode 'BeforeTestHostProcessStartAsync' doit être appelée avant 'OnTestHostProcessStartedAsync'
+
+
+
+ Produce a TRX report for the current test session
+ Produire un rapport TRX pour la session de test actuelle
+
+
+
+ TRX report generator
+ Générateur de rapports TRX
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ La variable d’environnement requise «{0}» est manquante pour le générateur de rapports TRX
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ '--report-trx' ne peut pas être activé lors de l'utilisation de '--list-tests'
+
+
+
+ Enable generating TRX report
+ Activer la génération du rapport TRX
+
+
+
+ Requests of type '{0}' is not supported
+ Les demandes de type «{0}» ne sont pas prises en charge
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.it.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.it.xlf
new file mode 100644
index 0000000000..985e0946d3
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.it.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ Il generatore di report TRX funziona solo con i generatori di tipo 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'.
+
+
+
+ The baseline TRX file
+ File TRX di base
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ È necessario specificare sia '--{0}' che '--{1}'
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ Questo strumento consente di confrontare e confrontare le differenze di vista tra 2 report TRX
+
+
+
+ TRX comparer tool
+ Strumento di confronto TRX
+
+
+
+ '--{0}' expects a single trx file path as argument
+ '--{0}' prevede un singolo percorso di file trx come argomento
+
+
+
+ The TRX file to compare with the baseline
+ File TRX da confrontare con la baseline
+
+
+
+ Test session
+ Sessione di test
+
+
+
+ TRX Report
+ Report TRX
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ L'argomento del nome del file '--report-trx-filename' deve terminare con '.trx' (ad esempio --report-trx-filename myreport.trx)
+
+
+
+ The name of the generated TRX report
+ Nome del report TRX generato
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ '--report-trx-filename' richiede l'abilitazione di '--report-trx'
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ l'argomento del nome del file non deve contenere il percorso (ad esempio --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ Il framework di test '{0}' con UID '{1}' non supporta 'ITrxReportCapability' causando report TRX mancanti o incompleti
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ Il metodo 'BeforeTestHostProcessStartAsync' deve essere chiamato prima di 'OnTestHostProcessStartedAsync'.
+
+
+
+ Produce a TRX report for the current test session
+ Generare un rapporto TRX per la sessione di test corrente.
+
+
+
+ TRX report generator
+ Generatore di report TRX
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ Variabile di ambiente obbligatoria '{0}' mancante per il generatore di report TRX
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ Non è possibile abilitare '--report-trx' quando si usa '--list-tests'
+
+
+
+ Enable generating TRX report
+ Abilitare la generazione del report TRX
+
+
+
+ Requests of type '{0}' is not supported
+ Le richieste di tipo '{0}' non sono supportate
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.ja.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.ja.xlf
new file mode 100644
index 0000000000..418cf99719
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.ja.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ TRX レポート ジェネレーター、'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' 型のビルダーでのみ機能します
+
+
+
+ The baseline TRX file
+ ベースライン TRX ファイル
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ '--{0}' と '--{1}' の両方を指定する必要があります
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ このツールを使用すると、2 つの TRX レポートの違いを比較し、強調表示できます
+
+
+
+ TRX comparer tool
+ TRX 比較ツール
+
+
+
+ '--{0}' expects a single trx file path as argument
+ '--{0}' には、引数として 1 つの trx ファイル パスが必要です
+
+
+
+ The TRX file to compare with the baseline
+ ベースラインと比較する TRX ファイル
+
+
+
+ Test session
+ テスト セッション
+
+
+
+ TRX Report
+ TRX レポート
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ '--report-trx-filename' ファイル名引数の末尾は '.trx' にする必要があります (例: --report-trx-filename myreport.trx)
+
+
+
+ The name of the generated TRX report
+ 生成された TRX レポートの名前
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ '--report-trx-filename' では、'--report-trx' を有効にする必要があります
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ ファイル名引数にパスを含めることはできません (例: --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ UID '{1}' のテスト フレームワーク '{0}' は 'ITrxReportCapability' をサポートしていないため、TRX レポートが見つからないか不完全です
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ 'OnTestHostProcessStartedAsync' の前にメソッド 'BeforeTestHostProcessStartAsync' を呼び出す必要があります
+
+
+
+ Produce a TRX report for the current test session
+ 現在のテスト セッションの TRX レポートを生成する
+
+
+
+ TRX report generator
+ TRX レポート ジェネレーター
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ TRX レポート ジェネレーターに必要な環境変数 '{0}' がありません
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ '--list-tests' を使用している場合、'--report-trx' を有効にすることはできません
+
+
+
+ Enable generating TRX report
+ TRX レポートの生成を有効にする
+
+
+
+ Requests of type '{0}' is not supported
+ 型 '{0}' の要求はサポートされていません
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.ko.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.ko.xlf
new file mode 100644
index 0000000000..3ee998b1ad
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.ko.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ TRX 보고서 생성기는 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' 유형의 작성기에서만 작동합니다.
+
+
+
+ The baseline TRX file
+ 기준 TRX 파일
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ '--{0}' 및 '--{1}'을(를) 모두 지정해야 합니다.
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ 이 도구를 사용하면 2개의 TRX 보고서 간의 차이점을 비교하고 강조할 수 있습니다.
+
+
+
+ TRX comparer tool
+ TRX 비교자 도구
+
+
+
+ '--{0}' expects a single trx file path as argument
+ '--{0}'에는 단일 trx 파일 경로가 인수로 필요합니다.
+
+
+
+ The TRX file to compare with the baseline
+ 기준과 비교할 TRX 파일입니다.
+
+
+
+ Test session
+ 테스트 세션
+
+
+
+ TRX Report
+ TRX 보고서
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ '--report-trx-filename' 파일 이름 인수는 '.trx'로 끝나야 합니다(예: --report-trx-filename myreport.trx).
+
+
+
+ The name of the generated TRX report
+ 생성된 TRX 보고서의 이름입니다.
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ '--report-trx-filename'을 사용하려면 '--report-trx'를 사용하도록 설정해야 합니다.
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ 파일 이름 인수는 경로를 포함해서는 안 됩니다(예: --report-trx-filename myreport.trx).
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ UID가 '{1}'인 테스트 프레임워크 '{0}'은(는) 'ITrxReportCapability'를 지원하지 않으므로 TRX 보고서가 없거나 불완전합니다.
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ 'BeforeTestHostProcessStartAsync' 메서드는 'OnTestHostProcessStartedAsync' 전에 호출해야 합니다.
+
+
+
+ Produce a TRX report for the current test session
+ 현재 테스트 세션에 대한 TRX 보고서 생성
+
+
+
+ TRX report generator
+ TRX 보고서 생성기
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ TRX 보고서 생성기에 필요한 환경 변수 '{0}'이(가) 없습니다.
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ '--list-tests'를 사용하는 경우 '--report-trx'를 사용하도록 설정할 수 없습니다.
+
+
+
+ Enable generating TRX report
+ TRX 보고서 생성 사용
+
+
+
+ Requests of type '{0}' is not supported
+ '{0}' 유형의 요청은 지원되지 않습니다.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.pl.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.pl.xlf
new file mode 100644
index 0000000000..681fa340a3
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.pl.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ Generator raportów TRX działa tylko z konstruktorami typu „Microsoft.Testing.Platform.Builder.TestApplicationBuilder”
+
+
+
+ The baseline TRX file
+ Plik TRX punktu odniesienia
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ „--{0}” i „--{1}” muszą być określone
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ To narzędzie umożliwia porównywanie i zwiększanie różnic między 2 raportami TRX
+
+
+
+ TRX comparer tool
+ Narzędzie do porównywania TRX
+
+
+
+ '--{0}' expects a single trx file path as argument
+ Element „--{0}” oczekuje pojedynczej ścieżki pliku trx jako argumentu
+
+
+
+ The TRX file to compare with the baseline
+ Plik TRX do porównania z punktem odniesienia
+
+
+
+ Test session
+ Sesja testowa
+
+
+
+ TRX Report
+ Raport TRX
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ Argument nazwy pliku „--report-trx-filename” musi kończyć się ciągiem „.trx” (np. --report-trx-filename myreport.trx)
+
+
+
+ The name of the generated TRX report
+ Nazwa wygenerowanego raportu TRX
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ Element „--report-trx-filename” wymaga włączenia elementu „--report-trx”
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ argument nazwy pliku nie może zawierać ścieżki (np. --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ Struktura testowa „{0}” o identyfikatorze UID „{1}” nie obsługuje elementu „ITrxReportCapability”, co prowadzi do brakujących lub niekompletnych raportów TRX
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ Metoda „BeforeTestHostProcessStartAsync” musi być wywołana przed elementem „OnTestHostProcessStartedAsync”
+
+
+
+ Produce a TRX report for the current test session
+ Tworzenie raportu TRX dla bieżącej sesji testowej
+
+
+
+ TRX report generator
+ Generator raportów TRX
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ Brak wymaganej zmiennej środowiskowej „{0}” dla generatora raportów TRX
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ Nie można włączyć polecenia „--report-trx” w przypadku używania polecenia „--list-tests”
+
+
+
+ Enable generating TRX report
+ Włącz generowanie raportu TRX
+
+
+
+ Requests of type '{0}' is not supported
+ Żądania typu „{0}” nie są obsługiwane
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.pt-BR.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.pt-BR.xlf
new file mode 100644
index 0000000000..8c30fe2079
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.pt-BR.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ O gerador de relatórios TRX só funciona com construtores do tipo ''Microsoft.Testing.Platform.Builder.TestApplicationBuilder''
+
+
+
+ The baseline TRX file
+ O arquivo TRX da linha de base
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ ''--{0}'' e ''--{1}'' devem ser especificados
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ Esta ferramenta permite comparar e definir diferenças entre dois relatórios TRX
+
+
+
+ TRX comparer tool
+ Ferramenta de comparador TRX
+
+
+
+ '--{0}' expects a single trx file path as argument
+ ''--{0}'' espera um único caminho de arquivo trx como argumento
+
+
+
+ The TRX file to compare with the baseline
+ O arquivo TRX a ser comparado com a linha de base
+
+
+
+ Test session
+ Sessão de teste
+
+
+
+ TRX Report
+ Relatório TRX
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ O argumento de nome de arquivo ''--report-trx-filename'' deve terminar com ''.trx'' (por exemplo, --report-trx-filename myreport.trx)
+
+
+
+ The name of the generated TRX report
+ O nome do relatório TRX gerado
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ ''--report-trx-filename'' requer que ''--report-trx'' esteja habilitado
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ argumento de nome de arquivo não deve conter caminho (por exemplo, --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ A estrutura de teste ''{0}'' com UID ''{1}'' não dá suporte a ''ITrxReportCapability'' levando a relatórios TRX ausentes ou incompletos
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ O método ''BeforeTestHostProcessStartAsync'' deve ser chamado antes de ''OnTestHostProcessStartedAsync''
+
+
+
+ Produce a TRX report for the current test session
+ Produzir um relatório TRX para a sessão de teste atual
+
+
+
+ TRX report generator
+ Gerador de relatório TRX
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ A variável de ambiente necessária ''{0}'' está ausente para o gerador de relatório TRX
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ Não é possível habilitar ''--report-trx'' ao usar ''--list-tests''
+
+
+
+ Enable generating TRX report
+ Habilitar geração de relatório TRX
+
+
+
+ Requests of type '{0}' is not supported
+ Não há suporte para solicitações de tipo ''{0}''
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.ru.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.ru.xlf
new file mode 100644
index 0000000000..0cced45270
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.ru.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ Генератор отчетов TRX работает только с построителями типа "Microsoft.Testing.Platform.Builder.TestApplicationBuilder"
+
+
+
+ The baseline TRX file
+ Базовый TRX-файл
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ Необходимо одновременно указать "--{0}" и "--{1}"
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ Этот инструмент позволяет сравнивать и выделять различия между двумя отчетами TRX
+
+
+
+ TRX comparer tool
+ Средство сравнения TRX
+
+
+
+ '--{0}' expects a single trx file path as argument
+ "--{0}" ожидает в качестве аргумента один путь к файлу TRX
+
+
+
+ The TRX file to compare with the baseline
+ TRX-файл для сравнения с базовыми показателями
+
+
+
+ Test session
+ Тестовый сеанс
+
+
+
+ TRX Report
+ Отчет TRX
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ Аргумент имени файла "--report-trx-filename" должен заканчиваться на ".trx" (например, --report-trx-filename myreport.trx)
+
+
+
+ The name of the generated TRX report
+ Имя созданного отчета TRX
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ Для параметра "--report-trx-filename" требуется включить "--report-trx"
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ аргумент имени файла не должен содержать путь (например, --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ Платформа тестирования "{0}" с идентификатором пользователя "{1}" не поддерживает "ITrxReportCapability", поэтому отчеты TRX не будут создаваться или будут неполными
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ Метод "BeforeTestHostProcessStartAsync" должен вызываться до "OnTestHostProcessStartedAsync"
+
+
+
+ Produce a TRX report for the current test session
+ Создавать отчет TRX для текущего тестового сеанса
+
+
+
+ TRX report generator
+ Генератор отчетов TRX
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ Для генератора отчетов TRX отсутствует необходимая переменная среды "{0}"
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ Невозможно включить "--report-trx" при использовании "--list-tests"
+
+
+
+ Enable generating TRX report
+ Включить создание отчета TRX
+
+
+
+ Requests of type '{0}' is not supported
+ Запросы типа "{0}" не поддерживаются
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.tr.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.tr.xlf
new file mode 100644
index 0000000000..27af5d58c1
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.tr.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ TRX rapor oluşturucu yalnızca 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' türündeki oluşturucularla çalışır
+
+
+
+ The baseline TRX file
+ Temel TRX dosyası
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ '--{0}' ve '--{1}' birlikte belirtilmelidir
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ Bu araç, 2 TRX raporu arasındaki farkların karşılaştırılmasına ve vurgulanmasına olanak tanır
+
+
+
+ TRX comparer tool
+ TRX karşılaştırma aracı
+
+
+
+ '--{0}' expects a single trx file path as argument
+ '--{0}', bağımsız değişken olarak tek bir trx dosya yolu bekliyor
+
+
+
+ The TRX file to compare with the baseline
+ Taban çizgisiyle karşılaştırılacak TRX dosyası
+
+
+
+ Test session
+ Test oturumu
+
+
+
+ TRX Report
+ TRX Raporu
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ '--report-trx-dosyaadı' dosya adı bağımsız değişkeni '.trx' ile bitmelidir (örn. --report-trx-dosyaadı myreport.trx)
+
+
+
+ The name of the generated TRX report
+ Oluşturulan TRX raporunun adı
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ '--report-trx-filename', '--report-trx'in etkinleştirilmesini gerektirir
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ dosya adı argümanı yol içermemelidir (e.g. --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ UID '{0}' olan '{1}' test çerçevesi eksik veya eksik TRX raporlarına yol açarak 'ITrxReportCapability' öğesini desteklemez
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ 'BeforeTestHostProcessStartAsync' metodu 'OnTestHostProcessStartedAsync' öğesinden önce çağrılmalıdır
+
+
+
+ Produce a TRX report for the current test session
+ Mevcut test oturumu için bir TRX raporu oluşturun
+
+
+
+ TRX report generator
+ TRX rapor oluşturucusu
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ TRX rapor oluşturucu için gerekli ortam değişkeni '{0}' eksik
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ '--list-tests' kullanılırken '--report-trx' etkinleştirilemez
+
+
+
+ Enable generating TRX report
+ TRX raporu oluşturmayı etkinleştirin
+
+
+
+ Requests of type '{0}' is not supported
+ '{0}' türündeki istek desteklenmiyor
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.zh-Hans.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.zh-Hans.xlf
new file mode 100644
index 0000000000..afefc4c42b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.zh-Hans.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ TRX 报表生成器仅适用于“Microsoft.Testing.Platform.Builder.TestApplicationBuilder”类型的生成器
+
+
+
+ The baseline TRX file
+ 基线 TRX 文件
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ 必须同时指定“--{0}”和“--{1}”
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ 此工具允许比较和突出显示 2 个 TRX 报表之间的差异
+
+
+
+ TRX comparer tool
+ TRX 比较器工具
+
+
+
+ '--{0}' expects a single trx file path as argument
+ “--{0}”需要单一 trx 文件路径作为参数
+
+
+
+ The TRX file to compare with the baseline
+ 要与基线进行比较的 TRX 文件
+
+
+
+ Test session
+ 测试会话
+
+
+
+ TRX Report
+ TRX 报表
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ “--report-trx-filename”文件名参数必须以“.trx”结尾(例如 --report-trx-filename myreport.trx)
+
+
+
+ The name of the generated TRX report
+ 生成的 TRX 报表的名称
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ “--report-trx-filename”需要启用“--report-trx”
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ 文件名参数不得包含路径(例如 --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ UID 为“{1}”的测试框架“{0}”不支持“ITrxReportCapability”,将导致 TRX 报告丢失或不完整
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ 必须在“OnTestHostProcessStartedAsync”之前调用方法“BeforeTestHostProcessStartAsync”
+
+
+
+ Produce a TRX report for the current test session
+ 为当前测试会话生成 TRX 报表
+
+
+
+ TRX report generator
+ TRX 报表生成器
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ TRX 报表生成器缺少所需的环境变量“{0}”
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ 使用“--list-tests”时,无法启用“--report-trx”
+
+
+
+ Enable generating TRX report
+ 启用生成 TRX 报表
+
+
+
+ Requests of type '{0}' is not supported
+ 不支持类型为“{0}”的请求
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.zh-Hant.xlf b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.zh-Hant.xlf
new file mode 100644
index 0000000000..e599551f93
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Resources/xlf/ExtensionResources.zh-Hant.xlf
@@ -0,0 +1,112 @@
+
+
+
+
+
+ TRX report generator only works with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder'
+ TRX 報表產生器只能與類型為 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' 的建立器一起運作
+
+
+
+ The baseline TRX file
+ 比較基準 TRX 檔案
+
+
+
+ '--{0}' and '--{1}' must both be specified
+ 必須同時指定 '--{0}' 和 '--{1}'
+
+
+
+ This tool allows to compare and highights differences between 2 TRX reports
+ 此工具可讓您比較 2 個 TRX 報表之間的高差異
+
+
+
+ TRX comparer tool
+ TRX 比較工具
+
+
+
+ '--{0}' expects a single trx file path as argument
+ '--{0}' 需要單一 TRX 檔案路徑做為引數
+
+
+
+ The TRX file to compare with the baseline
+ 要與基準比較的 TRX 檔案
+
+
+
+ Test session
+ 測試工作階段
+
+
+
+ TRX Report
+ TRX 報表
+
+
+
+ '--report-trx-filename' file name argument must end with '.trx' (e.g. --report-trx-filename myreport.trx)
+ '--report-trx-filename' 檔案名稱引數的結尾必須是 '.trx' (例如 --report-trx-filename myreport.trx)
+
+
+
+ The name of the generated TRX report
+ 產生的 TRX 報表名稱
+
+
+
+ '--report-trx-filename' requires '--report-trx' to be enabled
+ '--report-trx-filename' 需要啟用 '--report-trx'
+
+
+
+ file name argument must not contain path (e.g. --report-trx-filename myreport.trx)
+ 檔案名稱引數不能包含路徑 (例如 --report-trx-filename myreport.trx)
+
+
+
+ The test framework '{0}' with UID '{1}' does not support the 'ITrxReportCapability' leading to missing or incomplete TRX reports
+ 具有 UID '{1}' 的測試架構 '{0}' 不支援導致 TRX 報告遺漏或不完整的 'ITrxReportCapability'
+
+
+
+ Method 'BeforeTestHostProcessStartAsync' must be called before 'OnTestHostProcessStartedAsync'
+ 'BeforeTestHostProcessStartAsync' 方法必須在 'OnTestHostProcessStartedAsync' 之前呼叫
+
+
+
+ Produce a TRX report for the current test session
+ 產生目前測試工作階段的 TRX 報告
+
+
+
+ TRX report generator
+ TRX 報表產生器
+
+
+
+ Required environment variable '{0}' is missing for TRX report generator
+ TRX 報表產生器遺漏必要的環境變數 '{0}'
+
+
+
+ '--report-trx' cannot be enabled when using '--list-tests'
+ 使用 '--list-tests' 時,無法啟用 '--report-trx'
+
+
+
+ Enable generating TRX report
+ 啟用產生 TRX 報表
+
+
+
+ Requests of type '{0}' is not supported
+ 不支援類型 '{0}' 的要求
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Serializers/ReportFileNameSerializer.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Serializers/ReportFileNameSerializer.cs
new file mode 100644
index 0000000000..a2102ed28d
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Serializers/ReportFileNameSerializer.cs
@@ -0,0 +1,29 @@
+// 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.IPC;
+using Microsoft.Testing.Platform.IPC.Serializers;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions.Serializers;
+
+internal sealed class ReportFileNameRequest(string fileName) : IRequest
+{
+ public string FileName { get; } = fileName;
+}
+
+internal class ReportFileNameRequestSerializer : BaseSerializer, INamedPipeSerializer
+{
+ public int Id => 1;
+
+ public object Deserialize(Stream stream)
+ {
+ string reportFileName = ReadString(stream);
+ return new ReportFileNameRequest(reportFileName);
+ }
+
+ public void Serialize(object objectToSerialize, Stream stream)
+ {
+ var reportFileName = (ReportFileNameRequest)objectToSerialize;
+ WriteString(stream, reportFileName.FileName);
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Serializers/TestAdapterInformationsSerializer.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Serializers/TestAdapterInformationsSerializer.cs
new file mode 100644
index 0000000000..7c3c41e2f0
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Serializers/TestAdapterInformationsSerializer.cs
@@ -0,0 +1,39 @@
+// 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.IPC;
+using Microsoft.Testing.Platform.IPC.Serializers;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions.Serializers;
+
+internal class TestAdapterInformationRequest : IRequest
+{
+ public TestAdapterInformationRequest(string testAdapterId, string testAdapterVersion)
+ {
+ TestAdapterId = testAdapterId;
+ TestAdapterVersion = testAdapterVersion;
+ }
+
+ public string TestAdapterId { get; }
+
+ public string TestAdapterVersion { get; }
+}
+
+internal class TestAdapterInformationRequestSerializer : BaseSerializer, INamedPipeSerializer
+{
+ public int Id => 2;
+
+ public object Deserialize(Stream stream)
+ {
+ string testAdapterId = ReadString(stream);
+ string testAdapterVersion = ReadString(stream);
+ return new TestAdapterInformationRequest(testAdapterId, testAdapterVersion);
+ }
+
+ public void Serialize(object objectToSerialize, Stream stream)
+ {
+ var testAdapterInformationRequest = (TestAdapterInformationRequest)objectToSerialize;
+ WriteString(stream, testAdapterInformationRequest.TestAdapterId);
+ WriteString(stream, testAdapterInformationRequest.TestAdapterVersion);
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TestingPlatformBuilderHook.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TestingPlatformBuilderHook.cs
new file mode 100644
index 0000000000..8ac8e958db
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TestingPlatformBuilderHook.cs
@@ -0,0 +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.Testing.Platform.Builder;
+
+namespace Microsoft.Testing.Extensions.TrxReport;
+
+public static class TestingPlatformBuilderHook
+{
+ public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] _)
+ => testApplicationBuilder.AddTrxReportProvider();
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/ToolTrxCompareFactory.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/ToolTrxCompareFactory.cs
new file mode 100644
index 0000000000..e88cb5b300
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/ToolTrxCompareFactory.cs
@@ -0,0 +1,34 @@
+// 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.TestReports.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.OutputDevice;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+internal sealed class ToolTrxCompareFactory : IExtension
+{
+ ///
+ public string Uid { get; } = nameof(TrxCompareTool);
+
+ ///
+ public string Version { get; } = AppVersion.DefaultSemVer;
+
+ ///
+ public string DisplayName { get; } = ExtensionResources.TrxComparerToolDisplayName;
+
+ ///
+ public string Description { get; } = ExtensionResources.TrxComparerToolDescription;
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public TrxCompareTool CreateTrxCompareTool(ICommandLineOptions commandLineOptions, IOutputDevice outputDisplay, ITask task)
+ => new(commandLineOptions, this, outputDisplay, task);
+
+ public TrxCompareToolCommandLine CreateTrxCompareToolCommandLine()
+ => new(this);
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCommandLine.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCommandLine.cs
new file mode 100644
index 0000000000..51f36f19dc
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCommandLine.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.
+
+using Microsoft.Testing.Extensions.TestReports.Resources;
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.CommandLine;
+using Microsoft.Testing.Platform.Helpers;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+internal sealed class TrxReportGeneratorCommandLine : ICommandLineOptionsProvider
+{
+ public const string TrxReportOptionName = "report-trx";
+ public const string TrxReportFileNameOptionName = "report-trx-filename";
+
+ ///
+ public string Uid { get; } = nameof(TrxReportGeneratorCommandLine);
+
+ ///
+ public string Version { get; } = AppVersion.DefaultSemVer;
+
+ ///
+ public string DisplayName { get; } = ExtensionResources.TrxReportGeneratorDisplayName;
+
+ ///
+ public string Description { get; } = ExtensionResources.TrxReportGeneratorDescription;
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public IReadOnlyCollection GetCommandLineOptions()
+ =>
+ [
+ new(TrxReportOptionName, ExtensionResources.TrxReportOptionDescription, ArgumentArity.Zero, false),
+ new(TrxReportFileNameOptionName, ExtensionResources.TrxReportFileNameOptionDescription, ArgumentArity.ExactlyOne, false)
+ ];
+
+ public Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
+ {
+ if (commandOption.Name == TrxReportFileNameOptionName)
+ {
+ if (!arguments[0].EndsWith(".trx", StringComparison.OrdinalIgnoreCase))
+ {
+ return ValidationResult.InvalidTask(ExtensionResources.TrxReportFileNameExtensionIsNotTrx);
+ }
+
+ if (!RoslynString.IsNullOrEmpty(Path.GetDirectoryName(arguments[0])))
+ {
+ return ValidationResult.InvalidTask(ExtensionResources.TrxReportFileNameShouldNotContainPath);
+ }
+ }
+
+ return ValidationResult.ValidTask;
+ }
+
+ public Task ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
+ {
+ if (commandLineOptions.IsOptionSet(TrxReportFileNameOptionName)
+ && !commandLineOptions.IsOptionSet(TrxReportOptionName))
+ {
+ return ValidationResult.InvalidTask(ExtensionResources.TrxReportFileNameRequiresTrxReport);
+ }
+
+ if (commandLineOptions.IsOptionSet(TrxReportOptionName)
+ && commandLineOptions.IsOptionSet(PlatformCommandLineProvider.DiscoverTestsOptionKey))
+ {
+ return ValidationResult.InvalidTask(ExtensionResources.TrxReportIsNotValidForDiscovery);
+ }
+
+ // No problem found
+ return ValidationResult.ValidTask;
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.CommandLine.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.CommandLine.cs
new file mode 100644
index 0000000000..5738762730
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.CommandLine.cs
@@ -0,0 +1,84 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.TestReports.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.CommandLine;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.Tools;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+internal class TrxCompareToolCommandLine : IToolCommandLineOptionsProvider
+{
+ public const string BaselineTrxOptionName = "baseline-trx";
+ public const string TrxToCompareOptionName = "trx-to-compare";
+ private readonly IExtension _extension;
+
+ public TrxCompareToolCommandLine(IExtension extension)
+ {
+ _extension = extension;
+ Uid = _extension.Uid;
+ Version = _extension.Version;
+ DisplayName = _extension.DisplayName;
+ Description = _extension.Description;
+ }
+
+ ///
+ public string Uid { get; }
+
+ ///
+ public string Version { get; } = AppVersion.DefaultSemVer;
+
+ ///
+ public string DisplayName { get; }
+
+ ///
+ public string Description { get; }
+
+ ///
+ public string ToolName { get; } = TrxCompareTool.ToolName;
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public IReadOnlyCollection GetCommandLineOptions()
+ =>
+ [
+ new(BaselineTrxOptionName, ExtensionResources.TrxComparerToolBaselineFileOptionDescription, ArgumentArity.ExactlyOne, false),
+ new(TrxToCompareOptionName, ExtensionResources.TrxComparerToolOtherFileOptionDescription, ArgumentArity.ExactlyOne, false)
+ ];
+
+ public Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
+ {
+ if (commandOption.Name == BaselineTrxOptionName && (!arguments[0].EndsWith(".trx", StringComparison.OrdinalIgnoreCase) || !File.Exists(arguments[0])))
+ {
+ return ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxComparerToolOptionExpectsSingleArgument, BaselineTrxOptionName));
+ }
+
+ if (commandOption.Name == TrxToCompareOptionName && (!arguments[0].EndsWith(".trx", StringComparison.OrdinalIgnoreCase) || !File.Exists(arguments[0])))
+ {
+ return ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxComparerToolOptionExpectsSingleArgument, TrxToCompareOptionName));
+ }
+
+ // No problem found
+ return ValidationResult.ValidTask;
+ }
+
+ public Task ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
+ {
+ if ((commandLineOptions.IsOptionSet(BaselineTrxOptionName) && !commandLineOptions.IsOptionSet(TrxToCompareOptionName))
+ || (!commandLineOptions.IsOptionSet(BaselineTrxOptionName) && commandLineOptions.IsOptionSet(TrxToCompareOptionName)))
+ {
+ return Task.FromResult(
+ ValidationResult.Invalid(
+ string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxComparerToolBothFilesMustBeSpecified, BaselineTrxOptionName, TrxToCompareOptionName)));
+ }
+
+ // No problem found
+ return ValidationResult.ValidTask;
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs
new file mode 100644
index 0000000000..54954ce08f
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs
@@ -0,0 +1,250 @@
+// 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.Globalization;
+using System.Text;
+using System.Xml.Linq;
+
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.OutputDevice;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.Testing.Platform.Tools;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+internal class TrxCompareTool : ITool, IOutputDeviceDataProducer
+{
+ public const string ToolName = "ms-trxcompare";
+ private readonly ICommandLineOptions _commandLineOptions;
+ private readonly IExtension _extension;
+ private readonly IOutputDevice _outputDisplay;
+ private readonly ITask _task;
+
+ public TrxCompareTool(ICommandLineOptions commandLineOptions, IExtension extension, IOutputDevice outputDisplay,
+ ITask task)
+ {
+ _commandLineOptions = commandLineOptions;
+ _extension = extension;
+ _outputDisplay = outputDisplay;
+ _task = task;
+ }
+
+ ///
+ public string Name { get; } = ToolName;
+
+ ///
+ public bool Hidden { get; }
+
+ ///
+ public string Uid => _extension.Uid;
+
+ ///
+ public string Version => _extension.Version;
+
+ ///
+ public string DisplayName => _extension.DisplayName;
+
+ ///
+ public string Description => _extension.Description;
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ public async Task RunAsync()
+ {
+ if (!_commandLineOptions.TryGetOptionArgumentList(TrxCompareToolCommandLine.BaselineTrxOptionName, out string[]? baselineFilePaths)
+ || !_commandLineOptions.TryGetOptionArgumentList(TrxCompareToolCommandLine.TrxToCompareOptionName, out string[]? comparedFilePaths))
+ {
+ throw ApplicationStateGuard.Unreachable();
+ }
+
+ 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();
+ await _task.WhenAll(
+ _task.Run(() => CollectEntriesAndErrors(baselineFilePaths[0], trxNamespace, baseLineResults, baseLineIssues)),
+ _task.Run(() => CollectEntriesAndErrors(comparedFilePaths[0], trxNamespace, comparedResults, comparedIssues)));
+
+ StringBuilder outputBuilder = new();
+ AppendResultsAndIssues("Baseline", baselineFilePaths[0], baseLineResults, baseLineIssues, outputBuilder);
+ AppendResultsAndIssues("Compared TRX", comparedFilePaths[0], comparedResults, comparedIssues, outputBuilder);
+
+ if (AreMatchingTrxFiles(baseLineResults, comparedResults, outputBuilder))
+ {
+ await _outputDisplay.DisplayAsync(this, new TextOutputDeviceData(outputBuilder.ToString()));
+ return ExitCodes.Success;
+ }
+ else
+ {
+ await _outputDisplay.DisplayAsync(this, new TextOutputDeviceData(outputBuilder.ToString()));
+ return ExitCodes.GenericFailure;
+ }
+ }
+
+ private static bool AreMatchingTrxFiles(
+ List<(string TestName, string Outcome, string Storage)> baseLineResults,
+ List<(string TestName, string Outcome, string Storage)> comparedResults,
+ StringBuilder outputBuilder)
+ {
+ bool checkFailed = false;
+ outputBuilder.AppendLine("--- Comparing TRX files ---");
+
+ IEnumerable<((string TestName, string Outcome, string Storage), 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)
+ {
+ string otherSource = entrySource == "baseline" ? "other" : "baseline";
+ IEnumerable<(string MatchingTestName, string MatchingOutcome, string MatchingStorage)> matchingEntries =
+ entrySource == "baseline"
+ ? comparedResults.Where(x => x.TestName == sourceTrx.TestName)
+ : baseLineResults.Where(x => x.TestName == sourceTrx.TestName);
+ if (!matchingEntries.Any())
+ {
+ checkFailed = true;
+ outputBuilder.AppendLine(
+ CultureInfo.InvariantCulture,
+ $" - Test '{sourceTrx.TestName}' is missing inside the trx '{otherSource}'");
+ continue;
+ }
+
+ if (matchingEntries.Skip(1).Any())
+ {
+ checkFailed = true;
+ outputBuilder.AppendLine(
+ CultureInfo.InvariantCulture,
+ $" - Test '{sourceTrx.TestName}' is found multiple times inside the trx '{otherSource}'");
+ continue;
+ }
+
+ (string otherTestName, string otherOutcome, string otherStorage) = matchingEntries.First();
+ if (sourceTrx.Outcome != otherOutcome)
+ {
+ checkFailed = true;
+ outputBuilder.AppendLine(
+ CultureInfo.InvariantCulture,
+ $" - Test '{sourceTrx.TestName}' has a different outcome. Got '{otherOutcome}', expected '{sourceTrx.Outcome}'");
+ }
+ }
+
+ outputBuilder.AppendLine();
+ if (checkFailed)
+ {
+ outputBuilder.AppendLine("Comparison check failed!");
+ }
+ else
+ {
+ outputBuilder.AppendLine("Comparison check succeeded!");
+ }
+
+ return !checkFailed;
+ }
+
+ private static void AppendResultsAndIssues(string category, string filePath,
+ List<(string TestName, string Outcome, string Storage)> results, List issues, StringBuilder outputBuilder)
+ {
+ outputBuilder.AppendLine(CultureInfo.InvariantCulture, $"--- {category} ---");
+ outputBuilder.AppendLine(CultureInfo.InvariantCulture, $"File '{filePath}'");
+
+ outputBuilder.AppendLine("Issues:");
+ foreach (string issue in issues)
+ {
+ outputBuilder.AppendLine(CultureInfo.InvariantCulture, $" - {issue}");
+ }
+
+ if (issues.Count == 0)
+ {
+ outputBuilder.AppendLine(" None");
+ }
+
+ outputBuilder.AppendLine();
+ outputBuilder.AppendLine("Test containers (assemblies):");
+ foreach (string? storage in results.Select(x => x.Storage).Distinct())
+ {
+ outputBuilder.AppendLine(CultureInfo.InvariantCulture, $" - {storage}");
+ }
+
+ outputBuilder.AppendLine();
+ outputBuilder.AppendLine("Test results:");
+ foreach ((string outcome, int resultCount) in results.GroupBy(x => x.Outcome, (key, results) => (key, results.Count())))
+ {
+ outputBuilder.AppendLine(CultureInfo.InvariantCulture, $" - {outcome}: {resultCount}");
+ }
+
+ outputBuilder.AppendLine();
+ }
+
+ private static void CollectEntriesAndErrors(string trxFile, XNamespace ns, List<(string TestName, string Outcome, string Storage)> results, List issues)
+ {
+ var trxTestRun = XElement.Parse(File.ReadAllText(trxFile));
+ int testResultIndex = 0;
+ foreach (XElement testResult in trxTestRun.Elements(ns + "Results").Elements(ns + "UnitTestResult"))
+ {
+ testResultIndex++;
+ string? testId = testResult.Attribute("testId")?.Value;
+ if (testId is null)
+ {
+ issues.Add($"UnitTestResult at index '{testResultIndex}' is missing 'testId' attribute.");
+ continue;
+ }
+
+ string? testResultTestName = testResult.Attribute("testName")?.Value;
+ if (testResultTestName is null)
+ {
+ issues.Add($"UnitTestResult at index '{testResultIndex}' is missing 'testName' attribute.");
+ continue;
+ }
+
+ string? testResultOutcome = testResult.Attribute("outcome")?.Value;
+ if (testResultOutcome is null)
+ {
+ issues.Add($"UnitTestResult at index '{testResultIndex}' is missing 'outcome' attribute.");
+ continue;
+ }
+
+ IEnumerable matchingUnitTestDefinitions = trxTestRun
+ .Elements(ns + "TestDefinitions")
+ .Elements(ns + "UnitTest")
+ .Where(x => x.Attribute("id")?.Value == testId);
+ if (matchingUnitTestDefinitions.Skip(1).Any())
+ {
+ issues.Add($"Found more than one entry in 'TestDefinitions.UnitTest' matching the test ID '{testId}'.");
+ continue;
+ }
+
+ if (!matchingUnitTestDefinitions.Any())
+ {
+ issues.Add($"Cannot find any 'TestDefinitions.UnitTest' matching the test ID '{testId}'.");
+ continue;
+ }
+
+ XElement matchingUnitTestDefinition = matchingUnitTestDefinitions.First();
+ string testDefinitionId = matchingUnitTestDefinition.Attribute("id")!.Value;
+
+ string? testDefinitionStorage = matchingUnitTestDefinition.Attribute("storage")?.Value;
+ if (testDefinitionStorage is null)
+ {
+ issues.Add($"Cannot find attribute 'storage' for 'TestDefinitions.UnitTest' with ID '{testDefinitionId}'.");
+ continue;
+ }
+
+ string? testDefinitionClassName = matchingUnitTestDefinition.Element(ns + "TestMethod")
+ ?.Attribute("className")
+ ?.Value;
+ if (testDefinitionClassName is null)
+ {
+ issues.Add($"Cannot find attribute 'className' on sub node 'TestMethod' for 'TestDefinitions.UnitTest' with ID '{testDefinitionId}'.");
+ continue;
+ }
+
+ results.Add((testDefinitionClassName + "." + testResultTestName, testResultOutcome, testDefinitionStorage));
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs
new file mode 100644
index 0000000000..7e82970344
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs
@@ -0,0 +1,258 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.TestReports.Resources;
+using Microsoft.Testing.Extensions.TrxReport.Abstractions.Serializers;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Extensions.OutputDevice;
+using Microsoft.Testing.Platform.Extensions.TestFramework;
+using Microsoft.Testing.Platform.Extensions.TestHost;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.IPC.Models;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.Messages;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.Testing.Platform.TestHost;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+internal sealed class TrxReportGenerator :
+ IDataConsumer,
+ ITestSessionLifetimeHandler,
+ IDataProducer,
+ IOutputDeviceDataProducer
+{
+ private readonly IConfiguration _configuration;
+ private readonly ICommandLineOptions _commandLineOptionsService;
+ private readonly ITestApplicationModuleInfo _testApplicationModuleInfo;
+ private readonly IMessageBus _messageBus;
+ private readonly IClock _clock;
+ private readonly IEnvironment _environment;
+ private readonly IOutputDevice _outputDisplay;
+ private readonly ITestFramework _testFramework;
+ private readonly ITestFrameworkCapabilities _testFrameworkCapabilities;
+ private readonly TrxReportGeneratorCommandLine _trxReportGeneratorCommandLine;
+ private readonly TrxTestApplicationLifecycleCallbacks? _trxTestApplicationLifecycleCallbacks;
+ private readonly ILogger _logger;
+ private readonly List _tests = [];
+ private readonly Dictionary> _artifactsByTestNode = new();
+ private readonly Dictionary> _artifactsByExtension = new();
+ private readonly bool _isEnabled;
+
+ private DateTimeOffset? _testStartTime;
+ private int _failedTestsCount;
+ private int _passedTestsCount;
+ private bool _adapterSupportTrxCapability;
+
+ public TrxReportGenerator(
+ IConfiguration configuration,
+ ICommandLineOptions commandLineOptionsService,
+ ITestApplicationModuleInfo testApplicationModuleInfo,
+ IMessageBus messageBus,
+ IClock clock,
+ IEnvironment environment,
+ IOutputDevice outputDisplay,
+ ITestFramework testFramework,
+ ITestFrameworkCapabilities testFrameworkCapabilities,
+ TrxReportGeneratorCommandLine trxReportGeneratorCommandLine,
+ // Can be null in case of server mode
+ TrxTestApplicationLifecycleCallbacks? trxTestApplicationLifecycleCallbacks,
+ ILogger logger)
+ {
+ _configuration = configuration;
+ _commandLineOptionsService = commandLineOptionsService;
+ _testApplicationModuleInfo = testApplicationModuleInfo;
+ _messageBus = messageBus;
+ _clock = clock;
+ _environment = environment;
+ _outputDisplay = outputDisplay;
+ _testFramework = testFramework;
+ _testFrameworkCapabilities = testFrameworkCapabilities;
+ _trxReportGeneratorCommandLine = trxReportGeneratorCommandLine;
+ _trxTestApplicationLifecycleCallbacks = trxTestApplicationLifecycleCallbacks;
+ _logger = logger;
+ _isEnabled = commandLineOptionsService.IsOptionSet(TrxReportGeneratorCommandLine.TrxReportOptionName);
+ }
+
+ public Type[] DataTypesConsumed { get; } =
+ [
+ typeof(TestNodeUpdateMessage),
+ typeof(TestNodeFileArtifact),
+ typeof(SessionFileArtifact)
+ ];
+
+ public Type[] DataTypesProduced { get; } = [typeof(SessionFileArtifact)];
+
+ ///
+ public string Uid { get; } = nameof(TrxReportGenerator);
+
+ ///
+ public string Version { get; } = AppVersion.DefaultSemVer;
+
+ ///
+ public string DisplayName { get; } = ExtensionResources.TrxReportGeneratorDisplayName;
+
+ ///
+ public string Description { get; } = ExtensionResources.TrxReportGeneratorDescription;
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(_isEnabled);
+
+ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationToken cancellationToken)
+ {
+ if (!_isEnabled || cancellationToken.IsCancellationRequested)
+ {
+ return Task.CompletedTask;
+ }
+
+ try
+ {
+ switch (value)
+ {
+ case TestNodeUpdateMessage nodeChangedMessage:
+ TestNodeStateProperty nodeState = nodeChangedMessage.TestNode.Properties.Single();
+ if (nodeState is PassedTestNodeStateProperty)
+ {
+ _tests.Add(nodeChangedMessage);
+ _passedTestsCount++;
+ }
+ else if (Array.IndexOf(TestNodePropertiesCategories.WellKnownTestNodeTestRunOutcomeFailedProperties, nodeState.GetType()) != -1)
+ {
+ _tests.Add(nodeChangedMessage);
+ _failedTestsCount++;
+ }
+ else if (nodeState is SkippedTestNodeStateProperty)
+ {
+ _tests.Add(nodeChangedMessage);
+ }
+
+ break;
+ case TestNodeFileArtifact testNodeFileArtifact:
+ if (!_artifactsByTestNode.TryGetValue(testNodeFileArtifact.TestNode.Uid, out List? nodeFileArtifacts))
+ {
+ nodeFileArtifacts = [testNodeFileArtifact];
+ _artifactsByTestNode[testNodeFileArtifact.TestNode.Uid] = nodeFileArtifacts;
+ }
+ else
+ {
+ nodeFileArtifacts.Add(testNodeFileArtifact);
+ }
+
+ break;
+ case SessionFileArtifact fileArtifact:
+ if (!_artifactsByExtension.TryGetValue(dataProducer, out List? sessionFileArtifacts))
+ {
+ sessionFileArtifacts = [fileArtifact];
+ _artifactsByExtension[dataProducer] = sessionFileArtifacts;
+ }
+ else
+ {
+ sessionFileArtifacts.Add(fileArtifact);
+ }
+
+ break;
+ }
+ }
+ catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken)
+ {
+ // Do nothing, we're stopping
+ }
+
+ return Task.CompletedTask;
+ }
+
+ public async Task OnTestSessionStartingAsync(SessionUid _, CancellationToken cancellationToken)
+ {
+ if (!_isEnabled || cancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ if (_logger.IsEnabled(LogLevel.Debug))
+ {
+ await _logger.LogDebugAsync($"""
+PlatformCommandLineProvider.ServerOption: {_commandLineOptionsService.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey)}
+CrashDumpCommandLineOptions.CrashDumpOptionName: {_commandLineOptionsService.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName)}
+TrxReportGeneratorCommandLine.IsTrxReportEnabled: {_commandLineOptionsService.IsOptionSet(TrxReportGeneratorCommandLine.TrxReportOptionName)}
+""");
+ }
+
+ if (!_commandLineOptionsService.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey) &&
+ _commandLineOptionsService.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName))
+ {
+ ApplicationStateGuard.Ensure(_trxTestApplicationLifecycleCallbacks is not null);
+ ApplicationStateGuard.Ensure(_trxTestApplicationLifecycleCallbacks.NamedPipeClient is not null);
+
+ try
+ {
+ await _trxTestApplicationLifecycleCallbacks.NamedPipeClient.RequestReplyAsync(new TestAdapterInformationRequest(_testFramework.Uid, _testFramework.Version), cancellationToken)
+ .TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout);
+ }
+ catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken)
+ {
+ // Do nothing, we're stopping
+ }
+ }
+
+ ITrxReportCapability? trxCapability = _testFrameworkCapabilities.GetCapability();
+ if (_isEnabled && trxCapability is not null && trxCapability?.IsSupported == true)
+ {
+ _adapterSupportTrxCapability = true;
+ trxCapability.Enable();
+ }
+
+ _testStartTime = _clock.UtcNow;
+ }
+
+ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, CancellationToken cancellationToken)
+ {
+ if (!_isEnabled || cancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ try
+ {
+ if (!_adapterSupportTrxCapability)
+ {
+ await _outputDisplay.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateYellowConsoleColorText(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxReportFrameworkDoesNotSupportTrxReportCapability, _testFramework.DisplayName, _testFramework.Uid)));
+ }
+
+ ApplicationStateGuard.Ensure(_testStartTime is not null);
+
+ TrxReportEngine trxReportGeneratorEngine = new(_testApplicationModuleInfo, _environment, _commandLineOptionsService, _configuration,
+ _clock, _tests.ToArray(), _failedTestsCount, _passedTestsCount, _artifactsByExtension, _artifactsByTestNode,
+ _adapterSupportTrxCapability, _testFramework, _testStartTime.Value, cancellationToken);
+ string reportFileName = await trxReportGeneratorEngine.GenerateReportAsync();
+
+ if (
+
+ // TestController is not used when we run in server mode
+ _commandLineOptionsService.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey) ||
+
+ // If crash dump is not enabled we run trx in-process only
+ !_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));
+ }
+ else
+ {
+ ApplicationStateGuard.Ensure(_trxTestApplicationLifecycleCallbacks is not null);
+ ApplicationStateGuard.Ensure(_trxTestApplicationLifecycleCallbacks.NamedPipeClient is not null);
+ await _trxTestApplicationLifecycleCallbacks.NamedPipeClient.RequestReplyAsync(new ReportFileNameRequest(reportFileName), cancellationToken);
+ }
+ }
+ catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken)
+ {
+ // Do nothing, we're stopping
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxEnvironmentVariableProvider.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxEnvironmentVariableProvider.cs
new file mode 100644
index 0000000000..d19aa3f54e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxEnvironmentVariableProvider.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.Globalization;
+
+using Microsoft.Testing.Extensions.TestReports.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.TestHostControllers;
+using Microsoft.Testing.Platform.Helpers;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+internal sealed class TrxEnvironmentVariableProvider : ITestHostEnvironmentVariableProvider
+{
+ public const string TRXNAMEDPIPENAME = nameof(TRXNAMEDPIPENAME);
+
+ private readonly ICommandLineOptions _commandLineOptions;
+ private readonly string _pipeName;
+
+ public TrxEnvironmentVariableProvider(ICommandLineOptions commandLineOptions, string pipeName)
+ {
+ _commandLineOptions = commandLineOptions;
+ _pipeName = pipeName;
+ }
+
+ public string Uid => nameof(TrxEnvironmentVariableProvider);
+
+ public string Version => AppVersion.DefaultSemVer;
+
+ public string DisplayName => ExtensionResources.TrxReportGeneratorDisplayName;
+
+ public string Description => ExtensionResources.TrxReportGeneratorDescription;
+
+ public Task IsEnabledAsync()
+#pragma warning disable SA1114 // Parameter list should follow declaration
+ => Task.FromResult(
+ // TrxReportGenerator is enabled only when trx report is enabled
+ _commandLineOptions.IsOptionSet(TrxReportGeneratorCommandLine.TrxReportOptionName)
+ // TestController is not used when we run in server mode
+ && !_commandLineOptions.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey)
+ // If crash dump is not enabled we run trx in-process only
+ && _commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName));
+#pragma warning restore SA1114 // Parameter list should follow declaration
+
+ public Task UpdateAsync(IEnvironmentVariables environmentVariables)
+ {
+ environmentVariables.SetVariable(new(TRXNAMEDPIPENAME, _pipeName, false, true));
+ return Task.CompletedTask;
+ }
+
+ public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnlyEnvironmentVariables environmentVariables)
+ {
+ if (!environmentVariables.TryGetVariable(TRXNAMEDPIPENAME, out _))
+ {
+ return Task.FromResult(
+ ValidationResult.Invalid(
+ string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxReportGeneratorMissingTrxNamedPipeEnvironmentVariable, TRXNAMEDPIPENAME)));
+ }
+
+ // No problem found
+ return ValidationResult.ValidTask;
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs
new file mode 100644
index 0000000000..9d9b8d38f9
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs
@@ -0,0 +1,289 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.TestReports.Resources;
+using Microsoft.Testing.Extensions.TrxReport.Abstractions.Serializers;
+using Microsoft.Testing.Platform.Capabilities;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Extensions.TestFramework;
+using Microsoft.Testing.Platform.Extensions.TestHost;
+using Microsoft.Testing.Platform.Extensions.TestHostControllers;
+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.Logging;
+using Microsoft.Testing.Platform.Messages;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.Testing.Platform.TestHost;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+internal sealed class TrxProcessLifetimeHandler :
+ ITestHostProcessLifetimeHandler,
+ IDataConsumer,
+ IDataProducer,
+#if NETCOREAPP
+ IAsyncDisposable
+#else
+ IDisposable
+#endif
+{
+ private readonly ICommandLineOptions _commandLineOptions;
+ private readonly IEnvironment _environment;
+ private readonly IMessageBus _messageBus;
+ private readonly ITestApplicationModuleInfo _testApplicationModuleInfo;
+ private readonly IConfiguration _configuration;
+ private readonly IClock _clock;
+ private readonly ITask _task;
+ private readonly ILogger _logger;
+ private readonly PipeNameDescription _pipeNameDescription;
+ private readonly Dictionary> _fileArtifacts = new();
+ private readonly DateTimeOffset _startTime;
+
+ private NamedPipeServer? _singleConnectionNamedPipeServer;
+ private Task? _waitConnectionTask;
+ private ReportFileNameRequest? _fileNameRequest;
+ private TestAdapterInformationRequest? _testAdapterInformationRequest;
+
+ public TrxProcessLifetimeHandler(
+ ICommandLineOptions commandLineOptions,
+ IEnvironment environment,
+ ILoggerFactory loggerFactory,
+ IMessageBus messageBus,
+ ITestApplicationModuleInfo testApplicationModuleInfo,
+ IConfiguration configuration,
+ IClock clock,
+ ITask task,
+ PipeNameDescription pipeNameDescription)
+ {
+ _commandLineOptions = commandLineOptions;
+ _environment = environment;
+ _messageBus = messageBus;
+ _testApplicationModuleInfo = testApplicationModuleInfo;
+ _configuration = configuration;
+ _clock = clock;
+ _task = task;
+ _pipeNameDescription = pipeNameDescription;
+ _logger = loggerFactory.CreateLogger();
+ _startTime = _clock.UtcNow;
+ }
+
+ public string Uid => nameof(TrxProcessLifetimeHandler);
+
+ public string Version => AppVersion.DefaultSemVer;
+
+ public string DisplayName => string.Empty;
+
+ public string Description => string.Empty;
+
+ public Type[] DataTypesConsumed => [typeof(FileArtifact)];
+
+ public Type[] DataTypesProduced => [typeof(FileArtifact)];
+
+ public Task IsEnabledAsync()
+#pragma warning disable SA1114 // Parameter list should follow declaration
+ => Task.FromResult(
+ // TrxReportGenerator is enabled only when trx report is enabled
+ _commandLineOptions.IsOptionSet(TrxReportGeneratorCommandLine.TrxReportOptionName)
+ // TestController is not used when we run in server mode
+ && !_commandLineOptions.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey)
+ // If crash dump is not enabled we run trx in-process only
+ && _commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName));
+#pragma warning restore SA1114 // Parameter list should follow declaration
+
+ public Task BeforeTestHostProcessStartAsync(CancellationToken cancellation)
+ {
+ _waitConnectionTask = _task.Run(
+ async () =>
+ {
+ _singleConnectionNamedPipeServer = new(_pipeNameDescription, CallbackAsync, _environment, _logger, _task, 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);
+
+ return Task.CompletedTask;
+ }
+
+ public async Task OnTestHostProcessStartedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation)
+ {
+ if (_waitConnectionTask is null)
+ {
+ throw new InvalidOperationException(ExtensionResources.TrxReportGeneratorBeforeTestHostProcessStartAsyncNotCalled);
+ }
+
+ await _waitConnectionTask.TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellation);
+ }
+
+ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationToken cancellationToken)
+ {
+ if (!_fileArtifacts.TryGetValue(dataProducer, out List? fileArtifacts))
+ {
+ fileArtifacts = [];
+ _fileArtifacts.Add(dataProducer, fileArtifacts);
+ }
+
+ fileArtifacts.Add((FileArtifact)value);
+ return Task.CompletedTask;
+ }
+
+ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellation)
+ {
+ if (cancellation.IsCancellationRequested)
+ {
+ return;
+ }
+
+ Dictionary> artifacts = new();
+
+ foreach (KeyValuePair> prodArtifacts in _fileArtifacts)
+ {
+ var perProducerArtifact = new List();
+ var extensionInfo = new ExtensionInfo(prodArtifacts.Key.Uid, prodArtifacts.Key.Version, prodArtifacts.Key.DisplayName, prodArtifacts.Key.Description);
+ foreach (FileArtifact fileArtifact in prodArtifacts.Value)
+ {
+ perProducerArtifact.Add(new SessionFileArtifact(new SessionUid(Guid.Empty.ToString()), fileArtifact.FileInfo, fileArtifact.DisplayName, fileArtifact.Description));
+ }
+
+ artifacts.Add(extensionInfo, perProducerArtifact);
+ }
+
+ // We create a trx with only files in case of test host process crash.
+ if (!testHostProcessInformation.HasExitedGracefully)
+ {
+ TrxReportEngine trxReportGeneratorEngine = new(_testApplicationModuleInfo, _environment, _commandLineOptions, _configuration,
+ _clock, [], 0, 0,
+ artifacts,
+ new Dictionary>(),
+ adapterSupportTrxCapability: null,
+ new TestAdapterInfo(_testAdapterInformationRequest!.TestAdapterId, _testAdapterInformationRequest.TestAdapterVersion),
+ _startTime,
+ cancellation);
+
+ await _messageBus.PublishAsync(
+ this,
+ new FileArtifact(
+ new FileInfo(await trxReportGeneratorEngine.GenerateReportAsync(
+ isTestHostCrashed: true,
+ testHostCrashInfo: $"Test host process pid: {testHostProcessInformation.PID} crashed.")),
+ ExtensionResources.TrxReportArtifactDisplayName,
+ ExtensionResources.TrxReportArtifactDescription));
+ return;
+ }
+
+ if (_fileNameRequest is null)
+ {
+ throw ApplicationStateGuard.Unreachable();
+ }
+
+ var trxFile = new FileInfo(_fileNameRequest.FileName);
+
+ // Add attachments to the trx.
+ if (_fileArtifacts.Count > 0)
+ {
+ TrxReportEngine trxReportGeneratorEngine = new(_testApplicationModuleInfo, _environment, _commandLineOptions, _configuration,
+ _clock, [], 0, 0,
+ artifacts,
+ new Dictionary>(),
+ false,
+ new TestAdapterInfo(_testAdapterInformationRequest!.TestAdapterId, _testAdapterInformationRequest.TestAdapterVersion),
+ _startTime,
+ cancellation);
+
+ await trxReportGeneratorEngine.AddArtifactsAsync(trxFile, artifacts);
+ }
+
+ await _messageBus.PublishAsync(this, new FileArtifact(trxFile, ExtensionResources.TrxReportArtifactDisplayName, ExtensionResources.TrxReportArtifactDescription));
+ }
+
+ private Task CallbackAsync(IRequest request)
+ {
+ if (request is ReportFileNameRequest report)
+ {
+ _fileNameRequest = report;
+ return Task.FromResult((IResponse)VoidResponse.CachedInstance);
+ }
+ else if (request is TestAdapterInformationRequest testAdapterInformationRequest)
+ {
+ _testAdapterInformationRequest = testAdapterInformationRequest;
+ return Task.FromResult((IResponse)VoidResponse.CachedInstance);
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.UnsupportedRequestTypeErrorMessage, request.GetType().FullName));
+ }
+ }
+
+#if NETCOREAPP
+ public async ValueTask DisposeAsync()
+ {
+ await DisposeHelper.DisposeAsync(_singleConnectionNamedPipeServer);
+
+ // Dispose the pipe descriptor after the server to ensure the pipe is closed.
+ _pipeNameDescription?.Dispose();
+ }
+#else
+ public void Dispose()
+ {
+ _singleConnectionNamedPipeServer?.Dispose();
+
+ // Dispose the pipe descriptor after the server to ensure the pipe is closed.
+ _pipeNameDescription?.Dispose();
+ }
+#endif
+
+ private class ExtensionInfo : IExtension
+ {
+ public ExtensionInfo(string id, string semVer, string displayName, string description)
+ {
+ Uid = id;
+ Version = semVer;
+ DisplayName = displayName;
+ Description = description;
+ }
+
+ public string Uid { get; }
+
+ public string Version { get; }
+
+ public string DisplayName { get; }
+
+ public string Description { get; }
+
+ public Task IsEnabledAsync() => throw new NotImplementedException();
+ }
+
+ private class TestAdapterInfo : ITestFramework
+ {
+ public TestAdapterInfo(string id, string semVer)
+ {
+ Uid = id;
+ Version = semVer;
+ }
+
+ public string Uid { get; }
+
+ public string Version { get; }
+
+ public string DisplayName => throw new NotImplementedException();
+
+ public string Description => throw new NotImplementedException();
+
+ public ICapability[] Capabilities => throw new NotImplementedException();
+
+ public Task IsEnabledAsync() => throw new NotImplementedException();
+
+ public Task CloseTestSessionAsync(CloseTestSessionContext context) => throw new NotImplementedException();
+
+ public Task CreateTestSessionAsync(CreateTestSessionContext context) => throw new NotImplementedException();
+
+ public Task ExecuteRequestAsync(ExecuteRequestContext context) => throw new NotImplementedException();
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs
new file mode 100644
index 0000000000..d80c658f8e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs
@@ -0,0 +1,715 @@
+// 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.Globalization;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml.Linq;
+
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Extensions.TestFramework;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.Services;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+internal sealed partial class TrxReportEngine
+{
+ private const string UnitTestTypeGuid = "13CDC9D9-DDB5-4fa4-A97D-D965CCFC6D4B";
+
+ private static readonly Regex ReservedFileNamesRegex = BuildReservedFileNameRegex();
+ private static readonly Regex InvalidXmlCharReplace = BuildInvalidXmlCharReplace();
+ private static readonly MatchEvaluator InvalidXmlEvaluator = ReplaceInvalidCharacterWithUniCodeEscapeSequence;
+
+ private static readonly Type[] FailedStates =
+ [
+ typeof(FailedTestNodeStateProperty),
+ typeof(CancelledTestNodeStateProperty),
+ typeof(ErrorTestNodeStateProperty),
+ typeof(TimeoutTestNodeStateProperty)
+ ];
+
+ private static readonly HashSet InvalidFileNameChars =
+ [
+ '\"',
+ '<',
+ '>',
+ '|',
+ '\0',
+ (char)1,
+ (char)2,
+ (char)3,
+ (char)4,
+ (char)5,
+ (char)6,
+ (char)7,
+ (char)8,
+ (char)9,
+ (char)10,
+ (char)11,
+ (char)12,
+ (char)13,
+ (char)14,
+ (char)15,
+ (char)16,
+ (char)17,
+ (char)18,
+ (char)19,
+ (char)20,
+ (char)21,
+ (char)22,
+ (char)23,
+ (char)24,
+ (char)25,
+ (char)26,
+ (char)27,
+ (char)28,
+ (char)29,
+ (char)30,
+ (char)31,
+ ':',
+ '*',
+ '?',
+ '\\',
+ '/',
+ '@',
+ '(',
+ ')',
+ '^',
+ ' '
+ ];
+
+ private readonly ITestApplicationModuleInfo _testApplicationModuleInfo;
+ private readonly IEnvironment _environment;
+ private readonly ICommandLineOptions _commandLineOptionsService;
+ private readonly IConfiguration _configuration;
+ private readonly IClock _clock;
+ private readonly TestNodeUpdateMessage[] _testNodeUpdatedMessages;
+ private readonly int _failedTestsCount;
+ private readonly int _passedTestsCount;
+ private readonly Dictionary> _artifactsByExtension;
+ private readonly Dictionary> _artifactsByTestNode;
+ private readonly bool? _adapterSupportTrxCapability;
+ private readonly ITestFramework _testFrameworkAdapter;
+ private readonly DateTimeOffset _testStartTime;
+ private readonly CancellationToken _cancellationToken;
+ private readonly XNamespace _namespaceUri = XNamespace.Get("http://microsoft.com/schemas/VisualStudio/TeamTest/2010");
+ private readonly IFileSystem _fileSystem;
+ private readonly bool _isCopyingFileAllowed;
+
+ public TrxReportEngine(ITestApplicationModuleInfo testApplicationModuleInfo, IEnvironment environment, ICommandLineOptions commandLineOptionsService, IConfiguration configuration, IClock clock, TestNodeUpdateMessage[] testNodeUpdatedMessages, int failedTestsCount, int passedTestsCount, Dictionary> artifactsByExtension, Dictionary> artifactsByTestNode, bool? adapterSupportTrxCapability, ITestFramework testFrameworkAdapter, DateTimeOffset testStartTime, CancellationToken cancellationToken)
+ : this(
+ new SystemFileSystem(),
+ testApplicationModuleInfo,
+ environment,
+ commandLineOptionsService,
+ configuration,
+ clock,
+ testNodeUpdatedMessages,
+ failedTestsCount,
+ passedTestsCount,
+ artifactsByExtension,
+ artifactsByTestNode,
+ adapterSupportTrxCapability,
+ testFrameworkAdapter,
+ testStartTime,
+ cancellationToken)
+ {
+ }
+
+ internal TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testApplicationModuleInfo, IEnvironment environment, ICommandLineOptions commandLineOptionsService, IConfiguration configuration, IClock clock, TestNodeUpdateMessage[] testNodeUpdatedMessages, int failedTestsCount, int passedTestsCount, Dictionary> artifactsByExtension, Dictionary> artifactsByTestNode, bool? adapterSupportTrxCapability, ITestFramework testFrameworkAdapter, DateTimeOffset testStartTime, CancellationToken cancellationToken, bool isCopyingFileAllowed = true)
+ {
+ _testApplicationModuleInfo = testApplicationModuleInfo;
+ _environment = environment;
+ _commandLineOptionsService = commandLineOptionsService;
+ _configuration = configuration;
+ _clock = clock;
+ _testNodeUpdatedMessages = testNodeUpdatedMessages;
+ _failedTestsCount = failedTestsCount;
+ _passedTestsCount = passedTestsCount;
+ _artifactsByExtension = artifactsByExtension;
+ _artifactsByTestNode = artifactsByTestNode;
+ _adapterSupportTrxCapability = adapterSupportTrxCapability;
+ _testFrameworkAdapter = testFrameworkAdapter;
+ _testStartTime = testStartTime;
+ _cancellationToken = cancellationToken;
+ _fileSystem = fileSystem;
+ _isCopyingFileAllowed = isCopyingFileAllowed;
+ }
+
+ public async Task GenerateReportAsync(string testHostCrashInfo = "", bool isTestHostCrashed = false, bool keepReportFileStreamOpen = false)
+ => await RetryWhenIOExceptionAsync(async () =>
+ {
+ string testAppModule = _testApplicationModuleInfo.GetCurrentTestApplicationFullPath();
+
+ // 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());
+ string testRunName = $"{_environment.GetEnvironmentVariable("UserName")}@{_environment.MachineName} {FormatDateTimeForRunName(_clock.UtcNow)}";
+ testRun.SetAttributeValue("name", testRunName);
+
+ AddTimes(testRun);
+
+ // If the user added the the trxFileName the runDeploymentRoot would stay the same, We think it's a bug but I found that same behavior on vstest
+ string runDeploymentRoot = AddTestSettings(testRun, testRunName);
+ string trxFileName = $"{runDeploymentRoot}.trx";
+ if (_commandLineOptionsService.TryGetOptionArgumentList(TrxReportGeneratorCommandLine.TrxReportFileNameOptionName, out string[]? fileName))
+ {
+ trxFileName = ReplaceInvalidFileNameChars(fileName[0]);
+ }
+
+ AddResults(testAppModule, testRun, out XElement testDefinitions, out XElement testEntries, out string uncategorizedTestId, out string resultSummaryOutcome);
+ testRun.Add(testDefinitions);
+ testRun.Add(testEntries);
+ AddTestLists(testRun, uncategorizedTestId);
+
+ // NotExecuted is the status for the skipped test.
+ resultSummaryOutcome = isTestHostCrashed ? "Failed" : resultSummaryOutcome is "Passed" or "NotExecuted" ? "Completed" : resultSummaryOutcome;
+
+ await AddResultSummaryAsync(testRun, resultSummaryOutcome, runDeploymentRoot, testHostCrashInfo, isTestHostCrashed);
+
+ // will need catch Unauthorized access
+ document.Add(testRun);
+
+ foreach (XElement node in document.Root!.Descendants().Where(n => n.Name.NamespaceName == string.Empty))
+ {
+ // Remove the xmlns='' attribute. Note the use of
+ // Attributes rather than Attribute, in case the
+ // attribute doesn't exist (which it might not if we'd
+ // created the document "manually" instead of loading
+ // it from a file.)
+ node.Attributes("xmlns").Remove();
+
+ // Inherit the parent namespace instead
+ node.Name = node.Parent!.Name.Namespace + node.Name.LocalName;
+ }
+
+ string outputDirectory = _configuration.GetTestResultDirectory(); // add var for this
+ string finalFileName = Path.Combine(outputDirectory, trxFileName);
+ Stream stream = _fileSystem.NewFileStream(finalFileName, FileMode.CreateNew).Stream;
+ try
+ {
+#if NETCOREAPP
+ await document.SaveAsync(stream, SaveOptions.None, _cancellationToken);
+ return finalFileName;
+#else
+ _cancellationToken.ThrowIfCancellationRequested();
+ document.Save(stream);
+ return await Task.FromResult(finalFileName);
+#endif
+ }
+ finally
+ {
+ if (!keepReportFileStreamOpen)
+ {
+#if NET
+ await stream.DisposeAsync();
+#else
+ stream.Dispose();
+#endif
+ }
+ }
+ });
+
+ private async Task RetryWhenIOExceptionAsync(Func> func)
+ {
+ DateTimeOffset firstTryTime = _clock.UtcNow;
+ bool throwIOException = false;
+ while (true)
+ {
+ try
+ {
+ return await func();
+ }
+ catch (IOException)
+ {
+ // In case of file with the same name we retry with a new name.
+ if (throwIOException)
+ {
+ throw;
+ }
+ }
+
+ // We try for 30 seconds to create a file with a unique name.
+ if (_clock.UtcNow - firstTryTime > TimeSpan.FromSeconds(30))
+ {
+ throwIOException = true;
+ }
+ }
+ }
+
+ public async Task AddArtifactsAsync(FileInfo trxFile, Dictionary> artifacts)
+ {
+ var document = XDocument.Load(trxFile.FullName);
+ XElement deployment = document.Element(_namespaceUri + "TestRun")?.Element(_namespaceUri + "TestSettings")?.Element(_namespaceUri + "Deployment")
+ ?? throw new InvalidOperationException("Deployment element not found");
+ string? runDeploymentRoot = deployment.Attribute("runDeploymentRoot")?.Value
+ ?? throw new InvalidOperationException("Unexpected null 'runDeploymentRoot'");
+ XElement? resultSummary = document.Element(_namespaceUri + "TestRun")?.Element(_namespaceUri + "ResultSummary")
+ ?? throw new InvalidOperationException("ResultSummary element not found");
+ XElement? collectorDataEntries = resultSummary.Element(_namespaceUri + "CollectorDataEntries");
+ if (collectorDataEntries is null)
+ {
+ collectorDataEntries = new XElement(_namespaceUri + "CollectorDataEntries");
+ resultSummary.Add(collectorDataEntries);
+ }
+
+ foreach (KeyValuePair> extensionArtifacts in artifacts)
+ {
+ var collector = new XElement(
+ _namespaceUri + "Collector",
+ new XAttribute("agentName", _environment.MachineName),
+ new XAttribute("uri", $"datacollector://{extensionArtifacts.Key.Uid}/{extensionArtifacts.Key.Version}"),
+ new XAttribute("collectorDisplayName", extensionArtifacts.Key.DisplayName));
+ collectorDataEntries.Add(collector);
+
+ var uriAttachments = new XElement(_namespaceUri + "UriAttachments");
+ collector.Add(uriAttachments);
+
+ foreach (SessionFileArtifact artifact in extensionArtifacts.Value)
+ {
+ string href = await CopyArtifactIntoTrxDirectoryAndReturnHrefValueAsync(artifact.FileInfo, runDeploymentRoot);
+ uriAttachments.Add(new XElement(_namespaceUri + "UriAttachment", new XElement(_namespaceUri + "A", new XAttribute("href", href))));
+ }
+ }
+
+#if NETCOREAPP
+ using FileStream fs = File.OpenWrite(trxFile.FullName);
+ await document.SaveAsync(fs, SaveOptions.None, _cancellationToken);
+#else
+ _cancellationToken.ThrowIfCancellationRequested();
+ document.Save(trxFile.FullName);
+ await Task.CompletedTask;
+#endif
+ }
+
+ private async Task AddResultSummaryAsync(XElement testRun, string resultSummaryOutcome, string runDeploymentRoot, string testHostCrashInfo, bool isTestHostCrashed = false)
+ {
+ var resultSummary = new XElement(
+ _namespaceUri + "ResultSummary",
+ new XAttribute("outcome", resultSummaryOutcome));
+ testRun.Add(resultSummary);
+
+ var counters = new XElement(
+ _namespaceUri + "Counters",
+ new XAttribute("total", _testNodeUpdatedMessages.Length),
+ new XAttribute("executed", _passedTestsCount + _failedTestsCount),
+ new XAttribute("passed", _passedTestsCount),
+ new XAttribute("failed", _failedTestsCount),
+ new XAttribute("error", 0),
+ new XAttribute("timeout", 0),
+ new XAttribute("aborted", 0),
+ new XAttribute("inconclusive", 0),
+ new XAttribute("passedButRunAborted", 0),
+ new XAttribute("notRunnable", 0),
+ new XAttribute("notExecuted", 0),
+ new XAttribute("disconnected", 0),
+ new XAttribute("warning", 0),
+ new XAttribute("completed", 0),
+ new XAttribute("inProgress", 0),
+ new XAttribute("pending", 0));
+ resultSummary.Add(counters);
+
+ if (isTestHostCrashed)
+ {
+ var runInfos = new XElement(_namespaceUri + "RunInfos");
+ resultSummary.Add(runInfos);
+ var runInfo = new XElement(
+ _namespaceUri + "RunInfo",
+ new XAttribute("computerName", _environment.MachineName),
+ new XAttribute("outcome", "Error"),
+ new XAttribute("timestamp", _clock.UtcNow.DateTime));
+ var text = new XElement(_namespaceUri + "Text", testHostCrashInfo);
+ runInfo.Add(text);
+ runInfos.Add(runInfo);
+ }
+
+ if (_artifactsByExtension.Count == 0)
+ {
+ return;
+ }
+
+ var collectorDataEntries = new XElement(_namespaceUri + "CollectorDataEntries");
+ resultSummary.Add(collectorDataEntries);
+
+ foreach (KeyValuePair> tuple in _artifactsByExtension)
+ {
+ var collector = new XElement(
+ _namespaceUri + "Collector",
+ new XAttribute("agentName", _environment.MachineName),
+ new XAttribute("uri", $"datacollector://{tuple.Key.Uid}/{tuple.Key.Version}"),
+ new XAttribute("collectorDisplayName", tuple.Key.DisplayName));
+ collectorDataEntries.Add(collector);
+
+ var uriAttachments = new XElement(_namespaceUri + "UriAttachments");
+ collector.Add(uriAttachments);
+
+ foreach (SessionFileArtifact artifact in tuple.Value)
+ {
+ string href = await CopyArtifactIntoTrxDirectoryAndReturnHrefValueAsync(artifact.FileInfo, runDeploymentRoot);
+ uriAttachments.Add(new XElement(_namespaceUri + "UriAttachment", new XElement(_namespaceUri + "A", new XAttribute("href", href))));
+ }
+ }
+ }
+
+ private async Task CopyArtifactIntoTrxDirectoryAndReturnHrefValueAsync(FileInfo artifact, string runDeploymentRoot)
+ {
+ string artifactDirectory = CreateOrGetTrxArtifactDirectory(runDeploymentRoot);
+ string fileName = artifact.Name;
+
+ string destination = Path.Combine(artifactDirectory, fileName);
+ int nameCounter = 0;
+
+ // If the file already exists, append a number to the end of the file name
+ while (true)
+ {
+ if (File.Exists(destination))
+ {
+ nameCounter++;
+ destination = Path.Combine(artifactDirectory, $"{Path.GetFileNameWithoutExtension(fileName)}_{nameCounter}{Path.GetExtension(fileName)}");
+ continue;
+ }
+
+ break;
+ }
+
+ await CopyFileAsync(artifact, new FileInfo(destination));
+
+ return Path.Combine(_environment.MachineName, Path.GetFileName(destination));
+ }
+
+ private string CreateOrGetTrxArtifactDirectory(string runDeploymentRoot)
+ {
+ string directoryName = Path.Combine(_configuration.GetTestResultDirectory(), runDeploymentRoot, "In", _environment.MachineName);
+ if (!Directory.Exists(directoryName))
+ {
+ Directory.CreateDirectory(directoryName);
+ }
+
+ return directoryName;
+ }
+
+ private async Task CopyFileAsync(FileInfo origin, FileInfo destination)
+ {
+ if (!_isCopyingFileAllowed)
+ {
+ return;
+ }
+
+ using FileStream fileStream = File.OpenRead(origin.FullName);
+ using var destinationStream = new FileStream(destination.FullName, FileMode.Create);
+ await fileStream.CopyToAsync(destinationStream);
+ }
+
+ private static void AddTestLists(XElement testRun, string uncategorizedTestId)
+ {
+ var testLists = new XElement(
+ "TestLists",
+ new XElement(
+ "TestList",
+ new XAttribute("name", "Results Not in a List"),
+ new XAttribute("id", uncategorizedTestId)),
+ new XElement(
+ "TestList",
+ new XAttribute("name", "All Loaded Results"),
+ // parent of all categories (fake, not real category).
+ new XAttribute("id", new Guid("19431567-8539-422a-85D7-44EE4E166BDA"))));
+
+ testRun.Add(testLists);
+ }
+
+ private void AddResults(string testAppModule, XElement testRun, out XElement testDefinitions, out XElement testEntries, out string uncategorizedTestId, out string resultSummaryOutcome)
+ {
+ var results = new XElement("Results");
+
+ // Duplicate test ids are not allowed inside the TestDefinitions element.
+ testDefinitions = new XElement("TestDefinitions");
+ var uniqueTestDefinitionTestIds = new HashSet();
+
+ testEntries = new XElement("TestEntries");
+ uncategorizedTestId = "8C84FA94-04C1-424b-9868-57A2D4851A1D";
+ resultSummaryOutcome = "Passed";
+ foreach (TestNodeUpdateMessage nodeMessage in _testNodeUpdatedMessages)
+ {
+ TestNode testNode = nodeMessage.TestNode;
+
+ string id = GuidFromString($"{testNode.Uid.Value} {testNode.DisplayName}").ToString();
+ string displayName = RemoveInvalidXmlChar(testNode.DisplayName)!;
+ string executionId = Guid.NewGuid().ToString();
+
+ // Results
+ var unitTestResult = new XElement(
+ "UnitTestResult",
+ new XAttribute("executionId", executionId),
+ new XAttribute("testId", id),
+ new XAttribute("testName", displayName),
+ new XAttribute("computerName", _environment.MachineName));
+
+ TimingProperty? timing = testNode.Properties.SingleOrDefault();
+ string testDuration = timing?.GlobalTiming.Duration is { } duration
+ ? duration.ToString("hh\\:mm\\:ss\\.fffffff", CultureInfo.InvariantCulture)
+ : "00:00:00";
+ unitTestResult.SetAttributeValue("duration", testDuration);
+
+ unitTestResult.SetAttributeValue(
+ "startTime",
+ timing?.GlobalTiming.StartTime.ToUniversalTime().ToString("O") ?? _clock.UtcNow.ToString("O"));
+ unitTestResult.SetAttributeValue(
+ "endTime",
+ timing?.GlobalTiming.EndTime.ToUniversalTime().ToString("O") ?? _clock.UtcNow.ToString("O"));
+
+ // TODO: Are there other types?
+ unitTestResult.SetAttributeValue("testType", UnitTestTypeGuid);
+
+ string outcome = "Passed";
+ TestNodeStateProperty? testState = testNode.Properties.SingleOrDefault();
+ if (testState is { } state
+ && FailedStates.Contains(testState.GetType()))
+ {
+ outcome = resultSummaryOutcome = "Failed";
+ }
+ else if (testState is SkippedTestNodeStateProperty)
+ {
+ outcome = resultSummaryOutcome = "NotExecuted";
+ }
+
+ unitTestResult.SetAttributeValue("outcome", outcome);
+
+ unitTestResult.SetAttributeValue("testListId", uncategorizedTestId);
+
+ // It has the same value as executionId
+ unitTestResult.SetAttributeValue("relativeResultsDirectory", executionId);
+
+ // Below we're escaping most "dynamic body" using .Replace("\0", ""), because this is an invalid xml character.
+ // There're other invalid xml characters, but they're transformed inside the writer in a correct way so we try to
+ // rely on the built-in escaping/conversion.
+ // i.e. https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs#L890
+ var output = new XElement("Output");
+
+ TrxMessagesProperty? trxMessages = testNode.Properties.SingleOrDefault();
+ IEnumerable? nonErrorMessages = trxMessages?.Messages.Where(x => x is not StandardErrorTrxMessage).Select(x => x.Message);
+ if (nonErrorMessages?.Any() == true)
+ {
+ output.Add(new XElement("StdOut", RemoveInvalidXmlChar(string.Join(Environment.NewLine, nonErrorMessages))));
+ }
+
+ IEnumerable? errorMessages = trxMessages?.Messages.Where(x => x is StandardErrorTrxMessage).Select(x => x.Message);
+ if (errorMessages?.Any() == true)
+ {
+ output.Add(new XElement("StdErr", RemoveInvalidXmlChar(string.Join(Environment.NewLine, errorMessages))));
+ }
+
+ TrxExceptionProperty? trxException = testNode.Properties.SingleOrDefault();
+ if (trxException?.Message is not null || trxException?.StackTrace is not null)
+ {
+ XElement errorInfoElement = new("ErrorInfo");
+
+ if (trxException.Message is not null)
+ {
+ errorInfoElement.Add(new XElement("Message", RemoveInvalidXmlChar(trxException.Message)));
+ }
+
+ if (trxException.StackTrace is not null)
+ {
+ errorInfoElement.Add(new XElement("StackTrace", RemoveInvalidXmlChar(trxException.StackTrace)));
+ }
+
+ output.Add(errorInfoElement);
+ }
+
+ // add collectorDataEntries details
+ if (output.HasElements && outcome != "NotExecuted")
+ {
+ unitTestResult.Add(output);
+ }
+
+ if (_artifactsByTestNode.TryGetValue(testNode.Uid, out List? fileArtifacts))
+ {
+ var resultFiles = new XElement("ResultFiles");
+
+ foreach (SessionFileArtifact fileArtifact in fileArtifacts)
+ {
+ resultFiles.Add(new XElement(
+ "ResultFile",
+ new XAttribute("path", fileArtifact.FileInfo.FullName)));
+ }
+
+ unitTestResult.Add(resultFiles);
+ }
+
+ results.Add(unitTestResult);
+
+ // TestDefinitions
+ var unitTest = new XElement(
+ "UnitTest",
+ new XAttribute("name", displayName),
+ new XAttribute("storage", testAppModule.ToLowerInvariant()),
+ new XAttribute("id", id));
+
+ TrxCategoriesProperty? trxCategories = testNode.Properties.SingleOrDefault();
+ if (trxCategories?.Categories.Length > 0)
+ {
+ unitTest.Add(new XElement("TestCategory", trxCategories.Categories.Select(c => new XElement("TestCategoryItem", new XAttribute("TestCategory", c)))));
+ }
+
+ unitTest.Add(new XElement("Execution", new XAttribute("id", executionId)));
+
+ var testMethod = new XElement(
+ "TestMethod",
+ new XAttribute("codeBase", testAppModule),
+ new XAttribute("adapterTypeName", $"executor://{_testFrameworkAdapter.Uid}/{_testFrameworkAdapter.Version}"));
+
+ if (_adapterSupportTrxCapability == true)
+ {
+ string? className = testNode.Properties.SingleOrDefault()?.FullyQualifiedTypeName;
+ if (className is not null)
+ {
+ testMethod.SetAttributeValue("className", className);
+ }
+ }
+
+ testMethod.SetAttributeValue("name", displayName);
+
+ unitTest.Add(testMethod);
+
+ // Add the test method to the test definitions if it's not already there
+ if (!uniqueTestDefinitionTestIds.Contains(id))
+ {
+ testDefinitions.Add(unitTest);
+ uniqueTestDefinitionTestIds.Add(id);
+ }
+
+ // testEntry
+ var testEntry = new XElement(
+ "TestEntry",
+ new XAttribute("testId", id),
+ new XAttribute("executionId", executionId),
+ new XAttribute("testListId", uncategorizedTestId));
+ testEntries.Add(testEntry);
+ }
+
+ testRun.Add(results);
+ }
+
+ private static string AddTestSettings(XElement testRun, string testRunName)
+ {
+ var testSettings = new XElement(
+ "TestSettings",
+ new XAttribute("name", "default"),
+ new XAttribute("id", Guid.NewGuid()));
+ string runDeploymentRoot = ReplaceInvalidFileNameChars(testRunName);
+ testSettings.Add(new XElement("Deployment", new XAttribute("runDeploymentRoot", runDeploymentRoot)));
+ testRun.Add(testSettings);
+ return runDeploymentRoot;
+ }
+
+ private void AddTimes(XElement testRun)
+ {
+ var times = new XElement(
+ "Times",
+ new XAttribute("creation", _testStartTime),
+ new XAttribute("queuing", _testStartTime),
+ new XAttribute("start", _testStartTime),
+ new XAttribute("finish", _clock.UtcNow));
+ testRun.Add(times);
+ }
+
+ 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);
+
+ private static string ReplaceInvalidFileNameChars(string fileName)
+ {
+ // Replace bad chars by this.
+ char replacementChar = '_';
+ char[] result = new char[fileName.Length];
+
+ // Replace each invalid char with replacement char.
+ for (int i = 0; i < fileName.Length; ++i)
+ {
+ result[i] = InvalidFileNameChars.Contains(fileName[i]) ? replacementChar : fileName[i];
+ }
+
+ // We trim spaces in the end because CreateFile/Dir trim those.
+ string replaced = new string(result).TrimEnd();
+ ArgumentGuard.Ensure(replaced.Length > 0, nameof(fileName), $"File name {fileName} is empty after removing invalid characters.");
+
+ if (IsReservedFileName(replaced))
+ {
+ replaced = replacementChar + replaced; // Cannot add to the end because it can have extensions.
+ }
+
+ return replaced;
+ }
+
+ private static bool IsReservedFileName(string fileName) =>
+
+ // CreateFile:
+ // The following reserved device names cannot be used as the name of a file:
+ // CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9,
+ // 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;
+
+ private static Guid GuidFromString(string data)
+ {
+#if NETCOREAPP
+ int byteCount = Encoding.Unicode.GetByteCount(data);
+ Span hash = stackalloc byte[32];
+ byte[] dataBytes = ArrayPool.Shared.Rent(byteCount);
+ try
+ {
+ Encoding.Unicode.GetBytes(data, dataBytes);
+ SHA256.HashData(dataBytes.AsSpan()[..byteCount], hash);
+ return new Guid(hash[..16]);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(dataBytes);
+ }
+#else
+ var sha256 = SHA256.Create();
+ byte[] hash = sha256.ComputeHash(Encoding.Unicode.GetBytes(data));
+ byte[] bytes = new byte[16];
+ Array.Copy(hash, bytes, 16);
+ return new Guid(bytes);
+#endif
+ }
+
+#if NET7_0_OR_GREATER
+ [GeneratedRegex(@"(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9]|CLOCK\$)(\..*)?)$", RegexOptions.None, "en-150")]
+ private static partial Regex BuildReservedFileNameRegex();
+#else
+ private static Regex BuildReservedFileNameRegex() => new(@"(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9]|CLOCK\$)(\..*)?)$");
+#endif
+
+ // From xml spec (http://www.w3.org/TR/xml/#charsets) valid chars:
+ // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+ // we are handling only #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
+ // because C# support unicode character in range \u0000 to \uFFFF
+#if NET7_0_OR_GREATER
+ [GeneratedRegex(@"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD]")]
+ private static partial Regex BuildInvalidXmlCharReplace();
+#else
+ private static Regex BuildInvalidXmlCharReplace() => new(@"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD]");
+#endif
+
+ private static string? RemoveInvalidXmlChar(string? str) => str is null ? null : InvalidXmlCharReplace.Replace(str, InvalidXmlEvaluator);
+
+ private static string ReplaceInvalidCharacterWithUniCodeEscapeSequence(Match match)
+ {
+ char x = match.Value[0];
+ return $@"\u{(ushort)x:x4}";
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs
new file mode 100644
index 0000000000..69ba9fcc6a
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.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 Microsoft.Testing.Extensions.TestReports.Resources;
+using Microsoft.Testing.Extensions.TrxReport.Abstractions;
+using Microsoft.Testing.Platform.Builder;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.IPC;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.Testing.Platform.TestHostControllers;
+
+namespace Microsoft.Testing.Extensions;
+
+public static class TrxReportExtensions
+{
+ public static void AddTrxReportProvider(this ITestApplicationBuilder builder)
+ {
+ if (builder is not TestApplicationBuilder testApplicationBuilder)
+ {
+ throw new InvalidOperationException(ExtensionResources.InvalidTestApplicationBuilderType);
+ }
+
+ var commandLine = new TrxReportGeneratorCommandLine();
+
+ var compositeTestSessionTrxService =
+ new CompositeExtensionFactory(serviceProvider =>
+ new TrxReportGenerator(
+ serviceProvider.GetConfiguration(),
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetTestApplicationModuleInfo(),
+ serviceProvider.GetMessageBus(),
+ serviceProvider.GetSystemClock(),
+ serviceProvider.GetEnvironment(),
+ serviceProvider.GetOutputDevice(),
+ serviceProvider.GetTestFramework(),
+ serviceProvider.GetTestFrameworkCapabilities(),
+ commandLine,
+ serviceProvider.GetService(),
+ serviceProvider.GetLoggerFactory().CreateLogger()));
+
+ builder.TestHost.AddTestApplicationLifecycleCallbacks(serviceProvider =>
+ new TrxTestApplicationLifecycleCallbacks(
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetEnvironment()));
+ builder.TestHost.AddDataConsumer(compositeTestSessionTrxService);
+ builder.TestHost.AddTestSessionLifetimeHandle(compositeTestSessionTrxService);
+
+ builder.CommandLine.AddProvider(() => commandLine);
+
+ PipeNameDescription pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"));
+ var compositeLifeTimeHandler =
+ new CompositeExtensionFactory(serviceProvider =>
+ {
+ serviceProvider.GetLoggerFactory().CreateLogger().LogTrace($"TRX pipe name: '{pipeNameDescription.Name}");
+ return new TrxProcessLifetimeHandler(
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetEnvironment(),
+ serviceProvider.GetLoggerFactory(),
+ serviceProvider.GetMessageBus(),
+ serviceProvider.GetTestApplicationModuleInfo(),
+ serviceProvider.GetConfiguration(),
+ serviceProvider.GetSystemClock(),
+ serviceProvider.GetTask(),
+ pipeNameDescription);
+ });
+ ((TestHostControllersManager)builder.TestHostControllers).AddDataConsumer(compositeLifeTimeHandler);
+ builder.TestHostControllers.AddProcessLifetimeHandler(compositeLifeTimeHandler);
+ builder.TestHostControllers.AddEnvironmentVariableProvider(serviceProvider =>
+ {
+ serviceProvider.GetLoggerFactory().CreateLogger().LogTrace($"TRX pipe name: '{pipeNameDescription.Name}");
+ return new TrxEnvironmentVariableProvider(serviceProvider.GetCommandLineOptions(), pipeNameDescription.Name);
+ });
+
+ ToolTrxCompareFactory toolTrxCompareFactory = new();
+ TrxCompareToolCommandLine createTrxCompareToolCommandLine = toolTrxCompareFactory.CreateTrxCompareToolCommandLine();
+ builder.CommandLine.AddProvider(() => createTrxCompareToolCommandLine);
+
+ testApplicationBuilder.Tools.AddTool((serviceProvider) => toolTrxCompareFactory.CreateTrxCompareTool(
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetOutputDevice(),
+ serviceProvider.GetRequiredService()));
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs
new file mode 100644
index 0000000000..1dfe5a1f0d
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs
@@ -0,0 +1,87 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.TestReports.Resources;
+using Microsoft.Testing.Extensions.TrxReport.Abstractions.Serializers;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions.TestHost;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.IPC;
+using Microsoft.Testing.Platform.IPC.Models;
+using Microsoft.Testing.Platform.IPC.Serializers;
+
+namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;
+
+internal class TrxTestApplicationLifecycleCallbacks : ITestApplicationLifecycleCallbacks, IDisposable
+{
+ private readonly bool _isEnabled;
+ private readonly IEnvironment _environment;
+
+ public TrxTestApplicationLifecycleCallbacks(
+ ICommandLineOptions commandLineOptionsService,
+ IEnvironment environment)
+ {
+ _isEnabled =
+
+ // TrxReportGenerator is enabled only when trx report is enabled
+ commandLineOptionsService.IsOptionSet(TrxReportGeneratorCommandLine.TrxReportOptionName) &&
+
+ // TestController is not used when we run in server mode
+ !commandLineOptionsService.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey) &&
+
+ // If crash dump is not enabled we run trx in-process only
+ commandLineOptionsService.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName);
+
+ _environment = environment;
+ }
+
+ public NamedPipeClient? NamedPipeClient { get; private set; }
+
+ public string Uid { get; } = nameof(TrxTestApplicationLifecycleCallbacks);
+
+ ///
+ public string Version { get; } = AppVersion.DefaultSemVer;
+
+ ///
+ public string DisplayName { get; } = ExtensionResources.TrxReportGeneratorDisplayName;
+
+ ///
+ public string Description { get; } = ExtensionResources.TrxReportGeneratorDescription;
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(_isEnabled);
+
+ public Task AfterRunAsync(int exitCode, CancellationToken cancellation) => Task.CompletedTask;
+
+ public async Task BeforeRunAsync(CancellationToken cancellationToken)
+ {
+ if (!_isEnabled || cancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ try
+ {
+ if (_isEnabled)
+ {
+ string? namedPipeName = _environment.GetEnvironmentVariable(TrxEnvironmentVariableProvider.TRXNAMEDPIPENAME)
+ ?? throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxReportGeneratorMissingTrxNamedPipeEnvironmentVariable, TrxEnvironmentVariableProvider.TRXNAMEDPIPENAME));
+ NamedPipeClient = new NamedPipeClient(namedPipeName);
+ NamedPipeClient.RegisterSerializer(new ReportFileNameRequestSerializer(), typeof(ReportFileNameRequest));
+ NamedPipeClient.RegisterSerializer(new TestAdapterInformationRequestSerializer(), typeof(TestAdapterInformationRequest));
+ NamedPipeClient.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse));
+
+ // Connect to the named pipe server
+ await NamedPipeClient.ConnectAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout);
+ }
+ }
+ catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken)
+ {
+ // Do nothing, we're stopping
+ }
+ }
+
+ public void Dispose() => NamedPipeClient?.Dispose();
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/build/Microsoft.Testing.Extensions.TrxReport.props b/src/Platform/Microsoft.Testing.Extensions.TrxReport/build/Microsoft.Testing.Extensions.TrxReport.props
new file mode 100644
index 0000000000..4234fd10df
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/build/Microsoft.Testing.Extensions.TrxReport.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/buildMultiTargeting/Microsoft.Testing.Extensions.TrxReport.props b/src/Platform/Microsoft.Testing.Extensions.TrxReport/buildMultiTargeting/Microsoft.Testing.Extensions.TrxReport.props
new file mode 100644
index 0000000000..affb8f1ab0
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/buildMultiTargeting/Microsoft.Testing.Extensions.TrxReport.props
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Microsoft.Testing.Extensions.TrxReport
+ Microsoft.Testing.Extensions.TrxReport.TestingPlatformBuilderHook
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/buildTransitive/Microsoft.Testing.Extensions.TrxReport.props b/src/Platform/Microsoft.Testing.Extensions.TrxReport/buildTransitive/Microsoft.Testing.Extensions.TrxReport.props
new file mode 100644
index 0000000000..4234fd10df
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/buildTransitive/Microsoft.Testing.Extensions.TrxReport.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/BannedSymbols.txt
new file mode 100644
index 0000000000..13daece7e1
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/BannedSymbols.txt
@@ -0,0 +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,System.String); Use 'RoslynDebug.Assert' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/IVSTestFlattenedTestNodesReportCapability.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/IVSTestFlattenedTestNodesReportCapability.cs
new file mode 100644
index 0000000000..c433fe18f8
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/IVSTestFlattenedTestNodesReportCapability.cs
@@ -0,0 +1,18 @@
+// 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.Capabilities.TestFramework;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.Capabilities;
+
+///
+/// A capability to indicate whether the VSTest adapter supports flattened test nodes report.
+/// This corresponds to the way Visual Studio Test Explorer displays tests.
+///
+internal interface IVSTestFlattenedTestNodesReportCapability : ITestFrameworkCapability
+{
+ ///
+ /// Gets a value indicating whether a flag indicating whether the capability is supported.
+ ///
+ bool IsSupported { get; }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs
new file mode 100644
index 0000000000..bcf444bd2b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs
@@ -0,0 +1,29 @@
+// 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.TrxReport.Abstractions;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.Capabilities;
+
+public sealed class VSTestBridgeExtensionBaseCapabilities : ITrxReportCapability, IVSTestFlattenedTestNodesReportCapability, INamedFeatureCapability
+{
+ private const string MultiRequestSupport = "experimental_multiRequestSupport";
+ private const string VSTestProviderSupport = "vstestProvider";
+
+ ///
+ bool IVSTestFlattenedTestNodesReportCapability.IsSupported { get; } = true;
+
+ ///
+ bool ITrxReportCapability.IsSupported { get; } = true;
+
+ ///
+ /// Gets a value indicating whether a flag indicating whether the trx report capability is enabled.
+ ///
+ public bool IsTrxEnabled { get; private set; }
+
+ ///
+ void ITrxReportCapability.Enable() => IsTrxEnabled = true;
+
+ bool INamedFeatureCapability.IsSupported(string featureName) => featureName is MultiRequestSupport or VSTestProviderSupport;
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs
new file mode 100644
index 0000000000..dad26b9207
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs
@@ -0,0 +1,92 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.VSTestBridge.Resources;
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.CommandLine;
+using Microsoft.Testing.Platform.Helpers;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.CommandLine;
+
+///
+/// A command line service provider to support VSTest .runsettings files.
+///
+internal sealed class RunSettingsCommandLineOptionsProvider : ICommandLineOptionsProvider
+{
+ public const string RunSettingsOptionName = "settings";
+ private readonly IFileSystem _fileSystem;
+
+ public RunSettingsCommandLineOptionsProvider(IExtension extension)
+ : this(extension, new SystemFileSystem())
+ {
+ }
+
+ internal /* for testing purposes */ RunSettingsCommandLineOptionsProvider(IExtension extension, IFileSystem fileSystem)
+ {
+ Uid = extension.Uid;
+ DisplayName = extension.DisplayName;
+ Description = extension.Description;
+ Version = extension.Version;
+ _fileSystem = fileSystem;
+ }
+
+ ///
+ public string Uid { get; }
+
+ ///
+ public string Version { get; }
+
+ ///
+ public string DisplayName { get; }
+
+ ///
+ public string Description { get; }
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ ///
+ public IReadOnlyCollection GetCommandLineOptions()
+ => [new CommandLineOption(RunSettingsOptionName, ExtensionResources.RunSettingsOptionDescription, ArgumentArity.ExactlyOne, false)];
+
+ ///
+ public Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
+ {
+ RoslynDebug.Assert(commandOption.Name == RunSettingsOptionName);
+ string filePath = arguments[0];
+
+ if (!_fileSystem.Exists(filePath))
+ {
+ return ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, ExtensionResources.RunsettingsFileDoesNotExist, filePath));
+ }
+
+ // Even if the file exists, we want to validate we can open/read it.
+ if (!CanReadFile(filePath))
+ {
+ return ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, ExtensionResources.RunsettingsFileCannotBeRead, filePath));
+ }
+
+ // No problem found
+ return ValidationResult.ValidTask;
+ }
+
+ public Task ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
+ => ValidationResult.ValidTask;
+
+ private bool CanReadFile(string filePath)
+ {
+ try
+ {
+ using IFileStream stream = _fileSystem.NewFileStream(filePath, FileMode.Open, FileAccess.Read);
+ return true;
+ }
+ catch (IOException)
+ {
+ return false;
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestCaseFilterCommandLineOptionsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestCaseFilterCommandLineOptionsProvider.cs
new file mode 100644
index 0000000000..edd8bfe5a1
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestCaseFilterCommandLineOptionsProvider.cs
@@ -0,0 +1,53 @@
+// 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.VSTestBridge.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.CommandLine;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.CommandLine;
+
+///
+/// A command line service provider bringing support for the VSTest test case.
+///
+internal sealed class TestCaseFilterCommandLineOptionsProvider : ICommandLineOptionsProvider
+{
+ public const string TestCaseFilterOptionName = "filter";
+
+ public TestCaseFilterCommandLineOptionsProvider(IExtension extension)
+ {
+ Uid = extension.Uid;
+ DisplayName = extension.DisplayName;
+ Description = extension.Description;
+ Version = extension.Version;
+ }
+
+ ///
+ public string Uid { get; }
+
+ ///
+ public string Version { get; }
+
+ ///
+ public string DisplayName { get; }
+
+ ///
+ public string Description { get; }
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ ///
+ public IReadOnlyCollection GetCommandLineOptions() =>
+ [
+ new(TestCaseFilterOptionName, ExtensionResources.TestCaseFilterOptionDescription, ArgumentArity.ExactlyOne, false)
+ ];
+
+ ///
+ public Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
+ => ValidationResult.ValidTask;
+
+ public Task ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
+ => ValidationResult.ValidTask;
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestRunParametersCommandLineOptionsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestRunParametersCommandLineOptionsProvider.cs
new file mode 100644
index 0000000000..1646d8df09
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestRunParametersCommandLineOptionsProvider.cs
@@ -0,0 +1,61 @@
+// 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.Globalization;
+
+using Microsoft.Testing.Extensions.VSTestBridge.Resources;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.CommandLine;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.CommandLine;
+
+internal sealed class TestRunParametersCommandLineOptionsProvider : ICommandLineOptionsProvider
+{
+ public const string TestRunParameterOptionName = "test-parameter";
+
+ public TestRunParametersCommandLineOptionsProvider(IExtension extension)
+ {
+ Uid = extension.Uid;
+ DisplayName = extension.DisplayName;
+ Description = extension.Description;
+ Version = extension.Version;
+ }
+
+ ///
+ public string Uid { get; }
+
+ ///
+ public string Version { get; }
+
+ ///
+ public string DisplayName { get; }
+
+ ///
+ public string Description { get; }
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ ///
+ public IReadOnlyCollection GetCommandLineOptions()
+ => [new CommandLineOption(TestRunParameterOptionName, ExtensionResources.TestRunParameterOptionDescription, ArgumentArity.OneOrMore, false)];
+
+ ///
+ public Task ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
+ => ValidationResult.ValidTask;
+
+ ///
+ public Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
+ {
+ foreach (string argument in arguments)
+ {
+ if (!argument.Contains('='))
+ {
+ return ValidationResult.InvalidTask(string.Format(CultureInfo.CurrentCulture, ExtensionResources.TestRunParameterOptionArgumentIsNotParameter, argument));
+ }
+ }
+
+ return ValidationResult.ValidTask;
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Configurations/RunSettingsConfigurationProvider.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Configurations/RunSettingsConfigurationProvider.cs
new file mode 100644
index 0000000000..55ec90ffa5
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Configurations/RunSettingsConfigurationProvider.cs
@@ -0,0 +1,58 @@
+// 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.Xml.Linq;
+
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Helpers;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.Configurations;
+
+internal sealed class RunSettingsConfigurationProvider : IConfigurationSource, IConfigurationProvider
+{
+ private readonly string _runsettings;
+
+ public RunSettingsConfigurationProvider(string runSettings)
+ {
+ _runsettings = runSettings;
+ }
+
+ ///
+ public string Uid { get; } = nameof(RunSettingsConfigurationProvider);
+
+ ///
+ public string Version { get; } = AppVersion.DefaultSemVer;
+
+ ///
+ public string DisplayName { get; } = "VSTest Helpers: runsettings configuration";
+
+ ///
+ public string Description { get; } = "Configuration source to bridge VSTest xml runsettings configuration into Microsoft Testing Platform configuration model.";
+
+ ///
+ public Task IsEnabledAsync() => Task.FromResult(true);
+
+ ///
+ public Task LoadAsync() => Task.CompletedTask;
+
+ ///
+ public bool TryGet(string key, out string? value)
+ {
+ if (key == PlatformConfigurationConstants.PlatformResultDirectory)
+ {
+ var document = XDocument.Parse(_runsettings);
+ value = document.Element("RunSettings")?.Element("RunConfiguration")?.Element("ResultsDirectory")?.Value;
+ if (value is not null)
+ {
+ return true;
+ }
+ }
+
+ value = null;
+ return false;
+ }
+
+ ///
+ public IConfigurationProvider Build()
+ => new RunSettingsConfigurationProvider(_runsettings);
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/Constants.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/Constants.cs
new file mode 100644
index 0000000000..aa1c7c6582
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/Constants.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.Extensions.VSTestBridge;
+
+internal static class Constants
+{
+ public const string ExecutorUri = "executor://testingplatform-bridge/v1";
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/DebugUtils.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/DebugUtils.cs
new file mode 100644
index 0000000000..7b26b2254f
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/DebugUtils.cs
@@ -0,0 +1,17 @@
+// 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.VSTestBridge.Helpers;
+
+internal static class DebugUtils
+{
+ private const string VSTestBridgeAttachDebuggerEnvVar = "TESTINGPLATFORM_VSTESTBRIDGE_ATTACH_DEBUGGER";
+
+ public static void LaunchAttachDebugger()
+ {
+ if (Environment.GetEnvironmentVariable(VSTestBridgeAttachDebuggerEnvVar) == "1")
+ {
+ System.Diagnostics.Debugger.Launch();
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/SynchronousAwaiter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/SynchronousAwaiter.cs
new file mode 100644
index 0000000000..8db016da73
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/SynchronousAwaiter.cs
@@ -0,0 +1,29 @@
+// 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.VSTestBridge.Helpers;
+
+///
+/// A helper class to provide synchronous awaiter. Because of vstest sync APIs we need to wait synchronously.
+///
+internal static class SynchronousAwaiter
+{
+ public static void Await(this Task valueTask, bool busyWait = true)
+ {
+ if (busyWait)
+ {
+ var spin = default(SpinWait);
+ while (!valueTask.IsCompleted)
+ {
+ spin.SpinOnce();
+ }
+
+ // We want to observe the exception
+ valueTask.GetAwaiter().GetResult();
+ }
+ else
+ {
+ valueTask.GetAwaiter().GetResult();
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/TestApplicationBuilderExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/TestApplicationBuilderExtensions.cs
new file mode 100644
index 0000000000..92f0d489e3
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/TestApplicationBuilderExtensions.cs
@@ -0,0 +1,38 @@
+// 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.VSTestBridge.CommandLine;
+using Microsoft.Testing.Platform.Builder;
+using Microsoft.Testing.Platform.Extensions;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.Helpers;
+
+///
+/// A set of helper methods to register the VSTest services into Microsoft Testing Platform.
+///
+public static class TestApplicationBuilderExtensions
+{
+ ///
+ /// Allows to register the VSTest filter service.
+ ///
+ /// The test application builder.
+ /// The extension that will be used as the source of registration for this helper service.
+ public static void AddTestCaseFilterService(this ITestApplicationBuilder builder, IExtension extension)
+ => builder.CommandLine.AddProvider(() => new TestCaseFilterCommandLineOptionsProvider(extension));
+
+ ///
+ /// Allows to register the VSTest runsettings service.
+ ///
+ /// The test application builder.
+ /// The extension that will be used as the source of registration for this helper service.
+ public static void AddRunSettingsService(this ITestApplicationBuilder builder, IExtension extension)
+ => builder.CommandLine.AddProvider(() => new RunSettingsCommandLineOptionsProvider(extension));
+
+ ///
+ /// Allows to register the VSTest TestRunParameters service.
+ ///
+ /// The test application builder.
+ /// The extension that will be used as the source of registration for this helper service.
+ public static void AddTestRunParametersService(this ITestApplicationBuilder builder, IExtension extension)
+ => builder.CommandLine.AddProvider(() => new TestRunParametersCommandLineOptionsProvider(extension));
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/VSTestTestNodeProperties.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/VSTestTestNodeProperties.cs
new file mode 100644
index 0000000000..9a7d6b2daa
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Helpers/VSTestTestNodeProperties.cs
@@ -0,0 +1,15 @@
+// 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.VSTestBridge;
+
+internal static class VSTestTestNodeProperties
+{
+ internal const string Prefix = "vstest.";
+ public const string OriginalExecutorUriPropertyName = "vstest.original-executor-uri";
+
+ public static class TestNode
+ {
+ public const string UidPropertyName = "vstest.testnode.uid";
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj
new file mode 100644
index 0000000000..2ad5e86868
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj
@@ -0,0 +1,55 @@
+
+
+
+ netstandard2.0;$(MicrosoftTestingTargetFrameworks)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ ExtensionResources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ ExtensionResources.Designer.cs
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/Condition.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/Condition.cs
new file mode 100644
index 0000000000..1f54b44d53
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/Condition.cs
@@ -0,0 +1,375 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+// NOTE: This file is copied as-is from VSTest source code.
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Text;
+
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
+
+#pragma warning disable SA1602 // Enumeration items should be documented
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+internal enum Operation
+{
+ Equal,
+ NotEqual,
+ Contains,
+ NotContains,
+}
+
+///
+/// Operator in order of precedence.
+/// Precedence(And) > Precedence(Or)
+/// Precedence of OpenBrace and CloseBrace operators is not used, instead parsing code takes care of same.
+///
+internal enum Operator
+{
+ None,
+ Or,
+ And,
+ OpenBrace,
+ CloseBrace,
+}
+
+///
+/// Represents a condition in filter expression.
+///
+[ExcludeFromCodeCoverage] // Helper copied from VSTest source code
+internal sealed class Condition
+{
+ ///
+ /// Default property name which will be used when filter has only property value.
+ ///
+ public const string DefaultPropertyName = "FullyQualifiedName";
+
+ ///
+ /// Default operation which will be used when filter has only property value.
+ ///
+ public const Operation DefaultOperation = Operation.Contains;
+
+ internal Condition(string name, Operation operation, string value)
+ {
+ Name = name;
+ Operation = operation;
+ Value = value;
+ }
+
+ ///
+ /// Gets toolName of the property used in condition.
+ ///
+ internal string Name { get; private set; }
+
+ ///
+ /// Gets value for the property.
+ ///
+ internal string Value { get; private set; }
+
+ ///
+ /// Gets operation to be performed.
+ ///
+ internal Operation Operation { get; private set; }
+
+ ///
+ /// Evaluate this condition for testObject.
+ ///
+ internal bool Evaluate(Func propertyValueProvider)
+ {
+ ValidateArg.NotNull(propertyValueProvider, nameof(propertyValueProvider));
+ bool result = false;
+ string[]? multiValue = GetPropertyValue(propertyValueProvider);
+ switch (Operation)
+ {
+ case Operation.Equal:
+ // if any value in multi-valued property matches 'this.Value', for Equal to evaluate true.
+ if (multiValue != null)
+ {
+ foreach (string propertyValue in multiValue)
+ {
+ result = result || string.Equals(propertyValue, Value, StringComparison.OrdinalIgnoreCase);
+ if (result)
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+
+ case Operation.NotEqual:
+ // all values in multi-valued property should not match 'this.Value' for NotEqual to evaluate true.
+ result = true;
+
+ // if value is null.
+ if (multiValue != null)
+ {
+ foreach (string propertyValue in multiValue)
+ {
+ result = result && !string.Equals(propertyValue, Value, StringComparison.OrdinalIgnoreCase);
+ if (!result)
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+
+ case Operation.Contains:
+ // if any value in multi-valued property contains 'this.Value' for 'Contains' to be true.
+ if (multiValue != null)
+ {
+ foreach (string propertyValue in multiValue)
+ {
+ RoslynDebug.Assert(propertyValue != null, "PropertyValue can not be null.");
+ result = result || propertyValue.Contains(Value, StringComparison.OrdinalIgnoreCase);
+ if (result)
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+
+ case Operation.NotContains:
+ // all values in multi-valued property should not contain 'this.Value' for NotContains to evaluate true.
+ result = true;
+
+ if (multiValue != null)
+ {
+ foreach (string propertyValue in multiValue)
+ {
+ RoslynDebug.Assert(propertyValue != null, "PropertyValue can not be null.");
+ result = result && !propertyValue.Contains(Value, StringComparison.OrdinalIgnoreCase);
+ if (!result)
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+
+ return result;
+ }
+
+ ///
+ /// Returns a condition object after parsing input string of format 'Operation ]]>'.
+ ///
+ internal static Condition Parse(string? conditionString)
+ {
+ if (RoslynString.IsNullOrWhiteSpace(conditionString))
+ {
+ ThrownFormatExceptionForInvalidCondition(conditionString);
+ }
+
+ string[] parts = TokenizeFilterConditionString(conditionString).ToArray();
+ if (parts.Length == 1)
+ {
+ // If only parameter values is passed, create condition with default property name,
+ // default operation and given condition string as parameter value.
+ return new Condition(DefaultPropertyName, DefaultOperation, FilterHelper.Unescape(conditionString!.Trim()));
+ }
+
+ if (parts.Length != 3)
+ {
+ ThrownFormatExceptionForInvalidCondition(conditionString);
+ }
+
+ for (int index = 0; index < 3; index++)
+ {
+ if (RoslynString.IsNullOrWhiteSpace(parts[index]))
+ {
+ ThrownFormatExceptionForInvalidCondition(conditionString);
+ }
+
+ parts[index] = parts[index].Trim();
+ }
+
+ Operation operation = GetOperator(parts[1]);
+ Condition condition = new(parts[0], operation, FilterHelper.Unescape(parts[2]));
+ return condition;
+ }
+
+ [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)));
+
+ ///
+ /// Check if condition validates any property in properties.
+ ///
+ internal bool ValidForProperties(IEnumerable properties, Func? propertyProvider)
+ {
+ bool valid = false;
+
+ if (properties.Contains(Name, StringComparer.OrdinalIgnoreCase))
+ {
+ valid = true;
+
+ // Check if operation ~ (Contains) is on property of type string.
+ if (Operation == Operation.Contains)
+ {
+ valid = ValidForContainsOperation(propertyProvider);
+ }
+ }
+
+ return valid;
+ }
+
+ private bool ValidForContainsOperation(Func? propertyProvider)
+ {
+ bool valid = true;
+
+ // It is OK for propertyProvider to be null, no syntax check will happen.
+
+ // Check validity of operator only if related TestProperty is non-null.
+ // if null, it might be custom validation ignore it.
+ TestProperty? testProperty = propertyProvider?.Invoke(Name);
+ if (testProperty != null)
+ {
+ Type propertyType = testProperty.GetValueType();
+ valid = typeof(string) == propertyType ||
+ typeof(string[]) == propertyType;
+ }
+
+ return valid;
+ }
+
+ ///
+ /// Return Operation corresponding to the operationString.
+ ///
+ private static Operation GetOperator(string operationString) => operationString switch
+ {
+ "=" => Operation.Equal,
+ "!=" => Operation.NotEqual,
+ "~" => 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))),
+ };
+
+ ///
+ /// Returns property value for Property using propertyValueProvider.
+ ///
+ private string[]? GetPropertyValue(Func propertyValueProvider)
+ {
+ object? propertyValue = propertyValueProvider(Name);
+ if (propertyValue != null)
+ {
+ if (propertyValue is not string[] multiValue)
+ {
+ multiValue = new string[1];
+ multiValue[0] = propertyValue.ToString()!;
+ }
+
+ return multiValue;
+ }
+
+ return null;
+ }
+
+ internal static IEnumerable TokenizeFilterConditionString(string str)
+ {
+ ArgumentGuard.IsNotNull(str);
+ return TokenizeFilterConditionStringWorker(str);
+
+ static IEnumerable TokenizeFilterConditionStringWorker(string s)
+ {
+ StringBuilder tokenBuilder = new();
+
+ char last = '\0';
+ for (int i = 0; i < s.Length; ++i)
+ {
+ char current = s[i];
+
+ if (last == FilterHelper.EscapeCharacter)
+ {
+ // Don't check if `current` is one of the special characters here.
+ // Instead, we blindly let any character follows '\' pass though and
+ // relies on `FilterHelpers.Unescape` to report such errors.
+ tokenBuilder.Append(current);
+
+ if (current == FilterHelper.EscapeCharacter)
+ {
+ // We just encountered double backslash (i.e. escaped '\'), therefore set `last` to '\0'
+ // so the second '\' (i.e. current) will not be treated as the prefix of escape sequence
+ // in next iteration.
+ current = '\0';
+ }
+ }
+ else
+ {
+ switch (current)
+ {
+ case '=':
+ if (tokenBuilder.Length > 0)
+ {
+ yield return tokenBuilder.ToString();
+ tokenBuilder.Clear();
+ }
+
+ yield return "=";
+ break;
+
+ case '!':
+ if (tokenBuilder.Length > 0)
+ {
+ yield return tokenBuilder.ToString();
+ tokenBuilder.Clear();
+ }
+
+ // Determine if this is a "!=" or "!~" or just a single "!".
+ int next = i + 1;
+ if (next < s.Length && s[next] == '=')
+ {
+ i = next;
+ current = '=';
+ yield return "!=";
+ }
+ else if (next < s.Length && s[next] == '~')
+ {
+ i = next;
+ current = '~';
+ yield return "!~";
+ }
+ else
+ {
+ yield return "!";
+ }
+
+ break;
+
+ case '~':
+ if (tokenBuilder.Length > 0)
+ {
+ yield return tokenBuilder.ToString();
+ tokenBuilder.Clear();
+ }
+
+ yield return "~";
+ break;
+
+ default:
+ tokenBuilder.Append(current);
+ break;
+ }
+ }
+
+ last = current;
+ }
+
+ if (tokenBuilder.Length > 0)
+ {
+ yield return tokenBuilder.ToString();
+ }
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.cs
new file mode 100644
index 0000000000..ba561ce981
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.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 System.Globalization;
+
+using Microsoft.Testing.Extensions.VSTestBridge.CommandLine;
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+internal abstract class ContextAdapterBase
+{
+ public ContextAdapterBase(ICommandLineOptions commandLineOptions)
+ {
+ if (commandLineOptions.TryGetOptionArgumentList(
+ TestCaseFilterCommandLineOptionsProvider.TestCaseFilterOptionName,
+ out string[]? filterExpressions)
+ && filterExpressions is not null
+ && filterExpressions.Length == 1)
+ {
+ FilterExpressionWrapper = new(filterExpressions[0]);
+ }
+ }
+
+ protected FilterExpressionWrapper? FilterExpressionWrapper { get; set; }
+
+ // NOTE: Implementation is borrowed from VSTest
+ // MSTest relies on this method existing and access it through reflection: https://github.com/microsoft/testfx/blob/main/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs#L115
+ public ITestCaseFilterExpression? GetTestCaseFilter(
+ IEnumerable? supportedProperties,
+ Func propertyProvider)
+ {
+ if (FilterExpressionWrapper is null)
+ {
+ return null;
+ }
+
+ if (!RoslynString.IsNullOrEmpty(FilterExpressionWrapper.ParseError))
+ {
+ throw new TestPlatformFormatException(FilterExpressionWrapper.ParseError, FilterExpressionWrapper.FilterString);
+ }
+
+ var adapterSpecificTestCaseFilter = new TestCaseFilterExpression(FilterExpressionWrapper);
+ string[]? invalidProperties = adapterSpecificTestCaseFilter.ValidForProperties(supportedProperties, propertyProvider);
+
+ if (invalidProperties != null)
+ {
+ string validPropertiesString = supportedProperties == null
+ ? string.Empty
+ : string.Join(", ", supportedProperties.ToArray());
+ 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);
+ }
+
+ return adapterSpecificTestCaseFilter;
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/DiscoveryContextAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/DiscoveryContextAdapter.cs
new file mode 100644
index 0000000000..57e52eb3e2
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/DiscoveryContextAdapter.cs
@@ -0,0 +1,21 @@
+// 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.CommandLine;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+///
+/// A Microsoft Testing Platform oriented implementation of the VSTest .
+///
+internal sealed class DiscoveryContextAdapter : ContextAdapterBase, IDiscoveryContext
+{
+ public DiscoveryContextAdapter(ICommandLineOptions commandLineOptions, IRunSettings? runSettings = null)
+ : base(commandLineOptions)
+ {
+ RunSettings = runSettings;
+ }
+
+ public IRunSettings? RunSettings { get; }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FastFilter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FastFilter.cs
new file mode 100644
index 0000000000..7e0b07123a
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FastFilter.cs
@@ -0,0 +1,212 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+// NOTE: This file is copied as-is from VSTest source code.
+using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Text.RegularExpressions;
+
+using Microsoft.Testing.Platform;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+[ExcludeFromCodeCoverage] // Helper copied from VSTest source code
+internal sealed class FastFilter
+{
+ internal FastFilter(ImmutableDictionary> filterProperties, Operation filterOperation, Operator filterOperator)
+ {
+ ValidateArg.NotNullOrEmpty(filterProperties, nameof(filterProperties));
+
+ FilterProperties = filterProperties;
+
+ IsFilteredOutWhenMatched =
+ (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.")));
+ }
+
+ internal ImmutableDictionary> FilterProperties { get; }
+
+ internal bool IsFilteredOutWhenMatched { get; }
+
+ internal Regex? PropertyValueRegex { get; set; }
+
+ internal string? PropertyValueRegexReplacement { get; set; }
+
+ internal string[]? ValidForProperties(IEnumerable? properties) => properties is null
+ ? (string[]?)null
+ : FilterProperties.Keys.All(name => properties.Contains(name))
+ ? null
+ : FilterProperties.Keys.Where(name => !properties.Contains(name)).ToArray();
+
+ internal bool Evaluate(Func propertyValueProvider)
+ {
+ ValidateArg.NotNull(propertyValueProvider, nameof(propertyValueProvider));
+
+ bool matched = false;
+ foreach (string name in FilterProperties.Keys)
+ {
+ // If there is no value corresponding to given name, treat it as unmatched.
+ if (!TryGetPropertyValue(name, propertyValueProvider, out string? singleValue, out string[]? multiValues))
+ {
+ continue;
+ }
+
+ if (singleValue != null)
+ {
+ string? value = PropertyValueRegex == null ? singleValue : ApplyRegex(singleValue);
+ matched = value != null && FilterProperties[name].Contains(value);
+ }
+ else
+ {
+ IEnumerable? values = PropertyValueRegex == null ? multiValues : multiValues?.Select(value => ApplyRegex(value));
+ matched = values?.Any(result => result != null && FilterProperties[name].Contains(result)) == true;
+ }
+
+ if (matched)
+ {
+ break;
+ }
+ }
+
+ return IsFilteredOutWhenMatched ? !matched : matched;
+ }
+
+ ///
+ /// Apply regex matching or replacement to given value.
+ ///
+ /// For matching, returns the result of matching, null if no match found. For replacement, returns the result of replacement.
+ private string? ApplyRegex(string value)
+ {
+ RoslynDebug.Assert(PropertyValueRegex != null);
+
+ string? result = null;
+ if (PropertyValueRegexReplacement == null)
+ {
+ Match match = PropertyValueRegex!.Match(value);
+ if (match.Success)
+ {
+ result = match.Value;
+ }
+ }
+ else
+ {
+ result = PropertyValueRegex!.Replace(value, PropertyValueRegexReplacement);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Returns property value for Property using propertyValueProvider.
+ ///
+ private static bool TryGetPropertyValue(string name, Func propertyValueProvider, out string? singleValue, out string[]? multiValues)
+ {
+ object? propertyValue = propertyValueProvider(name);
+ if (propertyValue != null)
+ {
+ multiValues = propertyValue as string[];
+ singleValue = multiValues == null ? propertyValue.ToString() : null;
+ return true;
+ }
+
+ singleValue = null;
+ multiValues = null;
+ return false;
+ }
+
+ internal static Builder CreateBuilder() => new();
+
+ internal sealed class Builder
+ {
+ private readonly ImmutableDictionary.Builder>.Builder _filterDictionaryBuilder = ImmutableDictionary.CreateBuilder.Builder>(StringComparer.OrdinalIgnoreCase);
+
+ private bool _operatorEncountered;
+ private Operator _fastFilterOperator = Operator.None;
+
+ private bool _conditionEncountered;
+ private Operation _fastFilterOperation;
+
+ private bool _containsValidFilter = true;
+
+ internal bool ContainsValidFilter => _containsValidFilter && _conditionEncountered;
+
+ internal void AddOperator(Operator @operator)
+ {
+ if (_containsValidFilter && (@operator == Operator.And || @operator == Operator.Or))
+ {
+ if (_operatorEncountered)
+ {
+ _containsValidFilter = _fastFilterOperator == @operator;
+ }
+ else
+ {
+ _operatorEncountered = true;
+ _fastFilterOperator = @operator;
+ if ((_fastFilterOperation == Operation.NotEqual && _fastFilterOperator == Operator.Or)
+ || (_fastFilterOperation == Operation.Equal && _fastFilterOperator == Operator.And))
+ {
+ _containsValidFilter = false;
+ }
+ }
+ }
+ else
+ {
+ _containsValidFilter = false;
+ }
+ }
+
+ internal void AddCondition(Condition condition)
+ {
+ if (!_containsValidFilter)
+ {
+ return;
+ }
+
+ if (_conditionEncountered)
+ {
+ if (condition.Operation == _fastFilterOperation)
+ {
+ AddProperty(condition.Name, condition.Value);
+ }
+ else
+ {
+ _containsValidFilter = false;
+ }
+ }
+ else
+ {
+ _conditionEncountered = true;
+ _fastFilterOperation = condition.Operation;
+ AddProperty(condition.Name, condition.Value);
+
+ // Don't support `Contains`.
+ if (_fastFilterOperation is not Operation.Equal and not Operation.NotEqual)
+ {
+ _containsValidFilter = false;
+ }
+ }
+ }
+
+ private void AddProperty(string name, string value)
+ {
+ if (!_filterDictionaryBuilder.TryGetValue(name, out ImmutableHashSet.Builder? values))
+ {
+ values = ImmutableHashSet.CreateBuilder(StringComparer.OrdinalIgnoreCase);
+ _filterDictionaryBuilder.Add(name, values);
+ }
+
+ values.Add(value);
+ }
+
+ internal FastFilter? ToFastFilter() => ContainsValidFilter
+ ? new FastFilter(
+ _filterDictionaryBuilder.ToImmutableDictionary(kvp => kvp.Key, kvp => (ISet)_filterDictionaryBuilder[kvp.Key].ToImmutable()),
+ _fastFilterOperation,
+ _fastFilterOperator)
+ : null;
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpression.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpression.cs
new file mode 100644
index 0000000000..567f058e2a
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpression.cs
@@ -0,0 +1,411 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+// NOTE: This file is copied as-is from VSTest source code.
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+///
+/// Represents an expression tree.
+/// Supports:
+/// Logical Operators: !, |
+/// Equality Operators: =, !=
+/// Parenthesis (, ) for grouping.
+///
+[ExcludeFromCodeCoverage] // Helper copied from VSTest source code
+internal sealed partial class FilterExpression
+{
+ private const string TestCaseFilterFormatException = "Incorrect format for TestCaseFilter {0}. Specify the correct format and try again. Note that the incorrect format can lead to no test getting executed.";
+
+ ///
+ /// Condition, if expression is conditional expression.
+ ///
+ private readonly Condition? _condition;
+
+ ///
+ /// Left operand, when expression is logical expression.
+ ///
+ private readonly FilterExpression? _left;
+
+ ///
+ /// Right operand, when expression is logical expression.
+ ///
+ private readonly FilterExpression? _right;
+
+ ///
+ /// If logical expression is using logical And operator.
+ ///
+ private readonly bool _areJoinedByAnd;
+
+ private FilterExpression(FilterExpression left, FilterExpression right, bool areJoinedByAnd)
+ {
+ ArgumentGuard.IsNotNull(left);
+ ArgumentGuard.IsNotNull(right);
+ _left = left;
+ _right = right;
+ _areJoinedByAnd = areJoinedByAnd;
+ }
+
+ private FilterExpression(Condition condition)
+ {
+ ArgumentGuard.IsNotNull(condition);
+ _condition = condition;
+ }
+
+ ///
+ /// Create a new filter expression 'And'ing 'this' with 'filter'.
+ ///
+ private FilterExpression And(FilterExpression filter) => new(this, filter, true);
+
+ ///
+ /// Create a new filter expression 'Or'ing 'this' with 'filter'.
+ ///
+ private FilterExpression Or(FilterExpression filter) => new(this, filter, false);
+
+ ///
+ /// Process the given operator from the filterStack.
+ /// Puts back the result of operation back to filterStack.
+ ///
+ private static void ProcessOperator(Stack filterStack, Operator op)
+ {
+ if (op == Operator.And)
+ {
+ if (filterStack.Count < 2)
+ {
+ throw new FormatException(string.Format(CultureInfo.CurrentCulture, TestCaseFilterFormatException, "Error: Missing operand"));
+ }
+
+ FilterExpression filterRight = filterStack.Pop();
+ FilterExpression filterLeft = filterStack.Pop();
+ FilterExpression result = filterLeft.And(filterRight);
+ filterStack.Push(result);
+ }
+ else if (op == Operator.Or)
+ {
+ if (filterStack.Count < 2)
+ {
+ throw new FormatException(string.Format(CultureInfo.CurrentCulture, TestCaseFilterFormatException, "Error: Missing operand"));
+ }
+
+ FilterExpression filterRight = filterStack.Pop();
+ FilterExpression filterLeft = filterStack.Pop();
+ FilterExpression result = filterLeft.Or(filterRight);
+ filterStack.Push(result);
+ }
+ else if (op == Operator.OpenBrace)
+ {
+ throw new FormatException(string.Format(CultureInfo.CurrentCulture, TestCaseFilterFormatException, "Error: Missing ')'"));
+ }
+ else
+ {
+ Debug.Fail("ProcessOperator called for Unexpected operator.");
+ throw new FormatException(string.Format(CultureInfo.CurrentCulture, TestCaseFilterFormatException, string.Empty));
+ }
+ }
+
+ ///
+ /// True, if filter is valid for given set of properties.
+ /// When False, invalidProperties would contain properties making filter invalid.
+ ///
+ internal string[]? ValidForProperties(IEnumerable? properties, Func? propertyProvider)
+ {
+ // if null, initialize to empty list so that invalid properties can be found.
+ properties ??= [];
+
+ return IterateFilterExpression((current, result) =>
+ {
+ // Only the leaves have a condition value.
+ if (current._condition != null)
+ {
+ bool valid = current._condition.ValidForProperties(properties, propertyProvider);
+
+ // If it's not valid will add it to the function's return array.
+ return !valid ? [current._condition.Name] : null;
+ }
+
+ // Concatenate the children node's result to get their parent result.
+ string[]? invalidRight = current._right != null ? result.Pop() : null;
+ string[]? invalidProperties = current._left != null ? result.Pop() : null;
+
+ if (invalidProperties == null)
+ {
+ invalidProperties = invalidRight;
+ }
+ else if (invalidRight != null)
+ {
+ invalidProperties = invalidProperties.Concat(invalidRight).ToArray();
+ }
+
+ return invalidProperties;
+ });
+ }
+
+ ///
+ /// Return FilterExpression after parsing the given filter expression, and a FastFilter when possible.
+ ///
+ internal static FilterExpression Parse(string filterString, out FastFilter? fastFilter)
+ {
+ ValidateArg.NotNull(filterString, nameof(filterString));
+
+ // Below parsing doesn't error out on pattern (), so explicitly search for that (empty parenthesis).
+ Match invalidInput = GetEmptyParenthesisPattern().Match(filterString);
+ if (invalidInput.Success)
+ {
+ throw new FormatException(string.Format(CultureInfo.CurrentCulture, TestCaseFilterFormatException, "Error: Empty parenthesis ( )"));
+ }
+
+ IEnumerable tokens = TokenizeFilterExpressionString(filterString);
+ var operatorStack = new Stack();
+ var filterStack = new Stack();
+
+ FastFilter.Builder fastFilterBuilder = FastFilter.CreateBuilder();
+
+ // This is based on standard parsing of in order expression using two stacks (operand stack and operator stack)
+ // Precedence(And) > Precedence(Or)
+ foreach (string inputToken in tokens)
+ {
+ string token = inputToken.Trim();
+ if (RoslynString.IsNullOrEmpty(token))
+ {
+ // ignore empty tokens
+ continue;
+ }
+
+ switch (token)
+ {
+ case "&":
+ case "|":
+
+ Operator currentOperator = Operator.And;
+ if (string.Equals("|", token, StringComparison.Ordinal))
+ {
+ currentOperator = Operator.Or;
+ }
+
+ fastFilterBuilder.AddOperator(currentOperator);
+
+ // Always put only higher priority operator on stack.
+ // if lesser priority -- pop up the stack and process the operator to maintain operator precedence.
+ // if equal priority -- pop up the stack and process the operator to maintain operator associativity.
+ // OpenBrace is special condition. & or | can come on top of OpenBrace for case like ((a=b)&c=d)
+ while (true)
+ {
+ bool isEmpty = operatorStack.Count == 0;
+ Operator stackTopOperator = isEmpty ? Operator.None : operatorStack.Peek();
+ if (isEmpty || stackTopOperator == Operator.OpenBrace || stackTopOperator < currentOperator)
+ {
+ operatorStack.Push(currentOperator);
+ break;
+ }
+
+ stackTopOperator = operatorStack.Pop();
+ ProcessOperator(filterStack, stackTopOperator);
+ }
+
+ break;
+
+ case "(":
+ operatorStack.Push(Operator.OpenBrace);
+ break;
+
+ case ")":
+ // process operators from the stack till OpenBrace is found.
+ // If stack is empty at any time, than matching OpenBrace is missing from the expression.
+ if (operatorStack.Count == 0)
+ {
+ throw new FormatException(string.Format(CultureInfo.CurrentCulture, TestCaseFilterFormatException, "Error: Missing '('"));
+ }
+
+ Operator temp = operatorStack.Pop();
+ while (temp != Operator.OpenBrace)
+ {
+ ProcessOperator(filterStack, temp);
+ if (operatorStack.Count == 0)
+ {
+ throw new FormatException(string.Format(CultureInfo.CurrentCulture, TestCaseFilterFormatException, "Error: Missing '('"));
+ }
+
+ temp = operatorStack.Pop();
+ }
+
+ break;
+
+ default:
+ // push the operand to the operand stack.
+ var condition = Condition.Parse(token);
+ FilterExpression filter = new(condition);
+ filterStack.Push(filter);
+
+ fastFilterBuilder.AddCondition(condition);
+ break;
+ }
+ }
+
+ while (operatorStack.Count != 0)
+ {
+ Operator temp = operatorStack.Pop();
+ ProcessOperator(filterStack, temp);
+ }
+
+ if (filterStack.Count != 1)
+ {
+ throw new FormatException(string.Format(CultureInfo.CurrentCulture, TestCaseFilterFormatException, "Missing Operator '|' or '&'"));
+ }
+
+ fastFilter = fastFilterBuilder.ToFastFilter();
+
+ return filterStack.Pop();
+ }
+
+ private T IterateFilterExpression(Func, T> getNodeValue)
+ {
+ FilterExpression? current = this;
+
+ // Will have the nodes.
+ Stack filterStack = new();
+
+ // Will contain the nodes results to use them in thier parent result's calculation
+ // and at the end will have the root result.
+ Stack result = new();
+
+ do
+ {
+ // Push root's right child and then root to stack then Set root as root's left child.
+ while (current != null)
+ {
+ if (current._right != null)
+ {
+ filterStack.Push(current._right);
+ }
+
+ filterStack.Push(current);
+ current = current._left;
+ }
+
+ // If the popped item has a right child and the right child is at top of stack,
+ // then remove the right child from stack, push the root back and set root as root's right child.
+ current = filterStack.Pop();
+ if (filterStack.Count > 0 && current._right == filterStack.Peek())
+ {
+ filterStack.Pop();
+ filterStack.Push(current);
+ current = current._right;
+ continue;
+ }
+
+ result.Push(getNodeValue(current, result));
+ current = null;
+ }
+ while (filterStack.Count > 0);
+
+ RoslynDebug.Assert(result.Count == 1, "Result stack should have one element at the end.");
+ return result.Peek();
+ }
+
+ ///
+ /// Evaluate filterExpression with given propertyValueProvider.
+ ///
+ /// The property Value Provider.
+ /// True if evaluation is successful.
+ internal bool Evaluate(Func propertyValueProvider)
+ {
+ ValidateArg.NotNull(propertyValueProvider, nameof(propertyValueProvider));
+
+ return IterateFilterExpression((current, result) =>
+ {
+ // Only the leaves have a condition value.
+ if (current._condition != null)
+ {
+ return current._condition.Evaluate(propertyValueProvider);
+ }
+ else
+ {
+ // & or | operator
+ bool rightResult = current._right != null && result.Pop();
+ bool leftResult = current._left != null && result.Pop();
+
+ // Concatenate the children node's result to get their parent result.
+ return current._areJoinedByAnd ? leftResult && rightResult : leftResult || rightResult;
+ }
+ });
+ }
+
+ internal static IEnumerable TokenizeFilterExpressionString(string str)
+ {
+ ValidateArg.NotNull(str, nameof(str));
+ return TokenizeFilterExpressionStringHelper(str);
+
+ static IEnumerable TokenizeFilterExpressionStringHelper(string s)
+ {
+ StringBuilder tokenBuilder = new();
+
+ char last = '\0';
+ for (int i = 0; i < s.Length; ++i)
+ {
+ char current = s[i];
+
+ if (last == FilterHelper.EscapeCharacter)
+ {
+ // Don't check if `current` is one of the special characters here.
+ // Instead, we blindly let any character follows '\' pass though and
+ // relies on `FilterHelpers.Unescape` to report such errors.
+ tokenBuilder.Append(current);
+
+ if (current == FilterHelper.EscapeCharacter)
+ {
+ // We just encountered "\\" (escaped '\'), this will set last to '\0'
+ // so the next char will not be treated as a suffix of escape sequence.
+ current = '\0';
+ }
+ }
+ else
+ {
+ switch (current)
+ {
+ case '(':
+ case ')':
+ case '&':
+ case '|':
+ if (tokenBuilder.Length > 0)
+ {
+ yield return tokenBuilder.ToString();
+ tokenBuilder.Clear();
+ }
+
+ yield return current.ToString();
+ break;
+
+ default:
+ tokenBuilder.Append(current);
+ break;
+ }
+ }
+
+ last = current;
+ }
+
+ if (tokenBuilder.Length > 0)
+ {
+ yield return tokenBuilder.ToString();
+ }
+ }
+ }
+
+#if NET7_0_OR_GREATER
+ [GeneratedRegex(@"\(\s*\)")]
+ private static partial Regex GetEmptyParenthesisPattern();
+#else
+ private static Regex GetEmptyParenthesisPattern()
+ => new(@"\(\s*\)");
+#endif
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpressionWrapper.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpressionWrapper.cs
new file mode 100644
index 0000000000..5196f44f71
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FilterExpressionWrapper.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.
+
+// NOTE: This file is copied as-is from VSTest source code.
+using System.Diagnostics.CodeAnalysis;
+using System.Text.RegularExpressions;
+
+using Microsoft.Testing.Platform;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+[ExcludeFromCodeCoverage] // Helper copied from VSTest source code
+internal class FilterExpressionWrapper
+{
+ ///
+ /// FilterExpression corresponding to filter criteria.
+ ///
+ private readonly FilterExpression? _filterExpression;
+
+ ///
+ /// Exposed for testing purpose.
+ ///
+#pragma warning disable SA1401 // Fields should be private
+#pragma warning disable SA1604 // Element documentation should have summary
+ internal readonly FastFilter? _fastFilter;
+#pragma warning restore SA1604 // Element documentation should have summary
+#pragma warning restore SA1401 // Fields should be private
+
+ ///
+ /// Initializes a new instance of the class.
+ /// Initializes FilterExpressionWrapper with given filterString and options.
+ ///
+ public FilterExpressionWrapper(string filterString, FilterOptions? options)
+ {
+ ValidateArg.NotNullOrEmpty(filterString, nameof(filterString));
+
+ FilterString = filterString;
+ FilterOptions = options;
+
+ try
+ {
+ // We prefer fast filter when it's available.
+ _filterExpression = FilterExpression.Parse(filterString, out _fastFilter);
+
+ if (UseFastFilter)
+ {
+ _filterExpression = null;
+
+ // Property value regex is only supported for fast filter,
+ // so we ignore it if no fast filter is constructed.
+
+ // TODO: surface an error message to suer.
+ string? regexString = options?.FilterRegEx;
+ if (!RoslynString.IsNullOrEmpty(regexString))
+ {
+ RoslynDebug.Assert(options!.FilterRegExReplacement == null || options.FilterRegEx != null);
+ _fastFilter.PropertyValueRegex = new Regex(regexString, RegexOptions.Compiled);
+ _fastFilter.PropertyValueRegexReplacement = options.FilterRegExReplacement;
+ }
+ }
+ }
+ catch (FormatException ex)
+ {
+ ParseError = ex.Message;
+ }
+ catch (ArgumentException ex)
+ {
+ _fastFilter = null;
+ ParseError = ex.Message;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ /// Initializes FilterExpressionWrapper with given filterString.
+ ///
+ public FilterExpressionWrapper(string filterString)
+ : this(filterString, null)
+ {
+ }
+
+ [MemberNotNullWhen(true, nameof(_fastFilter))]
+ private bool UseFastFilter => _fastFilter != null;
+
+ ///
+ /// Gets user specified filter criteria.
+ ///
+ public string FilterString { get; }
+
+ ///
+ /// Gets user specified additional filter options.
+ ///
+ public FilterOptions? FilterOptions { get; }
+
+ ///
+ /// Gets parsing error (if any), when parsing 'FilterString' with built-in parser.
+ ///
+ public string? ParseError { get; }
+
+ ///
+ /// Validate if underlying filter expression is valid for given set of supported properties.
+ ///
+ public string[]? ValidForProperties(IEnumerable? supportedProperties, Func? propertyProvider)
+ => UseFastFilter
+ ? _fastFilter.ValidForProperties(supportedProperties)
+ : _filterExpression?.ValidForProperties(supportedProperties, propertyProvider);
+
+ ///
+ /// Evaluate filterExpression with given propertyValueProvider.
+ ///
+ public bool Evaluate(Func propertyValueProvider)
+ {
+ ValidateArg.NotNull(propertyValueProvider, nameof(propertyValueProvider));
+
+ return UseFastFilter
+ ? _fastFilter.Evaluate(propertyValueProvider)
+ : _filterExpression != null && _filterExpression.Evaluate(propertyValueProvider);
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs
new file mode 100644
index 0000000000..ceeb3cf84e
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs
@@ -0,0 +1,175 @@
+// 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.VSTestBridge.Helpers;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.Messages;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+using TestSessionContext = Microsoft.Testing.Platform.TestHost.TestSessionContext;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+///
+/// Bridge implementation of that forwards calls to VSTest and Microsoft Testing Platforms.
+///
+internal sealed class FrameworkHandlerAdapter : IFrameworkHandle
+{
+ ///
+ /// Not null when used in the context of VSTest.
+ ///
+ private readonly IFrameworkHandle? _frameworkHandle;
+ private readonly ILogger _logger;
+ private readonly IMessageBus _messageBus;
+ private readonly VSTestBridgedTestFrameworkBase _adapterExtensionBase;
+ private readonly TestSessionContext _session;
+ private readonly CancellationToken _cancellationToken;
+ private readonly bool _isTrxEnabled;
+ private readonly MessageLoggerAdapter _comboMessageLogger;
+ private readonly string _testAssemblyPath;
+
+ public FrameworkHandlerAdapter(VSTestBridgedTestFrameworkBase adapterExtensionBase, TestSessionContext session, string[] testAssemblyPaths,
+ ITestApplicationModuleInfo testApplicationModuleInfo, ILoggerFactory loggerFactory, IMessageBus messageBus, IOutputDevice outputDevice,
+ bool isTrxEnabled, CancellationToken cancellationToken, IFrameworkHandle? frameworkHandle = null)
+ {
+ if (testAssemblyPaths.Length == 0)
+ {
+ throw new ArgumentException($"{nameof(testAssemblyPaths)} should contain at least one test assembly.");
+ }
+ else if (testAssemblyPaths.Length > 1)
+ {
+ _testAssemblyPath = testApplicationModuleInfo.GetCurrentTestApplicationFullPath();
+
+ if (!testAssemblyPaths.Contains(_testAssemblyPath))
+ {
+ throw new ArgumentException("None of the test assemblies are the test application.");
+ }
+ }
+ else
+ {
+ _testAssemblyPath = testAssemblyPaths[0];
+ }
+
+ _frameworkHandle = frameworkHandle;
+ _logger = loggerFactory.CreateLogger();
+ _messageBus = messageBus;
+ _adapterExtensionBase = adapterExtensionBase;
+ _session = session;
+ _cancellationToken = cancellationToken;
+ _isTrxEnabled = isTrxEnabled;
+ _comboMessageLogger = new MessageLoggerAdapter(loggerFactory, outputDevice, adapterExtensionBase, frameworkHandle);
+ }
+
+ ///
+ public bool EnableShutdownAfterTestRun
+ {
+ get => _frameworkHandle?.EnableShutdownAfterTestRun ?? false;
+ set
+ {
+ _logger.LogTraceAsync($"{nameof(FrameworkHandlerAdapter)}.EnableShutdownAfterTestRun: set to {value}").Await();
+ if (_frameworkHandle is not null)
+ {
+ _frameworkHandle.EnableShutdownAfterTestRun = value;
+ }
+ }
+ }
+
+ ///
+ public int LaunchProcessWithDebuggerAttached(string filePath, string? workingDirectory, string? arguments,
+ IDictionary? environmentVariables)
+ {
+ _logger.LogTraceAsync($"{nameof(FrameworkHandlerAdapter)}.LaunchProcessWithDebuggerAttached").Await();
+ return _frameworkHandle?.LaunchProcessWithDebuggerAttached(filePath, workingDirectory, arguments, environmentVariables)
+ ?? -1;
+ }
+
+ ///
+ public void RecordAttachments(IList attachmentSets)
+ {
+ _logger.LogTraceAsync($"{nameof(FrameworkHandlerAdapter)}.RecordAttachments").Await();
+ _frameworkHandle?.RecordAttachments(attachmentSets);
+ PublishAttachmentsAsync(attachmentSets).Await();
+ }
+
+ ///
+ public void RecordEnd(TestCase testCase, TestOutcome outcome)
+ {
+ _logger.LogTraceAsync($"{nameof(FrameworkHandlerAdapter)}.RecordEnd").Await();
+
+ _cancellationToken.ThrowIfCancellationRequested();
+
+ testCase.FixUpTestCase(_testAssemblyPath);
+
+ // Forward call to VSTest
+ _frameworkHandle?.RecordEnd(testCase, outcome);
+ }
+
+ ///
+ public void RecordResult(TestResult testResult)
+ {
+ _logger.LogTraceAsync($"{nameof(FrameworkHandlerAdapter)}.RecordResult").Await();
+
+ _cancellationToken.ThrowIfCancellationRequested();
+
+ testResult.TestCase.FixUpTestCase(_testAssemblyPath);
+
+ // Forward call to VSTest
+ _frameworkHandle?.RecordResult(testResult);
+
+ // Publish node state change to Microsoft Testing Platform
+ var testNode = testResult.ToTestNode(_isTrxEnabled, _session.Client);
+
+ var testNodeChange = new TestNodeUpdateMessage(_session.SessionUid, testNode);
+ _messageBus.PublishAsync(_adapterExtensionBase, testNodeChange).Await();
+
+ PublishAttachmentsAsync(testResult.Attachments, testNode).Await();
+ }
+
+ ///
+ public void RecordStart(TestCase testCase)
+ {
+ _logger.LogTraceAsync($"{nameof(FrameworkHandlerAdapter)}.RecordStart").Await();
+
+ _cancellationToken.ThrowIfCancellationRequested();
+
+ testCase.FixUpTestCase(_testAssemblyPath);
+
+ // Forward call to VSTest
+ _frameworkHandle?.RecordStart(testCase);
+
+ // Publish node state change to Microsoft Testing Platform
+ var testNode = testCase.ToTestNode(_isTrxEnabled, _session.Client);
+ testNode.Properties.Add(InProgressTestNodeStateProperty.CachedInstance);
+ var testNodeChange = new TestNodeUpdateMessage(_session.SessionUid, testNode);
+
+ _messageBus.PublishAsync(_adapterExtensionBase, testNodeChange).Await();
+ }
+
+ ///
+ public void SendMessage(TestMessageLevel testMessageLevel, string message)
+ => _comboMessageLogger.SendMessage(testMessageLevel, message);
+
+ private async Task PublishAttachmentsAsync(IEnumerable attachments, TestNode? testNode = null)
+ {
+ foreach (AttachmentSet attachmentSet in attachments)
+ {
+ foreach (UriDataAttachment attachment in attachmentSet.Attachments)
+ {
+ if (!attachment.Uri.IsFile)
+ {
+ throw new FormatException($"Test adapter {_adapterExtensionBase.DisplayName} only supports file attachments.");
+ }
+
+ SessionFileArtifact fileArtifact = testNode is null
+ ? new SessionFileArtifact(_session.SessionUid, new(attachment.Uri.LocalPath), attachmentSet.DisplayName, attachment.Description)
+ : new TestNodeFileArtifact(_session.SessionUid, testNode, new(attachment.Uri.LocalPath), attachmentSet.DisplayName, attachment.Description);
+ await _messageBus.PublishAsync(_adapterExtensionBase, fileArtifact);
+ }
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/MessageLoggerAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/MessageLoggerAdapter.cs
new file mode 100644
index 0000000000..44177c1620
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/MessageLoggerAdapter.cs
@@ -0,0 +1,67 @@
+// 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.VSTestBridge.Helpers;
+using Microsoft.Testing.Platform.Extensions;
+using Microsoft.Testing.Platform.Extensions.OutputDevice;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+///
+/// Bridge implementation of that forwards calls to VSTest and Microsoft Testing Platforms.
+///
+internal sealed class MessageLoggerAdapter : IMessageLogger, IOutputDeviceDataProducer
+{
+ ///
+ /// Not null when used in the context of VSTest.
+ ///
+ private readonly IMessageLogger? _messageLogger;
+ private readonly ILogger _logger;
+ private readonly IOutputDevice _outputDevice;
+ private readonly IExtension _extension;
+
+ public MessageLoggerAdapter(ILoggerFactory loggerFactory, IOutputDevice outputDevice, IExtension extension,
+ IMessageLogger? messageLogger = null)
+ {
+ _outputDevice = outputDevice;
+ _extension = extension;
+ _messageLogger = messageLogger;
+ _logger = loggerFactory.CreateLogger();
+ }
+
+ string IExtension.Uid => _extension.Uid;
+
+ string IExtension.Version => _extension.Version;
+
+ string IExtension.DisplayName => _extension.DisplayName;
+
+ string IExtension.Description => _extension.Description;
+
+ ///
+ public void SendMessage(TestMessageLevel testMessageLevel, string message)
+ {
+ _messageLogger?.SendMessage(testMessageLevel, message);
+
+ switch (testMessageLevel)
+ {
+ case TestMessageLevel.Informational:
+ _logger.LogInformationAsync(message).Await();
+ break;
+ case TestMessageLevel.Warning:
+ _logger.LogWarningAsync(message).Await();
+ _outputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateYellowConsoleColorText(message)).Await();
+ break;
+ case TestMessageLevel.Error:
+ _logger.LogErrorAsync(message).Await();
+ _outputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(message)).Await();
+ break;
+ default:
+ throw new NotSupportedException($"Unsupported logging level '{testMessageLevel}'.");
+ }
+ }
+
+ Task IExtension.IsEnabledAsync() => _extension.IsEnabledAsync();
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs
new file mode 100644
index 0000000000..83ab28fdba
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs
@@ -0,0 +1,234 @@
+// 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.Diagnostics.CodeAnalysis;
+
+using Microsoft.Testing.Extensions.TrxReport.Abstractions;
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.TestHost;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+///
+/// A set of extension methods to convert between the Microsoft Testing Platform and VSTest object models.
+///
+internal static class ObjectModelConverters
+{
+ public static readonly TestProperty TestNodeUidProperty = TestProperty.Register(
+ VSTestTestNodeProperties.TestNode.UidPropertyName,
+ VSTestTestNodeProperties.TestNode.UidPropertyName, typeof(string), typeof(TestNode));
+
+ private static readonly TestProperty OriginalExecutorUriProperty = TestProperty.Register(
+ VSTestTestNodeProperties.OriginalExecutorUriPropertyName, VSTestTestNodeProperties.OriginalExecutorUriPropertyName,
+ typeof(Uri), typeof(TestNode));
+
+ ///
+ /// Converts a VSTest to a Microsoft Testing Platform .
+ ///
+ public static TestNode ToTestNode(this TestCase testCase, bool isTrxEnabled, ClientInfo client)
+ {
+ string testNodeUid = testCase.GetPropertyValue(TestNodeUidProperty, null)
+ ?? testCase.FullyQualifiedName;
+
+ TestNode testNode = new()
+ {
+ Uid = new TestNodeUid(testNodeUid),
+ DisplayName = testCase.DisplayName ?? testCase.FullyQualifiedName,
+ };
+
+ CopyVSTestProperties(testCase.Properties, testNode, testCase, testCase.GetPropertyValue, isTrxEnabled, client);
+ if (testCase.CodeFilePath is not null)
+ {
+ testNode.Properties.Add(new TestFileLocationProperty(testCase.CodeFilePath, new(new(testCase.LineNumber, -1), new(testCase.LineNumber, -1))));
+ }
+
+ return testNode;
+ }
+
+ private static void CopyVSTestProperties(IEnumerable testProperties, TestNode testNode, TestCase testCase, Func getPropertyValue,
+ bool isTrxEnabled, ClientInfo client)
+ {
+ List>? testNodeTraits = null;
+ foreach (TestProperty property in testProperties)
+ {
+ testNode.Properties.Add(new VSTestProperty(property, testCase));
+
+ if (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 (property.Id == "MSTestDiscoverer.TestCategory"
+ && getPropertyValue(property) is string[] mstestCategories)
+ {
+ testNode.Properties.Add(new TrxCategoriesProperty(mstestCategories));
+ }
+ }
+
+ // Implement handling of specific vstest properties for VS/VS Code Test Explorer,
+ // see https://github.com/microsoft/testanywhere/blob/main/docs/design/proposed/IDE_Protocol_IDE_Integration.md#vstest-test-node
+ if (client.Id == WellKnownClients.VisualStudio)
+ {
+ if (property.Id == TestCaseProperties.Id.Id
+ && getPropertyValue(property) is Guid testCaseId)
+ {
+ testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.Id", testCaseId.ToString()));
+ }
+ else if (property.Id == TestCaseProperties.FullyQualifiedName.Id
+ && getPropertyValue(property) is string testCaseFqn)
+ {
+ testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.FullyQualifiedName", testCaseFqn));
+ }
+ else if (property.Id == OriginalExecutorUriProperty.Id
+ && getPropertyValue(property) is Uri originalExecutorUri)
+ {
+ testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.original-executor-uri", originalExecutorUri.AbsoluteUri));
+ }
+
+ // The TP object holding the hierarchy property is defined on adapter utilities and we don't want to enforce that dependency
+ // so instead I use the string ID copied from TP.
+ else if (property.Id == "TestCase.Hierarchy"
+ && getPropertyValue(property) is string[] testCaseHierarchy
+ && testCaseHierarchy.Length == 4)
+ {
+ testNode.Properties.Add(new SerializableNamedArrayStringProperty("vstest.TestCase.Hierarchy", testCaseHierarchy));
+ }
+
+ // ID is defined on TraitCollection but is internal so again we copy the string here.
+ else if (property.Id == "TestObject.Traits"
+ && getPropertyValue(property) is KeyValuePair[] traits && traits.Length > 0)
+ {
+#pragma warning disable SA1010 // Opening square brackets should be spaced correctly
+ testNodeTraits ??= [];
+#pragma warning restore SA1010 // Opening square brackets should be spaced correctly
+ testNodeTraits.AddRange(traits);
+ }
+
+ // 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
+ else if (property.Id == "MSTestDiscoverer.TestCategory"
+ && getPropertyValue(property) is string[] mstestCategories && mstestCategories.Length > 0)
+ {
+#pragma warning disable SA1010 // Opening square brackets should be spaced correctly
+ testNodeTraits ??= [];
+#pragma warning restore SA1010 // Opening square brackets should be spaced correctly
+ foreach (string category in mstestCategories)
+ {
+ testNodeTraits.Add(new(category, string.Empty));
+ }
+ }
+ }
+ }
+
+ // Add all the traits and categories we collected from different properties.
+ if (testNodeTraits != null)
+ {
+ testNode.Properties.Add(new SerializableNamedKeyValuePairsStringProperty("traits", testNodeTraits.ToArray()));
+ }
+ }
+
+ ///
+ /// Converts a VSTest to a Microsoft Testing Platform .
+ ///
+ public static TestNode ToTestNode(this TestResult testResult, bool isTrxEnabled, ClientInfo client)
+ {
+ var testNode = testResult.TestCase.ToTestNode(isTrxEnabled, client);
+ CopyVSTestProperties(testResult.Properties, testNode, testResult.TestCase, testResult.GetPropertyValue, isTrxEnabled, client);
+ testNode.AddOutcome(testResult);
+
+ if (isTrxEnabled)
+ {
+ testNode.Properties.Add(new TrxExceptionProperty(testResult.ErrorMessage, testResult.ErrorStackTrace));
+
+ if (TryParseFullyQualifiedType(testResult.TestCase.FullyQualifiedName, out string? fullyQualifiedType))
+ {
+ testNode.Properties.Add(new TrxFullyQualifiedTypeNameProperty(fullyQualifiedType));
+ }
+ else
+ {
+ throw new InvalidOperationException("Unable to parse fully qualified type name from test case: " + testResult.TestCase.FullyQualifiedName);
+ }
+
+ testNode.Properties.Add(new TrxMessagesProperty(testResult.Messages
+ .Select(msg =>
+ msg.Category switch
+ {
+ string x when x == TestResultMessage.StandardErrorCategory => new StandardErrorTrxMessage(msg.Text),
+ 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), []));
+
+ return testNode;
+ }
+
+ private static void AddOutcome(this TestNode testNode, TestResult testResult)
+ {
+ switch (testResult.Outcome)
+ {
+ case TestOutcome.Passed:
+ testNode.Properties.Add(PassedTestNodeStateProperty.CachedInstance);
+ break;
+
+ case TestOutcome.NotFound:
+ testNode.Properties.Add(new ErrorTestNodeStateProperty(new VSTestException(testResult.ErrorMessage ?? "Not found", testResult.ErrorStackTrace)));
+ break;
+
+ case TestOutcome.Failed:
+ testNode.Properties.Add(new FailedTestNodeStateProperty(new VSTestException(testResult.ErrorMessage, testResult.ErrorStackTrace)));
+ break;
+
+ // It seems that NUnit inconclusive tests are reported as None which should be considered as Skipped.
+ case TestOutcome.None:
+ case TestOutcome.Skipped:
+ testNode.Properties.Add(SkippedTestNodeStateProperty.CachedInstance);
+ break;
+
+ default:
+ throw new NotSupportedException($"Unsupported test outcome value '{testResult.Outcome}'");
+ }
+ }
+
+ internal static void FixUpTestCase(this TestCase testCase, string? testAssemblyPath = null)
+ {
+ // To help framework authors using code generator, we replace the Source property of the test case with the
+ // test assembly path.
+ if (RoslynString.IsNullOrEmpty(testCase.Source) && !RoslynString.IsNullOrEmpty(testAssemblyPath))
+ {
+ testCase.Source = testAssemblyPath;
+ }
+
+ // Because this project is the actually registered test adapter, we need to replace test framework executor
+ // URI by ours.
+ if (!testCase.Properties.Any(x => x.Id == OriginalExecutorUriProperty.Id))
+ {
+ testCase.SetPropertyValue(OriginalExecutorUriProperty, testCase.ExecutorUri);
+ }
+
+ testCase.ExecutorUri = new(Constants.ExecutorUri);
+ }
+
+ private static bool TryParseFullyQualifiedType(string fullyQualifiedName, [NotNullWhen(true)] out string? fullyQualifiedType)
+ {
+ fullyQualifiedType = null;
+
+ // Some test frameworks display arguments in the fully qualified type name, so we need to exclude them
+ // before looking at the last dot.
+ int openBracketIndex = fullyQualifiedName.IndexOf('(');
+ int lastDotIndexBeforeOpenBracket = openBracketIndex <= 0
+ ? fullyQualifiedName.LastIndexOf('.')
+ : fullyQualifiedName.LastIndexOf('.', openBracketIndex - 1);
+ if (lastDotIndexBeforeOpenBracket <= 0)
+ {
+ return false;
+ }
+
+ fullyQualifiedType = fullyQualifiedName[..lastDotIndexBeforeOpenBracket];
+ return true;
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunContextAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunContextAdapter.cs
new file mode 100644
index 0000000000..ba279bfa59
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunContextAdapter.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.Diagnostics;
+using System.Text;
+using System.Xml.Linq;
+
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+///
+/// A Microsoft Testing Platform oriented implementation of the VSTest .
+///
+internal sealed class RunContextAdapter : ContextAdapterBase, IRunContext
+{
+ public RunContextAdapter(ICommandLineOptions commandLineOptions, IRunSettings runSettings)
+ : base(commandLineOptions)
+ {
+ RoslynDebug.Assert(runSettings.SettingsXml is not null);
+
+ RunSettings = runSettings;
+
+ // Parse and take the results directory from the runsettings.
+ TestRunDirectory = XElement.Parse(runSettings.SettingsXml).Descendants("ResultsDirectory").SingleOrDefault()?.Value;
+ }
+
+ public RunContextAdapter(ICommandLineOptions commandLineOptions, IRunSettings runSettings, TestNodeUid[] testNodeUids)
+ : this(commandLineOptions, runSettings)
+ {
+ // We assume that the UIDs we receive are TestCase.FullyQualifiedName values.
+ FilterExpressionWrapper = new(string.Join("|", testNodeUids.Select(ConvertToFullyQualifiedNameFilterString)));
+ }
+
+ // NOTE: Always false as it's TPv2 oriented and so not applicable to TA.
+
+ ///
+ public bool KeepAlive { get; }
+
+ // NOTE: Always false as it's TPv2 oriented and so not applicable to TA.
+
+ ///
+ public bool InIsolation { get; }
+
+ // NOTE: Always false as it's TPv2 oriented and so not applicable to TA.
+
+ ///
+ public bool IsDataCollectionEnabled { get; }
+
+ ///
+ public bool IsBeingDebugged => Debugger.IsAttached;
+
+ ///
+ public string? TestRunDirectory { get; }
+
+ ///
+ public string? SolutionDirectory { get; }
+
+ ///
+ public IRunSettings? RunSettings { get; }
+
+ private static string ConvertToFullyQualifiedNameFilterString(TestNodeUid testNodeUid)
+ {
+ StringBuilder filterString = new("FullyQualifiedName=");
+
+ for (int i = 0; i < testNodeUid.Value.Length; i++)
+ {
+ char currentChar = testNodeUid.Value[i];
+ switch (currentChar)
+ {
+ case '\\':
+ case '(':
+ case ')':
+ case '&':
+ case '|':
+ case '=':
+ case '!':
+ case '~':
+ // If the symbol is not escaped, add an escape character.
+ if (i - 1 < 0 || testNodeUid.Value[i - 1] != '\\')
+ {
+ filterString.Append('\\');
+ }
+
+ filterString.Append(currentChar);
+ break;
+
+ default:
+ filterString.Append(currentChar);
+ break;
+ }
+ }
+
+ return filterString.ToString();
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsAdapter.cs
new file mode 100644
index 0000000000..786f228e15
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsAdapter.cs
@@ -0,0 +1,47 @@
+// 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.VSTestBridge.CommandLine;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.TestHost;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+///
+/// A Microsoft Testing Platform oriented implementation of the VSTest .
+///
+internal sealed class RunSettingsAdapter : IRunSettings
+{
+ public RunSettingsAdapter(
+ ICommandLineOptions commandLineOptions,
+ IFileSystem fileSystem,
+ IConfiguration configuration,
+ ClientInfo client,
+ ILoggerFactory loggerFactory)
+ {
+ string? runSettingsXml =
+ commandLineOptions.TryGetOptionArgumentList(RunSettingsCommandLineOptionsProvider.RunSettingsOptionName, out string[]? fileNames)
+ && fileNames is not null
+ && fileNames.Length == 1
+ && fileSystem.Exists(fileNames[0])
+ ? fileSystem.ReadAllText(fileNames[0])
+ : Environment.GetEnvironmentVariable("TESTINGPLATFORM_EXPERIMENTAL_VSTEST_RUNSETTINGS");
+
+ runSettingsXml = RunSettingsPatcher.Patch(runSettingsXml, configuration, client, commandLineOptions).ToString();
+
+ loggerFactory.CreateLogger().LogDebug($"Execution will use the following runsettings:{Environment.NewLine}{runSettingsXml}");
+
+ SettingsXml = runSettingsXml;
+ }
+
+ ///
+ public string? SettingsXml { get; }
+
+ ///
+ // TODO: Needs to be implemented if used by adapters. It is not used by MSTest.
+ public ISettingsProvider? GetSettings(string? settingsName) => throw new NotImplementedException();
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsPatcher.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsPatcher.cs
new file mode 100644
index 0000000000..67e732bbe1
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/RunSettingsPatcher.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.Xml.Linq;
+
+using Microsoft.Testing.Extensions.VSTestBridge.CommandLine;
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.TestHost;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+internal static class RunSettingsPatcher
+{
+ private static readonly char[] TestRunParameterSeparator = ['='];
+
+ public static XDocument Patch(string? runSettingsXml, IConfiguration configuration, ClientInfo client, ICommandLineOptions commandLineOptions)
+ {
+ XDocument runSettingsDocument = PatchSettingsWithDefaults(runSettingsXml, isDesignMode: client.Id == WellKnownClients.VisualStudio, configuration);
+ PatchTestRunParameters(runSettingsDocument, commandLineOptions);
+
+ return runSettingsDocument;
+ }
+
+ private static XDocument PatchSettingsWithDefaults(string? runSettingsXml, bool isDesignMode, IConfiguration configuration)
+ {
+ if (RoslynString.IsNullOrWhiteSpace(runSettingsXml))
+ {
+ runSettingsXml = """
+
+
+ """;
+ }
+
+ var document = XDocument.Parse(runSettingsXml);
+ if (document.Element("RunSettings") is not { } runSettingsElement)
+ {
+ throw new InvalidOperationException("Invalid runsettings, section is missing.");
+ }
+
+ bool isPatchingCommentAdded = false;
+ if (runSettingsElement.Element("RunConfiguration") is not { } runConfigurationElement)
+ {
+ runConfigurationElement = new XElement("RunConfiguration");
+ AddPatchingCommentIfNeeded(runConfigurationElement, ref isPatchingCommentAdded);
+ 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);
+ runConfigurationElement.Add(new XElement("DesignMode", isDesignMode));
+ }
+
+ if (runConfigurationElement.Element("CollectSourceInformation") is null)
+ {
+ AddPatchingCommentIfNeeded(runConfigurationElement, ref isPatchingCommentAdded);
+ runConfigurationElement.Add(new XElement("CollectSourceInformation", false));
+ }
+
+ if (runConfigurationElement.Element("ResultsDirectory") is null)
+ {
+ AddPatchingCommentIfNeeded(runConfigurationElement, ref isPatchingCommentAdded);
+ runConfigurationElement.Add(new XElement("ResultsDirectory", configuration.GetTestResultDirectory()));
+ }
+
+ if (isPatchingCommentAdded)
+ {
+ runConfigurationElement.Add(new XComment("End"));
+ }
+
+ return document;
+ }
+
+ private static void AddPatchingCommentIfNeeded(XElement element, ref bool isPatchingCommentAdded)
+ {
+ if (isPatchingCommentAdded)
+ {
+ return;
+ }
+
+ element.Add(new XComment("Default configuration added by Microsoft Testing Platform"));
+ isPatchingCommentAdded = true;
+ }
+
+ private static void PatchTestRunParameters(XDocument runSettingsDocument, ICommandLineOptions commandLineOptions)
+ {
+ if (!commandLineOptions.TryGetOptionArgumentList(TestRunParametersCommandLineOptionsProvider.TestRunParameterOptionName, out string[]? testRunParameters))
+ {
+ return;
+ }
+
+ XElement runSettingsElement = runSettingsDocument.Element("RunSettings")!;
+ XElement? testRunParametersElement = runSettingsElement.Element("TestRunParameters");
+ if (testRunParametersElement is null)
+ {
+ testRunParametersElement = new XElement("TestRunParameters");
+ runSettingsElement.Add(testRunParametersElement);
+ }
+
+ XElement[] testRunParametersNodes = testRunParametersElement.Nodes().OfType().ToArray();
+ foreach (string testRunParameter in testRunParameters)
+ {
+ string[] parts = testRunParameter.Split(TestRunParameterSeparator, 2);
+ string name = parts[0];
+ string value = parts[1];
+ XElement? existingElement = testRunParametersNodes.FirstOrDefault(x => x.Attribute("name")?.Value == name);
+ if (existingElement is not null)
+ {
+ existingElement.Attribute("value")!.Value = value;
+ }
+ else
+ {
+ var parameterElement = new XElement("Parameter");
+ parameterElement.Add(new XAttribute("name", name));
+ parameterElement.Add(new XAttribute("value", value));
+ testRunParametersElement.Add(parameterElement);
+ }
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs
new file mode 100644
index 0000000000..a3fd9dcfea
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs
@@ -0,0 +1,82 @@
+// 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.VSTestBridge.Helpers;
+using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.Messages;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+using TestSessionContext = Microsoft.Testing.Platform.TestHost.TestSessionContext;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+///
+/// Bridge implementation of that forwards calls to VSTest and Microsoft Testing Platforms.
+///
+internal sealed class TestCaseDiscoverySinkAdapter : ITestCaseDiscoverySink
+{
+ ///
+ /// Not null when used in the context of VSTest.
+ ///
+ private readonly ITestCaseDiscoverySink? _testCaseDiscoverySink;
+ private readonly ILogger _logger;
+ private readonly IMessageBus _messageBus;
+ private readonly bool _isTrxEnabled;
+ private readonly VSTestBridgedTestFrameworkBase _adapterExtension;
+ private readonly TestSessionContext _session;
+ private readonly CancellationToken _cancellationToken;
+ private readonly string? _testAssemblyPath;
+
+ public TestCaseDiscoverySinkAdapter(VSTestBridgedTestFrameworkBase adapterExtension, TestSessionContext session, string[] testAssemblyPaths,
+ ITestApplicationModuleInfo testApplicationModuleInfo, ILoggerFactory loggerFactory, IMessageBus messageBus, bool isTrxEnabled, CancellationToken cancellationToken, ITestCaseDiscoverySink? testCaseDiscoverySink = null)
+ {
+ if (testAssemblyPaths.Length == 0)
+ {
+ throw new ArgumentException($"{nameof(testAssemblyPaths)} should contain at least one test assembly.");
+ }
+ else if (testAssemblyPaths.Length > 1)
+ {
+ _testAssemblyPath = testApplicationModuleInfo.GetCurrentTestApplicationFullPath();
+
+ if (!testAssemblyPaths.Contains(_testAssemblyPath))
+ {
+ throw new ArgumentException("None of the test assemblies are the test application.");
+ }
+ }
+ else
+ {
+ _testAssemblyPath = testAssemblyPaths[0];
+ }
+
+ _testCaseDiscoverySink = testCaseDiscoverySink;
+ _logger = loggerFactory.CreateLogger();
+ _messageBus = messageBus;
+ _isTrxEnabled = isTrxEnabled;
+ _adapterExtension = adapterExtension;
+ _session = session;
+ _cancellationToken = cancellationToken;
+ }
+
+ ///
+ public void SendTestCase(TestCase discoveredTest)
+ {
+ _logger.LogTraceAsync("BridgeTestCaseDiscoverySink.SendTestCase").Await();
+
+ _cancellationToken.ThrowIfCancellationRequested();
+
+ discoveredTest.FixUpTestCase(_testAssemblyPath);
+
+ // Forward call to VSTest
+ _testCaseDiscoverySink?.SendTestCase(discoveredTest);
+
+ // Publish node state change to Microsoft Testing Platform
+ var testNode = discoveredTest.ToTestNode(_isTrxEnabled, _session.Client);
+ testNode.Properties.Add(DiscoveredTestNodeStateProperty.CachedInstance);
+ var testNodeChange = new TestNodeUpdateMessage(_session.SessionUid, testNode);
+
+ _messageBus.PublishAsync(_adapterExtension, testNodeChange).Await();
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseFilterExpression.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseFilterExpression.cs
new file mode 100644
index 0000000000..deafa248f9
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseFilterExpression.cs
@@ -0,0 +1,76 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+// NOTE: This file is copied as-is from VSTest source code.
+using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+///
+/// Implements ITestCaseFilterExpression, providing test case filtering functionality.
+///
+internal sealed class TestCaseFilterExpression : ITestCaseFilterExpression
+{
+ private readonly FilterExpressionWrapper _filterWrapper;
+
+ ///
+ /// If filter Expression is valid for performing TestCase matching
+ /// (has only supported properties, syntax etc).
+ ///
+ private readonly bool _validForMatch;
+
+ ///
+ /// Initializes a new instance of the class.
+ /// Adapter specific filter expression.
+ ///
+ public TestCaseFilterExpression(FilterExpressionWrapper filterWrapper)
+ {
+ ArgumentGuard.IsNotNull(filterWrapper);
+ _filterWrapper = filterWrapper;
+ _validForMatch = RoslynString.IsNullOrEmpty(filterWrapper.ParseError);
+ }
+
+ ///
+ /// Gets user specified filter criteria.
+ ///
+ public string TestCaseFilterValue => _filterWrapper.FilterString;
+
+ ///
+ /// Validate if underlying filter expression is valid for given set of supported properties.
+ ///
+ public string[]? ValidForProperties(IEnumerable? supportedProperties, Func propertyProvider)
+ {
+ string[]? invalidProperties = null;
+ if (_filterWrapper != null && _validForMatch)
+ {
+ invalidProperties = _filterWrapper.ValidForProperties(supportedProperties, propertyProvider);
+ }
+
+ return invalidProperties;
+ }
+
+ ///
+ /// Match test case with filter criteria.
+ ///
+ public bool MatchTestCase(TestCase testCase, Func propertyValueProvider)
+ {
+ ValidateArg.NotNull(testCase, nameof(testCase));
+ ValidateArg.NotNull(propertyValueProvider, nameof(propertyValueProvider));
+
+ if (!_validForMatch)
+ {
+ return false;
+ }
+
+ if (_filterWrapper == null)
+ {
+ // can be null when parsing error occurs. Invalid filter results in no match.
+ return false;
+ }
+
+ return _filterWrapper.Evaluate(propertyValueProvider);
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/VSTestException.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/VSTestException.cs
new file mode 100644
index 0000000000..84e98265c0
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/VSTestException.cs
@@ -0,0 +1,15 @@
+// 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.VSTestBridge.ObjectModel;
+
+internal sealed class VSTestException : Exception
+{
+ public VSTestException(string? message, string? stackTrace)
+ : base(message)
+ {
+ StackTrace = stackTrace;
+ }
+
+ public override string? StackTrace { get; }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/VSTestProperty.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/VSTestProperty.cs
new file mode 100644
index 0000000000..1b4239fbc6
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/VSTestProperty.cs
@@ -0,0 +1,22 @@
+// 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.Messages;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+
+internal sealed class VSTestProperty(TestProperty property, TestCase testCase) : IProperty
+{
+ public TestProperty Property { get; } = property;
+
+ public TestCase TestCase { get; } = testCase;
+
+ // We don't want to pay the allocation if we're not printing it for instance inside the logs.
+ // So we go to get the property and ToString() it only if needed.
+ public override string ToString()
+ {
+ object? value = TestCase.GetPropertyValue(Property);
+ return $"VSTestProperty [Id: {Property.Id}] [Description: {Property.Description}] [ValueType: {Property.ValueType}] [Value: {(value is null ? "null" : value)}]";
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PACKAGE.md b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PACKAGE.md
new file mode 100644
index 0000000000..e11b0ee9a9
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PACKAGE.md
@@ -0,0 +1,9 @@
+# Microsoft.Testing
+
+Microsoft Testing is a set of platform, framework and protocol intended to make it possible to run any test on any target or device.
+
+Documentation can be found at .
+
+## About
+
+This package provides bridge extensions to Microsoft Testing Platform to help test framework authors support both Test Anywhere and the old VSTest Test Platform.
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Shipped.txt b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..65eebdc149
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Shipped.txt
@@ -0,0 +1,57 @@
+#nullable enable
+abstract Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.SynchronizedDiscoverTestsAsync(Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest! request, Microsoft.Testing.Platform.Messages.IMessageBus! messageBus, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
+abstract Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.SynchronizedRunTestsAsync(Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest! request, Microsoft.Testing.Platform.Messages.IMessageBus! messageBus, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.CloseTestSessionAsync(Microsoft.Testing.Platform.Extensions.TestFramework.CloseTestSessionContext! context) -> System.Threading.Tasks.Task!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.CreateTestSessionAsync(Microsoft.Testing.Platform.Extensions.TestFramework.CreateTestSessionContext! context) -> System.Threading.Tasks.Task!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.Description.get -> string!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.DiscoverTestsAsync(Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest! request, Microsoft.Testing.Platform.Messages.IMessageBus! messageBus, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.DisplayName.get -> string!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.IsEnabledAsync() -> System.Threading.Tasks.Task!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.RunTestsAsync(Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest! request, Microsoft.Testing.Platform.Messages.IMessageBus! messageBus, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.ExecuteRequestAsync(Microsoft.Testing.Platform.Requests.TestExecutionRequest! request, Microsoft.Testing.Platform.Messages.IMessageBus! messageBus, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.Uid.get -> string!
+abstract Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.Version.get -> string!
+Microsoft.Testing.Extensions.VSTestBridge.Capabilities.VSTestBridgeExtensionBaseCapabilities
+Microsoft.Testing.Extensions.VSTestBridge.Capabilities.VSTestBridgeExtensionBaseCapabilities.IsTrxEnabled.get -> bool
+Microsoft.Testing.Extensions.VSTestBridge.Capabilities.VSTestBridgeExtensionBaseCapabilities.VSTestBridgeExtensionBaseCapabilities() -> void
+Microsoft.Testing.Extensions.VSTestBridge.Helpers.TestApplicationBuilderExtensions
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest.AssemblyPaths.get -> string![]!
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest.DiscoveryContext.get -> Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IDiscoveryContext!
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest.DiscoverySink.get -> Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.ITestCaseDiscoverySink!
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest.MessageLogger.get -> Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging.IMessageLogger!
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest.VSTestFilter.get -> Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestTestExecutionFilter!
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequestFactory
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest.AssemblyPaths.get -> string![]!
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest.FrameworkHandle.get -> Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle!
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest.RunContext.get -> Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext!
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest.VSTestFilter.get -> Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestTestExecutionFilter!
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest.VSTestRunTestExecutionRequest(Microsoft.Testing.Platform.TestHost.TestSessionContext! session, Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestTestExecutionFilter! executionFilter, string![]! assemblyPaths, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IRunContext! runContext, Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.IFrameworkHandle! frameworkHandle) -> void
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequestFactory
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestTestExecutionFilter
+Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestTestExecutionFilter.TestCases.get -> System.Collections.Immutable.ImmutableArray?
+Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework
+Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.Dispose() -> void
+Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.SynchronizedSingleSessionVSTestBridgedTestFramework(Microsoft.Testing.Platform.Extensions.IExtension! extension, System.Func!>! getTestAssemblies, System.IServiceProvider! serviceProvider, Microsoft.Testing.Platform.Capabilities.TestFramework.ITestFrameworkCapabilities! capabilities) -> void
+Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase
+Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.DataTypesProduced.get -> System.Type![]!
+Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.ExecuteRequestAsync(Microsoft.Testing.Platform.Extensions.TestFramework.ExecuteRequestContext! context) -> System.Threading.Tasks.Task!
+Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.IsTrxEnabled.get -> bool
+Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.ServiceProvider.get -> System.IServiceProvider!
+Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase.VSTestBridgedTestFrameworkBase(System.IServiceProvider! serviceProvider, Microsoft.Testing.Platform.Capabilities.TestFramework.ITestFrameworkCapabilities! capabilities) -> void
+override Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.IsEnabledAsync() -> System.Threading.Tasks.Task!
+override sealed Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.CloseTestSessionAsync(Microsoft.Testing.Platform.Extensions.TestFramework.CloseTestSessionContext! context) -> System.Threading.Tasks.Task!
+override sealed Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.CreateTestSessionAsync(Microsoft.Testing.Platform.Extensions.TestFramework.CreateTestSessionContext! context) -> System.Threading.Tasks.Task!
+override sealed Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.Description.get -> string!
+override sealed Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.DiscoverTestsAsync(Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest! request, Microsoft.Testing.Platform.Messages.IMessageBus! messageBus, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
+override sealed Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.DisplayName.get -> string!
+override sealed Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.RunTestsAsync(Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest! request, Microsoft.Testing.Platform.Messages.IMessageBus! messageBus, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
+override sealed Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.ExecuteRequestAsync(Microsoft.Testing.Platform.Requests.TestExecutionRequest! request, Microsoft.Testing.Platform.Messages.IMessageBus! messageBus, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
+override sealed Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.Uid.get -> string!
+override sealed Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.Version.get -> string!
+static Microsoft.Testing.Extensions.VSTestBridge.Helpers.TestApplicationBuilderExtensions.AddRunSettingsService(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder, Microsoft.Testing.Platform.Extensions.IExtension! extension) -> void
+static Microsoft.Testing.Extensions.VSTestBridge.Helpers.TestApplicationBuilderExtensions.AddTestCaseFilterService(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder, Microsoft.Testing.Platform.Extensions.IExtension! extension) -> void
+static Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequestFactory.CreateRequest(Microsoft.Testing.Platform.Requests.DiscoverTestExecutionRequest! discoverTestExecutionRequest, Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase! adapterExtension, string![]! testAssemblyPaths, System.Threading.CancellationToken cancellationToken) -> Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestDiscoverTestExecutionRequest!
+static Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequestFactory.CreateRequest(Microsoft.Testing.Platform.Requests.RunTestExecutionRequest! runTestExecutionRequest, Microsoft.Testing.Extensions.VSTestBridge.VSTestBridgedTestFrameworkBase! adapterExtension, string![]! testAssemblyPaths, System.Threading.CancellationToken cancellationToken) -> Microsoft.Testing.Extensions.VSTestBridge.Requests.VSTestRunTestExecutionRequest!
+virtual Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.Dispose(bool disposing) -> void
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..50e9e00661
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/PublicAPI.Unshipped.txt
@@ -0,0 +1,2 @@
+#nullable enable
+static Microsoft.Testing.Extensions.VSTestBridge.Helpers.TestApplicationBuilderExtensions.AddTestRunParametersService(this Microsoft.Testing.Platform.Builder.ITestApplicationBuilder! builder, Microsoft.Testing.Platform.Extensions.IExtension! extension) -> void
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequest.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequest.cs
new file mode 100644
index 0000000000..7e737c256b
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequest.cs
@@ -0,0 +1,36 @@
+// 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.Requests;
+using Microsoft.Testing.Platform.TestHost;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.Requests;
+
+///
+/// A specialized discover test execution request for VSTest. It contains the VSTest specific properties.
+///
+public sealed class VSTestDiscoverTestExecutionRequest : DiscoverTestExecutionRequest
+{
+ internal VSTestDiscoverTestExecutionRequest(TestSessionContext session, VSTestTestExecutionFilter executionFilter, string[] assemblyPaths,
+ IDiscoveryContext discoveryContext, IMessageLogger messageLogger, ITestCaseDiscoverySink discoverySink)
+ : base(session, executionFilter)
+ {
+ AssemblyPaths = assemblyPaths;
+ DiscoveryContext = discoveryContext;
+ MessageLogger = messageLogger;
+ DiscoverySink = discoverySink;
+ }
+
+ public VSTestTestExecutionFilter VSTestFilter
+ => (VSTestTestExecutionFilter)Filter;
+
+ public string[] AssemblyPaths { get; }
+
+ public IDiscoveryContext DiscoveryContext { get; }
+
+ public IMessageLogger MessageLogger { get; }
+
+ public ITestCaseDiscoverySink DiscoverySink { get; }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequestFactory.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequestFactory.cs
new file mode 100644
index 0000000000..946606fe3c
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequestFactory.cs
@@ -0,0 +1,82 @@
+// 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.VSTestBridge.Capabilities;
+using Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Extensions.TestFramework;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.Messages;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.Testing.Platform.Requests;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.Requests;
+
+///
+/// VSTest specific implementation of Microsoft Testing Platform .
+///
+public sealed class VSTestDiscoverTestExecutionRequestFactory : ITestExecutionRequestFactory
+{
+ private readonly ITestFrameworkCapabilities _testFrameworkCapabilities;
+ private readonly ITestFramework _testFrameworkAdapter;
+ private readonly ICommandLineOptions _commandLineService;
+ private readonly ILogger _logger;
+ private readonly string[] _assemblyPaths;
+ private readonly VSTestTestExecutionFilter _testExecutionFilter;
+ private readonly IDiscoveryContext _discoveryContext;
+ private readonly IMessageLogger _messageLogger;
+ private readonly ITestCaseDiscoverySink _discoverySink;
+
+ internal VSTestDiscoverTestExecutionRequestFactory(ITestFrameworkCapabilities testFrameworkCapabilities, ITestFramework testFrameworkAdapter,
+ ICommandLineOptions commandLineService, ILoggerFactory loggerFactory, string[] assemblyPaths, VSTestTestExecutionFilter testExecutionFilter,
+ IDiscoveryContext discoveryContext, IMessageLogger messageLogger, ITestCaseDiscoverySink discoverySink)
+ {
+ _testFrameworkCapabilities = testFrameworkCapabilities;
+ _testFrameworkAdapter = testFrameworkAdapter;
+ _commandLineService = commandLineService;
+ _logger = loggerFactory.CreateLogger();
+ _assemblyPaths = assemblyPaths;
+ _discoveryContext = discoveryContext;
+ _messageLogger = messageLogger;
+ _discoverySink = discoverySink;
+ _testExecutionFilter = testExecutionFilter;
+ }
+
+ Task ITestExecutionRequestFactory.CreateRequestAsync(Platform.TestHost.TestSessionContext session)
+ => !_commandLineService.IsOptionSet(PlatformCommandLineProvider.VSTestAdapterModeOptionKey)
+ ? throw new InvalidOperationException($"Command line argument {PlatformCommandLineProvider.VSTestAdapterModeOptionKey} is not set but we are in VSTest adapter mode. This is a bug in the adapter.")
+ : _testFrameworkCapabilities.GetCapability()?.IsSupported != true
+ ? throw new InvalidOperationException($"Skipping test adapter {_testFrameworkAdapter.DisplayName} because it is not {nameof(IVSTestFlattenedTestNodesReportCapability)} capable.")
+ : !_commandLineService.IsOptionSet(PlatformCommandLineProvider.DiscoverTestsOptionKey)
+ ? throw new NotSupportedException($"The {nameof(VSTestRunTestExecutionRequestFactory)} does not support creating a {nameof(DiscoverTestExecutionRequest)}.")
+ : Task.FromResult(new VSTestDiscoverTestExecutionRequest(session, _testExecutionFilter, _assemblyPaths, _discoveryContext, _messageLogger, _discoverySink));
+
+ public static VSTestDiscoverTestExecutionRequest CreateRequest(
+ DiscoverTestExecutionRequest discoverTestExecutionRequest,
+ VSTestBridgedTestFrameworkBase adapterExtension, string[] testAssemblyPaths, CancellationToken cancellationToken)
+ {
+ IServiceProvider serviceProvider = adapterExtension.ServiceProvider;
+ IConfiguration configuration = serviceProvider.GetConfiguration();
+ ILoggerFactory loggerFactory = serviceProvider.GetRequiredService();
+ IFileSystem fileSystem = serviceProvider.GetFileSystem();
+
+ ICommandLineOptions commandLineOptions = serviceProvider.GetRequiredService();
+ RunSettingsAdapter runSettings = new(commandLineOptions, fileSystem, configuration, discoverTestExecutionRequest.Session.Client, loggerFactory);
+ DiscoveryContextAdapter discoveryContext = new(commandLineOptions, runSettings);
+
+ IOutputDevice outputDevice = serviceProvider.GetOutputDevice();
+ MessageLoggerAdapter messageLogger = new(loggerFactory, outputDevice, adapterExtension);
+
+ ITestApplicationModuleInfo testApplicationModuleInfo = serviceProvider.GetTestApplicationModuleInfo();
+ IMessageBus messageBus = serviceProvider.GetRequiredService();
+ TestCaseDiscoverySinkAdapter discoverySink = new(adapterExtension, discoverTestExecutionRequest.Session, testAssemblyPaths, testApplicationModuleInfo, loggerFactory, messageBus, adapterExtension.IsTrxEnabled, cancellationToken);
+
+ return new(discoverTestExecutionRequest.Session, new(), testAssemblyPaths, discoveryContext, messageLogger, discoverySink);
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequest.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequest.cs
new file mode 100644
index 0000000000..c0d52e8cb9
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequest.cs
@@ -0,0 +1,32 @@
+// 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.Requests;
+using Microsoft.Testing.Platform.TestHost;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.Requests;
+
+///
+/// A specialized run test execution request for VSTest. It contains the VSTest specific properties.
+///
+public sealed class VSTestRunTestExecutionRequest : RunTestExecutionRequest
+{
+ public VSTestRunTestExecutionRequest(TestSessionContext session, VSTestTestExecutionFilter executionFilter, string[] assemblyPaths,
+ IRunContext runContext, IFrameworkHandle frameworkHandle)
+ : base(session, executionFilter)
+ {
+ AssemblyPaths = assemblyPaths;
+ RunContext = runContext;
+ FrameworkHandle = frameworkHandle;
+ }
+
+ public VSTestTestExecutionFilter VSTestFilter
+ => (VSTestTestExecutionFilter)Filter;
+
+ public string[] AssemblyPaths { get; }
+
+ public IRunContext RunContext { get; }
+
+ public IFrameworkHandle FrameworkHandle { get; }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequestFactory.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequestFactory.cs
new file mode 100644
index 0000000000..dfd5d83b9a
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequestFactory.cs
@@ -0,0 +1,89 @@
+// 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.VSTestBridge.Capabilities;
+using Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.Testing.Platform.CommandLine;
+using Microsoft.Testing.Platform.Configurations;
+using Microsoft.Testing.Platform.Extensions.TestFramework;
+using Microsoft.Testing.Platform.Helpers;
+using Microsoft.Testing.Platform.Logging;
+using Microsoft.Testing.Platform.Messages;
+using Microsoft.Testing.Platform.OutputDevice;
+using Microsoft.Testing.Platform.Requests;
+using Microsoft.Testing.Platform.Services;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.Requests;
+
+///
+/// VSTest specific implementation of Microsoft Testing Platform .
+///
+public sealed class VSTestRunTestExecutionRequestFactory : ITestExecutionRequestFactory
+{
+ private readonly ITestFrameworkCapabilities _testFrameworkCapabilities;
+ private readonly ITestFramework _testFrameworkAdapter;
+ private readonly ICommandLineOptions _commandLineService;
+ private readonly ILogger _logger;
+ private readonly string[] _assemblyPaths;
+ private readonly VSTestTestExecutionFilter _testExecutionFilter;
+ private readonly IRunContext _runContext;
+ private readonly IFrameworkHandle _frameworkHandle;
+
+ internal VSTestRunTestExecutionRequestFactory(ITestFrameworkCapabilities testFrameworkCapabilities, ITestFramework testFrameworkAdapter,
+ ICommandLineOptions commandLineService, ILoggerFactory loggerFactory, string[] assemblyPaths, VSTestTestExecutionFilter testExecutionFilter,
+ IRunContext runContext, IFrameworkHandle frameworkHandle)
+ {
+ _testFrameworkCapabilities = testFrameworkCapabilities;
+ _testFrameworkAdapter = testFrameworkAdapter;
+ _commandLineService = commandLineService;
+ _logger = loggerFactory.CreateLogger();
+ _assemblyPaths = assemblyPaths;
+ _testExecutionFilter = testExecutionFilter;
+ _runContext = runContext;
+ _frameworkHandle = frameworkHandle;
+ }
+
+ Task ITestExecutionRequestFactory.CreateRequestAsync(Platform.TestHost.TestSessionContext session)
+ => !_commandLineService.IsOptionSet(PlatformCommandLineProvider.VSTestAdapterModeOptionKey)
+ ? throw new InvalidOperationException($"Command line argument {PlatformCommandLineProvider.VSTestAdapterModeOptionKey} is not set but we are in VSTest adapter mode. This is a bug in the adapter.")
+ : _testFrameworkCapabilities.GetCapability()?.IsSupported != true
+ ? throw new InvalidOperationException($"Skipping test adapter {_testFrameworkAdapter.DisplayName} because it is not {nameof(IVSTestFlattenedTestNodesReportCapability)} capable.")
+ : _commandLineService.IsOptionSet(PlatformCommandLineProvider.DiscoverTestsOptionKey)
+ ? throw new NotSupportedException($"The {nameof(VSTestRunTestExecutionRequestFactory)} does not support creating a {nameof(DiscoverTestExecutionRequest)}.")
+ : Task.FromResult(new VSTestRunTestExecutionRequest(session, _testExecutionFilter, _assemblyPaths, _runContext, _frameworkHandle));
+
+ ///
+ /// Helper method to convert a to a .
+ ///
+ /// The request to convert.
+ /// The test adapter extension.
+ /// The list of assemblies to test.
+ /// A cancellation token.
+ public static VSTestRunTestExecutionRequest CreateRequest(
+ RunTestExecutionRequest runTestExecutionRequest,
+ VSTestBridgedTestFrameworkBase adapterExtension,
+ string[] testAssemblyPaths,
+ CancellationToken cancellationToken)
+ {
+ IServiceProvider serviceProvider = adapterExtension.ServiceProvider;
+ IConfiguration configuration = serviceProvider.GetConfiguration();
+ ICommandLineOptions commandLineOptions = serviceProvider.GetRequiredService();
+ ILoggerFactory loggerFactory = serviceProvider.GetRequiredService();
+ IFileSystem fileSystem = serviceProvider.GetFileSystem();
+
+ RunSettingsAdapter runSettings = new(commandLineOptions, fileSystem, configuration, runTestExecutionRequest.Session.Client, loggerFactory);
+ RunContextAdapter runContext = runTestExecutionRequest.Filter is TestNodeUidListFilter uidListFilter
+ ? new(commandLineOptions, runSettings, uidListFilter.TestNodeUids)
+ : new(commandLineOptions, runSettings);
+
+ ITestApplicationModuleInfo testApplicationModuleInfo = serviceProvider.GetTestApplicationModuleInfo();
+ IMessageBus messageBus = serviceProvider.GetRequiredService();
+ IOutputDevice outputDevice = serviceProvider.GetOutputDevice();
+ FrameworkHandlerAdapter frameworkHandlerAdapter = new(adapterExtension, runTestExecutionRequest.Session, testAssemblyPaths,
+ testApplicationModuleInfo, loggerFactory, messageBus, outputDevice, adapterExtension.IsTrxEnabled, cancellationToken);
+
+ return new(runTestExecutionRequest.Session, new(), testAssemblyPaths, runContext, frameworkHandlerAdapter);
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestTestExecutionFilter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestTestExecutionFilter.cs
new file mode 100644
index 0000000000..68be9d37d5
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestTestExecutionFilter.cs
@@ -0,0 +1,26 @@
+// 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.Testing.Platform.Requests;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+
+namespace Microsoft.Testing.Extensions.VSTestBridge.Requests;
+
+///
+/// A specialized test execution filter for VSTest. It contains the VSTest specific properties.
+///
+public sealed class VSTestTestExecutionFilter : ITestExecutionFilter
+{
+ internal VSTestTestExecutionFilter()
+ {
+ }
+
+ internal VSTestTestExecutionFilter(ImmutableArray testCases)
+ {
+ TestCases = testCases;
+ }
+
+ public ImmutableArray? TestCases { get; }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.Designer.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.Designer.cs
new file mode 100644
index 0000000000..d9a86127d5
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.Designer.cs
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+//
+// 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.Testing.Extensions.VSTestBridge.Resources {
+ 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 ExtensionResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal ExtensionResources() {
+ }
+
+ ///
+ /// 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.Testing.Extensions.VSTestBridge.Resources.ExtensionResources", typeof(ExtensionResources).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 runsettings file '{0}' cannot be read.
+ ///
+ internal static string RunsettingsFileCannotBeRead {
+ get {
+ return ResourceManager.GetString("RunsettingsFileCannotBeRead", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to runsettings file '{0}' does not exist.
+ ///
+ internal static string RunsettingsFileDoesNotExist {
+ get {
+ return ResourceManager.GetString("RunsettingsFileDoesNotExist", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The path, relative or absolute, to the .runsettings file. For more information and examples on how to configure test run, see https://learn.microsoft.com/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file#the-runsettings-file.
+ ///
+ internal static string RunSettingsOptionDescription {
+ get {
+ return ResourceManager.GetString("RunSettingsOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Filters tests using the given expression. For more information, see the Filter option details section. For more information and examples on how to use selective unit test filtering, see https://learn.microsoft.com/dotnet/core/testing/selective-unit-tests..
+ ///
+ internal static string TestCaseFilterOptionDescription {
+ get {
+ return ResourceManager.GetString("TestCaseFilterOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to argument '{0}' is not a parameter. Parameters arguments are matching the following pattern 'key=value'..
+ ///
+ internal static string TestRunParameterOptionArgumentIsNotParameter {
+ get {
+ return ResourceManager.GetString("TestRunParameterOptionArgumentIsNotParameter", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specify or override a key-value pair parameter. For more information and examples, see https://learn.microsoft.com/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file#testrunparameters.
+ ///
+ internal static string TestRunParameterOptionDescription {
+ get {
+ return ResourceManager.GetString("TestRunParameterOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The bridged framework supports only one session at a time. A session with UID {0} is already open..
+ ///
+ internal static string VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage {
+ get {
+ return ResourceManager.GetString("VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resx b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resx
new file mode 100644
index 0000000000..8a15a99eba
--- /dev/null
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resx
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+