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 NativeGalaxyStateOwnershipWireTests
{
    private const long First=9007199254740993;
    private static object State(string key="Pseudo39")=>new{stateId=39,pseudoUnpopulated=true,defaulted=false,key,rawRgba=new[]{2.5f,.2f,.3f,0f}};
    private static object Owner(bool own=false)=>new{source=GalaxyNativeColonisationOwnership.Source,localCommanderId="9007199254740995",
        claimCommanderId=own?"9007199254740995":"9007199254740997",claimStatus=2,own};
    private static object Basic()=>new{population="9007199254740995",governmentId=4,primaryEconomyId=4,secondaryEconomyId=10,
        factionStateId=0,allegianceId="9007199254740999",securityValue=40,defaulted=false};
    private static object Row(params (string Name,object? Value)[] fields)
    {var row=new Dictionary<string,object?>{{"systemAddress",First.ToString(CultureInfo.InvariantCulture)}};foreach(var f in fields)row.Add(f.Name,f.Value);return row;}
    private static object Page(object row)=>new{generation=37UL,contextSystemAddress="42",total=1,done=true,error="",items=new[]{row}};
    private static async Task Serve(int pid,object result,CancellationToken stop,Action<JsonElement> inspect)
    {
        await using var server=new NamedPipeServerStream($"XFEEDToolBox.Navigation.{pid}",PipeDirection.InOut,1,PipeTransmissionMode.Byte,PipeOptions.Asynchronous);
        await server.WaitForConnectionAsync(stop);var bytes=new byte[8192];var used=0;
        while(true)
        {
            if(used==bytes.Length)throw new InvalidDataException("Fixture request is oversized.");
            var read=await server.ReadAsync(bytes.AsMemory(used),stop);if(read==0)throw new EndOfStreamException();used+=read;
            JsonDocument request;try{request=JsonDocument.Parse(bytes.AsMemory(0,used));}catch(JsonException){continue;}
            using(request)inspect(request.RootElement);break;
        }
        await server.WriteAsync(JsonSerializer.SerializeToUtf8Bytes(new{ok=true,result}),stop);await server.WriteAsync(new byte[]{10},stop);await server.FlushAsync(stop);
        if(OperatingSystem.IsWindows())server.WaitForPipeDrain();
    }
    private static void Inspect(JsonElement request,bool state,bool owner,bool basic=false,bool colony=false)
    {
        Check.Equal("galaxy.facts",request.GetProperty("op").GetString());
        Check.Equal(state,request.GetProperty("includeState").GetBoolean());Check.Equal(owner,request.GetProperty("includeColonisationOwnership").GetBoolean());
        Check.Equal(basic,request.GetProperty("includeBasicSystem").GetBoolean());Check.Equal(colony,request.GetProperty("includeColonisation").GetBoolean());
        Check.Equal(First.ToString(CultureInfo.InvariantCulture),request.GetProperty("systemAddresses")[0].GetString());
    }
    private static async Task<GalaxyNativeFilterFact> Read(object row,bool state=false,bool owner=false,bool basic=false,bool colony=false)
    {
        var pid=Random.Shared.Next(230000000,240000000);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(8));
        var server=Task.Run(()=>Serve(pid,Page(row),stop.Token,r=>Inspect(r,state,owner,basic,colony)));
        var result=await new NativeGalaxyFilterFactsCatalog(pid).ReadAsync([First],stop.Token,includeColonisation:colony,includeBasicSystem:basic,includeState:state,includeColonisationOwnership:owner);
        await server;Check.Equal(42L,result.OriginSystemAddress);return result.Rows.Single();
    }
    private static async Task Reject(object row,bool state=true,bool owner=true,bool colony=false)
    {
        var pid=Random.Shared.Next(230000000,240000000);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(8));
        var server=Task.Run(async()=>
        {
            await Serve(pid,Page(row),stop.Token,r=>Inspect(r,state,owner,colony:colony));
            await Serve(pid,new{cancelled=true},stop.Token,r=>{Check.Equal("galaxy.facts.cancel",r.GetProperty("op").GetString());Check.Equal(37UL,r.GetProperty("generation").GetUInt64());});
            await Serve(pid,Page(Row(("state",null),("colonisationOwnership",null))),stop.Token,r=>Inspect(r,state,owner,colony:colony));
        });
        var client=new NativeGalaxyFilterFactsCatalog(pid);var rejected=false;
        try{await client.ReadAsync([First],stop.Token,includeColonisation:colony,includeState:state,includeColonisationOwnership:owner);}catch(InvalidDataException){rejected=true;}
        Check.That(rejected,"Malformed or unsolicited original classification was accepted.");
        var recovered=(await client.ReadAsync([First],stop.Token,includeColonisation:colony,includeState:state,includeColonisationOwnership:owner)).Rows.Single();await server;
        Check.That(recovered.State is null&&recovered.ColonisationOwnership is null);Check.Equal(state,recovered.StateRequested);Check.Equal(owner,recovered.ColonisationOwnershipRequested);
    }
    private static GalaxySystemData Data(GalaxyNativeFilterFact f,string account="F1",int pid=42,long origin=42)=>new(){AccountFid=account,
        NativeFilterFacts=new(account,pid,origin){State=f.State,StateRequested=f.StateRequested,ColonisationOwnership=f.ColonisationOwnership,
            ColonisationOwnershipRequested=f.ColonisationOwnershipRequested,BasicSystem=f.BasicSystem,BasicSystemRequested=f.BasicSystemRequested,
            ColonisationHighlight=f.ColonisationHighlight,ColonisationHighlightRequested=f.ColonisationHighlightRequested,ColonisationStatus=f.ColonisationStatus,
            ColonisationNormalStatus=f.ColonisationNormalStatus,ColonisationNormalStatusRequested=f.ColonisationNormalStatusRequested}};

    [Test] public async Task OriginalNormalModeIsIndependentFromEligibilityAndDistinguishesUnavailableFromOldWire()
    {
        var known=await Read(Row(("colonisationStatus",0),("colonisationNormalStatus",5)),colony:true);
        Check.That(known.ColonisationNormalStatusRequested&&known.ColonisationNormalStatus==5&&known.ColonisationStatus==0);
        var pending=await Read(Row(("colonisationStatus",0),("colonisationNormalStatus",null)),colony:true);
        Check.That(pending.ColonisationNormalStatusRequested&&pending.ColonisationNormalStatus is null);
        var old=await Read(Row(("colonisationStatus",0)),colony:true);Check.That(!old.ColonisationNormalStatusRequested);
        await Reject(Row(("colonisationNormalStatus",5)),false,false);
        await Reject(Row(("colonisationNormalStatus",12)),false,false,true);
        await Reject(Row(("colonisationNormalStatus",-1)),false,false,true);
        var filter=GalaxyMapFilter.Default with{Mode=GalaxyMapMode.Colonisation,Category=GalaxyFilterCategory.Colonisation,SizeCategory=GalaxyFilterCategory.Colonisation};
        var system=new GalacticSystem("independent-normal-colony",new(0,0,0)){Data=Data(known)};
        Check.Equal(.35f,filter.GetOriginalRgba(system)!.Value.W);
        Check.Equal(GalaxyOriginalAppearance.DefaultSize*GalaxyOriginalSizeOptions.ColonisationExcludedMultiplier,filter.SelectedOriginalSize(system)!.Value);
        var missing=system with{Data=Data(pending)};Check.That(filter.GetOriginalRgba(missing) is null&&filter.SelectedOriginalSize(missing) is null);
        Check.That(system.Data.Merge(Data(pending)).NativeFilterFacts!.ColonisationNormalStatus is null);
    }

    [Test] public async Task ColonyHighlightWireRequiresMatchingRequestedEligibilityAndKeepsMissingSourceUnknown()
    {
        var highlight=new{source=GalaxyNativeColonisationHighlight.Source,centreSystemAddress="9007199254740995",eligibilityStatus=0,distanceSquared=4f,radiusSquared=4f,rawRgb=new[]{.3f,1f,.2f}};
        var known=await Read(Row(("colonisationStatus",0),("colonisationHighlight",highlight)),colony:true);
        Check.That(known.ColonisationHighlight is{Highlighted:true,CentreSystemAddress:9007199254740995L}&&known.ColonisationHighlightRequested);
        foreach(var row in new[]{Row(("colonisationStatus",0)),Row(("colonisationStatus",0),("colonisationHighlight",null))})
        {var missing=await Read(row,colony:true);Check.That(missing.ColonisationHighlightRequested&&missing.ColonisationHighlight is null);}
        await Reject(Row(("colonisationStatus",0),("colonisationHighlight",highlight)),false,false);
        await Reject(Row(("colonisationStatus",1),("colonisationHighlight",highlight)),false,false,true);
        await Reject(Row(("colonisationHighlight",highlight)),false,false,true);
        await Reject(Row(("colonisationStatus",0),("colonisationHighlight",new{source="journal",centreSystemAddress="42"})),false,false,true);
        var filter=GalaxyMapFilter.Default with{Mode=GalaxyMapMode.Colonisation,Category=GalaxyFilterCategory.Colonisation};
        var system=new GalacticSystem("wire-colony-style",new(0,0,0)){Data=Data(known)};
        Check.Equal(.3f,filter.GetOriginalRgba(system)!.Value.X);
    }

    [Test] public async Task ExplicitNullAndUnrequestedMissingRemainSeparateFromKnownNegativeOwnership()
    {
        foreach(var request in new[]{(State:true,Owner:false),(State:false,Owner:true),(State:true,Owner:true)})
        {
            var unknown=await Read(Row(("state",null),("colonisationOwnership",null)),request.State,request.Owner);
            Check.Equal(request.State,unknown.StateRequested);Check.Equal(request.Owner,unknown.ColonisationOwnershipRequested);
            Check.That(unknown.State is null&&unknown.ColonisationOwnership is null);
        }
        foreach(var row in new[]{Row(),Row(("state",null),("colonisationOwnership",null))})
        {var unrequested=await Read(row);Check.That(!unrequested.StateRequested&&!unrequested.ColonisationOwnershipRequested&&unrequested.State is null&&unrequested.ColonisationOwnership is null);}
        var known=await Read(Row(("state",State()),("colonisationOwnership",Owner()),("basicSystem",Basic())),true,true,true);
        Check.That(known.ColonisationOwnership is{Own:false,LocalCommanderId:9007199254740995UL,ClaimCommanderId:9007199254740997UL});
        Check.That(known.State is{StateId:39,PseudoUnpopulated:true,Defaulted:false,Key:"Pseudo39"});Check.Equal(2.5f,known.State!.RawRgba![0]);Check.Equal(0f,known.State.RawRgba[3]);
        Check.Equal(0U,known.BasicSystem!.FactionStateId);Check.Equal(9007199254740995UL,known.BasicSystem.Population);
    }
    [Test] public async Task MissingRequestedFieldsAndUnrequestedNonNullAreRejectedAndOriginalGenerationIsReleased()
    {
        await Reject(Row(("state",State())));await Reject(Row(("colonisationOwnership",Owner())));
        await Reject(Row(("state",State()),("colonisationOwnership",null)),false,true);
        await Reject(Row(("state",null),("colonisationOwnership",Owner())),true,false);
        await Reject(Row(("state",State())),false,false);await Reject(Row(("colonisationOwnership",Owner())),false,false);
    }
    [Test] public async Task InvalidStateAndOwnershipDtosCannotTurnIntoDefaultOrForeignFacts()
    {
        foreach(var invalid in new[]{"{}","false","{\"stateId\":3,\"pseudoUnpopulated\":true,\"defaulted\":false,\"key\":\"War\",\"rawRgba\":[1,1,1,1]}",
            "{\"stateId\":39,\"pseudoUnpopulated\":true,\"defaulted\":true,\"key\":\"War\",\"rawRgba\":[1,1,1,1]}",
            "{\"stateId\":0,\"pseudoUnpopulated\":false,\"defaulted\":false,\"key\":null,\"rawRgba\":[1,1,1,1]}",
            "{\"stateId\":0,\"pseudoUnpopulated\":false,\"defaulted\":false,\"key\":\"None\",\"rawRgba\":[-1,1,1,1]}"})
            await Reject(Row(("state",Check.Json(invalid)),("colonisationOwnership",null)));
        var valid=JsonSerializer.Serialize(Owner());
        foreach(var invalid in new[]{"{}","[]",valid.Replace("9007199254740995","0"),valid.Replace("original-colonisation-classifier-owner","public-colony"),
            valid.Replace("\"claimStatus\":2","\"claimStatus\":4"),valid.Replace("\"own\":false","\"own\":true"),valid.Replace("\"9007199254740995\"","9007199254740995")})
            await Reject(Row(("state",null),("colonisationOwnership",Check.Json(invalid))));
    }
    [Test] public async Task IndependentStateOwnershipAndBasicRequestsPreserveUnrequestedAndClearOnlyExplicitUnknown()
    {
        var initial=Data(await Read(Row(("state",State()),("colonisationOwnership",Owner()),("basicSystem",Basic())),true,true,true));
        var stateOnly=await Read(Row(("state",State("ActualState"))),state:true);Check.That(!stateOnly.ColonisationOwnershipRequested&&!stateOnly.BasicSystemRequested);
        var merged=initial.Merge(Data(stateOnly));Check.That(merged.NativeFilterFacts is{State.Key:"ActualState",ColonisationOwnership.Own:false,BasicSystem.Population:9007199254740995UL});
        merged=merged.Merge(Data(await Read(Row(("colonisationOwnership",Owner(true))),owner:true)));
        Check.That(merged.NativeFilterFacts is{State.Key:"ActualState",ColonisationOwnership.Own:true,BasicSystemRequested:true});
        merged=merged.Merge(Data(await Read(Row(("basicSystem",null)),basic:true)));
        Check.That(merged.NativeFilterFacts is{State.Key:"ActualState",ColonisationOwnership.Own:true,BasicSystemRequested:true,BasicSystem:null});
        merged=merged.Merge(Data(await Read(Row(("state",null)),state:true)));
        Check.That(merged.NativeFilterFacts is{StateRequested:true,State:null,ColonisationOwnership.Own:true});
        merged=merged.Merge(Data(await Read(Row(("colonisationOwnership",null)),owner:true)));
        Check.That(merged.NativeFilterFacts is{StateRequested:true,State:null,ColonisationOwnershipRequested:true,ColonisationOwnership:null,BasicSystemRequested:true,BasicSystem:null});
    }
    [Test] public async Task ChangedAccountProcessOrOriginCannotInheritAnyUnrequestedClassifier()
    {
        var initial=Data(await Read(Row(("state",State()),("colonisationOwnership",Owner()),("basicSystem",Basic())),true,true,true));
        var unrelated=await Read(Row());
        foreach(var context in new[]{(Account:"F2",Pid:42,Origin:42L),(Account:"F1",Pid:43,Origin:42L),(Account:"F1",Pid:42,Origin:43L)})
        {
            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{StateRequested:false,State:null,ColonisationOwnershipRequested:false,ColonisationOwnership:null,BasicSystemRequested:false,BasicSystem:null});
        }
    }
}