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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Collections.Concurrent;
using XFEExtension.NetCore.XUnit.Attributes;
using XFEEDToolBox.Core.Data;using XFEEDToolBox.Core.Models;using XFEEDToolBox.Core.Planning;
namespace XFEEDToolBox.Test;
[TestFixture]public sealed class AllStationTradePlanningTests
{
    private sealed class InlineProgress(Action<TradePlanningProgress> observe):IProgress<TradePlanningProgress>{public void Report(TradePlanningProgress value)=>observe(value);}
    private static MarketBook LargeBook()
    {
        var stations=Enumerable.Range(1,501).Select(id=>Check.Station(id,id*.01)).ToArray();
        var quotes=stations.Select(station=>Check.Quote(station.MarketId,"water",0,0,0,0)).ToList();
        quotes.RemoveAll(quote=>quote.MarketId is 250 or 251);
        quotes.Add(Check.Quote(250,"water",10,9));quotes.Add(Check.Quote(251,"water",0,20));
        return new(stations,quotes);
    }
    [Test]public void Beyond180AllStationsParticipateAndARealAlternateOriginIncludesItsDeadhead()
    {
        var events=new ConcurrentQueue<TradePlanningProgress>();var request=Check.Request with{Loop=false,MaxLegs=1,SearchRadiusLy=500};
        var result=new TradeRoutePlanner().CalculateCandidatesWithDiagnostics(LargeBook(),request,progress:new InlineProgress(events.Enqueue));
        var plan=result.Candidates.First();Check.Equal(250L,plan.Request.StartMarketId);Check.Equal(501,plan.StationsConsidered);Check.Equal(2.5,plan.DeadheadDistanceLy);
        Check.That(!result.Diagnostics.InputTruncated);Check.Equal(501,result.Diagnostics.CompatibleStations);
        Check.That(events.Any(value=>value.Stage=="完成"&&value.Processed==value.Total));
        Check.That(events.All(value=>value.Total is null||value.Processed<=value.Total));
    }
    [Test]public void SourceKindsDoNotExcludeCarrierDestinationsOrAnEmptyReturn()
    {
        var carrier=Check.Station(2,10) with{IsFleetCarrier=true,Type="FleetCarrier",MaxLandingPad=LandingPad.Unknown};
        var book=new MarketBook([Check.Station(1),carrier],[Check.Quote(1,"water",10,9),Check.Quote(2,"water",0,20)]);
        var request=Check.Request with{AllowedSourceKinds=StationSourceKinds.Starport,Loop=true,MaxLegs=2,IncludeCarriers=false};
        var plan=new TradeRoutePlanner().CalculateCandidates(book,request).First();
        Check.Equal(2L,plan.Legs[0].To.MarketId);Check.Equal(0,plan.Legs[1].Quantity);
        Check.That(plan.Legs.Where(leg=>leg.Quantity>0).All(leg=>!leg.From.IsFleetCarrier));
    }
    [Test]public void UnknownHullAndUnknownPadNeverBecomeAnAssumedSmallDestination()
    {
        var planner=new TradeRoutePlanner();
        Check.Throws<InvalidOperationException>(()=>planner.CalculateCandidates(Check.TwoStations,Check.Request with{ActualShipType="Unverified future ship",RequiredPad=LandingPad.Small}));
        var request=Check.Request with{ActualShipType="Type9",RequiredPad=LandingPad.Small,AllowUnknownMetadata=true};
        Check.That(!TradeRoutePlanner.IsStationCompatible(Check.Station(2) with{MaxLandingPad=LandingPad.Medium},request,false));
        Check.That(!TradeRoutePlanner.IsStationCompatible(Check.Station(2) with{MaxLandingPad=LandingPad.Unknown},request,false));
    }
    [Test]public void TheSeventeenthAffordableDestinationIsNotDiscardedByAGrossPriceHeuristic()
    {
        var stations=Enumerable.Range(1,18).Select(id=>Check.Station(id,id*.01)).ToArray();var quotes=new List<CommodityQuote>();
        for(var id=2;id<=17;id++){quotes.Add(Check.Quote(1,"expensive"+id,1_000_000_000,0));quotes.Add(Check.Quote(id,"expensive"+id,0,2_000_000_000));}
        quotes.Add(Check.Quote(1,"water",100,90));quotes.Add(Check.Quote(18,"water",0,180));
        var plans=new TradeRoutePlanner().CalculateCandidates(new(stations,quotes),Check.Request with{Loop=false,MaxLegs=1});
        Check.Equal(18L,plans.First().Legs.Single().To.MarketId);
    }
    [Test]public void CancellationDuringParallelIndexingNeverReportsCompletion()
    {
        using var cancellation=new CancellationTokenSource();var events=new ConcurrentQueue<TradePlanningProgress>();
        var progress=new InlineProgress(value=>{events.Enqueue(value);if(value.Stage=="建立商品与空间索引"&&value.Processed>0)cancellation.Cancel();});
        Check.Throws<OperationCanceledException>(()=>new TradeRoutePlanner().CalculateCandidates(LargeBook(),Check.Request,token:cancellation.Token,progress:progress));
        Check.That(!events.Any(value=>value.Stage=="完成"));
    }
    [Test]public async Task PlanningReadLoadsMoreThan180FreshCompatibleStationsWithoutDroppingRows()
    {
        using var temporary=new TemporaryDirectory();var repository=new MarketRepository(temporary.File("markets.db"));repository.InitializeCheap();var at=DateTimeOffset.UtcNow;
        for(var id=1;id<=205;id++)await repository.SaveSnapshotAsync(new(Check.Station(id,id*.01),[Check.Quote(id,"water",10,20)],at,DataSource.Journal));
        var book=repository.LoadPlanningRegion(Check.Request with{AsOf=at});Check.Equal(205,book.Stations.Count);Check.Equal(205,book.Quotes.Count);Check.That(!book.Truncated);
    }
}