using XFEEDToolBox.Core.Navigation;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]public class FlightControlCleanupTests
{
[Test]public async Task ScoConfirmationFailureStillSuspendsAndReleasesEveryIndependentOwnedControl()
{
var calls=new List<string>();var sco=new FlightTelemetryUnavailableException("Waiting for the owned SCO to report its real stopped state.");
try
{
await FlightControlCleanup.RunAllAsync(
()=>{calls.Add("sco");return Task.FromException(sco);},
()=>{calls.Add("docking-reset");return Task.CompletedTask;},
()=>{calls.Add("original-assists");return Task.CompletedTask;},
()=>{calls.Add("primary-inputs");return Task.CompletedTask;});
}
catch(FlightTelemetryUnavailableException error)
{Check.That(ReferenceEquals(sco,error));Check.Equal("sco,docking-reset,original-assists,primary-inputs",string.Join(',',calls));return;}
throw new Exception("Unconfirmed SCO release was swallowed");
}
[Test]public async Task IndependentReleaseErrorsPreserveIdentityAndSafetyFailuresWhileStillReleasingAxes()
{
var identity=new InvalidDataException("Different ship");var health=new FlightHealthPauseException();var released=false;
try
{
await FlightControlCleanup.RunAllAsync(()=>Task.FromException(identity),()=>Task.FromException(health),()=>{released=true;return Task.CompletedTask;});
}
catch(AggregateException error)
{Check.That(released&&error.InnerExceptions.Count==2&&ReferenceEquals(identity,error.InnerExceptions[0])&&ReferenceEquals(health,error.InnerExceptions[1]));
Check.That(!NavigationRecovery.CanRetry(error,CancellationToken.None));Check.That(FlightSafetyPauseException.Present(error));return;}
throw new Exception("Release failures lost");
}
[Test]public async Task CleanupFailurePreservesTheActualThreatAndDiagnostics()
{
var primary=new FlightThreatPauseException();var release=new InvalidOperationException("Protection refused cancellation");
try{await FlightControlCleanup.RunAsync(()=>Task.FromException(primary),()=>Task.FromException(release));}
catch(FlightControlCleanupException error){Check.That(ReferenceEquals(primary,error.InnerException));Check.That(ReferenceEquals(release,error.CleanupFailure));Check.That(FlightSafetyPauseException.Present(error));return;}
throw new Exception("Threat lost");
}
[Test]public async Task ASecondaryHealthFailureCannotConvertIdentityFailureIntoRetry()
{
var primary=new InvalidDataException("Identity changed");
try{await FlightControlCleanup.RunAsync(()=>Task.FromException(primary),()=>Task.FromException(new FlightHealthPauseException()));}
catch(FlightControlCleanupException error){Check.That(!FlightSafetyPauseException.Present(error));return;}
throw new Exception("Primary failure lost");
}
[Test]public async Task UserCancellationRemainsCancellationEvenIfReleaseFails()
{
var cancellation=new OperationCanceledException("User stopped");
try{await FlightControlCleanup.RunAsync(()=>Task.FromException(cancellation),()=>Task.FromException(new FlightHealthPauseException()));}
catch(OperationCanceledException error){Check.That(ReferenceEquals(cancellation,error));Check.That(error.Data.Contains("ControlReleaseFailure"));return;}
throw new Exception("Cancellation lost");
}
[Test]public async Task AReleaseFailureWithoutAPrimaryFailureRemainsTerminal()
{
var release=new InvalidOperationException("Release failed");
try{await FlightControlCleanup.RunAsync(()=>Task.CompletedTask,()=>Task.FromException(release));}
catch(InvalidOperationException error){Check.That(ReferenceEquals(release,error));return;}
throw new Exception("Release failure swallowed");
}
}
using XFEEDToolBox.Core.Navigation;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]public class FlightControlCleanupTests
{
[Test]public async Task ScoConfirmationFailureStillSuspendsAndReleasesEveryIndependentOwnedControl()
{
var calls=new List<string>();var sco=new FlightTelemetryUnavailableException("Waiting for the owned SCO to report its real stopped state.");
try
{
await FlightControlCleanup.RunAllAsync(
()=>{calls.Add("sco");return Task.FromException(sco);},
()=>{calls.Add("docking-reset");return Task.CompletedTask;},
()=>{calls.Add("original-assists");return Task.CompletedTask;},
()=>{calls.Add("primary-inputs");return Task.CompletedTask;});
}
catch(FlightTelemetryUnavailableException error)
{Check.That(ReferenceEquals(sco,error));Check.Equal("sco,docking-reset,original-assists,primary-inputs",string.Join(',',calls));return;}
throw new Exception("Unconfirmed SCO release was swallowed");
}
[Test]public async Task IndependentReleaseErrorsPreserveIdentityAndSafetyFailuresWhileStillReleasingAxes()
{
var identity=new InvalidDataException("Different ship");var health=new FlightHealthPauseException();var released=false;
try
{
await FlightControlCleanup.RunAllAsync(()=>Task.FromException(identity),()=>Task.FromException(health),()=>{released=true;return Task.CompletedTask;});
}
catch(AggregateException error)
{Check.That(released&&error.InnerExceptions.Count==2&&ReferenceEquals(identity,error.InnerExceptions[0])&&ReferenceEquals(health,error.InnerExceptions[1]));
Check.That(!NavigationRecovery.CanRetry(error,CancellationToken.None));Check.That(FlightSafetyPauseException.Present(error));return;}
throw new Exception("Release failures lost");
}
[Test]public async Task CleanupFailurePreservesTheActualThreatAndDiagnostics()
{
var primary=new FlightThreatPauseException();var release=new InvalidOperationException("Protection refused cancellation");
try{await FlightControlCleanup.RunAsync(()=>Task.FromException(primary),()=>Task.FromException(release));}
catch(FlightControlCleanupException error){Check.That(ReferenceEquals(primary,error.InnerException));Check.That(ReferenceEquals(release,error.CleanupFailure));Check.That(FlightSafetyPauseException.Present(error));return;}
throw new Exception("Threat lost");
}
[Test]public async Task ASecondaryHealthFailureCannotConvertIdentityFailureIntoRetry()
{
var primary=new InvalidDataException("Identity changed");
try{await FlightControlCleanup.RunAsync(()=>Task.FromException(primary),()=>Task.FromException(new FlightHealthPauseException()));}
catch(FlightControlCleanupException error){Check.That(!FlightSafetyPauseException.Present(error));return;}
throw new Exception("Primary failure lost");
}
[Test]public async Task UserCancellationRemainsCancellationEvenIfReleaseFails()
{
var cancellation=new OperationCanceledException("User stopped");
try{await FlightControlCleanup.RunAsync(()=>Task.FromException(cancellation),()=>Task.FromException(new FlightHealthPauseException()));}
catch(OperationCanceledException error){Check.That(ReferenceEquals(cancellation,error));Check.That(error.Data.Contains("ControlReleaseFailure"));return;}
throw new Exception("Cancellation lost");
}
[Test]public async Task AReleaseFailureWithoutAPrimaryFailureRemainsTerminal()
{
var release=new InvalidOperationException("Release failed");
try{await FlightControlCleanup.RunAsync(()=>Task.CompletedTask,()=>Task.FromException(release));}
catch(InvalidOperationException error){Check.That(ReferenceEquals(release,error));return;}
throw new Exception("Release failure swallowed");
}
}