tests: implemented go user api tests

This commit is contained in:
2025-01-04 21:30:29 +00:00
parent 48aae18736
commit f8933bee15
11 changed files with 289 additions and 84 deletions
@@ -1,23 +0,0 @@
package services_test
import "testing"
func TestCreateUserService(t *testing.T) {
mockRepo := mocks.NewMockUserRepository()
service := services.NewUserService(mockRepo)
user := entities.UserCreate{
Email: "service@test.com",
Name: "Jane Doe",
Password: "securepassword",
}
result := service.CreateUser(context.Background(), user)
assert.True(t, result.IsRight(), "Expected service to create user")
result.Map(func(user entities.User) {
assert.Equal(t, "service@test.com", user.Email)
assert.Equal(t, "Jane Doe", user.Name)
})
}
-10
View File
@@ -1,10 +0,0 @@
package mocks
import (
"github.com/google/uuid"
)
// GenerateID generates a new UUID string.
func GenerateID() string {
return uuid.New().String()
}
@@ -1,125 +0,0 @@
package mocks
import (
"actatempus_backend/internal/domain/data"
"actatempus_backend/internal/domain/entities"
impl "actatempus_backend/internal/infrastructure/data"
"context"
"fmt"
"sync"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
)
type MockProjectDataSource struct {
store map[string]*entities.Project
mu sync.RWMutex
}
func NewMockProjectDataSource() data.ProjectDataSource {
return &MockProjectDataSource{
store: make(map[string]*entities.Project),
}
}
// Create adds a new project to the store
func (ds *MockProjectDataSource) Create(ctx context.Context, project entities.ProjectCreate) E.Either[error, entities.Project] {
ds.mu.Lock()
defer ds.mu.Unlock()
id := GenerateID()
newProject := entities.Project{
ID: id,
Name: project.Name,
UserID: project.UserID,
Description: project.Description,
ClientID: project.ClientID,
}
ds.store[id] = &newProject
return E.Right[error](newProject)
}
// FindByID retrieves a project by its ID
func (ds *MockProjectDataSource) FindByID(ctx context.Context, id string) E.Either[error, entities.Project] {
ds.mu.RLock()
defer ds.mu.RUnlock()
return F.Pipe2(
O.FromNillable(ds.store[id]),
E.FromOption[*entities.Project](F.Constant(fmt.Errorf("project with ID %s not found", id))),
E.Chain(impl.TryDereference[entities.Project]),
)
}
// Update modifies an existing project
func (ds *MockProjectDataSource) Update(ctx context.Context, project entities.ProjectUpdate) E.Either[error, entities.Project] {
ds.mu.Lock()
defer ds.mu.Unlock()
existing, found := ds.store[project.ID]
if !found {
return E.Left[entities.Project](fmt.Errorf("project with ID %s not found", project.ID))
}
if project.Name != nil {
existing.Name = *project.Name
}
if project.Description != nil {
existing.Description = project.Description
}
if project.ClientID != nil {
existing.ClientID = project.ClientID
}
if project.UserID != nil {
existing.UserID = *project.UserID
}
return E.Right[error](*existing)
}
// Delete removes a project from the store
func (ds *MockProjectDataSource) Delete(ctx context.Context, id string) E.Either[error, entities.Project] {
ds.mu.Lock()
defer ds.mu.Unlock()
existing, found := ds.store[id]
if !found {
return E.Left[entities.Project](fmt.Errorf("project with ID %s not found", id))
}
delete(ds.store, id)
return E.Right[error](*existing)
}
// FindAll retrieves all projects
func (ds *MockProjectDataSource) FindAll(ctx context.Context) E.Either[error, []entities.Project] {
ds.mu.RLock()
defer ds.mu.RUnlock()
projects := make([]entities.Project, 0, len(ds.store))
for _, project := range ds.store {
projects = append(projects, *project)
}
return E.Right[error](projects)
}
// FindByUserID retrieves all projects for a specific user
func (ds *MockProjectDataSource) FindByUserID(ctx context.Context, userID string) E.Either[error, []entities.Project] {
ds.mu.RLock()
defer ds.mu.RUnlock()
projects := make([]entities.Project, 0)
for _, project := range ds.store {
if project.UserID == userID {
projects = append(projects, *project)
}
}
return E.Right[error](projects)
}
@@ -1,120 +0,0 @@
package mocks
import (
"actatempus_backend/internal/domain/data"
"actatempus_backend/internal/domain/entities"
impl "actatempus_backend/internal/infrastructure/data"
"context"
"fmt"
"sync"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
)
type MockProjectTaskDataSource struct {
store map[string]*entities.ProjectTask
mu sync.RWMutex
}
func NewMockProjectTaskDataSource() data.ProjectTaskDataSource {
return &MockProjectTaskDataSource{
store: make(map[string]*entities.ProjectTask),
}
}
// Create a new ProjectTask
func (ds *MockProjectTaskDataSource) Create(ctx context.Context, task entities.ProjectTaskCreate) E.Either[error, entities.ProjectTask] {
ds.mu.Lock()
defer ds.mu.Unlock()
id := GenerateID()
newTask := entities.ProjectTask{
ID: id,
Name: task.Name,
ProjectID: task.ProjectID,
Description: task.Description,
}
ds.store[id] = &newTask
return E.Right[error](newTask)
}
// Find ProjectTask by ID
func (ds *MockProjectTaskDataSource) FindByID(ctx context.Context, id string) E.Either[error, entities.ProjectTask] {
ds.mu.RLock()
defer ds.mu.RUnlock()
return F.Pipe2(
O.FromNillable(ds.store[id]),
E.FromOption[*entities.ProjectTask](F.Constant(fmt.Errorf("project task with ID %s not found", id))),
E.Chain(impl.TryDereference[entities.ProjectTask]),
)
}
// Update an existing ProjectTask
func (ds *MockProjectTaskDataSource) Update(ctx context.Context, task entities.ProjectTaskUpdate) E.Either[error, entities.ProjectTask] {
ds.mu.Lock()
defer ds.mu.Unlock()
existing, found := ds.store[task.ID]
if !found {
return E.Left[entities.ProjectTask](fmt.Errorf("project task with ID %s not found", task.ID))
}
if task.Name != nil {
existing.Name = *task.Name
}
if task.Description != nil {
existing.Description = task.Description
}
if task.ProjectID != nil {
existing.ProjectID = *task.ProjectID
}
return E.Right[error](*existing)
}
// Delete a ProjectTask
func (ds *MockProjectTaskDataSource) Delete(ctx context.Context, id string) E.Either[error, entities.ProjectTask] {
ds.mu.Lock()
defer ds.mu.Unlock()
existing, found := ds.store[id]
if !found {
return E.Left[entities.ProjectTask](fmt.Errorf("project task with ID %s not found", id))
}
delete(ds.store, id)
return E.Right[error](*existing)
}
// FindAll retrieves all ProjectTasks
func (ds *MockProjectTaskDataSource) FindAll(ctx context.Context) E.Either[error, []entities.ProjectTask] {
ds.mu.RLock()
defer ds.mu.RUnlock()
tasks := make([]entities.ProjectTask, 0, len(ds.store))
for _, task := range ds.store {
tasks = append(tasks, *task)
}
return E.Right[error](tasks)
}
// FindByProjectID retrieves all ProjectTasks for a given Project
func (ds *MockProjectTaskDataSource) FindByProjectID(ctx context.Context, projectID string) E.Either[error, []entities.ProjectTask] {
ds.mu.RLock()
defer ds.mu.RUnlock()
tasks := make([]entities.ProjectTask, 0)
for _, task := range ds.store {
if task.ProjectID == projectID {
tasks = append(tasks, *task)
}
}
return E.Right[error](tasks)
}
@@ -1,144 +0,0 @@
package mocks
import (
impl "actatempus_backend/internal/infrastructure/data"
"actatempus_backend/internal/domain/data"
"actatempus_backend/internal/domain/entities"
"context"
"fmt"
"sync"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
)
type MockTimeEntryDataSource struct {
store map[string]*entities.TimeEntry
mu sync.RWMutex
}
func NewMockTimeEntryDataSource() data.TimeEntryDataSource {
return &MockTimeEntryDataSource{
store: make(map[string]*entities.TimeEntry),
}
}
// Create a new TimeEntry
func (ds *MockTimeEntryDataSource) Create(ctx context.Context, entry entities.TimeEntryCreate) E.Either[error, entities.TimeEntry] {
ds.mu.Lock()
defer ds.mu.Unlock()
id := GenerateID()
newEntry := entities.TimeEntry{
ID: id,
StartTime: entry.StartTime,
EndTime: entry.EndTime,
Description: entry.Description,
UserID: entry.UserID,
ProjectID: entry.ProjectID,
}
ds.store[id] = &newEntry
return E.Right[error](newEntry)
}
// Find TimeEntry by ID
func (ds *MockTimeEntryDataSource) FindByID(ctx context.Context, id string) E.Either[error, entities.TimeEntry] {
ds.mu.RLock()
defer ds.mu.RUnlock()
return F.Pipe2(
O.FromNillable(ds.store[id]),
E.FromOption[*entities.TimeEntry](F.Constant(fmt.Errorf("time entry with ID %s not found", id))),
E.Chain(impl.TryDereference[entities.TimeEntry]),
)
}
// Update an existing TimeEntry
func (ds *MockTimeEntryDataSource) Update(ctx context.Context, entry entities.TimeEntryUpdate) E.Either[error, entities.TimeEntry] {
ds.mu.Lock()
defer ds.mu.Unlock()
existing, found := ds.store[entry.ID]
if !found {
return E.Left[entities.TimeEntry](fmt.Errorf("time entry with ID %s not found", entry.ID))
}
if entry.StartTime != nil {
existing.StartTime = *entry.StartTime
}
if entry.EndTime != nil {
existing.EndTime = entry.EndTime
}
if entry.Description != nil {
existing.Description = entry.Description
}
if entry.UserID != nil {
existing.UserID = *entry.UserID
}
if entry.ProjectID != nil {
existing.ProjectID = *entry.ProjectID
}
return E.Right[error](*existing)
}
// Delete a TimeEntry
func (ds *MockTimeEntryDataSource) Delete(ctx context.Context, id string) E.Either[error, entities.TimeEntry] {
ds.mu.Lock()
defer ds.mu.Unlock()
existing, found := ds.store[id]
if !found {
return E.Left[entities.TimeEntry](fmt.Errorf("time entry with ID %s not found", id))
}
delete(ds.store, id)
return E.Right[error](*existing)
}
// FindAll retrieves all TimeEntries
func (ds *MockTimeEntryDataSource) FindAll(ctx context.Context) E.Either[error, []entities.TimeEntry] {
ds.mu.RLock()
defer ds.mu.RUnlock()
entries := make([]entities.TimeEntry, 0, len(ds.store))
for _, entry := range ds.store {
entries = append(entries, *entry)
}
return E.Right[error](entries)
}
// FindByUserID retrieves all TimeEntries by UserID
func (ds *MockTimeEntryDataSource) FindByUserID(ctx context.Context, userID string) E.Either[error, []entities.TimeEntry] {
ds.mu.RLock()
defer ds.mu.RUnlock()
entries := make([]entities.TimeEntry, 0)
for _, entry := range ds.store {
if entry.UserID == userID {
entries = append(entries, *entry)
}
}
return E.Right[error](entries)
}
// FindByProjectID retrieves all TimeEntries by ProjectID
func (ds *MockTimeEntryDataSource) FindByProjectID(ctx context.Context, projectID string) E.Either[error, []entities.TimeEntry] {
ds.mu.RLock()
defer ds.mu.RUnlock()
entries := make([]entities.TimeEntry, 0)
for _, entry := range ds.store {
if entry.ProjectID == projectID {
entries = append(entries, *entry)
}
}
return E.Right[error](entries)
}
@@ -1,113 +0,0 @@
package mocks
import (
domain "actatempus_backend/internal/domain/data"
"actatempus_backend/internal/domain/entities"
impl "actatempus_backend/internal/infrastructure/data"
"context"
"fmt"
"sync"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
)
type MockUserDataSource struct {
store map[string]*entities.User
mu sync.RWMutex
}
func NewMockUserDataSource() domain.UserDataSource {
return &MockUserDataSource{
store: make(map[string]*entities.User),
}
}
func (ds *MockUserDataSource) Create(ctx context.Context, user entities.UserCreate) E.Either[error, entities.User] {
ds.mu.Lock()
defer ds.mu.Unlock()
id := GenerateID()
newUser := entities.User{
ID: id,
Name: user.Name,
Email: user.Email,
Password: impl.GenerateSecureHash(user.Password),
}
ds.store[id] = &newUser
return E.Right[error](newUser)
}
func (ds *MockUserDataSource) FindByID(ctx context.Context, id string) E.Either[error, entities.User] {
ds.mu.RLock()
defer ds.mu.RUnlock()
return F.Pipe2(
O.FromNillable(ds.store[id]),
E.FromOption[*entities.User](F.Constant(fmt.Errorf("user with ID %s not found", id))),
E.Chain(
impl.TryDereference[entities.User],
),
)
}
func (ds *MockUserDataSource) FindByEmail(ctx context.Context, email string) E.Either[error, entities.User] {
ds.mu.RLock()
defer ds.mu.RUnlock()
for _, user := range ds.store {
if user.Email == email {
return E.Right[error](*user)
}
}
return E.Left[entities.User](fmt.Errorf("user with email %s not found", email))
}
func (ds *MockUserDataSource) Update(ctx context.Context, user entities.UserUpdate) E.Either[error, entities.User] {
ds.mu.Lock()
defer ds.mu.Unlock()
existing, found := ds.store[user.ID]
if !found {
return E.Left[entities.User](fmt.Errorf("user with ID %s not found", user.ID))
}
if user.Name != nil {
existing.Name = *user.Name
}
if user.Email != nil {
existing.Email = *user.Email
}
if user.Password != nil {
existing.Password = impl.GenerateSecureHash(*user.Password)
}
return E.Right[error](*existing)
}
func (ds *MockUserDataSource) Delete(ctx context.Context, id string) E.Either[error, entities.User] {
ds.mu.Lock()
defer ds.mu.Unlock()
existing, found := ds.store[id]
if !found {
return E.Left[entities.User](fmt.Errorf("user with ID %s not found", id))
}
delete(ds.store, id)
return E.Right[error](*existing)
}
func (ds *MockUserDataSource) FindAll(ctx context.Context) E.Either[error, []entities.User] {
ds.mu.RLock()
defer ds.mu.RUnlock()
users := make([]entities.User, 0, len(ds.store))
for _, user := range ds.store {
users = append(users, *user)
}
return E.Right[error](users)
}