Assignment 4: add unit, integration, and e2e tests; refactor for testability
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"5803025015/w04/internal/models"
|
||||
"5803025015/w04/internal/store"
|
||||
)
|
||||
|
||||
// ---------- fakeUserStore ----------
|
||||
|
||||
type fakeUserStore struct {
|
||||
mu sync.Mutex
|
||||
users map[string]*models.User
|
||||
nextID int
|
||||
createErr error
|
||||
getErr error
|
||||
}
|
||||
|
||||
func newFakeUserStore() *fakeUserStore {
|
||||
return &fakeUserStore{users: make(map[string]*models.User)}
|
||||
}
|
||||
|
||||
func (f *fakeUserStore) Create(ctx context.Context, u *models.User) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.createErr != nil {
|
||||
return f.createErr
|
||||
}
|
||||
if _, exists := f.users[u.Username]; exists {
|
||||
return store.ErrDuplicate
|
||||
}
|
||||
if u.ID == "" {
|
||||
f.nextID++
|
||||
u.ID = "user-id"
|
||||
}
|
||||
cp := *u
|
||||
f.users[u.Username] = &cp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeUserStore) GetByUsername(ctx context.Context, username string) (*models.User, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.getErr != nil {
|
||||
return nil, f.getErr
|
||||
}
|
||||
u, ok := f.users[username]
|
||||
if !ok {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
cp := *u
|
||||
return &cp, nil
|
||||
}
|
||||
|
||||
// ---------- fakeSessionStore ----------
|
||||
|
||||
type fakeSessionStore struct {
|
||||
mu sync.Mutex
|
||||
sessions map[string]*models.Session
|
||||
createErr error
|
||||
getErr error
|
||||
deleteErr error
|
||||
}
|
||||
|
||||
func newFakeSessionStore() *fakeSessionStore {
|
||||
return &fakeSessionStore{sessions: make(map[string]*models.Session)}
|
||||
}
|
||||
|
||||
func (f *fakeSessionStore) Create(ctx context.Context, s *models.Session) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.createErr != nil {
|
||||
return f.createErr
|
||||
}
|
||||
cp := *s
|
||||
if cp.CreatedAt.IsZero() {
|
||||
cp.CreatedAt = time.Now()
|
||||
}
|
||||
f.sessions[s.Token] = &cp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeSessionStore) Get(ctx context.Context, token string) (*models.Session, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.getErr != nil {
|
||||
return nil, f.getErr
|
||||
}
|
||||
s, ok := f.sessions[token]
|
||||
if !ok {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
cp := *s
|
||||
return &cp, nil
|
||||
}
|
||||
|
||||
func (f *fakeSessionStore) Delete(ctx context.Context, token string) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.deleteErr != nil {
|
||||
return f.deleteErr
|
||||
}
|
||||
if _, ok := f.sessions[token]; !ok {
|
||||
return store.ErrNotFound
|
||||
}
|
||||
delete(f.sessions, token)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeSessionStore) HasToken(token string) bool {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
_, ok := f.sessions[token]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ---------- fakeSnippetStore ----------
|
||||
|
||||
type fakeSnippetStore struct {
|
||||
mu sync.Mutex
|
||||
snippets map[string]*models.Snippet
|
||||
createErr error
|
||||
getErr error
|
||||
listErr error
|
||||
deleteErr error
|
||||
}
|
||||
|
||||
func newFakeSnippetStore() *fakeSnippetStore {
|
||||
return &fakeSnippetStore{snippets: make(map[string]*models.Snippet)}
|
||||
}
|
||||
|
||||
func (f *fakeSnippetStore) Create(ctx context.Context, s *models.Snippet) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.createErr != nil {
|
||||
return f.createErr
|
||||
}
|
||||
cp := *s
|
||||
f.snippets[s.ID] = &cp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeSnippetStore) GetByID(ctx context.Context, id string) (*models.Snippet, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.getErr != nil {
|
||||
return nil, f.getErr
|
||||
}
|
||||
s, ok := f.snippets[id]
|
||||
if !ok {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
cp := *s
|
||||
return &cp, nil
|
||||
}
|
||||
|
||||
func (f *fakeSnippetStore) ListByOwner(ctx context.Context, ownerID string) ([]*models.Snippet, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.listErr != nil {
|
||||
return nil, f.listErr
|
||||
}
|
||||
out := make([]*models.Snippet, 0)
|
||||
for _, s := range f.snippets {
|
||||
if s.UserID == ownerID {
|
||||
cp := *s
|
||||
out = append(out, &cp)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (f *fakeSnippetStore) Delete(ctx context.Context, id string) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.deleteErr != nil {
|
||||
return f.deleteErr
|
||||
}
|
||||
if _, ok := f.snippets[id]; !ok {
|
||||
return store.ErrNotFound
|
||||
}
|
||||
delete(f.snippets, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeSnippetStore) HasSnippet(id string) bool {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
_, ok := f.snippets[id]
|
||||
return ok
|
||||
}
|
||||
Reference in New Issue
Block a user