Files
step3/api/QuestionsApi.Tests/DailyMissionPolicyTests.cs
T
2026-08-01 04:02:24 -05:00

79 lines
3.5 KiB
C#

using QuestionsApi.Models;
using QuestionsApi.Services;
using Xunit;
namespace QuestionsApi.Tests;
public sealed class DailyMissionPolicyTests
{
private static readonly DateTime Now = new(2026, 8, 1, 12, 0, 0, DateTimeKind.Utc);
[Fact]
public void DueReviewsArePrioritizedAndCappedAtTen()
{
var candidates = DailyMissionStore.BuildCandidates(Dashboard(17), Questions(), Now);
Assert.Equal(DailyMissionTypes.DueReviews, candidates[0].Type);
Assert.Equal(10, candidates[0].Target);
}
[Fact]
public void NoReviewsFallsBackToCoverageGaps()
{
var candidates = DailyMissionStore.BuildCandidates(Dashboard(0), Questions(), Now);
Assert.DoesNotContain(candidates, value => value.Type == DailyMissionTypes.DueReviews);
Assert.True(candidates.Count >= 3);
Assert.Contains(candidates.Take(3), value => value.Type == DailyMissionTypes.DifficultyFourCorrect);
Assert.All(candidates.Where(value => value.Type == DailyMissionTypes.WeakSystemCorrect),
value => Assert.Equal(3, value.Target));
}
[Fact]
public void HardMissionRequiresThreeEligiblePublishedQuestions()
{
var questions = Questions();
questions.RemoveAll(value => value.Step3System == Step3SystemCatalog.All[1] && value.Difficulty >= 4);
var candidates = DailyMissionStore.BuildCandidates(Dashboard(0), questions, Now);
Assert.DoesNotContain(candidates, value => value.Type == DailyMissionTypes.DifficultyFourCorrect
&& value.Step3System == Step3SystemCatalog.All[1]);
}
[Fact]
public void QuestionProgressRequiresCorrectEligibleActivityAfterMissionStart()
{
var system = Step3SystemCatalog.All[0];
var mission = new DailyMission
{
Type = DailyMissionTypes.DifficultyFourCorrect, Step3System = system, StartsUtc = Now
};
var question = new Question { Step3System = system, Difficulty = 4 };
Assert.True(DailyMissionStore.QualifiesQuestion(mission,
new QuestionAttempt { IsCorrect = true, CreatedUtc = Now }, question));
Assert.False(DailyMissionStore.QualifiesQuestion(mission,
new QuestionAttempt { IsCorrect = false, CreatedUtc = Now }, question));
Assert.False(DailyMissionStore.QualifiesQuestion(mission,
new QuestionAttempt { IsCorrect = true, IsSkip = true, CreatedUtc = Now }, question));
Assert.False(DailyMissionStore.QualifiesQuestion(mission,
new QuestionAttempt { IsCorrect = true, CreatedUtc = Now.AddSeconds(-1) }, question));
question.Difficulty = 3;
Assert.False(DailyMissionStore.QualifiesQuestion(mission,
new QuestionAttempt { IsCorrect = true, CreatedUtc = Now }, question));
}
private static DashboardResponse Dashboard(int pending) => new()
{
MissedQuestionCount = pending,
Systems = Step3SystemCatalog.All.Take(4).Select((system, index) => new DashboardSystemPerformance
{
System = system, MasteryState = index == 0 ? MasteryStates.Unseen : MasteryStates.Learning,
MasteryScore = index * 10, DistinctQuestions = index, Difficulty4PlusSuccessful = index
}).ToList()
};
private static List<Question> Questions() => Step3SystemCatalog.All.Take(4)
.SelectMany(system => Enumerable.Range(0, 6).Select(index => new Question
{
ExternalId = $"{system}-{index}", Step3System = system, Difficulty = index < 3 ? 4 : 2,
IsPublished = true
})).ToList();
}