Skip to content

Commit 574672e

Browse files
committed
testes
1 parent bdc1fa1 commit 574672e

File tree

13 files changed

+63
-66
lines changed

13 files changed

+63
-66
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,3 @@ jobs:
4646

4747
- name: Smoke tests (Codex CLI discover + invoke)
4848
run: dotnet test --solution ManagedCode.CodexSharpSDK.slnx -c Release --no-build -- --treenode-filter "/*/*/*/CodexCli_Smoke_*"
49-
50-
aot-smoke:
51-
name: NativeAOT Smoke
52-
runs-on: ubuntu-latest
53-
54-
steps:
55-
- name: Checkout
56-
uses: actions/checkout@v5
57-
58-
- name: Setup .NET
59-
uses: actions/setup-dotnet@v4
60-
with:
61-
dotnet-version: ${{ env.DOTNET_VERSION }}
62-
63-
- name: Publish AOT smoke app
64-
run: |
65-
dotnet publish tests/AotSmoke/ManagedCode.CodexSharpSDK.AotSmoke.csproj \
66-
-c Release \
67-
-r linux-x64 \
68-
-p:PublishAot=true \
69-
--self-contained true

AGENTS.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ If no new rule is detected -> do not update the file.
6969
- format: `dotnet format ManagedCode.CodexSharpSDK.slnx`
7070
- analyze: `dotnet build ManagedCode.CodexSharpSDK.slnx -c Release -warnaserror /p:TreatWarningsAsErrors=true`
7171
- coverage: `dotnet test --solution ManagedCode.CodexSharpSDK.slnx -c Release -- --coverage --coverage-output-format cobertura --coverage-output coverage.cobertura.xml`
72-
- aot-smoke: `dotnet publish tests/AotSmoke/ManagedCode.CodexSharpSDK.AotSmoke.csproj -c Release -r osx-arm64 /p:PublishAot=true`
7372
- For Codex CLI metadata checks (for example model list/default), always use the installed `codex` CLI directly first; do not use `cargo`/submodule helper binaries unless explicitly requested.
7473

7574
### Task Delivery (ALL TASKS)
@@ -88,15 +87,15 @@ If no new rule is detected -> do not update the file.
8887
- `docs/Architecture/Overview.md` when module boundaries or interactions change
8988
- Implement code and tests together.
9089
- When asked to fix review findings, close every confirmed finding in the same pass; do not leave partial fixes.
91-
- Do not keep or add public sample projects; repository focus is SDK + tests (including AOT tests) only.
90+
- Do not keep or add public sample projects; repository focus is SDK + tests only.
9291
- Upstream sync automation must track real `openai/codex` CLI changes (flags/models/features), not TypeScript SDK surface diffs, and open actionable repository issues for required SDK follow-up.
9392
- Automatically opened upstream sync issues must include change summary/checklist and assign Copilot by default.
9493
- Run verification in this order:
9594
- focused tests for changed behavior
9695
- full solution tests
9796
- format
9897
- final build
99-
- If changes impact trimming/AOT safety, run `aot-smoke`.
98+
- If changes impact trimming/AOT safety, validate via AOT-safe API design (for example `JsonTypeInfo<T>` overloads and annotations) and existing test/build gates; do not introduce a dedicated AOT smoke test project unless explicitly requested.
10099

101100
### Documentation (ALL TASKS)
102101

CodexSharpSDK.Tests/Unit/CodexCliMetadataReaderTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public async Task ParseModelsCache_ParsesListedAndHiddenModels()
157157
using var document = JsonDocument.Parse(json);
158158
var parsed = CodexCliMetadataReader.ParseModelsCache(document.RootElement);
159159

160-
await Assert.That(parsed).HasCount(2);
160+
await Assert.That(parsed).Count().IsEqualTo(2);
161161
await Assert.That(parsed[0].Slug).IsEqualTo("gpt-5.3-codex");
162162
await Assert.That(parsed[0].IsListed).IsTrue();
163163
await Assert.That(parsed[0].IsApiSupported).IsTrue();

CodexSharpSDK.Tests/Unit/CodexClientTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public async Task StartThread_CanBeCalledConcurrently()
4545
Enumerable.Range(0, 64)
4646
.Select(_ => Task.Run(() => client.StartThread())));
4747

48-
await Assert.That(createdThreads).HasCount(64);
48+
await Assert.That(createdThreads).Count().IsEqualTo(64);
4949
await Assert.That(createdThreads.All(thread => thread.Id is null)).IsTrue();
5050
await Assert.That(client.State).IsEqualTo(CodexClientState.Connected);
5151
}

CodexSharpSDK.Tests/Unit/CodexThreadTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public async Task RunAsync_HonorsCancellationToken()
167167
CancellationToken = cancellationSource.Token,
168168
});
169169

170-
var exception = await Assert.That(action).ThrowsException();
170+
var exception = await Assert.That(action!).ThrowsException();
171171
await Assert.That(exception).IsTypeOf<OperationCanceledException>();
172172
}
173173

@@ -178,7 +178,7 @@ public async Task RunAsync_GenericStructuredOutput_ThrowsWhenSchemaMissing()
178178
var thread = new CodexThread(exec, new CodexOptions(), new ThreadOptions());
179179

180180
var action = async () => await thread.RunAsync<StatusResponse>("typed output without schema");
181-
var exception = await Assert.That(action).ThrowsException();
181+
var exception = await Assert.That(action!).ThrowsException();
182182

183183
await Assert.That(exception).IsTypeOf<InvalidOperationException>();
184184
await Assert.That(exception!.Message).Contains(nameof(TurnOptions.OutputSchema));
@@ -195,7 +195,7 @@ public async Task RunAsync_GenericStructuredOutput_WithSchemaShortcut_ThrowsWhen
195195
null!,
196196
IntegrationOutputJsonContext.Default.StatusResponse);
197197

198-
var exception = await Assert.That(action).ThrowsException();
198+
var exception = await Assert.That(action!).ThrowsException();
199199
await Assert.That(exception).IsTypeOf<ArgumentNullException>();
200200
await Assert.That(((ArgumentNullException)exception!).ParamName).IsEqualTo("outputSchema");
201201
}

CodexSharpSDK.Tests/Unit/ThreadEventParserTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public async Task Parse_RecognizesAllTopLevelEventKinds()
2222

2323
var parsed = events.Select(ThreadEventParser.Parse).ToList();
2424

25-
await Assert.That(parsed).HasCount(8);
25+
await Assert.That(parsed).Count().IsEqualTo(8);
2626
await Assert.That(parsed[0]).IsTypeOf<ThreadStartedEvent>();
2727
await Assert.That(parsed[1]).IsTypeOf<TurnStartedEvent>();
2828
await Assert.That(parsed[2]).IsTypeOf<TurnCompletedEvent>();
@@ -55,7 +55,7 @@ public async Task Parse_RecognizesAllItemKinds()
5555
.Select(itemCompleted => itemCompleted.Item)
5656
.ToList();
5757

58-
await Assert.That(parsedItems).HasCount(9);
58+
await Assert.That(parsedItems).Count().IsEqualTo(9);
5959
await Assert.That(parsedItems[0]).IsTypeOf<AgentMessageItem>();
6060
await Assert.That(parsedItems[1]).IsTypeOf<ReasoningItem>();
6161
await Assert.That(parsedItems[2]).IsTypeOf<CommandExecutionItem>();

CodexSharpSDK/Client/CodexThread.cs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public async Task<RunResult<TResponse>> RunAsync<TResponse>(string input, TurnOp
8787
ArgumentNullException.ThrowIfNull(input);
8888
var runOptions = EnsureTypedRunOptions(turnOptions);
8989
var normalizedInput = new NormalizedInput(input, []);
90-
return await RunTypedInternalAsync<TResponse>(normalizedInput, runOptions, jsonTypeInfo: null).ConfigureAwait(false);
90+
return await RunTypedInternalWithReflectionAsync<TResponse>(normalizedInput, runOptions).ConfigureAwait(false);
9191
}
9292

9393
public async Task<RunResult<TResponse>> RunAsync<TResponse>(
@@ -110,7 +110,7 @@ public async Task<RunResult<TResponse>> RunAsync<TResponse>(IReadOnlyList<UserIn
110110
ThrowIfDisposed();
111111
var runOptions = EnsureTypedRunOptions(turnOptions);
112112
var normalizedInput = NormalizeInput(input);
113-
return await RunTypedInternalAsync<TResponse>(normalizedInput, runOptions, jsonTypeInfo: null).ConfigureAwait(false);
113+
return await RunTypedInternalWithReflectionAsync<TResponse>(normalizedInput, runOptions).ConfigureAwait(false);
114114
}
115115

116116
public async Task<RunResult<TResponse>> RunAsync<TResponse>(
@@ -137,7 +137,7 @@ public Task<RunResult<TResponse>> RunAsync<TResponse>(
137137
ArgumentNullException.ThrowIfNull(input);
138138
var normalizedInput = new NormalizedInput(input, []);
139139
var runOptions = CreateTypedTurnOptions(outputSchema, cancellationToken);
140-
return RunTypedInternalAsync<TResponse>(normalizedInput, runOptions, jsonTypeInfo: null);
140+
return RunTypedInternalWithReflectionAsync<TResponse>(normalizedInput, runOptions);
141141
}
142142

143143
public Task<RunResult<TResponse>> RunAsync<TResponse>(
@@ -164,7 +164,7 @@ public Task<RunResult<TResponse>> RunAsync<TResponse>(
164164
ThrowIfDisposed();
165165
var normalizedInput = NormalizeInput(input);
166166
var runOptions = CreateTypedTurnOptions(outputSchema, cancellationToken);
167-
return RunTypedInternalAsync<TResponse>(normalizedInput, runOptions, jsonTypeInfo: null);
167+
return RunTypedInternalWithReflectionAsync<TResponse>(normalizedInput, runOptions);
168168
}
169169

170170
public Task<RunResult<TResponse>> RunAsync<TResponse>(
@@ -384,7 +384,7 @@ private static TurnOptions CreateTypedTurnOptions(
384384
private async Task<RunResult<TResponse>> RunTypedInternalAsync<TResponse>(
385385
NormalizedInput normalizedInput,
386386
TurnOptions turnOptions,
387-
JsonTypeInfo<TResponse>? jsonTypeInfo)
387+
JsonTypeInfo<TResponse> jsonTypeInfo)
388388
{
389389
var runResult = await RunInternalAsync(normalizedInput, turnOptions).ConfigureAwait(false);
390390
var typedResponse = DeserializeTypedResponse(runResult.FinalResponse, jsonTypeInfo);
@@ -396,21 +396,56 @@ private async Task<RunResult<TResponse>> RunTypedInternalAsync<TResponse>(
396396
typedResponse);
397397
}
398398

399+
[RequiresDynamicCode(AotUnsafeTypedRunMessage)]
400+
[RequiresUnreferencedCode(AotUnsafeTypedRunMessage)]
401+
private async Task<RunResult<TResponse>> RunTypedInternalWithReflectionAsync<TResponse>(
402+
NormalizedInput normalizedInput,
403+
TurnOptions turnOptions)
404+
{
405+
var runResult = await RunInternalAsync(normalizedInput, turnOptions).ConfigureAwait(false);
406+
var typedResponse = DeserializeTypedResponseWithReflection<TResponse>(runResult.FinalResponse);
407+
408+
return new RunResult<TResponse>(
409+
runResult.Items,
410+
runResult.FinalResponse,
411+
runResult.Usage,
412+
typedResponse);
413+
}
414+
399415
private static TResponse DeserializeTypedResponse<TResponse>(
400416
string payload,
401-
JsonTypeInfo<TResponse>? jsonTypeInfo)
417+
JsonTypeInfo<TResponse> jsonTypeInfo)
418+
{
419+
ArgumentNullException.ThrowIfNull(jsonTypeInfo);
420+
421+
try
422+
{
423+
var response = JsonSerializer.Deserialize(payload, jsonTypeInfo);
424+
return response
425+
?? throw new InvalidOperationException(
426+
$"{EmptyTypedRunResponseMessagePrefix} '{typeof(TResponse).Name}'.");
427+
}
428+
catch (JsonException exception)
429+
{
430+
throw new InvalidOperationException(
431+
$"{TypedRunDeserializeFailedMessagePrefix} '{typeof(TResponse).Name}'.",
432+
exception);
433+
}
434+
}
435+
436+
[RequiresDynamicCode(AotUnsafeTypedRunMessage)]
437+
[RequiresUnreferencedCode(AotUnsafeTypedRunMessage)]
438+
private static TResponse DeserializeTypedResponseWithReflection<TResponse>(string payload)
402439
{
403440
try
404441
{
405-
var response = jsonTypeInfo is null
406-
? JsonSerializer.Deserialize<TResponse>(payload)
407-
: JsonSerializer.Deserialize(payload, jsonTypeInfo);
442+
var response = JsonSerializer.Deserialize<TResponse>(payload);
408443
return response
409444
?? throw new InvalidOperationException(
410445
$"{EmptyTypedRunResponseMessagePrefix} '{typeof(TResponse).Name}'.");
411446
}
412447
catch (InvalidOperationException exception)
413-
when (jsonTypeInfo is null && IsReflectionDisabledSerializationError(exception))
448+
when (IsReflectionDisabledSerializationError(exception))
414449
{
415450
throw new InvalidOperationException(TypedRunRequiresTypeInfoMessage, exception);
416451
}

Directory.Packages.props

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
<PropertyGroup>
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
</PropertyGroup>
5-
65
<ItemGroup>
7-
<PackageVersion Include="DotNet.ReproducibleBuilds" Version="1.2.25" />
8-
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
9-
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
10-
<PackageVersion Include="TUnit" Version="1.0.0" />
11-
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
6+
<PackageVersion Include="DotNet.ReproducibleBuilds" Version="2.0.2" />
7+
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" />
8+
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.103" />
9+
<PackageVersion Include="TUnit" Version="1.18.21" />
10+
<PackageVersion Include="coverlet.collector" Version="8.0.0" />
1211
</ItemGroup>
13-
</Project>
12+
</Project>

README.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,3 @@ await resumed.RunAsync("Continue from previous plan");
258258
dotnet build ManagedCode.CodexSharpSDK.slnx -c Release -warnaserror
259259
dotnet test --solution ManagedCode.CodexSharpSDK.slnx -c Release
260260
```
261-
262-
## AOT Smoke Check
263-
264-
```bash
265-
dotnet publish tests/AotSmoke/ManagedCode.CodexSharpSDK.AotSmoke.csproj \
266-
-c Release -r linux-x64 -p:PublishAot=true --self-contained true
267-
```

docs/Development/setup.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,7 @@ dotnet format ManagedCode.CodexSharpSDK.slnx
3131
Focused run (TUnit/MTP):
3232

3333
```bash
34-
dotnet test --project tests/CodexSharpSDK.Tests.csproj -c Release -- --treenode-filter "/*/*/ThreadEventParserTests/*"
35-
```
36-
37-
## AOT smoke check
38-
39-
```bash
40-
dotnet publish tests/AotSmoke/ManagedCode.CodexSharpSDK.AotSmoke.csproj -c Release -r osx-arm64 /p:PublishAot=true
34+
dotnet test --project CodexSharpSDK.Tests/CodexSharpSDK.Tests.csproj -c Release -- --treenode-filter "/*/*/ThreadEventParserTests/*"
4135
```
4236

4337
## Packaging check

0 commit comments

Comments
 (0)