Scenarios, tests, AetherDb templates and name-keyed maps now resolve designs by the generic names (231 literals in 30 files); TargetingCatalog's product texts lose the authoring note, Steadfast carries its r3 text, DragOnBreath plight's old design text. Not built yet; tests that depend on the generic-designs command and new tests follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
93 lines
5.1 KiB
C#
93 lines
5.1 KiB
C#
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<HullData>().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<HullData>().Where(h => h.Name == HullName).ToArray();
|
|
var keys = hulls.Select(h => db.Cache.RefOf(h).Key).ToArray();
|
|
var products = db.Cache.GetAll<FactionProductData>().Count(p => keys.Any(k => p.Design.Key.Equals(k)));
|
|
var fitted = new[] { "Charged Scatter Blaster", "Autocannon" }
|
|
.Select(name => db.Cache.GetAll<EquippableItemData>().Single(d => d.Name == name)).ToArray();
|
|
return (hulls, db.Cache.GetAll<HullData>().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);
|
|
}
|
|
}
|