using System; using System.IO; using System.Linq; using GameCult.Caching; using GameCult.Caching.MessagePack; using Xunit; // AetherDb's smoke-hull command (aetheria-release, cut scenarios-smoke), run on a scratch copy of the shipped catalog // with the Smoke Test Hull removed from it. public sealed class SmokeHullCommandTests : IDisposable { private const string HullName = "Smoke Test Hull"; private readonly string _root = Path.Combine(Path.GetTempPath(), "smoke-hull-command-" + Guid.NewGuid().ToString("N")); private string CatalogPath => Path.Combine(_root, "GameData", "Aetheria.cc"); public SmokeHullCommandTests() { Directory.CreateDirectory(Path.Combine(_root, "GameData")); Directory.CreateDirectory(Path.Combine(_root, "Assets", "Resources")); var shipped = AetherDb.FindRoot(); File.Copy(Path.Combine(shipped, "GameData", "Aetheria.cc"), CatalogPath); File.Copy(Path.Combine(shipped, "Assets", "Resources", "Settings.asset"), Path.Combine(_root, "Assets", "Resources", "Settings.asset")); using var cache = new CultCache(TestCatalog.Registry()); cache.AddBackingStore(new SingleFileMessagePackBackingStore(CatalogPath), AetheriaStores.CatalogTypes); foreach (var hull in cache.GetAll().Where(h => h.Name == HullName).ToArray()) Assert.True(cache.Remove(cache.RefOf(hull).Key)); cache.FlushAsync().Wait(); } public void Dispose() => Directory.Delete(_root, true); private (HullData[] Hulls, HullData Longinus, EquippableItemData[] Fitted, int Products) Read() { var db = AetherDb.Open(root: _root); try { var hulls = db.Cache.GetAll().Where(h => h.Name == HullName).ToArray(); var keys = hulls.Select(h => db.Cache.RefOf(h).Key).ToArray(); var products = db.Cache.GetAll().Count(p => keys.Any(k => p.Design.Key.Equals(k))); var fitted = new[] { "Charged Scatter Blaster", "Autocannon" } .Select(name => db.Cache.GetAll().Single(d => d.Name == name)).ToArray(); return (hulls, db.Cache.GetAll().Single(h => h.Name == "Longinus"), fitted, products); } finally { db.Cache.Dispose(); } } [Fact] public void A_dry_run_writes_nothing_and_apply_lands_one_productless_hull_once() { var before = File.ReadAllBytes(CatalogPath); Assert.Empty(Read().Hulls); Assert.Equal(0, Program.SmokeHullCatalog(apply: false, root: _root)); Assert.Equal(before, File.ReadAllBytes(CatalogPath)); Assert.Empty(Read().Hulls); Assert.Equal(0, Program.SmokeHullCatalog(apply: true, root: _root)); var landed = File.ReadAllBytes(CatalogPath); Assert.NotEqual(before, landed); var (hulls, longinus, fitted, products) = Read(); var hull = Assert.Single(hulls); Assert.Equal(0, products); // The Longinus's own hardpoints survive (moved over by the margin the flank blocks need), and four are added: each takes // the gear the scenarios fit to it. Assert.Equal(longinus.Hardpoints.Count + 4, hull.Hardpoints.Count); var added = hull.Hardpoints.Skip(longinus.Hardpoints.Count).ToArray(); var (chargeBlast, autocannon) = (fitted[0], fitted[1]); Assert.Equal(longinus.Hardpoints.Select(h => (h.Type, h.Position.x + 2, h.Position.y, h.Rotation)), hull.Hardpoints.Take(longinus.Hardpoints.Count).Select(h => (h.Type, h.Position.x, h.Position.y, h.Rotation))); Assert.Single(added, h => h.Type == HardpointType.Energy && h.Rotation == ItemRotation.None && h.Takes(chargeBlast)); Assert.Single(added, h => h.Type == HardpointType.Ballistic && h.Rotation == ItemRotation.None && h.Takes(autocannon)); Assert.Single(added, h => h.Type == HardpointType.Ballistic && h.Rotation == ItemRotation.Clockwise && h.Takes(autocannon)); Assert.Single(added, h => h.Type == HardpointType.Energy && h.Rotation == ItemRotation.CounterClockwise && h.Takes(chargeBlast)); // Each is a full 2x2 block with the default firing arc (0 uses the game setting; the side mounts bear by it, never wider) // and the Longinus-class armour the command writes. Assert.All(added, hardpoint => { Assert.Equal((2, 2, 0f, 20f), (hardpoint.Shape.Width, hardpoint.Shape.Height, hardpoint.FiringArc, hardpoint.Armor)); Assert.Equal(4, hardpoint.Shape.Coordinates.Length); }); foreach (var hardpoint in added) foreach (var cell in hardpoint.Shape.Coordinates) Assert.True(hull.Shape[hardpoint.Position + cell], "a new hardpoint lies outside the hull's cells"); // A second apply finds the hull authored and writes nothing; so does a dry run. Assert.Equal(0, Program.SmokeHullCatalog(apply: true, root: _root)); Assert.Equal(landed, File.ReadAllBytes(CatalogPath)); Assert.Equal(0, Program.SmokeHullCatalog(apply: false, root: _root)); Assert.Equal(landed, File.ReadAllBytes(CatalogPath)); Assert.Single(Read().Hulls); } }