Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
public sealed class ExperimentalSurfaceEmissionTests
[ClassDataSource<PinnedBinding>(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()
Expand Down Expand Up @@ -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);
Expand All @@ -217,7 +218,7 @@ public async Task Emit_Should_Mark_A_Hoisted_Interface_From_Its_Plan()
[ParallelLimiter<RoslynCompilationSlots>]
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ 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.
/// </summary>
public sealed partial class HandWrittenDoorRemarksTests
[ClassDataSource<PinnedBinding>(Shared = SharedType.PerTestSession)]
public sealed partial class HandWrittenDoorRemarksTests(PinnedBinding pinned)
{
/// <summary>The hand-written public door types (ADR-0021): every public operation method on them names its operation.</summary>
private static readonly string[] DoorTypes = ["PtyClient", "PtysClient", "PersistentPtyClient", "PersistentPtysClient"];

[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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
public sealed class HandWrittenExperimentalDoorTests
[ClassDataSource<PinnedBinding>(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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
public sealed class HandWrittenTransportTableTests
[ClassDataSource<PinnedBinding>(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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
public sealed class OptionalConverterEmitterTests
[ClassDataSource<PinnedBinding>(Shared = SharedType.PerTestSession)]
public sealed class OptionalConverterEmitterTests(PinnedBinding pinned)
{
[Test]
public async Task Emit_Should_Produce_One_Converter_Per_Distinct_Instantiation()
Expand Down Expand Up @@ -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<Optional<string?>>");
await Assert.That(source).Contains("public override bool HandleNull => true;");
Expand All @@ -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<PermissionRule>))");
await Assert.That(source).Contains("JsonSerializer.Deserialize(ref reader, typeInfo)");
Expand All @@ -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<string> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

namespace OpenCode.Sdk.Tools.Tests.Generator.Emission;

public sealed class SessionScopedEventEmissionTests
[ClassDataSource<PinnedBinding>(Shared = SharedType.PerTestSession)]
public sealed class SessionScopedEventEmissionTests(PinnedBinding pinned)
{
[Test]
public async Task Emit_Should_Add_The_Interface_And_An_Explicit_Payload_Projection()
Expand Down Expand Up @@ -90,7 +91,7 @@ await Assert.That(record.Members.OfType<PropertyDeclarationSyntax>()
[ParallelLimiter<RoslynCompilationSlots>]
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

namespace OpenCode.Sdk.Tools.Tests.Generator.Emission;

public sealed class SourceEmitterTests
[ClassDataSource<PinnedBinding>(Shared = SharedType.PerTestSession)]
public sealed class SourceEmitterTests(PinnedBinding pinned)
{
[Test]
public async Task Emit_Should_Return_Ordinal_Sorted_Byte_Identical_Source()
Expand Down Expand Up @@ -55,7 +56,7 @@ public async Task Emit_Should_Refuse_A_Generated_Type_Named_Like_A_HandWritten_I
[ParallelLimiter<RoslynCompilationSlots>]
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)
Expand Down Expand Up @@ -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);

Expand All @@ -152,7 +153,7 @@ public async Task Emit_Should_Produce_Every_GeneratedSurfaceConsumers_RequiredEm
[ParallelLimiter<RoslynCompilationSlots>]
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)!;
Expand Down Expand Up @@ -181,7 +182,7 @@ public async Task Emit_Should_Deserialize_A_Shared_Pinned_Leaf_Through_Both_Stre
[ParallelLimiter<RoslynCompilationSlots>]
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)!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
public sealed class PinnedSpecSmokeTests
[ClassDataSource<PinnedBinding>(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 =>
Expand All @@ -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();
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -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", })
{
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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();

Expand Down
Loading