using System.Security.Cryptography;
using System.Text.Json;
using System.Xml.Linq;
using XFEEDToolBox.Core.Navigation;
using XFEEDToolBox.Core.Presentation;
using XFEEDToolBox.Core.Rendering;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]
public class GameUiIconsTests
{
private static SystemLocation Place(int nativeKind, SystemLocationCategory category, string name = "Fixture")
=> new(1, 2, name, "", nativeKind, category, null, null, 10000, false, "same-location");
private static string AssetsDirectory()
{
foreach (var start in new[] { Environment.CurrentDirectory, AppContext.BaseDirectory })
for (var directory = new DirectoryInfo(start); directory is not null; directory = directory.Parent)
{
var assets = Path.Combine(directory.FullName, "XFEEDToolBox", "Assets", "GameIcons");
if (File.Exists(Path.Combine(assets, "source.json"))) return assets;
}
throw new InvalidOperationException("Original game icon asset manifest not found.");
}
[Test]
public void EveryGameIconHasAnUnmodifiedSourceAndPackagedAsset()
{
var directory = AssetsDirectory();
using var manifest = JsonDocument.Parse(File.ReadAllText(Path.Combine(directory, "source.json")));
var root = manifest.RootElement;
Check.That(root.GetProperty("originalsUnchanged").GetBoolean());
Check.That(!root.GetProperty("gameProcessAccess").GetBoolean());
var icons = root.GetProperty("icons").EnumerateArray().ToArray();
var keys = icons.Select(x => x.GetProperty("key").GetString()).ToHashSet();
Check.That(keys.SetEquals(Enum.GetNames<GameUiIcon>()), "The shared catalogue and packaged source manifest differ.");
Check.Equal(51, icons.Count(x => x.GetProperty("spriteId").GetInt32() == 84));
Check.Equal("TitanCloud", root.GetProperty("omittedFrames")[0].GetProperty("key").GetString());
foreach (var icon in icons.Concat(root.GetProperty("rasterIcons").EnumerateArray()))
{
var file = Path.Combine(directory, icon.GetProperty("file").GetString()!);
Check.Equal(icon.GetProperty("sha256").GetString(), Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(file))));
Check.That(root.GetProperty("sources").TryGetProperty(icon.GetProperty("resource").GetString()!, out _));
if (Path.GetExtension(file) != ".svg") continue;
var svg = XDocument.Load(file);
Check.That(svg.Descendants().Any(x => x.Name.LocalName == "path"));
Check.That(!svg.Descendants().Any(x => x.Name.LocalName is "text" or "image"), "An original vector depends on fonts or unresolved bitmaps.");
Check.That(!svg.Descendants().Attributes().Any(x => x.Name.LocalName.Contains("bitmap", StringComparison.OrdinalIgnoreCase)),
"A Scaleform external bitmap was exported as a solid-colour placeholder.");
}
Check.Equal(2, root.GetProperty("rasterIcons").GetArrayLength());
}
[Test]
public void NativeCatalogueKindsAreNotScaleformTimelineIndices()
{
Check.Equal(GameUiIcon.FleetCarrier, GameUiIcons.ForLocation(Place(14, SystemLocationCategory.Carrier)));
Check.Equal(GameUiIcon.SquadronCarrier, GameUiIcons.ForLocation(Place(15, SystemLocationCategory.Other)));
Check.Equal(GameUiIcon.NavBeacon, GameUiIcons.ForLocation(Place(23, SystemLocationCategory.Signal)));
Check.Equal(GameUiIcon.NavBeacon, GameUiIcons.ForLocation(Place(0, SystemLocationCategory.PointOfInterest, "$MULTIPLAYER_SCENARIO42_TITLE;")));
Check.Equal(GameUiIcon.POIGeneric, GameUiIcons.ForLocation(Place(22, SystemLocationCategory.Signal)));
Check.Equal(GameUiIcon.Megaship, GameUiIcons.ForLocation(Place(11, SystemLocationCategory.Carrier)));
Check.Equal(GameUiIcon.Planet, GameUiIcons.ForLocation(Place(3, SystemLocationCategory.Planet)));
Check.Equal(GameUiIcon.LandablePlanet, GameUiIcons.ForLocation(Place(2, SystemLocationCategory.LandablePlanet)));
Check.Equal(GameUiIcon.Belt, GameUiIcons.ForLocation(Place(19, SystemLocationCategory.Asteroid)));
}
[Test]
public void ALocationTypeChangeUpdatesOnlyItsIconBinding()
{
var original = Place(22, SystemLocationCategory.Signal);
var row = new SystemLocationLiveRow(original);
var properties = new List<string>();
row.PropertyChanged += (_, change) => properties.Add(change.PropertyName!);
Check.That(row.Update(original with { NativeKind = 23 }));
Check.That(properties.SequenceEqual(new[] { "IconKey" }));
Check.Equal(GameUiIcon.NavBeacon, row.IconKey);
properties.Clear();
Check.That(!row.Update(row.Record with { DistanceMetres = 10000.01, Position = new(1, 2, 3) }));
Check.Equal(0, properties.Count);
}
}
using System.Security.Cryptography;
using System.Text.Json;
using System.Xml.Linq;
using XFEEDToolBox.Core.Navigation;
using XFEEDToolBox.Core.Presentation;
using XFEEDToolBox.Core.Rendering;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]
public class GameUiIconsTests
{
private static SystemLocation Place(int nativeKind, SystemLocationCategory category, string name = "Fixture")
=> new(1, 2, name, "", nativeKind, category, null, null, 10000, false, "same-location");
private static string AssetsDirectory()
{
foreach (var start in new[] { Environment.CurrentDirectory, AppContext.BaseDirectory })
for (var directory = new DirectoryInfo(start); directory is not null; directory = directory.Parent)
{
var assets = Path.Combine(directory.FullName, "XFEEDToolBox", "Assets", "GameIcons");
if (File.Exists(Path.Combine(assets, "source.json"))) return assets;
}
throw new InvalidOperationException("Original game icon asset manifest not found.");
}
[Test]
public void EveryGameIconHasAnUnmodifiedSourceAndPackagedAsset()
{
var directory = AssetsDirectory();
using var manifest = JsonDocument.Parse(File.ReadAllText(Path.Combine(directory, "source.json")));
var root = manifest.RootElement;
Check.That(root.GetProperty("originalsUnchanged").GetBoolean());
Check.That(!root.GetProperty("gameProcessAccess").GetBoolean());
var icons = root.GetProperty("icons").EnumerateArray().ToArray();
var keys = icons.Select(x => x.GetProperty("key").GetString()).ToHashSet();
Check.That(keys.SetEquals(Enum.GetNames<GameUiIcon>()), "The shared catalogue and packaged source manifest differ.");
Check.Equal(51, icons.Count(x => x.GetProperty("spriteId").GetInt32() == 84));
Check.Equal("TitanCloud", root.GetProperty("omittedFrames")[0].GetProperty("key").GetString());
foreach (var icon in icons.Concat(root.GetProperty("rasterIcons").EnumerateArray()))
{
var file = Path.Combine(directory, icon.GetProperty("file").GetString()!);
Check.Equal(icon.GetProperty("sha256").GetString(), Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(file))));
Check.That(root.GetProperty("sources").TryGetProperty(icon.GetProperty("resource").GetString()!, out _));
if (Path.GetExtension(file) != ".svg") continue;
var svg = XDocument.Load(file);
Check.That(svg.Descendants().Any(x => x.Name.LocalName == "path"));
Check.That(!svg.Descendants().Any(x => x.Name.LocalName is "text" or "image"), "An original vector depends on fonts or unresolved bitmaps.");
Check.That(!svg.Descendants().Attributes().Any(x => x.Name.LocalName.Contains("bitmap", StringComparison.OrdinalIgnoreCase)),
"A Scaleform external bitmap was exported as a solid-colour placeholder.");
}
Check.Equal(2, root.GetProperty("rasterIcons").GetArrayLength());
}
[Test]
public void NativeCatalogueKindsAreNotScaleformTimelineIndices()
{
Check.Equal(GameUiIcon.FleetCarrier, GameUiIcons.ForLocation(Place(14, SystemLocationCategory.Carrier)));
Check.Equal(GameUiIcon.SquadronCarrier, GameUiIcons.ForLocation(Place(15, SystemLocationCategory.Other)));
Check.Equal(GameUiIcon.NavBeacon, GameUiIcons.ForLocation(Place(23, SystemLocationCategory.Signal)));
Check.Equal(GameUiIcon.NavBeacon, GameUiIcons.ForLocation(Place(0, SystemLocationCategory.PointOfInterest, "$MULTIPLAYER_SCENARIO42_TITLE;")));
Check.Equal(GameUiIcon.POIGeneric, GameUiIcons.ForLocation(Place(22, SystemLocationCategory.Signal)));
Check.Equal(GameUiIcon.Megaship, GameUiIcons.ForLocation(Place(11, SystemLocationCategory.Carrier)));
Check.Equal(GameUiIcon.Planet, GameUiIcons.ForLocation(Place(3, SystemLocationCategory.Planet)));
Check.Equal(GameUiIcon.LandablePlanet, GameUiIcons.ForLocation(Place(2, SystemLocationCategory.LandablePlanet)));
Check.Equal(GameUiIcon.Belt, GameUiIcons.ForLocation(Place(19, SystemLocationCategory.Asteroid)));
}
[Test]
public void ALocationTypeChangeUpdatesOnlyItsIconBinding()
{
var original = Place(22, SystemLocationCategory.Signal);
var row = new SystemLocationLiveRow(original);
var properties = new List<string>();
row.PropertyChanged += (_, change) => properties.Add(change.PropertyName!);
Check.That(row.Update(original with { NativeKind = 23 }));
Check.That(properties.SequenceEqual(new[] { "IconKey" }));
Check.Equal(GameUiIcon.NavBeacon, row.IconKey);
properties.Clear();
Check.That(!row.Update(row.Record with { DistanceMetres = 10000.01, Position = new(1, 2, 3) }));
Check.Equal(0, properties.Count);
}
}