- graders registry collected at boot from every HasGraders plugin, manual first; a duplicate or reserved code fails boot - grading job on queue quizzes_grading with three attempts; a stale or reviewed answer is never touched; the last failure marks it failed - learning answers enqueue at once, tests at close; a grade recalculates a finished attempt and fires AnswerGradedEvent after commit
80 lines
2.5 KiB
Go
80 lines
2.5 KiB
Go
package graders_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/sm-quizzes-plugin/graders"
|
|
)
|
|
|
|
type fake struct{ code, label string }
|
|
|
|
func (f fake) Code() string { return f.code }
|
|
func (f fake) Label() string { return f.label }
|
|
func (f fake) Grade(context.Context, graders.Input) (graders.Result, error) {
|
|
return graders.Result{}, nil
|
|
}
|
|
|
|
func TestGradersRegistry(t *testing.T) {
|
|
reg := graders.NewRegistry()
|
|
if got := reg.Codes(); !slices.Equal(got, []string{graders.Manual}) {
|
|
t.Fatalf("empty Codes = %v, want [manual]", got)
|
|
}
|
|
if err := reg.Add("acme.one", fake{"x", "X grader"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := reg.Codes(); !slices.Equal(got, []string{graders.Manual, "x"}) {
|
|
t.Errorf("Codes = %v, want [manual x]", got)
|
|
}
|
|
if g, ok := reg.Get("x"); !ok || g.Code() != "x" {
|
|
t.Errorf("Get(x) = %v, %v", g, ok)
|
|
}
|
|
for _, code := range []string{graders.Manual, "zzz", ""} {
|
|
if _, ok := reg.Get(code); ok {
|
|
t.Errorf("Get(%q) = true, want false", code)
|
|
}
|
|
}
|
|
if id, ok := reg.PluginID("x"); !ok || id != "acme.one" {
|
|
t.Errorf("PluginID(x) = %q, %v", id, ok)
|
|
}
|
|
|
|
err := reg.Add("acme.two", fake{"x", "Other"})
|
|
if !errors.Is(err, graders.ErrDuplicateCode) || !strings.Contains(err.Error(), "acme.one") || !strings.Contains(err.Error(), "acme.two") {
|
|
t.Errorf("duplicate Add = %v, want ErrDuplicateCode naming both plugins", err)
|
|
}
|
|
if err := reg.Add("acme.two", fake{graders.Manual, "M"}); !errors.Is(err, graders.ErrReservedCode) {
|
|
t.Errorf("manual Add = %v, want ErrReservedCode", err)
|
|
}
|
|
for _, g := range []graders.Grader{nil, fake{"", "E"}, fake{"Bad Code", "B"}, fake{"9lives", "N"}, fake{strings.Repeat("a", 65), "L"}} {
|
|
if err := reg.Add("acme.two", g); err == nil {
|
|
t.Errorf("Add(%v) = nil, want an error", g)
|
|
}
|
|
}
|
|
if got := reg.Codes(); !slices.Equal(got, []string{graders.Manual, "x"}) {
|
|
t.Errorf("rejected Adds changed Codes: %v", got)
|
|
}
|
|
|
|
opts := reg.Options()
|
|
want := []graders.Option{{Code: graders.Manual, Label: graders.ManualLabel}, {Code: "x", Label: "X grader"}}
|
|
if !slices.Equal(opts, want) {
|
|
t.Errorf("Options = %v, want %v", opts, want)
|
|
}
|
|
|
|
var none *graders.Registry
|
|
if got := none.Codes(); !slices.Equal(got, []string{graders.Manual}) {
|
|
t.Errorf("nil Codes = %v", got)
|
|
}
|
|
if _, ok := none.Get("x"); ok {
|
|
t.Error("nil Get = true")
|
|
}
|
|
if got := none.Options(); len(got) != 1 || got[0].Code != graders.Manual {
|
|
t.Errorf("nil Options = %v", got)
|
|
}
|
|
if err := none.Add("acme.one", fake{"y", "Y"}); err == nil {
|
|
t.Error("nil Add = nil, want an error")
|
|
}
|
|
}
|