namespace Mr.BrickAdventures.Progression.Tests; public class ProfileTests { private static readonly LevelId Level = LevelId.Of("village_1"); [Fact] public void A_slower_run_does_not_replace_a_better_time() { var profile = Profile.Empty(); Assert.True(profile.RecordTime(Level, LevelTime.Of(42.5))); Assert.False(profile.RecordTime(Level, LevelTime.Of(51.0))); Assert.Equal(LevelTime.Of(42.5), profile.BestTimeFor(Level)); } [Fact] public void Unlocking_the_same_achievement_twice_announces_it_once() { // AchievementManager shows a popup and pushes to Steam on every unlock call, guarded only by // a Contains check on a list it reached into. Announcing only on the transition means // subscribers cannot double-fire regardless of how often they are told. var rescueTen = AchievementId.Of("rescue_ten_kids"); var profile = Profile.Empty(); profile.UnlockAchievement(rescueTen); profile.UnlockAchievement(rescueTen); Assert.True(profile.HasAchievement(rescueTen)); Assert.Single(profile.DrainEvents().OfType()); } [Fact] public void Statistics_accumulate_and_an_unrecorded_one_reads_as_zero() { var profile = Profile.Empty(); profile.Record(StatName.CoinsCollected, 5); profile.Record(StatName.CoinsCollected, 3); Assert.Equal(8, profile.ReadStat(StatName.CoinsCollected)); Assert.Equal(0, profile.ReadStat(StatName.Deaths)); } [Fact] public void A_statistic_cannot_be_decremented() { // IncrementStat currently takes any int. A lifetime counter that can go down is not a // lifetime counter, and nothing in the game has a reason to reduce one. var profile = Profile.Empty(); Assert.Throws(() => profile.Record(StatName.Deaths, -1)); Assert.Throws(() => profile.Record(StatName.Deaths, 0)); } [Fact] public void Relocking_an_achievement_removes_it_and_lets_it_announce_again() { // Console-only. Note the asymmetry: unlocking is mirrored to Steam by a subscriber, but // relocking cannot be, because a Steam achievement cannot be un-earned. var rescueTen = AchievementId.Of("rescue_ten_kids"); var profile = Profile.Empty(); profile.UnlockAchievement(rescueTen); profile.DrainEvents(); profile.RelockAchievement(rescueTen); Assert.False(profile.HasAchievement(rescueTen)); profile.UnlockAchievement(rescueTen); Assert.Single(profile.DrainEvents().OfType()); } }