From 4630df9032f5aa92e45d492a7de659db34ff9cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deniz=20=C4=B0rgin?= Date: Sat, 17 Oct 2026 13:15:08 +0300 Subject: [PATCH] test: the emission and ingestion tests that only read the pinned spec share its one binding TST-E3 first half, PR 3. Eight emission and ingestion test classes read Document, Curation or Plan from the session-shared PinnedBinding instead of ingesting or binding the pin themselves (22 ingestions per session become 3: the fixture plus PinnedSpecSmokeTests' two deliberately independent determinism ingestions, now commented). No assertion, test name or argument row changes. --- .../ExperimentalSurfaceEmissionTests.cs | 7 ++++--- .../Emission/HandWrittenDoorRemarksTests.cs | 5 +++-- .../HandWrittenExperimentalDoorTests.cs | 6 ++++-- .../Emission/HandWrittenTransportTableTests.cs | 5 +++-- .../Emission/OptionalConverterEmitterTests.cs | 12 ++++++------ .../SessionScopedEventEmissionTests.cs | 5 +++-- .../Generator/Emission/SourceEmitterTests.cs | 11 ++++++----- .../Ingestion/PinnedSpecSmokeTests.cs | 18 ++++++++++-------- 8 files changed, 39 insertions(+), 30 deletions(-) diff --git a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/ExperimentalSurfaceEmissionTests.cs b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/ExperimentalSurfaceEmissionTests.cs index f2f7d340..56070093 100644 --- a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/ExperimentalSurfaceEmissionTests.cs +++ b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/ExperimentalSurfaceEmissionTests.cs @@ -16,7 +16,8 @@ namespace OpenCode.Sdk.Tools.Tests.Generator.Emission; /// on the per-operation records and the types only experimental operations reach, and never on an /// internal artifact. A consumer compilation proves the emitted id is the one the compiler reports. /// -public sealed class ExperimentalSurfaceEmissionTests +[ClassDataSource(Shared = SharedType.PerTestSession)] +public sealed class ExperimentalSurfaceEmissionTests(PinnedBinding pinned) { [Test] public async Task Emit_Should_Mark_An_All_Experimental_Handle_With_An_Unmarked_Empty_Collection() @@ -205,7 +206,7 @@ public async Task Emit_Should_Mark_A_Structural_Union_And_Its_Kind_But_Not_Its_C [Test] public async Task Emit_Should_Mark_A_Hoisted_Interface_From_Its_Plan() { - var plan = await new BindingTestHost().BindPinnedAsync(); + var plan = pinned.Plan; var hoisted = plan.HoistedInterfaces.Single(static value => value.Name == "IDurableEnvelope") with { ExperimentalDiagnostic = "OPENCODE003" }; var sources = HoistedInterfaceEmitter.Emit([hoisted], plan.Placement); @@ -217,7 +218,7 @@ public async Task Emit_Should_Mark_A_Hoisted_Interface_From_Its_Plan() [ParallelLimiter] public async Task Compile_Should_Report_The_Experimental_Diagnostic_Unless_The_Consumer_Suppresses_It() { - var sources = SourceEmitter.Emit(await new BindingTestHost().BindPinnedAsync()); + var sources = SourceEmitter.Emit(pinned.Plan); var consumer = ExperimentalConsumerSyntax.CreateTree(); var unsuppressed = await GeneratedSourceCompiler.CompileConsumerAsync(sources, consumer, suppressExperimental: false); diff --git a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenDoorRemarksTests.cs b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenDoorRemarksTests.cs index 8666b6ab..014010b0 100644 --- a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenDoorRemarksTests.cs +++ b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenDoorRemarksTests.cs @@ -19,7 +19,8 @@ namespace OpenCode.Sdk.Tools.Tests.Generator.Emission; /// Hand-written sources are recognized the way the compile probe recognizes them: generated /// sources carry the writer's header. /// -public sealed partial class HandWrittenDoorRemarksTests +[ClassDataSource(Shared = SharedType.PerTestSession)] +public sealed partial class HandWrittenDoorRemarksTests(PinnedBinding pinned) { /// The hand-written public door types (ADR-0021): every public operation method on them names its operation. private static readonly string[] DoorTypes = ["PtyClient", "PtysClient", "PersistentPtyClient", "PersistentPtysClient"]; @@ -27,7 +28,7 @@ public sealed partial class HandWrittenDoorRemarksTests [Test] public async Task HandWritten_Remarks_Should_Name_A_Pinned_Operation_By_Its_Method_And_Route() { - var document = await BindingTestHost.IngestPinnedAsync(); + var document = pinned.Document; var operations = document.Operations.ToDictionary(static operation => operation.OperationId, StringComparer.Ordinal); var remarks = (await LoadHandWrittenMethodsAsync()).SelectMany(static method => method.Remarks).ToArray(); diff --git a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenExperimentalDoorTests.cs b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenExperimentalDoorTests.cs index 93540c3f..7419464d 100644 --- a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenExperimentalDoorTests.cs +++ b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenExperimentalDoorTests.cs @@ -14,12 +14,14 @@ namespace OpenCode.Sdk.Tools.Tests.Generator.Emission; /// nothing else keeps the two in step: every public type the family's folder declares by hand /// carries the attribute, and the id it names resolves to the one the family's curation row holds. /// -public sealed class HandWrittenExperimentalDoorTests +[ClassDataSource(Shared = SharedType.PerTestSession)] +public sealed class HandWrittenExperimentalDoorTests(PinnedBinding pinned) { [Test] public async Task HandWritten_Public_Types_Of_An_Experimental_Raw_Family_Should_Carry_Its_Id() { - var (document, _, curation) = await BindingTestHost.LoadPinnedInputsAsync(); + var document = pinned.Document; + var curation = pinned.Curation; var families = curation.Groups .Where(pair => pair.Value is { Emission: EmissionMode.InternalRaw, ExperimentalDiagnostic: not null, ClientName: not null } && document.Operations diff --git a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenTransportTableTests.cs b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenTransportTableTests.cs index df348156..077c50c7 100644 --- a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenTransportTableTests.cs +++ b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/HandWrittenTransportTableTests.cs @@ -13,14 +13,15 @@ namespace OpenCode.Sdk.Tools.Tests.Generator.Emission; /// its stream would stop reconnecting. Every id each table names is an operation of the pinned /// document, identity curation applied. /// -public sealed class HandWrittenTransportTableTests +[ClassDataSource(Shared = SharedType.PerTestSession)] +public sealed class HandWrittenTransportTableTests(PinnedBinding pinnedBinding) { [Test] [Arguments("Internal/Transport/NetworkTimeouts.cs", "LongPollOperations")] [Arguments("Internal/Transport/StreamReconnect.cs", "ReconnectingOperations")] public async Task Every_Table_Id_Should_Name_A_Pinned_Operation(string tablePath, string tableField) { - var (document, _, _) = await BindingTestHost.LoadPinnedInputsAsync(); + var document = pinnedBinding.Document; var pinned = document.Operations.Select(static operation => operation.OperationId).ToHashSet(StringComparer.Ordinal); var ids = await TableIdsAsync(tablePath, tableField); diff --git a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/OptionalConverterEmitterTests.cs b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/OptionalConverterEmitterTests.cs index ba44298a..2ef24b66 100644 --- a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/OptionalConverterEmitterTests.cs +++ b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/OptionalConverterEmitterTests.cs @@ -14,7 +14,8 @@ namespace OpenCode.Sdk.Tools.Tests.Generator.Emission; /// instantiation, and a body that binds metadata through the emitted context rather than through /// the reflection path. /// -public sealed class OptionalConverterEmitterTests +[ClassDataSource(Shared = SharedType.PerTestSession)] +public sealed class OptionalConverterEmitterTests(PinnedBinding pinned) { [Test] public async Task Emit_Should_Produce_One_Converter_Per_Distinct_Instantiation() @@ -44,7 +45,7 @@ await Assert [Test] public async Task Emit_Should_Read_And_Write_The_Explicit_Null_State_For_A_Scalar() { - var source = await EmitPinnedAsync("OptionalOfStringJsonConverter"); + var source = EmitPinned("OptionalOfStringJsonConverter"); await Assert.That(source).Contains("internal sealed class OptionalOfStringJsonConverter : JsonConverter>"); await Assert.That(source).Contains("public override bool HandleNull => true;"); @@ -58,7 +59,7 @@ public async Task Emit_Should_Read_And_Write_The_Explicit_Null_State_For_A_Scala [Test] public async Task Emit_Should_Bind_A_Container_Instantiation_Through_The_Generated_Context() { - var source = await EmitPinnedAsync("OptionalOfPermissionRuleListJsonConverter"); + var source = EmitPinned("OptionalOfPermissionRuleListJsonConverter"); await Assert.That(source).Contains("OpenCodeJsonContext.Default.GetTypeInfo(typeof(IReadOnlyList))"); await Assert.That(source).Contains("JsonSerializer.Deserialize(ref reader, typeInfo)"); @@ -69,11 +70,10 @@ public async Task Emit_Should_Bind_A_Container_Instantiation_Through_The_Generat await Assert.That(source).DoesNotContain(", options);"); } - private static async Task EmitPinnedAsync(string converterName) + private string EmitPinned(string converterName) { - var plan = await new BindingTestHost().BindPinnedAsync(); var source = OptionalConverterEmitter - .Emit(plan.Models) + .Emit(pinned.Plan.Models) .Single(candidate => candidate.RelativePath == $"Internal/Serialization/{converterName}.cs"); return Encoding.UTF8.GetString(source.Utf8Source.Span); } diff --git a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/SessionScopedEventEmissionTests.cs b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/SessionScopedEventEmissionTests.cs index a2d1a6b7..626c8884 100644 --- a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/SessionScopedEventEmissionTests.cs +++ b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/SessionScopedEventEmissionTests.cs @@ -9,7 +9,8 @@ namespace OpenCode.Sdk.Tools.Tests.Generator.Emission; -public sealed class SessionScopedEventEmissionTests +[ClassDataSource(Shared = SharedType.PerTestSession)] +public sealed class SessionScopedEventEmissionTests(PinnedBinding pinned) { [Test] public async Task Emit_Should_Add_The_Interface_And_An_Explicit_Payload_Projection() @@ -90,7 +91,7 @@ await Assert.That(record.Members.OfType() [ParallelLimiter] public async Task Emit_Should_Compile_The_Pinned_Surface_And_A_Session_Routing_Consumer() { - var sources = SourceEmitter.Emit(await new BindingTestHost().BindPinnedAsync()); + var sources = SourceEmitter.Emit(pinned.Plan); var generatedDiagnostics = await GeneratedSourceCompiler.CompileWithSdkCoreAsync(sources); var consumerDiagnostics = await GeneratedSourceCompiler.CompileConsumerAsync( diff --git a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/SourceEmitterTests.cs b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/SourceEmitterTests.cs index f5d49411..585071ae 100644 --- a/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/SourceEmitterTests.cs +++ b/tests/OpenCode.Sdk.Tools.Tests/Generator/Emission/SourceEmitterTests.cs @@ -12,7 +12,8 @@ namespace OpenCode.Sdk.Tools.Tests.Generator.Emission; -public sealed class SourceEmitterTests +[ClassDataSource(Shared = SharedType.PerTestSession)] +public sealed class SourceEmitterTests(PinnedBinding pinned) { [Test] public async Task Emit_Should_Return_Ordinal_Sorted_Byte_Identical_Source() @@ -55,7 +56,7 @@ public async Task Emit_Should_Refuse_A_Generated_Type_Named_Like_A_HandWritten_I [ParallelLimiter] public async Task Emit_Should_Preserve_All_Bound_Union_And_Registry_Evidence_Through_Source_Generation_And_Compilation() { - var plan = await new BindingTestHost().BindPinnedAsync(); + var plan = pinned.Plan; var sources = SourceEmitter.Emit(plan); foreach (var union in plan.Unions) @@ -138,7 +139,7 @@ public async Task Emit_Should_Preserve_All_Bound_Union_And_Registry_Evidence_Thr [Test] public async Task Emit_Should_Produce_Every_GeneratedSurfaceConsumers_RequiredEmission() { - var plan = await new BindingTestHost().BindPinnedAsync(); + var plan = pinned.Plan; var sources = SourceEmitter.Emit(plan); var emittedPaths = sources.Select(static source => source.RelativePath).ToHashSet(StringComparer.Ordinal); @@ -152,7 +153,7 @@ public async Task Emit_Should_Produce_Every_GeneratedSurfaceConsumers_RequiredEm [ParallelLimiter] public async Task Emit_Should_Deserialize_A_Shared_Pinned_Leaf_Through_Both_Stream_Interfaces() { - var plan = await new BindingTestHost().BindPinnedAsync(); + var plan = pinned.Plan; var sources = SourceEmitter.Emit(plan); var assembly = await GeneratedSourceCompiler.CompileAndLoadWithSdkCoreAsync(sources); var durableType = assembly.GetType("OpenCode.Sdk.Models.ISessionEventDurable", throwOnError: true)!; @@ -181,7 +182,7 @@ public async Task Emit_Should_Deserialize_A_Shared_Pinned_Leaf_Through_Both_Stre [ParallelLimiter] public async Task Emit_Should_Preserve_An_Unclaimed_Pinned_Structural_Token_As_Unknown() { - var plan = await new BindingTestHost().BindPinnedAsync(); + var plan = pinned.Plan; var sources = SourceEmitter.Emit(plan); var assembly = await GeneratedSourceCompiler.CompileAndLoadWithSdkCoreAsync(sources); var contextType = assembly.GetType("OpenCode.Sdk.Internal.OpenCodeJsonContext", throwOnError: true)!; diff --git a/tests/OpenCode.Sdk.Tools.Tests/Generator/Ingestion/PinnedSpecSmokeTests.cs b/tests/OpenCode.Sdk.Tools.Tests/Generator/Ingestion/PinnedSpecSmokeTests.cs index ea3248ee..1dd4dbc0 100644 --- a/tests/OpenCode.Sdk.Tools.Tests/Generator/Ingestion/PinnedSpecSmokeTests.cs +++ b/tests/OpenCode.Sdk.Tools.Tests/Generator/Ingestion/PinnedSpecSmokeTests.cs @@ -9,12 +9,13 @@ namespace OpenCode.Sdk.Tools.Tests.Generator.Ingestion; /// the known lossy seams, no count assertions. A red landmark is evidence about the wire, /// never a reason to patch the assertion. /// -public sealed class PinnedSpecSmokeTests +[ClassDataSource(Shared = SharedType.PerTestSession)] +public sealed class PinnedSpecSmokeTests(PinnedBinding pinned) { [Test] public async Task Ingest_Should_Absorb_The_Pinned_Spec() { - var document = await IngestPinnedSpecAsync(); + var document = pinned.Document; await Assert.That(document.Operations).IsNotEmpty(); await Assert.That(document.Operations).All(static operation => @@ -24,7 +25,7 @@ await Assert.That(document.Operations).All(static operation => [Test] public async Task Ingest_Should_Flag_Stream_Wildcard_And_WebSocket_Operations() { - var document = await IngestPinnedSpecAsync(); + var document = pinned.Document; var sessionLog = document.Operations.Single(static operation => operation.OperationId == "session.log"); await Assert.That(sessionLog.IsSse).IsTrue(); @@ -43,7 +44,7 @@ await Assert [Test] public async Task Ingest_Should_Classify_Marked_Nested_And_Structural_Union_Landmarks() { - var document = await IngestPinnedSpecAsync(); + var document = pinned.Document; var durableEvent = (UnionNode)document.Schemas["Session.Event.Durable"]; await Assert.That(durableEvent.Keyword).IsEqualTo(UnionKeyword.AnyOf); @@ -66,7 +67,7 @@ public async Task Ingest_Should_Classify_Marked_Nested_And_Structural_Union_Land [Test] public async Task Ingest_Should_Project_Special_Number_And_Unrestricted_Landmarks() { - var document = await IngestPinnedSpecAsync(); + var document = pinned.Document; var shell = (ObjectNode)document.Schemas["Session.Message.Shell"]; await Assert @@ -82,7 +83,7 @@ await Assert [Test] public async Task Ingest_Should_Project_The_Pinned_Stream_Cause_Schema() { - var document = await IngestPinnedSpecAsync(); + var document = pinned.Document; foreach (var operationId in new[] { "session.log", "event.subscribe", }) { @@ -119,7 +120,7 @@ public async Task Ingest_Should_Classify_A_Tagged_Error_That_Also_Carries_A_Name { // WorktreeError is a tagged error whose fields keep the former name/data shape, so it // carries both markers; the _tag marker decides. - var document = await IngestPinnedSpecAsync(); + var document = pinned.Document; await Assert.That(((ObjectNode)document.Schemas["WorktreeErrorEncoded"]).ErrorStyle).IsEqualTo(ErrorStyle.EffectTag); await Assert.That(((ObjectNode)document.Schemas["UnauthorizedErrorEncoded"]).ErrorStyle).IsEqualTo(ErrorStyle.EffectTag); @@ -128,7 +129,7 @@ public async Task Ingest_Should_Classify_A_Tagged_Error_That_Also_Carries_A_Name [Test] public async Task Ingest_Should_Classify_Envelope_Shapes() { - var document = await IngestPinnedSpecAsync(); + var document = pinned.Document; await Assert.That(EnvelopeOf(document, "session.list")).IsEqualTo(SpecEnvelopeShape.CursorData); await Assert.That(EnvelopeOf(document, "agent.list")).IsEqualTo(SpecEnvelopeShape.DataLocation); @@ -138,6 +139,7 @@ public async Task Ingest_Should_Classify_Envelope_Shapes() [Test] public async Task Ingest_Should_Be_Deterministic_Across_Repeated_Runs() { + // Ingest twice on purpose: comparing a cached result with itself proves nothing. var first = await IngestPinnedSpecAsync(); var second = await IngestPinnedSpecAsync();