diff --git a/GameData/Aetheria.cc b/GameData/Aetheria.cc index 9f9ff69e5..a2ddaad5d 100644 --- a/GameData/Aetheria.cc +++ b/GameData/Aetheria.cc @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:22342ea360c7f453de500da8650e6a23648f8c1250eb22e724765bbcf619eac0 -size 186037 +oid sha256:c327ef1bbabbd34ddb7b9f643f5db8cc54aa5730f232bd42a1fa5f2b03973e89 +size 189753 diff --git a/tests/Aetheria.Shared.Tests/LoadoutTests.cs b/tests/Aetheria.Shared.Tests/LoadoutTests.cs index 5673b205d..86bf4e698 100644 --- a/tests/Aetheria.Shared.Tests/LoadoutTests.cs +++ b/tests/Aetheria.Shared.Tests/LoadoutTests.cs @@ -622,6 +622,13 @@ public sealed class LoadoutTests : IDisposable var result = items.GetTier((CraftedItemInstance) items.CreateInstance(lot)); Assert.Equal(settings.Tiers[0].Name, result.tier.Name); Assert.Equal(2, result.upgrades); + + // The same width from the other side (follow-up tier-upgrade-step-two-sided): two steps less a hair is one upgrade, so a + // step narrower than .0499 reads two and a wider one reads none. + var under = items.Lots.Add(new Lot { Design = cache.RefOf(lamp), Origin = new Attributed(), Quality = settings.Tiers[0].Quality + 2 * .0499f - .0001f, Roles = new List() }); + var below = items.GetTier((CraftedItemInstance) items.CreateInstance(under)); + Assert.Equal(settings.Tiers[0].Name, below.tier.Name); + Assert.Equal(1, below.upgrades); } // S7 (docs/stats-and-power-cut.md Cut 1 findings): a Quality term must raise the lot's quality to its own diff --git a/tests/Aetheria.Shared.Tests/ProductLinesCatalogTests.cs b/tests/Aetheria.Shared.Tests/ProductLinesCatalogTests.cs index 6a91bb457..7ce78218f 100644 --- a/tests/Aetheria.Shared.Tests/ProductLinesCatalogTests.cs +++ b/tests/Aetheria.Shared.Tests/ProductLinesCatalogTests.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; using System.Linq; using GameCult.Caching; +using GameCult.Caching.MessagePack; +using MessagePack; using Xunit; // The weapon product lines the shipped catalog holds (campaign aetheria-release, cut product-lines-weapons; rulings @@ -99,4 +101,61 @@ public sealed class ProductLinesCatalogTests } } } + // Cut product-tiers: the six bins of the command's tier table are in the catalog, each a single product that names its line. + [Fact] + public void TierRowsAreShipped() + { + using var cache = RestoredHullsTests.OpenCatalog(); + var table = ProductLinesCommand.TierTable(); + Assert.Equal(6, table.Count); + foreach (var row in table) + { + var bin = Assert.Single(cache.GetAll(), p => p.Name == row.Name); + var line = Assert.Single(cache.GetAll(), p => p.Name == row.Line); + Assert.Equal(cache.RefOf(line).Key, bin.Bin.Line.Key); + Assert.Equal(line.Design.Key, bin.Design.Key); + Assert.Equal(line.Manufacturer.Key, bin.Manufacturer.Key); + Assert.Equal(row.Floor, bin.Bin.Floor); + Assert.Equal(row.Description, bin.Description); + Assert.Empty(bin.Roles); + Assert.Null(bin.Assembly); + } + } + + // A bin bins an unbinned line of its own design and maker, and the catalog holds no bin the table does not author. + [Fact] + public void BinsBinAnUnbinnedLineOfTheirOwnDesignAndMaker() + { + using var cache = RestoredHullsTests.OpenCatalog(); + var bins = cache.GetAll().Where(p => p.Bin != null).ToArray(); + Assert.Equal(ProductLinesCommand.TierTable().Select(r => r.Name).OrderBy(n => n, StringComparer.Ordinal), bins.Select(b => b.Name).OrderBy(n => n, StringComparer.Ordinal)); + foreach (var bin in bins) + { + var line = cache.Get(bin.Bin.Line); + Assert.NotNull(line); + Assert.Null(line.Bin); + Assert.Equal(line.Design.Key, bin.Design.Key); + Assert.Equal(line.Manufacturer.Key, bin.Manufacturer.Key); + Assert.True(bin.Bin.Floor >= 0 && float.IsFinite(bin.Bin.Floor)); + } + } + + // FactionProductData slot 7 is additive under the same schema id: a bin round-trips, and a record written before the slot + // existed (an array one element shorter) reads no bin. + [Fact] + public void BinIsSlotSevenAndACatalogWithoutItReadsNoBin() + { + var options = CultDocumentMessagePackSerialization.OptionsFor(typeof(FactionProductData).Assembly); + var binned = MessagePackSerializer.Deserialize( + MessagePackSerializer.Serialize(new FactionProductData { Name = "Binned", Bin = new ProductBin { Floor = .67f } }, options), options); + Assert.Equal(.67f, binned.Bin.Floor); + + var bytes = MessagePackSerializer.Serialize(new FactionProductData { Name = "Old", Description = "d" }, options); + Assert.Equal(0x98, bytes[0]); + Assert.Equal(0xC0, bytes[^1]); + var before = new byte[] { 0x97 }.Concat(bytes.Skip(1).Take(bytes.Length - 2)).ToArray(); + var old = MessagePackSerializer.Deserialize(before, options); + Assert.Equal("Old", old.Name); + Assert.Null(old.Bin); + } }