TestCreate exam almost completed

This commit is contained in:
andrea 2023-11-28 16:19:49 +01:00
parent 489226d5f5
commit 10620eae13
14 changed files with 228 additions and 22 deletions

View file

@ -1,23 +1,37 @@
package models package models
import ( import (
"time" "encoding/json"
"fmt"
"gorm.io/gorm"
) )
type Exam struct { type Exam struct {
ID string `gorm:"primaryKey"` Meta
Participant *Participant
CreatedAt time.Time Quizzes []*Quiz
UpdatedAt time.Time }
DeletedAt gorm.DeletedAt `gorm:"index"`
func (e *Exam) String() string {
Name string return fmt.Sprintf("Exam ID %v with %v quizzes.", e.ID, len(e.Quizzes))
Description string }
Collection *Collection `gorm:"foreignKey:ID"` func (e *Exam) GetID() string {
Participant []*Participant `gorm:"many2many:exam_participants"` return e.ID
}
// Responses []string
func (e *Exam) SetID(id string) {
e.ID = id
}
func (e *Exam) GetHash() string {
return ""
}
func (e *Exam) Marshal() ([]byte, error) {
return json.Marshal(e)
}
func (e *Exam) Unmarshal(data []byte) error {
return json.Unmarshal(data, e)
} }

5
store/exam.go Normal file
View file

@ -0,0 +1,5 @@
package store
import "git.andreafazzi.eu/andrea/probo/models"
type ExamStore = Store[*models.Exam]

View file

@ -8,6 +8,7 @@ var (
DefaultCollectionsSubdir = "collections" DefaultCollectionsSubdir = "collections"
DefaultParticipantsSubdir = "participants" DefaultParticipantsSubdir = "participants"
DefaultGroupsSubdir = "groups" DefaultGroupsSubdir = "groups"
DefaultExamsSubdir = "exams"
) )
func GetDefaultQuizzesDir() string { func GetDefaultQuizzesDir() string {
@ -25,3 +26,7 @@ func GetDefaultParticipantsDir() string {
func GetDefaultGroupsDir() string { func GetDefaultGroupsDir() string {
return filepath.Join(DefaultBaseDir, DefaultGroupsSubdir) return filepath.Join(DefaultBaseDir, DefaultGroupsSubdir)
} }
func GetDefaultExamsDir() string {
return filepath.Join(DefaultBaseDir, DefaultExamsSubdir)
}

28
store/file/exam.go Normal file
View file

@ -0,0 +1,28 @@
package file
import (
"git.andreafazzi.eu/andrea/probo/models"
"git.andreafazzi.eu/andrea/probo/store"
)
type ExamFileStore = FileStore[*models.Exam, *store.Store[*models.Exam]]
func NewExamFileStore(config *FileStoreConfig[*models.Exam, *store.ExamStore]) (*ExamFileStore, error) {
return NewFileStore[*models.Exam](config, store.NewStore[*models.Exam]())
}
func NewDefaultExamFileStore() (*ExamFileStore, error) {
return NewExamFileStore(
&FileStoreConfig[*models.Exam, *store.ExamStore]{
FilePathConfig: FilePathConfig{GetDefaultExamsDir(), "exam", ".json"},
IndexDirFunc: DefaultIndexDirFunc[*models.Exam, *store.ExamStore],
CreateEntityFunc: func() *models.Exam {
return &models.Exam{
Participant: &models.Participant{},
Quizzes: make([]*models.Quiz, 0),
}
},
},
)
}

111
store/file/exam_test.go Normal file
View file

@ -0,0 +1,111 @@
package file
import (
"encoding/json"
"fmt"
"io"
"os"
"git.andreafazzi.eu/andrea/probo/models"
"git.andreafazzi.eu/andrea/probo/store"
"github.com/remogatto/prettytest"
)
type examTestSuite struct {
prettytest.Suite
}
func (t *examTestSuite) TestCreate() {
participantStore, err := NewParticipantFileStore(
&FileStoreConfig[*models.Participant, *store.ParticipantStore]{
FilePathConfig: FilePathConfig{"testdata/exams/participants", "participant", ".json"},
IndexDirFunc: DefaultIndexDirFunc[*models.Participant, *store.ParticipantStore],
CreateEntityFunc: func() *models.Participant {
return &models.Participant{
Attributes: make(map[string]string),
}
},
},
)
t.Nil(err)
quizStore, err := NewQuizFileStore(
&FileStoreConfig[*models.Quiz, *store.QuizStore]{
FilePathConfig: FilePathConfig{"testdata/exams/quizzes", "quiz", ".md"},
IndexDirFunc: DefaultQuizIndexDirFunc,
},
)
t.Nil(err)
if !t.Failed() {
t.Equal(3, len(participantStore.ReadAll()))
examStore, err := NewDefaultExamFileStore()
t.Nil(err)
if !t.Failed() {
g := new(models.Group)
c := new(models.Collection)
participants := participantStore.Storer.FilterInGroup(g, &models.ParticipantFilter{
Attributes: map[string]string{"class": "1 D LIN"},
})
quizzes := quizStore.Storer.FilterInCollection(c, &models.Filter{
Tags: []*models.Tag{
{Name: "#tag1"},
},
})
for _, p := range participants {
e := new(models.Exam)
e.Participant = p
e.Quizzes = quizzes
_, err = examStore.Create(e)
t.Nil(err)
defer os.Remove(examStore.GetPath(e))
examFromDisk, err := readExamFromJSON(e.GetID())
t.Nil(err)
if !t.Failed() {
t.Not(t.Nil(examFromDisk.Participant))
if !t.Failed() {
t.Equal("Smith", examFromDisk.Participant.Lastname)
t.Equal(2, len(examFromDisk.Quizzes))
}
}
}
}
}
}
func readExamFromJSON(examID string) (*models.Exam, error) {
// Build the path to the JSON file
jsonPath := fmt.Sprintf("testdata/exams/exam_%s.json", examID)
// Open the JSON file
file, err := os.Open(jsonPath)
if err != nil {
return nil, fmt.Errorf("failed to open JSON file: %w", err)
}
defer file.Close()
// Read the JSON data from the file
jsonData, err := io.ReadAll(file)
if err != nil {
return nil, fmt.Errorf("failed to read JSON data: %w", err)
}
// Unmarshal the JSON data into an Exam object
var exam models.Exam
if err := json.Unmarshal(jsonData, &exam); err != nil {
return nil, fmt.Errorf("failed to parse JSON data: %w", err)
}
return &exam, nil
}

View file

@ -86,7 +86,7 @@ func DefaultIndexDirFunc[T FileStorable, K Storer[T]](s *FileStore[T, K]) error
return err return err
} }
mEntity, err := s.Create(entity) mEntity, err := s.Create(entity, fullPath)
if err != nil { if err != nil {
return err return err
} }
@ -116,20 +116,22 @@ func NewFileStore[T FileStorable, K Storer[T]](config *FileStoreConfig[T, K], st
return store, nil return store, nil
} }
func (s *FileStore[T, K]) Create(entity T) (T, error) { func (s *FileStore[T, K]) Create(entity T, path ...string) (T, error) {
e, err := s.Storer.Create(entity) e, err := s.Storer.Create(entity)
if err != nil { if err != nil {
return e, err return e, err
} }
filePath := filepath.Join(s.Dir, fmt.Sprintf("%s_%v%s", s.FilePrefix, e.GetID(), s.FileSuffix))
data, err := e.Marshal() data, err := e.Marshal()
if err != nil { if err != nil {
return e, err return e, err
} }
file, err := os.Create(filePath) if len(path) == 0 {
path = append(path, filepath.Join(s.Dir, fmt.Sprintf("%s_%v%s", s.FilePrefix, e.GetID(), s.FileSuffix)))
}
file, err := os.Create(path[0])
if err != nil { if err != nil {
return e, err return e, err
} }
@ -141,7 +143,7 @@ func (s *FileStore[T, K]) Create(entity T) (T, error) {
return e, err return e, err
} }
s.SetPath(e, filePath) s.SetPath(e, path[0])
return e, nil return e, nil
} }

View file

@ -17,5 +17,6 @@ func TestRunner(t *testing.T) {
new(collectionTestSuite), new(collectionTestSuite),
new(participantTestSuite), new(participantTestSuite),
new(groupTestSuite), new(groupTestSuite),
new(examTestSuite),
) )
} }

View file

@ -0,0 +1 @@
{"id":"fe0a7ee0-f31a-413d-ba81-ab5068bc4c73","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","Participant":{"ID":"1234","Firstname":"John","Lastname":"Smith","Token":111222,"Attributes":{"class":"1 D LIN"}},"Quizzes":[{"id":"0610939b-a1a3-4d0e-bbc4-2aae0e8ee4b9","created_at":"2023-11-27T17:51:53.910642221+01:00","updated_at":"0001-01-01T00:00:00Z","hash":"","question":{"id":"98c0eec9-677f-464e-9e3e-864a859f29a3","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","text":"Question text with #tag1."},"answers":[{"id":"1ab5ff1f-74c8-4efc-abdc-d03a3640f3bc","text":"Answer 1"},{"id":"74547724-b905-476f-8cfc-6ee633f92ef3","text":"Answer 2"},{"id":"96c1a8ee-c50c-4ebc-89e4-9f3ca356adbd","text":"Answer 3"},{"id":"16c4b95e-64ce-4666-8cbe-b66fa59eb23b","text":"Answer 4"}],"tags":[{"CreatedAt":"0001-01-01T00:00:00Z","UpdatedAt":"0001-01-01T00:00:00Z","DeletedAt":null,"name":"#tag1"}],"correct":{"id":"1ab5ff1f-74c8-4efc-abdc-d03a3640f3bc","text":"Answer 1"},"CorrectPos":0,"type":0},{"id":"915818c4-b0ce-4efc-8def-7fc8d5fa7454","created_at":"2023-11-27T17:51:53.91077796+01:00","updated_at":"0001-01-01T00:00:00Z","hash":"","question":{"id":"70793f0d-2855-4140-814e-40167464424b","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","text":"Another question text with #tag1."},"answers":[{"id":"1ab5ff1f-74c8-4efc-abdc-d03a3640f3bc","text":"Answer 1"},{"id":"74547724-b905-476f-8cfc-6ee633f92ef3","text":"Answer 2"},{"id":"96c1a8ee-c50c-4ebc-89e4-9f3ca356adbd","text":"Answer 3"},{"id":"16c4b95e-64ce-4666-8cbe-b66fa59eb23b","text":"Answer 4"}],"tags":[{"CreatedAt":"0001-01-01T00:00:00Z","UpdatedAt":"0001-01-01T00:00:00Z","DeletedAt":null,"name":"#tag1"}],"correct":{"id":"1ab5ff1f-74c8-4efc-abdc-d03a3640f3bc","text":"Answer 1"},"CorrectPos":0,"type":0}]}

View file

@ -0,0 +1 @@
{"ID":"5467","Firstname":"Jack","Lastname":"Sparrow","Token":333444,"Attributes":{"class":"2 D LIN"}}

View file

@ -0,0 +1 @@
{"ID":"1234","Firstname":"John","Lastname":"Smith","Token":111222,"Attributes":{"class":"1 D LIN"}}

View file

@ -0,0 +1 @@
{"ID":"567812","Firstname":"Wendy","Lastname":"Darling","Token":333444,"Attributes":{"class":"2 D LIN"}}

View file

@ -0,0 +1,12 @@
---
id: 0610939b-a1a3-4d0e-bbc4-2aae0e8ee4b9
created_at: 2023-11-27T17:51:53.910642221+01:00
updated_at: 0001-01-01T00:00:00Z
---
Question text with #tag1.
* Answer 1
* Answer 2
* Answer 3
* Answer 4

View file

@ -0,0 +1,12 @@
---
id: 915818c4-b0ce-4efc-8def-7fc8d5fa7454
created_at: 2023-11-27T17:51:53.91077796+01:00
updated_at: 0001-01-01T00:00:00Z
---
Another question text with #tag1.
* Answer 1
* Answer 2
* Answer 3
* Answer 4

View file

@ -0,0 +1,12 @@
---
id: 87e7825d-c75c-448b-b718-9c0b68407ab6
created_at: 2023-11-27T17:51:53.910886823+01:00
updated_at: 0001-01-01T00:00:00Z
---
Another question text with #tag2.
* Answer 1
* Answer 2
* Answer 3
* Answer 4