using Outnumbered.Domain; using Xunit; namespace Outnumbered.Tests; // ProgressionModel: XP curve + prestige boost. Expected XP values are INDEPENDENT literals (computed offline from the // documented formula), so these catch an implementation typo, not just lock current output. public class ProgressionModelTests { // XpToNext = LevelXpBase + round(LevelXpStep * (max(0,L-1))^LevelXpExponent); defaults Base=100, Step=8, Exp=1.7. [Theory] [InlineData(1, 100)] // (L-1)=0 -> 0 -> just the base [InlineData(2, 108)] [InlineData(3, 126)] [InlineData(5, 184)] [InlineData(10, 435)] [InlineData(25, 1876)] [InlineData(50, 6076)] [InlineData(100, 19855)] public void XpToNext_matches_curve(int level, long expected) => Assert.Equal(expected, ProgressionModel.XpToNext(level, T.Prog())); [Theory] [InlineData(0)] [InlineData(-5)] public void XpToNext_floors_negative_level_at_base(int level) => Assert.Equal(100L, ProgressionModel.XpToNext(level, T.Prog())); // Math.Max(0, L-1) guards the Pow base [Fact] public void XpToNext_is_strictly_increasing_above_level_one() { var c = T.Prog(); long prev = ProgressionModel.XpToNext(1, c); for (int l = 2; l <= c.LevelCap; l++) { long cur = ProgressionModel.XpToNext(l, c); Assert.True(cur > prev, $"XpToNext({l})={cur} should exceed XpToNext({l - 1})={prev}"); prev = cur; } } // PrestigeXpMultiplier = 1 + prestige * (PrestigeXpBoostPercent/100); default 10% per prestige. [Theory] [InlineData(0, 1.00)] [InlineData(1, 1.10)] [InlineData(5, 1.50)] [InlineData(10, 2.00)] public void PrestigeXpMultiplier_matches(int prestige, double expected) => T.Close(expected, ProgressionModel.PrestigeXpMultiplier(prestige, T.Prog())); [Fact] public void Retune_pinned_prestige_boost_is_ten_percent() => Assert.Equal(10, T.Prog().PrestigeXpBoostPercent); // pins the balance-retune knob }