using System.Text.Json;
using XFEEDToolBox.Core.Execution;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]
public class TradeJourneyCheckpointTests
{
[Test] public void IncompleteJourneyDisplaysItsActualCauseAndPreservesTheResult()
{
var cause=new InvalidOperationException("Original health is unavailable");
var result=new NativeTradeJourneyResult(false,Purchased(),TradeProfitSnapshot.Empty,10000,null,cause.ToString(),DateTimeOffset.UtcNow);
var error=new NativeTradeJourneyIncompleteException(result,cause);
Check.That(error.Message.Contains(cause.Message,StringComparison.Ordinal));Check.That(ReferenceEquals(result,error.Result));Check.That(ReferenceEquals(cause,error.InnerException));
}
private static TradeJourneyCheckpoint Purchased()
{
var started=DateTimeOffset.UtcNow.AddHours(-2);
var receipt=new ConfirmedTradeReceipt(Guid.NewGuid().ToString("N"),1,"biowaste",1,40,10000,9960,0,1,"resume-test",5,started.AddMinutes(-1),started.AddSeconds(5),true,true);
return new("resume-test",5,started,receipt);
}
[Test] public void ExistingCamelCaseCheckpointRestoresTheOriginalPurchaseAfterRestart()
{
using var temp=new TemporaryDirectory();var expected=Purchased();var path=temp.File("journey.json");
// This is the format already written by the live acceptance harness.
File.WriteAllText(path,JsonSerializer.Serialize(expected,new JsonSerializerOptions(JsonSerializerDefaults.Web)));
var actual=TradeJourneyCheckpoints.Load(path);
Check.Equal(expected,actual);Check.Equal(expected.Bought!.OperationKey,actual.Bought!.OperationKey);
Check.Equal(expected.Bought.SessionStartedAt,actual.Bought.SessionStartedAt);
}
[Test] public void AtomicReplacementRetainsTheWholePurchaseAndSaleAcrossDifferentGameSessions()
{
using var temp=new TemporaryDirectory();var path=temp.File("journey.json");var bought=Purchased();
TradeJourneyCheckpoints.Save(path,bought);
var sale=new ConfirmedTradeReceipt(Guid.NewGuid().ToString("N"),2,"biowaste",-1,100,9960,10060,1,0,"resume-test",5,DateTimeOffset.UtcNow.AddMinutes(-1),DateTimeOffset.UtcNow,true,true);
var sold=bought with{Sold=sale};TradeJourneyCheckpoints.Save(path,sold);
Check.Equal(sold,TradeJourneyCheckpoints.Load(path));Check.Equal(0,Directory.GetFiles(temp.Path,"*.tmp").Length);
}
[Test] public void RestoringAnOldReceiptDoesNotCountOrBuyTheCargoAgain()
{
using var temp=new TemporaryDirectory();var path=temp.File("journey.json");var ledgerPath=temp.File("ledger");var value=Purchased();
TradeJourneyCheckpoints.Save(path,value);
using(var ledger=new TradeProfitLedger(ledgerPath))Check.That(ledger.RecordTrade(value.Bought!));
var restored=TradeJourneyCheckpoints.Load(path);
using(var ledger=new TradeProfitLedger(ledgerPath))
{
Check.That(!ledger.RecordTrade(restored.Bought!));Check.Equal(40m,ledger.Snapshot.Purchases);
Check.Equal(40m,ledger.Snapshot.CargoInvestment);Check.Equal(-40m,ledger.Snapshot.CashChange);Check.Equal(0m,ledger.Snapshot.NetProfit);
}
}
[Test] public void AnInconsistentReceiptCannotReplaceThePreviousCheckpoint()
{
using var temp=new TemporaryDirectory();var path=temp.File("journey.json");var expected=Purchased();TradeJourneyCheckpoints.Save(path,expected);
var before=File.ReadAllBytes(path);var rejected=false;
try{TradeJourneyCheckpoints.Save(path,expected with{Bought=expected.Bought! with{CreditsAfter=1}});}catch(InvalidDataException){rejected=true;}
Check.That(rejected);Check.That(before.SequenceEqual(File.ReadAllBytes(path)));Check.Equal(expected,TradeJourneyCheckpoints.Load(path));
}
}
using System.Text.Json;
using XFEEDToolBox.Core.Execution;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]
public class TradeJourneyCheckpointTests
{
[Test] public void IncompleteJourneyDisplaysItsActualCauseAndPreservesTheResult()
{
var cause=new InvalidOperationException("Original health is unavailable");
var result=new NativeTradeJourneyResult(false,Purchased(),TradeProfitSnapshot.Empty,10000,null,cause.ToString(),DateTimeOffset.UtcNow);
var error=new NativeTradeJourneyIncompleteException(result,cause);
Check.That(error.Message.Contains(cause.Message,StringComparison.Ordinal));Check.That(ReferenceEquals(result,error.Result));Check.That(ReferenceEquals(cause,error.InnerException));
}
private static TradeJourneyCheckpoint Purchased()
{
var started=DateTimeOffset.UtcNow.AddHours(-2);
var receipt=new ConfirmedTradeReceipt(Guid.NewGuid().ToString("N"),1,"biowaste",1,40,10000,9960,0,1,"resume-test",5,started.AddMinutes(-1),started.AddSeconds(5),true,true);
return new("resume-test",5,started,receipt);
}
[Test] public void ExistingCamelCaseCheckpointRestoresTheOriginalPurchaseAfterRestart()
{
using var temp=new TemporaryDirectory();var expected=Purchased();var path=temp.File("journey.json");
// This is the format already written by the live acceptance harness.
File.WriteAllText(path,JsonSerializer.Serialize(expected,new JsonSerializerOptions(JsonSerializerDefaults.Web)));
var actual=TradeJourneyCheckpoints.Load(path);
Check.Equal(expected,actual);Check.Equal(expected.Bought!.OperationKey,actual.Bought!.OperationKey);
Check.Equal(expected.Bought.SessionStartedAt,actual.Bought.SessionStartedAt);
}
[Test] public void AtomicReplacementRetainsTheWholePurchaseAndSaleAcrossDifferentGameSessions()
{
using var temp=new TemporaryDirectory();var path=temp.File("journey.json");var bought=Purchased();
TradeJourneyCheckpoints.Save(path,bought);
var sale=new ConfirmedTradeReceipt(Guid.NewGuid().ToString("N"),2,"biowaste",-1,100,9960,10060,1,0,"resume-test",5,DateTimeOffset.UtcNow.AddMinutes(-1),DateTimeOffset.UtcNow,true,true);
var sold=bought with{Sold=sale};TradeJourneyCheckpoints.Save(path,sold);
Check.Equal(sold,TradeJourneyCheckpoints.Load(path));Check.Equal(0,Directory.GetFiles(temp.Path,"*.tmp").Length);
}
[Test] public void RestoringAnOldReceiptDoesNotCountOrBuyTheCargoAgain()
{
using var temp=new TemporaryDirectory();var path=temp.File("journey.json");var ledgerPath=temp.File("ledger");var value=Purchased();
TradeJourneyCheckpoints.Save(path,value);
using(var ledger=new TradeProfitLedger(ledgerPath))Check.That(ledger.RecordTrade(value.Bought!));
var restored=TradeJourneyCheckpoints.Load(path);
using(var ledger=new TradeProfitLedger(ledgerPath))
{
Check.That(!ledger.RecordTrade(restored.Bought!));Check.Equal(40m,ledger.Snapshot.Purchases);
Check.Equal(40m,ledger.Snapshot.CargoInvestment);Check.Equal(-40m,ledger.Snapshot.CashChange);Check.Equal(0m,ledger.Snapshot.NetProfit);
}
}
[Test] public void AnInconsistentReceiptCannotReplaceThePreviousCheckpoint()
{
using var temp=new TemporaryDirectory();var path=temp.File("journey.json");var expected=Purchased();TradeJourneyCheckpoints.Save(path,expected);
var before=File.ReadAllBytes(path);var rejected=false;
try{TradeJourneyCheckpoints.Save(path,expected with{Bought=expected.Bought! with{CreditsAfter=1}});}catch(InvalidDataException){rejected=true;}
Check.That(rejected);Check.That(before.SequenceEqual(File.ReadAllBytes(path)));Check.Equal(expected,TradeJourneyCheckpoints.Load(path));
}
}