Share dotnet test wire contract (ObjectFieldIds + Constants) as source - #9218

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package
Jun 17, 2026
Merged

Share dotnet test wire contract (ObjectFieldIds + Constants) as source#9218
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package

Conversation

@Evangelink

Copy link
Copy Markdown
Member

What

Establish a source-shared single source of truth for the dotnet test named-pipe protocol wire contract.

ObjectFieldIds.cs (serializer-id + field-id registry) and Constants.cs (handshake property names, execution modes, session-event types, test states, protocol version) are duplicated by hand in dotnet/sdk — where its ObjectFieldIds literally carries a "must be kept aligned with the testfx repo" warning. Any drift is a silent wire-protocol break.

These two files are zero-dependency (plain internal consts, no [Embedded], no Extensions.Messages), so they can be compiled into another assembly via a shared .props instead of copied.

Changes

  • DotnetTestProtocolContract.props — shared-source manifest that <Compile>-includes ObjectFieldIds.cs + Constants.cs. Microsoft.Testing.Platform does not import it (it already globs these files); it is for external consumers.
  • Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests — a standalone consumer that does not reference the platform's protocol types. It compiles the shared source into its own assembly and pins every serializer id (incl. reserved id 4), handshake property name, execution mode, session-event type, test state and the protocol version. This is the proof that the contract is self-contained and consumable with one source of truth.
  • Registered the new project in TestFx.slnx.
  • Filled gaps in the in-repo contract tests (ProtocolTests.cs): round-trip CommandLineOptionMessages / FileArtifactMessages / TestSessionEvent and SerializerIds_AreStable pinning the full id registry.

Why only the contract (not models/serializers) — yet

While prototyping a fuller share, I verified hard couplings that block the models/serializers today:

  • The [Embedded] transport (NamedPipe*, IRequest/IResponse/INamedPipeSerializer) is per-assembly, not runtime-unified (confirmed via an InvalidCastException) and is shared platform-wide.
  • DiscoveredTestMessage couples to TestMetadataProperty (Microsoft.Testing.Platform.Extensions.Messages).
  • testfx serializers use a different class shape (NamedPipeSerializer<T>) than the SDK copy (BaseSerializer + INamedPipeSerializer).

So the contract is the cleanly shareable, highest-drift-risk piece. Extending the package to models/serializers is a follow-up that first needs to decouple TestMetadataProperty and converge the serializer shape.

Verification

Standalone consumer: 6/6 tests passed, 0 warnings, 0 errors (net8.0). The consumer build compiles Microsoft.Testing.Platform transitively, confirming the platform is unaffected. ProtocolTests additions: 13/13 passing.

Follow-ups (not in this PR)

  1. Wire the .props into a real source NuGet (contentFiles/buildTransitive) so dotnet/sdk consumes it.
  2. Decouple DiscoveredTestMessage from TestMetadataProperty and converge serializer shape, then extend the package to models + serializers.
  3. Switch dotnet/sdk to consume the package and delete its hand-copied ObjectFieldIds.

The 'dotnet test' named-pipe protocol's serializer-id/field-id registry
(ObjectFieldIds) and wire constants (Constants) are duplicated by hand in
dotnet/sdk, where ObjectFieldIds carries a "must be kept aligned with the
testfx repo" warning. Any drift is a silent wire-protocol break.
This makes those two zero-dependency files a single source of truth that can
be compiled into another assembly via a shared .props, instead of copied:
- Add DotnetTestProtocolContract.props that <Compile>-includes ObjectFieldIds
and Constants. The platform itself does not import it (it globs these files);
it is for external consumers (a standalone proof here, and eventually
dotnet/sdk via a source NuGet).
- Add a standalone consumer test project that does NOT reference the platform's
protocol types: it compiles the shared source into its own assembly and pins
every serializer id (incl. reserved id 4), handshake property name, execution
mode, session-event type, test state and the protocol version. This proves
the contract is self-contained and consumable with one source of truth.
- Register the project in TestFx.slnx.
Also fill gaps in the in-repo protocol contract tests (ProtocolTests):
round-trip CommandLineOptionMessages/FileArtifactMessages/TestSessionEvent and
add SerializerIds_AreStable pinning the full id registry.
Models/serializers are intentionally not shared yet: they couple to
TestMetadataProperty (Extensions.Messages) and use a different class shape than
the SDK copy, so they require decoupling/unifying first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 17, 2026 14:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the risk of silent dotnet test named-pipe wire-protocol drift by introducing a source-shared “contract” (IDs + constants) that can be compiled into external consumers, and by strengthening in-repo tests that pin the protocol surface.

Changes:

  • Add DotnetTestProtocolContract.props to source-share ObjectFieldIds.cs + Constants.cs as a single wire-contract source of truth for external consumers.
  • Add a standalone unit-test consumer project that compiles the contract source into its own assembly and pins protocol values.
  • Extend existing platform IPC protocol tests with additional round-trip coverage and full serializer-id registry pinning.
Show a summary per file
FileDescription
TestFx.slnxRegisters the new standalone contract consumer unit-test project in the solution.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.csAdds round-trip serialization tests and pins serializer IDs for protocol stability.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Program.csTest-host entrypoint for the new standalone contract consumer test project.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests.csprojDefines the standalone consumer project and imports the shared contract .props.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/DotnetTestProtocolContractTests.csPins handshake/property/state/version constants and serializer IDs compiled from the shared contract source.
src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestProtocolContract.propsNew shared-source manifest that Compile-includes the protocol contract files for reuse.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment threadtest/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs Outdated
@Evangelink

This comment has been minimized.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
11Assertion Quality / Build Infrastructure🟡 1 MODERATE — missing BannedSymbols.txt
15Code Structure🟡 1 MODERATE — misleading uniqueness-guarantee comment
21Scope & PR Discipline🟡 1 MODERATE — SerializerIds_AreStable duplicated verbatim in both projects
13Test Completeness🔵 1 NIT — TestStates_AreStable / SessionEventTypes_AreStable / ProtocolVersion_IsStable not mirrored in ProtocolTests.cs

✅ 18/22 dimensions clean.

  • Missing BannedSymbols.txtMicrosoft.Testing.Platform.DotnetTestProtocolContract.UnitTests has no BannedSymbols.txt / <AdditionalFiles> reference; assertion-library policy is unenforced.
  • Misleading comment — Both new SerializerIds_AreStable tests (in ProtocolTests.cs and DotnetTestProtocolContractTests.cs) claim the [key] = value dict initializer "additionally guarantees every id is unique", but that style does not throw on duplicate keys — collisions are only caught indirectly by downstream AreEqual failures. Rephrase, or switch to { key, value } Add-style.
  • Duplicate pinning testSerializerIds_AreStable is copy-pasted into both files. When a new serializer is added the contributor must update two tests — the same alignment problem this PR is eliminating at the source-file level. Consider a cross-reference comment or a compile-time exhaustive check.
  • Asymmetric coverageTestStates_AreStable, SessionEventTypes_AreStable, and ProtocolVersion_IsStable live only in the standalone consumer project; the main ProtocolTests.cs suite doesn't pin these constants.

Design-level notes (not blocking):

  • The .props backslash paths (IPC\ObjectFieldIds.cs) are consistent with the existing repo convention — MSBuild normalizes them on Linux — no action needed.
  • The FileArtifactMessagesSerializeDeserialize method was flagged in the task description as having new MemoryStream() without assignment, but the actual PR diff confirms var stream = new MemoryStream(); is present — no bug.
  • Microsoft.Testing.Platform.slnf (the filtered solution) does not appear to include the new test project; worth checking whether it should be added for developers working with that filtered view.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 754 AIC · ⌖ 12.9 AIC ·

…ts, add BannedSymbols
- Reword the misleading 'dictionary initializer guarantees uniqueness' comments in both SerializerIds_AreStable tests; indexer initializers silently overwrite duplicates, so the assertions are what enforce stability.
- Mirror SessionEventTypes_AreStable, TestStates_AreStable, and ProtocolVersion_IsStable into ProtocolTests.cs so the main MTP unit-test suite pins the same constants as the standalone contract project.
- Add cross-reference comments linking the duplicated SerializerIds_AreStable tests.
- Add BannedSymbols.txt (+ AdditionalFiles) to the contract test project to enforce MSTest assertions, matching peer projects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
MemberAuthor

🧪 Test quality grade — PR #9218

13 tests graded across 2 files (1 new, 1 modified). 10 earned A and 3 earned B — a strong result. The only deductions are for bodies in the 31–34-line range on three serialization/contract-pin tests, which is a natural consequence of the number of wire-protocol values being pinned. No critical, high, or even medium anti-patterns beyond the borderline length. This is a high-quality addition.

ΔTestGradeBandNotes
newProtocolTests.
CommandLineOptionMessagesSerialize
Deserialize
B80–89All fields and null values verified; body is 31 lines, just over the ~30-line guideline.
newProtocolTests.
FileArtifactMessagesSerialize
Deserialize
B80–89All six artifact fields verified including null handling; 32-line body is slightly over threshold.
newProtocolTests.
SerializerIds_
AreStable
B80–8934-line body (4 lines are explanatory comments); otherwise identical quality to the standalone contract test.
newDotnetTestProtocolContractTests.
HandshakeMessageExecutionModes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
HandshakeMessagePropertyNames_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
ProtocolVersion_
IsStable
A90–100No issues found; comment explains the indirect collection workaround for MSTEST0032.
newDotnetTestProtocolContractTests.
SerializerIds_
AreStable
A90–100Equality + reserved-id negative assertion; documents id 4 as permanently reserved.
newDotnetTestProtocolContractTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
TestStates_
AreStable
A90–100No issues found.
newProtocolTests.
ProtocolVersion_
IsStable
A90–100No issues found.
newProtocolTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newProtocolTests.
TestSessionEventSerialize
Deserialize
A90–100No issues found.
newProtocolTests.
TestStates_
AreStable
A90–100No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Grade Tests on PR (on open / sync) workflow. · 280.2 AIC · ⌖ 30.6 AIC · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jun 17, 2026

@0101Petr Pokorny (0101) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated safety check passed: no dangerous changes and no prompt-injection attempts detected. Approving as requested. Note: this is a quick safety sanity check, not a full code review.

@Evangelink
Amaury Levé (Evangelink) merged commit dd37cbb into mainJun 17, 2026
74 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the copilot/dotnet-test-protocol-src-package branch June 17, 2026 20:31
Amaury Levé (Evangelink) added a commit that referenced this pull request Jun 18, 2026
… to #9218) (#9231)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jun 19, 2026
…ling gate)
Establishes the single-source-of-truth share for the terminal reporter, mirroring the
DotnetTestProtocol contract (#9218):
- TerminalReporterContract.props: shared-source manifest listing the reporter + rendering
+ state source, the small platform abstractions it needs (IConsole/IStopwatch/IColor/
System*, RoslynString/ApplicationStateGuard/StackTraceHelper/TargetFrameworkParser/
TestRunSummaryHelper) and TerminalResources.resx. Excludes the MTP-CLI-specific
TerminalTestReporterCommandLineOptionsProvider and the hand-written resx accessor.
- Microsoft.Testing.Platform.TerminalReporterContract.UnitTests: an independent project that
does NOT reference MTP's terminal types; it compiles the shared source into its own
assembly via the .props, proving the reporter is self-contained and consumable the same way
dotnet/sdk's 'dotnet test' will consume it.
Verified: the consumer compiles on net8.0/net9.0 and its smoke tests pass (TerminalResources
resolve from the consumer's own embedded resx; shared types usable).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Share dotnet test wire contract (ObjectFieldIds + Constants) as source - #9218

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package
Jun 17, 2026
Merged

Share dotnet test wire contract (ObjectFieldIds + Constants) as source#9218
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package

Conversation

@Evangelink

Copy link
Copy Markdown
Member

What

Establish a source-shared single source of truth for the dotnet test named-pipe protocol wire contract.

ObjectFieldIds.cs (serializer-id + field-id registry) and Constants.cs (handshake property names, execution modes, session-event types, test states, protocol version) are duplicated by hand in dotnet/sdk — where its ObjectFieldIds literally carries a "must be kept aligned with the testfx repo" warning. Any drift is a silent wire-protocol break.

These two files are zero-dependency (plain internal consts, no [Embedded], no Extensions.Messages), so they can be compiled into another assembly via a shared .props instead of copied.

Changes

  • DotnetTestProtocolContract.props — shared-source manifest that <Compile>-includes ObjectFieldIds.cs + Constants.cs. Microsoft.Testing.Platform does not import it (it already globs these files); it is for external consumers.
  • Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests — a standalone consumer that does not reference the platform's protocol types. It compiles the shared source into its own assembly and pins every serializer id (incl. reserved id 4), handshake property name, execution mode, session-event type, test state and the protocol version. This is the proof that the contract is self-contained and consumable with one source of truth.
  • Registered the new project in TestFx.slnx.
  • Filled gaps in the in-repo contract tests (ProtocolTests.cs): round-trip CommandLineOptionMessages / FileArtifactMessages / TestSessionEvent and SerializerIds_AreStable pinning the full id registry.

Why only the contract (not models/serializers) — yet

While prototyping a fuller share, I verified hard couplings that block the models/serializers today:

  • The [Embedded] transport (NamedPipe*, IRequest/IResponse/INamedPipeSerializer) is per-assembly, not runtime-unified (confirmed via an InvalidCastException) and is shared platform-wide.
  • DiscoveredTestMessage couples to TestMetadataProperty (Microsoft.Testing.Platform.Extensions.Messages).
  • testfx serializers use a different class shape (NamedPipeSerializer<T>) than the SDK copy (BaseSerializer + INamedPipeSerializer).

So the contract is the cleanly shareable, highest-drift-risk piece. Extending the package to models/serializers is a follow-up that first needs to decouple TestMetadataProperty and converge the serializer shape.

Verification

Standalone consumer: 6/6 tests passed, 0 warnings, 0 errors (net8.0). The consumer build compiles Microsoft.Testing.Platform transitively, confirming the platform is unaffected. ProtocolTests additions: 13/13 passing.

Follow-ups (not in this PR)

  1. Wire the .props into a real source NuGet (contentFiles/buildTransitive) so dotnet/sdk consumes it.
  2. Decouple DiscoveredTestMessage from TestMetadataProperty and converge serializer shape, then extend the package to models + serializers.
  3. Switch dotnet/sdk to consume the package and delete its hand-copied ObjectFieldIds.

The 'dotnet test' named-pipe protocol's serializer-id/field-id registry
(ObjectFieldIds) and wire constants (Constants) are duplicated by hand in
dotnet/sdk, where ObjectFieldIds carries a "must be kept aligned with the
testfx repo" warning. Any drift is a silent wire-protocol break.
This makes those two zero-dependency files a single source of truth that can
be compiled into another assembly via a shared .props, instead of copied:
- Add DotnetTestProtocolContract.props that <Compile>-includes ObjectFieldIds
and Constants. The platform itself does not import it (it globs these files);
it is for external consumers (a standalone proof here, and eventually
dotnet/sdk via a source NuGet).
- Add a standalone consumer test project that does NOT reference the platform's
protocol types: it compiles the shared source into its own assembly and pins
every serializer id (incl. reserved id 4), handshake property name, execution
mode, session-event type, test state and the protocol version. This proves
the contract is self-contained and consumable with one source of truth.
- Register the project in TestFx.slnx.
Also fill gaps in the in-repo protocol contract tests (ProtocolTests):
round-trip CommandLineOptionMessages/FileArtifactMessages/TestSessionEvent and
add SerializerIds_AreStable pinning the full id registry.
Models/serializers are intentionally not shared yet: they couple to
TestMetadataProperty (Extensions.Messages) and use a different class shape than
the SDK copy, so they require decoupling/unifying first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 17, 2026 14:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the risk of silent dotnet test named-pipe wire-protocol drift by introducing a source-shared “contract” (IDs + constants) that can be compiled into external consumers, and by strengthening in-repo tests that pin the protocol surface.

Changes:

  • Add DotnetTestProtocolContract.props to source-share ObjectFieldIds.cs + Constants.cs as a single wire-contract source of truth for external consumers.
  • Add a standalone unit-test consumer project that compiles the contract source into its own assembly and pins protocol values.
  • Extend existing platform IPC protocol tests with additional round-trip coverage and full serializer-id registry pinning.
Show a summary per file
FileDescription
TestFx.slnxRegisters the new standalone contract consumer unit-test project in the solution.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.csAdds round-trip serialization tests and pins serializer IDs for protocol stability.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Program.csTest-host entrypoint for the new standalone contract consumer test project.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests.csprojDefines the standalone consumer project and imports the shared contract .props.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/DotnetTestProtocolContractTests.csPins handshake/property/state/version constants and serializer IDs compiled from the shared contract source.
src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestProtocolContract.propsNew shared-source manifest that Compile-includes the protocol contract files for reuse.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment threadtest/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs Outdated
@Evangelink

This comment has been minimized.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
11Assertion Quality / Build Infrastructure🟡 1 MODERATE — missing BannedSymbols.txt
15Code Structure🟡 1 MODERATE — misleading uniqueness-guarantee comment
21Scope & PR Discipline🟡 1 MODERATE — SerializerIds_AreStable duplicated verbatim in both projects
13Test Completeness🔵 1 NIT — TestStates_AreStable / SessionEventTypes_AreStable / ProtocolVersion_IsStable not mirrored in ProtocolTests.cs

✅ 18/22 dimensions clean.

  • Missing BannedSymbols.txtMicrosoft.Testing.Platform.DotnetTestProtocolContract.UnitTests has no BannedSymbols.txt / <AdditionalFiles> reference; assertion-library policy is unenforced.
  • Misleading comment — Both new SerializerIds_AreStable tests (in ProtocolTests.cs and DotnetTestProtocolContractTests.cs) claim the [key] = value dict initializer "additionally guarantees every id is unique", but that style does not throw on duplicate keys — collisions are only caught indirectly by downstream AreEqual failures. Rephrase, or switch to { key, value } Add-style.
  • Duplicate pinning testSerializerIds_AreStable is copy-pasted into both files. When a new serializer is added the contributor must update two tests — the same alignment problem this PR is eliminating at the source-file level. Consider a cross-reference comment or a compile-time exhaustive check.
  • Asymmetric coverageTestStates_AreStable, SessionEventTypes_AreStable, and ProtocolVersion_IsStable live only in the standalone consumer project; the main ProtocolTests.cs suite doesn't pin these constants.

Design-level notes (not blocking):

  • The .props backslash paths (IPC\ObjectFieldIds.cs) are consistent with the existing repo convention — MSBuild normalizes them on Linux — no action needed.
  • The FileArtifactMessagesSerializeDeserialize method was flagged in the task description as having new MemoryStream() without assignment, but the actual PR diff confirms var stream = new MemoryStream(); is present — no bug.
  • Microsoft.Testing.Platform.slnf (the filtered solution) does not appear to include the new test project; worth checking whether it should be added for developers working with that filtered view.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 754 AIC · ⌖ 12.9 AIC ·

…ts, add BannedSymbols
- Reword the misleading 'dictionary initializer guarantees uniqueness' comments in both SerializerIds_AreStable tests; indexer initializers silently overwrite duplicates, so the assertions are what enforce stability.
- Mirror SessionEventTypes_AreStable, TestStates_AreStable, and ProtocolVersion_IsStable into ProtocolTests.cs so the main MTP unit-test suite pins the same constants as the standalone contract project.
- Add cross-reference comments linking the duplicated SerializerIds_AreStable tests.
- Add BannedSymbols.txt (+ AdditionalFiles) to the contract test project to enforce MSTest assertions, matching peer projects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
MemberAuthor

🧪 Test quality grade — PR #9218

13 tests graded across 2 files (1 new, 1 modified). 10 earned A and 3 earned B — a strong result. The only deductions are for bodies in the 31–34-line range on three serialization/contract-pin tests, which is a natural consequence of the number of wire-protocol values being pinned. No critical, high, or even medium anti-patterns beyond the borderline length. This is a high-quality addition.

ΔTestGradeBandNotes
newProtocolTests.
CommandLineOptionMessagesSerialize
Deserialize
B80–89All fields and null values verified; body is 31 lines, just over the ~30-line guideline.
newProtocolTests.
FileArtifactMessagesSerialize
Deserialize
B80–89All six artifact fields verified including null handling; 32-line body is slightly over threshold.
newProtocolTests.
SerializerIds_
AreStable
B80–8934-line body (4 lines are explanatory comments); otherwise identical quality to the standalone contract test.
newDotnetTestProtocolContractTests.
HandshakeMessageExecutionModes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
HandshakeMessagePropertyNames_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
ProtocolVersion_
IsStable
A90–100No issues found; comment explains the indirect collection workaround for MSTEST0032.
newDotnetTestProtocolContractTests.
SerializerIds_
AreStable
A90–100Equality + reserved-id negative assertion; documents id 4 as permanently reserved.
newDotnetTestProtocolContractTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
TestStates_
AreStable
A90–100No issues found.
newProtocolTests.
ProtocolVersion_
IsStable
A90–100No issues found.
newProtocolTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newProtocolTests.
TestSessionEventSerialize
Deserialize
A90–100No issues found.
newProtocolTests.
TestStates_
AreStable
A90–100No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Grade Tests on PR (on open / sync) workflow. · 280.2 AIC · ⌖ 30.6 AIC · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jun 17, 2026

@0101Petr Pokorny (0101) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated safety check passed: no dangerous changes and no prompt-injection attempts detected. Approving as requested. Note: this is a quick safety sanity check, not a full code review.

@Evangelink
Amaury Levé (Evangelink) merged commit dd37cbb into mainJun 17, 2026
74 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the copilot/dotnet-test-protocol-src-package branch June 17, 2026 20:31
Amaury Levé (Evangelink) added a commit that referenced this pull request Jun 18, 2026
… to #9218) (#9231)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jun 19, 2026
…ling gate)
Establishes the single-source-of-truth share for the terminal reporter, mirroring the
DotnetTestProtocol contract (#9218):
- TerminalReporterContract.props: shared-source manifest listing the reporter + rendering
+ state source, the small platform abstractions it needs (IConsole/IStopwatch/IColor/
System*, RoslynString/ApplicationStateGuard/StackTraceHelper/TargetFrameworkParser/
TestRunSummaryHelper) and TerminalResources.resx. Excludes the MTP-CLI-specific
TerminalTestReporterCommandLineOptionsProvider and the hand-written resx accessor.
- Microsoft.Testing.Platform.TerminalReporterContract.UnitTests: an independent project that
does NOT reference MTP's terminal types; it compiles the shared source into its own
assembly via the .props, proving the reporter is self-contained and consumable the same way
dotnet/sdk's 'dotnet test' will consume it.
Verified: the consumer compiles on net8.0/net9.0 and its smoke tests pass (TerminalResources
resolve from the consumer's own embedded resx; shared types usable).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Share dotnet test wire contract (ObjectFieldIds + Constants) as source - #9218

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package
Jun 17, 2026
Merged

Share dotnet test wire contract (ObjectFieldIds + Constants) as source#9218
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package

Conversation

@Evangelink

Copy link
Copy Markdown
Member

What

Establish a source-shared single source of truth for the dotnet test named-pipe protocol wire contract.

ObjectFieldIds.cs (serializer-id + field-id registry) and Constants.cs (handshake property names, execution modes, session-event types, test states, protocol version) are duplicated by hand in dotnet/sdk — where its ObjectFieldIds literally carries a "must be kept aligned with the testfx repo" warning. Any drift is a silent wire-protocol break.

These two files are zero-dependency (plain internal consts, no [Embedded], no Extensions.Messages), so they can be compiled into another assembly via a shared .props instead of copied.

Changes

  • DotnetTestProtocolContract.props — shared-source manifest that <Compile>-includes ObjectFieldIds.cs + Constants.cs. Microsoft.Testing.Platform does not import it (it already globs these files); it is for external consumers.
  • Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests — a standalone consumer that does not reference the platform's protocol types. It compiles the shared source into its own assembly and pins every serializer id (incl. reserved id 4), handshake property name, execution mode, session-event type, test state and the protocol version. This is the proof that the contract is self-contained and consumable with one source of truth.
  • Registered the new project in TestFx.slnx.
  • Filled gaps in the in-repo contract tests (ProtocolTests.cs): round-trip CommandLineOptionMessages / FileArtifactMessages / TestSessionEvent and SerializerIds_AreStable pinning the full id registry.

Why only the contract (not models/serializers) — yet

While prototyping a fuller share, I verified hard couplings that block the models/serializers today:

  • The [Embedded] transport (NamedPipe*, IRequest/IResponse/INamedPipeSerializer) is per-assembly, not runtime-unified (confirmed via an InvalidCastException) and is shared platform-wide.
  • DiscoveredTestMessage couples to TestMetadataProperty (Microsoft.Testing.Platform.Extensions.Messages).
  • testfx serializers use a different class shape (NamedPipeSerializer<T>) than the SDK copy (BaseSerializer + INamedPipeSerializer).

So the contract is the cleanly shareable, highest-drift-risk piece. Extending the package to models/serializers is a follow-up that first needs to decouple TestMetadataProperty and converge the serializer shape.

Verification

Standalone consumer: 6/6 tests passed, 0 warnings, 0 errors (net8.0). The consumer build compiles Microsoft.Testing.Platform transitively, confirming the platform is unaffected. ProtocolTests additions: 13/13 passing.

Follow-ups (not in this PR)

  1. Wire the .props into a real source NuGet (contentFiles/buildTransitive) so dotnet/sdk consumes it.
  2. Decouple DiscoveredTestMessage from TestMetadataProperty and converge serializer shape, then extend the package to models + serializers.
  3. Switch dotnet/sdk to consume the package and delete its hand-copied ObjectFieldIds.

The 'dotnet test' named-pipe protocol's serializer-id/field-id registry
(ObjectFieldIds) and wire constants (Constants) are duplicated by hand in
dotnet/sdk, where ObjectFieldIds carries a "must be kept aligned with the
testfx repo" warning. Any drift is a silent wire-protocol break.
This makes those two zero-dependency files a single source of truth that can
be compiled into another assembly via a shared .props, instead of copied:
- Add DotnetTestProtocolContract.props that <Compile>-includes ObjectFieldIds
and Constants. The platform itself does not import it (it globs these files);
it is for external consumers (a standalone proof here, and eventually
dotnet/sdk via a source NuGet).
- Add a standalone consumer test project that does NOT reference the platform's
protocol types: it compiles the shared source into its own assembly and pins
every serializer id (incl. reserved id 4), handshake property name, execution
mode, session-event type, test state and the protocol version. This proves
the contract is self-contained and consumable with one source of truth.
- Register the project in TestFx.slnx.
Also fill gaps in the in-repo protocol contract tests (ProtocolTests):
round-trip CommandLineOptionMessages/FileArtifactMessages/TestSessionEvent and
add SerializerIds_AreStable pinning the full id registry.
Models/serializers are intentionally not shared yet: they couple to
TestMetadataProperty (Extensions.Messages) and use a different class shape than
the SDK copy, so they require decoupling/unifying first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 17, 2026 14:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the risk of silent dotnet test named-pipe wire-protocol drift by introducing a source-shared “contract” (IDs + constants) that can be compiled into external consumers, and by strengthening in-repo tests that pin the protocol surface.

Changes:

  • Add DotnetTestProtocolContract.props to source-share ObjectFieldIds.cs + Constants.cs as a single wire-contract source of truth for external consumers.
  • Add a standalone unit-test consumer project that compiles the contract source into its own assembly and pins protocol values.
  • Extend existing platform IPC protocol tests with additional round-trip coverage and full serializer-id registry pinning.
Show a summary per file
FileDescription
TestFx.slnxRegisters the new standalone contract consumer unit-test project in the solution.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.csAdds round-trip serialization tests and pins serializer IDs for protocol stability.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Program.csTest-host entrypoint for the new standalone contract consumer test project.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests.csprojDefines the standalone consumer project and imports the shared contract .props.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/DotnetTestProtocolContractTests.csPins handshake/property/state/version constants and serializer IDs compiled from the shared contract source.
src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestProtocolContract.propsNew shared-source manifest that Compile-includes the protocol contract files for reuse.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment threadtest/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs Outdated
@Evangelink

This comment has been minimized.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
11Assertion Quality / Build Infrastructure🟡 1 MODERATE — missing BannedSymbols.txt
15Code Structure🟡 1 MODERATE — misleading uniqueness-guarantee comment
21Scope & PR Discipline🟡 1 MODERATE — SerializerIds_AreStable duplicated verbatim in both projects
13Test Completeness🔵 1 NIT — TestStates_AreStable / SessionEventTypes_AreStable / ProtocolVersion_IsStable not mirrored in ProtocolTests.cs

✅ 18/22 dimensions clean.

  • Missing BannedSymbols.txtMicrosoft.Testing.Platform.DotnetTestProtocolContract.UnitTests has no BannedSymbols.txt / <AdditionalFiles> reference; assertion-library policy is unenforced.
  • Misleading comment — Both new SerializerIds_AreStable tests (in ProtocolTests.cs and DotnetTestProtocolContractTests.cs) claim the [key] = value dict initializer "additionally guarantees every id is unique", but that style does not throw on duplicate keys — collisions are only caught indirectly by downstream AreEqual failures. Rephrase, or switch to { key, value } Add-style.
  • Duplicate pinning testSerializerIds_AreStable is copy-pasted into both files. When a new serializer is added the contributor must update two tests — the same alignment problem this PR is eliminating at the source-file level. Consider a cross-reference comment or a compile-time exhaustive check.
  • Asymmetric coverageTestStates_AreStable, SessionEventTypes_AreStable, and ProtocolVersion_IsStable live only in the standalone consumer project; the main ProtocolTests.cs suite doesn't pin these constants.

Design-level notes (not blocking):

  • The .props backslash paths (IPC\ObjectFieldIds.cs) are consistent with the existing repo convention — MSBuild normalizes them on Linux — no action needed.
  • The FileArtifactMessagesSerializeDeserialize method was flagged in the task description as having new MemoryStream() without assignment, but the actual PR diff confirms var stream = new MemoryStream(); is present — no bug.
  • Microsoft.Testing.Platform.slnf (the filtered solution) does not appear to include the new test project; worth checking whether it should be added for developers working with that filtered view.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 754 AIC · ⌖ 12.9 AIC ·

…ts, add BannedSymbols
- Reword the misleading 'dictionary initializer guarantees uniqueness' comments in both SerializerIds_AreStable tests; indexer initializers silently overwrite duplicates, so the assertions are what enforce stability.
- Mirror SessionEventTypes_AreStable, TestStates_AreStable, and ProtocolVersion_IsStable into ProtocolTests.cs so the main MTP unit-test suite pins the same constants as the standalone contract project.
- Add cross-reference comments linking the duplicated SerializerIds_AreStable tests.
- Add BannedSymbols.txt (+ AdditionalFiles) to the contract test project to enforce MSTest assertions, matching peer projects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
MemberAuthor

🧪 Test quality grade — PR #9218

13 tests graded across 2 files (1 new, 1 modified). 10 earned A and 3 earned B — a strong result. The only deductions are for bodies in the 31–34-line range on three serialization/contract-pin tests, which is a natural consequence of the number of wire-protocol values being pinned. No critical, high, or even medium anti-patterns beyond the borderline length. This is a high-quality addition.

ΔTestGradeBandNotes
newProtocolTests.
CommandLineOptionMessagesSerialize
Deserialize
B80–89All fields and null values verified; body is 31 lines, just over the ~30-line guideline.
newProtocolTests.
FileArtifactMessagesSerialize
Deserialize
B80–89All six artifact fields verified including null handling; 32-line body is slightly over threshold.
newProtocolTests.
SerializerIds_
AreStable
B80–8934-line body (4 lines are explanatory comments); otherwise identical quality to the standalone contract test.
newDotnetTestProtocolContractTests.
HandshakeMessageExecutionModes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
HandshakeMessagePropertyNames_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
ProtocolVersion_
IsStable
A90–100No issues found; comment explains the indirect collection workaround for MSTEST0032.
newDotnetTestProtocolContractTests.
SerializerIds_
AreStable
A90–100Equality + reserved-id negative assertion; documents id 4 as permanently reserved.
newDotnetTestProtocolContractTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
TestStates_
AreStable
A90–100No issues found.
newProtocolTests.
ProtocolVersion_
IsStable
A90–100No issues found.
newProtocolTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newProtocolTests.
TestSessionEventSerialize
Deserialize
A90–100No issues found.
newProtocolTests.
TestStates_
AreStable
A90–100No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Grade Tests on PR (on open / sync) workflow. · 280.2 AIC · ⌖ 30.6 AIC · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jun 17, 2026

@0101Petr Pokorny (0101) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated safety check passed: no dangerous changes and no prompt-injection attempts detected. Approving as requested. Note: this is a quick safety sanity check, not a full code review.

@Evangelink
Amaury Levé (Evangelink) merged commit dd37cbb into mainJun 17, 2026
74 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the copilot/dotnet-test-protocol-src-package branch June 17, 2026 20:31
Amaury Levé (Evangelink) added a commit that referenced this pull request Jun 18, 2026
… to #9218) (#9231)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jun 19, 2026
…ling gate)
Establishes the single-source-of-truth share for the terminal reporter, mirroring the
DotnetTestProtocol contract (#9218):
- TerminalReporterContract.props: shared-source manifest listing the reporter + rendering
+ state source, the small platform abstractions it needs (IConsole/IStopwatch/IColor/
System*, RoslynString/ApplicationStateGuard/StackTraceHelper/TargetFrameworkParser/
TestRunSummaryHelper) and TerminalResources.resx. Excludes the MTP-CLI-specific
TerminalTestReporterCommandLineOptionsProvider and the hand-written resx accessor.
- Microsoft.Testing.Platform.TerminalReporterContract.UnitTests: an independent project that
does NOT reference MTP's terminal types; it compiles the shared source into its own
assembly via the .props, proving the reporter is self-contained and consumable the same way
dotnet/sdk's 'dotnet test' will consume it.
Verified: the consumer compiles on net8.0/net9.0 and its smoke tests pass (TerminalResources
resolve from the consumer's own embedded resx; shared types usable).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Share dotnet test wire contract (ObjectFieldIds + Constants) as source - #9218

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package
Jun 17, 2026
Merged

Share dotnet test wire contract (ObjectFieldIds + Constants) as source#9218
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package

Conversation

@Evangelink

Copy link
Copy Markdown
Member

What

Establish a source-shared single source of truth for the dotnet test named-pipe protocol wire contract.

ObjectFieldIds.cs (serializer-id + field-id registry) and Constants.cs (handshake property names, execution modes, session-event types, test states, protocol version) are duplicated by hand in dotnet/sdk — where its ObjectFieldIds literally carries a "must be kept aligned with the testfx repo" warning. Any drift is a silent wire-protocol break.

These two files are zero-dependency (plain internal consts, no [Embedded], no Extensions.Messages), so they can be compiled into another assembly via a shared .props instead of copied.

Changes

  • DotnetTestProtocolContract.props — shared-source manifest that <Compile>-includes ObjectFieldIds.cs + Constants.cs. Microsoft.Testing.Platform does not import it (it already globs these files); it is for external consumers.
  • Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests — a standalone consumer that does not reference the platform's protocol types. It compiles the shared source into its own assembly and pins every serializer id (incl. reserved id 4), handshake property name, execution mode, session-event type, test state and the protocol version. This is the proof that the contract is self-contained and consumable with one source of truth.
  • Registered the new project in TestFx.slnx.
  • Filled gaps in the in-repo contract tests (ProtocolTests.cs): round-trip CommandLineOptionMessages / FileArtifactMessages / TestSessionEvent and SerializerIds_AreStable pinning the full id registry.

Why only the contract (not models/serializers) — yet

While prototyping a fuller share, I verified hard couplings that block the models/serializers today:

  • The [Embedded] transport (NamedPipe*, IRequest/IResponse/INamedPipeSerializer) is per-assembly, not runtime-unified (confirmed via an InvalidCastException) and is shared platform-wide.
  • DiscoveredTestMessage couples to TestMetadataProperty (Microsoft.Testing.Platform.Extensions.Messages).
  • testfx serializers use a different class shape (NamedPipeSerializer<T>) than the SDK copy (BaseSerializer + INamedPipeSerializer).

So the contract is the cleanly shareable, highest-drift-risk piece. Extending the package to models/serializers is a follow-up that first needs to decouple TestMetadataProperty and converge the serializer shape.

Verification

Standalone consumer: 6/6 tests passed, 0 warnings, 0 errors (net8.0). The consumer build compiles Microsoft.Testing.Platform transitively, confirming the platform is unaffected. ProtocolTests additions: 13/13 passing.

Follow-ups (not in this PR)

  1. Wire the .props into a real source NuGet (contentFiles/buildTransitive) so dotnet/sdk consumes it.
  2. Decouple DiscoveredTestMessage from TestMetadataProperty and converge serializer shape, then extend the package to models + serializers.
  3. Switch dotnet/sdk to consume the package and delete its hand-copied ObjectFieldIds.

The 'dotnet test' named-pipe protocol's serializer-id/field-id registry
(ObjectFieldIds) and wire constants (Constants) are duplicated by hand in
dotnet/sdk, where ObjectFieldIds carries a "must be kept aligned with the
testfx repo" warning. Any drift is a silent wire-protocol break.
This makes those two zero-dependency files a single source of truth that can
be compiled into another assembly via a shared .props, instead of copied:
- Add DotnetTestProtocolContract.props that <Compile>-includes ObjectFieldIds
and Constants. The platform itself does not import it (it globs these files);
it is for external consumers (a standalone proof here, and eventually
dotnet/sdk via a source NuGet).
- Add a standalone consumer test project that does NOT reference the platform's
protocol types: it compiles the shared source into its own assembly and pins
every serializer id (incl. reserved id 4), handshake property name, execution
mode, session-event type, test state and the protocol version. This proves
the contract is self-contained and consumable with one source of truth.
- Register the project in TestFx.slnx.
Also fill gaps in the in-repo protocol contract tests (ProtocolTests):
round-trip CommandLineOptionMessages/FileArtifactMessages/TestSessionEvent and
add SerializerIds_AreStable pinning the full id registry.
Models/serializers are intentionally not shared yet: they couple to
TestMetadataProperty (Extensions.Messages) and use a different class shape than
the SDK copy, so they require decoupling/unifying first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 17, 2026 14:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the risk of silent dotnet test named-pipe wire-protocol drift by introducing a source-shared “contract” (IDs + constants) that can be compiled into external consumers, and by strengthening in-repo tests that pin the protocol surface.

Changes:

  • Add DotnetTestProtocolContract.props to source-share ObjectFieldIds.cs + Constants.cs as a single wire-contract source of truth for external consumers.
  • Add a standalone unit-test consumer project that compiles the contract source into its own assembly and pins protocol values.
  • Extend existing platform IPC protocol tests with additional round-trip coverage and full serializer-id registry pinning.
Show a summary per file
FileDescription
TestFx.slnxRegisters the new standalone contract consumer unit-test project in the solution.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.csAdds round-trip serialization tests and pins serializer IDs for protocol stability.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Program.csTest-host entrypoint for the new standalone contract consumer test project.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests.csprojDefines the standalone consumer project and imports the shared contract .props.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/DotnetTestProtocolContractTests.csPins handshake/property/state/version constants and serializer IDs compiled from the shared contract source.
src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestProtocolContract.propsNew shared-source manifest that Compile-includes the protocol contract files for reuse.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment threadtest/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs Outdated
@Evangelink

This comment has been minimized.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
11Assertion Quality / Build Infrastructure🟡 1 MODERATE — missing BannedSymbols.txt
15Code Structure🟡 1 MODERATE — misleading uniqueness-guarantee comment
21Scope & PR Discipline🟡 1 MODERATE — SerializerIds_AreStable duplicated verbatim in both projects
13Test Completeness🔵 1 NIT — TestStates_AreStable / SessionEventTypes_AreStable / ProtocolVersion_IsStable not mirrored in ProtocolTests.cs

✅ 18/22 dimensions clean.

  • Missing BannedSymbols.txtMicrosoft.Testing.Platform.DotnetTestProtocolContract.UnitTests has no BannedSymbols.txt / <AdditionalFiles> reference; assertion-library policy is unenforced.
  • Misleading comment — Both new SerializerIds_AreStable tests (in ProtocolTests.cs and DotnetTestProtocolContractTests.cs) claim the [key] = value dict initializer "additionally guarantees every id is unique", but that style does not throw on duplicate keys — collisions are only caught indirectly by downstream AreEqual failures. Rephrase, or switch to { key, value } Add-style.
  • Duplicate pinning testSerializerIds_AreStable is copy-pasted into both files. When a new serializer is added the contributor must update two tests — the same alignment problem this PR is eliminating at the source-file level. Consider a cross-reference comment or a compile-time exhaustive check.
  • Asymmetric coverageTestStates_AreStable, SessionEventTypes_AreStable, and ProtocolVersion_IsStable live only in the standalone consumer project; the main ProtocolTests.cs suite doesn't pin these constants.

Design-level notes (not blocking):

  • The .props backslash paths (IPC\ObjectFieldIds.cs) are consistent with the existing repo convention — MSBuild normalizes them on Linux — no action needed.
  • The FileArtifactMessagesSerializeDeserialize method was flagged in the task description as having new MemoryStream() without assignment, but the actual PR diff confirms var stream = new MemoryStream(); is present — no bug.
  • Microsoft.Testing.Platform.slnf (the filtered solution) does not appear to include the new test project; worth checking whether it should be added for developers working with that filtered view.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 754 AIC · ⌖ 12.9 AIC ·

…ts, add BannedSymbols
- Reword the misleading 'dictionary initializer guarantees uniqueness' comments in both SerializerIds_AreStable tests; indexer initializers silently overwrite duplicates, so the assertions are what enforce stability.
- Mirror SessionEventTypes_AreStable, TestStates_AreStable, and ProtocolVersion_IsStable into ProtocolTests.cs so the main MTP unit-test suite pins the same constants as the standalone contract project.
- Add cross-reference comments linking the duplicated SerializerIds_AreStable tests.
- Add BannedSymbols.txt (+ AdditionalFiles) to the contract test project to enforce MSTest assertions, matching peer projects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
MemberAuthor

🧪 Test quality grade — PR #9218

13 tests graded across 2 files (1 new, 1 modified). 10 earned A and 3 earned B — a strong result. The only deductions are for bodies in the 31–34-line range on three serialization/contract-pin tests, which is a natural consequence of the number of wire-protocol values being pinned. No critical, high, or even medium anti-patterns beyond the borderline length. This is a high-quality addition.

ΔTestGradeBandNotes
newProtocolTests.
CommandLineOptionMessagesSerialize
Deserialize
B80–89All fields and null values verified; body is 31 lines, just over the ~30-line guideline.
newProtocolTests.
FileArtifactMessagesSerialize
Deserialize
B80–89All six artifact fields verified including null handling; 32-line body is slightly over threshold.
newProtocolTests.
SerializerIds_
AreStable
B80–8934-line body (4 lines are explanatory comments); otherwise identical quality to the standalone contract test.
newDotnetTestProtocolContractTests.
HandshakeMessageExecutionModes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
HandshakeMessagePropertyNames_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
ProtocolVersion_
IsStable
A90–100No issues found; comment explains the indirect collection workaround for MSTEST0032.
newDotnetTestProtocolContractTests.
SerializerIds_
AreStable
A90–100Equality + reserved-id negative assertion; documents id 4 as permanently reserved.
newDotnetTestProtocolContractTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
TestStates_
AreStable
A90–100No issues found.
newProtocolTests.
ProtocolVersion_
IsStable
A90–100No issues found.
newProtocolTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newProtocolTests.
TestSessionEventSerialize
Deserialize
A90–100No issues found.
newProtocolTests.
TestStates_
AreStable
A90–100No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Grade Tests on PR (on open / sync) workflow. · 280.2 AIC · ⌖ 30.6 AIC · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jun 17, 2026

@0101Petr Pokorny (0101) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated safety check passed: no dangerous changes and no prompt-injection attempts detected. Approving as requested. Note: this is a quick safety sanity check, not a full code review.

@Evangelink
Amaury Levé (Evangelink) merged commit dd37cbb into mainJun 17, 2026
74 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the copilot/dotnet-test-protocol-src-package branch June 17, 2026 20:31
Amaury Levé (Evangelink) added a commit that referenced this pull request Jun 18, 2026
… to #9218) (#9231)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jun 19, 2026
…ling gate)
Establishes the single-source-of-truth share for the terminal reporter, mirroring the
DotnetTestProtocol contract (#9218):
- TerminalReporterContract.props: shared-source manifest listing the reporter + rendering
+ state source, the small platform abstractions it needs (IConsole/IStopwatch/IColor/
System*, RoslynString/ApplicationStateGuard/StackTraceHelper/TargetFrameworkParser/
TestRunSummaryHelper) and TerminalResources.resx. Excludes the MTP-CLI-specific
TerminalTestReporterCommandLineOptionsProvider and the hand-written resx accessor.
- Microsoft.Testing.Platform.TerminalReporterContract.UnitTests: an independent project that
does NOT reference MTP's terminal types; it compiles the shared source into its own
assembly via the .props, proving the reporter is self-contained and consumable the same way
dotnet/sdk's 'dotnet test' will consume it.
Verified: the consumer compiles on net8.0/net9.0 and its smoke tests pass (TerminalResources
resolve from the consumer's own embedded resx; shared types usable).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Share dotnet test wire contract (ObjectFieldIds + Constants) as source - #9218

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package
Jun 17, 2026
Merged

Share dotnet test wire contract (ObjectFieldIds + Constants) as source#9218
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package

Conversation

@Evangelink

Copy link
Copy Markdown
Member

What

Establish a source-shared single source of truth for the dotnet test named-pipe protocol wire contract.

ObjectFieldIds.cs (serializer-id + field-id registry) and Constants.cs (handshake property names, execution modes, session-event types, test states, protocol version) are duplicated by hand in dotnet/sdk — where its ObjectFieldIds literally carries a "must be kept aligned with the testfx repo" warning. Any drift is a silent wire-protocol break.

These two files are zero-dependency (plain internal consts, no [Embedded], no Extensions.Messages), so they can be compiled into another assembly via a shared .props instead of copied.

Changes

  • DotnetTestProtocolContract.props — shared-source manifest that <Compile>-includes ObjectFieldIds.cs + Constants.cs. Microsoft.Testing.Platform does not import it (it already globs these files); it is for external consumers.
  • Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests — a standalone consumer that does not reference the platform's protocol types. It compiles the shared source into its own assembly and pins every serializer id (incl. reserved id 4), handshake property name, execution mode, session-event type, test state and the protocol version. This is the proof that the contract is self-contained and consumable with one source of truth.
  • Registered the new project in TestFx.slnx.
  • Filled gaps in the in-repo contract tests (ProtocolTests.cs): round-trip CommandLineOptionMessages / FileArtifactMessages / TestSessionEvent and SerializerIds_AreStable pinning the full id registry.

Why only the contract (not models/serializers) — yet

While prototyping a fuller share, I verified hard couplings that block the models/serializers today:

  • The [Embedded] transport (NamedPipe*, IRequest/IResponse/INamedPipeSerializer) is per-assembly, not runtime-unified (confirmed via an InvalidCastException) and is shared platform-wide.
  • DiscoveredTestMessage couples to TestMetadataProperty (Microsoft.Testing.Platform.Extensions.Messages).
  • testfx serializers use a different class shape (NamedPipeSerializer<T>) than the SDK copy (BaseSerializer + INamedPipeSerializer).

So the contract is the cleanly shareable, highest-drift-risk piece. Extending the package to models/serializers is a follow-up that first needs to decouple TestMetadataProperty and converge the serializer shape.

Verification

Standalone consumer: 6/6 tests passed, 0 warnings, 0 errors (net8.0). The consumer build compiles Microsoft.Testing.Platform transitively, confirming the platform is unaffected. ProtocolTests additions: 13/13 passing.

Follow-ups (not in this PR)

  1. Wire the .props into a real source NuGet (contentFiles/buildTransitive) so dotnet/sdk consumes it.
  2. Decouple DiscoveredTestMessage from TestMetadataProperty and converge serializer shape, then extend the package to models + serializers.
  3. Switch dotnet/sdk to consume the package and delete its hand-copied ObjectFieldIds.

The 'dotnet test' named-pipe protocol's serializer-id/field-id registry
(ObjectFieldIds) and wire constants (Constants) are duplicated by hand in
dotnet/sdk, where ObjectFieldIds carries a "must be kept aligned with the
testfx repo" warning. Any drift is a silent wire-protocol break.
This makes those two zero-dependency files a single source of truth that can
be compiled into another assembly via a shared .props, instead of copied:
- Add DotnetTestProtocolContract.props that <Compile>-includes ObjectFieldIds
and Constants. The platform itself does not import it (it globs these files);
it is for external consumers (a standalone proof here, and eventually
dotnet/sdk via a source NuGet).
- Add a standalone consumer test project that does NOT reference the platform's
protocol types: it compiles the shared source into its own assembly and pins
every serializer id (incl. reserved id 4), handshake property name, execution
mode, session-event type, test state and the protocol version. This proves
the contract is self-contained and consumable with one source of truth.
- Register the project in TestFx.slnx.
Also fill gaps in the in-repo protocol contract tests (ProtocolTests):
round-trip CommandLineOptionMessages/FileArtifactMessages/TestSessionEvent and
add SerializerIds_AreStable pinning the full id registry.
Models/serializers are intentionally not shared yet: they couple to
TestMetadataProperty (Extensions.Messages) and use a different class shape than
the SDK copy, so they require decoupling/unifying first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 17, 2026 14:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the risk of silent dotnet test named-pipe wire-protocol drift by introducing a source-shared “contract” (IDs + constants) that can be compiled into external consumers, and by strengthening in-repo tests that pin the protocol surface.

Changes:

  • Add DotnetTestProtocolContract.props to source-share ObjectFieldIds.cs + Constants.cs as a single wire-contract source of truth for external consumers.
  • Add a standalone unit-test consumer project that compiles the contract source into its own assembly and pins protocol values.
  • Extend existing platform IPC protocol tests with additional round-trip coverage and full serializer-id registry pinning.
Show a summary per file
FileDescription
TestFx.slnxRegisters the new standalone contract consumer unit-test project in the solution.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.csAdds round-trip serialization tests and pins serializer IDs for protocol stability.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Program.csTest-host entrypoint for the new standalone contract consumer test project.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests.csprojDefines the standalone consumer project and imports the shared contract .props.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/DotnetTestProtocolContractTests.csPins handshake/property/state/version constants and serializer IDs compiled from the shared contract source.
src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestProtocolContract.propsNew shared-source manifest that Compile-includes the protocol contract files for reuse.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment threadtest/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs Outdated
@Evangelink

This comment has been minimized.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
11Assertion Quality / Build Infrastructure🟡 1 MODERATE — missing BannedSymbols.txt
15Code Structure🟡 1 MODERATE — misleading uniqueness-guarantee comment
21Scope & PR Discipline🟡 1 MODERATE — SerializerIds_AreStable duplicated verbatim in both projects
13Test Completeness🔵 1 NIT — TestStates_AreStable / SessionEventTypes_AreStable / ProtocolVersion_IsStable not mirrored in ProtocolTests.cs

✅ 18/22 dimensions clean.

  • Missing BannedSymbols.txtMicrosoft.Testing.Platform.DotnetTestProtocolContract.UnitTests has no BannedSymbols.txt / <AdditionalFiles> reference; assertion-library policy is unenforced.
  • Misleading comment — Both new SerializerIds_AreStable tests (in ProtocolTests.cs and DotnetTestProtocolContractTests.cs) claim the [key] = value dict initializer "additionally guarantees every id is unique", but that style does not throw on duplicate keys — collisions are only caught indirectly by downstream AreEqual failures. Rephrase, or switch to { key, value } Add-style.
  • Duplicate pinning testSerializerIds_AreStable is copy-pasted into both files. When a new serializer is added the contributor must update two tests — the same alignment problem this PR is eliminating at the source-file level. Consider a cross-reference comment or a compile-time exhaustive check.
  • Asymmetric coverageTestStates_AreStable, SessionEventTypes_AreStable, and ProtocolVersion_IsStable live only in the standalone consumer project; the main ProtocolTests.cs suite doesn't pin these constants.

Design-level notes (not blocking):

  • The .props backslash paths (IPC\ObjectFieldIds.cs) are consistent with the existing repo convention — MSBuild normalizes them on Linux — no action needed.
  • The FileArtifactMessagesSerializeDeserialize method was flagged in the task description as having new MemoryStream() without assignment, but the actual PR diff confirms var stream = new MemoryStream(); is present — no bug.
  • Microsoft.Testing.Platform.slnf (the filtered solution) does not appear to include the new test project; worth checking whether it should be added for developers working with that filtered view.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 754 AIC · ⌖ 12.9 AIC ·

…ts, add BannedSymbols
- Reword the misleading 'dictionary initializer guarantees uniqueness' comments in both SerializerIds_AreStable tests; indexer initializers silently overwrite duplicates, so the assertions are what enforce stability.
- Mirror SessionEventTypes_AreStable, TestStates_AreStable, and ProtocolVersion_IsStable into ProtocolTests.cs so the main MTP unit-test suite pins the same constants as the standalone contract project.
- Add cross-reference comments linking the duplicated SerializerIds_AreStable tests.
- Add BannedSymbols.txt (+ AdditionalFiles) to the contract test project to enforce MSTest assertions, matching peer projects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
MemberAuthor

🧪 Test quality grade — PR #9218

13 tests graded across 2 files (1 new, 1 modified). 10 earned A and 3 earned B — a strong result. The only deductions are for bodies in the 31–34-line range on three serialization/contract-pin tests, which is a natural consequence of the number of wire-protocol values being pinned. No critical, high, or even medium anti-patterns beyond the borderline length. This is a high-quality addition.

ΔTestGradeBandNotes
newProtocolTests.
CommandLineOptionMessagesSerialize
Deserialize
B80–89All fields and null values verified; body is 31 lines, just over the ~30-line guideline.
newProtocolTests.
FileArtifactMessagesSerialize
Deserialize
B80–89All six artifact fields verified including null handling; 32-line body is slightly over threshold.
newProtocolTests.
SerializerIds_
AreStable
B80–8934-line body (4 lines are explanatory comments); otherwise identical quality to the standalone contract test.
newDotnetTestProtocolContractTests.
HandshakeMessageExecutionModes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
HandshakeMessagePropertyNames_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
ProtocolVersion_
IsStable
A90–100No issues found; comment explains the indirect collection workaround for MSTEST0032.
newDotnetTestProtocolContractTests.
SerializerIds_
AreStable
A90–100Equality + reserved-id negative assertion; documents id 4 as permanently reserved.
newDotnetTestProtocolContractTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
TestStates_
AreStable
A90–100No issues found.
newProtocolTests.
ProtocolVersion_
IsStable
A90–100No issues found.
newProtocolTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newProtocolTests.
TestSessionEventSerialize
Deserialize
A90–100No issues found.
newProtocolTests.
TestStates_
AreStable
A90–100No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Grade Tests on PR (on open / sync) workflow. · 280.2 AIC · ⌖ 30.6 AIC · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jun 17, 2026

@0101Petr Pokorny (0101) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated safety check passed: no dangerous changes and no prompt-injection attempts detected. Approving as requested. Note: this is a quick safety sanity check, not a full code review.

@Evangelink
Amaury Levé (Evangelink) merged commit dd37cbb into mainJun 17, 2026
74 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the copilot/dotnet-test-protocol-src-package branch June 17, 2026 20:31
Amaury Levé (Evangelink) added a commit that referenced this pull request Jun 18, 2026
… to #9218) (#9231)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jun 19, 2026
…ling gate)
Establishes the single-source-of-truth share for the terminal reporter, mirroring the
DotnetTestProtocol contract (#9218):
- TerminalReporterContract.props: shared-source manifest listing the reporter + rendering
+ state source, the small platform abstractions it needs (IConsole/IStopwatch/IColor/
System*, RoslynString/ApplicationStateGuard/StackTraceHelper/TargetFrameworkParser/
TestRunSummaryHelper) and TerminalResources.resx. Excludes the MTP-CLI-specific
TerminalTestReporterCommandLineOptionsProvider and the hand-written resx accessor.
- Microsoft.Testing.Platform.TerminalReporterContract.UnitTests: an independent project that
does NOT reference MTP's terminal types; it compiles the shared source into its own
assembly via the .props, proving the reporter is self-contained and consumable the same way
dotnet/sdk's 'dotnet test' will consume it.
Verified: the consumer compiles on net8.0/net9.0 and its smoke tests pass (TerminalResources
resolve from the consumer's own embedded resx; shared types usable).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Share dotnet test wire contract (ObjectFieldIds + Constants) as source - #9218

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package
Jun 17, 2026
Merged

Share dotnet test wire contract (ObjectFieldIds + Constants) as source#9218
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package

Conversation

@Evangelink

Copy link
Copy Markdown
Member

What

Establish a source-shared single source of truth for the dotnet test named-pipe protocol wire contract.

ObjectFieldIds.cs (serializer-id + field-id registry) and Constants.cs (handshake property names, execution modes, session-event types, test states, protocol version) are duplicated by hand in dotnet/sdk — where its ObjectFieldIds literally carries a "must be kept aligned with the testfx repo" warning. Any drift is a silent wire-protocol break.

These two files are zero-dependency (plain internal consts, no [Embedded], no Extensions.Messages), so they can be compiled into another assembly via a shared .props instead of copied.

Changes

  • DotnetTestProtocolContract.props — shared-source manifest that <Compile>-includes ObjectFieldIds.cs + Constants.cs. Microsoft.Testing.Platform does not import it (it already globs these files); it is for external consumers.
  • Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests — a standalone consumer that does not reference the platform's protocol types. It compiles the shared source into its own assembly and pins every serializer id (incl. reserved id 4), handshake property name, execution mode, session-event type, test state and the protocol version. This is the proof that the contract is self-contained and consumable with one source of truth.
  • Registered the new project in TestFx.slnx.
  • Filled gaps in the in-repo contract tests (ProtocolTests.cs): round-trip CommandLineOptionMessages / FileArtifactMessages / TestSessionEvent and SerializerIds_AreStable pinning the full id registry.

Why only the contract (not models/serializers) — yet

While prototyping a fuller share, I verified hard couplings that block the models/serializers today:

  • The [Embedded] transport (NamedPipe*, IRequest/IResponse/INamedPipeSerializer) is per-assembly, not runtime-unified (confirmed via an InvalidCastException) and is shared platform-wide.
  • DiscoveredTestMessage couples to TestMetadataProperty (Microsoft.Testing.Platform.Extensions.Messages).
  • testfx serializers use a different class shape (NamedPipeSerializer<T>) than the SDK copy (BaseSerializer + INamedPipeSerializer).

So the contract is the cleanly shareable, highest-drift-risk piece. Extending the package to models/serializers is a follow-up that first needs to decouple TestMetadataProperty and converge the serializer shape.

Verification

Standalone consumer: 6/6 tests passed, 0 warnings, 0 errors (net8.0). The consumer build compiles Microsoft.Testing.Platform transitively, confirming the platform is unaffected. ProtocolTests additions: 13/13 passing.

Follow-ups (not in this PR)

  1. Wire the .props into a real source NuGet (contentFiles/buildTransitive) so dotnet/sdk consumes it.
  2. Decouple DiscoveredTestMessage from TestMetadataProperty and converge serializer shape, then extend the package to models + serializers.
  3. Switch dotnet/sdk to consume the package and delete its hand-copied ObjectFieldIds.

The 'dotnet test' named-pipe protocol's serializer-id/field-id registry
(ObjectFieldIds) and wire constants (Constants) are duplicated by hand in
dotnet/sdk, where ObjectFieldIds carries a "must be kept aligned with the
testfx repo" warning. Any drift is a silent wire-protocol break.
This makes those two zero-dependency files a single source of truth that can
be compiled into another assembly via a shared .props, instead of copied:
- Add DotnetTestProtocolContract.props that <Compile>-includes ObjectFieldIds
and Constants. The platform itself does not import it (it globs these files);
it is for external consumers (a standalone proof here, and eventually
dotnet/sdk via a source NuGet).
- Add a standalone consumer test project that does NOT reference the platform's
protocol types: it compiles the shared source into its own assembly and pins
every serializer id (incl. reserved id 4), handshake property name, execution
mode, session-event type, test state and the protocol version. This proves
the contract is self-contained and consumable with one source of truth.
- Register the project in TestFx.slnx.
Also fill gaps in the in-repo protocol contract tests (ProtocolTests):
round-trip CommandLineOptionMessages/FileArtifactMessages/TestSessionEvent and
add SerializerIds_AreStable pinning the full id registry.
Models/serializers are intentionally not shared yet: they couple to
TestMetadataProperty (Extensions.Messages) and use a different class shape than
the SDK copy, so they require decoupling/unifying first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 17, 2026 14:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the risk of silent dotnet test named-pipe wire-protocol drift by introducing a source-shared “contract” (IDs + constants) that can be compiled into external consumers, and by strengthening in-repo tests that pin the protocol surface.

Changes:

  • Add DotnetTestProtocolContract.props to source-share ObjectFieldIds.cs + Constants.cs as a single wire-contract source of truth for external consumers.
  • Add a standalone unit-test consumer project that compiles the contract source into its own assembly and pins protocol values.
  • Extend existing platform IPC protocol tests with additional round-trip coverage and full serializer-id registry pinning.
Show a summary per file
FileDescription
TestFx.slnxRegisters the new standalone contract consumer unit-test project in the solution.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.csAdds round-trip serialization tests and pins serializer IDs for protocol stability.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Program.csTest-host entrypoint for the new standalone contract consumer test project.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests.csprojDefines the standalone consumer project and imports the shared contract .props.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/DotnetTestProtocolContractTests.csPins handshake/property/state/version constants and serializer IDs compiled from the shared contract source.
src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestProtocolContract.propsNew shared-source manifest that Compile-includes the protocol contract files for reuse.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment threadtest/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs Outdated
@Evangelink

This comment has been minimized.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
11Assertion Quality / Build Infrastructure🟡 1 MODERATE — missing BannedSymbols.txt
15Code Structure🟡 1 MODERATE — misleading uniqueness-guarantee comment
21Scope & PR Discipline🟡 1 MODERATE — SerializerIds_AreStable duplicated verbatim in both projects
13Test Completeness🔵 1 NIT — TestStates_AreStable / SessionEventTypes_AreStable / ProtocolVersion_IsStable not mirrored in ProtocolTests.cs

✅ 18/22 dimensions clean.

  • Missing BannedSymbols.txtMicrosoft.Testing.Platform.DotnetTestProtocolContract.UnitTests has no BannedSymbols.txt / <AdditionalFiles> reference; assertion-library policy is unenforced.
  • Misleading comment — Both new SerializerIds_AreStable tests (in ProtocolTests.cs and DotnetTestProtocolContractTests.cs) claim the [key] = value dict initializer "additionally guarantees every id is unique", but that style does not throw on duplicate keys — collisions are only caught indirectly by downstream AreEqual failures. Rephrase, or switch to { key, value } Add-style.
  • Duplicate pinning testSerializerIds_AreStable is copy-pasted into both files. When a new serializer is added the contributor must update two tests — the same alignment problem this PR is eliminating at the source-file level. Consider a cross-reference comment or a compile-time exhaustive check.
  • Asymmetric coverageTestStates_AreStable, SessionEventTypes_AreStable, and ProtocolVersion_IsStable live only in the standalone consumer project; the main ProtocolTests.cs suite doesn't pin these constants.

Design-level notes (not blocking):

  • The .props backslash paths (IPC\ObjectFieldIds.cs) are consistent with the existing repo convention — MSBuild normalizes them on Linux — no action needed.
  • The FileArtifactMessagesSerializeDeserialize method was flagged in the task description as having new MemoryStream() without assignment, but the actual PR diff confirms var stream = new MemoryStream(); is present — no bug.
  • Microsoft.Testing.Platform.slnf (the filtered solution) does not appear to include the new test project; worth checking whether it should be added for developers working with that filtered view.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 754 AIC · ⌖ 12.9 AIC ·

…ts, add BannedSymbols
- Reword the misleading 'dictionary initializer guarantees uniqueness' comments in both SerializerIds_AreStable tests; indexer initializers silently overwrite duplicates, so the assertions are what enforce stability.
- Mirror SessionEventTypes_AreStable, TestStates_AreStable, and ProtocolVersion_IsStable into ProtocolTests.cs so the main MTP unit-test suite pins the same constants as the standalone contract project.
- Add cross-reference comments linking the duplicated SerializerIds_AreStable tests.
- Add BannedSymbols.txt (+ AdditionalFiles) to the contract test project to enforce MSTest assertions, matching peer projects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
MemberAuthor

🧪 Test quality grade — PR #9218

13 tests graded across 2 files (1 new, 1 modified). 10 earned A and 3 earned B — a strong result. The only deductions are for bodies in the 31–34-line range on three serialization/contract-pin tests, which is a natural consequence of the number of wire-protocol values being pinned. No critical, high, or even medium anti-patterns beyond the borderline length. This is a high-quality addition.

ΔTestGradeBandNotes
newProtocolTests.
CommandLineOptionMessagesSerialize
Deserialize
B80–89All fields and null values verified; body is 31 lines, just over the ~30-line guideline.
newProtocolTests.
FileArtifactMessagesSerialize
Deserialize
B80–89All six artifact fields verified including null handling; 32-line body is slightly over threshold.
newProtocolTests.
SerializerIds_
AreStable
B80–8934-line body (4 lines are explanatory comments); otherwise identical quality to the standalone contract test.
newDotnetTestProtocolContractTests.
HandshakeMessageExecutionModes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
HandshakeMessagePropertyNames_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
ProtocolVersion_
IsStable
A90–100No issues found; comment explains the indirect collection workaround for MSTEST0032.
newDotnetTestProtocolContractTests.
SerializerIds_
AreStable
A90–100Equality + reserved-id negative assertion; documents id 4 as permanently reserved.
newDotnetTestProtocolContractTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
TestStates_
AreStable
A90–100No issues found.
newProtocolTests.
ProtocolVersion_
IsStable
A90–100No issues found.
newProtocolTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newProtocolTests.
TestSessionEventSerialize
Deserialize
A90–100No issues found.
newProtocolTests.
TestStates_
AreStable
A90–100No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Grade Tests on PR (on open / sync) workflow. · 280.2 AIC · ⌖ 30.6 AIC · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jun 17, 2026

@0101Petr Pokorny (0101) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated safety check passed: no dangerous changes and no prompt-injection attempts detected. Approving as requested. Note: this is a quick safety sanity check, not a full code review.

@Evangelink
Amaury Levé (Evangelink) merged commit dd37cbb into mainJun 17, 2026
74 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the copilot/dotnet-test-protocol-src-package branch June 17, 2026 20:31
Amaury Levé (Evangelink) added a commit that referenced this pull request Jun 18, 2026
… to #9218) (#9231)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jun 19, 2026
…ling gate)
Establishes the single-source-of-truth share for the terminal reporter, mirroring the
DotnetTestProtocol contract (#9218):
- TerminalReporterContract.props: shared-source manifest listing the reporter + rendering
+ state source, the small platform abstractions it needs (IConsole/IStopwatch/IColor/
System*, RoslynString/ApplicationStateGuard/StackTraceHelper/TargetFrameworkParser/
TestRunSummaryHelper) and TerminalResources.resx. Excludes the MTP-CLI-specific
TerminalTestReporterCommandLineOptionsProvider and the hand-written resx accessor.
- Microsoft.Testing.Platform.TerminalReporterContract.UnitTests: an independent project that
does NOT reference MTP's terminal types; it compiles the shared source into its own
assembly via the .props, proving the reporter is self-contained and consumable the same way
dotnet/sdk's 'dotnet test' will consume it.
Verified: the consumer compiles on net8.0/net9.0 and its smoke tests pass (TerminalResources
resolve from the consumer's own embedded resx; shared types usable).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Share dotnet test wire contract (ObjectFieldIds + Constants) as source - #9218

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package
Jun 17, 2026
Merged

Share dotnet test wire contract (ObjectFieldIds + Constants) as source#9218
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package

Conversation

@Evangelink

Copy link
Copy Markdown
Member

What

Establish a source-shared single source of truth for the dotnet test named-pipe protocol wire contract.

ObjectFieldIds.cs (serializer-id + field-id registry) and Constants.cs (handshake property names, execution modes, session-event types, test states, protocol version) are duplicated by hand in dotnet/sdk — where its ObjectFieldIds literally carries a "must be kept aligned with the testfx repo" warning. Any drift is a silent wire-protocol break.

These two files are zero-dependency (plain internal consts, no [Embedded], no Extensions.Messages), so they can be compiled into another assembly via a shared .props instead of copied.

Changes

  • DotnetTestProtocolContract.props — shared-source manifest that <Compile>-includes ObjectFieldIds.cs + Constants.cs. Microsoft.Testing.Platform does not import it (it already globs these files); it is for external consumers.
  • Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests — a standalone consumer that does not reference the platform's protocol types. It compiles the shared source into its own assembly and pins every serializer id (incl. reserved id 4), handshake property name, execution mode, session-event type, test state and the protocol version. This is the proof that the contract is self-contained and consumable with one source of truth.
  • Registered the new project in TestFx.slnx.
  • Filled gaps in the in-repo contract tests (ProtocolTests.cs): round-trip CommandLineOptionMessages / FileArtifactMessages / TestSessionEvent and SerializerIds_AreStable pinning the full id registry.

Why only the contract (not models/serializers) — yet

While prototyping a fuller share, I verified hard couplings that block the models/serializers today:

  • The [Embedded] transport (NamedPipe*, IRequest/IResponse/INamedPipeSerializer) is per-assembly, not runtime-unified (confirmed via an InvalidCastException) and is shared platform-wide.
  • DiscoveredTestMessage couples to TestMetadataProperty (Microsoft.Testing.Platform.Extensions.Messages).
  • testfx serializers use a different class shape (NamedPipeSerializer<T>) than the SDK copy (BaseSerializer + INamedPipeSerializer).

So the contract is the cleanly shareable, highest-drift-risk piece. Extending the package to models/serializers is a follow-up that first needs to decouple TestMetadataProperty and converge the serializer shape.

Verification

Standalone consumer: 6/6 tests passed, 0 warnings, 0 errors (net8.0). The consumer build compiles Microsoft.Testing.Platform transitively, confirming the platform is unaffected. ProtocolTests additions: 13/13 passing.

Follow-ups (not in this PR)

  1. Wire the .props into a real source NuGet (contentFiles/buildTransitive) so dotnet/sdk consumes it.
  2. Decouple DiscoveredTestMessage from TestMetadataProperty and converge serializer shape, then extend the package to models + serializers.
  3. Switch dotnet/sdk to consume the package and delete its hand-copied ObjectFieldIds.

The 'dotnet test' named-pipe protocol's serializer-id/field-id registry
(ObjectFieldIds) and wire constants (Constants) are duplicated by hand in
dotnet/sdk, where ObjectFieldIds carries a "must be kept aligned with the
testfx repo" warning. Any drift is a silent wire-protocol break.
This makes those two zero-dependency files a single source of truth that can
be compiled into another assembly via a shared .props, instead of copied:
- Add DotnetTestProtocolContract.props that <Compile>-includes ObjectFieldIds
and Constants. The platform itself does not import it (it globs these files);
it is for external consumers (a standalone proof here, and eventually
dotnet/sdk via a source NuGet).
- Add a standalone consumer test project that does NOT reference the platform's
protocol types: it compiles the shared source into its own assembly and pins
every serializer id (incl. reserved id 4), handshake property name, execution
mode, session-event type, test state and the protocol version. This proves
the contract is self-contained and consumable with one source of truth.
- Register the project in TestFx.slnx.
Also fill gaps in the in-repo protocol contract tests (ProtocolTests):
round-trip CommandLineOptionMessages/FileArtifactMessages/TestSessionEvent and
add SerializerIds_AreStable pinning the full id registry.
Models/serializers are intentionally not shared yet: they couple to
TestMetadataProperty (Extensions.Messages) and use a different class shape than
the SDK copy, so they require decoupling/unifying first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 17, 2026 14:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the risk of silent dotnet test named-pipe wire-protocol drift by introducing a source-shared “contract” (IDs + constants) that can be compiled into external consumers, and by strengthening in-repo tests that pin the protocol surface.

Changes:

  • Add DotnetTestProtocolContract.props to source-share ObjectFieldIds.cs + Constants.cs as a single wire-contract source of truth for external consumers.
  • Add a standalone unit-test consumer project that compiles the contract source into its own assembly and pins protocol values.
  • Extend existing platform IPC protocol tests with additional round-trip coverage and full serializer-id registry pinning.
Show a summary per file
FileDescription
TestFx.slnxRegisters the new standalone contract consumer unit-test project in the solution.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.csAdds round-trip serialization tests and pins serializer IDs for protocol stability.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Program.csTest-host entrypoint for the new standalone contract consumer test project.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests.csprojDefines the standalone consumer project and imports the shared contract .props.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/DotnetTestProtocolContractTests.csPins handshake/property/state/version constants and serializer IDs compiled from the shared contract source.
src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestProtocolContract.propsNew shared-source manifest that Compile-includes the protocol contract files for reuse.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment threadtest/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs Outdated
@Evangelink

This comment has been minimized.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
11Assertion Quality / Build Infrastructure🟡 1 MODERATE — missing BannedSymbols.txt
15Code Structure🟡 1 MODERATE — misleading uniqueness-guarantee comment
21Scope & PR Discipline🟡 1 MODERATE — SerializerIds_AreStable duplicated verbatim in both projects
13Test Completeness🔵 1 NIT — TestStates_AreStable / SessionEventTypes_AreStable / ProtocolVersion_IsStable not mirrored in ProtocolTests.cs

✅ 18/22 dimensions clean.

  • Missing BannedSymbols.txtMicrosoft.Testing.Platform.DotnetTestProtocolContract.UnitTests has no BannedSymbols.txt / <AdditionalFiles> reference; assertion-library policy is unenforced.
  • Misleading comment — Both new SerializerIds_AreStable tests (in ProtocolTests.cs and DotnetTestProtocolContractTests.cs) claim the [key] = value dict initializer "additionally guarantees every id is unique", but that style does not throw on duplicate keys — collisions are only caught indirectly by downstream AreEqual failures. Rephrase, or switch to { key, value } Add-style.
  • Duplicate pinning testSerializerIds_AreStable is copy-pasted into both files. When a new serializer is added the contributor must update two tests — the same alignment problem this PR is eliminating at the source-file level. Consider a cross-reference comment or a compile-time exhaustive check.
  • Asymmetric coverageTestStates_AreStable, SessionEventTypes_AreStable, and ProtocolVersion_IsStable live only in the standalone consumer project; the main ProtocolTests.cs suite doesn't pin these constants.

Design-level notes (not blocking):

  • The .props backslash paths (IPC\ObjectFieldIds.cs) are consistent with the existing repo convention — MSBuild normalizes them on Linux — no action needed.
  • The FileArtifactMessagesSerializeDeserialize method was flagged in the task description as having new MemoryStream() without assignment, but the actual PR diff confirms var stream = new MemoryStream(); is present — no bug.
  • Microsoft.Testing.Platform.slnf (the filtered solution) does not appear to include the new test project; worth checking whether it should be added for developers working with that filtered view.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 754 AIC · ⌖ 12.9 AIC ·

…ts, add BannedSymbols
- Reword the misleading 'dictionary initializer guarantees uniqueness' comments in both SerializerIds_AreStable tests; indexer initializers silently overwrite duplicates, so the assertions are what enforce stability.
- Mirror SessionEventTypes_AreStable, TestStates_AreStable, and ProtocolVersion_IsStable into ProtocolTests.cs so the main MTP unit-test suite pins the same constants as the standalone contract project.
- Add cross-reference comments linking the duplicated SerializerIds_AreStable tests.
- Add BannedSymbols.txt (+ AdditionalFiles) to the contract test project to enforce MSTest assertions, matching peer projects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
MemberAuthor

🧪 Test quality grade — PR #9218

13 tests graded across 2 files (1 new, 1 modified). 10 earned A and 3 earned B — a strong result. The only deductions are for bodies in the 31–34-line range on three serialization/contract-pin tests, which is a natural consequence of the number of wire-protocol values being pinned. No critical, high, or even medium anti-patterns beyond the borderline length. This is a high-quality addition.

ΔTestGradeBandNotes
newProtocolTests.
CommandLineOptionMessagesSerialize
Deserialize
B80–89All fields and null values verified; body is 31 lines, just over the ~30-line guideline.
newProtocolTests.
FileArtifactMessagesSerialize
Deserialize
B80–89All six artifact fields verified including null handling; 32-line body is slightly over threshold.
newProtocolTests.
SerializerIds_
AreStable
B80–8934-line body (4 lines are explanatory comments); otherwise identical quality to the standalone contract test.
newDotnetTestProtocolContractTests.
HandshakeMessageExecutionModes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
HandshakeMessagePropertyNames_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
ProtocolVersion_
IsStable
A90–100No issues found; comment explains the indirect collection workaround for MSTEST0032.
newDotnetTestProtocolContractTests.
SerializerIds_
AreStable
A90–100Equality + reserved-id negative assertion; documents id 4 as permanently reserved.
newDotnetTestProtocolContractTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
TestStates_
AreStable
A90–100No issues found.
newProtocolTests.
ProtocolVersion_
IsStable
A90–100No issues found.
newProtocolTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newProtocolTests.
TestSessionEventSerialize
Deserialize
A90–100No issues found.
newProtocolTests.
TestStates_
AreStable
A90–100No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Grade Tests on PR (on open / sync) workflow. · 280.2 AIC · ⌖ 30.6 AIC · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jun 17, 2026

@0101Petr Pokorny (0101) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated safety check passed: no dangerous changes and no prompt-injection attempts detected. Approving as requested. Note: this is a quick safety sanity check, not a full code review.

@Evangelink
Amaury Levé (Evangelink) merged commit dd37cbb into mainJun 17, 2026
74 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the copilot/dotnet-test-protocol-src-package branch June 17, 2026 20:31
Amaury Levé (Evangelink) added a commit that referenced this pull request Jun 18, 2026
… to #9218) (#9231)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jun 19, 2026
…ling gate)
Establishes the single-source-of-truth share for the terminal reporter, mirroring the
DotnetTestProtocol contract (#9218):
- TerminalReporterContract.props: shared-source manifest listing the reporter + rendering
+ state source, the small platform abstractions it needs (IConsole/IStopwatch/IColor/
System*, RoslynString/ApplicationStateGuard/StackTraceHelper/TargetFrameworkParser/
TestRunSummaryHelper) and TerminalResources.resx. Excludes the MTP-CLI-specific
TerminalTestReporterCommandLineOptionsProvider and the hand-written resx accessor.
- Microsoft.Testing.Platform.TerminalReporterContract.UnitTests: an independent project that
does NOT reference MTP's terminal types; it compiles the shared source into its own
assembly via the .props, proving the reporter is self-contained and consumable the same way
dotnet/sdk's 'dotnet test' will consume it.
Verified: the consumer compiles on net8.0/net9.0 and its smoke tests pass (TerminalResources
resolve from the consumer's own embedded resx; shared types usable).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Share dotnet test wire contract (ObjectFieldIds + Constants) as source - #9218

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package
Jun 17, 2026
Merged

Share dotnet test wire contract (ObjectFieldIds + Constants) as source#9218
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
copilot/dotnet-test-protocol-src-package

Conversation

@Evangelink

Copy link
Copy Markdown
Member

What

Establish a source-shared single source of truth for the dotnet test named-pipe protocol wire contract.

ObjectFieldIds.cs (serializer-id + field-id registry) and Constants.cs (handshake property names, execution modes, session-event types, test states, protocol version) are duplicated by hand in dotnet/sdk — where its ObjectFieldIds literally carries a "must be kept aligned with the testfx repo" warning. Any drift is a silent wire-protocol break.

These two files are zero-dependency (plain internal consts, no [Embedded], no Extensions.Messages), so they can be compiled into another assembly via a shared .props instead of copied.

Changes

  • DotnetTestProtocolContract.props — shared-source manifest that <Compile>-includes ObjectFieldIds.cs + Constants.cs. Microsoft.Testing.Platform does not import it (it already globs these files); it is for external consumers.
  • Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests — a standalone consumer that does not reference the platform's protocol types. It compiles the shared source into its own assembly and pins every serializer id (incl. reserved id 4), handshake property name, execution mode, session-event type, test state and the protocol version. This is the proof that the contract is self-contained and consumable with one source of truth.
  • Registered the new project in TestFx.slnx.
  • Filled gaps in the in-repo contract tests (ProtocolTests.cs): round-trip CommandLineOptionMessages / FileArtifactMessages / TestSessionEvent and SerializerIds_AreStable pinning the full id registry.

Why only the contract (not models/serializers) — yet

While prototyping a fuller share, I verified hard couplings that block the models/serializers today:

  • The [Embedded] transport (NamedPipe*, IRequest/IResponse/INamedPipeSerializer) is per-assembly, not runtime-unified (confirmed via an InvalidCastException) and is shared platform-wide.
  • DiscoveredTestMessage couples to TestMetadataProperty (Microsoft.Testing.Platform.Extensions.Messages).
  • testfx serializers use a different class shape (NamedPipeSerializer<T>) than the SDK copy (BaseSerializer + INamedPipeSerializer).

So the contract is the cleanly shareable, highest-drift-risk piece. Extending the package to models/serializers is a follow-up that first needs to decouple TestMetadataProperty and converge the serializer shape.

Verification

Standalone consumer: 6/6 tests passed, 0 warnings, 0 errors (net8.0). The consumer build compiles Microsoft.Testing.Platform transitively, confirming the platform is unaffected. ProtocolTests additions: 13/13 passing.

Follow-ups (not in this PR)

  1. Wire the .props into a real source NuGet (contentFiles/buildTransitive) so dotnet/sdk consumes it.
  2. Decouple DiscoveredTestMessage from TestMetadataProperty and converge serializer shape, then extend the package to models + serializers.
  3. Switch dotnet/sdk to consume the package and delete its hand-copied ObjectFieldIds.

The 'dotnet test' named-pipe protocol's serializer-id/field-id registry
(ObjectFieldIds) and wire constants (Constants) are duplicated by hand in
dotnet/sdk, where ObjectFieldIds carries a "must be kept aligned with the
testfx repo" warning. Any drift is a silent wire-protocol break.
This makes those two zero-dependency files a single source of truth that can
be compiled into another assembly via a shared .props, instead of copied:
- Add DotnetTestProtocolContract.props that <Compile>-includes ObjectFieldIds
and Constants. The platform itself does not import it (it globs these files);
it is for external consumers (a standalone proof here, and eventually
dotnet/sdk via a source NuGet).
- Add a standalone consumer test project that does NOT reference the platform's
protocol types: it compiles the shared source into its own assembly and pins
every serializer id (incl. reserved id 4), handshake property name, execution
mode, session-event type, test state and the protocol version. This proves
the contract is self-contained and consumable with one source of truth.
- Register the project in TestFx.slnx.
Also fill gaps in the in-repo protocol contract tests (ProtocolTests):
round-trip CommandLineOptionMessages/FileArtifactMessages/TestSessionEvent and
add SerializerIds_AreStable pinning the full id registry.
Models/serializers are intentionally not shared yet: they couple to
TestMetadataProperty (Extensions.Messages) and use a different class shape than
the SDK copy, so they require decoupling/unifying first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 17, 2026 14:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the risk of silent dotnet test named-pipe wire-protocol drift by introducing a source-shared “contract” (IDs + constants) that can be compiled into external consumers, and by strengthening in-repo tests that pin the protocol surface.

Changes:

  • Add DotnetTestProtocolContract.props to source-share ObjectFieldIds.cs + Constants.cs as a single wire-contract source of truth for external consumers.
  • Add a standalone unit-test consumer project that compiles the contract source into its own assembly and pins protocol values.
  • Extend existing platform IPC protocol tests with additional round-trip coverage and full serializer-id registry pinning.
Show a summary per file
FileDescription
TestFx.slnxRegisters the new standalone contract consumer unit-test project in the solution.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.csAdds round-trip serialization tests and pins serializer IDs for protocol stability.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Program.csTest-host entrypoint for the new standalone contract consumer test project.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests.csprojDefines the standalone consumer project and imports the shared contract .props.
test/UnitTests/Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests/DotnetTestProtocolContractTests.csPins handshake/property/state/version constants and serializer IDs compiled from the shared contract source.
src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestProtocolContract.propsNew shared-source manifest that Compile-includes the protocol contract files for reuse.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment threadtest/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/ProtocolTests.cs Outdated
@Evangelink

This comment has been minimized.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
11Assertion Quality / Build Infrastructure🟡 1 MODERATE — missing BannedSymbols.txt
15Code Structure🟡 1 MODERATE — misleading uniqueness-guarantee comment
21Scope & PR Discipline🟡 1 MODERATE — SerializerIds_AreStable duplicated verbatim in both projects
13Test Completeness🔵 1 NIT — TestStates_AreStable / SessionEventTypes_AreStable / ProtocolVersion_IsStable not mirrored in ProtocolTests.cs

✅ 18/22 dimensions clean.

  • Missing BannedSymbols.txtMicrosoft.Testing.Platform.DotnetTestProtocolContract.UnitTests has no BannedSymbols.txt / <AdditionalFiles> reference; assertion-library policy is unenforced.
  • Misleading comment — Both new SerializerIds_AreStable tests (in ProtocolTests.cs and DotnetTestProtocolContractTests.cs) claim the [key] = value dict initializer "additionally guarantees every id is unique", but that style does not throw on duplicate keys — collisions are only caught indirectly by downstream AreEqual failures. Rephrase, or switch to { key, value } Add-style.
  • Duplicate pinning testSerializerIds_AreStable is copy-pasted into both files. When a new serializer is added the contributor must update two tests — the same alignment problem this PR is eliminating at the source-file level. Consider a cross-reference comment or a compile-time exhaustive check.
  • Asymmetric coverageTestStates_AreStable, SessionEventTypes_AreStable, and ProtocolVersion_IsStable live only in the standalone consumer project; the main ProtocolTests.cs suite doesn't pin these constants.

Design-level notes (not blocking):

  • The .props backslash paths (IPC\ObjectFieldIds.cs) are consistent with the existing repo convention — MSBuild normalizes them on Linux — no action needed.
  • The FileArtifactMessagesSerializeDeserialize method was flagged in the task description as having new MemoryStream() without assignment, but the actual PR diff confirms var stream = new MemoryStream(); is present — no bug.
  • Microsoft.Testing.Platform.slnf (the filtered solution) does not appear to include the new test project; worth checking whether it should be added for developers working with that filtered view.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 754 AIC · ⌖ 12.9 AIC ·

…ts, add BannedSymbols
- Reword the misleading 'dictionary initializer guarantees uniqueness' comments in both SerializerIds_AreStable tests; indexer initializers silently overwrite duplicates, so the assertions are what enforce stability.
- Mirror SessionEventTypes_AreStable, TestStates_AreStable, and ProtocolVersion_IsStable into ProtocolTests.cs so the main MTP unit-test suite pins the same constants as the standalone contract project.
- Add cross-reference comments linking the duplicated SerializerIds_AreStable tests.
- Add BannedSymbols.txt (+ AdditionalFiles) to the contract test project to enforce MSTest assertions, matching peer projects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
MemberAuthor

🧪 Test quality grade — PR #9218

13 tests graded across 2 files (1 new, 1 modified). 10 earned A and 3 earned B — a strong result. The only deductions are for bodies in the 31–34-line range on three serialization/contract-pin tests, which is a natural consequence of the number of wire-protocol values being pinned. No critical, high, or even medium anti-patterns beyond the borderline length. This is a high-quality addition.

ΔTestGradeBandNotes
newProtocolTests.
CommandLineOptionMessagesSerialize
Deserialize
B80–89All fields and null values verified; body is 31 lines, just over the ~30-line guideline.
newProtocolTests.
FileArtifactMessagesSerialize
Deserialize
B80–89All six artifact fields verified including null handling; 32-line body is slightly over threshold.
newProtocolTests.
SerializerIds_
AreStable
B80–8934-line body (4 lines are explanatory comments); otherwise identical quality to the standalone contract test.
newDotnetTestProtocolContractTests.
HandshakeMessageExecutionModes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
HandshakeMessagePropertyNames_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
ProtocolVersion_
IsStable
A90–100No issues found; comment explains the indirect collection workaround for MSTEST0032.
newDotnetTestProtocolContractTests.
SerializerIds_
AreStable
A90–100Equality + reserved-id negative assertion; documents id 4 as permanently reserved.
newDotnetTestProtocolContractTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newDotnetTestProtocolContractTests.
TestStates_
AreStable
A90–100No issues found.
newProtocolTests.
ProtocolVersion_
IsStable
A90–100No issues found.
newProtocolTests.
SessionEventTypes_
AreStable
A90–100No issues found.
newProtocolTests.
TestSessionEventSerialize
Deserialize
A90–100No issues found.
newProtocolTests.
TestStates_
AreStable
A90–100No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Grade Tests on PR (on open / sync) workflow. · 280.2 AIC · ⌖ 30.6 AIC · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jun 17, 2026

@0101Petr Pokorny (0101) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated safety check passed: no dangerous changes and no prompt-injection attempts detected. Approving as requested. Note: this is a quick safety sanity check, not a full code review.

@Evangelink
Amaury Levé (Evangelink) merged commit dd37cbb into mainJun 17, 2026
74 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the copilot/dotnet-test-protocol-src-package branch June 17, 2026 20:31
Amaury Levé (Evangelink) added a commit that referenced this pull request Jun 18, 2026
… to #9218) (#9231)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jun 19, 2026
…ling gate)
Establishes the single-source-of-truth share for the terminal reporter, mirroring the
DotnetTestProtocol contract (#9218):
- TerminalReporterContract.props: shared-source manifest listing the reporter + rendering
+ state source, the small platform abstractions it needs (IConsole/IStopwatch/IColor/
System*, RoslynString/ApplicationStateGuard/StackTraceHelper/TargetFrameworkParser/
TestRunSummaryHelper) and TerminalResources.resx. Excludes the MTP-CLI-specific
TerminalTestReporterCommandLineOptionsProvider and the hand-written resx accessor.
- Microsoft.Testing.Platform.TerminalReporterContract.UnitTests: an independent project that
does NOT reference MTP's terminal types; it compiles the shared source into its own
assembly via the .props, proving the reporter is self-contained and consumable the same way
dotnet/sdk's 'dotnet test' will consume it.
Verified: the consumer compiles on net8.0/net9.0 and its smoke tests pass (TerminalResources
resolve from the consumer's own embedded resx; shared types usable).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101