93 lines
3.3 KiB
C#
93 lines
3.3 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Tests;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public sealed class FixtureCleanupTests
|
|
{
|
|
[Fact]
|
|
public async Task Successful_body_runs_one_awaited_cleanup()
|
|
{
|
|
var calls = 0;
|
|
var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
var run = FixtureCleanup.RunAsync(() => Task.CompletedTask, async () =>
|
|
{
|
|
calls++;
|
|
await release.Task;
|
|
}, _ => throw new Exception("unexpected report"));
|
|
|
|
run.IsCompleted.ShouldBeFalse();
|
|
release.SetResult();
|
|
await run;
|
|
calls.ShouldBe(1);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Body_fault_remains_same_exception_and_original_throwing_stack()
|
|
{
|
|
var primary = new InvalidOperationException("body");
|
|
var cleanupCalls = 0;
|
|
var actual = await Should.ThrowAsync<InvalidOperationException>(() => FixtureCleanup.RunAsync(
|
|
() => ThrowFromBody(primary),
|
|
() => { cleanupCalls++; return Task.CompletedTask; },
|
|
_ => throw new Exception("unexpected report")));
|
|
|
|
actual.ShouldBeSameAs(primary);
|
|
actual.StackTrace.ShouldNotBeNull().ShouldContain(nameof(ThrowFromBody));
|
|
cleanupCalls.ShouldBe(1);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Cleanup_only_fault_is_thrown_exactly()
|
|
{
|
|
var cleanup = new ApplicationException("cleanup");
|
|
var actual = await Should.ThrowAsync<ApplicationException>(() => FixtureCleanup.RunAsync(
|
|
() => Task.CompletedTask,
|
|
() => Task.FromException(cleanup),
|
|
_ => throw new Exception("unexpected report")));
|
|
actual.ShouldBeSameAs(cleanup);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Both_faults_preserve_primary_and_record_secondary_once()
|
|
{
|
|
var primary = new InvalidOperationException("body");
|
|
var cleanup = new ApplicationException("cleanup");
|
|
var reported = new List<Exception>();
|
|
var actual = await Should.ThrowAsync<InvalidOperationException>(() => FixtureCleanup.RunAsync(
|
|
() => ThrowFromBody(primary),
|
|
() => Task.FromException(cleanup),
|
|
reported.Add));
|
|
|
|
actual.ShouldBeSameAs(primary);
|
|
actual.StackTrace.ShouldNotBeNull().ShouldContain(nameof(ThrowFromBody));
|
|
actual.Data[FixtureCleanup.SecondaryExceptionKey].ShouldBeSameAs(cleanup);
|
|
reported.Count.ShouldBe(1);
|
|
reported[0].ShouldBeSameAs(cleanup);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Reporting_fault_does_not_replace_primary()
|
|
{
|
|
var primary = new InvalidOperationException("body");
|
|
var cleanup = new ApplicationException("cleanup");
|
|
var reportCalls = 0;
|
|
var actual = await Should.ThrowAsync<InvalidOperationException>(() => FixtureCleanup.RunAsync(
|
|
() => ThrowFromBody(primary),
|
|
() => Task.FromException(cleanup),
|
|
_ => { reportCalls++; throw new Exception("report"); }));
|
|
|
|
actual.ShouldBeSameAs(primary);
|
|
actual.Data[FixtureCleanup.SecondaryExceptionKey].ShouldBeSameAs(cleanup);
|
|
reportCalls.ShouldBe(1);
|
|
}
|
|
|
|
private static async Task ThrowFromBody(Exception failure)
|
|
{
|
|
await Task.Yield();
|
|
throw failure;
|
|
}
|
|
}
|