Initial commit: standalone quiz-testing system
Full-stack F# (Domain/Server/Client via Fable+Elmish+Feliz), PostgreSQL persistence via Dapper, Docker Compose deployment. Student quiz-taking flow with time-limit enforcement and focus-loss tracking, Teacher question bank and quiz builder with results analytics, Admin user management.
This commit is contained in:
98
tests/Domain.Tests/ValidationTests.fs
Normal file
98
tests/Domain.Tests/ValidationTests.fs
Normal file
@@ -0,0 +1,98 @@
|
||||
module Domain.Tests.ValidationTests
|
||||
|
||||
open System
|
||||
open Xunit
|
||||
open Domain
|
||||
|
||||
let private newQuestion (qType: QuestionType) : Question =
|
||||
{ Id = QuestionId(Guid.NewGuid())
|
||||
TopicId = TopicId(Guid.NewGuid())
|
||||
Text = "Sample?"
|
||||
Points = 1.0
|
||||
Type = qType }
|
||||
|
||||
[<Fact>]
|
||||
let ``single choice: correct option must be among the listed options`` () =
|
||||
let optA = { Id = OptionId(Guid.NewGuid()); Text = "A" }
|
||||
let optB = { Id = OptionId(Guid.NewGuid()); Text = "B" }
|
||||
let foreignId = OptionId(Guid.NewGuid())
|
||||
let question = newQuestion (SingleChoice([ optA; optB ], foreignId))
|
||||
|
||||
match QuestionValidation.validate question with
|
||||
| Error errors -> Assert.Contains("Correct option must be one of the provided options", errors)
|
||||
| Ok _ -> Assert.Fail "expected validation error"
|
||||
|
||||
[<Fact>]
|
||||
let ``multiple choice: correct set must be subset of options`` () =
|
||||
let optA = { Id = OptionId(Guid.NewGuid()); Text = "A" }
|
||||
let optB = { Id = OptionId(Guid.NewGuid()); Text = "B" }
|
||||
let foreignId = OptionId(Guid.NewGuid())
|
||||
let question = newQuestion (MultipleChoice([ optA; optB ], Set.ofList [ optA.Id; foreignId ]))
|
||||
|
||||
match QuestionValidation.validate question with
|
||||
| Error errors -> Assert.Contains("Correct options must be a subset of the provided options", errors)
|
||||
| Ok _ -> Assert.Fail "expected validation error"
|
||||
|
||||
[<Fact>]
|
||||
let ``numeric: negative tolerance is invalid`` () =
|
||||
let question = newQuestion (Numeric(1.0, -0.5))
|
||||
|
||||
match QuestionValidation.validate question with
|
||||
| Error errors -> Assert.Contains("Tolerance must not be negative", errors)
|
||||
| Ok _ -> Assert.Fail "expected validation error"
|
||||
|
||||
[<Fact>]
|
||||
let ``valid question passes validation`` () =
|
||||
let optA = { Id = OptionId(Guid.NewGuid()); Text = "A" }
|
||||
let optB = { Id = OptionId(Guid.NewGuid()); Text = "B" }
|
||||
let question = newQuestion (SingleChoice([ optA; optB ], optA.Id))
|
||||
|
||||
match QuestionValidation.validate question with
|
||||
| Ok _ -> ()
|
||||
| Error errors -> Assert.Fail(String.concat "; " errors)
|
||||
|
||||
[<Fact>]
|
||||
let ``quiz: must contain at least one question`` () =
|
||||
let quiz: Quiz =
|
||||
{ Id = QuizId(Guid.NewGuid())
|
||||
OwnerId = UserId(Guid.NewGuid())
|
||||
Title = "Empty quiz"
|
||||
Description = ""
|
||||
TimeLimit = None
|
||||
MaxAttempts = None
|
||||
GradingMethod = HighestAttempt
|
||||
ShuffleQuestions = false
|
||||
ShuffleAnswers = false
|
||||
OpenFrom = None
|
||||
OpenTo = None
|
||||
PassingScore = None
|
||||
QuestionSources = []
|
||||
AssignedStudentIds = Set.empty }
|
||||
|
||||
match QuizValidation.validate quiz with
|
||||
| Error errors -> Assert.Contains("Quiz must contain at least one question", errors)
|
||||
| Ok _ -> Assert.Fail "expected validation error"
|
||||
|
||||
[<Fact>]
|
||||
let ``quiz: OpenFrom must precede OpenTo`` () =
|
||||
let now = DateTimeOffset.UtcNow
|
||||
|
||||
let quiz: Quiz =
|
||||
{ Id = QuizId(Guid.NewGuid())
|
||||
OwnerId = UserId(Guid.NewGuid())
|
||||
Title = "Backwards window"
|
||||
Description = ""
|
||||
TimeLimit = None
|
||||
MaxAttempts = None
|
||||
GradingMethod = HighestAttempt
|
||||
ShuffleQuestions = false
|
||||
ShuffleAnswers = false
|
||||
OpenFrom = Some(now.AddDays 1.0)
|
||||
OpenTo = Some now
|
||||
PassingScore = None
|
||||
QuestionSources = [ FixedQuestion { QuestionId = QuestionId(Guid.NewGuid()); Points = 1.0; Order = 0 } ]
|
||||
AssignedStudentIds = Set.empty }
|
||||
|
||||
match QuizValidation.validate quiz with
|
||||
| Error errors -> Assert.Contains("OpenFrom must be before OpenTo", errors)
|
||||
| Ok _ -> Assert.Fail "expected validation error"
|
||||
Reference in New Issue
Block a user