using NUnit.Framework; using ProjectM.Simulation; using Unity.Collections; namespace ProjectM.Tests { /// /// Pure-function tests for (no ECS world), mirroring AutoTargetTests. /// Pins the ARPG fold order: effective = (base + sum flat) * (1 + sum percentAdd) * product(1 + percentMult). /// public class StatMathTests { static StatModifier Mod(StatTarget target, ModOp op, float value) => new StatModifier { Target = (byte)target, Op = (byte)op, Value = value }; static float Apply(float baseValue, StatTarget target, params StatModifier[] mods) { using var arr = new NativeArray(mods, Allocator.Temp); return StatMath.Apply(baseValue, target, arr); } [Test] public void Empty_Returns_Base() { using var arr = new NativeArray(0, Allocator.Temp); Assert.AreEqual(10f, StatMath.Apply(10f, StatTarget.Damage, arr), 1e-4f); } [Test] public void Flat_Adds() { Assert.AreEqual(15f, Apply(10f, StatTarget.Damage, Mod(StatTarget.Damage, ModOp.Flat, 5f)), 1e-4f); } [Test] public void Flats_Sum() { Assert.AreEqual(18f, Apply(10f, StatTarget.Damage, Mod(StatTarget.Damage, ModOp.Flat, 5f), Mod(StatTarget.Damage, ModOp.Flat, 3f)), 1e-4f); } [Test] public void PercentAdd_Pools() { // base 10 * (1 + 0.2 + 0.3) = 15 Assert.AreEqual(15f, Apply(10f, StatTarget.Damage, Mod(StatTarget.Damage, ModOp.PercentAdd, 0.2f), Mod(StatTarget.Damage, ModOp.PercentAdd, 0.3f)), 1e-4f); } [Test] public void PercentMult_Multiplies_Separately() { // base 10 * (1+0.5) * (1+0.2) = 18 (note: distinct from a pooled +0.7 = 17) Assert.AreEqual(18f, Apply(10f, StatTarget.Damage, Mod(StatTarget.Damage, ModOp.PercentMult, 0.5f), Mod(StatTarget.Damage, ModOp.PercentMult, 0.2f)), 1e-4f); } [Test] public void Combined_Applies_In_Standard_Order() { // (10 + 5) * (1 + 0.2) * (1 + 0.5) = 27 Assert.AreEqual(27f, Apply(10f, StatTarget.Damage, Mod(StatTarget.Damage, ModOp.Flat, 5f), Mod(StatTarget.Damage, ModOp.PercentAdd, 0.2f), Mod(StatTarget.Damage, ModOp.PercentMult, 0.5f)), 1e-4f); } [Test] public void Other_Targets_Are_Ignored() { // A MoveSpeed modifier must not affect a Damage query. Assert.AreEqual(10f, Apply(10f, StatTarget.Damage, Mod(StatTarget.MoveSpeed, ModOp.Flat, 100f), Mod(StatTarget.MoveSpeed, ModOp.PercentAdd, 5f)), 1e-4f); } [Test] public void Mixed_Targets_Fold_Independently() { var dmg = Mod(StatTarget.Damage, ModOp.Flat, 5f); var spd = Mod(StatTarget.MoveSpeed, ModOp.PercentAdd, 0.5f); Assert.AreEqual(15f, Apply(10f, StatTarget.Damage, dmg, spd), 1e-4f); Assert.AreEqual(9f, Apply(6f, StatTarget.MoveSpeed, dmg, spd), 1e-4f); } } }