From e14123ea19da20e8810896b98bf96370a92fd3f3 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Sat, 17 Oct 2026 17:44:29 +0800 Subject: [PATCH] fix(tests): record progress events synchronously to remove flake Progress posts callbacks to the captured SynchronizationContext, so under xUnit's AsyncTestSyncContext events could arrive after the awaited call returned and the assertions had already run. Use a shared synchronous ListProgress so RunAsyncContinuesAfterSkippedItem and RunAsyncReportsStagesAndOutputPath observe every event deterministically. Co-Authored-By: Claude Code --- .../BatchLocalizationRunnerTests.cs | 10 +--------- tests/BSPLocalizationTools.Tests/ListProgress.cs | 12 ++++++++++++ .../LocalizationRunnerProgressTests.cs | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 tests/BSPLocalizationTools.Tests/ListProgress.cs diff --git a/tests/BSPLocalizationTools.Tests/BatchLocalizationRunnerTests.cs b/tests/BSPLocalizationTools.Tests/BatchLocalizationRunnerTests.cs index 40647b2..8ae926e 100644 --- a/tests/BSPLocalizationTools.Tests/BatchLocalizationRunnerTests.cs +++ b/tests/BSPLocalizationTools.Tests/BatchLocalizationRunnerTests.cs @@ -19,7 +19,7 @@ public async Task RunAsyncContinuesAfterSkippedItem() new LocalizationRequest(first, "schinese", null, CreateOptions()), new LocalizationRequest(second, "schinese", null, CreateOptions()), ]), - new Progress(progressEvents.Add), + new ListProgress(progressEvents), CancellationToken.None); Assert.True(results[0].Succeeded); @@ -119,14 +119,6 @@ public Task CompleteTextAsync( } } - private sealed class ListProgress(List events) : IProgress - { - public void Report(TranslationProgress value) - { - events.Add(value); - } - } - private sealed class QueuingSynchronizationContext : SynchronizationContext { public override void Post(SendOrPostCallback d, object? state) diff --git a/tests/BSPLocalizationTools.Tests/ListProgress.cs b/tests/BSPLocalizationTools.Tests/ListProgress.cs new file mode 100644 index 0000000..b20f86d --- /dev/null +++ b/tests/BSPLocalizationTools.Tests/ListProgress.cs @@ -0,0 +1,12 @@ +namespace BSPLocalizationTools.Tests; + +// Synchronous IProgress so progress events are recorded before the awaited call returns. +// Progress posts callbacks to the captured SynchronizationContext, which under xUnit can +// deliver them after the test's assertions have already run. +internal sealed class ListProgress(List events) : IProgress +{ + public void Report(TranslationProgress value) + { + events.Add(value); + } +} diff --git a/tests/BSPLocalizationTools.Tests/LocalizationRunnerProgressTests.cs b/tests/BSPLocalizationTools.Tests/LocalizationRunnerProgressTests.cs index 7b70e33..fd20560 100644 --- a/tests/BSPLocalizationTools.Tests/LocalizationRunnerProgressTests.cs +++ b/tests/BSPLocalizationTools.Tests/LocalizationRunnerProgressTests.cs @@ -19,7 +19,7 @@ public async Task RunAsyncReportsStagesAndOutputPath() "schinese", null, new LLMOptions("gpt-test", "sk-", null, null, "medium", null)), - new Progress(progressEvents.Add), + new ListProgress(progressEvents), CancellationToken.None); Assert.Equal(Path.Combine(temp.Path, "fake_map_dictionary_schinese.csv"), result.OutputPath);