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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

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

namespace XFEEDToolBox.Test;

[TestFixture]
public sealed class NativeGalaxyCarrierWireTests
{
    private const long First=9007199254740993;
    private static object Carrier(bool dockable)=>new{dockable};
    private static object Row(long address,params (string Name,object? Value)[] fields)
    {
        var row=new Dictionary<string,object?>{{"systemAddress",address.ToString(CultureInfo.InvariantCulture)}};
        foreach(var field in fields)row.Add(field.Name,field.Value);
        return row;
    }
    private static object Page(string origin,int total,bool done,params object[] rows)=>new
        {generation=19UL,contextSystemAddress=origin,total,done,error="",items=rows};

    private static async Task Serve(int pid,object result,CancellationToken token,Action<JsonElement>? inspect=null)
    {
        await using var server=new NamedPipeServerStream($"XFEEDToolBox.Navigation.{pid}",PipeDirection.InOut,1,PipeTransmissionMode.Byte,PipeOptions.Asynchronous);
        await server.WaitForConnectionAsync(token);var buffer=new byte[8192];var count=0;
        while(true)
        {
            if(count==buffer.Length)throw new InvalidDataException("Fixture request exceeds its bound.");
            var read=await server.ReadAsync(buffer.AsMemory(count),token);if(read==0)throw new EndOfStreamException();count+=read;
            JsonDocument request;
            try{request=JsonDocument.Parse(buffer.AsMemory(0,count));}catch(JsonException){continue;}
            using(request)inspect?.Invoke(request.RootElement);
            break;
        }
        await server.WriteAsync(JsonSerializer.SerializeToUtf8Bytes(new{ok=true,result}),token);
        await server.WriteAsync(new byte[]{10},token);await server.FlushAsync(token);
        if(OperatingSystem.IsWindows())server.WaitForPipeDrain();
    }

    private static void Inspect(JsonElement request,bool carrier,bool civilization=false,bool services=false)
    {
        Check.Equal("galaxy.facts",request.GetProperty("op").GetString());
        Check.Equal(carrier,request.GetProperty("includeCarrier").GetBoolean());
        Check.Equal(civilization,request.GetProperty("includeCivilization").GetBoolean());
        Check.Equal(services,request.GetProperty("includeServices").GetBoolean());
        Check.Equal(First.ToString(CultureInfo.InvariantCulture),request.GetProperty("systemAddresses")[0].GetString());
    }

    private static async Task<GalaxyNativeFilterFact> ReadOne(object row,bool carrier,bool civilization=false,bool services=false)
    {
        var pid=Random.Shared.Next(200000000,210000000);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(8));
        var server=Task.Run(()=>Serve(pid,Page("42",1,true,row),stop.Token,r=>Inspect(r,carrier,civilization,services)));
        var result=await new NativeGalaxyFilterFactsCatalog(pid).ReadAsync([First],stop.Token,includeCarrier:carrier,includeCivilization:civilization,includeServices:services);
        await server;Check.Equal(42L,result.OriginSystemAddress);return result.Rows.Single();
    }

    private static async Task RejectAndRecover(object row,bool requested)
    {
        var pid=Random.Shared.Next(200000000,210000000);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(8));
        var server=Task.Run(async()=>
        {
            await Serve(pid,Page("42",1,true,row),stop.Token,r=>Inspect(r,requested));
            await Serve(pid,new{cancelled=true},stop.Token,r=>
            {Check.Equal("galaxy.facts.cancel",r.GetProperty("op").GetString());Check.Equal(19UL,r.GetProperty("generation").GetUInt64());});
            await Serve(pid,Page("42",1,true,Row(First,("carrier",null))),stop.Token,r=>Inspect(r,requested));
        });
        var catalog=new NativeGalaxyFilterFactsCatalog(pid);var rejected=false;
        try{await catalog.ReadAsync([First],stop.Token,includeCarrier:requested);}catch(InvalidDataException){rejected=true;}
        Check.That(rejected,"Invalid carrier receipt was accepted.");
        var recovered=await catalog.ReadAsync([First],stop.Token,includeCarrier:requested);await server;
        Check.That(recovered.Rows.Single().CarrierDockable is null);Check.Equal(requested,recovered.Rows.Single().CarrierRequested);
    }

    [Test] public async Task RequestedCarrierPreservesTrueFalseAndExplicitUnknownForExactAddresses()
    {
        var pid=Random.Shared.Next(200000000,210000000);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(8));
        var server=Task.Run(()=>Serve(pid,Page("42",3,true,
            Row(First,("carrier",Carrier(true))),Row(First+1,("carrier",Carrier(false))),Row(First+2,("carrier",null))),stop.Token,r=>Inspect(r,true)));
        var result=await new NativeGalaxyFilterFactsCatalog(pid).ReadAsync([First,First+1,First+2],stop.Token,includeCarrier:true);await server;
        Check.That(result.Rows.All(row=>row.CarrierRequested&&!row.CivilizationRequested&&!row.ServicesRequested));
        Check.Equal(First,result.Rows[0].SystemAddress);Check.Equal(First+1,result.Rows[1].SystemAddress);Check.Equal(First+2,result.Rows[2].SystemAddress);
        Check.That(result.Rows[0].CarrierDockable==true&&result.Rows[1].CarrierDockable==false&&result.Rows[2].CarrierDockable is null);
    }

    [Test] public async Task UnrequestedMissingAndExplicitNullDoNotReuseAnEarlierClientResult()
    {
        var pid=Random.Shared.Next(200000000,210000000);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(8));
        var server=Task.Run(async()=>
        {
            await Serve(pid,Page("42",1,true,Row(First,("carrier",Carrier(true)))),stop.Token,r=>Inspect(r,true));
            await Serve(pid,Page("42",1,true,Row(First)),stop.Token,r=>Inspect(r,false));
            await Serve(pid,Page("42",1,true,Row(First,("carrier",null))),stop.Token,r=>Inspect(r,false));
        });
        var catalog=new NativeGalaxyFilterFactsCatalog(pid);
        Check.That((await catalog.ReadAsync([First],stop.Token,includeCarrier:true)).Rows.Single().CarrierDockable==true);
        for(var i=0;i<2;i++)Check.That((await catalog.ReadAsync([First],stop.Token)).Rows.Single() is{CarrierRequested:false,CarrierDockable:null});
        await server;
    }

    [Test] public async Task RequestedMissingBindingAndMalformedDockableAreRejectedWithQueueCleanup()
    {
        await RejectAndRecover(Row(First),true);
        foreach(var invalid in new[]{"true","false","1","\"false\"","[]","{}","{\"dockable\":null}","{\"dockable\":1}",
            "{\"dockable\":\"false\"}","{\"dockable\":[]}","{\"dockable\":{}}"})
            await RejectAndRecover(Row(First,("carrier",Check.Json(invalid))),true);
    }

    [Test] public async Task AnyUnrequestedNonNullCarrierPayloadIsRejectedEvenWhenItLooksFalse()
    {
        foreach(var value in new[]{"{\"dockable\":true}","{\"dockable\":false}","{\"dockable\":null}","false","{}"})
            await RejectAndRecover(Row(First,("carrier",Check.Json(value))),false);
    }

    [Test] public async Task CarrierIsIndependentOfCivilizationAndServicesForEveryAddress()
    {
        var pid=Random.Shared.Next(200000000,210000000);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(8));
        var server=Task.Run(()=>Serve(pid,Page("42",3,true,
            Row(First,("carrier",null),("civilization",new{definitionId="9007199254740995",key="guardian",defaulted=false}),("services",new{mask=513,defaulted=false})),
            Row(First+1,("carrier",Carrier(false)),("civilization",null),("services",null)),
            Row(First+2,("carrier",Carrier(true)),("civilization",new{definitionId="18446744073709551615",key="none",defaulted=true}),("services",new{mask=0,defaulted=true}))),stop.Token,r=>Inspect(r,true,true,true)));
        var result=await new NativeGalaxyFilterFactsCatalog(pid).ReadAsync([First,First+1,First+2],stop.Token,includeCarrier:true,includeCivilization:true,includeServices:true);await server;
        Check.That(result.Rows.All(row=>row.CarrierRequested&&row.CivilizationRequested&&row.ServicesRequested));
        Check.That(result.Rows[0] is{CarrierDockable:null,Civilization.Key:"guardian",ServiceMask:513,ServicesDefaulted:false});
        Check.That(result.Rows[1] is{CarrierDockable:false,Civilization:null,ServiceMask:null,ServicesDefaulted:null});
        Check.That(result.Rows[2] is{CarrierDockable:true,Civilization.Key:"none",Civilization.Defaulted:true,ServiceMask:0,ServicesDefaulted:true});
    }

    [Test] public async Task ProgressivePagesDoNotCopyOneAddressesCarrierValueIntoAnother()
    {
        var pid=Random.Shared.Next(200000000,210000000);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(8));
        var server=Task.Run(async()=>
        {
            await Serve(pid,Page("42",2,false,Row(First,("carrier",Carrier(false)))),stop.Token,r=>Inspect(r,true));
            await Serve(pid,Page("42",2,true,Row(First+1,("carrier",null))),stop.Token,r=>
            {Check.Equal("galaxy.facts.result",r.GetProperty("op").GetString());Check.Equal(1,r.GetProperty("offset").GetInt32());Check.Equal(19UL,r.GetProperty("generation").GetUInt64());});
        });
        var result=await new NativeGalaxyFilterFactsCatalog(pid).ReadAsync([First,First+1],stop.Token,includeCarrier:true);await server;
        Check.That(result.Rows[0].CarrierDockable==false&&result.Rows[1].CarrierDockable is null&&result.Rows.All(row=>row.CarrierRequested));
    }

    [Test] public async Task ChangedOriginRejectsMixedPagesAndFreshQueryDoesNotRetainOldDockability()
    {
        var pid=Random.Shared.Next(200000000,210000000);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(8));
        var server=Task.Run(async()=>
        {
            await Serve(pid,Page("42",2,false,Row(First,("carrier",Carrier(true)))),stop.Token);
            await Serve(pid,Page("43",2,true,Row(First+1,("carrier",Carrier(false)))),stop.Token);
            await Serve(pid,new{cancelled=true},stop.Token,r=>Check.Equal("galaxy.facts.cancel",r.GetProperty("op").GetString()));
            await Serve(pid,Page("43",1,true,Row(First,("carrier",null))),stop.Token,r=>Inspect(r,true));
        });
        var catalog=new NativeGalaxyFilterFactsCatalog(pid);var rejected=false;
        try{await catalog.ReadAsync([First,First+1],stop.Token,includeCarrier:true);}catch(InvalidDataException){rejected=true;}
        Check.That(rejected);var result=await catalog.ReadAsync([First],stop.Token,includeCarrier:true);await server;
        Check.Equal(43L,result.OriginSystemAddress);Check.That(result.Rows.Single() is{CarrierRequested:true,CarrierDockable:null});
    }

    private static GalaxySystemData Data(GalaxyNativeFilterFact row,string account="F1",int pid=42,long origin=100)=>new()
    {NativeFilterFacts=new(account,pid,origin){CarrierDockable=row.CarrierDockable,CarrierRequested=row.CarrierRequested,
        Civilization=row.Civilization,CivilizationRequested=row.CivilizationRequested,ServiceMask=row.ServiceMask,ServicesRequested=row.ServicesRequested,ServicesDefaulted=row.ServicesDefaulted}};

    [Test] public async Task UnrequestedWireUpdatesPreserveBothKnownCarrierValuesButExplicitNullClearsThem()
    {
        foreach(var dockable in new[]{false,true})
        {
            var initial=Data(await ReadOne(Row(First,("carrier",Carrier(dockable)),("civilization",new{definitionId="9007199254740995",key="guardian",defaulted=false}),("services",new{mask=513,defaulted=false})),true,true,true));
            var civilizationOnly=Data(await ReadOne(Row(First,("civilization",new{definitionId="9007199254740997",key="human",defaulted=false})),false,true));
            var state=initial.Merge(civilizationOnly);
            Check.That(state.NativeFilterFacts is{CarrierRequested:true,Civilization.Key:"human",ServicesRequested:true,ServiceMask:513});
            Check.Equal((bool?)dockable,state.NativeFilterFacts!.CarrierDockable);
            var serviceOnly=Data(await ReadOne(Row(First,("services",new{mask=0,defaulted=true})),false,false,true));
            state=state.Merge(serviceOnly);Check.Equal((bool?)dockable,state.NativeFilterFacts!.CarrierDockable);
            Check.That(state.NativeFilterFacts is{CarrierRequested:true,Civilization.Key:"human",ServiceMask:0,ServicesDefaulted:true});
            var unknown=Data(await ReadOne(Row(First,("carrier",null)),true));state=state.Merge(unknown);
            Check.That(state.NativeFilterFacts is{CarrierRequested:true,CarrierDockable:null,Civilization.Key:"human",ServiceMask:0,ServicesDefaulted:true});
        }
    }

    [Test] public async Task AccountProcessAndOriginChangesNeverInheritUnrequestedCarrierEvidence()
    {
        var initial=Data(await ReadOne(Row(First,("carrier",Carrier(false))),true));
        var unrelated=await ReadOne(Row(First),false);
        foreach(var context in new[]{(Account:"F2",Pid:42,Origin:100L),(Account:"F1",Pid:43,Origin:100L),(Account:"F1",Pid:42,Origin:101L)})
        {
            Check.That(initial.ForNativeContext(context.Account,context.Pid,context.Origin).NativeFilterFacts is null);
            var changed=initial.Merge(Data(unrelated,context.Account,context.Pid,context.Origin));
            Check.That(changed.NativeFilterFacts is{CarrierRequested:false,CarrierDockable:null});
        }
    }
}