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) } } }