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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

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

namespace XFEEDToolBox.Test;

[TestFixture]
public class CruiseOverchargeSampleHistoryTests
{
    private static readonly DateTimeOffset Now=DateTimeOffset.FromUnixTimeMilliseconds(1700000000000);
    private static readonly string Hash=new('a',64);
    private static readonly SystemFlightFrame Flight=new(){ShipEntity=12,ReferenceWorld=24,GameSha256=Hash};
    private static JsonElement Sample(DateTimeOffset at,double heat=40,double reserve=.4,ulong entity=12,ulong world=24,int rawFsd=2,bool bound=true,bool ready=true,int state=0,bool canEngage=true)
        =>JsonSerializer.SerializeToElement(new{enabled=true,sampleReady=ready,gameSha256=Hash,sample=new{verified=true,entityId=entity.ToString(),referenceWorldAddress=world.ToString(),
            observedAtUnixMilliseconds=at.ToUnixTimeMilliseconds(),inSupercruise=true,stableFsd=true,rawFsdState=rawFsd,state,nativeCanEngage=canEngage,heatPercent=heat,
            geometryVerified=true,collisionCourse=false,nativeAssistEnabled=false,
            fuelVerified=true,fuelMainTonnes=32,fuelCapacityTonnes=32,reserveFuelTonnes=reserve,fuelBoundVerified=bound,fuelRateUpperTonnesPerSecond=1}});
    [Test]public void FirstSampleCannotInventHeatOrFuelSlopes()
    {var value=new CruiseOverchargeSampleHistory(Hash).Read(Sample(Now),Flight,Now);Check.That(value.OriginalInterfacesVerified&&double.IsNaN(value.HeatRisePercentPerSecond)&&double.IsNaN(value.FuelBurnTonnesPerSecond));}
    [Test]public void NativeCollisionAndAssistFactsSurviveProjectionInsteadOfBeingReplacedByThePrimaryDefaults()
    {
        var node=JsonNode.Parse(Sample(Now).GetRawText())!;node["sample"]!["collisionCourse"]=true;node["sample"]!["nativeAssistEnabled"]=true;
        var projected=new CruiseOverchargeSampleHistory(Hash).Read(JsonSerializer.SerializeToElement(node),Flight,Now);
        Check.That(projected.NativeFlightConstraintsVerified&&projected.NativeGeometryVerified&&projected.NativeCollisionCourse&&projected.NativeAssistEnabled);
        node["sample"]!.AsObject().Remove("geometryVerified");
        Check.That(!new CruiseOverchargeSampleHistory(Hash).Read(JsonSerializer.SerializeToElement(node),Flight,Now).NativeFlightConstraintsVerified);
    }
    [Test]public void TwoSamplesUseBothTheMainAndReservoirFuel()
    {
        var history=new CruiseOverchargeSampleHistory(Hash);history.Read(Sample(Now),Flight,Now);var later=Now.AddMilliseconds(100);
        var value=history.Read(Sample(later,42,.3),Flight,later);Check.That(Math.Abs(value.HeatRisePercentPerSecond-20)<1e-6&&Math.Abs(value.FuelBurnTonnesPerSecond-1)<1e-6);
    }
    [Test]public void DuplicateBackwardStaleAndFutureFramesCannotEnable()
    {
        var history=new CruiseOverchargeSampleHistory(Hash);history.Read(Sample(Now),Flight,Now);
        foreach(var at in new[]{Now,Now.AddMilliseconds(-1),Now.AddMilliseconds(-251),Now.AddMilliseconds(1)})
            Check.That(!history.Read(Sample(at),Flight,Now).OriginalInterfacesVerified);
    }
    [Test]public void OwnedFreshExactDuplicateKeepsItsOriginalTimeAndMeasuredSlopes()
    {
        var history=new CruiseOverchargeSampleHistory(Hash);history.Read(Sample(Now,state:1),Flight,Now);
        var at=Now.AddMilliseconds(100);var sample=Sample(at,42,.3,state:2);
        var previous=history.Read(sample,Flight,at);
        var repeated=history.Read(sample,Flight,at.AddMilliseconds(80),allowRepeated:true);
        Check.Equal(previous,repeated);Check.Equal(at,repeated.ObservedAt);
        Check.That(double.IsFinite(repeated.HeatRisePercentPerSecond)&&double.IsFinite(repeated.FuelBurnTonnesPerSecond));
        Check.That(!history.Read(sample,Flight,at.AddMilliseconds(80)).OriginalInterfacesVerified);
        Check.That(!history.Read(sample,Flight,at.AddMilliseconds(251),allowRepeated:true).OriginalInterfacesVerified);
    }
    [Test]public void OwnedDuplicatePermissionCannotAcceptChangedBackwardFutureOrWrongIdentitySamples()
    {
        var history=new CruiseOverchargeSampleHistory(Hash);history.Read(Sample(Now,state:1),Flight,Now);
        var at=Now.AddMilliseconds(100);history.Read(Sample(at,42,.3,state:2),Flight,at);
        foreach(var sample in new[]{Sample(at,43,.3,state:2),Sample(at,42,.2,state:2),Sample(at,42,.3,state:1),Sample(at,42,.3,state:2,canEngage:false),
            Sample(at.AddMilliseconds(-1),42,.3,state:2),Sample(at.AddMilliseconds(81),42,.3,state:2),Sample(at,42,.3,entity:13,state:2),Sample(at,42,.3,world:25,state:2)})
            Check.That(!history.Read(sample,Flight,at.AddMilliseconds(80),allowRepeated:true).OriginalInterfacesVerified);
    }
    [Test]public void SceneAndShipChangesRequireNewSlopes()
    {
        var history=new CruiseOverchargeSampleHistory(Hash);history.Read(Sample(Now),Flight,Now);var later=Now.AddMilliseconds(100);
        Check.That(!history.Read(Sample(later,entity:13),Flight,later).OriginalInterfacesVerified);
        var value=history.Read(Sample(later,entity:13,world:25),Flight with{ShipEntity=13,ReferenceWorld=25},later);
        Check.That(value.OriginalInterfacesVerified&&double.IsNaN(value.HeatRisePercentPerSecond));
    }
    [Test]public void UnknownFuelBoundWrongFsdAndNoSampleRemainUnusable()
    {
        var history=new CruiseOverchargeSampleHistory(Hash);Check.That(double.IsNaN(history.Read(Sample(Now,bound:false),Flight,Now).FuelRateUpperTonnesPerSecond));
        Check.That(!history.Read(Sample(Now,rawFsd:3),Flight,Now).OriginalInterfacesVerified);
        Check.That(!history.Read(Sample(Now,ready:false),Flight,Now).OriginalInterfacesVerified);
    }
    private static JsonElement WithThermal(ulong entity=12,ulong world=24,long sourceAgeMilliseconds=100,long heatAgeMilliseconds=0)
    {
        var value=JsonNode.Parse(Sample(Now).GetRawText())!;
        value["sample"]!["thermal"]=JsonSerializer.SerializeToNode(new
        {
            verified=true,entityId=entity.ToString(),referenceWorldAddress=world.ToString(),
            sourceObservedAtUnixMilliseconds=Now.ToUnixTimeMilliseconds()-sourceAgeMilliseconds,
            heatObservedAtUnixMilliseconds=Now.ToUnixTimeMilliseconds()-heatAgeMilliseconds,
            heatCapacity=100,heatDisplayScale=1.5,scoInputUpper=30,otherInputUpper=3,
            coolingPassive=5,coolingMaximum=20,coolingScale=1,coolingHeatLower=.2,coolingHeatUpper=1,
            responseDelaySeconds=.02
        });
        return JsonSerializer.SerializeToElement(value);
    }
    [Test]public void NativeSourceAgeDoesNotBecomeTheAgeOfFreshlyObservedHeat()
    {
        var observed=new CruiseOverchargeSampleHistory(Hash).Read(WithThermal(),Flight,Now);
        var thermal=observed.ThermalInput??throw new InvalidOperationException("Native source model was lost.");
        Check.That(thermal.Verified);Check.Equal(.1,thermal.SourceAgeSeconds);Check.Equal(0d,thermal.HeatAgeSeconds);
        var forecast=ScoThermalPredictor.Predict(thermal);
        Check.That(forecast.Known&&forecast.ScoOnNetRisePercentPerSecond>0&&forecast.ScoOffNetRisePercentPerSecond<0);
    }
    [Test]public void ThermalSourcesFromAnotherShipOrReferenceWorldCannotAuthorizeSCO()
    {
        foreach(var sample in new[]{WithThermal(entity:13),WithThermal(world:25)})
        {
            var thermal=new CruiseOverchargeSampleHistory(Hash).Read(sample,Flight,Now).ThermalInput!;
            Check.That(!thermal.Verified&&!ScoThermalPredictor.Predict(thermal).Known);
        }
    }
    [Test]public void FutureOrExpiredNativeSourcesCannotAuthorizeSCOFromAFreshFlightFrame()
    {
        foreach(var age in new long[]{-1,201})
        {
            var thermal=new CruiseOverchargeSampleHistory(Hash).Read(WithThermal(sourceAgeMilliseconds:age),Flight,Now).ThermalInput!;
            Check.That(!ScoThermalPredictor.Predict(thermal).Known);
        }
    }
    [Test]public void IndependentHeatTimestampSurvivesTheNewerControlSampleTimestamp()
    {
        var thermal=new CruiseOverchargeSampleHistory(Hash).Read(WithThermal(heatAgeMilliseconds:1),Flight,Now).ThermalInput!;
        Check.Equal(.001,thermal.HeatAgeSeconds);Check.Equal(.1,thermal.SourceAgeSeconds);
        Check.That(ScoThermalPredictor.Predict(thermal).Known);
    }
    [Test]public void UnknownFutureOrExpiredHeatCannotBeRenewedByAFreshControlSample()
    {
        foreach(var age in new long[]{-1,201})
        {
            var thermal=new CruiseOverchargeSampleHistory(Hash).Read(WithThermal(heatAgeMilliseconds:age),Flight,Now).ThermalInput!;
            Check.That(!ScoThermalPredictor.Predict(thermal).Known);
        }
        foreach(var unknown in new JsonNode?[]{null,JsonValue.Create("unknown"),JsonValue.Create(0L)})
        {
            var node=JsonNode.Parse(WithThermal().GetRawText())!;node["sample"]!["thermal"]!["heatObservedAtUnixMilliseconds"]=unknown;
            var thermal=new CruiseOverchargeSampleHistory(Hash).Read(JsonSerializer.SerializeToElement(node),Flight,Now).ThermalInput!;
            Check.That(!ScoThermalPredictor.Predict(thermal).Known);
        }
        var missing=JsonNode.Parse(WithThermal().GetRawText())!;missing["sample"]!["thermal"]!.AsObject().Remove("heatObservedAtUnixMilliseconds");
        Check.That(!ScoThermalPredictor.Predict(new CruiseOverchargeSampleHistory(Hash).Read(JsonSerializer.SerializeToElement(missing),Flight,Now).ThermalInput!).Known);
    }
}