package classes_test import ( "os" "strings" "testing" "git.golem15.com/jakub/sm-bm-plugin/classes" ) func parse(t *testing.T, doc string) *classes.SeedFile { t.Helper() f, err := classes.ParseSeed(strings.NewReader(doc)) if err != nil { t.Fatalf("ParseSeed: %v", err) } return f } func TestExampleFixtureIsValid(t *testing.T) { fh, err := os.Open("../testdata/seed.example.json") if err != nil { t.Fatal(err) } defer fh.Close() f, err := classes.ParseSeed(fh) if err != nil { t.Fatal(err) } if err := f.Validate(); err != nil { t.Fatalf("Validate: %v", err) } if len(f.Meetings) != 2 || len(f.Courses) != 3 || len(f.ClassSessions) != 3 || len(f.Deadlines) != 2 || len(f.Readings) != 2 { t.Errorf("fixture counts = %d %d %d %d %d", len(f.Meetings), len(f.Courses), len(f.ClassSessions), len(f.Deadlines), len(f.Readings)) } if f.Courses[2].ElectiveGroup == nil || *f.Courses[2].ElectiveGroup != "przyklad-do-wyboru" { t.Errorf("elective_group = %v", f.Courses[2].ElectiveGroup) } } func TestEmptyDocumentIsValid(t *testing.T) { if err := parse(t, `{}`).Validate(); err != nil { t.Errorf("{}: %v", err) } } func TestParseRejectsUnknownFieldsAndTrailingData(t *testing.T) { for _, doc := range []string{ `{"courses": [{"key": "a", "nmae": "typo"}]}`, `{"lectures": []}`, `{} {}`, `[]`, `{"meetings": [{"number": "one"}]}`, } { if _, err := classes.ParseSeed(strings.NewReader(doc)); err == nil { t.Errorf("ParseSeed(%s) accepted", doc) } } } func TestValidateNamesTheRecord(t *testing.T) { cases := []struct { doc string want []string }{ {`{"class_sessions": [{"course": "ghost", "starts_at": "2030-10-05T08:00:00+02:00", "ends_at": "2030-10-05T09:00:00+02:00"}]}`, []string{`class_sessions[0]`, `unknown course key "ghost"`}}, {`{"courses": [{"key": "a", "name": "A", "form": "wyklad", "semester": 1}], "class_sessions": [{"course": "a", "meeting": 9, "starts_at": "2030-10-05T08:00:00+02:00", "ends_at": "2030-10-05T09:00:00+02:00"}]}`, []string{`unknown meeting number 9`}}, {`{"deadlines": [{"title": "X", "due_at": "2030-10-05T08:00:00+02:00", "course": "nope", "kind": "inne"}]}`, []string{`deadlines[0] ("X")`, `unknown course key "nope"`}}, {`{"readings": [{"course": "nope", "title": "Book"}]}`, []string{`readings[0]`, `unknown course key "nope"`}}, {`{"courses": [{"key": "a", "name": "A", "form": "lecture", "semester": 7}]}`, []string{`form "lecture"`, `semester must be between 1 and 4`}}, {`{"courses": [{"key": "a", "name": "A", "form": "wyklad", "semester": 1}, {"key": "a", "name": "A", "form": "wyklad", "semester": 1}]}`, []string{`duplicate course key`, `same name, form and semester`}}, {`{"meetings": [{"number": 1, "starts_on": "2030-10-06", "ends_on": "2030-10-05"}, {"number": 1, "starts_on": "05.10.2030", "ends_on": "2030-10-05"}]}`, []string{`ends_on is before starts_on`, `duplicate meeting number`, `starts_on`}}, {`{"courses": [{"key": "a", "name": "A", "form": "wyklad", "semester": 1}], "class_sessions": [{"course": "a", "starts_at": "2030-10-05 10:00", "ends_at": "2030-10-05 09:00"}]}`, []string{`ends_at is not after starts_at`}}, {`{"deadlines": [{"title": "", "due_at": "soon", "kind": "deadline"}]}`, []string{`title is required`, `due_at`, `kind "deadline"`}}, } for _, tc := range cases { err := parse(t, tc.doc).Validate() if err == nil { t.Errorf("Validate(%s) passed", tc.doc) continue } for _, want := range tc.want { if !strings.Contains(err.Error(), want) { t.Errorf("Validate(%s) = %q, want it to mention %q", tc.doc, err, want) } } } } func TestSeedValidatesBeforeTouchingTheDatabase(t *testing.T) { f := parse(t, `{"readings": [{"course": "ghost", "title": "Book"}]}`) // A nil database would panic if Seed reached it. if _, err := classes.Seed(t.Context(), nil, f); err == nil || !strings.Contains(err.Error(), "ghost") { t.Errorf("Seed = %v, want the unknown course error", err) } } func TestSummaryRows(t *testing.T) { var s classes.SeedSummary s.Courses.Created = 2 s.Readings.Unchanged = 1 rows := s.Rows() if len(rows) != 5 || rows[1][0] != "courses" || rows[1][1] != "2" || rows[4][3] != "1" || len(rows[0]) != 5 { t.Errorf("Rows = %v", rows) } }