diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000000..be6c1fa878
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-coverage": {
+ "version": "17.13.1",
+ "commands": [
+ "dotnet-coverage"
+ ],
+ "rollForward": false
+ }
+ }
+}
diff --git a/.editorconfig b/.editorconfig
index e323c80086..742a013007 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -66,6 +66,9 @@ tab_width = 4
# Do not set end_of_line property, this is causing issues with Linux,
# see https://github.com/dotnet/roslyn/issues/55526
+# MSTESTOBS: Type or member is obsolete
+dotnet_diagnostic.MSTESTOBS.severity = none
+
#### .NET Coding Conventions ####
## Organize usings
@@ -211,6 +214,7 @@ dotnet_diagnostic.CA1827.severity = warning # CA1827: Do not use Cou
dotnet_diagnostic.CA1836.severity = warning # CA1836: Prefer IsEmpty over Count
dotnet_diagnostic.CA1840.severity = warning # CA1840: Use 'Environment.CurrentManagedThreadId'
dotnet_diagnostic.CA1852.severity = warning # CA1852: Seal internal types
+dotnet_code_quality.CA1852.ignore_internalsvisibleto = true
dotnet_diagnostic.CA1854.severity = warning # CA1854: Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method
# Disabled as it's making the code complex to deal with when multi targeting
dotnet_diagnostic.CA1863.severity = none # CA1863: Use 'CompositeFormat'
@@ -245,6 +249,7 @@ dotnet_diagnostic.SA1402.severity = none # SA1402: File may only
dotnet_diagnostic.SA1515.severity = none # SA1515: Single-line comment should be preceded by blank line
dotnet_diagnostic.SA1611.severity = none # SA1611: Element parameters should be documented
dotnet_diagnostic.SA1615.severity = none # SA1615: Element return value should be documented
+dotnet_diagnostic.SA1633.severity = none # SA1633: File should have header
dotnet_diagnostic.SA1649.severity = none # SA1649: File name should match first type name
# -----------------------------------------------------------------------------------------
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 2874056945..804b456c01 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,4 +1,4 @@
# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners
-src/Package/MSTest.Sdk @MarcoRossignoli
-src/Platform @MarcoRossignoli @Evangelink
+src/Package/MSTest.Sdk @MarcoRossignoli @Evangelink
+src/Platform @MarcoRossignoli @Youssef1313 @Evangelink
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
index 5375827be7..88ed4a361d 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.md
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -1,6 +1,6 @@
---
name: Bug report
-about: Create a bug report to help us improve MSTest
+about: Create a bug report to help us improve Microsoft.Testing.Platform and MSTest
labels: [bug, need-triage]
---
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
index 53121833f4..aa865b4bf0 100644
--- a/.github/ISSUE_TEMPLATE/feature-request.md
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -1,6 +1,6 @@
---
name: Feature request
-about: Suggest a new feature/idea for MSTest
+about: Suggest a new feature/idea for Microsoft.Testing.Platform or MSTest
labels: [feature-request, need-triage]
---
diff --git a/.github/workflows/backport-base.yml b/.github/workflows/backport-base.yml
new file mode 100644
index 0000000000..8518144320
--- /dev/null
+++ b/.github/workflows/backport-base.yml
@@ -0,0 +1,265 @@
+on:
+ workflow_call:
+ inputs:
+ pr_title_template:
+ description: 'The template used for the PR title. Special placeholder tokens that will be replaced with a value: %target_branch%, %source_pr_title%, %source_pr_number%, %cc_users%.'
+ required: false
+ type: string
+ default: '[%target_branch%] %source_pr_title%'
+ pr_description_template:
+ description: 'The template used for the PR description. Special placeholder tokens that will be replaced with a value: %target_branch%, %source_pr_title%, %source_pr_number%, %cc_users%.'
+ required: false
+ type: string
+ default: |
+ Backport of #%source_pr_number% to %target_branch%
+
+ /cc %cc_users%
+ repository_owners:
+ description: 'A comma-separated list of repository owners where the workflow will run. Defaults to "dotnet,microsoft".'
+ required: false
+ type: string
+ default: 'dotnet,microsoft'
+
+jobs:
+ cleanup:
+ if: ${{ contains(format('{0},', inputs.repository_owners), format('{0},', github.repository_owner)) && github.event_name == 'schedule' }}
+ runs-on: ubuntu-latest
+ permissions:
+ actions: write
+ steps:
+ - name: Cleanup workflow runs
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const repo_owner = context.payload.repository.owner.login;
+ const repo_name = context.payload.repository.name;
+
+ // look up workflow from current run
+ const currentWorkflowRun = await github.rest.actions.getWorkflowRun({
+ owner: repo_owner,
+ repo: repo_name,
+ run_id: context.runId
+ });
+
+ // get runs which are 'completed' (other candidate values of status field are e.g. 'queued' and 'in_progress')
+ for await (const response of github.paginate.iterator(
+ github.rest.actions.listWorkflowRuns, {
+ owner: repo_owner,
+ repo: repo_name,
+ workflow_id: currentWorkflowRun.data.workflow_id,
+ status: 'completed'
+ }
+ )) {
+ // delete each run
+ for (const run of response.data) {
+ console.log(`Deleting workflow run ${run.id}`);
+ await github.rest.actions.deleteWorkflowRun({
+ owner: repo_owner,
+ repo: repo_name,
+ run_id: run.id
+ });
+ }
+ }
+
+ run_backport:
+ if: ${{ contains(format('{0},', inputs.repository_owners), format('{0},', github.repository_owner)) && github.event.issue.pull_request != '' && contains(github.event.comment.body, '/backport to') }}
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ issues: write
+ pull-requests: write
+ steps:
+ - name: Extract backport target branch
+ uses: actions/github-script@v7
+ id: target-branch-extractor
+ with:
+ result-encoding: string
+ script: |
+ if (context.eventName !== "issue_comment") throw "Error: This action only works on issue_comment events.";
+
+ // extract the target branch name from the trigger phrase containing these characters: a-z, A-Z, digits, forward slash, dot, hyphen, underscore
+ const regex = /^\/backport to ([a-zA-Z\d\/\.\-\_]+)/;
+ target_branch = regex.exec(context.payload.comment.body);
+ if (target_branch == null) throw "Error: No backport branch found in the trigger phrase.";
+
+ return target_branch[1];
+ - name: Unlock comments if PR is locked
+ uses: actions/github-script@v7
+ if: ${{ github.event.issue.locked == true }}
+ with:
+ script: |
+ console.log(`Unlocking locked PR #${context.issue.number}.`);
+ await github.rest.issues.unlock({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ });
+ - name: Post backport started comment to pull request
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const target_branch = '${{ steps.target-branch-extractor.outputs.result }}';
+ const backport_start_body = `Started backporting to ${target_branch}: https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
+ await github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: backport_start_body
+ });
+ - name: Checkout repo
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Run backport
+ uses: actions/github-script@v7
+ env:
+ BACKPORT_PR_TITLE_TEMPLATE: ${{ inputs.pr_title_template }}
+ BACKPORT_PR_DESCRIPTION_TEMPLATE: ${{ inputs.pr_description_template }}
+ with:
+ script: |
+ const target_branch = '${{ steps.target-branch-extractor.outputs.result }}';
+ const repo_owner = context.payload.repository.owner.login;
+ const repo_name = context.payload.repository.name;
+ const pr_number = context.payload.issue.number;
+ const comment_user = context.payload.comment.user.login;
+
+ try {
+ // verify the comment user is a repo collaborator
+ try {
+ await github.rest.repos.checkCollaborator({
+ owner: repo_owner,
+ repo: repo_name,
+ username: comment_user
+ });
+ console.log(`Verified ${comment_user} is a repo collaborator.`);
+ } catch (error) {
+ console.log(error);
+ throw new Error(`Error: @${comment_user} is not a repo collaborator, backporting is not allowed. If you're a collaborator please make sure your ${repo_owner} team membership visibility is set to Public on https://github.com/orgs/${repo_owner}/people?query=${comment_user}`);
+ }
+
+ try { await exec.exec(`git ls-remote --exit-code --heads origin ${target_branch}`) } catch { throw new Error(`Error: The specified backport target branch ${target_branch} wasn't found in the repo.`); }
+ console.log(`Backport target branch: ${target_branch}`);
+
+ console.log("Applying backport patch");
+
+ await exec.exec(`git checkout ${target_branch}`);
+ await exec.exec(`git clean -xdff`);
+
+ // configure git
+ await exec.exec(`git config user.name "github-actions"`);
+ await exec.exec(`git config user.email "github-actions@github.com"`);
+
+ // create temporary backport branch
+ const temp_branch = `backport/pr-${pr_number}-to-${target_branch}`;
+ await exec.exec(`git checkout -b ${temp_branch}`);
+
+ // skip opening PR if the branch already exists on the origin remote since that means it was opened
+ // by an earlier backport and force pushing to the branch updates the existing PR
+ let should_open_pull_request = true;
+ try {
+ await exec.exec(`git ls-remote --exit-code --heads origin ${temp_branch}`);
+ should_open_pull_request = false;
+ } catch { }
+
+ // download and apply patch
+ await exec.exec(`curl -sSL "${context.payload.issue.pull_request.patch_url}" --output changes.patch`);
+
+ // const git_am_command = "git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch";
+ // let git_am_output = `$ ${git_am_command}\n\n`;
+ // let git_am_failed = false;
+ // try {
+ // await exec.exec(git_am_command, [], {
+ // listeners: {
+ // stdout: function stdout(data) { git_am_output += data; },
+ // stderr: function stderr(data) { git_am_output += data; }
+ // }
+ // });
+ // } catch (error) {
+ // git_am_output += error;
+ // git_am_failed = true;
+ // }
+
+ // if (git_am_failed) {
+ // const git_am_failed_body = `@${context.payload.comment.user.login} backporting to ${target_branch} failed, the patch most likely resulted in conflicts:\n\n\`\`\`shell\n${git_am_output}\n\`\`\`\n\nPlease backport manually!`;
+ // await github.rest.issues.createComment({
+ // owner: repo_owner,
+ // repo: repo_name,
+ // issue_number: pr_number,
+ // body: git_am_failed_body
+ // });
+ // core.setFailed("Error: git am failed, most likely due to a merge conflict.");
+ // return;
+ // }
+ // else {
+ // // push the temp branch to the repository
+ // await exec.exec(`git push --force --set-upstream origin HEAD:${temp_branch}`);
+ // }
+
+ // if (!should_open_pull_request) {
+ // console.log("Backport temp branch already exists, skipping opening a PR.");
+ // return;
+ // }
+
+ // prepare the GitHub PR details
+
+ // get users to cc (append PR author if different from user who issued the backport command)
+ // let cc_users = `@${comment_user}`;
+ // if (comment_user != context.payload.issue.user.login) cc_users += ` @${context.payload.issue.user.login}`;
+
+ // replace the special placeholder tokens with values
+ // const { BACKPORT_PR_TITLE_TEMPLATE, BACKPORT_PR_DESCRIPTION_TEMPLATE } = process.env
+
+ // const backport_pr_title = BACKPORT_PR_TITLE_TEMPLATE
+ // .replace(/%target_branch%/g, target_branch)
+ // .replace(/%source_pr_title%/g, context.payload.issue.title)
+ // .replace(/%source_pr_number%/g, context.payload.issue.number)
+ // .replace(/%cc_users%/g, cc_users);
+
+ // const backport_pr_description = BACKPORT_PR_DESCRIPTION_TEMPLATE
+ // .replace(/%target_branch%/g, target_branch)
+ // .replace(/%source_pr_title%/g, context.payload.issue.title)
+ // .replace(/%source_pr_number%/g, context.payload.issue.number)
+ // .replace(/%cc_users%/g, cc_users);
+
+ // open the GitHub PR
+ // await github.rest.pulls.create({
+ // owner: repo_owner,
+ // repo: repo_name,
+ // title: backport_pr_title,
+ // body: backport_pr_description,
+ // head: temp_branch,
+ // base: target_branch
+ // });
+
+ // console.log("Successfully opened the GitHub PR.");
+ } catch (error) {
+
+ core.setFailed(error);
+
+ // post failure to GitHub comment
+ const unknown_error_body = `@${comment_user} an error occurred while backporting to ${target_branch}, please check the run log for details!\n\n${error.message}`;
+ await github.rest.issues.createComment({
+ owner: repo_owner,
+ repo: repo_name,
+ issue_number: pr_number,
+ body: unknown_error_body
+ });
+ }
+
+ - uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7
+ with:
+ token: ${{ secrets.BACKPORT_MACHINE_USER_PAT }}
+ push-to-fork: youssef-backport-bot/testfx
+
+ - name: Re-lock PR comments
+ uses: actions/github-script@v7
+ if: ${{ github.event.issue.locked == true && (success() || failure()) }}
+ with:
+ script: |
+ console.log(`Locking previously locked PR #${context.issue.number} again.`);
+ await github.rest.issues.lock({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ lock_reason: "resolved"
+ });
\ No newline at end of file
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
new file mode 100644
index 0000000000..f0a13576ad
--- /dev/null
+++ b/.github/workflows/backport.yml
@@ -0,0 +1,23 @@
+name: Backport PR to branch
+on:
+ issue_comment:
+ types: [created]
+ schedule:
+ # once a day at 13:00 UTC to cleanup old runs
+ - cron: '0 13 * * *'
+
+permissions:
+ contents: write
+ issues: write
+ pull-requests: write
+ actions: write
+
+jobs:
+ backport:
+ if: ${{ contains(github.event.comment.body, '/backport to') || github.event_name == 'schedule' }}
+ uses: microsoft/testfx/.github/workflows/backport-base.yml@main
+ with:
+ pr_description_template: |
+ Backport of #%source_pr_number% to %target_branch%
+
+ /cc %cc_users%
diff --git a/Directory.Build.props b/Directory.Build.props
index 291e3b4f05..6e927fe5da 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -25,13 +25,11 @@
- 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
+ net6.0;net7.0;net8.0;net9.0
+ netcoreapp3.1;net6.0;net7.0;net8.0;net9.0
@@ -67,4 +65,21 @@
0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index d50ae7fda7..0aae14f8fc 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -6,17 +6,17 @@
8.2.2
17.11.4
- 3.11.0-beta1.24574.2
3.11.0
4.10.0
- $(MicrosoftCodeAnalysisAnalyzersVersion)
+ 3.11.0-beta1.24629.2
$(MicrosoftCodeAnalysisPublicApiAnalyzersVersion)
6.2.14
17.12.0
1.49.0
- 17.12.0-beta.24429.1
+ 17.12.0
+ 1.5.0-preview.24577.4
4.3.1
4.3.1
@@ -24,6 +24,7 @@
1.1.3-beta1.24423.1
+ 3.8.0-preview.25057.8
@@ -36,23 +37,21 @@
-
+
-
-
+
-
@@ -64,23 +63,24 @@
-
-
+
+
+
+
-
+
-
-
+
-
+
- latest-recommended
+ preview-recommended
true
-
+
+
-
diff --git a/eng/Build.props b/eng/Build.props
index 57aac3a459..e04a3d62ad 100644
--- a/eng/Build.props
+++ b/eng/Build.props
@@ -4,38 +4,47 @@
all
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eng/CodeCoverage.proj b/eng/CodeCoverage.proj
index 76ae926fba..c336517d96 100644
--- a/eng/CodeCoverage.proj
+++ b/eng/CodeCoverage.proj
@@ -8,45 +8,51 @@
-
<_CodecovPath>$(PkgCodecov)\tools\Codecov.exe
- <_ReportGeneratorPath>$(PkgReportGenerator)\tools\net47\ReportGenerator.exe
+ <_LocalDotNetPath>$(DotNetRoot)\dotnet.exe
+ $(ArtifactsCoverageDir)full\
+ $(ArtifactsCoverageDir)unit\
+ $(ArtifactsCoverageDir)integration\
+ Cobertura.xml
<_CoverageReports Include="$(ArtifactsTestResultsDir)\*.coverage" />
+ <_CoverageReports Include="@(_CoverageReports->'"%(Identity)"', ' ')" />
<_UnitCoverageReports Include="@(_CoverageReports)" Condition="$([System.String]::Copy('%(Identity)').Contains('.UnitTests_'))" />
+ <_UnitCoverageReports Include="@(_UnitCoverageReports->'"%(Identity)"', ' ')" />
<_IntegrationCoverageReports Include="@(_CoverageReports)" Condition="$([System.String]::Copy('%(Identity)').Contains('.IntegrationTests_'))" />
+ <_IntegrationCoverageReports Include="@(_IntegrationCoverageReports->'"%(Identity)"', ' ')" />
-
-
+
+
-
-
+
+
-
-
+
+
- <_CodecovFullArgs Include="-f;$(ArtifactsCoverageDir)full\Cobertura.xml" />
- <_CodecovUnitArgs Include="-f;$(ArtifactsCoverageDir)unit\Cobertura.xml" />
- <_CodecovIntegrationArgs Include="-f;$(ArtifactsCoverageDir)integration\Cobertura.xml" />
+ <_CodecovFullArgs Include="-f;$(MergedFullCoverageDirectory)$(CoberturaFileName)" />
+ <_CodecovUnitArgs Include="-f;$(MergedUnitCoverageDirectory)$(CoberturaFileName)" />
+ <_CodecovIntegrationArgs Include="-f;$(MergedIntegrationCoverageDirectory)$(CoberturaFileName)" />
<_CodecovArgs Include="--required" />
diff --git a/eng/DotNetBuild.props b/eng/DotNetBuild.props
new file mode 100644
index 0000000000..f4d2580ef8
--- /dev/null
+++ b/eng/DotNetBuild.props
@@ -0,0 +1,10 @@
+
+
+
+
+
+ testfx
+ true
+
+
+
diff --git a/eng/SourceBuildPrebuiltBaseline.xml b/eng/SourceBuildPrebuiltBaseline.xml
new file mode 100644
index 0000000000..1b37a10db6
--- /dev/null
+++ b/eng/SourceBuildPrebuiltBaseline.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index afaac5d206..d550616ca3 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,29 +1,49 @@
-
+
https://github.com/dotnet/arcade
- 7d955f9f470465e144c76d47fd2596a0e4c02a21
+ 61b8f746424762d2e3173ebfaab19346224d591c
-
+
https://github.com/dotnet/arcade
- 7d955f9f470465e144c76d47fd2596a0e4c02a21
+ 61b8f746424762d2e3173ebfaab19346224d591c
-
+
https://github.com/dotnet/arcade
- 7d955f9f470465e144c76d47fd2596a0e4c02a21
+ 61b8f746424762d2e3173ebfaab19346224d591c
-
+
https://dev.azure.com/devdiv/DevDiv/_git/vs-code-coverage
- 2d88381a218863f6b20537637b2bcfb0bc93686d
+ 0bfbc955e0dc1826412fdeaa4587106f038ec8de
-
+
https://github.com/microsoft/testanywhere
- 222b1daf1d58cd34402736d9a896975b79171b6d
+ d898ece7f4a764f772bf2ec89ac78a960edb3114
-
- https://github.com/microsoft/testanywhere
- aa2fcc8616d988b234bc1d218465b20c56d0b82f
+
+
+ https://github.com/dotnet/diagnostics
+ 8c505ca6921b5f7e9b8acc234cc8f15035537ee4
+
+
+
+
+ https://github.com/dotnet/source-build-externals
+ 4df883d781a4290873b3b968afc0ff0df7132507
+
+
+
+
+ https://github.com/dotnet/source-build-reference-packages
+ 80f1e84b2077a7208943db050067d86c94ace837
+
+
+
+
+ https://github.com/dotnet/arcade
+ 61b8f746424762d2e3173ebfaab19346224d591c
+
diff --git a/eng/Versions.props b/eng/Versions.props
index 6c4dd96500..15569ec0e6 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -1,16 +1,15 @@
- 3.7.0
+ 3.8.0
- 1.5.0
+ 1.6.0
preview
- 10.0.0-beta.24572.3
- 17.13.0-preview.24572.7
+ 10.0.0-beta.24606.6
+ 17.14.0-preview.25058.3
- 1.5.0-preview.24573.1
- 1.0.0-alpha.24473.2
+ 1.0.0-alpha.25058.1
diff --git a/eng/common/core-templates/steps/source-build.yml b/eng/common/core-templates/steps/source-build.yml
index 4da05afe05..f9ba1625c2 100644
--- a/eng/common/core-templates/steps/source-build.yml
+++ b/eng/common/core-templates/steps/source-build.yml
@@ -78,7 +78,7 @@ steps:
portableBuildArgs=
if [ '${{ parameters.platform.portableBuild }}' != '' ]; then
- portableBuildArgs='/p:PortabelBuild=${{ parameters.platform.portableBuild }}'
+ portableBuildArgs='/p:PortableBuild=${{ parameters.platform.portableBuild }}'
fi
${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \
diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh
index 20ae8c2868..096bfe51f1 100644
--- a/eng/common/cross/build-rootfs.sh
+++ b/eng/common/cross/build-rootfs.sh
@@ -73,8 +73,8 @@ __AlpinePackages+=" krb5-dev"
__AlpinePackages+=" openssl-dev"
__AlpinePackages+=" zlib-dev"
-__FreeBSDBase="13.3-RELEASE"
-__FreeBSDPkg="1.17.0"
+__FreeBSDBase="13.4-RELEASE"
+__FreeBSDPkg="1.21.3"
__FreeBSDABI="13"
__FreeBSDPackages="libunwind"
__FreeBSDPackages+=" icu"
@@ -371,7 +371,7 @@ while :; do
;;
freebsd14)
__CodeName=freebsd
- __FreeBSDBase="14.0-RELEASE"
+ __FreeBSDBase="14.2-RELEASE"
__FreeBSDABI="14"
__SkipUnmount=1
;;
@@ -574,7 +574,7 @@ elif [[ "$__CodeName" == "freebsd" ]]; then
curl -SL "https://download.freebsd.org/ftp/releases/${__FreeBSDArch}/${__FreeBSDMachineArch}/${__FreeBSDBase}/base.txz" | tar -C "$__RootfsDir" -Jxf - ./lib ./usr/lib ./usr/libdata ./usr/include ./usr/share/keys ./etc ./bin/freebsd-version
fi
echo "ABI = \"FreeBSD:${__FreeBSDABI}:${__FreeBSDMachineArch}\"; FINGERPRINTS = \"${__RootfsDir}/usr/share/keys\"; REPOS_DIR = [\"${__RootfsDir}/etc/pkg\"]; REPO_AUTOUPDATE = NO; RUN_SCRIPTS = NO;" > "${__RootfsDir}"/usr/local/etc/pkg.conf
- echo "FreeBSD: { url: \"pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly\", mirror_type: \"srv\", signature_type: \"fingerprints\", fingerprints: \"${__RootfsDir}/usr/share/keys/pkg\", enabled: yes }" > "${__RootfsDir}"/etc/pkg/FreeBSD.conf
+ echo "FreeBSD: { url: \"pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly\", mirror_type: \"srv\", signature_type: \"fingerprints\", fingerprints: \"/usr/share/keys/pkg\", enabled: yes }" > "${__RootfsDir}"/etc/pkg/FreeBSD.conf
mkdir -p "$__RootfsDir"/tmp
# get and build package manager
if [[ "$__hasWget" == 1 ]]; then
diff --git a/eng/common/native/install-dependencies.sh b/eng/common/native/install-dependencies.sh
index dc396a9556..3eef7409f7 100644
--- a/eng/common/native/install-dependencies.sh
+++ b/eng/common/native/install-dependencies.sh
@@ -44,15 +44,11 @@ case "$os" in
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
# Skip brew update for now, see https://github.com/actions/setup-python/issues/577
# brew update --preinstall
-
- # Temporarily uninstall pkg-config@0.29.2 to work around https://github.com/actions/runner-images/issues/10984
- brew uninstall --ignore-dependencies --force pkg-config@0.29.2
-
brew bundle --no-upgrade --no-lock --file=- <
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/eng/stylecop.test.ruleset b/eng/stylecop.test.ruleset
deleted file mode 100644
index 40fc485f7c..0000000000
--- a/eng/stylecop.test.ruleset
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/eng/verify-nupkgs.ps1 b/eng/verify-nupkgs.ps1
index d119680355..a8c3ba4d07 100644
--- a/eng/verify-nupkgs.ps1
+++ b/eng/verify-nupkgs.ps1
@@ -1,6 +1,6 @@
[CmdletBinding()]
Param(
- [Parameter(Mandatory=$true)]
+ [Parameter(Mandatory = $true)]
[System.String] $configuration
)
@@ -19,12 +19,13 @@ function Unzip {
function Confirm-NugetPackages {
Write-Verbose "Starting Confirm-NugetPackages."
$expectedNumOfFiles = @{
- "MSTest.Sdk" = 15;
- "MSTest.Internal.TestFx.Documentation" = 10;
- "MSTest.TestFramework" = 130;
- "MSTest.TestAdapter" = 76;
- "MSTest" = 6;
- "MSTest.Analyzers" = 10;
+ "MSTest.Sdk" = 15
+ "MSTest.Internal.TestFx.Documentation" = 10
+ "MSTest.TestFramework" = 148
+ "MSTest.TestAdapter" = 75
+ "MSTest" = 6
+ "MSTest.Analyzers" = 50
+ "Microsoft.Testing.Platform.DotNetTestClient" = 7
}
$packageDirectory = Resolve-Path "$PSScriptRoot/../artifacts/packages/$configuration"
@@ -79,7 +80,8 @@ function Confirm-NugetPackages {
if ($errors) {
Write-Error "Validation of NuGet packages failed with $($errors.Count) errors:`n$($errors -join "`n")"
- } else {
+ }
+ else {
Write-Host "Successfully validated content of NuGet packages"
}
}
diff --git a/global.json b/global.json
index 77e444f5e2..6534c78b79 100644
--- a/global.json
+++ b/global.json
@@ -1,18 +1,19 @@
{
"tools": {
- "dotnet": "9.0.100",
+ "dotnet": "10.0.100-alpha.1.24573.1",
"runtimes": {
"dotnet": [
"3.1.32",
"6.0.35",
"7.0.20",
- "8.0.10"
+ "8.0.11",
+ "9.0.0"
],
"dotnet/x86": [
- "8.0.10"
+ "9.0.0"
],
"aspnetcore": [
- "8.0.10"
+ "9.0.0"
]
},
"vs": {
@@ -20,12 +21,12 @@
}
},
"sdk": {
- "version": "9.0.100",
+ "version": "10.0.100-alpha.1.24573.1",
"allowPrerelease": true,
"rollForward": "latestFeature"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.24572.3",
+ "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.24606.6",
"MSBuild.Sdk.Extras": "3.0.44"
}
}
diff --git a/samples/FxExtensibility/AssertEx.cs b/samples/FxExtensibility/AssertEx.cs
index 595d001974..6e9abb7eb6 100644
--- a/samples/FxExtensibility/AssertEx.cs
+++ b/samples/FxExtensibility/AssertEx.cs
@@ -1,9 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MSTest.Extensibility.Samples;
diff --git a/samples/FxExtensibility/AssertIs.cs b/samples/FxExtensibility/AssertIs.cs
index 91d3c662a7..eff6cfed75 100644
--- a/samples/FxExtensibility/AssertIs.cs
+++ b/samples/FxExtensibility/AssertIs.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Globalization;
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MSTest.Extensibility.Samples;
diff --git a/samples/FxExtensibility/Properties/AssemblyInfo.cs b/samples/FxExtensibility/Properties/AssemblyInfo.cs
index d3592d292b..3c43a8702b 100644
--- a/samples/FxExtensibility/Properties/AssemblyInfo.cs
+++ b/samples/FxExtensibility/Properties/AssemblyInfo.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Runtime.InteropServices;
-
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
diff --git a/samples/Playground/DebuggerUtility.cs b/samples/Playground/DebuggerUtility.cs
index 6b58a2a58d..babb647424 100644
--- a/samples/Playground/DebuggerUtility.cs
+++ b/samples/Playground/DebuggerUtility.cs
@@ -1,15 +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.
+#if NETCOREAPP
#pragma warning disable CA1837 // Use 'Environment.ProcessId'
#pragma warning disable CA1416 // Validate platform compatibility
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace Microsoft.Testing.TestInfrastructure;
@@ -26,7 +21,7 @@ private static bool AttachVSToProcess(int? pid, int? vsPid, bool enableLog = fal
{
if (pid == null)
{
- Trace($"FAIL: Pid is null.", enabled: enableLog);
+ Trace("FAIL: Pid is null.", enabled: enableLog);
return false;
}
@@ -42,7 +37,7 @@ private static bool AttachVSToProcess(int? pid, int? vsPid, bool enableLog = fal
return true;
}
- Trace($"Parent VS not found, finding the first VS that started.", enabled: enableLog);
+ Trace("Parent VS not found, finding the first VS that started.", enabled: enableLog);
Process? firstVsProcess = GetFirstVsProcess();
if (firstVsProcess != null)
@@ -127,21 +122,21 @@ private static bool AttachVs(Process vs, int pid, bool enableLog = false)
Marshal.ThrowExceptionForHR(r);
if (bindCtx == null)
{
- Trace($"BindCtx is null. Cannot attach VS.", enabled: enableLog);
+ Trace("BindCtx is null. Cannot attach VS.", enabled: enableLog);
return false;
}
bindCtx.GetRunningObjectTable(out runningObjectTable);
if (runningObjectTable == null)
{
- Trace($"RunningObjectTable is null. Cannot attach VS.", enabled: enableLog);
+ Trace("RunningObjectTable is null. Cannot attach VS.", enabled: enableLog);
return false;
}
runningObjectTable.EnumRunning(out enumMoniker);
if (enumMoniker == null)
{
- Trace($"EnumMoniker is null. Cannot attach VS.", enabled: enableLog);
+ Trace("EnumMoniker is null. Cannot attach VS.", enabled: enableLog);
return false;
}
@@ -356,3 +351,5 @@ private static extern int NtQueryInformationProcess(
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
}
+
+#endif
diff --git a/samples/Playground/Playground.csproj b/samples/Playground/Playground.csproj
index 6e3e66fa49..f83ced76c8 100644
--- a/samples/Playground/Playground.csproj
+++ b/samples/Playground/Playground.csproj
@@ -2,12 +2,16 @@
Exe
- net8.0
+ net9.0
enable
false
$(NoWarn);NETSDK1023
+
+
+
+
diff --git a/samples/Playground/Program.cs b/samples/Playground/Program.cs
index c285308345..35fee852f9 100644
--- a/samples/Playground/Program.cs
+++ b/samples/Playground/Program.cs
@@ -1,20 +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.Reflection;
-
using Microsoft.Testing.Platform.Builder;
using Microsoft.Testing.Platform.Extensions.Messages;
using Microsoft.Testing.Platform.Extensions.TestFramework;
using Microsoft.Testing.Platform.Extensions.TestHostControllers;
using Microsoft.Testing.Platform.Messages;
+#if NETCOREAPP
using Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100;
-using Microsoft.Testing.Platform.Services;
+using MSTest.Acceptance.IntegrationTests.Messages.V100;
+#endif
using Microsoft.Testing.Platform.TestHost;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using MSTest.Acceptance.IntegrationTests.Messages.V100;
-
namespace Playground;
public class Program
@@ -26,8 +24,11 @@ public static async Task Main(string[] args)
if (Environment.GetEnvironmentVariable("TESTSERVERMODE") != "1")
{
+#if NETCOREAPP
// To attach to the children
Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess();
+#endif
+
ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args);
// Test MSTest
@@ -37,7 +38,7 @@ public static async Task Main(string[] args)
// testApplicationBuilder.RegisterTestFramework(_ => new TestFrameworkCapabilities(), (_, _) => new DummyAdapter());
// Custom test host controller extension
- testApplicationBuilder.TestHostControllers.AddProcessLifetimeHandler(s => new OutOfProc(s.GetMessageBus()));
+ // testApplicationBuilder.TestHostControllers.AddProcessLifetimeHandler(s => new OutOfProc(s.GetMessageBus()));
// Enable Trx
// testApplicationBuilder.AddTrxReportProvider();
@@ -49,8 +50,11 @@ public static async Task Main(string[] args)
}
else
{
+#if NETFRAMEWORK
+ throw new NotSupportedException("Server mode is not supported on .NET Framework");
+#else
Environment.SetEnvironmentVariable("TESTSERVERMODE", "0");
- using TestingPlatformClient client = await TestingPlatformClientFactory.StartAsServerAndConnectAsync(Environment.ProcessPath!, enableDiagnostic: true);
+ using TestingPlatformClient client = await TestingPlatformClientFactory.StartAsServerAndConnectToTheClientAsync(Environment.ProcessPath!);
await client.InitializeAsync();
List testNodeUpdates = new();
@@ -61,12 +65,13 @@ public static async Task Main(string[] args)
});
await discoveryResponse.WaitCompletionAsync();
- ResponseListener runRequest = await client.RunTestsAsync(Guid.NewGuid(), testNodeUpdates.Select(x => x.Node).ToArray(), node => Task.CompletedTask);
+ ResponseListener runRequest = await client.RunTestsAsync(Guid.NewGuid(), testNodeUpdates.Select(x => x.Node).ToArray(), _ => Task.CompletedTask);
await runRequest.WaitCompletionAsync();
await client.ExitAsync();
return 0;
+#endif
}
}
}
diff --git a/samples/Playground/ServerMode/LogsCollector.cs b/samples/Playground/ServerMode/LogsCollector.cs
index 037e12b643..8ac87d7e0a 100644
--- a/samples/Playground/ServerMode/LogsCollector.cs
+++ b/samples/Playground/ServerMode/LogsCollector.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Collections.Concurrent;
-
using static Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100.TestingPlatformClient;
namespace Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100;
diff --git a/samples/Playground/ServerMode/TelemetryCollector.cs b/samples/Playground/ServerMode/TelemetryCollector.cs
index ac621b10fd..7b48806dc5 100644
--- a/samples/Playground/ServerMode/TelemetryCollector.cs
+++ b/samples/Playground/ServerMode/TelemetryCollector.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Collections.Concurrent;
-
using Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100;
namespace MSTest.Acceptance.IntegrationTests.Messages.V100;
diff --git a/samples/Playground/ServerMode/TestNodeUpdateCollector.cs b/samples/Playground/ServerMode/TestNodeUpdateCollector.cs
index 5943cf25fa..067a4f4410 100644
--- a/samples/Playground/ServerMode/TestNodeUpdateCollector.cs
+++ b/samples/Playground/ServerMode/TestNodeUpdateCollector.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Collections.Concurrent;
-
using Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100;
namespace MSTest.Acceptance.IntegrationTests.Messages.V100;
diff --git a/samples/Playground/ServerMode/TestingPlatformClientFactory.cs b/samples/Playground/ServerMode/TestingPlatformClientFactory.cs
index a5f432d990..44491c2798 100644
--- a/samples/Playground/ServerMode/TestingPlatformClientFactory.cs
+++ b/samples/Playground/ServerMode/TestingPlatformClientFactory.cs
@@ -1,13 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Collections;
-using System.Diagnostics;
-using System.Globalization;
using System.Net;
using System.Net.Sockets;
-using System.Text;
-using System.Text.RegularExpressions;
using Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100;
@@ -51,7 +46,7 @@ public static async Task StartAsServerAndConnectToTheClie
{
OnStandardOutput = (_, output) => builder.AppendLine(CultureInfo.InvariantCulture, $"OnStandardOutput:\n{output}"),
OnErrorOutput = (_, output) => builder.AppendLine(CultureInfo.InvariantCulture, $"OnErrorOutput:\n{output}"),
- OnExit = (processHandle, exitCode) => builder.AppendLine(CultureInfo.InvariantCulture, $"OnExit: exit code '{exitCode}'"),
+ OnExit = (_, exitCode) => builder.AppendLine(CultureInfo.InvariantCulture, $"OnExit: exit code '{exitCode}'"),
Arguments = $"--server --client-host localhost --client-port {((IPEndPoint)tcpListener.LocalEndpoint).Port}",
// Arguments = $"--server --client-host localhost --client-port {((IPEndPoint)tcpListener.LocalEndpoint).Port} --diagnostic --diagnostic-verbosity trace",
@@ -73,89 +68,6 @@ public static async Task StartAsServerAndConnectToTheClie
return new TestingPlatformClient(new(tcpClient.GetStream()), tcpClient, processHandler);
}
-
- public static async Task StartAsServerAndConnectAsync(string testApp, bool enableDiagnostic = false)
- {
- var environmentVariables = new Dictionary(DefaultEnvironmentVariables);
- foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables())
- {
- // Skip all unwanted environment variables.
- string? key = entry.Key.ToString();
- if (WellKnownEnvironmentVariables.ToSkipEnvironmentVariables.Contains(key, StringComparer.OrdinalIgnoreCase))
- {
- continue;
- }
-
- environmentVariables[key!] = entry.Value!.ToString()!;
- }
-
- // We expect to not fail for unhandled exception in server mode for IDE needs.
- environmentVariables.Add("TESTINGPLATFORM_EXIT_PROCESS_ON_UNHANDLED_EXCEPTION", "0");
-
- // To attach to the server on startup
- // environmentVariables.Add(EnvironmentVariableConstants.TESTINGPLATFORM_LAUNCH_ATTACH_DEBUGGER, "1");
- TaskCompletionSource portFound = new();
- ProcessConfiguration processConfig = new(testApp)
- {
- OnStandardOutput =
- (_, output) =>
- {
- Match m = ParsePort().Match(output);
- if (m.Success && int.TryParse(m.Groups[1].Value, out int port))
- {
- portFound.SetResult(port);
- }
-
- // Do not remove pls
- // NotepadWindow.WriteLine($"[OnStandardOutput] {output}");
- },
-
- // Do not remove pls
- // OnErrorOutput = (_, output) => NotepadWindow.WriteLine($"[OnErrorOutput] {output}"),
- OnErrorOutput = (_, output) =>
- {
- if (!portFound.Task.IsCompleted)
- {
- try
- {
- portFound.SetException(new InvalidOperationException(output));
- }
- catch (InvalidOperationException)
- {
- // possible race
- }
- }
- },
- OnExit = (processHandle, exitCode) =>
- {
- if (exitCode != 0)
- {
- if (portFound.Task.Exception is null && !portFound.Task.IsCompleted)
- {
- portFound.SetException(new InvalidOperationException($"Port not found during parsing and process exited with code '{exitCode}'"));
- }
- }
- },
-
- // OnExit = (_, exitCode) => NotepadWindow.WriteLine($"[OnExit] Process exit code '{exitCode}'"),
- Arguments = "--server --diagnostic --diagnostic-verbosity trace",
- // Arguments = "--server",
- EnvironmentVariables = environmentVariables,
- };
-
- IProcessHandle processHandler = ProcessFactory.Start(processConfig, cleanDefaultEnvironmentVariableIfCustomAreProvided: false);
- await portFound.Task;
-
- var tcpClient = new TcpClient();
- using CancellationTokenSource cancellationTokenSource = new(TimeSpan.FromSeconds(90));
-#pragma warning disable VSTHRD103 // Call async methods when in an async method
- await tcpClient.ConnectAsync(new IPEndPoint(IPAddress.Loopback, portFound.Task.Result), cancellationTokenSource.Token);
-#pragma warning restore VSTHRD103 // Call async methods when in an async method
- return new TestingPlatformClient(new(tcpClient.GetStream()), tcpClient, processHandler, enableDiagnostic);
- }
-
- [GeneratedRegex(@"Starting server. Listening on port '(\d+)'")]
- private static partial Regex ParsePort();
}
public sealed class ProcessConfiguration
@@ -257,7 +169,7 @@ public static IProcessHandle Start(ProcessConfiguration config, bool cleanDefaul
if (config.OnExit != null)
{
- process.Exited += (s, e) => config.OnExit.Invoke(processHandle, process.ExitCode);
+ process.Exited += (_, _) => config.OnExit.Invoke(processHandle, process.ExitCode);
}
if (config.OnStandardOutput != null)
diff --git a/samples/Playground/ServerMode/v1.0.0/ClientInfo.cs b/samples/Playground/ServerMode/v1.0.0/ClientInfo.cs
index a4548d891f..5acc6821ed 100644
--- a/samples/Playground/ServerMode/v1.0.0/ClientInfo.cs
+++ b/samples/Playground/ServerMode/v1.0.0/ClientInfo.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Text.Json;
-
using Newtonsoft.Json;
namespace Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100;
diff --git a/samples/Playground/ServerMode/v1.0.0/InitializeRequest.cs b/samples/Playground/ServerMode/v1.0.0/InitializeRequest.cs
index abf5adb281..f15e94ab37 100644
--- a/samples/Playground/ServerMode/v1.0.0/InitializeRequest.cs
+++ b/samples/Playground/ServerMode/v1.0.0/InitializeRequest.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Text.Json;
-
using Newtonsoft.Json;
namespace Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100;
diff --git a/samples/Playground/ServerMode/v1.0.0/RpcListener.cs b/samples/Playground/ServerMode/v1.0.0/RpcListener.cs
index 6bed732b68..e4eca6facb 100644
--- a/samples/Playground/ServerMode/v1.0.0/RpcListener.cs
+++ b/samples/Playground/ServerMode/v1.0.0/RpcListener.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Diagnostics;
-
namespace Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100;
internal sealed class ConsoleRpcListener : TraceListener
diff --git a/samples/Playground/ServerMode/v1.0.0/ServerInfo.cs b/samples/Playground/ServerMode/v1.0.0/ServerInfo.cs
index ccab026462..e2b0e4a49f 100644
--- a/samples/Playground/ServerMode/v1.0.0/ServerInfo.cs
+++ b/samples/Playground/ServerMode/v1.0.0/ServerInfo.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Text.Json;
-
using Newtonsoft.Json;
namespace Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100;
diff --git a/samples/Playground/ServerMode/v1.0.0/TestingPlatformClient.cs b/samples/Playground/ServerMode/v1.0.0/TestingPlatformClient.cs
index 57a585299b..0d37b7f3d5 100644
--- a/samples/Playground/ServerMode/v1.0.0/TestingPlatformClient.cs
+++ b/samples/Playground/ServerMode/v1.0.0/TestingPlatformClient.cs
@@ -1,10 +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.Collections.Concurrent;
-using System.Diagnostics;
using System.Net.Sockets;
-using System.Text;
using MSTest.Acceptance.IntegrationTests.Messages.V100;
diff --git a/samples/Playground/Tests.cs b/samples/Playground/Tests.cs
index eb480d750f..ffd007f386 100644
--- a/samples/Playground/Tests.cs
+++ b/samples/Playground/Tests.cs
@@ -15,13 +15,16 @@ public class TestClass
public TestContext TestContext { get; set; }
[TestMethod]
- public void Test() => TestContext.AddResultFile(@"c:\hello2");
+ [DynamicData(nameof(Data))]
+ public void Test3(int a, int b)
+ => Assert.AreNotEqual(a, b);
- [TestMethod]
- public void Test2() => Assert.AreEqual(1, 0, "few");
-
- [TestMethod]
- public void Test3()
+ public static IEnumerable<(int A, int B)> Data
{
+ get
+ {
+ yield return (1, 2);
+ yield return (3, 4);
+ }
}
}
diff --git a/samples/public/Directory.Build.props b/samples/public/Directory.Build.props
index a5c07027eb..3dff110b22 100644
--- a/samples/public/Directory.Build.props
+++ b/samples/public/Directory.Build.props
@@ -1,13 +1,13 @@
- 8.1.0
- 17.12.6
- 3.6.2
+ 8.2.2
+ 17.13.1
+ 3.6.4
1.0.0-alpha.24530.4
- 1.45.1
- 1.4.2
- 17.11.1
+ 1.49.0
+ 1.4.3
+ 17.12.0
diff --git a/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain.sln b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain.sln
new file mode 100644
index 0000000000..392762a899
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.13.35507.96 d17.13
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSTestProjectWithExplicitMain", "MSTestProjectWithExplicitMain\MSTestProjectWithExplicitMain.csproj", "{3F00FD7B-D9E6-42C6-8607-3186BFBD4A0F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3F00FD7B-D9E6-42C6-8607-3186BFBD4A0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3F00FD7B-D9E6-42C6-8607-3186BFBD4A0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3F00FD7B-D9E6-42C6-8607-3186BFBD4A0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3F00FD7B-D9E6-42C6-8607-3186BFBD4A0F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {68CE81DD-68F6-49B0-87AF-DC6223F45845}
+ EndGlobalSection
+EndGlobal
diff --git a/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain.csproj b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain.csproj
new file mode 100644
index 0000000000..83058077b3
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net9.0
+ latest
+ enable
+ enable
+ true
+ Exe
+ true
+
+ true
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/MSTestSettings.cs b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/MSTestSettings.cs
new file mode 100644
index 0000000000..553a44aa64
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/MSTestSettings.cs
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
diff --git a/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/Program.cs b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/Program.cs
new file mode 100644
index 0000000000..d0f56c90bd
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/Program.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 System.Reflection;
+
+using Microsoft.Testing.Extensions;
+using Microsoft.Testing.Platform.Builder;
+
+// Create the test application builder
+ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args);
+
+// Register the testing framework
+testApplicationBuilder.AddMSTest(() => new[] { Assembly.GetExecutingAssembly() });
+
+// Register Code Coverage extension
+testApplicationBuilder.AddCodeCoverageProvider();
+
+// Register TRX report extension
+testApplicationBuilder.AddTrxReportProvider();
+
+// Register Telemetry extension
+testApplicationBuilder.AddAppInsightsTelemetryProvider();
+
+// Alternatively, instead of registering everything manually, I could rely on the MSBuild hooks and use
+// testApplicationBuilder.AddSelfRegisteredExtensions(args);
+// This is what is called by the generated entry point
+
+// In addition to be using each extension helper method, we can directly register extensions to each of
+// the extensibility area. For now, the following 3 are exposed:
+// testApplicationBuilder.CommandLine
+// testApplicationBuilder.TestHost
+// testApplicationBuilder.TestHostControllers
+// but the goal is to also expose all these areas: https://github.com/microsoft/testfx/blob/main/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs#L57-L69
+
+// NOTE that registering an extension is not enough and each extension has some activation criteria,
+// most of the time the presence of a command line option but it could be anything (including nothing).
+
+// Build the test app
+using ITestApplication testApplication = await testApplicationBuilder.BuildAsync();
+
+// Run the test app
+return await testApplication.RunAsync();
diff --git a/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/Test1.cs b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/Test1.cs
new file mode 100644
index 0000000000..21f9186303
--- /dev/null
+++ b/samples/public/mstest-runner/MSTestProjectWithExplicitMain/MSTestProjectWithExplicitMain/Test1.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace MSTestProjectWithExplicitMain;
+
+[TestClass]
+public sealed class Test1
+{
+ [TestMethod]
+ public void TestMethod1()
+ {
+ }
+}
diff --git a/src/Adapter/MSTest.TestAdapter/BannedSymbols.txt b/src/Adapter/MSTest.TestAdapter/BannedSymbols.txt
index 91178cbc64..31a6272126 100644
--- a/src/Adapter/MSTest.TestAdapter/BannedSymbols.txt
+++ b/src/Adapter/MSTest.TestAdapter/BannedSymbols.txt
@@ -1 +1,2 @@
M:Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers.ReflectHelper.#ctor; This is allowed only for tests.
+N:Microsoft.Testing.Platform
diff --git a/src/Adapter/MSTest.TestAdapter/Constants.cs b/src/Adapter/MSTest.TestAdapter/Constants.cs
index 057ebb6bfa..569d49159b 100644
--- a/src/Adapter/MSTest.TestAdapter/Constants.cs
+++ b/src/Adapter/MSTest.TestAdapter/Constants.cs
@@ -10,6 +10,8 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
///
internal static class Constants
{
+ internal const string PublicTypeObsoleteMessage = "We will remove or hide this type starting with v4. If you are using this type, reach out to our team on https://github.com/microsoft/testfx.";
+
///
/// The 3rd level entry (class) name in the hierarchy array.
///
@@ -121,6 +123,8 @@ internal static class Constants
internal static readonly TestProperty TestDynamicDataProperty = TestProperty.Register("MSTest.DynamicData", "DynamicData", typeof(string[]), TestPropertyAttributes.Hidden, typeof(TestCase));
internal static readonly TestProperty TestIdGenerationStrategyProperty = TestProperty.Register("MSTest.TestIdGenerationStrategy", "TestIdGenerationStrategy", typeof(int), TestPropertyAttributes.Hidden, typeof(TestCase));
+
+ internal static readonly TestProperty TestDataSourceIgnoreMessageProperty = TestProperty.Register("MSTest.TestDataSourceIgnoreMessageProperty", "TestDataSourceIgnoreMessageProperty", typeof(string), TestPropertyAttributes.Hidden, typeof(TestCase));
#endregion
#region Private Constants
diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs
index 711bda3b0e..74654b6bca 100644
--- a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs
+++ b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs
@@ -1,12 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Reflection;
using System.Runtime.Serialization;
using System.Security;
-using System.Text;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
@@ -20,6 +16,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery;
///
/// Enumerates through all types in the assembly in search of valid test methods.
///
+[SuppressMessage("Performance", "CA1852: Seal internal types", Justification = "Overrides required for testability")]
internal class AssemblyEnumerator : MarshalByRefObject
{
///
@@ -49,11 +46,6 @@ public AssemblyEnumerator(MSTestSettings settings) =>
// 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.
- ///
- public string? RunSettingsXml { get; set; }
-
///
/// Returns object to be used for controlling lifetime, null means infinite lifetime.
///
@@ -70,19 +62,22 @@ public AssemblyEnumerator(MSTestSettings settings) =>
/// Enumerates through all types in the assembly in search of valid test methods.
///
/// The assembly file name.
+ /// The xml specifying runsettings.
/// Contains warnings if any, that need to be passed back to the caller.
/// A collection of Test Elements.
- internal ICollection EnumerateAssembly(string assemblyFileName, out ICollection warnings)
+ internal ICollection EnumerateAssembly(
+ string assemblyFileName,
+ [StringSyntax(StringSyntaxAttribute.Xml, nameof(runSettingsXml))] string? runSettingsXml,
+ List 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);
- IReadOnlyList types = GetTypes(assembly, assemblyFileName, warningMessages);
+ Type[] types = GetTypes(assembly, assemblyFileName, warnings);
bool discoverInternals = ReflectHelper.GetDiscoverInternalsAttribute(assembly) != null;
TestIdGenerationStrategy testIdGenerationStrategy = ReflectHelper.GetTestIdGenerationStrategy(assembly);
@@ -91,15 +86,28 @@ internal ICollection EnumerateAssembly(string assemblyFileName,
DataRowAttribute.TestIdGenerationStrategy = testIdGenerationStrategy;
DynamicDataAttribute.TestIdGenerationStrategy = testIdGenerationStrategy;
- TestDataSourceDiscoveryOption testDataSourceDiscovery = ReflectHelper.GetTestDataSourceDiscoveryOption(assembly)
+ TestDataSourceUnfoldingStrategy dataSourcesUnfoldingStrategy = ReflectHelper.GetTestDataSourceOptions(assembly)?.UnfoldingStrategy switch
+ {
+ // When strategy is auto we want to unfold
+ TestDataSourceUnfoldingStrategy.Auto => TestDataSourceUnfoldingStrategy.Unfold,
+ // When strategy is set, let's use it
+ { } value => value,
+ // When the attribute is not set, let's look at the legacy attribute
+#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
-
- // When using legacy strategy, there is no point in trying to "read" data during discovery
- // as the ID generator will ignore it.
- ?? (testIdGenerationStrategy == TestIdGenerationStrategy.Legacy
- ? TestDataSourceDiscoveryOption.DuringExecution
- : TestDataSourceDiscoveryOption.DuringDiscovery);
+ null => (ReflectHelper.GetTestDataSourceDiscoveryOption(assembly), testIdGenerationStrategy) switch
+#pragma warning restore CS0612 // Type or member is obsolete
+ {
+ (TestDataSourceDiscoveryOption.DuringExecution, _) => TestDataSourceUnfoldingStrategy.Fold,
+ // When using legacy strategy, there is no point in trying to "read" data during discovery
+ // as the ID generator will ignore it.
+ (null, TestIdGenerationStrategy.Legacy) => TestDataSourceUnfoldingStrategy.Fold,
#pragma warning restore CS0618 // Type or member is obsolete
+ _ => TestDataSourceUnfoldingStrategy.Unfold,
+ },
+ };
+
+ Dictionary? testRunParametersFromRunSettings = RunSettingsUtilities.GetTestRunParameters(runSettingsXml);
foreach (Type type in types)
{
if (type == null)
@@ -107,12 +115,11 @@ internal ICollection EnumerateAssembly(string assemblyFileName,
continue;
}
- List testsInType = DiscoverTestsInType(assemblyFileName, RunSettingsXml, type, warningMessages, discoverInternals,
- testDataSourceDiscovery, testIdGenerationStrategy, fixturesTests);
+ List testsInType = DiscoverTestsInType(assemblyFileName, testRunParametersFromRunSettings, type, warnings, discoverInternals,
+ dataSourcesUnfoldingStrategy, testIdGenerationStrategy, fixturesTests);
tests.AddRange(testsInType);
}
- warnings = warningMessages;
return tests;
}
@@ -192,29 +199,28 @@ 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, TestDataSourceDiscoveryOption discoveryOption, TestIdGenerationStrategy testIdGenerationStrategy)
+ internal virtual TypeEnumerator GetTypeEnumerator(Type type, string assemblyFileName, bool discoverInternals, TestIdGenerationStrategy testIdGenerationStrategy)
{
var typeValidator = new TypeValidator(ReflectHelper, discoverInternals);
var testMethodValidator = new TestMethodValidator(ReflectHelper, discoverInternals);
- return new TypeEnumerator(type, assemblyFileName, ReflectHelper, typeValidator, testMethodValidator, discoveryOption, testIdGenerationStrategy);
+ return new TypeEnumerator(type, assemblyFileName, ReflectHelper, typeValidator, testMethodValidator, testIdGenerationStrategy);
}
private List DiscoverTestsInType(
string assemblyFileName,
- [StringSyntax(StringSyntaxAttribute.Xml, nameof(runSettingsXml))] string? runSettingsXml,
+ Dictionary? testRunParametersFromRunSettings,
Type type,
List warningMessages,
bool discoverInternals,
- TestDataSourceDiscoveryOption discoveryOption,
+ TestDataSourceUnfoldingStrategy dataSourcesUnfoldingStrategy,
TestIdGenerationStrategy testIdGenerationStrategy,
HashSet fixturesTests)
{
IDictionary tempSourceLevelParameters = PlatformServiceProvider.Instance.SettingsProvider.GetProperties(assemblyFileName);
- tempSourceLevelParameters = RunSettingsUtilities.GetTestRunParameters(runSettingsXml)?.ConcatWithOverwrites(tempSourceLevelParameters)
+ tempSourceLevelParameters = testRunParametersFromRunSettings?.ConcatWithOverwrites(tempSourceLevelParameters)
?? tempSourceLevelParameters
?? new Dictionary();
var sourceLevelParameters = tempSourceLevelParameters.ToDictionary(x => x.Key, x => (object?)x.Value);
@@ -225,25 +231,22 @@ private List DiscoverTestsInType(
try
{
typeFullName = type.FullName;
- TypeEnumerator testTypeEnumerator = GetTypeEnumerator(type, assemblyFileName, discoverInternals, discoveryOption, testIdGenerationStrategy);
- ICollection? unitTestCases = testTypeEnumerator.Enumerate(out ICollection warningsFromTypeEnumerator);
- warningMessages.AddRange(warningsFromTypeEnumerator);
+ TypeEnumerator testTypeEnumerator = GetTypeEnumerator(type, assemblyFileName, discoverInternals, testIdGenerationStrategy);
+ List? unitTestCases = testTypeEnumerator.Enumerate(warningMessages);
if (unitTestCases != null)
{
foreach (UnitTestElement test in unitTestCases)
{
- if (discoveryOption == TestDataSourceDiscoveryOption.DuringDiscovery)
+ if (_typeCache.GetTestMethodInfoForDiscovery(test.TestMethod) is { } testMethodInfo)
{
- Lazy testMethodInfo = GetTestMethodInfo(sourceLevelParameters, test);
-
// Add fixture tests like AssemblyInitialize, AssemblyCleanup, ClassInitialize, ClassCleanup.
- if (MSTestSettings.CurrentSettings.ConsiderFixturesAsSpecialTests && testMethodInfo.Value is not null)
+ if (MSTestSettings.CurrentSettings.ConsiderFixturesAsSpecialTests)
{
- AddFixtureTests(testMethodInfo.Value, tests, fixturesTests);
+ AddFixtureTests(testMethodInfo, tests, fixturesTests);
}
- if (DynamicDataAttached(test, testMethodInfo, tests))
+ if (TryUnfoldITestDataSources(test, testMethodInfo, dataSourcesUnfoldingStrategy, tests))
{
continue;
}
@@ -265,51 +268,10 @@ private List DiscoverTestsInType(
return 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.
- if (!test.TestMethod.HasManagedMethodAndTypeProperties)
- {
- return false;
- }
-
- DynamicDataType originalDataType = test.TestMethod.DataType;
-
- // 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;
-
- // The data source tests that we can process currently are those using attributes that
- // implement ITestDataSource (i.e, DataRow and DynamicData attributes).
- // However, for DataSourceAttribute, we currently don't have anyway to process it during discovery.
- // (Note: this method is only called under discoveryOption == TestDataSourceDiscoveryOption.DuringDiscovery)
- // So we want to return false from this method for non ITestDataSource (whether it's None or DataSourceAttribute). Otherwise, the test
- // will be completely skipped which is wrong behavior.
- return originalDataType == DynamicDataType.ITestDataSource &&
- testMethodInfo.Value != null &&
- TryProcessITestDataSourceTests(test, testMethodInfo.Value, tests);
- }
-
private static void AddFixtureTests(TestMethodInfo testMethodInfo, List tests, HashSet fixtureTests)
{
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.
@@ -320,13 +282,13 @@ private static void AddFixtureTests(TestMethodInfo testMethodInfo, List tests)
+ private static bool TryUnfoldITestDataSources(UnitTestElement test, TestMethodInfo testMethodInfo, TestDataSourceUnfoldingStrategy dataSourcesUnfoldingStrategy, 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.
+ if (!test.TestMethod.HasManagedMethodAndTypeProperties)
+ {
+ return false;
+ }
+
// We don't have a special method to filter attributes that are not derived from Attribute, so we take all
// attributes and filter them. We don't have to care if there is one, because this method is only entered when
// there is at least one (we determine this in TypeEnumerator.GetTestFromMethod.
IEnumerable testDataSources = ReflectHelper.Instance.GetDerivedAttributes(testMethodInfo.MethodInfo, inherit: false).OfType();
+ // We need to use a temporary list to avoid adding tests to the main list if we fail to expand any data source.
+ List tempListOfTests = new();
+
try
{
- return ProcessITestDataSourceTests(test, new(testMethodInfo.MethodInfo, test.DisplayName), testDataSources, tests);
+ bool isDataDriven = false;
+ foreach (ITestDataSource dataSource in testDataSources)
+ {
+ isDataDriven = true;
+ if (!TryUnfoldITestDataSource(dataSource, dataSourcesUnfoldingStrategy, test, new(testMethodInfo.MethodInfo, test.DisplayName), tempListOfTests))
+ {
+ // TODO: Improve multi-source design!
+ // Ideally we would want to consider each data source separately but when one source cannot be expanded,
+ // we will run all sources from the given method so we need to bail-out "globally".
+ return false;
+ }
+ }
+
+ if (tempListOfTests.Count > 0)
+ {
+ tests.AddRange(tempListOfTests);
+ }
+
+ return isDataDriven;
}
catch (Exception ex)
{
string message = string.Format(CultureInfo.CurrentCulture, Resource.CannotEnumerateIDataSourceAttribute, test.TestMethod.ManagedTypeName, test.TestMethod.ManagedMethodName, ex);
PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo($"DynamicDataEnumerator: {message}");
+
+ if (tempListOfTests.Count > 0)
+ {
+ tests.AddRange(tempListOfTests);
+ }
+
return false;
}
}
- private static bool ProcessITestDataSourceTests(UnitTestElement test, ReflectionTestMethodInfo methodInfo, IEnumerable testDataSources,
- List tests)
+ private static bool TryUnfoldITestDataSource(ITestDataSource dataSource, TestDataSourceUnfoldingStrategy dataSourcesUnfoldingStrategy, UnitTestElement test, ReflectionTestMethodInfo methodInfo, List tests)
{
- foreach (ITestDataSource dataSource in testDataSources)
+ var unfoldingCapability = dataSource as ITestDataSourceUnfoldingCapability;
+
+ // If the global strategy is to fold and local has no strategy or uses Auto then return false
+ if (dataSourcesUnfoldingStrategy == TestDataSourceUnfoldingStrategy.Fold
+ && (unfoldingCapability is null || unfoldingCapability.UnfoldingStrategy == TestDataSourceUnfoldingStrategy.Auto))
{
- IEnumerable
Byly zjiÅ¡tÄ›ny soubory .runsettings i .testconfig.json. Vyberte prosÃm jenom jeden z tÄ›chto souborů konfigurace testu.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- Odkazovaný Älen [DynamicData] {0}.{1} by mÄ›l vracet IEnumerable<object[]>, IEnumerable<Tuple> nebo IEnumerable<ValueTuple>.
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ Dynamický zdroj dat '{0}' v typu '{1}' by měl existovat a být vlastnostà nebo metodou.
- Test '{0}' exceeded execution timeout period.
- Test {0} pÅ™ekroÄil Äasový limit spuÅ¡tÄ›nÃ.
-
+ Test '{0}' timed out after {1}ms
+ Časový limit '{0}' testu vypršel po {1}ms.
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ Typ obecného parametru '{0}' nelze odvodit.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ Obecná testovacà metoda '{0}' nemá argumenty, takže obecný parametr nelze odvodit.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ Byly nalezeny dva konfliktnà typy pro obecný parametr '{0}'. Konfliktnà typy jsou '{1}' a '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
Chyba: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: Obecná metoda nemůže být testovacà metodou. {0}.{1} má neplatný podpis.
-
-
File does not exist: {0}
NeexistujÃcà soubor: {0}
@@ -408,9 +418,9 @@ Chyba: {1}
- Test '{0}' execution has been aborted.
- Spouštěnà testu {0} se přerušilo.
-
+ Test '{0}' was canceled
+ Testovacà '{0}' se zrušila.
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Chyba: {1}
Vyvolané výjimky:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- NepodaÅ™ilo se zÃskat mezipaměť atributů. Ignoruje se dÄ›diÄnost atributů a spadánà do „type defines Attribute model“, abychom zÃskali urÄitá data.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
ZÃskánà vlastnÃch atributů pro typ {0} vyvolalo výjimku (bude ignorovat a použÃvat způsob reflexe): {1}
@@ -456,11 +461,6 @@ Chyba: {1}
Volaný kód vyvolal výjimku, která byla zachycena, ale jejà hodnota byla null.
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- V sestavenà je naÄtena staršà verze balÃÄku MSTestV2. Metody ÄiÅ¡tÄ›nà testů se nemusà spustit oÄekávaným způsobem. UjistÄ›te se prosÃm, že vÅ¡echny vaÅ¡e testovacà projekty odkazujà na balÃÄky MSTest novÄ›jšà než verze 2.2.8.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
Došlo k výjimce při rozbalovánà řádků IDataSource z atributu na „{0}.{1}“: {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.de.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.de.xlf
index 43c7aec3be..4f563a2f9d 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.de.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.de.xlf
@@ -61,15 +61,30 @@ aber empfing {4} Argument(e) mit den Typen „{5}“.
Es wurden sowohl die Dateien „.runsettings“ als auch „.testconfig.json“ erkannt. Wählen Sie nur eine dieser Testkonfigurationsdateien aus.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- "[DynamicData]"-Element "{0}.{1}" muss "IEnumerable"<"object[]>", "IEnumerable<Tuple>" oder "IEnumerable<ValueTuple>" zurückgeben.
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ Die dynamische Datenquelle '{0}' im Typ '{1}' muss vorhanden sein und eine Eigenschaft oder Methode sein.
- Test '{0}' exceeded execution timeout period.
- Der Test "{0}" hat das Ausführungstimeout überschritten.
-
+ Test '{0}' timed out after {1}ms
+ Timeout bei test '{0}' nach {1}ms.
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ Der Typ des generischen Parameters '{0}' konnte nicht abgeleitet werden.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ Die generische Testmethode '{0}' hat keine Argumente, daher kann der generische Parameter nicht abgeleitet werden.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ Es wurden zwei in Konflikt stehende Typen für den generischen Parameter '{0}' gefunden. Die in Konflikt stehenden Typen sind '{1}' und '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
Fehler: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: Eine generische Methode kann keine Testmethode sein. '{0}.{1}' weist eine ungültige Signatur auf.
-
-
File does not exist: {0}
Die Datei ist nicht vorhanden: {0}
@@ -408,9 +418,9 @@ Fehler: {1}
- Test '{0}' execution has been aborted.
- Die Ausführung des Tests "{0}" wurde abgebrochen.
-
+ Test '{0}' was canceled
+ Test '{0}' wurde abgebrochen.
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Fehler: {1}
Ausgelöste Ausnahmen:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- Fehler beim Abrufen des Attributcaches. Die Attributvererbung wird ignoriert und fällt in "type defines Attribute model", sodass einige Daten vorhanden sind.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
Beim Abrufen von benutzerdefinierten Attributen für den Typ {0} wurde Ausnahme ausgelöst (wird ignoriert und die Reflektionsart verwendet): {1}
@@ -456,11 +461,6 @@ Fehler: {1}
Der aufgerufene Code hat eine Ausnahme ausgelöst, die abgefangen wurde, aber der Ausnahmewert war NULL.
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- Eine ältere Version des MSTestV2-Pakets wird in die Assembly geladen. Testbereinigungsmethoden werden möglicherweise nicht wie erwartet ausgeführt. Stellen Sie sicher, dass alle Testprojekte auf MSTest-Pakete verweisen, die neuer als Version 2.2.8 sind.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
Ausnahme beim Erweitern von IDataSource-Zeilen aus dem Attribut auf "{0}.{1}": {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.es.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.es.xlf
index 31d9b13040..a7665e8fe1 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.es.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.es.xlf
@@ -61,15 +61,30 @@ pero recibió {4} argumento(s), con los tipos "{5}".
Se han detectado los archivos ".runsettings" y ".testconfig.json". Seleccione solo uno de estos archivos de configuración de prueba.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- El miembro ''{0}.{1}'' de '[DynamicData]' al que se hace referencia debe devolver ''IEnumerable<object[]>', 'IEnumerable<Tuple>'' o ''IEnumerable<ValueTuple>''
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ El origen de datos dinámico '{0}' en el tipo '{1}' debe existir y ser una propiedad o un método.
- Test '{0}' exceeded execution timeout period.
- La prueba '{0}' superó el tiempo de espera de ejecución.
-
+ Test '{0}' timed out after {1}ms
+ Se agotó el tiempo de espera de la '{0}' de pruebas después de {1}ms
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ No se pudo inferir el tipo del parámetro genérico '{0}'.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ El método de prueba genérico '{0}' no tiene argumentos, por lo que no se puede inferir el parámetro genérico.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ Se encontraron dos tipos en conflicto para el parámetro genérico '{0}'. Los tipos en conflicto son '{1}' y '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
Error: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: Un método genérico no puede ser un método de prueba. {0}.{1} tiene una firma no válida
-
-
File does not exist: {0}
El archivo no existe: {0}
@@ -408,9 +418,9 @@ Error: {1}
- Test '{0}' execution has been aborted.
- Se anuló la ejecución de la prueba "{0}".
-
+ Test '{0}' was canceled
+ Se canceló la '{0}' de pruebas
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Error: {1}
Excepciones devueltas:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- No se pudo obtener la memoria caché de atributos. Se omitirá la herencia del atributo y se entrará en "type define Attribute model", de modo que tengamos algunos datos.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
Al obtener atributos personalizados para el tipo {0} se produjo una excepción (se omitirá y se usará la forma de reflexión): {1}
@@ -456,11 +461,6 @@ Error: {1}
El código llamado produjo una excepción que se detectó, pero el valor de la excepción era null
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- Hay una versión anterior del paquete MSTestV2 cargada en el ensamblado. Es posible que los métodos de limpieza de pruebas no se ejecuten según lo esperado. Asegúrese de que todos los proyectos de prueba hacen referencia a paquetes MSTest más recientes que la versión 2.2.8.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
Se produjo una excepción al expandir las filas de IDataSource del atributo en "{0}.{1}": {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.fr.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.fr.xlf
index d6ea39b5be..908df3801d 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.fr.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.fr.xlf
@@ -61,15 +61,30 @@ mais a reçu {4} argument(s), avec les types « {5} ».
Les fichiers « .runsettings » et « .testconfig.json » ont été détectés. Veuillez sélectionner un seul de ces fichiers de configuration de test.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- Le membre référencé « [DynamicData] '{0}.{1}' doit renvoyer « IEnumerable<object[]> », « IEnumerable<Tuple> » ou « IEnumerable<ValueTuple> »
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ La source de données dynamique '{0}' dans le type '{1}' doit exister et être une propriété ou une méthode.
- Test '{0}' exceeded execution timeout period.
- Le test '{0}' a dépassé le délai d'attente de l'exécution.
-
+ Test '{0}' timed out after {1}ms
+ Délai de '{0}' de test dépassé après {1}ms
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ Impossible de déduire le type du paramètre générique '{0}'.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ La méthode de test générique '{0}' n’a pas d’arguments. Le paramètre générique ne peut donc pas être déduit.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ Deux types en conflit ont été trouvés pour le paramètre générique '{0}'. Les types en conflit sont '{1}' et '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
Erreur : {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015 : une méthode générique ne peut pas être une méthode de test. {0}.{1} a une signature non valide
-
-
File does not exist: {0}
Fichier inexistant : {0}
@@ -408,9 +418,9 @@ Erreur : {1}
- Test '{0}' execution has been aborted.
- L'exécution du test '{0}' a été abandonnée.
-
+ Test '{0}' was canceled
+ Le test '{0}' a été annulé
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Erreur : {1}
Exceptions levées/s :
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- Échec de l’obtention du cache d’attributs. Héritage d’attribut ignoré et retour à 'type defines Attribute model' pour que nous ayons des données.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
L’obtention d’attributs personnalisés pour le type {0} a levé une exception (ignorera et utilisera la méthode de réflexion) : {1}
@@ -456,11 +461,6 @@ Erreur : {1}
Le code appelé a levé une exception qui a été interceptée, mais la valeur de l’exception était nul
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- Une version antérieure du package MSTestV2 est chargée dans l’assembly. Les méthodes de nettoyage de test risquent de ne pas s’exécuter comme prévu. Vérifiez que tous vos projets de test référencent des packages MSTest plus récent que la version 2.2.8.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
Une exception s’est produite lors du développement des lignes IDataSource à partir de l’attribut sur « {0}.{1} » : {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.it.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.it.xlf
index f46eb424a9..4bbe3658f6 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.it.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.it.xlf
@@ -61,15 +61,30 @@ ma ha ricevuto {4} argomenti, con tipi "{5}".
Sono stati rilevati sia i file '.runsettings' sia '.testconfig.json'. Selezionare solo uno di questi file di configurazione di test.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- '[DynamicData]' membro di riferimento '{0}.{1}' deve restituire 'IEnumerable<object[]>', 'IEnumerable<Tuple>' o 'IEnumerable<ValueTuple>'
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ L'origine dati dinamica '{0}' nel tipo '{1}' deve esistere ed essere una proprietà o un metodo.
- Test '{0}' exceeded execution timeout period.
- È stato superato il periodo di timeout per l'esecuzione del test '{0}'.
-
+ Test '{0}' timed out after {1}ms
+ Timeout del '{0}' di test dopo {1}ms
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ Impossibile dedurre il tipo del parametro generico '{0}'.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ Il metodo di test generico '{0}' non contiene argomenti, di conseguenza non è possibile dedurre il parametro generico.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ Sono stati trovati due tipi in conflitto per il parametro generico '{0}'. I tipi in conflitto sono '{1}' e '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
Errore: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: un metodo generico non può essere un metodo di test. La firma di {0}.{1} non è valida
-
-
File does not exist: {0}
Il file {0} non esiste
@@ -408,9 +418,9 @@ Errore: {1}
- Test '{0}' execution has been aborted.
- L'esecuzione del test '{0}' è stata interrotta.
-
+ Test '{0}' was canceled
+ Il '{0}' di test è stato annullato
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Errore: {1}
Eccezioni generate:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- Non è stato possibile ottenere la cache degli attributi. L'ereditarietà dell'attributo verrà ignorata e verrà considerato 'il tipo definisce il modello di attributo', in modo che siano disponibili alcuni dati.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
Il recupero degli attributi personalizzati per il tipo {0} ha generato un'eccezione (verrà ignorata e verrà usata la modalità reflection): {1}
@@ -456,11 +461,6 @@ Errore: {1}
Il codice chiamato ha generato un'eccezione che è stata rilevata, ma il valore dell'eccezione è Null
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- Nell'assembly è caricata una versione precedente del pacchetto MSTestV2. I metodi di pulizia dei test potrebbero non essere eseguiti come previsto. Assicurarsi che tutti i progetti di test facciano riferimento a pacchetti MSTest più recenti della versione 2.2.8.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
Si è verificata un'eccezione durante l'espansione delle righe IDataSource dall'attributo in "{0}.{1}": {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ja.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ja.xlf
index fcf792a564..f33a668f43 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ja.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ja.xlf
@@ -62,15 +62,30 @@ but received {4} argument(s), with types '{5}'.
'.runsettings' ファイル㨠'.testconfig.json' ファイルã®ä¸¡æ–¹ãŒæ¤œå‡ºã•れã¾ã—ãŸã€‚ã“れらã®ãƒ†ã‚¹ãƒˆæ§‹æˆãƒ•ァイルã®ã„ãšã‚Œã‹ 1 ã¤ã ã‘ã‚’é¸æŠžã—ã¦ãã ã•ã„。
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- '[DynamicData]' ã®å‚ç…§ã•れるメンãƒãƒ¼ '{0}.{1}' ã¯ã€'IEnumerable<object[]>'ã€'IEnumerable<Tuple>`ã€'IEnumerable<ValueTuple>' ã®ã„ãšã‚Œã‹ã‚’è¿”ã™å¿…è¦ãŒã‚りã¾ã™
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ åž‹ '{1}' ã®å‹•的データ ソース '{0}' ã¯ã€ãƒ—ãƒãƒ‘ティã¾ãŸã¯ãƒ¡ã‚½ãƒƒãƒ‰ã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚
- Test '{0}' exceeded execution timeout period.
- テスト '{0}' ã¯å®Ÿè¡Œã‚¿ã‚¤ãƒ アウトを超ãˆã¾ã—ãŸã€‚
-
+ Test '{0}' timed out after {1}ms
+ テスト '{0}' ㌠{1}ミリ秒後ã«ã‚¿ã‚¤ãƒ アウトã—ã¾ã—ãŸ
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ ジェãƒãƒªãƒƒã‚¯ パラメーター '{0}' ã®åž‹ã‚’推論ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ '{0}' ジェãƒãƒªãƒƒã‚¯ テスト メソッドã«å¼•æ•°ãŒãªã„ãŸã‚ã€ã‚¸ã‚§ãƒãƒªãƒƒã‚¯ パラメーターを推論ã§ãã¾ã›ã‚“。
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ ジェãƒãƒªãƒƒã‚¯ パラメーター '{0}' ã« 2 ã¤ã®ç«¶åˆã™ã‚‹åž‹ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸã€‚ç«¶åˆã™ã‚‹åž‹ã¯ '{1}' ã§ '{2}'。
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -204,11 +219,6 @@ Error: {1}
エラー: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: ジェãƒãƒªãƒƒã‚¯ メソッドãŒãƒ†ã‚¹ãƒˆ メソッドã«ãªã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。{0}.{1} ã®ã‚·ã‚°ãƒãƒãƒ£ã¯ç„¡åйã§ã™
-
-
File does not exist: {0}
ファイルãŒå˜åœ¨ã—ã¾ã›ã‚“: {0}
@@ -409,9 +419,9 @@ Error: {1}
- Test '{0}' execution has been aborted.
- テスト '{0}' ã®å®Ÿè¡ŒãŒä¸æ¢ã•れã¾ã—ãŸã€‚
-
+ Test '{0}' was canceled
+ テスト '{0}' ãŒå–り消ã•れã¾ã—ãŸ
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -436,11 +446,6 @@ Error: {1}
スãƒãƒ¼ã•れãŸä¾‹å¤–:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- 属性ã‚ャッシュをå–å¾—ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚属性ã®ç¶™æ‰¿ã‚’無視ã™ã‚‹ã¨ã€'type defines Attribute model' ã«åˆ†é¡žã•れるãŸã‚ã€ã„ãã¤ã‹ã®ãƒ‡ãƒ¼ã‚¿ãŒã‚るよã†ã«ãªã‚Šã¾ã™ã€‚
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
åž‹ {0} ã®ã‚«ã‚¹ã‚¿ãƒ 属性をå–å¾—ä¸ã«ä¾‹å¤–ãŒã‚¹ãƒãƒ¼ã•れã¾ã—㟠(無視ã—ã¦ãƒªãƒ•ãƒ¬ã‚¯ã‚·ãƒ§ãƒ³ã®æ–¹æ³•を使用ã—ã¾ã™): {1}
@@ -457,11 +462,6 @@ Error: {1}
呼ã³å‡ºã•れãŸã‚³ãƒ¼ãƒ‰ã¯ã‚ャッãƒã•れãŸä¾‹å¤–をスãƒãƒ¼ã—ã¾ã—ãŸãŒã€ä¾‹å¤–値㌠null ã§ã—ãŸ
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- å¤ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã® MSTestV2 パッケージãŒã‚¢ã‚»ãƒ³ãƒ–リã«èªã¿è¾¼ã¾ã‚Œã¦ã„ã¾ã™ã€‚テスト クリーンアップ ãƒ¡ã‚½ãƒƒãƒ‰ãŒæ£ã—ã実行ã•れãªã„å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ã™ã¹ã¦ã®ãƒ†ã‚¹ãƒˆ プãƒã‚¸ã‚§ã‚¯ãƒˆãŒã€ãƒãƒ¼ã‚¸ãƒ§ãƒ³ 2.2.8 より新ã—ã„ MSTest パッケージをå‚ç…§ã—ã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
"{0}.{1}" ã®å±žæ€§ã‹ã‚‰ IDataSource 行を展開ä¸ã«ä¾‹å¤–ãŒç™ºç”Ÿã—ã¾ã—ãŸ: {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ko.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ko.xlf
index 47f6282d7a..83f037d230 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ko.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ko.xlf
@@ -61,15 +61,30 @@ but received {4} argument(s), with types '{5}'.
'.runsettings' ë° '.testconfig.json' 파ì¼ì´ ëª¨ë‘ ê²€ìƒ‰ë˜ì—ˆìŠµë‹ˆë‹¤. ì´ëŸ¬í•œ 테스트 구성 íŒŒì¼ ì¤‘ 하나만 ì„ íƒí•˜ì„¸ìš”.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- '[DynamicData]'ì´(ê°€) '{0} 멤버를 참조했습니다.{1}'ì€(는) 'IEnumerable<object[]>', 'IEnumerable<Tuple>' ë˜ëŠ” 'IEnumerable<ValueTuple>'ì„ ë°˜í™˜í•´ì•¼ 합니다.
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ '{1}' 형ì‹ì˜ ë™ì ë°ì´í„° ì›ë³¸ '{0}' 존재하며 ì†ì„± ë˜ëŠ” 메서드여야 합니다.
- Test '{0}' exceeded execution timeout period.
- '{0}' 테스트가 실행 시간 ì œí•œì„ ì´ˆê³¼í–ˆìŠµë‹ˆë‹¤.
-
+ Test '{0}' timed out after {1}ms
+ 테스트 '{0}' {1}밀리초 í›„ì— ì‹œê°„ 초과ë˜ì—ˆìŠµë‹ˆë‹¤.
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ ì œë„¤ë¦ ë§¤ê°œ 변수 '{0}' 형ì‹ì„ ìœ ì¶”í• ìˆ˜ 없습니다.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ ì œë„¤ë¦ í…ŒìŠ¤íŠ¸ 메서드 '{0}' ì¸ìˆ˜ê°€ 없으므로 ì œë„¤ë¦ ë§¤ê°œ 변수를 ìœ ì¶”í• ìˆ˜ 없습니다.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ ì œë„¤ë¦ ë§¤ê°œ 변수 '{0}' ì¶©ëŒí•˜ëŠ” ë‘ ê°€ì§€ 형ì‹ì„ 찾았습니다. ì¶©ëŒí•˜ëŠ” 형ì‹ì€ '{1}' '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
오류: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: ì œë„¤ë¦ ë©”ì„œë“œëŠ” 테스트 ë©”ì„œë“œì¼ ìˆ˜ 없습니다. {0}.{1}ì— ìž˜ëª»ëœ ì„œëª…ì´ ìžˆìŠµë‹ˆë‹¤.
-
-
File does not exist: {0}
파ì¼ì´ 없습니다. {0}
@@ -408,9 +418,9 @@ Error: {1}
- Test '{0}' execution has been aborted.
- 테스트 '{0}' ì‹¤í–‰ì´ ì¤‘ë‹¨ë˜ì—ˆìŠµë‹ˆë‹¤.
-
+ Test '{0}' was canceled
+ 테스트 '{0}' 취소ë˜ì—ˆìŠµë‹ˆë‹¤.
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Error: {1}
예외 ë°œìƒ:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- 특성 ìºì‹œë¥¼ ê°€ì ¸ì˜¤ì§€ 못했습니다. ì¼ë¶€ ë°ì´í„°ê°€ 있ë„ë¡ íŠ¹ì„± ìƒì†ì„ ë¬´ì‹œí•˜ê³ 'type defines Attribute model'로 바꿉니다.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
{0} 형ì‹ì— 대한 ì‚¬ìš©ìž ì§€ì • íŠ¹ì„±ì„ ê°€ì ¸ì˜¤ëŠ” ë° ì˜ˆì™¸ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤(ë¬´ì‹œí•˜ê³ ë¦¬í”Œë ‰ì…˜ 방법 사용). {1}
@@ -456,11 +461,6 @@ Error: {1}
í˜¸ì¶œëœ ì½”ë“œì—서 확ì¸ëœ 예외가 ë°œìƒí–ˆì§€ë§Œ 예외 ê°’ì´ null입니다.
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- ì´ì „ ë²„ì „ MSTestV2 패키지가 ì–´ì…ˆë¸”ë¦¬ì— ë¡œë“œë˜ì–´ 테스트 ì •ë¦¬ 메서드가 예ìƒëŒ€ë¡œ 실행ë˜ì§€ ì•Šì„ ìˆ˜ 있습니다. ëª¨ë“ í…ŒìŠ¤íŠ¸ 프로ì 트가 2.2.8 ì´í›„ ë²„ì „ MSTest 패키지를 참조하는지 확ì¸í•˜ì„¸ìš”.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
"{0}.{1}"ì˜ íŠ¹ì„±ì—서 IDataSource í–‰ì„ í™•ìž¥í•˜ëŠ” ë™ì•ˆ 예외가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pl.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pl.xlf
index 8acb03e878..4889dce291 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pl.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pl.xlf
@@ -61,15 +61,30 @@ ale liczba odebranych argumentów to {4} z typami „{5}â€.
Wykryto zarówno pliki „.runsettingsâ€, jak i „.testconfig.jsonâ€. Wybierz tylko jeden z tych plików konfiguracji testu.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- PrzywoÅ‚any element czÅ‚onkowski „{0}.{1}†„[DynamicData]†powinien zwrócić „IEnumerable<object[]>â€, „IEnumerable<Tuple>†lub „IEnumerable<ValueTuple>â€
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ Dynamiczne źródło danych '{0}' w typie '{1}' powinno istnieć i być właściwością lub metodą.
- Test '{0}' exceeded execution timeout period.
- Test „{0}†przekroczył okres limitu czasu na wykonanie.
-
+ Test '{0}' timed out after {1}ms
+ Upłynął limit czasu '{0}' testu po {1}ms
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ Nie można wywnioskować typu '{0}' parametru ogólnego.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ Ogólna metoda testowa '{0}' nie ma argumentów, więc nie można wywnioskować parametru ogólnego.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ Znaleziono dwa typy powodujące konflikt dla parametru ogólnego '{0}'. Typy powodujące konflikty są '{1}' i '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
Błąd: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: Metoda ogólna nie może być metodą testową. {0}{1} ma nieprawidłową sygnaturę
-
-
File does not exist: {0}
Plik nie istnieje: {0}
@@ -408,9 +418,9 @@ Błąd: {1}
- Test '{0}' execution has been aborted.
- Wykonanie testu „{0}†zostało przerwane.
-
+ Test '{0}' was canceled
+ Anulowano '{0}' testowe
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Błąd: {1}
Zgłoszone wyjątki:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- Nie można pobrać pamiÄ™ci podrÄ™cznej atrybutów. Ignorowanie dziedziczenia atrybutów i wpadniÄ™cie do elementu „typ definiuje model atrybutuâ€, dziÄ™ki czemu mamy pewne dane.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
Pobieranie atrybutów niestandardowych dla typu {0} zgłosiło wyjątek (zignoruje i użyje sposobu odbicia): {1}
@@ -456,11 +461,6 @@ Błąd: {1}
Wywołany kod zgłosił wyjątek, który został przechwycony, ale wartość wyjątku miała wartość null
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- Starsza wersja pakietu MSTestV2 jest załadowana do zestawu. Metody czyszczenia testów mogą nie działać zgodnie z oczekiwaniami. Upewnij się, że wszystkie projekty testowe odwołują się do pakietów MSTest nowszych niż wersja 2.2.8.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
WystÄ…piÅ‚ wyjÄ…tek podczas rozwijania wierszy IDataSource z atrybutu w przestrzeni nazw „{0}.{1}â€: {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pt-BR.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pt-BR.xlf
index 50f9d4c703..25daeea3dc 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pt-BR.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.pt-BR.xlf
@@ -61,15 +61,30 @@ mas {4} argumentos recebidos, com tipos '{5}'.
Ambos os arquivos '.runsettings' e '.testconfig.json' foram detectados. Selecione apenas um desses arquivos de configuração de teste.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- O membro referenciado "{0}.{1}" de "[DynamicData]" deve retornar "IEnumerable<object[]>", "IEnumerable<Tuple>" ou "IEnumerable<ValueTuple>"
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ A fonte de dados dinâmica '{0}' no tipo '{1}' deve existir e ser uma propriedade ou um método.
- Test '{0}' exceeded execution timeout period.
- Teste '{0}' ultrapassou o perÃodo de tempo limite de execução.
-
+ Test '{0}' timed out after {1}ms
+ Tempo '{0}' tempo limite do teste após {1}ms
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ Não foi possÃvel inferir o tipo '{0}' parâmetro genérico.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ O método de teste genérico '{0}' não tem argumentos, portanto, o parâmetro genérico não pode ser inferido.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ Foram encontrados dois tipos conflitativos para parâmetro genérico '{0}'. Os tipos conflitativos são '{1}' e '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
Erro: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: um método genérico não pode ser um método de teste. {0}.{1} tem assinatura inválida
-
-
File does not exist: {0}
O arquivo não existe: {0}
@@ -408,9 +418,9 @@ Erro: {1}
- Test '{0}' execution has been aborted.
- A execução do teste '{0}' foi anulada.
-
+ Test '{0}' was canceled
+ O '{0}' teste foi cancelado
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Erro: {1}
Exceções lançadas:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- Falha ao obter cache de atributos. Ignorando a herança de atributos e caindo em 'tipo define modelo de atributo', para que tenhamos alguns dados.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
A obtenção de atributos personalizados para o tipo {0} gerou uma exceção (irá ignorar e usar o modo de reflexão): {1}
@@ -456,11 +461,6 @@ Erro: {1}
O código chamado lançou uma exceção que foi capturada, mas o valor da exceção era nulo
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- Uma versão mais antiga do pacote MSTestV2 é carregada no assembly, os métodos de limpeza de teste podem não ser executados conforme o esperado. Certifique-se de que todos os seus projetos de teste façam referência a pacotes MSTest mais recentes que a versão 2.2.8.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
Ocorreu uma exceção ao expandir as linhas IDataSource do atributo em "{0}.{1}": {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ru.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ru.xlf
index 21c0cf85e8..ce2e4f5ef3 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ru.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.ru.xlf
@@ -61,15 +61,30 @@ but received {4} argument(s), with types '{5}'.
Обнаружены файлы ".runsettings" и ".testconfig.json". Выберите только один из Ñтих файлов теÑтовой конфигурации.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- Указанный Ñлемент "[DynamicData]" "{0}.{1}" должен возвращать "IEnumerable<object[]>", "IEnumerable<Tuple>" или "IEnumerable<ValueTuple>"
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ ДинамичеÑкий иÑточник '{0}' в типе '{1}' должен ÑущеÑтвовать и быть ÑвойÑтвом или методом.
- Test '{0}' exceeded execution timeout period.
- Превышено Ð²Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ñ‚ÐµÑта "{0}".
-
+ Test '{0}' timed out after {1}ms
+ Ð’Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ '{0}' иÑтекло через {1}мÑ
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ Ðе удалоÑÑŒ определить тип универÑального '{0}' параметра.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ УниверÑальный метод '{0}' не имеет аргументов, поÑтому невозможно вывеÑти универÑальный параметр.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ Обнаружены два конфликтующих типа Ð´Ð»Ñ ÑƒÐ½Ð¸Ð²ÐµÑ€Ñального параметра '{0}'. Конфликтуют типы '{1}' и '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
Ошибка: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: универÑальный метод не может быть методом теÑта. {0}.{1} имеет недопуÑтимую Ñигнатуру
-
-
File does not exist: {0}
Файл не ÑущеÑтвует: {0}
@@ -408,9 +418,9 @@ Error: {1}
- Test '{0}' execution has been aborted.
- Выполнение теÑта "{0}" было прервано.
-
+ Test '{0}' was canceled
+ Проверка '{0}' отменена
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Error: {1}
Выданные иÑключениÑ:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- Ðе удалоÑÑŒ получить кÑш атрибутов. ÐаÑледование атрибутов игнорируетÑÑ Ð¸ выполнÑетÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´ к Ñхеме "тип определÑет модель атрибута", чтобы получить некоторые данные.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
При получении наÑтраиваемых атрибутов Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ð° {0} возникло иÑключение (оно будет проигнорировано и будет иÑпользовано отражение): {1}
@@ -456,11 +461,6 @@ Error: {1}
Вызванный код вызвал иÑключение, которое было перехвачено, но значение иÑÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð±Ñ‹Ð»Ð¾ равно NULL
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- Ð’ Ñборку загружена ÑÑ‚Ð°Ñ€Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ð¿Ð°ÐºÐµÑ‚Ð° MSTestV2. Методы очиÑтки теÑтов могут выполнÑтьÑÑ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð¾. УбедитеÑÑŒ, что вÑе теÑтовые проекты ÑÑылаютÑÑ Ð½Ð° пакеты MSTest Ñ Ð²ÐµÑ€Ñией выше 2.2.8.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
Возникло иÑключение при развертывании Ñтрок IDataSource из атрибута "{0}.{1}": {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.tr.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.tr.xlf
index d7ab817338..255dbab729 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.tr.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.tr.xlf
@@ -61,15 +61,30 @@ ancak, '{5}' türüyle {4} argüman aldı.
Hem '.runsettings' hem de '.testconfig.json' dosyaları algılandı. Lütfen bu test yapılandırma dosyalarından yalnızca birini seçin.
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- '[DynamicData]' başvurulan üyesi '{0}.{1}' şu değerleri döndürmelidir: 'IEnumerable<object[]>', 'IEnumerable<Tuple>` veya 'IEnumerable<ValueTuple>'
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ Dinamik veri kaynağı '{0}' türdeki '{1}' bir özellik veya yöntem olmalıdır.
- Test '{0}' exceeded execution timeout period.
- '{0}' testi yürütme zaman aşımı süresini aştı.
-
+ Test '{0}' timed out after {1}ms
+ Test '{0}' ms sonra zaman aşımına {1}oldu
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ Genel parametre türü '{0}' çıkarsanamadı.
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ Genel test '{0}' bağımsız değişkene sahip olmadığından genel parametre çıkarsanamıyor.
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ Genel parametre türü için iki çakışan tür '{0}'. Çakışan türler '{1}' '{2}'.
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
Hata: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: Genel metot bir test metodu olamaz. {0}.{1} geçersiz imzaya sahip
-
-
File does not exist: {0}
Dosya yok: {0}
@@ -408,9 +418,9 @@ Hata: {1}
- Test '{0}' execution has been aborted.
- '{0}' testinin yürütülmesi iptal edildi.
-
+ Test '{0}' was canceled
+ Test '{0}' iptal edildi
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Hata: {1}
Oluşturulan özel durumlar:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- Öznitelik önbelleği alınamadı. Öznitelik devralmayı yok saymak ve 'tür, Öznitelik modelini tanımlar' içine düşmek, böylece bazı verilerimiz olur.
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
{0} tipi için özel niteliklerin alınması özel durum oluşturdu (yok sayar ve yansıma yolunu kullanır): {1}
@@ -456,11 +461,6 @@ Hata: {1}
Çağrılan kod, yakalanan bir özel durum yarattı, ancak özel durum değeri boştu
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- Montaja MSTestV2 paketinin daha eski bir sürümü yüklendi, test temizleme yöntemleri beklendiği gibi çalışmayabilir. Lütfen tüm test projelerinizin 2.2.8 sürümünden daha yeni olan MSTest paketlerine başvurduğundan emin olun.
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
"{0}. {1}" üzerindeki öznitelikten IDataSource satırları genişletilirken özel durum oluştu: {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hans.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hans.xlf
index 8ee17e2acf..c8617c0588 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hans.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hans.xlf
@@ -61,15 +61,30 @@ but received {4} argument(s), with types '{5}'.
检测到 ".runsettings" å’Œ ".testconfig.json" 文件。请仅选择其ä¸ä¸€ä¸ªæµ‹è¯•é…置文件。
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- “[DynamicData]â€å¼•用的æˆå‘˜â€œ{0}.{1}â€åº”返回“IEnumerable<object[]>â€ã€â€œIEnumerable<Tuple>â€æˆ–“IEnumerable<ValueTuple>â€
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ 类型 '{1}' ä¸çš„åŠ¨æ€æ•°æ®æº '{0}' 应å˜åœ¨ï¼Œå¹¶ä¸”应为属性或方法。
- Test '{0}' exceeded execution timeout period.
- 测试“{0}â€çš„æ‰§è¡Œè¶…时。
-
+ Test '{0}' timed out after {1}ms
+ 测试 '{0}' 在 {1}毫秒åŽè¶…æ—¶
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ æ— æ³•æŽ¨æ– '{0}' æ³›åž‹å‚æ•°çš„类型。
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ 泛型测试方法 '{0}' æ²¡æœ‰å‚æ•°ï¼Œå› æ¤æ— æ³•æŽ¨æ–æ³›åž‹å‚数。
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ å‘çŽ°æ³›åž‹å‚æ•° '{0}' 的两个冲çªç±»åž‹ã€‚冲çªç±»åž‹ '{1}' å’Œ '{2}'。
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
错误: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: 泛型方法ä¸å¯ä¸ºæµ‹è¯•方法。{0}.{1} å…·æœ‰æ— æ•ˆç¾å
-
-
File does not exist: {0}
文件ä¸å˜åœ¨: {0}
@@ -408,9 +418,9 @@ Error: {1}
- Test '{0}' execution has been aborted.
- 已䏿¢æµ‹è¯•“{0}â€çš„æ‰§è¡Œã€‚
-
+ Test '{0}' was canceled
+ 测试 '{0}' 已喿¶ˆ
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Error: {1}
引å‘的异常:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- æ— æ³•èŽ·å–属性缓å˜ã€‚忽略属性继承并进入“type 定义属性模型â€ï¼Œä»¥ä¾¿æˆ‘们拥有一些数æ®ã€‚
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
获å–类型 {0} 自定义属性引å‘异常(将忽略并使用åå°„æ–¹å¼): {1}
@@ -456,11 +461,6 @@ Error: {1}
调用的代ç 引å‘了æ•获的异常,但异常值为 null
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- 较旧版本的 MSTestV2 åŒ…å·²åŠ è½½åˆ°ç¨‹åºé›†ä¸ï¼Œæµ‹è¯•æ¸…ç†æ–¹æ³•å¯èƒ½ä¸ä¼šæŒ‰é¢„期è¿è¡Œã€‚è¯·ç¡®ä¿æ‰€æœ‰æµ‹è¯•项目都引用更高版本 2.2.8 çš„ MSTest 包。
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
从“{0}.{1}â€ä¸Šçš„属性扩展 IDataSource 行时出现异常: {2}
diff --git a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hant.xlf b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hant.xlf
index 661dc53fc6..6943b4e708 100644
--- a/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hant.xlf
+++ b/src/Adapter/MSTest.TestAdapter/Resources/xlf/Resource.zh-Hant.xlf
@@ -61,15 +61,30 @@ but received {4} argument(s), with types '{5}'.
嵿¸¬åˆ° '.runsettings' å’Œ '.testconfig.json' 檔案。請åªé¸å–å…¶ä¸ä¸€å€‹æ¸¬è©¦è¨å®šæª”。
-
- '[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
- '[DynamicData]' åƒè€ƒæˆå“¡ '{0}.{1}' 應傳回 'IEnumerable<object[]>', 'IEnumerable<Tuple>` or 'IEnumerable<ValueTuple>'
+
+ The dynamic data source '{0}' in type '{1}' should exist and be a property or a method.
+ 類型 '{1}' ä¸çš„å‹•æ…‹æ•¸æ“šæº '{0}' 應該å˜åœ¨ï¼Œè€Œä¸”å¿…é ˆæ˜¯å±¬æ€§æˆ–æ–¹æ³•ã€‚
- Test '{0}' exceeded execution timeout period.
- 測試 '{0}' è¶…éŽåŸ·è¡Œé€¾æ™‚期é™ã€‚
-
+ Test '{0}' timed out after {1}ms
+ 測試 '{0}' 在 {1}毫秒後逾時
+
+
+
+ The type of the generic parameter '{0}' could not be inferred.
+ ç„¡æ³•æŽ¨æ–·æ³›åž‹åƒæ•¸ '{0}' 的類型。
+
+
+
+ The generic test method '{0}' doesn't have arguments, so the generic parameter cannot be inferred.
+ 泛型測試方法 '{0}' æ²’æœ‰è‡ªè®Šæ•¸ï¼Œå› æ¤ç„¡æ³•æŽ¨æ–·æ³›åž‹åƒæ•¸ã€‚
+
+
+
+ Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.
+ 發ç¾å…©å€‹è¡çªçš„æ³›åž‹åƒæ•¸é¡žåž‹ '{0}'。è¡çªçš„類型 '{1}' 且 '{2}'。
+
Invalid value '{0}' for runsettings entry '{1}', setting will be ignored.
@@ -203,11 +218,6 @@ Error: {1}
錯誤: {1}
-
- UTA015: A generic method cannot be a test method. {0}.{1} has invalid signature
- UTA015: 泛型方法ä¸å¯ç‚ºæ¸¬è©¦æ–¹æ³•。{0}.{1} 具有無效的簽ç«
-
-
File does not exist: {0}
檔案ä¸å˜åœ¨: {0}
@@ -408,9 +418,9 @@ Error: {1}
- Test '{0}' execution has been aborted.
- 測試 '{0}' åŸ·è¡Œå·²ä¸æ¢ã€‚
-
+ Test '{0}' was canceled
+ 已喿¶ˆæ¸¬è©¦ '{0}'
+
Invalid value '{0}' specified for 'ClassCleanupLifecycle'. Supported scopes are {1}.
@@ -435,11 +445,6 @@ Error: {1}
æ“²å›žçš„ä¾‹å¤–ç‹€æ³æ•¸:
This is usually precedes by TestAssembly_AssemblyDiscoveryFailure message, and preceded by list of exceptions thrown in a test discovery session.
-
- Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
- 無法å–得屬性快å–。略éŽå±¬æ€§ç¹¼æ‰¿ä¸¦è½åœ¨ 'type defines Attribute model' ä¸ï¼Œå› æ¤æˆ‘們有一些資料。
-
-
Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
å–得類型 {0} 擲回例外狀æ³çš„自訂屬性 (將會略éŽä¸¦ä½¿ç”¨åæ˜ æ–¹å¼): {1}
@@ -456,11 +461,6 @@ Error: {1}
被呼å«çš„程å¼ç¢¼æ“²å›žæ””截到的例外狀æ³ï¼Œä½†ä¾‹å¤–ç‹€æ³å€¼ç‚º Null
-
- An older version of MSTestV2 package is loaded in assembly, test cleanup methods might not run as expected. Please make sure all your test projects references MSTest packages newer then version 2.2.8.
- 元件ä¸å·²è¼‰å…¥èˆŠç‰ˆçš„ MSTestV2 å¥—ä»¶ï¼Œæ¸¬è©¦æ¸…ç†æ–¹æ³•å¯èƒ½ç„¡æ³•å¦‚é æœŸæ–¹å¼åŸ·è¡Œã€‚請確定您的所有測試專案都åƒè€ƒäº†æ–°ç‰ˆçš„ MSTest 套件 2.2.8 版。
-
-
Exception occurred while expanding IDataSource rows from attribute on "{0}.{1}": {2}
從「{0}.{1}ã€ä¸Šçš„屬性展開 IDataSource 資料列時發生例外狀æ³: {2}
diff --git a/src/Adapter/MSTest.TestAdapter/RunConfigurationSettings.cs b/src/Adapter/MSTest.TestAdapter/RunConfigurationSettings.cs
index ff48f1945e..2f9a8da62f 100644
--- a/src/Adapter/MSTest.TestAdapter/RunConfigurationSettings.cs
+++ b/src/Adapter/MSTest.TestAdapter/RunConfigurationSettings.cs
@@ -1,11 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Xml;
+#if !WINDOWS_UWP
+using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
+#endif
-using Microsoft.Testing.Platform.Configurations;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
@@ -13,6 +12,13 @@
namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class RunConfigurationSettings
{
///
@@ -159,6 +165,7 @@ private static RunConfigurationSettings ToSettings(XmlReader reader)
return settings;
}
+#if !WINDOWS_UWP
internal static RunConfigurationSettings SetRunConfigurationSettingsFromConfig(IConfiguration configuration, RunConfigurationSettings settings)
{
// Expected format of the json is: -
@@ -188,4 +195,5 @@ internal static RunConfigurationSettings SetRunConfigurationSettingsFromConfig(I
return settings;
}
+#endif
}
diff --git a/src/Adapter/MSTest.TestAdapter/SourceGeneratedDynamicDataOperations.cs b/src/Adapter/MSTest.TestAdapter/SourceGeneratedDynamicDataOperations.cs
index 96f1d4470e..9ea21161d0 100644
--- a/src/Adapter/MSTest.TestAdapter/SourceGeneratedDynamicDataOperations.cs
+++ b/src/Adapter/MSTest.TestAdapter/SourceGeneratedDynamicDataOperations.cs
@@ -3,6 +3,4 @@
namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
-internal class SourceGeneratedDynamicDataOperations : DynamicDataOperations
-{
-}
+internal sealed class SourceGeneratedDynamicDataOperations : DynamicDataOperations;
diff --git a/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedFileOperations.cs b/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedFileOperations.cs
index 537cd989f4..c8b8ac98f3 100644
--- a/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedFileOperations.cs
+++ b/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedFileOperations.cs
@@ -2,8 +2,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Reflection;
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
@@ -14,11 +12,10 @@ internal sealed class SourceGeneratedFileOperations : IFileOperations
// Not great, but the inner class does some complicated stuff on checking if files exist, better would be to extract the functionality to a class that provides it to both these implementations.
private readonly FileOperations _fileOperationsInner = new(skipSourceGeneratorCheck: true);
-#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
- public SourceGeneratedReflectionDataProvider ReflectionDataProvider { get; set; }
-#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
+ // null is allowed here because the ReflectionDataProvider is set by the source generator.
+ public SourceGeneratedReflectionDataProvider ReflectionDataProvider { get; set; } = null!;
- public object? CreateNavigationSession(string source) =>
+ public object CreateNavigationSession(string source) =>
// locations are in static metadata, nothing to do here.
// But don't return null so the consumer thinks we are doing something.
new();
@@ -28,18 +25,18 @@ public void DisposeNavigationSession(object? navigationSession)
// locations are in static metadata, nothing to do here.
}
- public bool DoesFileExist(string assemblyFileName) => ((IFileOperations)_fileOperationsInner).DoesFileExist(assemblyFileName);
+ public bool DoesFileExist(string assemblyFileName) => _fileOperationsInner.DoesFileExist(assemblyFileName);
- public string GetFullFilePath(string assemblyFileName) => ((IFileOperations)_fileOperationsInner).GetFullFilePath(assemblyFileName);
+ public string GetFullFilePath(string assemblyFileName) => _fileOperationsInner.GetFullFilePath(assemblyFileName);
public void GetNavigationData(object navigationSession, string className, string methodName, out int minLineNumber, out string? fileName)
- => ReflectionDataProvider!.GetNavigationData(className, methodName, out minLineNumber, out fileName);
+ => ReflectionDataProvider.GetNavigationData(className, methodName, out minLineNumber, out fileName);
- public string? GetAssemblyPath(Assembly assembly)
+ public string GetAssemblyPath(Assembly assembly)
=> throw new NotSupportedException("Only tests within the same assembly are allowed in source gen mode");
public Assembly LoadAssembly(string assemblyName, bool isReflectionOnly) => isReflectionOnly
? throw new InvalidOperationException("Reflection only mode is not allowed")
- : ReflectionDataProvider!.GetAssembly(assemblyName);
+ : ReflectionDataProvider.GetAssembly(assemblyName);
}
#endif
diff --git a/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionDataProvider.cs b/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionDataProvider.cs
index 925eeba044..b29bb954be 100644
--- a/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionDataProvider.cs
+++ b/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionDataProvider.cs
@@ -2,8 +2,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Reflection;
-
namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.SourceGeneration;
///
diff --git a/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionOperations.cs b/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionOperations.cs
index c69b9bbdc4..d66a4db69a 100644
--- a/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionOperations.cs
+++ b/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionOperations.cs
@@ -2,8 +2,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
@@ -50,35 +48,46 @@ public object[] GetCustomAttributes(Assembly assembly, Type /* the attribute typ
return attributes.ToArray();
}
- public IEnumerable GetDeclaredConstructors(Type classType)
+ public ConstructorInfo[] GetDeclaredConstructors(Type classType)
=> ReflectionDataProvider.TypeConstructors[classType];
public MethodInfo? GetDeclaredMethod(Type dynamicDataDeclaringType, string dynamicDataSourceName)
=> GetDeclaredMethods(dynamicDataDeclaringType).FirstOrDefault(m => m.Name == dynamicDataSourceName);
- public IEnumerable GetDeclaredMethods(Type classType)
+ public MethodInfo[] GetDeclaredMethods(Type classType)
=> ReflectionDataProvider.TypeMethods[classType];
- public IEnumerable GetDeclaredProperties(Type type)
+ public PropertyInfo[] GetDeclaredProperties(Type type)
=> ReflectionDataProvider.TypeProperties[type];
public PropertyInfo? GetDeclaredProperty(Type type, string propertyName)
- => GetRuntimeProperty(type, propertyName);
+ => GetRuntimeProperty(type, propertyName, includeNonPublic: true);
public Type[] GetDefinedTypes(Assembly assembly)
=> ReflectionDataProvider.Types;
- public IEnumerable GetRuntimeMethods(Type type)
+ public MethodInfo[] GetRuntimeMethods(Type type)
=> ReflectionDataProvider.TypeMethods[type];
- public MethodInfo? GetRuntimeMethod(Type declaringType, string methodName, Type[] parameters) => throw new NotImplementedException();
+ public MethodInfo? GetRuntimeMethod(Type declaringType, string methodName, Type[] parameters, bool includeNonPublic)
+ {
+ IEnumerable runtimeMethods = GetRuntimeMethods(declaringType)
+ .Where(
+ m => m.Name == methodName &&
+ m.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(parameters) &&
+ (includeNonPublic || m.IsPublic));
+ return runtimeMethods.SingleOrDefault();
+ }
- public PropertyInfo? GetRuntimeProperty(Type classType, string propertyName)
+ public PropertyInfo? GetRuntimeProperty(Type classType, string propertyName, bool includeNonPublic)
{
Dictionary type = ReflectionDataProvider.TypePropertiesByName[classType];
// We as asking for TestContext here, it may not be there.
- return type.TryGetValue(propertyName, out PropertyInfo? propertyInfo) ? propertyInfo : null;
+ PropertyInfo? property = type.TryGetValue(propertyName, out PropertyInfo? propertyInfo) ? propertyInfo : null;
+ return !includeNonPublic && (property?.GetMethod?.IsPublic == true || property?.SetMethod?.IsPublic == true)
+ ? null
+ : property;
}
public Type? GetType(string typeName)
diff --git a/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs b/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs
index 1076988370..a713f7acc8 100644
--- a/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs
+++ b/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Reflection;
-
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
@@ -10,7 +8,7 @@
namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
-internal class TestMethodFilter
+internal sealed class TestMethodFilter
{
///
/// Supported properties for filtering.
diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/BridgedConfiguration.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/BridgedConfiguration.cs
new file mode 100644
index 0000000000..2deb1e6aa3
--- /dev/null
+++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/BridgedConfiguration.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.
+
+#if !WINDOWS_UWP
+using Microsoft.Testing.Platform.Configurations;
+
+using PlatformServicesConfiguration = Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.IConfiguration;
+
+namespace Microsoft.VisualStudio.TestTools.UnitTesting;
+
+[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")]
+internal sealed class BridgedConfiguration : PlatformServicesConfiguration
+{
+ private readonly IConfiguration _configuration;
+
+ public BridgedConfiguration(IConfiguration configuration)
+ => _configuration = configuration;
+
+ public string? this[string key] => _configuration[key];
+}
+#endif
diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBannerCapability.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBannerCapability.cs
index af5c0c0e4b..3ebc32ee6d 100644
--- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBannerCapability.cs
+++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBannerCapability.cs
@@ -2,15 +2,14 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Runtime.InteropServices;
-using System.Text;
-
using Microsoft.Testing.Platform.Capabilities.TestFramework;
using Microsoft.Testing.Platform.Services;
namespace Microsoft.VisualStudio.TestTools.UnitTesting;
#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+
+[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")]
internal sealed class MSTestBannerCapability : IBannerMessageOwnerCapability
{
private readonly IPlatformInformation _platformInformation;
@@ -31,7 +30,7 @@ internal sealed class MSTestBannerCapability : IBannerMessageOwnerCapability
}
#if NETCOREAPP
- if (System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeCompiled)
+ if (RuntimeFeature.IsDynamicCodeCompiled)
#endif
{
bannerMessage.Append(" [");
diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBridgedTestFramework.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBridgedTestFramework.cs
index 5160e34c44..b8c584587b 100644
--- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBridgedTestFramework.cs
+++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestBridgedTestFramework.cs
@@ -2,29 +2,24 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Diagnostics;
-using System.Reflection;
-
using Microsoft.Testing.Extensions.VSTestBridge;
using Microsoft.Testing.Extensions.VSTestBridge.Requests;
using Microsoft.Testing.Platform.Capabilities.TestFramework;
-using Microsoft.Testing.Platform.Configurations;
using Microsoft.Testing.Platform.Messages;
using Microsoft.Testing.Platform.Services;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
namespace Microsoft.VisualStudio.TestTools.UnitTesting;
+[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")]
internal sealed class MSTestBridgedTestFramework : SynchronizedSingleSessionVSTestBridgedTestFramework
{
- private readonly IConfiguration? _configration;
+ private readonly BridgedConfiguration? _configuration;
public MSTestBridgedTestFramework(MSTestExtension mstestExtension, Func> getTestAssemblies,
IServiceProvider serviceProvider, ITestFrameworkCapabilities capabilities)
: base(mstestExtension, getTestAssemblies, serviceProvider, capabilities)
- {
- _configration = serviceProvider.GetConfiguration();
- }
+ => _configuration = new(serviceProvider.GetConfiguration());
///
protected override Task SynchronizedDiscoverTestsAsync(VSTestDiscoverTestExecutionRequest request, IMessageBus messageBus,
@@ -36,7 +31,7 @@ protected override Task SynchronizedDiscoverTestsAsync(VSTestDiscoverTestExecuti
Debugger.Launch();
}
- MSTestDiscoverer.DiscoverTests(request.AssemblyPaths, request.DiscoveryContext, request.MessageLogger, request.DiscoverySink, _configration);
+ MSTestDiscoverer.DiscoverTests(request.AssemblyPaths, request.DiscoveryContext, request.MessageLogger, request.DiscoverySink, _configuration);
return Task.CompletedTask;
}
@@ -54,11 +49,11 @@ protected override Task SynchronizedRunTestsAsync(VSTestRunTestExecutionRequest
if (request.VSTestFilter.TestCases is { } testCases)
{
- testExecutor.RunTests(testCases, request.RunContext, request.FrameworkHandle, _configration);
+ testExecutor.RunTests(testCases, request.RunContext, request.FrameworkHandle, _configuration);
}
else
{
- testExecutor.RunTests(request.AssemblyPaths, request.RunContext, request.FrameworkHandle, _configration);
+ testExecutor.RunTests(request.AssemblyPaths, request.RunContext, request.FrameworkHandle, _configuration);
}
return Task.CompletedTask;
diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestExtension.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestExtension.cs
index d39139e914..b331865f1a 100644
--- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestExtension.cs
+++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestExtension.cs
@@ -2,12 +2,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Reflection;
-
using Microsoft.Testing.Platform.Extensions;
namespace Microsoft.VisualStudio.TestTools.UnitTesting;
+[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")]
internal sealed class MSTestExtension : IExtension
{
public string Uid { get; } = GetExtensionUid();
diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestGracefulStopTestExecutionCapability.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestGracefulStopTestExecutionCapability.cs
new file mode 100644
index 0000000000..ea80488cb6
--- /dev/null
+++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestGracefulStopTestExecutionCapability.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.
+
+#if !WINDOWS_UWP
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
+
+namespace Microsoft.VisualStudio.TestTools.UnitTesting;
+
+#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+
+[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")]
+internal sealed class MSTestGracefulStopTestExecutionCapability : IGracefulStopTestExecutionCapability
+#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+{
+ private MSTestGracefulStopTestExecutionCapability()
+ {
+ }
+
+ public static MSTestGracefulStopTestExecutionCapability Instance { get; } = new();
+
+ public Task StopTestExecutionAsync(CancellationToken cancellationToken)
+ {
+ PlatformServiceProvider.Instance.IsGracefulStopRequested = true;
+ return Task.CompletedTask;
+ }
+}
+#endif
diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs
index 2a86adaf09..f16999eb17 100644
--- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs
+++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs
@@ -2,16 +2,16 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Reflection;
-
using Microsoft.Testing.Extensions.VSTestBridge.Capabilities;
using Microsoft.Testing.Extensions.VSTestBridge.Helpers;
using Microsoft.Testing.Platform.Builder;
using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.Testing.Platform.Helpers;
using Microsoft.Testing.Platform.Services;
namespace Microsoft.VisualStudio.TestTools.UnitTesting;
+[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")]
public static class TestApplicationBuilderExtensions
{
public static void AddMSTest(this ITestApplicationBuilder testApplicationBuilder, Func> getTestAssemblies)
@@ -20,12 +20,16 @@ public static void AddMSTest(this ITestApplicationBuilder testApplicationBuilder
testApplicationBuilder.AddRunSettingsService(extension);
testApplicationBuilder.AddTestCaseFilterService(extension);
testApplicationBuilder.AddTestRunParametersService(extension);
+#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ testApplicationBuilder.AddMaximumFailedTestsService(extension);
+#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
testApplicationBuilder.AddRunSettingsEnvironmentVariableProvider(extension);
testApplicationBuilder.RegisterTestFramework(
serviceProvider => new TestFrameworkCapabilities(
new VSTestBridgeExtensionBaseCapabilities(),
#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- new MSTestBannerCapability(serviceProvider.GetRequiredService())),
+ new MSTestBannerCapability(serviceProvider.GetRequiredService()),
+ MSTestGracefulStopTestExecutionCapability.Instance),
#pragma warning restore TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
(capabilities, serviceProvider) => new MSTestBridgedTestFramework(extension, getTestAssemblies, serviceProvider, capabilities));
}
diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestingPlatformBuilderHook.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestingPlatformBuilderHook.cs
index befda48370..380adc63c3 100644
--- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestingPlatformBuilderHook.cs
+++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestingPlatformBuilderHook.cs
@@ -2,15 +2,15 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Reflection;
-
using Microsoft.Testing.Platform.Builder;
namespace Microsoft.VisualStudio.TestTools.UnitTesting;
+[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")]
public static class TestingPlatformBuilderHook
{
#pragma warning disable IDE0060 // Remove unused parameter
- public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] arguments) => testApplicationBuilder.AddMSTest(() => [Assembly.GetEntryAssembly()!]);
+ public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] arguments)
+ => testApplicationBuilder.AddMSTest(() => [Assembly.GetEntryAssembly()!]);
}
#endif
diff --git a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestDiscoverer.cs b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestDiscoverer.cs
index 47a01bf4f6..04eefda012 100644
--- a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestDiscoverer.cs
+++ b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestDiscoverer.cs
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using Microsoft.Testing.Platform.Configurations;
+using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
@@ -16,6 +16,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
[FileExtension(".appx")]
[FileExtension(".dll")]
[FileExtension(".exe")]
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class MSTestDiscoverer : ITestDiscoverer
{
///
@@ -26,8 +33,8 @@ public class MSTestDiscoverer : ITestDiscoverer
/// Logger used to log messages.
/// Used to send testcases and discovery related events back to Discoverer manager.
[System.Security.SecurityCritical]
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Discovery context can be null.")]
- public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink) => MSTestDiscoverer.DiscoverTests(sources, discoveryContext, logger, discoverySink, null);
+ [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Discovery context can be null.")]
+ public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink) => DiscoverTests(sources, discoveryContext, logger, discoverySink, null);
internal static void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink, IConfiguration? configuration)
{
diff --git a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs
index fcad29af3a..236659f902 100644
--- a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs
+++ b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs
@@ -1,10 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Runtime.InteropServices;
-
-using Microsoft.Testing.Platform.Configurations;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution;
+using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
@@ -15,6 +13,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
/// Contains the execution logic for this adapter.
///
[ExtensionUri(Constants.ExecutorUriString)]
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class MSTestExecutor : ITestExecutor
{
private readonly CancellationToken _cancellationToken;
@@ -44,9 +49,11 @@ internal MSTestExecutor(CancellationToken cancellationToken)
///
public TestExecutionManager TestExecutionManager { get; protected set; }
- public void RunTests(IEnumerable? tests, IRunContext? runContext, IFrameworkHandle? frameworkHandle) => RunTests(tests, runContext, frameworkHandle, null);
+ public void RunTests(IEnumerable? tests, IRunContext? runContext, IFrameworkHandle? frameworkHandle)
+ => RunTests(tests, runContext, frameworkHandle, null);
- public void RunTests(IEnumerable? sources, IRunContext? runContext, IFrameworkHandle? frameworkHandle) => RunTests(sources, runContext, frameworkHandle, null);
+ public void RunTests(IEnumerable? sources, IRunContext? runContext, IFrameworkHandle? frameworkHandle)
+ => RunTests(sources, runContext, frameworkHandle, null);
internal void RunTests(IEnumerable? tests, IRunContext? runContext, IFrameworkHandle? frameworkHandle, IConfiguration? configuration)
{
diff --git a/src/Adapter/MSTest.TestAdapter/build/net/MSTest.TestAdapter.targets b/src/Adapter/MSTest.TestAdapter/build/common/MSTest.TestAdapter.targets
similarity index 100%
rename from src/Adapter/MSTest.TestAdapter/build/net/MSTest.TestAdapter.targets
rename to src/Adapter/MSTest.TestAdapter/build/common/MSTest.TestAdapter.targets
diff --git a/src/Adapter/MSTest.TestAdapter/build/netfx-netcore-netstandard/MSTest.TestAdapter.targets b/src/Adapter/MSTest.TestAdapter/build/netfx-netcore-netstandard/MSTest.TestAdapter.targets
deleted file mode 100644
index 64fb79bf30..0000000000
--- a/src/Adapter/MSTest.TestAdapter/build/netfx-netcore-netstandard/MSTest.TestAdapter.targets
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
- $(EnableMSTestRunner)
- $(EnableMSTestRunner)
- false
- true
-
-
-
-
- Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.dll
- PreserveNewest
- False
-
-
- Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.dll
- PreserveNewest
- False
-
-
- Microsoft.TestPlatform.AdapterUtilities.dll
- PreserveNewest
- False
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(MSBuildThisFileDirectory)Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %(CurrentUICultureHierarchy.Identity)
-
-
-
-
-
-
- %(MSTestV2Files.UICulture)\%(FileName).dll
- PreserveNewest
- %(FullPath)
- False
-
-
-
-
-
diff --git a/src/Adapter/MSTest.TestAdapter/build/uwp/MSTest.TestAdapter.props b/src/Adapter/MSTest.TestAdapter/build/uwp/MSTest.TestAdapter.props
index 365706e987..259e47a969 100644
--- a/src/Adapter/MSTest.TestAdapter/build/uwp/MSTest.TestAdapter.props
+++ b/src/Adapter/MSTest.TestAdapter/build/uwp/MSTest.TestAdapter.props
@@ -1,30 +1,7 @@
-
-
- Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.dll
- PreserveNewest
- False
-
-
- Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.dll
- PreserveNewest
- False
-
-
- Microsoft.TestPlatform.AdapterUtilities.dll
- PreserveNewest
- False
-
-
-
-
-
-
-
+
+ true
+
diff --git a/src/Adapter/MSTest.TestAdapter/build/uwp/MSTest.TestAdapter.targets b/src/Adapter/MSTest.TestAdapter/build/uwp/MSTest.TestAdapter.targets
index c33b561416..e8d37601f3 100644
--- a/src/Adapter/MSTest.TestAdapter/build/uwp/MSTest.TestAdapter.targets
+++ b/src/Adapter/MSTest.TestAdapter/build/uwp/MSTest.TestAdapter.targets
@@ -1,13 +1,31 @@
-
- true
-
- $(EnableMSTestRunner)
- $(EnableMSTestRunner)
- false
- true
-
+
+
+ Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.dll
+ PreserveNewest
+ False
+
+
+ Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.dll
+ PreserveNewest
+ False
+
+
+ Microsoft.TestPlatform.AdapterUtilities.dll
+ PreserveNewest
+ False
+
+
+
+
+
+
+
@@ -31,10 +31,14 @@
-
+
+ Analyzer
+ false
+
+
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Properties/AssemblyInfo.cs b/src/Adapter/MSTestAdapter.PlatformServices/Properties/AssemblyInfo.cs
index e1f84be7e3..d7f4830787 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Properties/AssemblyInfo.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Properties/AssemblyInfo.cs
@@ -1,15 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-#if NETFRAMEWORK || WIN_UI
-using System.Runtime.CompilerServices;
-#endif
-using System.Runtime.InteropServices;
-
-#if WIN_UI
-using System.Runtime.Versioning;
-#endif
-
[assembly: ComVisible(false)]
#if WIN_UI
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Shipped.txt
index 0c08630cca..5acee6d2bc 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Shipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Shipped.txt
@@ -1,4 +1,4 @@
-#nullable enable
+#nullable enable
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AdapterTraceLogger
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AdapterTraceLogger.AdapterTraceLogger() -> void
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AdapterTraceLogger.LogError(string! format, params object?[]! args) -> void
@@ -40,7 +40,10 @@ Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITe
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.GetResultFiles() -> System.Collections.Generic.IList?
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.SetDataConnection(object? dbConnection) -> void
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.SetDataRow(object? dataRow) -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.SetDisplayName(string? displayName) -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.SetException(System.Exception? exception) -> void
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.SetOutcome(Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome outcome) -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.SetTestData(object?[]? data) -> void
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.TryGetPropertyValue(string! propertyName, out object? propertyValue) -> bool
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestDataSource
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestDataSource.GetData(Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod! testMethodInfo, Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext! testContext) -> System.Collections.Generic.IEnumerable?
@@ -93,7 +96,10 @@ Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextIm
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.GetResultFiles() -> System.Collections.Generic.IList?
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.SetDataConnection(object? dbConnection) -> void
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.SetDataRow(object? dataRow) -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.SetDisplayName(string? displayName) -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.SetException(System.Exception? exception) -> void
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.SetOutcome(Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome outcome) -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.SetTestData(object?[]? data) -> void
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.TestContextImplementation(Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel.ITestMethod! testMethod, System.IO.StringWriter! stringWriter, System.Collections.Generic.IDictionary! properties) -> void
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.TryGetPropertyValue(string! propertyName, out object? propertyValue) -> bool
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestDataSource
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Unshipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Unshipped.txt
index 04a7900759..e2d86d5ce1 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Unshipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Unshipped.txt
@@ -1,7 +1,5 @@
-#nullable enable
-Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.SetDisplayName(string? displayName) -> void
-Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.SetException(System.Exception? exception) -> void
-Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.SetTestData(object?[]? data) -> void
-Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.SetDisplayName(string? displayName) -> void
-Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.SetException(System.Exception? exception) -> void
-Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.SetTestData(object?[]? data) -> void
+#nullable enable
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext.DisplayMessage(Microsoft.VisualStudio.TestTools.UnitTesting.MessageLevel messageLevel, string! message) -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.TestContextImplementation(Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel.ITestMethod? testMethod, System.IO.StringWriter! stringWriter, System.Collections.Generic.IDictionary! properties) -> void
+override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.DisplayMessage(Microsoft.VisualStudio.TestTools.UnitTesting.MessageLevel messageLevel, string! message) -> void
+*REMOVED*Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.TestContextImplementation(Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel.ITestMethod! testMethod, System.IO.StringWriter! stringWriter, System.Collections.Generic.IDictionary! properties) -> void
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net462/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net462/PublicAPI.Shipped.txt
index 7bb31399b1..163eb68518 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net462/PublicAPI.Shipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net462/PublicAPI.Shipped.txt
@@ -82,4 +82,4 @@ virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Assem
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AssemblyResolver.ReflectionOnlyLoadAssemblyFrom(string! path) -> System.Reflection.Assembly!
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AssemblyResolver.SearchAssembly(System.Collections.Generic.List! searchDirectorypaths, string! name, bool isReflectionOnly) -> System.Reflection.Assembly?
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DoesDirectoryExist(string! path) -> bool
-virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
\ No newline at end of file
+virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net6.0-windows10.0.18362.0/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net6.0-windows10.0.18362.0/PublicAPI.Shipped.txt
index 0e08282b9a..2dd69c993e 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net6.0-windows10.0.18362.0/PublicAPI.Shipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net6.0-windows10.0.18362.0/PublicAPI.Shipped.txt
@@ -33,4 +33,4 @@ System.SerializableAttribute (forwarded, contained in System.Runtime)
System.SerializableAttribute.SerializableAttribute() -> void (forwarded, contained in System.Runtime)
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DoesDirectoryExist(string! path) -> bool
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
-virtual System.MarshalByRefObject.InitializeLifetimeService() -> object! (forwarded, contained in System.Runtime)
\ No newline at end of file
+virtual System.MarshalByRefObject.InitializeLifetimeService() -> object! (forwarded, contained in System.Runtime)
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net6.0/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net6.0/PublicAPI.Shipped.txt
index b5ff64abc0..f4783138ee 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net6.0/PublicAPI.Shipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net6.0/PublicAPI.Shipped.txt
@@ -30,4 +30,4 @@ static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTest
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Reset() -> void
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Settings.get -> Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings!
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DoesDirectoryExist(string! path) -> bool
-virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
\ No newline at end of file
+virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net7.0/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net7.0/PublicAPI.Shipped.txt
index b5ff64abc0..f4783138ee 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net7.0/PublicAPI.Shipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net7.0/PublicAPI.Shipped.txt
@@ -30,4 +30,4 @@ static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTest
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Reset() -> void
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Settings.get -> Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings!
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DoesDirectoryExist(string! path) -> bool
-virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
\ No newline at end of file
+virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net8.0/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net8.0/PublicAPI.Shipped.txt
index b5ff64abc0..f4783138ee 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net8.0/PublicAPI.Shipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net8.0/PublicAPI.Shipped.txt
@@ -30,4 +30,4 @@ static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTest
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Reset() -> void
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Settings.get -> Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings!
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DoesDirectoryExist(string! path) -> bool
-virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
\ No newline at end of file
+virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net9.0/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net9.0/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..f4783138ee
--- /dev/null
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net9.0/PublicAPI.Shipped.txt
@@ -0,0 +1,33 @@
+#nullable enable
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment.TestRunDirectories
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment.TestRunDirectories.InDirectory.get -> string!
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment.TestRunDirectories.InMachineNameDirectory.get -> string!
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment.TestRunDirectories.OutDirectory.get -> string!
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment.TestRunDirectories.RootDeploymentDirectory.get -> string!
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment.TestRunDirectories.RootDeploymentDirectory.set -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment.TestRunDirectories.TestRunDirectories(string! rootDirectory) -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DeleteDeploymentDirectoryAfterTestRunIsComplete.get -> bool
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DeploymentEnabled.get -> bool
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DeployTestSourceDependencies.get -> bool
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.GetDirectoryListWithRecursiveProperty(string! baseDirectory) -> System.Collections.Generic.List!
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.MSTestAdapterSettings() -> void
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.SearchDirectories.get -> System.Collections.Generic.List!
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.RecursiveDirectoryPath
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.RecursiveDirectoryPath.DirectoryPath.get -> string!
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.RecursiveDirectoryPath.IncludeSubDirectories.get -> bool
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.RecursiveDirectoryPath.RecursiveDirectoryPath(string! dirPath, bool includeSubDirectories) -> void
+override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.RecursiveDirectoryPath.InitializeLifetimeService() -> object!
+override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.DeploymentDirectory.get -> string?
+override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.FullyQualifiedTestClassName.get -> string!
+override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.ResultsDirectory.get -> string?
+override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.TestName.get -> string!
+override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.TestResultsDirectory.get -> string?
+override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.TestRunDirectory.get -> string?
+override Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestContextImplementation.TestRunResultsDirectory.get -> string?
+static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.IsAppDomainCreationDisabled(string? settingsXml) -> bool
+static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ToSettings(System.Xml.XmlReader! reader) -> Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings!
+static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Reset() -> void
+static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Settings.get -> Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings!
+virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DoesDirectoryExist(string! path) -> bool
+virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net9.0/PublicAPI.Unshipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net9.0/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..7dc5c58110
--- /dev/null
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/net9.0/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/netcoreapp3.1/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/netcoreapp3.1/PublicAPI.Shipped.txt
index b5ff64abc0..f4783138ee 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/netcoreapp3.1/PublicAPI.Shipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/netcoreapp3.1/PublicAPI.Shipped.txt
@@ -30,4 +30,4 @@ static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTest
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Reset() -> void
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Settings.get -> Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings!
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DoesDirectoryExist(string! path) -> bool
-virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
\ No newline at end of file
+virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt
index b5ff64abc0..f4783138ee 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt
@@ -30,4 +30,4 @@ static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTest
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Reset() -> void
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestSettingsProvider.Settings.get -> Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings!
virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.DoesDirectoryExist(string! path) -> bool
-virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
\ No newline at end of file
+virtual Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.MSTestAdapterSettings.ExpandEnvironmentVariables(string! path) -> string!
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/uap10.0.16299/PublicAPI.Shipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/uap10.0.16299/PublicAPI.Shipped.txt
index 0f2adb28da..24625c1ccf 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/uap10.0.16299/PublicAPI.Shipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/uap10.0.16299/PublicAPI.Shipped.txt
@@ -1,4 +1,4 @@
#nullable enable
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TraceListenerManager.Close(Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITraceListener! traceListener) -> void
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TraceListenerWrapper.Close() -> void
-Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TraceListenerWrapper.Dispose() -> void
\ No newline at end of file
+Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TraceListenerWrapper.Dispose() -> void
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/uap10.0.16299/PublicAPI.Unshipped.txt b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/uap10.0.16299/PublicAPI.Unshipped.txt
index 815c92006a..7dc5c58110 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/uap10.0.16299/PublicAPI.Unshipped.txt
+++ b/src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/uap10.0.16299/PublicAPI.Unshipped.txt
@@ -1 +1 @@
-#nullable enable
\ No newline at end of file
+#nullable enable
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs b/src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs
index 3162c23030..e2dbebb62f 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Diagnostics.CodeAnalysis;
using System.Security;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
@@ -20,6 +19,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
/// For each directory we need to have two info 1) path 2) includeSubDirectories.
///
[Serializable]
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1603:DocumentationMustContainValidXml", Justification = "Reviewed. Suppression is ok here.")]
public class RecursiveDirectoryPath : MarshalByRefObject
{
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/DiaSessionOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/DiaSessionOperations.cs
index dd44632e3a..715db4e02b 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/DiaSessionOperations.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/DiaSessionOperations.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Reflection;
-
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
internal static class DiaSessionOperations
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ExecutionContextService.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ExecutionContextService.cs
index c38800d1c0..9ba8f8c5d1 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ExecutionContextService.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ExecutionContextService.cs
@@ -1,9 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Collections.Concurrent;
-using System.Diagnostics;
-
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
internal static class ExecutionContextService
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs
index 82064d7c5b..e28a2f5009 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs
@@ -1,9 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Collections.Concurrent;
-using System.Reflection;
-
#if WIN_UI
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AppContainer;
#endif
@@ -18,6 +15,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// The file operations.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class FileOperations : IFileOperations
{
private readonly ConcurrentDictionary _assemblyCache = new();
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs
index 9ceb4b58d9..f8af181afd 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs
@@ -2,16 +2,21 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using System.Globalization;
-using System.Xml;
-using Microsoft.Testing.Platform.Configurations;
+using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class MSTestAdapterSettings
{
///
@@ -253,7 +258,7 @@ public List GetDirectoryListWithRecursiveProperty(string
}
else
{
- warningMessage = $"The Directory: {path}, has following problem: {"This is not an absolute path. A base directory should be provided for this to be used as a relative path."}";
+ warningMessage = $"The Directory: {path}, has following problem: This is not an absolute path. A base directory should be provided for this to be used as a relative path.";
if (EqtTrace.IsWarningEnabled)
{
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/MessageLevel.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/MessageLevel.cs
new file mode 100644
index 0000000000..455c39aaf8
--- /dev/null
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/MessageLevel.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.VisualStudio.TestPlatform.ObjectModel.Logging;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
+
+internal static class MessageLevelExtensions
+{
+ public static TestMessageLevel ToTestMessageLevel(this MessageLevel messageLevel)
+ => messageLevel switch
+ {
+ MessageLevel.Informational => TestMessageLevel.Informational,
+ MessageLevel.Warning => TestMessageLevel.Warning,
+ MessageLevel.Error => TestMessageLevel.Error,
+ _ => throw new ArgumentOutOfRangeException(nameof(messageLevel)),
+ };
+}
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs
index 4dfbe0b35f..f72e120267 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs
@@ -1,9 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
#if NETFRAMEWORK
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
@@ -14,6 +11,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// This service is responsible for platform specific reflection operations.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class ReflectionOperations : IReflectionOperations
{
///
@@ -23,11 +27,20 @@ public class ReflectionOperations : IReflectionOperations
/// True to inspect the ancestors of element; otherwise, false.
/// The list of attributes on the member. Empty list if none found.
[return: NotNullIfNotNull(nameof(memberInfo))]
- public object[]? GetCustomAttributes(MemberInfo memberInfo, bool inherit) =>
+ public object[]? GetCustomAttributes(MemberInfo memberInfo, bool inherit)
#if NETFRAMEWORK
- ReflectionUtility.GetCustomAttributes(memberInfo, inherit).ToArray();
+ => ReflectionUtility.GetCustomAttributes(memberInfo, inherit).ToArray();
#else
- memberInfo.GetCustomAttributes(inherit);
+ {
+ object[] attributes = memberInfo.GetCustomAttributes(typeof(Attribute), inherit);
+
+ // Ensures that when the return of this method is used here:
+ // https://github.com/microsoft/testfx/blob/e101a9d48773cc935c7b536d25d378d9a3211fee/src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs#L461
+ // then we are already Attribute[] to avoid LINQ Cast and extra array allocation.
+ // This assert is solely for performance. Nothing "functional" will go wrong if the assert failed.
+ Debug.Assert(attributes is Attribute[], $"Expected Attribute[], found '{attributes.GetType()}'.");
+ return attributes;
+ }
#endif
///
@@ -55,6 +68,6 @@ public object[] GetCustomAttributes(Assembly assembly, Type type) =>
#if NETFRAMEWORK
ReflectionUtility.GetCustomAttributes(assembly, type).ToArray();
#else
- assembly.GetCustomAttributes(type).ToArray();
+ assembly.GetCustomAttributes(type, inherit: true);
#endif
}
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs
index 8f74a3e352..98d475b99b 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs
@@ -1,18 +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 System.Reflection;
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
-internal class ReflectionOperations2 : ReflectionOperations, IReflectionOperations2
+internal sealed class ReflectionOperations2 : ReflectionOperations, IReflectionOperations2
{
+ private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
+ private const BindingFlags Everything = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
+
public ReflectionOperations2()
{
#if NET8_0_OR_GREATER
- if (!System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported)
+ if (!RuntimeFeature.IsDynamicCodeSupported)
{
throw new NotSupportedException("ReflectionOperations2 are not allowed when dynamic code is not supported, use NativeReflectionOperations instead");
}
@@ -23,32 +24,36 @@ public ReflectionOperations2()
#pragma warning disable IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming
#pragma warning disable IL2067 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'.
#pragma warning disable IL2057 // Unrecognized value passed to the typeName parameter of 'System.Type.GetType(String)'
- public IEnumerable GetDeclaredConstructors(Type classType)
- => classType.GetTypeInfo().DeclaredConstructors;
+ public ConstructorInfo[] GetDeclaredConstructors(Type classType)
+ => classType.GetConstructors(DeclaredOnlyLookup);
public MethodInfo? GetDeclaredMethod(Type type, string methodName)
- => type.GetTypeInfo().GetDeclaredMethod(methodName);
+ => type.GetMethod(methodName, DeclaredOnlyLookup);
- public IEnumerable GetDeclaredMethods(Type classType)
- => classType.GetTypeInfo().DeclaredMethods;
+ public MethodInfo[] GetDeclaredMethods(Type classType)
+ => classType.GetMethods(DeclaredOnlyLookup);
- public IEnumerable GetDeclaredProperties(Type type)
- => type.GetTypeInfo().DeclaredProperties;
+ public PropertyInfo[] GetDeclaredProperties(Type type)
+ => type.GetProperties(DeclaredOnlyLookup);
public PropertyInfo? GetDeclaredProperty(Type type, string propertyName)
- => type.GetTypeInfo().GetDeclaredProperty(propertyName);
+ => type.GetProperty(propertyName, DeclaredOnlyLookup);
public Type[] GetDefinedTypes(Assembly assembly)
- => assembly.DefinedTypes.ToArray();
+ => assembly.GetTypes();
- public IEnumerable GetRuntimeMethods(Type type)
- => type.GetRuntimeMethods();
+ public MethodInfo[] GetRuntimeMethods(Type type)
+ => type.GetMethods(Everything);
- public MethodInfo? GetRuntimeMethod(Type declaringType, string methodName, Type[] parameters)
- => declaringType.GetRuntimeMethod(methodName, parameters);
+ public MethodInfo? GetRuntimeMethod(Type declaringType, string methodName, Type[] parameters, bool includeNonPublic)
+ => includeNonPublic
+ ? declaringType.GetMethod(methodName, Everything, null, parameters, null)
+ : declaringType.GetMethod(methodName, parameters);
- public PropertyInfo? GetRuntimeProperty(Type classType, string testContextPropertyName)
- => classType.GetProperty(testContextPropertyName);
+ public PropertyInfo? GetRuntimeProperty(Type classType, string testContextPropertyName, bool includeNonPublic)
+ => includeNonPublic
+ ? classType.GetProperty(testContextPropertyName, Everything)
+ : classType.GetProperty(testContextPropertyName);
public Type? GetType(string typeName)
=> Type.GetType(typeName);
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs
index 2846da17e6..709ca664ec 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs
@@ -1,12 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-#if !WINDOWS_UWP
-using System.Diagnostics.CodeAnalysis;
-#endif
-using System.Xml;
-
-using Microsoft.Testing.Platform.Configurations;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
@@ -14,6 +8,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// Class to read settings from the runsettings xml for the desktop.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class MSTestSettingsProvider : ISettingsProvider
{
#if !WINDOWS_UWP
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs
index b67fa921c0..4dc75ae796 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs
@@ -1,14 +1,13 @@
// 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;
#if NETFRAMEWORK
using System.Data;
using System.Data.Common;
#endif
-using System.Globalization;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ITestMethod = Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel.ITestMethod;
@@ -20,6 +19,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
/// The virtual string properties of the TestContext are retrieved from the property dictionary
/// like GetProperty<string>("TestName") or GetProperty<string>("FullyQualifiedTestClassName").
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class TestContextImplementation : TestContext, ITestContext
{
///
@@ -33,15 +39,11 @@ public class TestContextImplementation : TestContext, ITestContext
private readonly StringWriter _stringWriter;
private readonly ThreadSafeStringWriter? _threadSafeStringWriter;
- ///
- /// Test Method.
- ///
- private readonly ITestMethod _testMethod;
-
///
/// Properties.
///
private readonly Dictionary _properties;
+ private readonly IMessageLogger? _messageLogger;
///
/// Specifies whether the writer is disposed or not.
@@ -71,27 +73,40 @@ public class TestContextImplementation : TestContext, ITestContext
/// The test method.
/// The writer where diagnostic messages are written to.
/// Properties/configuration passed in.
- public TestContextImplementation(ITestMethod testMethod, StringWriter stringWriter, IDictionary properties)
+ /// The message logger to use.
+ internal TestContextImplementation(ITestMethod? testMethod, StringWriter stringWriter, IDictionary properties, IMessageLogger messageLogger)
+ : this(testMethod, stringWriter, properties)
+ => _messageLogger = messageLogger;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The test method.
+ /// The writer where diagnostic messages are written to.
+ /// Properties/configuration passed in.
+ public TestContextImplementation(ITestMethod? testMethod, StringWriter stringWriter, IDictionary properties)
{
- DebugEx.Assert(testMethod != null, "TestMethod is not null");
+ // testMethod can be null when running ForceCleanup (done when reaching --maximum-failed-tests.
DebugEx.Assert(properties != null, "properties is not null");
#if NETFRAMEWORK
DebugEx.Assert(stringWriter != null, "StringWriter is not null");
#endif
- _testMethod = testMethod;
_stringWriter = stringWriter;
// Cannot get this type in constructor directly, because all signatures for all platforms need to be the same.
_threadSafeStringWriter = stringWriter as ThreadSafeStringWriter;
- _properties = new Dictionary(properties)
- {
- [FullyQualifiedTestClassNameLabel] = _testMethod.FullClassName,
- [ManagedTypeLabel] = _testMethod.ManagedTypeName,
- [ManagedMethodLabel] = _testMethod.ManagedMethodName,
- [TestNameLabel] = _testMethod.Name,
- };
+ _properties = testMethod is null
+ ? new Dictionary(properties)
+ : new Dictionary(properties)
+ {
+ [FullyQualifiedTestClassNameLabel] = testMethod.FullClassName,
+ [ManagedTypeLabel] = testMethod.ManagedTypeName,
+ [ManagedMethodLabel] = testMethod.ManagedMethodName,
+ [TestNameLabel] = testMethod.Name,
+ };
+
_testResultFiles = [];
}
@@ -350,5 +365,7 @@ public void ClearDiagnosticMessages()
public void SetDisplayName(string? displayName)
=> TestDisplayName = displayName;
+ public override void DisplayMessage(MessageLevel messageLevel, string message)
+ => _messageLogger?.SendMessage(messageLevel.ToTestMessageLevel(), message);
#endregion
}
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs
index 04b6218b9e..232dc8d19b 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs
@@ -4,17 +4,14 @@
#if NETFRAMEWORK
using System.Configuration;
using System.Data;
-using System.Diagnostics;
-using System.Globalization;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Data;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
#endif
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
using ITestDataSource = Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestDataSource;
-using UTF = Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
@@ -26,12 +23,19 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
/// the tests since it can only be found at the test output directory. DO NOT call into this platform service outside of the appdomain context if you do not want to hit
/// a ReflectionTypeLoadException.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class TestDataSource : ITestDataSource
{
#if NETFRAMEWORK
- public IEnumerable? GetData(UTF.ITestMethod testMethodInfo, ITestContext testContext)
+ public IEnumerable? GetData(ITestMethod testMethodInfo, ITestContext testContext)
#else
- IEnumerable? ITestDataSource.GetData(UTF.ITestMethod testMethodInfo, ITestContext testContext)
+ IEnumerable? ITestDataSource.GetData(ITestMethod testMethodInfo, ITestContext testContext)
#endif
{
#if NETFRAMEWORK
@@ -42,12 +46,12 @@ public class TestDataSource : ITestDataSource
Path.GetDirectoryName(new Uri(testMethodInfo.MethodInfo.Module.Assembly.CodeBase).LocalPath),
];
- List dataRowResults = [];
+ List dataRowResults = [];
// Connect to data source.
TestDataConnectionFactory factory = new();
- GetConnectionProperties(testMethodInfo.GetAttributes(false)[0], out string providerNameInvariant, out string? connectionString, out string? tableName, out UTF.DataAccessMethod dataAccessMethod);
+ GetConnectionProperties(testMethodInfo.GetAttributes(false)[0], out string providerNameInvariant, out string? connectionString, out string? tableName, out DataAccessMethod dataAccessMethod);
try
{
@@ -96,7 +100,7 @@ public class TestDataSource : ITestDataSource
/// The data access method.
/// Number of permutations.
/// Permutations.
- private static IEnumerable GetPermutation(UTF.DataAccessMethod dataAccessMethod, int length)
+ private static IEnumerable GetPermutation(DataAccessMethod dataAccessMethod, int length)
{
switch (dataAccessMethod)
{
@@ -120,8 +124,8 @@ private static IEnumerable GetPermutation(UTF.DataAccessMethod dataAccessMe
/// The connection string.
/// The table name.
/// The data access method.
- private static void GetConnectionProperties(UTF.DataSourceAttribute dataSourceAttribute, out string providerNameInvariant,
- out string? connectionString, out string? tableName, out UTF.DataAccessMethod dataAccessMethod)
+ private static void GetConnectionProperties(DataSourceAttribute dataSourceAttribute, out string providerNameInvariant,
+ out string? connectionString, out string? tableName, out DataAccessMethod dataAccessMethod)
{
if (StringEx.IsNullOrEmpty(dataSourceAttribute.DataSourceSettingName))
{
@@ -132,7 +136,7 @@ private static void GetConnectionProperties(UTF.DataSourceAttribute dataSourceAt
return;
}
- UTF.DataSourceElement element = TestConfiguration.ConfigurationSection.DataSources[dataSourceAttribute.DataSourceSettingName]
+ DataSourceElement element = TestConfiguration.ConfigurationSection.DataSources[dataSourceAttribute.DataSourceSettingName]
#pragma warning disable CA2201 // Do not raise reserved exception types
?? throw new Exception(string.Format(CultureInfo.CurrentCulture, Resource.UTA_DataSourceConfigurationSectionMissing, dataSourceAttribute.DataSourceSettingName));
#pragma warning restore CA2201 // Do not raise reserved exception types
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs
index 74c88e6d38..257f02d895 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs
@@ -1,9 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-
#if !WINDOWS_UWP
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
#endif
@@ -25,6 +22,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// The test deployment.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class TestDeployment : ITestDeployment
{
#if !WINDOWS_UWP
@@ -179,7 +183,7 @@ group test by test.Source into testGroup
#if !WINDOWS_UWP
internal static IDictionary GetDeploymentInformation(string source)
{
- var properties = new Dictionary();
+ var properties = new Dictionary(capacity: 8);
string applicationBaseDirectory = string.Empty;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSource.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSource.cs
index 9261cdb897..e24f91db0a 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSource.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSource.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Reflection;
-
#if WIN_UI
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.AppContainer;
#endif
@@ -17,6 +15,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
/// This platform service is responsible for any data or operations to validate
/// the test sources provided to the adapter.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class TestSource : ITestSource
{
#if WINDOWS_UWP || WIN_UI
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs
index 482c4f9b94..441b3c7d5d 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Diagnostics.CodeAnalysis;
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
#if NETFRAMEWORK
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
@@ -23,6 +21,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// A host that loads the test source. This can be in isolation for desktop using an AppDomain or just loading the source in the current context.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class TestSourceHost : ITestSourceHost
{
#if !WINDOWS_UWP
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadOperations.cs
index bea00ebe35..52ee8d5205 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadOperations.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadOperations.cs
@@ -1,10 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-#if !NETFRAMEWORK
-using System.Runtime.InteropServices;
-#endif
-
+using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
@@ -12,6 +9,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// This service is responsible for any Async operations specific to a platform.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class ThreadOperations : IThreadOperations
{
///
@@ -40,11 +44,7 @@ private static bool ExecuteWithThreadPool(Action action, int timeout, Cancellati
// False means execution timed out.
return executionTask.Wait(timeout, cancellationToken);
}
- catch (Exception ex) when
- ((ex is OperationCanceledException oce && oce.CancellationToken == cancellationToken)
-
- // This exception occurs when the cancellation happens before the task is actually started.
- || (ex is TaskCanceledException tce && tce.CancellationToken == cancellationToken))
+ catch (Exception ex) when (ex.IsOperationCanceledExceptionFromToken(cancellationToken))
{
// Task execution canceled.
return false;
@@ -52,7 +52,7 @@ private static bool ExecuteWithThreadPool(Action action, int timeout, Cancellati
}
#endif
- [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ [SupportedOSPlatform("windows")]
private static bool ExecuteWithCustomThread(Action action, int timeout, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
@@ -78,11 +78,7 @@ private static bool ExecuteWithCustomThread(Action action, int timeout, Cancella
// If the execution thread completes before the timeout, the task will return true, otherwise false.
return executionTask.Result;
}
- catch (Exception ex) when
- ((ex is OperationCanceledException oce && oce.CancellationToken == cancellationToken)
-
- // This exception occurs when the cancellation happens before the task is actually started.
- || (ex is TaskCanceledException tce && tce.CancellationToken == cancellationToken))
+ catch (Exception ex) when (ex.IsOperationCanceledExceptionFromToken(cancellationToken))
{
// Task execution canceled.
return false;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadSafeStringWriter.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadSafeStringWriter.cs
index d898382960..2994696ebd 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadSafeStringWriter.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ThreadSafeStringWriter.cs
@@ -1,13 +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.Text;
-
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// AsyncContext aware, thread safe string writer that allows output writes from different threads to end up in the same async local context.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class ThreadSafeStringWriter : StringWriter
{
#if DEBUG
@@ -18,7 +23,7 @@ public class ThreadSafeStringWriter : StringWriter
// This static lock guards access to the state and getting values from dictionary. There can be multiple different instances of ThreadSafeStringWriter
// accessing the state at the same time, and we need to give them the correct state for their async context. Non-concurrent dictionary is used to store the
// state because we need to lock around it anyway, to ensure that the State is populated, but not overwritten by every new instance of ThreadSafeStringWriter.
- private static readonly object StaticLockObject = new();
+ private static readonly Lock StaticLockObject = new();
private readonly string _outputType;
///
@@ -172,10 +177,10 @@ private ThreadSafeStringBuilder GetOrAddStringBuilder()
///
/// This StringBuilder puts locks around all the methods to avoid conflicts when writing or reading from multiple threads.
///
- private class ThreadSafeStringBuilder
+ private sealed class ThreadSafeStringBuilder
{
private readonly StringBuilder _stringBuilder = new();
- private readonly object _instanceLockObject = new();
+ private readonly Lock _instanceLockObject = new();
public void Append(string? value)
{
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListener.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListener.cs
index 36ec699eed..667fa713c0 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListener.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListener.cs
@@ -1,10 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-#if !WINDOWS_UWP && !WIN_UI
-using System.Diagnostics;
-#endif
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
@@ -16,6 +12,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
/// The virtual operations of the TraceListener are implemented here
/// like Close(), Dispose() etc.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class TraceListenerWrapper :
#if !WINDOWS_UWP && !WIN_UI
TextWriterTraceListener,
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListenerManager.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListenerManager.cs
index 9aff10dc67..0eec6af8f1 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListenerManager.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceListenerManager.cs
@@ -1,10 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-#if !WINDOWS_UWP && !WIN_UI
-using System.Diagnostics;
-#endif
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
@@ -13,6 +9,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
/// Internal implementation of TraceListenerManager exposed to the user.
/// Responsible for performing Add(), Remove(), Close(), Dispose() operations on traceListener object.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class TraceListenerManager : ITraceListenerManager
{
#if !WINDOWS_UWP && !WIN_UI
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceLogger.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceLogger.cs
index 73e691f00c..60234199e6 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceLogger.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TraceLogger.cs
@@ -9,6 +9,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// A service to log any trace messages from the adapter that would be shown in *.TpTrace files.
///
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public class AdapterTraceLogger : IAdapterTraceLogger
{
///
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainUtilities.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainUtilities.cs
index 0d74da2d04..a9f194d52a 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainUtilities.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainUtilities.cs
@@ -3,10 +3,6 @@
#if NETFRAMEWORK
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Reflection;
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -45,7 +41,7 @@ internal static void SetAppDomainFrameworkVersionBasedOnTestSource(AppDomainSetu
{
if (GetTargetFrameworkVersionFromVersionString(frameworkVersionString).CompareTo(Version45) > 0)
{
- PropertyInfo pInfo = typeof(AppDomainSetup).GetProperty(Constants.TargetFrameworkName);
+ PropertyInfo? pInfo = typeof(AppDomainSetup).GetProperty(Constants.TargetFrameworkName);
pInfo?.SetValue(setup, frameworkVersionString, null);
}
}
@@ -257,7 +253,7 @@ internal static Version GetTargetFrameworkVersionFromVersionString(string versio
appDomainCultureHelper?.SetUICulture(uiCulture);
}
- private class AppDomainCultureHelper : MarshalByRefObject
+ private sealed class AppDomainCultureHelper : MarshalByRefObject
{
#pragma warning disable CA1822 // Mark members as static - Should not be static for our need
public void SetUICulture(CultureInfo uiCulture) => CultureInfo.DefaultThreadCurrentUICulture = uiCulture;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainWrapper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainWrapper.cs
index ce5057c5b6..1fd4e53f75 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainWrapper.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AppDomainWrapper.cs
@@ -10,11 +10,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// Abstraction over the AppDomain APIs.
///
-internal class AppDomainWrapper : IAppDomain
+internal sealed class AppDomainWrapper : IAppDomain
{
- public AppDomain CreateDomain(string friendlyName, Evidence securityInfo, AppDomainSetup info) => AppDomain.CreateDomain(friendlyName, securityInfo, info);
+ public AppDomain CreateDomain(string friendlyName, Evidence securityInfo, AppDomainSetup info)
+ => AppDomain.CreateDomain(friendlyName, securityInfo, info);
- public void Unload(AppDomain appDomain) => AppDomain.Unload(appDomain);
+ public void Unload(AppDomain appDomain)
+ => AppDomain.Unload(appDomain);
}
#endif
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ApplicationStateGuard.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ApplicationStateGuard.cs
index 1028c8e7da..6e6c1f2bd7 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ApplicationStateGuard.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ApplicationStateGuard.cs
@@ -1,9 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
-
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter;
internal static class ApplicationStateGuard
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AssemblyUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AssemblyUtility.cs
index 8c6511384d..18ddbf8cd5 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AssemblyUtility.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/AssemblyUtility.cs
@@ -4,10 +4,6 @@
#if !WINDOWS_UWP
#if NETFRAMEWORK
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Reflection;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
@@ -19,6 +15,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Uti
///
/// Utility for assembly specific functionality.
///
+[SuppressMessage("Performance", "CA1852: Seal internal types", Justification = "Overrides required for testability")]
internal class AssemblyUtility
#if NETFRAMEWORK
: IAssemblyUtility
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs
index a787c71b3e..6cf7c7fade 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs
@@ -3,11 +3,6 @@
#if !WINDOWS_UWP
-using System.Collections;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Reflection;
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -17,7 +12,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Uti
///
/// The deployment utility.
///
-internal class DeploymentItemUtility
+internal sealed class DeploymentItemUtility
{
// REVIEW: it would be better if this was a ReflectionHelper, because helper is able to cache. But we don't have reflection helper here, because this is platform services dll.
private readonly ReflectionUtility _reflectionUtility;
@@ -79,7 +74,7 @@ internal IList GetClassLevelDeploymentItems(Type type, ICollecti
/// The warning message if it is an invalid deployment item.
/// Returns true if it is a valid deployment item.
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "Internal method.")]
- internal static bool IsValidDeploymentItem([NotNullWhen(true)] string? sourcePath, [NotNullWhen(true)] string? relativeOutputDirectory, out string warning)
+ internal static bool IsValidDeploymentItem([NotNullWhen(true)] string? sourcePath, [NotNullWhen(true)] string? relativeOutputDirectory, [NotNullWhen(false)] out string? warning)
{
if (StringEx.IsNullOrEmpty(sourcePath))
{
@@ -105,7 +100,7 @@ internal static bool IsValidDeploymentItem([NotNullWhen(true)] string? sourcePat
return false;
}
- warning = string.Empty;
+ warning = null;
return true;
}
@@ -264,9 +259,9 @@ private static List GetDeploymentItems(IEnumerable deploymentIte
IList result = new List();
- foreach (KeyValuePair deploymentItemData in deploymentItemsData)
+ foreach ((string? key, string? value) in deploymentItemsData)
{
- AddDeploymentItem(result, new DeploymentItem(deploymentItemData.Key, deploymentItemData.Value));
+ AddDeploymentItem(result, new DeploymentItem(key, value));
}
return result;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs
index 73fdc4278e..af43490bde 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs
@@ -3,10 +3,6 @@
#if !WINDOWS_UWP
-#if NETFRAMEWORK || NETSTANDARD || NETCOREAPP3_1
-using System.Diagnostics;
-#endif
-using System.Globalization;
#if NETFRAMEWORK
using System.Security;
#endif
@@ -20,7 +16,7 @@
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
-internal class DeploymentUtility : DeploymentUtilityBase
+internal sealed class DeploymentUtility : DeploymentUtilityBase
{
public DeploymentUtility()
: base()
@@ -103,8 +99,8 @@ protected override void AddDependenciesOfDeploymentItem(string deploymentItemFil
}
#if NETFRAMEWORK
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
- protected void ProcessNewStorage(string testSource, IList deploymentItems, IList warnings)
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
+ public void ProcessNewStorage(string testSource, IList deploymentItems, IList warnings)
{
// Add deployment items and process .config files only for storages we have not processed before.
if (!DeploymentItemUtility.IsValidDeploymentItem(testSource, string.Empty, out string? errorMessage))
@@ -136,7 +132,7 @@ protected void ProcessNewStorage(string testSource, IList deploy
}
}
- protected IEnumerable GetSatellites(IEnumerable deploymentItems, string testSource, IList warnings)
+ public IEnumerable GetSatellites(IEnumerable deploymentItems, string testSource, IList warnings)
{
List satellites = [];
foreach (DeploymentItem item in deploymentItems)
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
index 0fbcabc78e..a63aa0656a 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
@@ -3,9 +3,6 @@
#if !WINDOWS_UWP
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/FileUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/FileUtility.cs
index 905e3e09ef..f97005e844 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/FileUtility.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/FileUtility.cs
@@ -3,14 +3,13 @@
#if !WINDOWS_UWP
-using System.Globalization;
-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
+[SuppressMessage("Performance", "CA1852: Seal internal types", Justification = "Overrides required for mocking")]
internal class FileUtility
{
private readonly AssemblyUtility _assemblyUtility;
@@ -84,7 +83,7 @@ public virtual string GetNextIterationDirectoryName(string parentDirectoryName,
/// Returns empty string on error when specified to continue the run on error,
/// throw on error when specified to abort the run on error.
///
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
public virtual string CopyFileOverwrite(string source, string destination, out string? warning)
{
DebugEx.Assert(!StringEx.IsNullOrEmpty(source), "source should not be null.");
@@ -222,7 +221,7 @@ public static string TryConvertPathToRelative(string path, string rootDir)
/// them.
///
/// The root directory to clear.
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
public virtual void DeleteDirectories(string filePath)
{
Guard.NotNullOrWhiteSpace(filePath);
@@ -253,7 +252,7 @@ public virtual void DeleteDirectories(string filePath)
///
/// path to symbols file.
/// Pdb file name or null if non-existent.
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
private static string? GetSymbolsFileName(string? path)
{
if (StringEx.IsNullOrEmpty(path) || path.IndexOfAny(Path.GetInvalidPathChars()) != -1)
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/IAssemblyUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/IAssemblyUtility.cs
index e180d9eada..1f923fb408 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/IAssemblyUtility.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/IAssemblyUtility.cs
@@ -3,8 +3,6 @@
#if NETFRAMEWORK
-using System.Reflection;
-
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
internal interface IAssemblyUtility
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/RandomIntPermutation.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/RandomIntPermutation.cs
index 668da63a8a..a18ca30068 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/RandomIntPermutation.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/RandomIntPermutation.cs
@@ -2,16 +2,13 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if NETFRAMEWORK
-
-using System.Collections;
-
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// Permutation of integers from 0 to (numberOfObjects - 1), in random order and in the end all values are returned.
/// Used to get random permutation for data row access in data driven test.
///
-internal class RandomIntPermutation : IEnumerable
+internal sealed class RandomIntPermutation : IEnumerable
{
private readonly int[] _objects;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs
index 5ebf1ee8d2..b9fe555b32 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs
@@ -3,16 +3,12 @@
#if !WINDOWS_UWP
-#if NETFRAMEWORK
-using System.Collections;
-#endif
-using System.Reflection;
-
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
///
/// Utility for reflection API's.
///
+[SuppressMessage("Performance", "CA1852: Seal internal types", Justification = "Overrides required for testability")]
internal class ReflectionUtility
{
///
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/SequentialIntPermutation.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/SequentialIntPermutation.cs
index c77c8fe83d..179aeb21f1 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/SequentialIntPermutation.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/SequentialIntPermutation.cs
@@ -3,15 +3,13 @@
#if NETFRAMEWORK
-using System.Collections;
-
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
///
/// Permutation of integers from 0 to (numberOfObjects - 1) returned by increment of 1.
/// Used to get sequential permutation for data row access in data driven test.
///
-internal class SequentialIntPermutation : IEnumerable
+internal sealed class SequentialIntPermutation : IEnumerable
{
private readonly int _numberOfObjects;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/VSInstallationUtilities.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/VSInstallationUtilities.cs
index 1775e61d6c..87f29d19a1 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/VSInstallationUtilities.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/VSInstallationUtilities.cs
@@ -3,13 +3,17 @@
#if NETFRAMEWORK
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
using static System.String;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
+#if RELEASE
+#if NET6_0_OR_GREATER
+[Obsolete(Constants.PublicTypeObsoleteMessage, DiagnosticId = "MSTESTOBS")]
+#else
+[Obsolete(Constants.PublicTypeObsoleteMessage)]
+#endif
+#endif
public static class VSInstallationUtilities
{
///
@@ -33,7 +37,7 @@ public static class VSInstallationUtilities
/// Gets the visual studio installation path on the local machine.
///
/// VS install path.
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Need to ignore failures to read the registry settings")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Need to ignore failures to read the registry settings")]
public static string? VSInstallPath
{
get
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/XmlUtilities.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/XmlUtilities.cs
index afbef47053..6c23bce1db 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/XmlUtilities.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/XmlUtilities.cs
@@ -3,15 +3,11 @@
#if NETFRAMEWORK
-using System.Globalization;
-using System.Reflection;
-using System.Text;
-using System.Xml;
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
+[SuppressMessage("Performance", "CA1852: Seal internal types", Justification = "Overrides required for mocking")]
internal class XmlUtilities
{
private const string XmlNamespace = "urn:schemas-microsoft-com:asm.v1";
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldAvoidConditionalAccessFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldAvoidConditionalAccessFixer.cs
new file mode 100644
index 0000000000..60e8614c80
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldAvoidConditionalAccessFixer.cs
@@ -0,0 +1,239 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Collections.Immutable;
+using System.Composition;
+
+using Analyzer.Utilities;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+
+using MSTest.Analyzers.Helpers;
+
+namespace MSTest.Analyzers;
+
+[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertionArgsShouldAvoidConditionalAccessFixer))]
+[Shared]
+public sealed class AssertionArgsShouldAvoidConditionalAccessFixer : CodeFixProvider
+{
+ ///
+ /// The scenario that is complicating this code fix is if we have multiple diagnostics that are doing conditional access
+ /// on the same expression. In that case, we need to ensure that we don't add multiple Assert.IsNotNull calls.
+ /// The first idea was to iterate through the existing statements, and if we found Assert.IsNotNull with
+ /// the relevant expression, we don't add it again. However, this approach works for iterative codefix application
+ /// only, and doesn't work with the BatchFixAllProvider. The BatchFixAllProvider works by applying individual fixes
+ /// completely in isolation, then merging the text changes.
+ /// This means, every invocation of the code action will not see that Assert.IsNotNull was added by another.
+ /// So, we provide our own FixAllProvider.
+ /// This FixAllProvider will reuse the same DocumentEditor across all the code actions.
+ ///
+ private sealed class CustomFixAll : DocumentBasedFixAllProvider
+ {
+ protected override async Task FixAllAsync(FixAllContext fixAllContext, Document document, ImmutableArray diagnostics)
+ {
+ SyntaxNode root = await document.GetRequiredSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
+ DocumentEditor editor = await DocumentEditor.CreateAsync(document, fixAllContext.CancellationToken);
+ Document currentDocument = document;
+ foreach (Diagnostic diagnostic in diagnostics)
+ {
+ SyntaxNode assertInvocation = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
+ // We need to track the assert invocation so that the individual 'SingleFixCodeAction's can get the up-to-date node
+ // from the most recent tree.
+ // Having the most recent node is important for IsNullAssertAlreadyPresent to work properly.
+ // We get the most recent node via editor.GetChangedRoot().GetCurrentNode(...)
+ editor.TrackNode(assertInvocation);
+ }
+
+ foreach (Diagnostic diagnostic in diagnostics)
+ {
+ SyntaxNode conditionalAccess = root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true);
+ SyntaxNode assertInvocation = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
+ if (conditionalAccess is not ConditionalAccessExpressionSyntax conditionalAccessExpressionSyntax ||
+ assertInvocation is not InvocationExpressionSyntax invocationExpressionSyntax)
+ {
+ continue;
+ }
+
+ var codeAction = new SingleFixCodeAction(currentDocument, conditionalAccessExpressionSyntax, invocationExpressionSyntax);
+ currentDocument = codeAction.ApplyFix(editor);
+ }
+
+ return editor.GetChangedDocument();
+ }
+ }
+
+ public sealed override ImmutableArray FixableDiagnosticIds { get; }
+ = ImmutableArray.Create(DiagnosticIds.AssertionArgsShouldAvoidConditionalAccessRuleId);
+
+ public override FixAllProvider GetFixAllProvider()
+ // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/FixAllProvider.md for more information on Fix All Providers
+ => new CustomFixAll();
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ SyntaxNode root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ Diagnostic diagnostic = context.Diagnostics[0];
+
+ SyntaxNode conditionalAccess = root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true);
+ SyntaxNode assertInvocation = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
+ if (conditionalAccess is not ConditionalAccessExpressionSyntax conditionalAccessExpressionSyntax ||
+ assertInvocation is not InvocationExpressionSyntax invocationExpressionSyntax)
+ {
+ return;
+ }
+
+ context.RegisterCodeFix(
+ new SingleFixCodeAction(context.Document, conditionalAccessExpressionSyntax, invocationExpressionSyntax),
+ diagnostic);
+ }
+
+ private sealed class SingleFixCodeAction : CodeAction
+ {
+ private readonly Document _document;
+ private readonly ConditionalAccessExpressionSyntax _conditionalAccessExpressionSyntax;
+ private readonly InvocationExpressionSyntax _invocationExpressionSyntax;
+
+ public SingleFixCodeAction(Document document, ConditionalAccessExpressionSyntax conditionalAccessExpressionSyntax, InvocationExpressionSyntax invocationExpressionSyntax)
+ {
+ _document = document;
+ _conditionalAccessExpressionSyntax = conditionalAccessExpressionSyntax;
+ _invocationExpressionSyntax = invocationExpressionSyntax;
+ }
+
+ public override string Title { get; } = CodeFixResources.AssertionArgsShouldAvoidConditionalAccessFix;
+
+ public override string? EquivalenceKey => nameof(AssertionArgsShouldAvoidConditionalAccessFixer);
+
+ protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken)
+ {
+ DocumentEditor editor = await DocumentEditor.CreateAsync(_document, cancellationToken).ConfigureAwait(false);
+ return ApplyFix(editor);
+ }
+
+ internal Document ApplyFix(DocumentEditor editor)
+ {
+ ExpressionSyntax expressionCheckedForNull = _conditionalAccessExpressionSyntax.Expression;
+ bool isNullAssertAlreadyPresent = IsNullAssertAlreadyPresent(expressionCheckedForNull, editor.GetChangedRoot().GetCurrentNode(_invocationExpressionSyntax) ?? _invocationExpressionSyntax);
+
+ // Easier than correctly reconstructing the syntax node manually, but not ideal.
+ ExpressionSyntax parsedExpression = SyntaxFactory.ParseExpression($"{expressionCheckedForNull.ToFullString()}{_conditionalAccessExpressionSyntax.WhenNotNull}");
+ parsedExpression = parsedExpression.WithTriviaFrom(_conditionalAccessExpressionSyntax);
+
+ editor.ReplaceNode(_conditionalAccessExpressionSyntax, parsedExpression);
+
+ if (!isNullAssertAlreadyPresent)
+ {
+ ExpressionStatementSyntax assertIsNotNull = SyntaxFactory.ExpressionStatement(
+ SyntaxFactory.InvocationExpression(
+ SyntaxFactory.MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ SyntaxFactory.IdentifierName("Assert"),
+ SyntaxFactory.IdentifierName("IsNotNull")))
+ .WithArgumentList(
+ SyntaxFactory.ArgumentList(
+ SyntaxFactory.SingletonSeparatedList(
+ SyntaxFactory.Argument(expressionCheckedForNull)))));
+ if (_invocationExpressionSyntax.Parent is ExpressionStatementSyntax expressionStatement)
+ {
+ editor.InsertBefore(expressionStatement, assertIsNotNull);
+ }
+ else if (_invocationExpressionSyntax.Parent is ArrowExpressionClauseSyntax arrowExpressionClauseSyntax)
+ {
+ // The following types are where ArrowExpressionClause can appear.
+ // BaseMethodDeclarationSyntax: ConstructorDeclarationSyntax, ConversionOperatorDeclarationSyntax, DestructorDeclarationSyntax, MethodDeclarationSyntax, OperatorDeclarationSyntax
+ // AccessorDeclarationSyntax, IndexerDeclarationSyntax, PropertyDeclarationSyntax, LocalFunctionStatementSyntax
+ //
+ // PropertyDeclarationSyntax and IndexerDeclarationSyntax don't make sense so we won't handle it.
+ if (arrowExpressionClauseSyntax.Parent is BaseMethodDeclarationSyntax parentBaseMethod)
+ {
+ editor.ReplaceNode(
+ parentBaseMethod,
+ (node, _) =>
+ {
+ var parentBaseMethod = (BaseMethodDeclarationSyntax)node;
+ return parentBaseMethod
+ .WithExpressionBody(null)
+ .WithSemicolonToken(default)
+ .WithBody(SyntaxFactory.Block(
+ assertIsNotNull,
+ SyntaxFactory.ExpressionStatement(parentBaseMethod.ExpressionBody!.Expression)));
+ });
+ }
+ else if (arrowExpressionClauseSyntax.Parent is AccessorDeclarationSyntax parentAccessor)
+ {
+ editor.ReplaceNode(
+ parentAccessor,
+ (node, _) =>
+ {
+ var parentAccessor = (AccessorDeclarationSyntax)node;
+ return parentAccessor
+ .WithExpressionBody(null)
+ .WithSemicolonToken(default)
+ .WithBody(SyntaxFactory.Block(
+ assertIsNotNull,
+ SyntaxFactory.ExpressionStatement(parentAccessor.ExpressionBody!.Expression)));
+ });
+ }
+ else if (arrowExpressionClauseSyntax.Parent is LocalFunctionStatementSyntax parentLocalFunction)
+ {
+ editor.ReplaceNode(
+ parentLocalFunction,
+ (node, _) =>
+ {
+ var parentLocalFunction = (LocalFunctionStatementSyntax)node;
+ return parentLocalFunction
+ .WithExpressionBody(null)
+ .WithSemicolonToken(default)
+ .WithBody(SyntaxFactory.Block(
+ assertIsNotNull,
+ SyntaxFactory.ExpressionStatement(parentLocalFunction.ExpressionBody!.Expression)));
+ });
+ }
+ }
+ }
+
+ return editor.GetChangedDocument();
+ }
+ }
+
+ private static bool IsNullAssertAlreadyPresent(SyntaxNode expressionCheckedForNull, InvocationExpressionSyntax invocationExpressionSyntax)
+ {
+ if (invocationExpressionSyntax.Parent?.Parent is not BlockSyntax blockSyntax)
+ {
+ return false;
+ }
+
+ foreach (StatementSyntax statement in blockSyntax.Statements)
+ {
+ if (statement is not ExpressionStatementSyntax expressionStatement)
+ {
+ continue;
+ }
+
+ // We expect Assert.IsNull to be present before the invocation expression in question.
+ if (expressionStatement.Expression == invocationExpressionSyntax)
+ {
+ return false;
+ }
+
+ if (expressionStatement.Expression is InvocationExpressionSyntax invocation)
+ {
+ SimpleNameSyntax? methodName =
+ invocation.Expression as IdentifierNameSyntax ?? (invocation.Expression as MemberAccessExpressionSyntax)?.Name;
+ if ((methodName?.Identifier.Value as string) == "IsNotNull" &&
+ invocation.ArgumentList.Arguments.Count > 0 &&
+ invocation.ArgumentList.Arguments[0].Expression.IsEquivalentTo(expressionCheckedForNull))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldBePassedInCorrectOrderFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldBePassedInCorrectOrderFixer.cs
index 6b0ae32313..a949ea4dfd 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldBePassedInCorrectOrderFixer.cs
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/AssertionArgsShouldBePassedInCorrectOrderFixer.cs
@@ -56,8 +56,8 @@ private static Task SwapArgumentsAsync(Document document, SyntaxNode r
SeparatedSyntaxList arguments = invocationExpr.ArgumentList.Arguments;
- ArgumentSyntax expectedArg = arguments.FirstOrDefault(IsExpectedArgument);
- ArgumentSyntax actualArg = arguments.FirstOrDefault(IsActualArgument);
+ ArgumentSyntax? expectedArg = arguments.FirstOrDefault(IsExpectedArgument);
+ ArgumentSyntax? actualArg = arguments.FirstOrDefault(IsActualArgument);
// Handle positional arguments if named arguments are not found
if (expectedArg == null || actualArg == null)
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/AvoidAssertAreSameWithValueTypesFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/AvoidAssertAreSameWithValueTypesFixer.cs
new file mode 100644
index 0000000000..81f5f78d5c
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/AvoidAssertAreSameWithValueTypesFixer.cs
@@ -0,0 +1,72 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Collections.Immutable;
+using System.Composition;
+
+using Analyzer.Utilities;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+
+using MSTest.Analyzers.Helpers;
+
+namespace MSTest.Analyzers;
+
+[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AvoidAssertAreSameWithValueTypesFixer))]
+[Shared]
+public sealed class AvoidAssertAreSameWithValueTypesFixer : CodeFixProvider
+{
+ public sealed override ImmutableArray FixableDiagnosticIds { get; }
+ = ImmutableArray.Create(DiagnosticIds.AvoidAssertAreSameWithValueTypesRuleId);
+
+ 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);
+ Diagnostic diagnostic = context.Diagnostics[0];
+
+ string? replacement = diagnostic.Properties[AvoidAssertAreSameWithValueTypesAnalyzer.ReplacemenyKey]
+ ?? throw ApplicationStateGuard.Unreachable();
+
+ SyntaxNode diagnosticNode = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
+ if (diagnosticNode is not InvocationExpressionSyntax invocation)
+ {
+ Debug.Fail($"Is this an interesting scenario where IInvocationOperation for Assert call isn't associated with InvocationExpressionSyntax? SyntaxNode type: '{diagnosticNode.GetType()}', Text: '{diagnosticNode.GetText()}'");
+ return;
+ }
+
+ SyntaxNode methodNameIdentifier = invocation.Expression;
+ if (methodNameIdentifier is MemberAccessExpressionSyntax memberAccess)
+ {
+ methodNameIdentifier = memberAccess.Name;
+ }
+
+ if (methodNameIdentifier is not SimpleNameSyntax simpleNameSyntax)
+ {
+ Debug.Fail($"Is this an interesting scenario where we are unable to retrieve SimpleNameSyntax corresponding to the assert method? SyntaxNode type: '{methodNameIdentifier}', Text: '{methodNameIdentifier.GetText()}'.");
+ return;
+ }
+
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title: string.Format(CultureInfo.InvariantCulture, CodeFixResources.AvoidAssertAreSameWithValueTypesFix, replacement),
+ ct => FixMethodNameAsync(context.Document, simpleNameSyntax, replacement, ct),
+ equivalenceKey: nameof(AvoidAssertAreSameWithValueTypesFixer)),
+ diagnostic);
+ }
+
+ private static async Task FixMethodNameAsync(Document document, SimpleNameSyntax simpleNameSyntax, string properAssertMethodName, CancellationToken cancellationToken)
+ {
+ DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
+ editor.ReplaceNode(simpleNameSyntax, simpleNameSyntax.WithIdentifier(SyntaxFactory.Identifier(properAssertMethodName)));
+ return editor.GetChangedDocument();
+ }
+}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/AvoidExpectedExceptionAttributeFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/AvoidExpectedExceptionAttributeFixer.cs
index cf08f96300..ee68f392bb 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/AvoidExpectedExceptionAttributeFixer.cs
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/AvoidExpectedExceptionAttributeFixer.cs
@@ -42,10 +42,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
return;
}
- if (diagnostic.Properties.ContainsKey(DiagnosticDescriptorHelper.CannotFixPropertyKey))
- {
- return;
- }
+ bool allowDerivedTypes = diagnostic.Properties.ContainsKey(AvoidExpectedExceptionAttributeAnalyzer.AllowDerivedTypesKey);
// Find the method declaration identified by the diagnostic.
MethodDeclarationSyntax methodDeclaration = syntaxToken.Parent.AncestorsAndSelf().OfType().First();
@@ -84,35 +81,105 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
context.RegisterCodeFix(
CodeAction.Create(
title: CodeFixResources.UseAssertThrowsExceptionOnLastStatementFix,
- createChangedDocument: c => WrapLastStatementWithAssertThrowsExceptionAsync(context.Document, methodDeclaration, attributeSyntax, exceptionTypeSymbol, c),
+ createChangedDocument: c => WrapLastStatementWithAssertThrowsExceptionAsync(context.Document, methodDeclaration, attributeSyntax, exceptionTypeSymbol, allowDerivedTypes, c),
equivalenceKey: nameof(AvoidExpectedExceptionAttributeFixer)),
diagnostic);
}
+ private static (SyntaxNode ExpressionOrStatement, SyntaxNode NodeToReplace)? TryGetExpressionOfInterestAndNodeToFromBlockSyntax(BlockSyntax? block)
+ {
+ if (block is null)
+ {
+ return null;
+ }
+
+ for (int i = block.Statements.Count - 1; i >= 0; i--)
+ {
+ StatementSyntax statement = block.Statements[i];
+
+ if (statement is LockStatementSyntax lockStatement)
+ {
+ if (lockStatement.Statement is BlockSyntax lockBlock)
+ {
+ if (TryGetExpressionOfInterestAndNodeToFromBlockSyntax(lockBlock) is { } resultFromLock)
+ {
+ return resultFromLock;
+ }
+
+ continue;
+ }
+
+ statement = lockStatement.Statement;
+ }
+
+ if (statement is LocalFunctionStatementSyntax or EmptyStatementSyntax)
+ {
+ continue;
+ }
+ else if (statement is BlockSyntax nestedBlock)
+ {
+ if (TryGetExpressionOfInterestAndNodeToFromBlockSyntax(nestedBlock) is { } expressionFromNestedBlock)
+ {
+ return expressionFromNestedBlock;
+ }
+
+ // The BlockSyntax doesn't have any meaningful statements/expressions.
+ // Ignore it.
+ continue;
+ }
+ else if (statement is ExpressionStatementSyntax expressionStatement)
+ {
+ return (expressionStatement.Expression, statement);
+ }
+ else if (statement is LocalDeclarationStatementSyntax localDeclarationStatementSyntax &&
+ localDeclarationStatementSyntax.Declaration.Variables.Count == 1 &&
+ localDeclarationStatementSyntax.Declaration.Variables[0].Initializer is { } initializer)
+ {
+ return (initializer.Value, statement);
+ }
+
+ return (statement, statement);
+ }
+
+ return null;
+ }
+
+ private static (SyntaxNode ExpressionOrStatement, SyntaxNode NodeToReplace)? TryGetExpressionOfInterestAndNodeToFromExpressionBody(MethodDeclarationSyntax method)
+ => method.ExpressionBody is null ? null : (method.ExpressionBody.Expression, method.ExpressionBody.Expression);
+
private static async Task WrapLastStatementWithAssertThrowsExceptionAsync(
Document document,
MethodDeclarationSyntax methodDeclaration,
SyntaxNode attributeSyntax,
ITypeSymbol exceptionTypeSymbol,
+ bool allowDerivedTypes,
CancellationToken cancellationToken)
{
DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
editor.RemoveNode(attributeSyntax);
- SyntaxNode? oldStatement = (SyntaxNode?)methodDeclaration.Body?.Statements.LastOrDefault() ?? methodDeclaration.ExpressionBody?.Expression;
- if (oldStatement is null)
+ (SyntaxNode ExpressionOrStatement, SyntaxNode NodeToReplace)? expressionAndNodeToReplace = TryGetExpressionOfInterestAndNodeToFromBlockSyntax(methodDeclaration.Body)
+ ?? TryGetExpressionOfInterestAndNodeToFromExpressionBody(methodDeclaration);
+
+ if (expressionAndNodeToReplace is null)
{
return editor.GetChangedDocument();
}
- SyntaxNode newLambdaExpression = oldStatement switch
+ SyntaxGenerator generator = editor.Generator;
+ SyntaxNode expressionToUseInLambda = expressionAndNodeToReplace.Value.ExpressionOrStatement;
+
+ expressionToUseInLambda = expressionToUseInLambda switch
{
- ExpressionStatementSyntax oldLambdaExpression => oldLambdaExpression.Expression,
- _ => oldStatement,
+ ThrowStatementSyntax { Expression: not null } throwStatement => generator.ThrowExpression(throwStatement.Expression),
+ // This is the case when the last statement of the method body is a loop for example (e.g, for, foreach, while, do while).
+ // It can also happen for using statement, or switch statement.
+ // In that case, we need to wrap in a block syntax (i.e, curly braces)
+ StatementSyntax expressionToUseAsStatement => SyntaxFactory.Block(expressionToUseAsStatement),
+ _ => expressionToUseInLambda.WithoutTrivia(),
};
- SyntaxGenerator generator = editor.Generator;
- newLambdaExpression = generator.VoidReturningLambdaExpression(newLambdaExpression);
+ SyntaxNode newLambdaExpression = generator.VoidReturningLambdaExpression(expressionToUseInLambda);
bool containsAsyncCode = newLambdaExpression.DescendantNodesAndSelf().Any(n => n is AwaitExpressionSyntax);
if (containsAsyncCode)
@@ -123,7 +190,14 @@ private static async Task WrapLastStatementWithAssertThrowsExceptionAs
SyntaxNode newStatement = generator.InvocationExpression(
generator.MemberAccessExpression(
generator.IdentifierName("Assert"),
- generator.GenericName(containsAsyncCode ? "ThrowsExceptionAsync" : "ThrowsException", [exceptionTypeSymbol])),
+ generator.GenericName(
+ (containsAsyncCode, allowDerivedTypes) switch
+ {
+ (false, false) => "ThrowsExactly",
+ (false, true) => "Throws",
+ (true, false) => "ThrowsExactlyAsync",
+ (true, true) => "ThrowsAsync",
+ }, [exceptionTypeSymbol])),
newLambdaExpression);
if (containsAsyncCode)
@@ -137,7 +211,7 @@ private static async Task WrapLastStatementWithAssertThrowsExceptionAs
newStatement = generator.ExpressionStatement(newStatement);
}
- editor.ReplaceNode(oldStatement, newStatement);
+ editor.ReplaceNode(expressionAndNodeToReplace.Value.NodeToReplace, newStatement.WithTriviaFrom(expressionAndNodeToReplace.Value.NodeToReplace));
return editor.GetChangedDocument();
}
}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.Designer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.Designer.cs
index 442d0dc282..a32c10e0bf 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.Designer.cs
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.Designer.cs
@@ -78,6 +78,24 @@ internal static string AssemblyInitializeShouldBeValidCodeFix {
}
}
+ ///
+ /// Looks up a localized string similar to Move conditional access in assertion to separate 'Assert.IsNotNull' check.
+ ///
+ internal static string AssertionArgsShouldAvoidConditionalAccessFix {
+ get {
+ return ResourceManager.GetString("AssertionArgsShouldAvoidConditionalAccessFix", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Use '{0}'.
+ ///
+ internal static string AvoidAssertAreSameWithValueTypesFix {
+ get {
+ return ResourceManager.GetString("AvoidAssertAreSameWithValueTypesFix", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Change method accessibility to 'private'.
///
@@ -203,5 +221,23 @@ internal static string UseAttributeOnTestMethodFix {
return ResourceManager.GetString("UseAttributeOnTestMethodFix", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to Use '{0}'.
+ ///
+ internal static string UseNewerAssertThrows {
+ get {
+ return ResourceManager.GetString("UseNewerAssertThrows", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Use '{0}'.
+ ///
+ internal static string UseProperAssertMethodsFix {
+ get {
+ return ResourceManager.GetString("UseProperAssertMethodsFix", resourceCulture);
+ }
+ }
}
}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.resx b/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.resx
index 6e97d9e1a8..50c67bba6c 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.resx
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/CodeFixResources.resx
@@ -165,4 +165,16 @@
Use 'Assert.ThrowsException<T>' instead of '[ExpectedException]' attribute
+
+ Use '{0}'
+
+
+ Use '{0}'
+
+
+ Move conditional access in assertion to separate 'Assert.IsNotNull' check
+
+
+ Use '{0}'
+
\ No newline at end of file
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferAssertFailOverAlwaysFalseConditionsFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferAssertFailOverAlwaysFalseConditionsFixer.cs
index 56966e24e2..7b5379e0c9 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferAssertFailOverAlwaysFalseConditionsFixer.cs
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferAssertFailOverAlwaysFalseConditionsFixer.cs
@@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Text;
@@ -44,22 +45,28 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
context.RegisterCodeFix(
CodeAction.Create(
CodeFixResources.ReplaceWithFailAssertionFix,
- ct => SwapArgumentsAsync(context.Document, invocationExpr, ct),
+ ct => UseAssertFailAsync(context.Document, invocationExpr, diagnostic.AdditionalLocations, ct),
nameof(PreferAssertFailOverAlwaysFalseConditionsFixer)),
context.Diagnostics);
}
}
- private static async Task SwapArgumentsAsync(Document document, InvocationExpressionSyntax invocationExpr, CancellationToken cancellationToken)
+ private static async Task UseAssertFailAsync(Document document, InvocationExpressionSyntax invocationExpr, IReadOnlyList additionalLocations, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
SyntaxGenerator generator = editor.Generator;
- SyntaxNode newInvocationExpr = generator.InvocationExpression(
+ var newInvocationExpr = (InvocationExpressionSyntax)generator.InvocationExpression(
generator.MemberAccessExpression(generator.IdentifierName("Assert"), "Fail"));
+ if (additionalLocations.Count >= 1)
+ {
+ IEnumerable arguments = additionalLocations.Select(location => (ArgumentSyntax)invocationExpr.FindNode(location.SourceSpan));
+ newInvocationExpr = newInvocationExpr.WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(arguments)));
+ }
+
editor.ReplaceNode(invocationExpr, newInvocationExpr);
return editor.GetChangedDocument();
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferConstructorOverTestInitializeFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferConstructorOverTestInitializeFixer.cs
index 7b02f31dc8..edf1f99822 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferConstructorOverTestInitializeFixer.cs
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferConstructorOverTestInitializeFixer.cs
@@ -43,7 +43,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
}
// Find the method declaration identified by the diagnostic.
- MethodDeclarationSyntax methodDeclaration = syntaxToken.Parent.AncestorsAndSelf().OfType().FirstOrDefault();
+ MethodDeclarationSyntax? methodDeclaration = syntaxToken.Parent.AncestorsAndSelf().OfType().FirstOrDefault();
if (methodDeclaration == null)
{
return;
@@ -64,7 +64,7 @@ private static async Task ReplaceTestInitializeWithConstructorAsync(Do
// Find the class containing the method
if (testInitializeMethod.Parent is ClassDeclarationSyntax containingClass)
{
- ConstructorDeclarationSyntax existingConstructor = containingClass.Members
+ ConstructorDeclarationSyntax? existingConstructor = containingClass.Members
.OfType()
.FirstOrDefault();
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferDisposeOverTestCleanupFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferDisposeOverTestCleanupFixer.cs
index 1c844f6f61..730be4dc58 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferDisposeOverTestCleanupFixer.cs
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferDisposeOverTestCleanupFixer.cs
@@ -44,7 +44,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
}
// Find the TestCleanup method declaration identified by the diagnostic.
- MethodDeclarationSyntax testCleanupMethod = syntaxToken.Parent.AncestorsAndSelf().OfType().FirstOrDefault();
+ MethodDeclarationSyntax? testCleanupMethod = syntaxToken.Parent.AncestorsAndSelf().OfType().FirstOrDefault();
if (testCleanupMethod == null ||
!IsTestCleanupMethodValid(testCleanupMethod) ||
testCleanupMethod.Parent is not TypeDeclarationSyntax containingType)
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestInitializeOverConstructorFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestInitializeOverConstructorFixer.cs
index 6f8b9a2923..c48bdbe928 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestInitializeOverConstructorFixer.cs
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/PreferTestInitializeOverConstructorFixer.cs
@@ -43,7 +43,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
}
// Find the constructor declaration identified by the diagnostic.
- ConstructorDeclarationSyntax constructorDeclaration = syntaxToken.Parent.AncestorsAndSelf().OfType().FirstOrDefault();
+ ConstructorDeclarationSyntax? constructorDeclaration = syntaxToken.Parent.AncestorsAndSelf().OfType().FirstOrDefault();
if (constructorDeclaration == null)
{
return;
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/UseNewerAssertThrowsFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/UseNewerAssertThrowsFixer.cs
new file mode 100644
index 0000000000..587c039756
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/UseNewerAssertThrowsFixer.cs
@@ -0,0 +1,156 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Collections.Immutable;
+using System.Composition;
+
+using Analyzer.Utilities;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Simplification;
+
+using MSTest.Analyzers.Helpers;
+
+namespace MSTest.Analyzers;
+
+[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseNewerAssertThrowsFixer))]
+[Shared]
+public sealed class UseNewerAssertThrowsFixer : CodeFixProvider
+{
+ public sealed override ImmutableArray FixableDiagnosticIds { get; }
+ = ImmutableArray.Create(DiagnosticIds.UseNewerAssertThrowsRuleId);
+
+ 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);
+ Diagnostic diagnostic = context.Diagnostics[0];
+
+ SyntaxNode diagnosticNode = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
+ if (diagnosticNode is not InvocationExpressionSyntax invocation)
+ {
+ Debug.Fail($"Is this an interesting scenario where IInvocationOperation for Assert call isn't associated with InvocationExpressionSyntax? SyntaxNode type: '{diagnosticNode.GetType()}', Text: '{diagnosticNode.GetText()}'");
+ return;
+ }
+
+ SyntaxNode methodNameIdentifier = invocation.Expression;
+ if (methodNameIdentifier is MemberAccessExpressionSyntax memberAccess)
+ {
+ methodNameIdentifier = memberAccess.Name;
+ }
+
+ if (methodNameIdentifier is not GenericNameSyntax genericNameSyntax)
+ {
+ Debug.Fail($"Is this an interesting scenario where we are unable to retrieve GenericNameSyntax corresponding to the assert method? SyntaxNode type: '{methodNameIdentifier}', Text: '{methodNameIdentifier.GetText()}'.");
+ return;
+ }
+
+ string updatedMethodName = genericNameSyntax.Identifier.Text switch
+ {
+ "ThrowsException" => "ThrowsExactly",
+ "ThrowsExceptionAsync" => "ThrowsExactlyAsync",
+ // The analyzer should report a diagnostic only for ThrowsException and ThrowsExceptionAsync
+ _ => throw ApplicationStateGuard.Unreachable(),
+ };
+
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title: string.Format(CultureInfo.InvariantCulture, CodeFixResources.UseNewerAssertThrows, updatedMethodName),
+ ct => Task.FromResult(context.Document.WithSyntaxRoot(UpdateMethodName(new SyntaxEditor(root, context.Document.Project.Solution.Workspace), invocation, genericNameSyntax, updatedMethodName, diagnostic.AdditionalLocations))),
+ equivalenceKey: nameof(UseProperAssertMethodsFixer)),
+ diagnostic);
+ }
+
+ private static SyntaxNode UpdateMethodName(SyntaxEditor editor, InvocationExpressionSyntax invocation, GenericNameSyntax genericNameSyntax, string updatedMethodName, IReadOnlyList additionalLocations)
+ {
+ editor.ReplaceNode(genericNameSyntax, genericNameSyntax.WithIdentifier(SyntaxFactory.Identifier(updatedMethodName).WithTriviaFrom(genericNameSyntax.Identifier)));
+
+ // The object[] parameter to format the message is named parameters in the old ThrowsException[Async] methods, but is named messageArgs in the new ThrowsExactly[Async] methods.
+ if (invocation.ArgumentList.Arguments.FirstOrDefault(arg => arg.NameColon is { Name.Identifier.Text: "parameters" }) is { } arg)
+ {
+ editor.ReplaceNode(arg.NameColon!.Name, arg.NameColon!.Name.WithIdentifier(SyntaxFactory.Identifier("messageArgs").WithTriviaFrom(arg.NameColon.Name.Identifier)));
+ }
+
+ if (additionalLocations.Count != 1)
+ {
+ return editor.GetChangedRoot();
+ }
+
+ // The existing ThrowsException call is using the Func overload. The new ThrowsExactly method does not have this overload, so we need to adjust.
+ // This is a best effort handling.
+ SyntaxNode actionArgument = editor.OriginalRoot.FindNode(additionalLocations[0].SourceSpan, getInnermostNodeForTie: true);
+
+ if (actionArgument is ParenthesizedLambdaExpressionSyntax lambdaSyntax)
+ {
+ if (lambdaSyntax.ExpressionBody is not null)
+ {
+ editor.ReplaceNode(
+ lambdaSyntax.ExpressionBody,
+ AssignToDiscard(lambdaSyntax.ExpressionBody));
+ }
+ else if (lambdaSyntax.Block is not null)
+ {
+ // This is more complex. We need to iterate through all descendants of type ReturnStatementSyntax, and split it into two statements.
+ // The first statement will be an assignment expression to a discard, and the second statement will be 'return;'.
+ // We may even need to add extra braces in case the return statement (for example) is originally inside an if statement without braces.
+ // For example:
+ // if (condition)
+ // return Whatever;
+ // should be converted to:
+ // if (condition)
+ // {
+ // _ = Whatever;
+ // return;
+ // }
+ // Keep in mind: When descending into descendant nodes, we shouldn't descend into potential other lambda expressions or local functions.
+ IEnumerable returnStatements = lambdaSyntax.Block.DescendantNodes(descendIntoChildren: node => node is not (LocalFunctionStatementSyntax or AnonymousFunctionExpressionSyntax)).OfType();
+ foreach (ReturnStatementSyntax returnStatement in returnStatements)
+ {
+ if (returnStatement.Expression is not { } returnExpression)
+ {
+ // This should be an error in user code.
+ continue;
+ }
+
+ ExpressionStatementSyntax returnReplacement = SyntaxFactory.ExpressionStatement(AssignToDiscard(returnStatement.Expression));
+
+ if (returnStatement.Parent is BlockSyntax blockSyntax)
+ {
+ editor.InsertAfter(returnStatement, SyntaxFactory.ReturnStatement());
+ editor.ReplaceNode(returnStatement, returnReplacement);
+ }
+ else
+ {
+ editor.ReplaceNode(
+ returnStatement,
+ SyntaxFactory.Block(
+ returnReplacement,
+ SyntaxFactory.ReturnStatement()));
+ }
+ }
+ }
+ }
+ else if (actionArgument is ExpressionSyntax expressionSyntax)
+ {
+ editor.ReplaceNode(
+ expressionSyntax,
+ SyntaxFactory.ParenthesizedLambdaExpression(
+ SyntaxFactory.ParameterList(),
+ block: null,
+ expressionBody: AssignToDiscard(SyntaxFactory.InvocationExpression(SyntaxFactory.ParenthesizedExpression(expressionSyntax).WithAdditionalAnnotations(Simplifier.Annotation)))));
+ }
+
+ return editor.GetChangedRoot();
+ }
+
+ private static AssignmentExpressionSyntax AssignToDiscard(ExpressionSyntax expression)
+ => SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName("_"), expression);
+}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/UseProperAssertMethodsFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/UseProperAssertMethodsFixer.cs
new file mode 100644
index 0000000000..d8dfaf8a42
--- /dev/null
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/UseProperAssertMethodsFixer.cs
@@ -0,0 +1,207 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Collections.Immutable;
+using System.Composition;
+
+using Analyzer.Utilities;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Formatting;
+
+using MSTest.Analyzers.Helpers;
+
+namespace MSTest.Analyzers;
+
+[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseProperAssertMethodsFixer))]
+[Shared]
+public sealed class UseProperAssertMethodsFixer : CodeFixProvider
+{
+ public sealed override ImmutableArray FixableDiagnosticIds { get; }
+ = ImmutableArray.Create(DiagnosticIds.UseProperAssertMethodsRuleId);
+
+ 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);
+ Diagnostic diagnostic = context.Diagnostics[0];
+ string? mode = diagnostic.Properties[UseProperAssertMethodsAnalyzer.CodeFixModeKey];
+ string? properAssertMethodName = diagnostic.Properties[UseProperAssertMethodsAnalyzer.ProperAssertMethodNameKey];
+ if (mode is null || properAssertMethodName is null)
+ {
+ Debug.Fail($"Both '{nameof(mode)}' and '{properAssertMethodName}' are expected to be non-null.");
+ return;
+ }
+
+ SyntaxNode diagnosticNode = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
+ if (diagnosticNode is not InvocationExpressionSyntax invocation)
+ {
+ Debug.Fail($"Is this an interesting scenario where IInvocationOperation for Assert call isn't associated with InvocationExpressionSyntax? SyntaxNode type: '{diagnosticNode.GetType()}', Text: '{diagnosticNode.GetText()}'");
+ return;
+ }
+
+ SyntaxNode methodNameIdentifier = invocation.Expression;
+ if (methodNameIdentifier is MemberAccessExpressionSyntax memberAccess)
+ {
+ methodNameIdentifier = memberAccess.Name;
+ }
+
+ if (methodNameIdentifier is not SimpleNameSyntax simpleNameSyntax)
+ {
+ Debug.Fail($"Is this an interesting scenario where we are unable to retrieve SimpleNameSyntax corresponding to the assert method? SyntaxNode type: '{methodNameIdentifier}', Text: '{methodNameIdentifier.GetText()}'.");
+ return;
+ }
+
+ Func>? createChangedDocument = null;
+ switch (mode)
+ {
+ case UseProperAssertMethodsAnalyzer.CodeFixModeSimple:
+ createChangedDocument = ct => FixAssertMethodForSimpleModeAsync(context.Document, diagnostic.AdditionalLocations[0], diagnostic.AdditionalLocations[1], root, simpleNameSyntax, properAssertMethodName, ct);
+ break;
+ case UseProperAssertMethodsAnalyzer.CodeFixModeAddArgument:
+ createChangedDocument = ct => FixAssertMethodForAddArgumentModeAsync(context.Document, diagnostic.AdditionalLocations[0], diagnostic.AdditionalLocations[1], diagnostic.AdditionalLocations[2], root, simpleNameSyntax, properAssertMethodName, ct);
+ break;
+ case UseProperAssertMethodsAnalyzer.CodeFixModeRemoveArgument:
+ createChangedDocument = ct => FixAssertMethodForRemoveArgumentModeAsync(context.Document, diagnostic.AdditionalLocations, root, simpleNameSyntax, properAssertMethodName, diagnostic.Properties.ContainsKey(UseProperAssertMethodsAnalyzer.NeedsNullableBooleanCastKey), ct);
+ break;
+ default:
+ break;
+ }
+
+ if (createChangedDocument is not null)
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title: string.Format(CultureInfo.InvariantCulture, CodeFixResources.UseProperAssertMethodsFix, properAssertMethodName),
+ createChangedDocument,
+ equivalenceKey: nameof(UseProperAssertMethodsFixer)),
+ diagnostic);
+ }
+ }
+
+ private static async Task FixAssertMethodForSimpleModeAsync(Document document, Location conditionLocationToBeReplaced, Location replacementExpressionLocation, SyntaxNode root, SimpleNameSyntax simpleNameSyntax, string properAssertMethodName, CancellationToken cancellationToken)
+ {
+ // This doesn't properly handle cases like Assert.IsTrue(message: "My message", condition: x == null)
+ // The proper handling of this may be Assert.IsNull(message: "My message", value: x)
+ // Or: Assert.IsNull(x, "My message")
+ // For now this is not handled.
+ if (root.FindNode(conditionLocationToBeReplaced.SourceSpan) is not ArgumentSyntax conditionNodeToBeReplaced)
+ {
+ return document;
+ }
+
+ if (root.FindNode(replacementExpressionLocation.SourceSpan) is not ExpressionSyntax replacementExpressionNode)
+ {
+ return document;
+ }
+
+ DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
+ FixInvocationMethodName(editor, simpleNameSyntax, properAssertMethodName);
+ editor.ReplaceNode(conditionNodeToBeReplaced, SyntaxFactory.Argument(replacementExpressionNode).WithAdditionalAnnotations(Formatter.Annotation));
+
+ return editor.GetChangedDocument();
+ }
+
+ private static async Task FixAssertMethodForAddArgumentModeAsync(Document document, Location conditionLocation, Location expectedLocation, Location actualLocation, SyntaxNode root, SimpleNameSyntax simpleNameSyntax, string properAssertMethodName, CancellationToken cancellationToken)
+ {
+ // This doesn't properly handle cases like Assert.IsTrue(message: "My message", condition: x == y)
+ // The proper handling of this may be Assert.AreEqual(message: "My message", expected: x, actual: y)
+ // Or: Assert.AreEqual(x, y, "My message")
+ // For now this is not handled.
+ if (root.FindNode(conditionLocation.SourceSpan) is not ArgumentSyntax conditionNode)
+ {
+ return document;
+ }
+
+ if (conditionNode.Parent is not ArgumentListSyntax argumentList)
+ {
+ return document;
+ }
+
+ if (root.FindNode(expectedLocation.SourceSpan) is not ExpressionSyntax expectedNode)
+ {
+ return document;
+ }
+
+ if (root.FindNode(actualLocation.SourceSpan) is not ExpressionSyntax actualNode)
+ {
+ return document;
+ }
+
+ DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
+ FixInvocationMethodName(editor, simpleNameSyntax, properAssertMethodName);
+
+ ArgumentListSyntax newArgumentList = argumentList;
+ newArgumentList = newArgumentList.ReplaceNode(conditionNode, SyntaxFactory.Argument(expectedNode).WithAdditionalAnnotations(Formatter.Annotation));
+ int insertionIndex = argumentList.Arguments.IndexOf(conditionNode) + 1;
+ newArgumentList = newArgumentList.WithArguments(newArgumentList.Arguments.Insert(insertionIndex, SyntaxFactory.Argument(actualNode).WithAdditionalAnnotations(Formatter.Annotation)));
+
+ editor.ReplaceNode(argumentList, newArgumentList);
+
+ return editor.GetChangedDocument();
+ }
+
+ private static async Task FixAssertMethodForRemoveArgumentModeAsync(
+ Document document,
+ IReadOnlyList additionalLocations,
+ SyntaxNode root,
+ SimpleNameSyntax simpleNameSyntax,
+ string properAssertMethodName,
+ bool needsNullableBoolCast,
+ CancellationToken cancellationToken)
+ {
+ // This doesn't properly handle cases like Assert.AreEqual(message: "My message", expected: true, actual: x)
+ // The proper handling of this may be Assert.IsTrue(message: "My message", condition: x)
+ // Or: Assert.IsTrue(x, "My message")
+ // For now this is not handled.
+ if (root.FindNode(additionalLocations[0].SourceSpan) is not ArgumentSyntax expectedArgumentToRemove)
+ {
+ return document;
+ }
+
+ if (expectedArgumentToRemove.Parent is not ArgumentListSyntax argumentList)
+ {
+ return document;
+ }
+
+ DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
+ FixInvocationMethodName(editor, simpleNameSyntax, properAssertMethodName);
+
+ int argumentIndexToRemove = argumentList.Arguments.IndexOf(expectedArgumentToRemove);
+ ArgumentListSyntax newArgumentList;
+ if (additionalLocations.Count > 1 && needsNullableBoolCast &&
+ root.FindNode(additionalLocations[1].SourceSpan) is ArgumentSyntax actualArgument)
+ {
+ Compilation compilation = editor.SemanticModel.Compilation;
+ var castExpression = (CastExpressionSyntax)editor.Generator.CastExpression(
+ compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(compilation.GetSpecialType(SpecialType.System_Boolean)),
+ actualArgument.Expression);
+ newArgumentList = argumentList.WithArguments(
+ argumentList.Arguments.Replace(actualArgument, SyntaxFactory.Argument(castExpression)).RemoveAt(argumentIndexToRemove));
+ }
+ else
+ {
+ newArgumentList = argumentList.WithArguments(argumentList.Arguments.RemoveAt(argumentIndexToRemove));
+ }
+
+ editor.ReplaceNode(argumentList, newArgumentList);
+
+ return editor.GetChangedDocument();
+ }
+
+ private static void FixInvocationMethodName(DocumentEditor editor, SimpleNameSyntax simpleNameSyntax, string properAssertMethodName)
+ // NOTE: Switching Assert.IsTrue(x == y) to Assert.AreEqual(x, y) MAY produce an overload resolution error.
+ // For example, Assert.AreEqual("string", true) will fail the inference for generic argument.
+ // This is not very common and is currently not handled properly.
+ // If needed, we can adjust the codefix to account for that case and
+ // produce a GenericNameSyntax (e.g, AreEqual) instead of IdentifierNameSyntax (e.g, AreEqual).
+ => editor.ReplaceNode(simpleNameSyntax, SyntaxFactory.IdentifierName(properAssertMethodName));
+}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf
index db5674fdf1..e756f5cdc7 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/xlf/CodeFixResources.cs.xlf
@@ -7,6 +7,16 @@
Přidat [TestMethod]
+
+ Move conditional access in assertion to separate 'Assert.IsNotNull' check
+ PÅ™esunout podmÃnÄ›ný pÅ™Ãstup v kontrolnÃm výrazu, aby se oddÄ›lila kontrola Assert.IsNotNull
+
+
+
+ Use '{0}'
+ Use '{0}'
+
+
Change method accessibility to 'private'
ZmÄ›nit pÅ™Ãstupnost metody na private
@@ -82,6 +92,16 @@
Přidat [TestMethod]
+
+ Use '{0}'
+ PoužÃt {0}
+
+
+
+ Use '{0}'
+ PoužÃt {0}
+
+