using System.Text.RegularExpressions;
using XFEExtension.NetCore.XUnit.Attributes;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Planning;
namespace XFEEDToolBox.Test;
[TestFixture]
public class StationAndShipPolicyTests
{
[Test]public void ExecutionRechecksTheLiveHullAndRejectsUnknownOrSmallerPads()
{
Check.Throws<InvalidOperationException>(()=>ShipPadPolicy.RequireFits(Check.Station(1) with{MaxLandingPad=LandingPad.Medium},"PantherMkII",LandingPad.Small));
Check.Throws<InvalidOperationException>(()=>ShipPadPolicy.RequireFits(Check.Station(1) with{MaxLandingPad=LandingPad.Unknown},"Type9"));
Check.Throws<InvalidOperationException>(()=>ShipPadPolicy.RequireFits(Check.Station(1),"Unknown future ship"));
ShipPadPolicy.RequireFits(Check.Station(1) with{IsFleetCarrier=true,MaxLandingPad=LandingPad.Unknown},"Type9");
}
[Test] public void ShipPadsMatchEveryHullInTheBundledEdsySource()
{
using var stream = typeof(ShipPadPolicy).Assembly.GetManifestResourceStream("XFEEDToolBox.Core.Outfitting.Edsy.eddb.js")!;
using var reader = new StreamReader(stream);
var source = reader.ReadToEnd();
var hulls = Regex.Matches(source,
"""^\t\t\s*\d+\s*:\s*\{\s*fdid:[^\r\n]*fdname:'(?<type>[^']+)'[^\r\n]*\r?\n\s*id:\d+, stype:'[^']+', name:'(?<name>[^']+)', class:(?<pad>\d+)""",
RegexOptions.Multiline);
Check.That(hulls.Count >= 49, "The independent pinned EDSY hull catalogue must be read in full.");
foreach (Match hull in hulls)
{
var expected = int.Parse(hull.Groups["pad"].Value) switch
{
1 => LandingPad.Small, 2 => LandingPad.Medium, 3 => LandingPad.Large,
_ => throw new InvalidOperationException("An unrecognized EDSY hull class needs review.")
};
Check.Equal(expected, ShipPadPolicy.RequiredPad(hull.Groups["type"].Value));
Check.Equal(expected, ShipPadPolicy.RequiredPad(hull.Groups["name"].Value));
}
}
[Test] public void ActualLargeHullCannotBeReducedByManualSmallPreference()
{
// PantherMkII is the Journal fdname, rather than the display name.
Check.Equal(LandingPad.Large, ShipPadPolicy.RequiredPad("panthermkii"));
Check.Equal(LandingPad.Large, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Small, LandingPad.Unknown, "PantherMkII"));
Check.Equal(LandingPad.Large, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Small, LandingPad.Small, "type9"));
Check.Equal(LandingPad.Large, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Large, LandingPad.Small, "sidewinder"));
Check.Equal(LandingPad.Large, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Small, LandingPad.Large, "python"));
}
[Test] public void UnknownHullNeverBecomesAnAssumedSmallShip()
{
foreach (var type in new string?[] { null, "", " ", "new-unverified-hull", "PantherMkIII", "Unknown" })
Check.Equal(LandingPad.Unknown, ShipPadPolicy.RequiredPad(type));
Check.Equal(LandingPad.Unknown, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Unknown, LandingPad.Unknown, "new-unverified-hull"));
}
[Test] public void JournalAndPublicCatalogStationTypesRemainDistinct()
{
(StationSourceKinds Kind, string[] Types)[] cases =
[
(StationSourceKinds.Starport, ["Coriolis", "Orbis", "Ocellus", "Bernal", "Dodec", "Ocellus Starport"]),
(StationSourceKinds.Outpost, ["Outpost", "OutpostScientific", "Scientific Outpost"]),
(StationSourceKinds.PlanetaryPort, ["CraterOutpost", "CraterPort", "Planetary Port", "Planetary Outpost", "DockablePlanetStation"]),
(StationSourceKinds.Settlement, ["OnFootSettlement", "SurfaceStation", "Odyssey Settlement", "Planetary Settlement"]),
(StationSourceKinds.FleetCarrier, ["FleetCarrier", "Fleet Carrier", "SquadronCarrier", "StrongholdCarrier"]),
(StationSourceKinds.AsteroidBase, ["AsteroidBase", "Asteroid base"]),
(StationSourceKinds.Megaship, ["MegaShip", "MegaShipCivilian", "Mega ship", "RescueMegaship"]),
(StationSourceKinds.Other, ["PlanetaryConstructionDepot", "SpaceConstructionDepot", "ShipDepot", "GameplayPOI", "FutureStationType"]),
(StationSourceKinds.Unknown, ["", " ", "None", "Unknown"])
];
foreach (var item in cases)
foreach (var type in item.Types)
Check.Equal(item.Kind, StationSourcePolicy.Classify(new() { Type = type }));
}
[Test] public void SourceTypeFiltersSupportMultipleKindsWithoutTreatingUnknownAsKnown()
{
var selected = StationSourceKinds.Starport | StationSourceKinds.FleetCarrier;
Check.That(StationSourcePolicy.Allows(new() { Type = "Coriolis" }, selected));
Check.That(StationSourcePolicy.Allows(new() { Type = "FleetCarrier" }, selected));
Check.That(!StationSourcePolicy.Allows(new() { Type = "Outpost" }, selected));
Check.That(!StationSourcePolicy.Allows(new() { Type = "Coriolis" }, StationSourceKinds.None));
Check.That(!StationSourcePolicy.Allows(new(), StationSourceKinds.AllKnown));
Check.That(StationSourcePolicy.Allows(new(), StationSourceKinds.All));
Check.That(StationSourcePolicy.Allows(new() { Type = "FutureStationType" }, StationSourceKinds.Other));
}
[Test] public void CarrierIdentityProvidesLargePadsButOtherTypesDoNotInventPadMetadata()
{
Check.Equal(LandingPad.Large, StationSourcePolicy.EffectiveMaxLandingPad(new() { Type = "FleetCarrier" }));
Check.Equal(LandingPad.Large, StationSourcePolicy.EffectiveMaxLandingPad(new() { IsFleetCarrier = true }));
Check.Equal(StationSourceKinds.FleetCarrier, StationSourcePolicy.Classify(new() { Type = "CraterPort", IsFleetCarrier = true }));
foreach (var type in new[] { "ShipDepot", "SpaceConstructionDepot", "SurfaceStation", "MegaShip", "FutureStationType", "" })
Check.Equal(LandingPad.Unknown, StationSourcePolicy.EffectiveMaxLandingPad(new() { Type = type }));
Check.Equal(LandingPad.Medium, StationSourcePolicy.EffectiveMaxLandingPad(new() { Type = "MegaShip", MaxLandingPad = LandingPad.Medium }));
}
[Test] public void PlanetaryLocationFlagDoesNotInventASettlementSubtype()
{
Check.Equal(StationSourceKinds.Unknown, StationSourcePolicy.Classify(new() { IsPlanetary = true }));
Check.Equal(StationSourceKinds.PlanetaryPort, StationSourcePolicy.Classify(new() { Type = "Starport", IsPlanetary = true }));
Check.Equal(StationSourceKinds.Settlement, StationSourcePolicy.Classify(new() { Type = "SurfaceStation", IsPlanetary = true }));
Check.Equal(StationSourceKinds.Other, StationSourcePolicy.Classify(new() { Type = "FutureStationType", IsPlanetary = true }));
}
}
using System.Text.RegularExpressions;
using XFEExtension.NetCore.XUnit.Attributes;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Planning;
namespace XFEEDToolBox.Test;
[TestFixture]
public class StationAndShipPolicyTests
{
[Test]public void ExecutionRechecksTheLiveHullAndRejectsUnknownOrSmallerPads()
{
Check.Throws<InvalidOperationException>(()=>ShipPadPolicy.RequireFits(Check.Station(1) with{MaxLandingPad=LandingPad.Medium},"PantherMkII",LandingPad.Small));
Check.Throws<InvalidOperationException>(()=>ShipPadPolicy.RequireFits(Check.Station(1) with{MaxLandingPad=LandingPad.Unknown},"Type9"));
Check.Throws<InvalidOperationException>(()=>ShipPadPolicy.RequireFits(Check.Station(1),"Unknown future ship"));
ShipPadPolicy.RequireFits(Check.Station(1) with{IsFleetCarrier=true,MaxLandingPad=LandingPad.Unknown},"Type9");
}
[Test] public void ShipPadsMatchEveryHullInTheBundledEdsySource()
{
using var stream = typeof(ShipPadPolicy).Assembly.GetManifestResourceStream("XFEEDToolBox.Core.Outfitting.Edsy.eddb.js")!;
using var reader = new StreamReader(stream);
var source = reader.ReadToEnd();
var hulls = Regex.Matches(source,
"""^\t\t\s*\d+\s*:\s*\{\s*fdid:[^\r\n]*fdname:'(?<type>[^']+)'[^\r\n]*\r?\n\s*id:\d+, stype:'[^']+', name:'(?<name>[^']+)', class:(?<pad>\d+)""",
RegexOptions.Multiline);
Check.That(hulls.Count >= 49, "The independent pinned EDSY hull catalogue must be read in full.");
foreach (Match hull in hulls)
{
var expected = int.Parse(hull.Groups["pad"].Value) switch
{
1 => LandingPad.Small, 2 => LandingPad.Medium, 3 => LandingPad.Large,
_ => throw new InvalidOperationException("An unrecognized EDSY hull class needs review.")
};
Check.Equal(expected, ShipPadPolicy.RequiredPad(hull.Groups["type"].Value));
Check.Equal(expected, ShipPadPolicy.RequiredPad(hull.Groups["name"].Value));
}
}
[Test] public void ActualLargeHullCannotBeReducedByManualSmallPreference()
{
// PantherMkII is the Journal fdname, rather than the display name.
Check.Equal(LandingPad.Large, ShipPadPolicy.RequiredPad("panthermkii"));
Check.Equal(LandingPad.Large, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Small, LandingPad.Unknown, "PantherMkII"));
Check.Equal(LandingPad.Large, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Small, LandingPad.Small, "type9"));
Check.Equal(LandingPad.Large, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Large, LandingPad.Small, "sidewinder"));
Check.Equal(LandingPad.Large, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Small, LandingPad.Large, "python"));
}
[Test] public void UnknownHullNeverBecomesAnAssumedSmallShip()
{
foreach (var type in new string?[] { null, "", " ", "new-unverified-hull", "PantherMkIII", "Unknown" })
Check.Equal(LandingPad.Unknown, ShipPadPolicy.RequiredPad(type));
Check.Equal(LandingPad.Unknown, ShipPadPolicy.EffectiveRequiredPad(LandingPad.Unknown, LandingPad.Unknown, "new-unverified-hull"));
}
[Test] public void JournalAndPublicCatalogStationTypesRemainDistinct()
{
(StationSourceKinds Kind, string[] Types)[] cases =
[
(StationSourceKinds.Starport, ["Coriolis", "Orbis", "Ocellus", "Bernal", "Dodec", "Ocellus Starport"]),
(StationSourceKinds.Outpost, ["Outpost", "OutpostScientific", "Scientific Outpost"]),
(StationSourceKinds.PlanetaryPort, ["CraterOutpost", "CraterPort", "Planetary Port", "Planetary Outpost", "DockablePlanetStation"]),
(StationSourceKinds.Settlement, ["OnFootSettlement", "SurfaceStation", "Odyssey Settlement", "Planetary Settlement"]),
(StationSourceKinds.FleetCarrier, ["FleetCarrier", "Fleet Carrier", "SquadronCarrier", "StrongholdCarrier"]),
(StationSourceKinds.AsteroidBase, ["AsteroidBase", "Asteroid base"]),
(StationSourceKinds.Megaship, ["MegaShip", "MegaShipCivilian", "Mega ship", "RescueMegaship"]),
(StationSourceKinds.Other, ["PlanetaryConstructionDepot", "SpaceConstructionDepot", "ShipDepot", "GameplayPOI", "FutureStationType"]),
(StationSourceKinds.Unknown, ["", " ", "None", "Unknown"])
];
foreach (var item in cases)
foreach (var type in item.Types)
Check.Equal(item.Kind, StationSourcePolicy.Classify(new() { Type = type }));
}
[Test] public void SourceTypeFiltersSupportMultipleKindsWithoutTreatingUnknownAsKnown()
{
var selected = StationSourceKinds.Starport | StationSourceKinds.FleetCarrier;
Check.That(StationSourcePolicy.Allows(new() { Type = "Coriolis" }, selected));
Check.That(StationSourcePolicy.Allows(new() { Type = "FleetCarrier" }, selected));
Check.That(!StationSourcePolicy.Allows(new() { Type = "Outpost" }, selected));
Check.That(!StationSourcePolicy.Allows(new() { Type = "Coriolis" }, StationSourceKinds.None));
Check.That(!StationSourcePolicy.Allows(new(), StationSourceKinds.AllKnown));
Check.That(StationSourcePolicy.Allows(new(), StationSourceKinds.All));
Check.That(StationSourcePolicy.Allows(new() { Type = "FutureStationType" }, StationSourceKinds.Other));
}
[Test] public void CarrierIdentityProvidesLargePadsButOtherTypesDoNotInventPadMetadata()
{
Check.Equal(LandingPad.Large, StationSourcePolicy.EffectiveMaxLandingPad(new() { Type = "FleetCarrier" }));
Check.Equal(LandingPad.Large, StationSourcePolicy.EffectiveMaxLandingPad(new() { IsFleetCarrier = true }));
Check.Equal(StationSourceKinds.FleetCarrier, StationSourcePolicy.Classify(new() { Type = "CraterPort", IsFleetCarrier = true }));
foreach (var type in new[] { "ShipDepot", "SpaceConstructionDepot", "SurfaceStation", "MegaShip", "FutureStationType", "" })
Check.Equal(LandingPad.Unknown, StationSourcePolicy.EffectiveMaxLandingPad(new() { Type = type }));
Check.Equal(LandingPad.Medium, StationSourcePolicy.EffectiveMaxLandingPad(new() { Type = "MegaShip", MaxLandingPad = LandingPad.Medium }));
}
[Test] public void PlanetaryLocationFlagDoesNotInventASettlementSubtype()
{
Check.Equal(StationSourceKinds.Unknown, StationSourcePolicy.Classify(new() { IsPlanetary = true }));
Check.Equal(StationSourceKinds.PlanetaryPort, StationSourcePolicy.Classify(new() { Type = "Starport", IsPlanetary = true }));
Check.Equal(StationSourceKinds.Settlement, StationSourcePolicy.Classify(new() { Type = "SurfaceStation", IsPlanetary = true }));
Check.Equal(StationSourceKinds.Other, StationSourcePolicy.Classify(new() { Type = "FutureStationType", IsPlanetary = true }));
}
}