feat: add open questions with a pending grading state
- migration: open question type, rubric, max_length, quiz grader and the grading and review columns of attempt answers - open answers are checked, stored as pending and never scored on answer; a changed text resets the grading state - student JSON gains text, grading_status, grader_feedback, review_comment, max_length, needs_review and open_answers; the rubric is never serialized
This commit is contained in:
59
classes/open_test.go
Normal file
59
classes/open_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package classes_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.golem15.com/golem15/sm-quizzes-plugin/classes"
|
||||
"git.golem15.com/golem15/sm-quizzes-plugin/models"
|
||||
)
|
||||
|
||||
func TestCheckOpenText(t *testing.T) {
|
||||
q := models.Question{Type: models.TypeOpen}
|
||||
long := 3000
|
||||
wide := models.Question{Type: models.TypeOpen, MaxLength: &long}
|
||||
|
||||
fieldKey := func(err error) string {
|
||||
var fe *classes.FieldError
|
||||
if errors.As(err, &fe) && fe.Field == "text" {
|
||||
return fe.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
if _, err := classes.CheckOpenText(" \n\t ", q); fieldKey(err) != "text_required" {
|
||||
t.Errorf("blank text: err = %v, want text_required", err)
|
||||
}
|
||||
if _, err := classes.CheckOpenText("\x00 \x00", q); fieldKey(err) != "text_required" {
|
||||
t.Errorf("NUL-only text: err = %v, want text_required", err)
|
||||
}
|
||||
over := strings.Repeat("a", 2001)
|
||||
if _, err := classes.CheckOpenText(over, q); fieldKey(err) != "text_too_long" {
|
||||
t.Errorf("2001 runes with default max: err = %v, want text_too_long", err)
|
||||
}
|
||||
if got, err := classes.CheckOpenText(over, wide); err != nil || got != over {
|
||||
t.Errorf("2001 runes with max 3000: %q, %v", got[:10], err)
|
||||
}
|
||||
if got, err := classes.CheckOpenText("a\x00b", q); err != nil || got != "ab" {
|
||||
t.Errorf("NUL stripped: %q, %v; want ab", got, err)
|
||||
}
|
||||
if got, err := classes.CheckOpenText(" moja odpowiedź \n", q); err != nil || got != "moja odpowiedź" {
|
||||
t.Errorf("trimmed: %q, %v", got, err)
|
||||
}
|
||||
polish := strings.Repeat("ż", 2000)
|
||||
if got, err := classes.CheckOpenText(polish, q); err != nil || got != polish {
|
||||
t.Errorf("2000 runes of ż (4000 bytes) refused: %v", err)
|
||||
}
|
||||
five := 5
|
||||
if _, err := classes.CheckOpenText("abcdef", models.Question{MaxLength: &five}); fieldKey(err) != "text_too_long" {
|
||||
t.Errorf("6 runes with max 5: err = %v, want text_too_long", err)
|
||||
}
|
||||
if classes.MaxLength(q) != models.DefaultMaxLength || classes.MaxLength(wide) != 3000 {
|
||||
t.Errorf("MaxLength = %d / %d", classes.MaxLength(q), classes.MaxLength(wide))
|
||||
}
|
||||
zero := 0
|
||||
if classes.MaxLength(models.Question{MaxLength: &zero}) != models.DefaultMaxLength {
|
||||
t.Error("MaxLength of a non-positive value should fall back to the default")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user