Add data-driven dynamic question mode
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using QuestionsApi.Models;
|
||||
using QuestionsApi.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace QuestionsApi.Tests;
|
||||
|
||||
public sealed class DynamicQuestionTests
|
||||
{
|
||||
[Fact]
|
||||
public void Generator_IsDeterministic_AndPreservesCorrectAnswer()
|
||||
{
|
||||
var blueprint = Blueprint();
|
||||
var generator = new DynamicQuestionGenerator();
|
||||
|
||||
var first = generator.Generate(blueprint, "same-seed", "one").Question;
|
||||
var second = generator.Generate(blueprint, "same-seed", "two").Question;
|
||||
|
||||
Assert.Equal(first.Stem, second.Stem);
|
||||
Assert.Equal(first.Choices.Select(value => value.Text), second.Choices.Select(value => value.Text));
|
||||
Assert.Equal("correct", first.CorrectChoiceId);
|
||||
Assert.Null(DynamicQuestionGenerator.Validate(blueprint));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SignedTokens_AreUserBound_AndRejectTampering()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?> { ["DynamicQuestions:SigningKey"] = "unit-test-key" })
|
||||
.Build();
|
||||
var service = new DynamicQuestionTokenService(configuration);
|
||||
var claims = new DynamicGenerationClaims
|
||||
{
|
||||
UserId = "user-one",
|
||||
BlueprintExternalId = "test",
|
||||
BlueprintVersion = 1,
|
||||
ObjectiveId = "objective",
|
||||
Seed = "seed",
|
||||
Nonce = "nonce",
|
||||
GeneratorVersion = 1,
|
||||
ExpiresUtc = DateTime.UtcNow.AddMinutes(5)
|
||||
};
|
||||
|
||||
var token = service.SignGeneration(claims);
|
||||
|
||||
Assert.Equal("seed", service.ReadGeneration(token, "user-one").Seed);
|
||||
Assert.Throws<ArgumentException>(() => service.ReadGeneration(token, "user-two"));
|
||||
Assert.ThrowsAny<Exception>(() => service.ReadGeneration(token + "x", "user-one"));
|
||||
}
|
||||
|
||||
private static DynamicQuestionBlueprint Blueprint() => new()
|
||||
{
|
||||
ExternalId = "test",
|
||||
ObjectiveId = "objective",
|
||||
StemTemplate = "Patient age {{age}}.",
|
||||
LeadIn = "What is correct?",
|
||||
Variables = new()
|
||||
{
|
||||
["age"] = new DynamicVariableDefinition { Minimum = 20, Maximum = 80, Step = 1 }
|
||||
},
|
||||
CorrectAnswer = new DynamicAnswerTemplate { Id = "correct", TextTemplate = "Correct" },
|
||||
Distractors =
|
||||
[
|
||||
new() { Id = "a", TextTemplate = "A" },
|
||||
new() { Id = "b", TextTemplate = "B" },
|
||||
new() { Id = "c", TextTemplate = "C" },
|
||||
new() { Id = "d", TextTemplate = "D" }
|
||||
],
|
||||
References = [new QuestionReference { Title = "Reference", Url = "https://example.test" }]
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user