Merge pull request #67 from rede5/codex/definir-cobertura-de-testes-no-backend

Codex-generated pull request
This commit is contained in:
Tiago Yamamoto 2026-02-16 23:25:44 -03:00 committed by GitHub
commit 6d84b0fa4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 470 additions and 0 deletions

View file

@ -0,0 +1,183 @@
package tenant
import (
"context"
"errors"
"testing"
"time"
"github.com/rede5/gohorsejobs/backend/internal/core/domain/entity"
"github.com/rede5/gohorsejobs/backend/internal/core/dto"
)
type fakeCompanyRepo struct {
saveFn func(context.Context, *entity.Company) (*entity.Company, error)
findAll []*entity.Company
findErr error
}
func (f *fakeCompanyRepo) Save(ctx context.Context, company *entity.Company) (*entity.Company, error) {
if f.saveFn != nil {
return f.saveFn(ctx, company)
}
return company, nil
}
func (f *fakeCompanyRepo) FindByID(ctx context.Context, id string) (*entity.Company, error) { return nil, nil }
func (f *fakeCompanyRepo) FindAll(ctx context.Context) ([]*entity.Company, error) {
return f.findAll, f.findErr
}
func (f *fakeCompanyRepo) Update(ctx context.Context, company *entity.Company) (*entity.Company, error) {
return company, nil
}
func (f *fakeCompanyRepo) Delete(ctx context.Context, id string) error { return nil }
type fakeUserRepoTenant struct {
findByEmailUser *entity.User
findByEmailErr error
saveErr error
savedUser *entity.User
}
func (f *fakeUserRepoTenant) Save(ctx context.Context, user *entity.User) (*entity.User, error) {
f.savedUser = user
return user, f.saveErr
}
func (f *fakeUserRepoTenant) FindByID(ctx context.Context, id string) (*entity.User, error) { return nil, nil }
func (f *fakeUserRepoTenant) FindByEmail(ctx context.Context, email string) (*entity.User, error) {
return f.findByEmailUser, f.findByEmailErr
}
func (f *fakeUserRepoTenant) FindAllByTenant(ctx context.Context, tenantID string, limit, offset int) ([]*entity.User, int, error) {
return nil, 0, nil
}
func (f *fakeUserRepoTenant) LinkGuestApplications(ctx context.Context, email string, userID string) error {
return nil
}
func (f *fakeUserRepoTenant) Update(ctx context.Context, user *entity.User) (*entity.User, error) { return user, nil }
func (f *fakeUserRepoTenant) Delete(ctx context.Context, id string) error { return nil }
type fakeAuthTenant struct {
hashResult string
hashErr error
token string
tokenErr error
}
func (f *fakeAuthTenant) HashPassword(password string) (string, error) { return f.hashResult, f.hashErr }
func (f *fakeAuthTenant) VerifyPassword(hash, password string) bool { return false }
func (f *fakeAuthTenant) GenerateToken(userID, tenantID string, roles []string) (string, error) {
return f.token, f.tokenErr
}
func (f *fakeAuthTenant) ValidateToken(token string) (map[string]interface{}, error) { return nil, nil }
func TestCreateCompanyUseCaseExecute_ValidationAndSuccess(t *testing.T) {
companyRepo := &fakeCompanyRepo{}
userRepo := &fakeUserRepoTenant{}
auth := &fakeAuthTenant{hashResult: "hashed", token: "jwt-token"}
uc := NewCreateCompanyUseCase(companyRepo, userRepo, auth)
_, err := uc.Execute(context.Background(), dto.CreateCompanyRequest{})
if err == nil {
t.Fatalf("expected company name validation error")
}
invalidDoc := "123"
_, err = uc.Execute(context.Background(), dto.CreateCompanyRequest{Name: "ACME", Document: invalidDoc})
if err == nil {
t.Fatalf("expected invalid document error")
}
userRepo.findByEmailUser = entity.NewUser("u1", "t1", "Admin", "admin@acme.com")
_, err = uc.Execute(context.Background(), dto.CreateCompanyRequest{Name: "ACME", AdminEmail: "admin@acme.com"})
if err == nil {
t.Fatalf("expected duplicate admin user error")
}
userRepo.findByEmailUser = nil
companyRepo.saveFn = func(_ context.Context, company *entity.Company) (*entity.Company, error) {
if company.Name != "Acme Co" {
t.Fatalf("expected sanitized company name, got %q", company.Name)
}
company.ID = "company-1"
company.CreatedAt = time.Now()
return company, nil
}
birthDate := "1990-05-20"
website := "https://acme.test"
address := "Rua 1"
resp, err := uc.Execute(context.Background(), dto.CreateCompanyRequest{
CompanyName: " Acme Co ",
Email: "contact@acme.test",
AdminEmail: "",
Password: "",
Website: &website,
Address: &address,
BirthDate: &birthDate,
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if resp.ID != "company-1" || resp.Token != "jwt-token" {
t.Fatalf("unexpected response: %+v", resp)
}
if userRepo.savedUser == nil || userRepo.savedUser.PasswordHash != "hashed" {
t.Fatalf("expected saved admin user with hashed password")
}
if userRepo.savedUser.BirthDate == nil {
t.Fatalf("expected birth date to be parsed")
}
if len(userRepo.savedUser.Roles) != 1 || userRepo.savedUser.Roles[0].Name != entity.RoleAdmin {
t.Fatalf("expected admin role")
}
}
func TestCreateCompanyUseCaseExecute_RepositoryFailures(t *testing.T) {
companyRepo := &fakeCompanyRepo{}
userRepo := &fakeUserRepoTenant{}
auth := &fakeAuthTenant{hashResult: "hashed", tokenErr: errors.New("token fail")}
uc := NewCreateCompanyUseCase(companyRepo, userRepo, auth)
companyRepo.saveFn = func(_ context.Context, company *entity.Company) (*entity.Company, error) {
return nil, errors.New("save company fail")
}
_, err := uc.Execute(context.Background(), dto.CreateCompanyRequest{Name: "ACME", AdminEmail: "admin@acme.com"})
if err == nil {
t.Fatalf("expected save company error")
}
companyRepo.saveFn = func(_ context.Context, company *entity.Company) (*entity.Company, error) {
company.ID = "company-2"
return company, nil
}
userRepo.saveErr = errors.New("save admin fail")
_, err = uc.Execute(context.Background(), dto.CreateCompanyRequest{Name: "ACME", AdminEmail: "admin@acme.com"})
if err == nil {
t.Fatalf("expected save admin error")
}
userRepo.saveErr = nil
resp, err := uc.Execute(context.Background(), dto.CreateCompanyRequest{Name: "ACME", AdminEmail: "admin@acme.com"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if resp.Token != "" {
t.Fatalf("expected empty token when generation fails")
}
}
func TestListCompaniesUseCaseExecute(t *testing.T) {
repo := &fakeCompanyRepo{findAll: []*entity.Company{{ID: "c1", Name: "Acme", Status: "ACTIVE"}}}
uc := NewListCompaniesUseCase(repo)
resp, err := uc.Execute(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(resp) != 1 || resp[0].ID != "c1" {
t.Fatalf("unexpected response: %+v", resp)
}
repo.findErr = errors.New("db fail")
_, err = uc.Execute(context.Background())
if err == nil {
t.Fatalf("expected find all error")
}
}

View file

@ -0,0 +1,275 @@
package user
import (
"context"
"errors"
"testing"
"github.com/rede5/gohorsejobs/backend/internal/core/domain/entity"
"github.com/rede5/gohorsejobs/backend/internal/core/dto"
)
type fakeUserRepo struct {
findByEmailUser *entity.User
findByEmailErr error
saveFn func(context.Context, *entity.User) (*entity.User, error)
findByIDUser *entity.User
findByIDErr error
findAllByTenantUsers []*entity.User
findAllByTenantTotal int
findAllByTenantErr error
updateFn func(context.Context, *entity.User) (*entity.User, error)
deleteErr error
capturedLimit int
capturedOffset int
}
func (f *fakeUserRepo) Save(ctx context.Context, user *entity.User) (*entity.User, error) {
if f.saveFn != nil {
return f.saveFn(ctx, user)
}
return user, nil
}
func (f *fakeUserRepo) FindByID(ctx context.Context, id string) (*entity.User, error) {
return f.findByIDUser, f.findByIDErr
}
func (f *fakeUserRepo) FindByEmail(ctx context.Context, email string) (*entity.User, error) {
return f.findByEmailUser, f.findByEmailErr
}
func (f *fakeUserRepo) FindAllByTenant(ctx context.Context, tenantID string, limit, offset int) ([]*entity.User, int, error) {
f.capturedLimit = limit
f.capturedOffset = offset
return f.findAllByTenantUsers, f.findAllByTenantTotal, f.findAllByTenantErr
}
func (f *fakeUserRepo) LinkGuestApplications(ctx context.Context, email string, userID string) error {
return nil
}
func (f *fakeUserRepo) Update(ctx context.Context, user *entity.User) (*entity.User, error) {
if f.updateFn != nil {
return f.updateFn(ctx, user)
}
return user, nil
}
func (f *fakeUserRepo) Delete(ctx context.Context, id string) error {
return f.deleteErr
}
type fakeAuthService struct {
hashPasswordResult string
hashPasswordErr error
}
func (f *fakeAuthService) HashPassword(password string) (string, error) {
return f.hashPasswordResult, f.hashPasswordErr
}
func (f *fakeAuthService) VerifyPassword(hash, password string) bool {
return false
}
func (f *fakeAuthService) GenerateToken(userID, tenantID string, roles []string) (string, error) {
return "", nil
}
func (f *fakeAuthService) ValidateToken(token string) (map[string]interface{}, error) {
return nil, nil
}
func TestCreateUserUseCaseExecute_ValidationAndSuccess(t *testing.T) {
repo := &fakeUserRepo{}
auth := &fakeAuthService{hashPasswordResult: "hashed"}
uc := NewCreateUserUseCase(repo, auth)
_, err := uc.Execute(context.Background(), dto.CreateUserRequest{Email: "x"}, "tenant-1")
if err == nil {
t.Fatalf("expected invalid email error")
}
repo.findByEmailUser = entity.NewUser("u-existing", "tenant-1", "A", "john@example.com")
_, err = uc.Execute(context.Background(), dto.CreateUserRequest{
Name: "John",
Email: "john@example.com",
Password: "secret",
}, "tenant-1")
if err == nil {
t.Fatalf("expected duplicate email error")
}
repo.findByEmailUser = nil
auth.hashPasswordErr = errors.New("hash failed")
_, err = uc.Execute(context.Background(), dto.CreateUserRequest{
Name: "John",
Email: "john@example.com",
Password: "secret",
}, "tenant-1")
if err == nil {
t.Fatalf("expected hash error")
}
auth.hashPasswordErr = nil
repo.saveFn = func(_ context.Context, user *entity.User) (*entity.User, error) {
if user.TenantID != "tenant-2" {
t.Fatalf("expected tenant from input when current tenant empty")
}
if user.PasswordHash != "hashed" {
t.Fatalf("expected hashed password")
}
if len(user.Roles) != 1 || user.Roles[0].Name != entity.RoleAdmin {
t.Fatalf("expected admin role")
}
return user, nil
}
status := "inactive"
tenantID := "tenant-2"
resp, err := uc.Execute(context.Background(), dto.CreateUserRequest{
Name: " Jo<hn> ",
Email: " JOHN@example.com ",
Password: "secret",
Roles: []string{entity.RoleAdmin},
Status: &status,
TenantID: &tenantID,
}, "")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if resp.Status != status {
t.Fatalf("expected status %s, got %s", status, resp.Status)
}
}
func TestListUsersUseCaseExecute_NormalizesPaginationAndMapsRoles(t *testing.T) {
repo := &fakeUserRepo{
findAllByTenantUsers: []*entity.User{{
ID: "u1", Name: "Ana", Email: "ana@example.com", Status: "active", Roles: []entity.Role{{Name: entity.RoleRecruiter}},
}},
findAllByTenantTotal: 1,
}
uc := NewListUsersUseCase(repo)
resp, err := uc.Execute(context.Background(), "tenant", -5, 999)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if repo.capturedLimit != 100 || repo.capturedOffset != 0 {
t.Fatalf("expected normalized limit/offset to 100/0, got %d/%d", repo.capturedLimit, repo.capturedOffset)
}
if resp.Pagination.Page != 1 || resp.Pagination.Limit != 100 || resp.Pagination.Total != 1 {
t.Fatalf("unexpected pagination: %+v", resp.Pagination)
}
users, ok := resp.Data.([]dto.UserResponse)
if !ok || len(users) != 1 || len(users[0].Roles) != 1 || users[0].Roles[0] != entity.RoleRecruiter {
t.Fatalf("unexpected users payload: %#v", resp.Data)
}
repo.findAllByTenantErr = errors.New("db down")
_, err = uc.Execute(context.Background(), "tenant", 1, 10)
if err == nil {
t.Fatalf("expected repository error")
}
}
func TestUpdateUserUseCaseExecute_Flows(t *testing.T) {
repo := &fakeUserRepo{}
uc := NewUpdateUserUseCase(repo)
repo.findByIDErr = errors.New("find error")
_, err := uc.Execute(context.Background(), "u1", "t1", dto.UpdateUserRequest{})
if err == nil {
t.Fatalf("expected find error")
}
repo.findByIDErr = nil
repo.findByIDUser = nil
_, err = uc.Execute(context.Background(), "u1", "t1", dto.UpdateUserRequest{})
if err == nil {
t.Fatalf("expected not found error")
}
repo.findByIDUser = &entity.User{ID: "u1", TenantID: "other"}
_, err = uc.Execute(context.Background(), "u1", "t1", dto.UpdateUserRequest{})
if err == nil {
t.Fatalf("expected forbidden error")
}
name := "New Name"
email := "new@example.com"
active := false
phone := "11999990000"
bio := "bio"
avatar := "https://avatar"
roles := []string{entity.RoleAdmin, entity.RoleRecruiter}
skills := []string{"go", "sql"}
repo.findByIDUser = &entity.User{ID: "u1", TenantID: "t1", Status: "active"}
repo.updateFn = func(_ context.Context, user *entity.User) (*entity.User, error) {
if user.Status != "inactive" || user.Name != name || user.Email != email || user.AvatarUrl != avatar {
t.Fatalf("user not updated as expected: %+v", user)
}
if len(user.Roles) != 2 || user.Roles[0].Name != entity.RoleAdmin {
t.Fatalf("roles not updated: %+v", user.Roles)
}
if len(user.Skills) != 2 {
t.Fatalf("skills not updated")
}
return user, nil
}
resp, err := uc.Execute(context.Background(), "u1", "t1", dto.UpdateUserRequest{
Name: &name,
Email: &email,
Phone: &phone,
Bio: &bio,
Active: &active,
Roles: &roles,
AvatarUrl: &avatar,
Skills: skills,
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if resp.Status != "inactive" {
t.Fatalf("expected inactive status")
}
status := "active"
repo.updateFn = func(_ context.Context, user *entity.User) (*entity.User, error) {
if user.Status != "active" {
t.Fatalf("expected explicit status to override active")
}
return nil, errors.New("update failed")
}
_, err = uc.Execute(context.Background(), "u1", "", dto.UpdateUserRequest{Status: &status})
if err == nil {
t.Fatalf("expected update error")
}
}
func TestDeleteUserUseCaseExecute_Flows(t *testing.T) {
repo := &fakeUserRepo{}
uc := NewDeleteUserUseCase(repo)
repo.findByIDErr = errors.New("boom")
if err := uc.Execute(context.Background(), "u1", "t1"); err == nil {
t.Fatalf("expected find error")
}
repo.findByIDErr = nil
repo.findByIDUser = &entity.User{ID: "u1", TenantID: "other"}
if err := uc.Execute(context.Background(), "u1", "t1"); err == nil {
t.Fatalf("expected tenant mismatch error")
}
repo.findByIDUser = &entity.User{ID: "u1", TenantID: "t1"}
repo.deleteErr = errors.New("delete fail")
if err := uc.Execute(context.Background(), "u1", "t1"); err == nil {
t.Fatalf("expected delete error")
}
repo.deleteErr = nil
if err := uc.Execute(context.Background(), "u1", ""); err != nil {
t.Fatalf("unexpected error: %v", err)
}
}

View file

@ -0,0 +1,12 @@
# Backend Coverage (com e sem banco)
## Sem banco de dados (unitário)
- **Cobertura total:** **27.2%**
- **Fonte:** `docs/txt/backend_coverage.txt` (`total: (statements) 27.2%`).
## Com banco de dados (integração)
- **Cobertura total reportada:** **~59.8%**
- **Fonte:** `docs/TEST_REPORT.md` (seção de backend com menção de cobertura total de ~59.8% e integração 100% pass).
## Observação
Esses números vêm de artefatos já versionados no repositório e representam execuções em momentos distintos.