- SetScore (0..points in 0.5 steps, comment shown to the student), ConfirmBulk per quiz or attempt and Regrade through the quiz's grader - close() announces an attempt reviewed while it was open - quizzes_review_set_score, quizzes_review_confirm_bulk, quizzes_review_regrade; 409 already_reviewed and grader_manual
116 lines
4.4 KiB
Go
116 lines
4.4 KiB
Go
package classes_test
|
|
|
|
import (
|
|
"math"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/sm-quizzes-plugin/classes"
|
|
)
|
|
|
|
// TestCheckReviewStatus: "" and open list the three unreviewed statuses,
|
|
// a grading status lists itself, all lists everything (nil), and any
|
|
// other value is a problem naming the valid values.
|
|
func TestCheckReviewStatus(t *testing.T) {
|
|
open := []string{"pending", "graded", "failed"}
|
|
for in, want := range map[string][]string{
|
|
"": open,
|
|
"open": open,
|
|
" open ": open,
|
|
"pending": {"pending"},
|
|
"graded": {"graded"},
|
|
"failed": {"failed"},
|
|
"reviewed": {"reviewed"},
|
|
"all": nil,
|
|
} {
|
|
got, problems := classes.CheckReviewStatus(in)
|
|
if len(problems) != 0 {
|
|
t.Errorf("%q: problems %v", in, problems)
|
|
}
|
|
if !slices.Equal(got, want) || (want == nil) != (got == nil) {
|
|
t.Errorf("%q = %v, want %v", in, got, want)
|
|
}
|
|
}
|
|
for _, in := range []string{"done", "Open", "pending,graded"} {
|
|
got, problems := classes.CheckReviewStatus(in)
|
|
if got != nil || len(problems) != 1 || !strings.Contains(problems[0], "open, pending, graded, failed, reviewed, all") {
|
|
t.Errorf("%q = %v %v, want one problem listing the valid values", in, got, problems)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestCheckReviewPoints: 0..points in steps of 0.5, finite.
|
|
func TestCheckReviewPoints(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
p float64
|
|
max int
|
|
want bool
|
|
}{
|
|
{0, 2, true}, {1.5, 2, true}, {2, 2, true}, {0, 0, true}, {0.5, 1, true},
|
|
{-0.5, 2, false}, {2.5, 2, false}, {1.25, 2, false}, {0.1, 2, false},
|
|
{math.NaN(), 2, false}, {math.Inf(1), 2, false}, {math.Inf(-1), 2, false},
|
|
{0.5, 0, false}, {0, -1, true}, {1, -1, false},
|
|
} {
|
|
if got := classes.CheckReviewPoints(tc.p, tc.max); got != tc.want {
|
|
t.Errorf("CheckReviewPoints(%v, %d) = %v, want %v", tc.p, tc.max, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestCheckReviewComment: trimmed, blank is no comment, NUL dropped,
|
|
// at most 2000 runes.
|
|
func TestCheckReviewComment(t *testing.T) {
|
|
str := func(s string) *string { return &s }
|
|
if got, p := classes.CheckReviewComment(nil); got != nil || p != nil {
|
|
t.Errorf("nil = %v %v", got, p)
|
|
}
|
|
if got, p := classes.CheckReviewComment(str(" \n ")); got != nil || p != nil {
|
|
t.Errorf("spaces = %v %v, want no comment", got, p)
|
|
}
|
|
if got, p := classes.CheckReviewComment(str(" Dobrze, ale\x00 brak przykładu. ")); got == nil || *got != "Dobrze, ale brak przykładu." || p != nil {
|
|
t.Errorf("trimmed = %v %v", got, p)
|
|
}
|
|
max := strings.Repeat("ł", classes.MaxReviewComment)
|
|
if got, p := classes.CheckReviewComment(&max); got == nil || *got != max || p != nil {
|
|
t.Errorf("2000 runes refused: %v", p)
|
|
}
|
|
over := max + "x"
|
|
if got, p := classes.CheckReviewComment(&over); got != nil || len(p) != 1 || p[0] != "comment must be at most 2000 characters" {
|
|
t.Errorf("2001 runes = %v %v, want one problem", got, p)
|
|
}
|
|
}
|
|
|
|
// TestCheckReviewScope: exactly one key; answer_id only for regrade.
|
|
func TestCheckReviewScope(t *testing.T) {
|
|
regrade := "exactly one of answer_id, attempt_id and quiz is required"
|
|
bulk := "exactly one of attempt_id and quiz is required"
|
|
for name, tc := range map[string]struct {
|
|
scope classes.ReviewScope
|
|
allow bool
|
|
want string
|
|
}{
|
|
"regrade answer": {classes.ReviewScope{AnswerID: 1}, true, ""},
|
|
"regrade attempt": {classes.ReviewScope{AttemptID: 1}, true, ""},
|
|
"regrade quiz": {classes.ReviewScope{QuizSlug: "q"}, true, ""},
|
|
"regrade none": {classes.ReviewScope{}, true, regrade},
|
|
"regrade blank quiz": {classes.ReviewScope{QuizSlug: " "}, true, regrade},
|
|
"regrade two": {classes.ReviewScope{AnswerID: 1, QuizSlug: "q"}, true, regrade},
|
|
"regrade three": {classes.ReviewScope{AnswerID: 1, AttemptID: 2, QuizSlug: "q"}, true, regrade},
|
|
"bulk attempt": {classes.ReviewScope{AttemptID: 1}, false, ""},
|
|
"bulk quiz": {classes.ReviewScope{QuizSlug: "q"}, false, ""},
|
|
"bulk none": {classes.ReviewScope{}, false, bulk},
|
|
"bulk two": {classes.ReviewScope{AttemptID: 1, QuizSlug: "q"}, false, bulk},
|
|
"bulk answer": {classes.ReviewScope{AnswerID: 1}, false, bulk},
|
|
"bulk answer and quiz": {classes.ReviewScope{AnswerID: 1, QuizSlug: "q"}, false, bulk},
|
|
} {
|
|
got := classes.CheckReviewScope(tc.scope, tc.allow)
|
|
switch {
|
|
case tc.want == "" && got != nil:
|
|
t.Errorf("%s = %v, want no problem", name, got)
|
|
case tc.want != "" && (len(got) != 1 || got[0] != tc.want):
|
|
t.Errorf("%s = %v, want %q", name, got, tc.want)
|
|
}
|
|
}
|
|
}
|