best times only improve; achievement unlock announces on the transition only, so popup/Steam subscribers cannot double-fire; statistics are increase-only (IncrementStat took any int). RelockAchievement is console-only and documented as not reaching Steam - a Steam achievement cannot be un-earned, so the disagreement is permanent and deliberate. refactor: extract EventLog, composed by both aggregates now that the duplication actually exists. 34 tests.
75 lines
2.7 KiB
C#
75 lines
2.7 KiB
C#
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<AchievementUnlocked>());
|
|
}
|
|
|
|
[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<ArgumentOutOfRangeException>(() => profile.Record(StatName.Deaths, -1));
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => 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<AchievementUnlocked>());
|
|
}
|
|
}
|