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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.IO.Pipes;
using System.Text.Json;
using XFEEDToolBox.Core.Navigation;
using XFEExtension.NetCore.XUnit.Attributes;

namespace XFEEDToolBox.Test;

[TestFixture]
public class NativeGameInputChannelTests
{
    private sealed class Fixture:IAsyncDisposable
    {
        private readonly CancellationTokenSource stop=new();
        private readonly Task navigation,interaction;
        public readonly int Pid=Random.Shared.Next(300000000,400000000);
        public int Reads,Writes;
        public bool AlwaysOther,Verified=true,Stale;
        public Fixture(){navigation=Serve("Navigation");interaction=Serve("Interaction");}
        private async Task Serve(string service)
        {
            try
            {
                while(!stop.IsCancellationRequested)
                {
                    await using var server=new NamedPipeServerStream($"XFEEDToolBox.{service}.{Pid}",PipeDirection.InOut,1,PipeTransmissionMode.Byte,PipeOptions.Asynchronous);
                    await server.WaitForConnectionAsync(stop.Token);var buffer=new byte[4096];var count=await server.ReadAsync(buffer,stop.Token);
                    using var request=JsonDocument.Parse(buffer.AsMemory(0,count));object result;
                    if(service=="Navigation")
                        result=new{entityId="42",localPlayerShipVerified=Verified,shipHealth=new{entityId="42",verified=Verified,observedAtUnixMilliseconds=DateTimeOffset.UtcNow.AddSeconds(Stale?-2:0).ToUnixTimeMilliseconds()}};
                    else if(request.RootElement.GetProperty("op").GetString()=="read")
                        result=new{sequence=Interlocked.Increment(ref Reads),entityId=AlwaysOther||Reads<=2?"99":"42",observedAtUnixMilliseconds=DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),hardpoints=false,cargoScoop=false,landingGear=false,appliedGeneration=0};
                    else {Interlocked.Increment(ref Writes);result=new{generation=1,queued=true};}
                    var bytes=JsonSerializer.SerializeToUtf8Bytes(new{ok=true,result});await server.WriteAsync(bytes,stop.Token);await server.WriteAsync(new byte[]{10},stop.Token);server.WaitForPipeDrain();
                }
            }
            catch(OperationCanceledException)when(stop.IsCancellationRequested){}
        }
        public async ValueTask DisposeAsync(){stop.Cancel();await Task.WhenAll(navigation,interaction);stop.Dispose();}
        public NativeGameInputChannel Channel()=>new(Pid,new string('a',64),"unused");
    }
    [Test]public async Task OtherShipSamplesAreSkippedUntilTheVerifiedMainShipIsObserved()
    {
        await using var fixture=new Fixture();var value=await fixture.Channel().ReadAsync(CancellationToken.None);
        Check.Equal(42UL,value.EntityId);Check.That(fixture.Reads>=3);Check.Equal(0,fixture.Writes);
    }
    [Test]public async Task PersistentOtherShipCannotProduceAPlayerInputFrame()
    {
        await using var fixture=new Fixture{AlwaysOther=true};
        try{await fixture.Channel().ReadAsync(CancellationToken.None);throw new Exception("Expected unavailable telemetry");}
        catch(FlightTelemetryUnavailableException){}
        Check.Equal(0,fixture.Writes);
    }
    [Test]public async Task UnverifiedOrStaleMainShipBlocksBothObservationAndWrites()
    {
        foreach(var stale in new[]{false,true})
        {
            await using var fixture=new Fixture{Verified=stale,Stale=stale};var channel=fixture.Channel();
            try{await channel.ReadAsync(CancellationToken.None);throw new Exception("Expected unavailable telemetry");}catch(FlightTelemetryUnavailableException){}
            try{await channel.SetAsync(new(1,42,DateTimeOffset.UtcNow,false,false,false),"landingGear",false,CancellationToken.None);throw new Exception("Expected unavailable telemetry");}catch(FlightTelemetryUnavailableException){}
            Check.Equal(0,fixture.Reads);Check.Equal(0,fixture.Writes);
        }
    }
    [Test]public async Task ChangedMainShipBlocksAnOldInputCommandBeforeItsPipeWrite()
    {
        await using var fixture=new Fixture();
        try{await fixture.Channel().SetAsync(new(1,99,DateTimeOffset.UtcNow,false,false,false),"landingGear",false,CancellationToken.None);throw new Exception("Expected ship rejection");}
        catch(InvalidOperationException){}
        Check.Equal(0,fixture.Writes);
    }
}