using System.Text.Json;
using XFEExtension.NetCore.XUnit.Attributes;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Outfitting;
namespace XFEEDToolBox.Test;
[TestFixture]
public class EdsyTests
{
private static JsonElement[] Fixtures=>JsonDocument.Parse(File.ReadAllText(Path.Combine(AppContext.BaseDirectory,"Fixtures","edsy-oracle.json"))).RootElement.EnumerateArray().Select(e=>e.Clone()).ToArray();
[Test] public void AllOfficialStockShipsAndEngineeringFixtureRoundTripExactly()
{
foreach(var fixture in Fixtures)
{
var hash=fixture.GetProperty("hash").GetString()!;
var doc=EdsyLinkCodec.Import("https://edsy.org/#/L="+hash);
Check.Equal(fixture.GetProperty("ship").GetString(),doc.ShipType);
Check.Equal("https://edsy.org/#/L="+hash,EdsyLinkCodec.Export(doc));
foreach(var expected in fixture.GetProperty("loadout").GetProperty("Modules").EnumerateArray().Where(m=>m.GetProperty("Slot").GetString()!="CargoHatch"))
{
var slot=doc.Slots.Single(s=>s.Slot==expected.GetProperty("Slot").GetString());
Check.Equal(expected.GetProperty("Item").GetString(),slot.Module?.Item);
Check.Equal(expected.GetProperty("On").GetBoolean(),slot.Module!.Enabled);
Check.Equal(expected.GetProperty("Priority").GetInt32(),slot.Module.Priority);
}
}
}
[Test] public void EngineeredFieldsAndPartialProgressArePreserved()
{
var fixture=Fixtures.Last();var doc=EdsyLinkCodec.Import(fixture.GetProperty("hash").GetString()!);
Check.That(doc.Slots.Any(s=>s.Module?.Engineering?.ExperimentalEffectId.Length>0));
var module=doc.Slots.First(s=>s.Module?.Engineering is not null).Module!;
Check.Equal(3,module.Engineering!.Level);Check.That(Math.Abs(module.Engineering.Quality!.Value-.435)<.0003);Check.That(module.Engineering.Modifiers.Count>0);
Check.Equal("XFE Test - 42",doc.Name);Check.Equal("XF-42",doc.Ident);
}
[Test] public void ReplacementAndUninstallationSurviveLinkRoundTrip()
{
var doc=EdsyLinkCodec.Import(Fixtures[0].GetProperty("hash").GetString()!);
var slot=doc.Slots.First(s=>s.Category=="hardpoint"&&s.Module is not null);
var removed=ShipRefit.Install(doc,slot.Slot,null,OutfittingCatalog.Default);
var imported=EdsyLinkCodec.Import(EdsyLinkCodec.Export(removed));
Check.That(imported.Slots.Single(s=>s.Slot==slot.Slot).Module is null);
Check.That(doc.Slots.Single(s=>s.Slot==slot.Slot).Module is not null);
var definition=OutfittingCatalog.Default.Modules.First(m=>m.Category=="hardpoint"&&m.Size==slot.Capacity&&m.Item!=slot.Module!.Item&&m.Ship.Length==0);
var replacement=ShipRefit.Install(doc,slot.Slot,new("","计划购入",new(){Slot=slot.Slot,Item=definition.Item,Enabled=true},definition),OutfittingCatalog.Default);
Check.Equal(definition.Item,EdsyLinkCodec.Import(EdsyLinkCodec.Export(replacement)).Slots.Single(s=>s.Slot==slot.Slot).Module?.Item);
}
[Test] public void NewEngineeringTargetReplacesOldModifiersInExport()
{
var doc=EdsyLinkCodec.Import(Fixtures.Last().GetProperty("hash").GetString()!);
var target=doc.Slots.Single(s=>s.Slot=="PowerPlant");
doc=ShipRefit.SetTarget(doc,target.Slot,new("Overcharged",5,1,"special_powerplant_cooled",0,false,true));
var exported=EdsyLinkCodec.Import(EdsyLinkCodec.Export(doc));
var module=exported.Slots.Single(s=>s.Slot==target.Slot).Module!;
Check.Equal(5,module.Engineering!.Level);Check.That(module.Engineering.Quality>.999);
Check.Equal("PowerPlant_Boosted",module.Engineering.Blueprint);
Check.That(module.Engineering.Modifiers.Count>0);
}
[Test] public void ExplicitNoExperimentalEffectDoesNotReappearAfterEdsyExport()
{
var doc=EdsyLinkCodec.Import(Fixtures.Last().GetProperty("hash").GetString()!);
var slot=doc.Slots.First(s=>s.Module?.Engineering?.ExperimentalEffectId.Length>0);
var engineering=slot.Module!.Engineering!;
var none=ShipRefit.SetTarget(doc,slot.Slot,new(engineering.Blueprint,engineering.Level,engineering.Quality??1,"",0,false,true));
var restored=EdsyLinkCodec.Import(EdsyLinkCodec.Export(none)).Slots.Single(s=>s.Slot==slot.Slot).Module!;
Check.That(restored.Engineering is not null&&restored.Engineering.ExperimentalEffectId.Length==0);
Check.Equal(engineering.Level,restored.Engineering!.Level);
Check.That(doc.Slots.Single(s=>s.Slot==slot.Slot).Module!.Engineering!.ExperimentalEffectId.Length>0);
}
[Test] public void IncompleteCoreConfigurationIsRejectedInsteadOfInventingStockModules()
{
var doc=EdsyLinkCodec.Import(Fixtures[0].GetProperty("hash").GetString()!);
doc=ShipRefit.Install(doc,"PowerPlant",null,OutfittingCatalog.Default);
Check.Throws<FormatException>(()=>EdsyLinkCodec.Export(doc));
}
[Test] public void UnsupportedOrInvalidLinksAreRejected()
{
foreach(var value in new[]{"https://evil.example/#/L=K100000,xxx","https://edsy.org.evil.example/#/L=K100000,xxx","https://edsy.org/#/L=Z123456,,,","garbage","https://edsy.org/#/L=K!!!!,xx","https://edsy.org/#/L=K100000,xxx<script>","https://edsy.org/#/L=Kzzzzzz,,,"})
Check.Throws<FormatException>(()=>EdsyLinkCodec.Import(value));
}
[Test] public void UnknownModuleExportFailsWithoutSilentlyDroppingIt()
{
var doc=EdsyLinkCodec.Import(Fixtures[0].GetProperty("hash").GetString()!);
var slot=doc.Slots.First(s=>s.Module is not null);doc=doc with{Slots=doc.Slots.Select(s=>s==slot?s with{Module=s.Module! with{Item="int_unknown_fake_module"}}:s).ToArray()};
Check.Throws<FormatException>(()=>EdsyLinkCodec.Export(doc));
}
[Test] public void ActualLoadoutPreservesEngineeringScoopAndScoDrive()
{
var doc=JsonSerializer.Deserialize<ShipRefitDocument>(File.ReadAllText(Path.Combine(AppContext.BaseDirectory,"Fixtures","edsy-actual-loadout.json")),ToolboxSettings.JsonOptions)!;
var actualUrl=EdsyLinkCodec.Export(doc);
var imported=EdsyLinkCodec.Import(actualUrl);
foreach(var slot in doc.Slots.Where(s=>s.Module is not null&&s.Category.Length>0&&s.Slot!="PlanetaryApproachSuite"))
{
var before=slot.Module!;var after=imported.Slots.Single(s=>s.Slot==slot.Slot).Module!;
Check.Equal(before.Item,after.Item);Check.Equal(before.Enabled,after.Enabled);Check.Equal(before.Priority,after.Priority);
if(before.Engineering is {} e)
{
Check.Equal(e.Blueprint,after.Engineering!.Blueprint);Check.Equal(e.Level,after.Engineering.Level);
Check.Equal(e.ExperimentalEffectId,after.Engineering.ExperimentalEffectId);
if(e.Quality is {} quality)Check.That(Math.Abs(quality-after.Engineering.Quality!.Value)<.0003);
}
}
Check.That(imported.Slots.Any(s=>s.Module?.Item.Contains("fuelscoop")==true));
Check.That(imported.Slots.Any(s=>s.Module?.Item.Contains("hyperdrive_overcharge")==true));
var modified=ShipRefit.SetTarget(doc,"PowerPlant",new("Overcharged",5,1,"special_powerplant_cooled",0,false,true));
File.WriteAllText(Path.Combine(AppContext.BaseDirectory,"edsy-v8-exports.json"),JsonSerializer.Serialize(new[]{
new{name="actual-loadout",url=actualUrl,expected=(object?)null},
new{name="modified-engineering",url=EdsyLinkCodec.Export(modified),expected=(object?)new{slot="PowerPlant",blueprint="PowerPlant_Boosted",grade=5,effect="special_powerplant_cooled"}}
}));
}
[Test] public void EnglishExperimentalNamesAreResolvedForTheirModuleType()
{
var doc=EdsyLinkCodec.Import(Fixtures.Last().GetProperty("hash").GetString()!);
doc=ShipRefit.SetTarget(doc,"PowerPlant",new("Overcharged",4,.75,"Stripped Down",0,false,true));
var imported=EdsyLinkCodec.Import(EdsyLinkCodec.Export(doc));
Check.Equal("special_powerplant_lightweight",imported.Slots.Single(s=>s.Slot=="PowerPlant").Module!.Engineering!.ExperimentalEffectId);
}
}
using System.Text.Json;
using XFEExtension.NetCore.XUnit.Attributes;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Outfitting;
namespace XFEEDToolBox.Test;
[TestFixture]
public class EdsyTests
{
private static JsonElement[] Fixtures=>JsonDocument.Parse(File.ReadAllText(Path.Combine(AppContext.BaseDirectory,"Fixtures","edsy-oracle.json"))).RootElement.EnumerateArray().Select(e=>e.Clone()).ToArray();
[Test] public void AllOfficialStockShipsAndEngineeringFixtureRoundTripExactly()
{
foreach(var fixture in Fixtures)
{
var hash=fixture.GetProperty("hash").GetString()!;
var doc=EdsyLinkCodec.Import("https://edsy.org/#/L="+hash);
Check.Equal(fixture.GetProperty("ship").GetString(),doc.ShipType);
Check.Equal("https://edsy.org/#/L="+hash,EdsyLinkCodec.Export(doc));
foreach(var expected in fixture.GetProperty("loadout").GetProperty("Modules").EnumerateArray().Where(m=>m.GetProperty("Slot").GetString()!="CargoHatch"))
{
var slot=doc.Slots.Single(s=>s.Slot==expected.GetProperty("Slot").GetString());
Check.Equal(expected.GetProperty("Item").GetString(),slot.Module?.Item);
Check.Equal(expected.GetProperty("On").GetBoolean(),slot.Module!.Enabled);
Check.Equal(expected.GetProperty("Priority").GetInt32(),slot.Module.Priority);
}
}
}
[Test] public void EngineeredFieldsAndPartialProgressArePreserved()
{
var fixture=Fixtures.Last();var doc=EdsyLinkCodec.Import(fixture.GetProperty("hash").GetString()!);
Check.That(doc.Slots.Any(s=>s.Module?.Engineering?.ExperimentalEffectId.Length>0));
var module=doc.Slots.First(s=>s.Module?.Engineering is not null).Module!;
Check.Equal(3,module.Engineering!.Level);Check.That(Math.Abs(module.Engineering.Quality!.Value-.435)<.0003);Check.That(module.Engineering.Modifiers.Count>0);
Check.Equal("XFE Test - 42",doc.Name);Check.Equal("XF-42",doc.Ident);
}
[Test] public void ReplacementAndUninstallationSurviveLinkRoundTrip()
{
var doc=EdsyLinkCodec.Import(Fixtures[0].GetProperty("hash").GetString()!);
var slot=doc.Slots.First(s=>s.Category=="hardpoint"&&s.Module is not null);
var removed=ShipRefit.Install(doc,slot.Slot,null,OutfittingCatalog.Default);
var imported=EdsyLinkCodec.Import(EdsyLinkCodec.Export(removed));
Check.That(imported.Slots.Single(s=>s.Slot==slot.Slot).Module is null);
Check.That(doc.Slots.Single(s=>s.Slot==slot.Slot).Module is not null);
var definition=OutfittingCatalog.Default.Modules.First(m=>m.Category=="hardpoint"&&m.Size==slot.Capacity&&m.Item!=slot.Module!.Item&&m.Ship.Length==0);
var replacement=ShipRefit.Install(doc,slot.Slot,new("","计划购入",new(){Slot=slot.Slot,Item=definition.Item,Enabled=true},definition),OutfittingCatalog.Default);
Check.Equal(definition.Item,EdsyLinkCodec.Import(EdsyLinkCodec.Export(replacement)).Slots.Single(s=>s.Slot==slot.Slot).Module?.Item);
}
[Test] public void NewEngineeringTargetReplacesOldModifiersInExport()
{
var doc=EdsyLinkCodec.Import(Fixtures.Last().GetProperty("hash").GetString()!);
var target=doc.Slots.Single(s=>s.Slot=="PowerPlant");
doc=ShipRefit.SetTarget(doc,target.Slot,new("Overcharged",5,1,"special_powerplant_cooled",0,false,true));
var exported=EdsyLinkCodec.Import(EdsyLinkCodec.Export(doc));
var module=exported.Slots.Single(s=>s.Slot==target.Slot).Module!;
Check.Equal(5,module.Engineering!.Level);Check.That(module.Engineering.Quality>.999);
Check.Equal("PowerPlant_Boosted",module.Engineering.Blueprint);
Check.That(module.Engineering.Modifiers.Count>0);
}
[Test] public void ExplicitNoExperimentalEffectDoesNotReappearAfterEdsyExport()
{
var doc=EdsyLinkCodec.Import(Fixtures.Last().GetProperty("hash").GetString()!);
var slot=doc.Slots.First(s=>s.Module?.Engineering?.ExperimentalEffectId.Length>0);
var engineering=slot.Module!.Engineering!;
var none=ShipRefit.SetTarget(doc,slot.Slot,new(engineering.Blueprint,engineering.Level,engineering.Quality??1,"",0,false,true));
var restored=EdsyLinkCodec.Import(EdsyLinkCodec.Export(none)).Slots.Single(s=>s.Slot==slot.Slot).Module!;
Check.That(restored.Engineering is not null&&restored.Engineering.ExperimentalEffectId.Length==0);
Check.Equal(engineering.Level,restored.Engineering!.Level);
Check.That(doc.Slots.Single(s=>s.Slot==slot.Slot).Module!.Engineering!.ExperimentalEffectId.Length>0);
}
[Test] public void IncompleteCoreConfigurationIsRejectedInsteadOfInventingStockModules()
{
var doc=EdsyLinkCodec.Import(Fixtures[0].GetProperty("hash").GetString()!);
doc=ShipRefit.Install(doc,"PowerPlant",null,OutfittingCatalog.Default);
Check.Throws<FormatException>(()=>EdsyLinkCodec.Export(doc));
}
[Test] public void UnsupportedOrInvalidLinksAreRejected()
{
foreach(var value in new[]{"https://evil.example/#/L=K100000,xxx","https://edsy.org.evil.example/#/L=K100000,xxx","https://edsy.org/#/L=Z123456,,,","garbage","https://edsy.org/#/L=K!!!!,xx","https://edsy.org/#/L=K100000,xxx<script>","https://edsy.org/#/L=Kzzzzzz,,,"})
Check.Throws<FormatException>(()=>EdsyLinkCodec.Import(value));
}
[Test] public void UnknownModuleExportFailsWithoutSilentlyDroppingIt()
{
var doc=EdsyLinkCodec.Import(Fixtures[0].GetProperty("hash").GetString()!);
var slot=doc.Slots.First(s=>s.Module is not null);doc=doc with{Slots=doc.Slots.Select(s=>s==slot?s with{Module=s.Module! with{Item="int_unknown_fake_module"}}:s).ToArray()};
Check.Throws<FormatException>(()=>EdsyLinkCodec.Export(doc));
}
[Test] public void ActualLoadoutPreservesEngineeringScoopAndScoDrive()
{
var doc=JsonSerializer.Deserialize<ShipRefitDocument>(File.ReadAllText(Path.Combine(AppContext.BaseDirectory,"Fixtures","edsy-actual-loadout.json")),ToolboxSettings.JsonOptions)!;
var actualUrl=EdsyLinkCodec.Export(doc);
var imported=EdsyLinkCodec.Import(actualUrl);
foreach(var slot in doc.Slots.Where(s=>s.Module is not null&&s.Category.Length>0&&s.Slot!="PlanetaryApproachSuite"))
{
var before=slot.Module!;var after=imported.Slots.Single(s=>s.Slot==slot.Slot).Module!;
Check.Equal(before.Item,after.Item);Check.Equal(before.Enabled,after.Enabled);Check.Equal(before.Priority,after.Priority);
if(before.Engineering is {} e)
{
Check.Equal(e.Blueprint,after.Engineering!.Blueprint);Check.Equal(e.Level,after.Engineering.Level);
Check.Equal(e.ExperimentalEffectId,after.Engineering.ExperimentalEffectId);
if(e.Quality is {} quality)Check.That(Math.Abs(quality-after.Engineering.Quality!.Value)<.0003);
}
}
Check.That(imported.Slots.Any(s=>s.Module?.Item.Contains("fuelscoop")==true));
Check.That(imported.Slots.Any(s=>s.Module?.Item.Contains("hyperdrive_overcharge")==true));
var modified=ShipRefit.SetTarget(doc,"PowerPlant",new("Overcharged",5,1,"special_powerplant_cooled",0,false,true));
File.WriteAllText(Path.Combine(AppContext.BaseDirectory,"edsy-v8-exports.json"),JsonSerializer.Serialize(new[]{
new{name="actual-loadout",url=actualUrl,expected=(object?)null},
new{name="modified-engineering",url=EdsyLinkCodec.Export(modified),expected=(object?)new{slot="PowerPlant",blueprint="PowerPlant_Boosted",grade=5,effect="special_powerplant_cooled"}}
}));
}
[Test] public void EnglishExperimentalNamesAreResolvedForTheirModuleType()
{
var doc=EdsyLinkCodec.Import(Fixtures.Last().GetProperty("hash").GetString()!);
doc=ShipRefit.SetTarget(doc,"PowerPlant",new("Overcharged",4,.75,"Stripped Down",0,false,true));
var imported=EdsyLinkCodec.Import(EdsyLinkCodec.Export(doc));
Check.Equal("special_powerplant_lightweight",imported.Slots.Single(s=>s.Slot=="PowerPlant").Module!.Engineering!.ExperimentalEffectId);
}
}