using QuestionsApi.Models; using QuestionsApi.Services; using Xunit; namespace QuestionsApi.Tests; public sealed class ChoicePoolTests { [Fact] public void LegacyResponseContainsFiveChoicesAndAlwaysIncludesCorrectAnswer() { var question = BuildQuestion(9); for (var iteration = 0; iteration < 50; iteration++) { var response = QuestionResponse.FromModel(question, includeChoicePool: false); Assert.Equal(5, response.Choices.Count); Assert.Equal(5, response.Choices.Select(choice => choice.Id).Distinct().Count()); Assert.Contains(response.Choices, choice => choice.Id == question.CorrectChoiceId); Assert.All(response.ChoiceExplanations.Keys, id => Assert.Contains(response.Choices, choice => choice.Id == id)); Assert.All(response.WrongAnswerFollowups.Keys, id => Assert.Contains(response.Choices, choice => choice.Id == id)); } } [Fact] public void PoolCapableResponseContainsCompletePool() { var question = BuildQuestion(9); var response = QuestionResponse.FromModel(question, includeChoicePool: true); Assert.Equal(9, response.Choices.Count); } [Fact] public void PublishedQuestionRequiresCompletePerChoiceTeachingContent() { var request = BuildRequest(6); Assert.Null(QuestionValidator.Validate(request)); request.WrongAnswerFollowups.Remove("F"); Assert.Contains("every incorrect choice", QuestionValidator.Validate(request)); } [Fact] public void PublishedQuestionRequiresAtLeastFiveUniqueChoices() { var request = BuildRequest(4); Assert.Contains("at least five", QuestionValidator.Validate(request)); request = BuildRequest(5); request.Choices[4].Id = "A"; Assert.Contains("unique", QuestionValidator.Validate(request)); } private static Question BuildQuestion(int count) { var request = BuildRequest(count); return new Question { ExternalId = request.ExternalId, Stem = request.Stem, LeadIn = request.LeadIn, Choices = request.Choices, CorrectChoiceId = request.CorrectChoiceId, Explanation = request.Explanation, ChoiceExplanations = request.ChoiceExplanations, WrongAnswerFollowups = request.WrongAnswerFollowups, ChoiceSelectionPercentages = request.ChoiceSelectionPercentages }; } private static UpsertQuestionRequest BuildRequest(int count) { var ids = Enumerable.Range(0, count).Select(index => ((char)('A' + index)).ToString()).ToList(); var choices = ids.Select(id => new QuestionChoice { Id = id, Text = $"Choice {id}" }).ToList(); return new UpsertQuestionRequest { ExternalId = "choice-pool-test", Stem = "A complete clinical vignette.", LeadIn = "Which option is most appropriate?", Choices = choices, CorrectChoiceId = "A", Explanation = "Explanation", ChoiceExplanations = ids.ToDictionary(id => id, id => id == "A" ? "Correct." : "Incorrect."), WrongAnswerFollowups = ids.Where(id => id != "A").ToDictionary( id => id, id => new WrongAnswerFollowup { Prompt = "Which finding makes this less appropriate?", Choices = [ new QuestionChoice { Id = "A", Text = "Finding one" }, new QuestionChoice { Id = "B", Text = "Finding two" } ], CorrectChoiceId = "A", TeachingPoint = "Teaching point" }), ChoiceSelectionPercentages = ids.ToDictionary(id => id, _ => 0), Discipline = "Medicine", System = "Cardiovascular System", Difficulty = 2, IsPublished = true }; } }