XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using XFEEDToolBox.Core.Execution;
using XFEEDToolBox.Core.Models;
using XFEExtension.NetCore.XUnit.Attributes;

namespace XFEEDToolBox.Test;

[TestFixture]
public sealed class TradeRunMenuScopeTests
{
    private static PlayerState Player=>new(){Ship="Type9",InGame=true,Docked=true,MarketId=1,Credits=10000,CreditsReliable=true,CargoCapacity=10,StatusAt=DateTimeOffset.UtcNow};
    private static RoutePlan Plan=>new(){Request=Check.Request with{MaxLegs=1},Legs=[new(){Number=1,From=Check.Station(1),To=Check.Station(2),Orders=[new("gold","Gold",3,100,180)]}]};
    private sealed class Lease(Func<bool> running):IDisposable
    {
        public bool Disposed;public bool Allowed=>running();
        public void Dispose(){Disposed=true;Check.That(!Allowed,"Permission must be revoked before disposing its scope.");}
    }
    private sealed class Driver:ITradeCommandDriver,ITradeRunMenuRecovery
    {
        public List<Lease> Leases=[];public bool Released,RejectPreflight,RejectScope,RejectAction;public Action? BeforeScopeReturned;
        public IDisposable EnterRunningMenuRecovery(Func<bool> isRunning,CancellationToken token)
        {
            if(RejectScope)throw new InvalidOperationException("scope fixture failure");
            var scope=new Lease(isRunning);Leases.Add(scope);Check.That(scope.Allowed);BeforeScopeReturned?.Invoke();return scope;
        }
        public Task PreflightAsync(CancellationToken token){if(RejectPreflight)throw new InvalidOperationException("preflight fixture failure");return Task.CompletedTask;}
        public Task ServiceDockedAsync(DockedServiceRequest request,Func<CancellationToken,Task> beforeInput,CancellationToken token)=>beforeInput(token);
        public async Task ExecuteAsync(TradeAction action,Func<CancellationToken,Task> beforeInput,CancellationToken token)
        {await beforeInput(token);if(RejectAction)throw new InvalidOperationException("action fixture failure");await Task.Delay(Timeout.Infinite,token);}
        public Task ReleaseAllAsync(){Released=true;return Task.CompletedTask;}
    }
    private static TradeRunner Runner(Driver driver)=>new(()=>Player,(id,key)=>Check.Quote(id,key,id==1?100:200,id==1?90:180));

    [Test]public async Task NativeRunningPauseResumeAndStopOwnDifferentRevocableScopes()
    {
        var driver=new Driver();var runner=Runner(driver);var checkedState=false;
        runner.Progress+=progress=>
        {
            if(checkedState||!progress.Message.StartsWith("开始执行"))return;checkedState=true;
            var first=driver.Leases.Single();Check.That(first.Allowed&&!first.Disposed);
            runner.Pause();Check.Equal(RunState.Paused,runner.State);Check.That(first.Disposed&&!first.Allowed);
            runner.Resume();Check.Equal(RunState.Running,runner.State);Check.Equal(2,driver.Leases.Count);
            var second=driver.Leases[1];Check.That(second.Allowed&&!second.Disposed&&!first.Allowed);
            runner.Stop();Check.That(second.Disposed&&!second.Allowed);runner.Resume();Check.Equal(2,driver.Leases.Count);
        };
        await runner.RunAsync(Plan,ExecutionMode.NativeBridge,driver).WaitAsync(TimeSpan.FromSeconds(2));
        Check.That(checkedState&&driver.Released);Check.Equal(RunState.Stopped,runner.State);Check.That(driver.Leases.All(lease=>lease.Disposed&&!lease.Allowed));
    }
    [Test]public async Task GuideSimulationAndRejectedPreflightNeverAuthorizeMenuActions()
    {
        foreach(var mode in new[]{ExecutionMode.JournalGuide,ExecutionMode.Simulation,ExecutionMode.NativeBridge})
        {
            var driver=new Driver{RejectPreflight=mode==ExecutionMode.NativeBridge};var runner=Runner(driver);
            runner.Progress+=progress=>{if(progress.Message.StartsWith("开始执行"))runner.Stop();};
            await runner.RunAsync(Plan,mode,driver).WaitAsync(TimeSpan.FromSeconds(2));
            Check.Equal(0,driver.Leases.Count);Check.That(driver.Released);
        }
    }
    [Test]public async Task CallerCancellationRevokesPermissionBeforeRunUnwinds()
    {
        using var cancellation=new CancellationTokenSource();var driver=new Driver();var runner=Runner(driver);var observed=false;
        runner.Progress+=progress=>
        {
            if(observed||!progress.Message.StartsWith("开始执行"))return;observed=true;
            Check.That(driver.Leases.Single().Allowed);cancellation.Cancel();Check.That(!driver.Leases.Single().Allowed);
        };
        await runner.RunAsync(Plan,ExecutionMode.NativeBridge,driver,cancellation.Token).WaitAsync(TimeSpan.FromSeconds(2));
        Check.That(observed&&driver.Leases.Single().Disposed&&driver.Released);Check.Equal(RunState.Stopped,runner.State);
    }
    [Test]public async Task DriverFailureAndScopeCreationFailureReleasePermissionAndControls()
    {
        foreach(var rejectScope in new[]{false,true})
        {
            var driver=new Driver{RejectScope=rejectScope,RejectAction=!rejectScope};var runner=Runner(driver);
            await runner.RunAsync(Plan,ExecutionMode.NativeBridge,driver).WaitAsync(TimeSpan.FromSeconds(2));
            Check.Equal(RunState.Failed,runner.State);Check.That(driver.Released);
            Check.That(driver.Leases.All(lease=>lease.Disposed&&!lease.Allowed));
        }
    }
    [Test]public async Task PauseDuringScopeCreationRejectsTheLateScopeAndRunningNotification()
    {
        var driver=new Driver();var runner=Runner(driver);var paused=false;var lateRunning=false;
        driver.BeforeScopeReturned=()=>runner.Pause();
        runner.Progress+=progress=>
        {
            if(progress.State==RunState.Paused){paused=true;runner.Stop();}
            if(paused&&progress.State==RunState.Running)lateRunning=true;
        };
        await runner.RunAsync(Plan,ExecutionMode.NativeBridge,driver).WaitAsync(TimeSpan.FromSeconds(2));
        Check.That(paused&&!lateRunning&&driver.Released);Check.Equal(1,driver.Leases.Count);Check.That(driver.Leases[0].Disposed&&!driver.Leases[0].Allowed);
        Check.Equal(RunState.Stopped,runner.State);
    }
}