diff --git a/entity/user.go b/entity/user.go index 81208eb8..8352501d 100644 --- a/entity/user.go +++ b/entity/user.go @@ -46,7 +46,7 @@ func NewUser(name, uType, document, avatar_url, email, phone, pass, city, state } } -func UserToUpdate(dtoUpdate dto.UserUpdateDto) User { +func UserToUpdate(dtoUpdate *dto.UserUpdateDto) User { user := User{ Name: dtoUpdate.Name, Document: dtoUpdate.Document, @@ -60,5 +60,5 @@ func UserToUpdate(dtoUpdate dto.UserUpdateDto) User { user.BirthDate = nil } - return *user + return user } diff --git a/usecase/breed.go b/usecase/breed.go index 4f22447f..11aa577d 100644 --- a/usecase/breed.go +++ b/usecase/breed.go @@ -25,7 +25,7 @@ func (useCase *BreedUseCase) List() ([]*dto.BreedList, error) { breed, err := useCase.repo.List() if err != nil { loggerBreed.Error("error listing breeds", err) - err = fmt.Errorf("error listing breeds: %w", err) + err = fmt.Errorf("error listing breeds: %s", err) return nil, err } return breed, nil @@ -34,7 +34,7 @@ func (useCase *BreedUseCase) List() ([]*dto.BreedList, error) { func (useCase *BreedUseCase) FindByID(ID uniqueEntityId.ID) (*entity.Breed, error) { breed, err := useCase.repo.FindByID(ID) if err != nil { - err = fmt.Errorf("failed to retrieve breed: %w", err) + err = fmt.Errorf("failed to retrieve breed: %s", err) return nil, err } return breed, nil diff --git a/usecase/breed_test.go b/usecase/breed_test.go index c03e717b..29255703 100644 --- a/usecase/breed_test.go +++ b/usecase/breed_test.go @@ -1,29 +1,140 @@ package usecase import ( - mockInterfaces "pet-dex-backend/v2/mocks/pet-dex-backend/v2/interfaces" - - "github.com/stretchr/testify/assert" - + "fmt" "pet-dex-backend/v2/entity" + "pet-dex-backend/v2/entity/dto" + mockInterfaces "pet-dex-backend/v2/mocks/pet-dex-backend/v2/interfaces" "pet-dex-backend/v2/pkg/uniqueEntityId" "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" ) +func TestList(t *testing.T) { + uuidList := []uniqueEntityId.ID{ + uuid.MustParse("f3768895-d8cc-40d7-b8ae-8b7eb0eac26c"), + uuid.MustParse("db6ba220-19dc-4f6c-845f-0fbf84c275b9"), + uuid.MustParse("eb90009f-dfcc-4568-95b9-3f393ef9a9c2"), + uuid.MustParse("43c7b32a-3e31-4894-8c93-0e8b29415caa"), + } + + tcases := map[string]struct { + repo *mockInterfaces.MockBreedRepository + expectOutput []*dto.BreedList + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockBreedRepository(t), + expectOutput: []*dto.BreedList{ + {ID: uuidList[0], Name: "Amarelo", ImgUrl: "image url 1"}, + {ID: uuidList[1], Name: "Caramela", ImgUrl: "image url 2"}, + {ID: uuidList[2], Name: "Nuvem", ImgUrl: "image url 3"}, + {ID: uuidList[3], Name: "Thor", ImgUrl: "image url 4"}, + }, + expectedError: nil, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("List").Return(tcase.expectOutput, nil) + + usecase := NewBreedUseCase(tcase.repo) + list, err := usecase.List() + + assert.Equal(t, tcase.expectOutput, list, "expected output mismatch") + assert.Equal(t, tcase.expectedError, err, "expected error mismatch") + }) + } +} + +func TestListErrorOnRepo(t *testing.T) { + + tcases := map[string]struct { + repo *mockInterfaces.MockBreedRepository + expectOutput []*dto.BreedList + mockError error + expectedError error + }{ + "errorList": { + repo: mockInterfaces.NewMockBreedRepository(t), + expectOutput: nil, + mockError: fmt.Errorf("error listing breeds"), + expectedError: fmt.Errorf("error listing breeds: error listing breeds"), + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("List").Return(tcase.expectOutput, tcase.mockError) + + usecase := NewBreedUseCase(tcase.repo) + _, err := usecase.List() + + assert.Equal(t, tcase.expectedError, err, "expected error mismatch") + }) + } +} + func TestBreedFindByID(t *testing.T) { ID := uniqueEntityId.NewID() expectedBreed := &entity.Breed{ID: ID, Name: "Pastor Alemão", Specie: "Dog"} - mockRepo := mockInterfaces.NewMockBreedRepository(t) - defer mockRepo.AssertExpectations(t) + tcases := map[string]struct { + repo *mockInterfaces.MockBreedRepository + expectOutput *entity.Breed + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockBreedRepository(t), + expectOutput: expectedBreed, + expectedError: nil, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("FindByID", expectedBreed.ID).Return(tcase.expectOutput, tcase.expectedError) + + usecase := NewBreedUseCase(tcase.repo) + list, err := usecase.FindByID(expectedBreed.ID) + + assert.Equal(t, tcase.expectOutput, list, "expected output mismatch") + assert.Equal(t, tcase.expectedError, err, "expected error mismatch") + }) + } +} + +func TestBreedFindByIDErrorOnRepo(t *testing.T) { + ID := uniqueEntityId.NewID() + + tcases := map[string]struct { + repo *mockInterfaces.MockBreedRepository + expectOutput *entity.Breed + mockInput error + expectedError error + }{ + "error": { + repo: mockInterfaces.NewMockBreedRepository(t), + expectOutput: nil, + mockInput: fmt.Errorf("error retrieving breed"), + expectedError: fmt.Errorf("failed to retrieve breed:"), + }, + } - mockRepo.On("FindByID", ID).Return(expectedBreed, nil) - usecase := NewBreedUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("FindByID", ID).Return(tcase.expectOutput, tcase.mockInput) - resultPet, err := usecase.FindByID(ID) + usecase := NewBreedUseCase(tcase.repo) + list, err := usecase.FindByID(ID) - assert.NoError(t, err) - assert.NotNil(t, resultPet) - assert.Equal(t, expectedBreed, resultPet) + assert.EqualError(t, err, "failed to retrieve breed: error retrieving breed") + assert.Equal(t, list, tcase.expectOutput) + assert.Error(t, err, tcase.expectedError) + }) + } } diff --git a/usecase/pet_test.go b/usecase/pet_test.go index c3b8e4ba..fc63922a 100644 --- a/usecase/pet_test.go +++ b/usecase/pet_test.go @@ -3,223 +3,496 @@ package usecase import ( "errors" "time" - - mockInterfaces "pet-dex-backend/v2/mocks/pet-dex-backend/v2/interfaces" - "pet-dex-backend/v2/entity/dto" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "pet-dex-backend/v2/entity" + + "pet-dex-backend/v2/entity/dto" "pet-dex-backend/v2/infra/config" + + "pet-dex-backend/v2/entity" + mockInterfaces "pet-dex-backend/v2/mocks/pet-dex-backend/v2/interfaces" "pet-dex-backend/v2/pkg/uniqueEntityId" "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) func TestUpdateUseCaseDo(t *testing.T) { id := "123" Data, _ := time.Parse(time.DateTime, "2023-09-20") Birthdate, _ := time.Parse(time.DateTime, "2023-09-20") - userID := uniqueEntityId.NewID() + userId := uniqueEntityId.NewID() petUpdateDto := dto.PetUpdateDto{Size: "small", AdoptionDate: Data, Birthdate: Birthdate, Weight: 4.53, WeightMeasure: "kg"} - mockRepo := mockInterfaces.NewMockPetRepository(t) - mockRepo.On("Update", id, userID.String(), entity.PetToEntity(&petUpdateDto)).Return(nil) - usecase := NewPetUseCase(mockRepo) - err := usecase.Update(id, userID.String(), petUpdateDto) + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + input dto.PetUpdateDto + petId string + userId string + expectOutput error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: petUpdateDto, + petId: id, + userId: userId.String(), + expectOutput: nil, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("Update", tcase.petId, tcase.userId, entity.PetToEntity((&tcase.input))).Return(tcase.expectOutput) + + usecase := NewPetUseCase(tcase.repo) + err := usecase.Update(tcase.petId, tcase.userId, tcase.input) - assert.NoError(t, err) - mockRepo.AssertExpectations(t) + assert.NoError(t, err) + assert.Equal(t, tcase.expectOutput, err, "expected error mismatch") + }) + } } func TestUseCaseDoInvalidSize(t *testing.T) { id := "123" - userID := uniqueEntityId.NewID() - petUpdateDto := dto.PetUpdateDto{Size: "Invalid Size"} - mockRepo := mockInterfaces.NewMockPetRepository(t) - mockRepo.On("Update", id, userID.String(), entity.PetToEntity(&petUpdateDto)).Return(nil) - usecase := NewPetUseCase(mockRepo) + Data, _ := time.Parse(time.DateTime, "2023-09-20") + Birthdate, _ := time.Parse(time.DateTime, "2023-09-20") + userId := uniqueEntityId.NewID() + petUpdateDto := dto.PetUpdateDto{Size: "Invalid Size", AdoptionDate: Data, Birthdate: Birthdate, Weight: 4.53, WeightMeasure: "kg"} + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + input dto.PetUpdateDto + petId string + userId string + expectOutput error + }{ + "error": { + repo: mockInterfaces.NewMockPetRepository(t), + input: petUpdateDto, + petId: id, + userId: userId.String(), + expectOutput: nil, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { - err := usecase.Update(id, userID.String(), petUpdateDto) + usecase := NewPetUseCase(tcase.repo) + err := usecase.Update(tcase.petId, tcase.userId, tcase.input) - assert.EqualError(t, err, "the animal size is invalid") - mockRepo.AssertNotCalled(t, "Update") + assert.EqualError(t, err, "the animal size is invalid") + tcase.repo.AssertNotCalled(t, "Update") + }) + } } func TestUpdateUseCaseDoRepositoryError(t *testing.T) { id := "123" - userID := "321" - petUpdateDto := dto.PetUpdateDto{Size: "small", Weight: 4.53, WeightMeasure: "kg"} + Data, _ := time.Parse(time.DateTime, "2023-09-20") + Birthdate, _ := time.Parse(time.DateTime, "2023-09-20") + userId := uniqueEntityId.NewID() + petUpdateDto := dto.PetUpdateDto{Size: "small", AdoptionDate: Data, Birthdate: Birthdate, Weight: 4.53, WeightMeasure: "kg"} repoError := errors.New("error updating pet") - mockRepo := mockInterfaces.NewMockPetRepository(t) - mockRepo.On("Update", id, userID, entity.PetToEntity(&petUpdateDto)).Return(repoError) - usecase := NewPetUseCase(mockRepo) - err := usecase.Update(id, userID, petUpdateDto) + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + input dto.PetUpdateDto + petId string + userId string + expectOutput error + }{ + "error": { + repo: mockInterfaces.NewMockPetRepository(t), + input: petUpdateDto, + petId: id, + userId: userId.String(), + expectOutput: repoError, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("Update", tcase.petId, tcase.userId, entity.PetToEntity((&tcase.input))).Return(tcase.expectOutput) - assert.EqualError(t, err, "failed to update pet with ID 123: error updating pet") - mockRepo.AssertExpectations(t) + usecase := NewPetUseCase(tcase.repo) + err := usecase.Update(tcase.petId, tcase.userId, tcase.input) + + assert.EqualError(t, err, "failed to update pet with ID 123: error updating pet") + }) + } } func TestUpdateUseCaseisValidSize(t *testing.T) { - usecase := PetUseCase{} - - assert.True(t, usecase.isValidPetSize(&entity.Pet{Size: "small"})) - assert.True(t, usecase.isValidPetSize(&entity.Pet{Size: "medium"})) - assert.True(t, usecase.isValidPetSize(&entity.Pet{Size: "large"})) - assert.True(t, usecase.isValidPetSize(&entity.Pet{Size: "giant"})) - assert.False(t, usecase.isValidPetSize(&entity.Pet{Size: "Invalid Size"})) - assert.False(t, usecase.isValidPetSize(&entity.Pet{Size: ""})) + usecase := NewPetUseCase(nil) + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + input *entity.Pet + expectOutput bool + }{ + "small": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Size: "small"}, + expectOutput: true, + }, + "medium": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Size: "medium"}, + expectOutput: true, + }, + "large": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Size: "large"}, + expectOutput: true, + }, + "giant": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Size: "giant"}, + expectOutput: true, + }, + "Invalid Size": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Size: "Invalid Size"}, + expectOutput: false, + }, + "empty": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Size: ""}, + expectOutput: false, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + value := usecase.isValidPetSize(tcase.input) + assert.Equal(t, tcase.expectOutput, value) + }) + } } func TestUpdateUseCaseDoVaccines(t *testing.T) { id := "123" - userID := uniqueEntityId.NewID().String() + userId := uniqueEntityId.NewID() vaccines := []dto.VaccinesDto{ {Name: "Rabies", Date: time.Now(), DoctorCRM: "123456"}, {Name: "Distemper", Date: time.Now(), DoctorCRM: "123456"}, } petUpdateDto := dto.PetUpdateDto{Size: "medium", Vaccines: vaccines, Weight: 4.53, WeightMeasure: "kg"} - mockRepo := mockInterfaces.NewMockPetRepository(t) - mockRepo.On("Update", id, userID, entity.PetToEntity(&petUpdateDto)).Return(nil) - usecase := NewPetUseCase(mockRepo) - err := usecase.Update(id, userID, petUpdateDto) + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + input dto.PetUpdateDto + petId string + userId string + expectOutput error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: petUpdateDto, + petId: id, + userId: userId.String(), + expectOutput: nil, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("Update", tcase.petId, tcase.userId, entity.PetToEntity((&tcase.input))).Return(tcase.expectOutput) + + usecase := NewPetUseCase(tcase.repo) + err := usecase.Update(tcase.petId, tcase.userId, tcase.input) - assert.NoError(t, err) - mockRepo.AssertExpectations(t) + assert.NoError(t, err) + assert.Equal(t, tcase.expectOutput, err, "expected error mismatch") + }) + } } func TestUpdateUseCaseDoVaccinesError(t *testing.T) { id := "123" - userID := "321" + userId := uniqueEntityId.NewID() vaccines := []dto.VaccinesDto{ {Name: "Rabies", Date: time.Now(), DoctorCRM: "123456"}, {Name: "Distemper", Date: time.Now(), DoctorCRM: "123456"}, } - petUpdateDto := dto.PetUpdateDto{Size: "small", Vaccines: vaccines, Weight: 4.53, WeightMeasure: "kg"} + petUpdateDto := dto.PetUpdateDto{Size: "medium", Vaccines: vaccines, Weight: 4.53, WeightMeasure: "kg"} repoError := errors.New("error updating vaccines") - mockRepo := mockInterfaces.NewMockPetRepository(t) - mockRepo.On("Update", id, userID, entity.PetToEntity(&petUpdateDto)).Return(repoError) - usecase := NewPetUseCase(mockRepo) - err := usecase.Update(id, userID, petUpdateDto) + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + input dto.PetUpdateDto + petId string + userId string + expectOutput error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: petUpdateDto, + petId: id, + userId: userId.String(), + expectOutput: repoError, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("Update", tcase.petId, tcase.userId, entity.PetToEntity((&tcase.input))).Return(tcase.expectOutput) - assert.EqualError(t, err, "failed to update pet with ID 123: error updating vaccines") - mockRepo.AssertExpectations(t) + usecase := NewPetUseCase(tcase.repo) + err := usecase.Update(tcase.petId, tcase.userId, tcase.input) + + assert.EqualError(t, err, "failed to update pet with ID 123: error updating vaccines") + tcase.repo.AssertExpectations(t) + }) + } } func TestUpdateUseCaseValidWeight(t *testing.T) { - usecase := PetUseCase{} + usecase := NewPetUseCase(nil) + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + input *entity.Pet + expectOutput bool + }{ + "success kg": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Weight: 1, WeightMeasure: "kg"}, + expectOutput: true, + }, + "success lb": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Weight: 1, WeightMeasure: "lb"}, + expectOutput: true, + }, + "error kg": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Weight: 0, WeightMeasure: "kg"}, + expectOutput: false, + }, + "error lb": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Weight: 0, WeightMeasure: "lb"}, + expectOutput: false, + }, + "error invalid": { + repo: mockInterfaces.NewMockPetRepository(t), + input: &entity.Pet{Weight: 1, WeightMeasure: "invalid"}, + expectOutput: false, + }, + } - assert.True(t, usecase.isValidWeight(&entity.Pet{Weight: 1, WeightMeasure: "kg"})) - assert.True(t, usecase.isValidWeight(&entity.Pet{Weight: 1, WeightMeasure: "lb"})) - assert.False(t, usecase.isValidWeight(&entity.Pet{Weight: 0, WeightMeasure: "kg"})) - assert.False(t, usecase.isValidWeight(&entity.Pet{Weight: 1, WeightMeasure: "invalid"})) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + value := usecase.isValidWeight(tcase.input) + assert.Equal(t, tcase.expectOutput, value) + }) + } } func TestListUserPets(t *testing.T) { - userID := uniqueEntityId.NewID() + userId := uniqueEntityId.NewID() var availableToAdoption = true expectedPets := []*entity.Pet{ - {ID: uniqueEntityId.NewID(), UserID: userID, Name: "Rex", AvailableToAdoption: &availableToAdoption}, - {ID: uniqueEntityId.NewID(), UserID: userID, Name: "Thor", AvailableToAdoption: &availableToAdoption}, + {ID: uniqueEntityId.NewID(), UserID: userId, Name: "Rex", AvailableToAdoption: &availableToAdoption}, + {ID: uniqueEntityId.NewID(), UserID: userId, Name: "Thor", AvailableToAdoption: &availableToAdoption}, } - mockRepo := mockInterfaces.NewMockPetRepository(t) - defer mockRepo.AssertExpectations(t) + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + userId uuid.UUID + expectOutput []*entity.Pet + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + userId: userId, + expectOutput: expectedPets, + expectedError: nil, + }, + } - mockRepo.On("ListByUser", userID).Return(expectedPets, nil) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("ListByUser", tcase.userId).Return(tcase.expectOutput, tcase.expectedError) - pets, err := usecase.ListUserPets(userID) + usecase := NewPetUseCase(tcase.repo) + pets, err := usecase.ListUserPets(userId) - assert.NoError(t, err) - assert.Len(t, pets, 2) + assert.NoError(t, err) + assert.Len(t, pets, 2) + assert.Equal(t, tcase.expectOutput, pets, "expected error mismatch") + }) + } } func TestListUserPetsNoPetsFound(t *testing.T) { - userID := uniqueEntityId.NewID() - - mockRepo := mockInterfaces.NewMockPetRepository(t) - defer mockRepo.AssertExpectations(t) + userId := uniqueEntityId.NewID() + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + petId uuid.UUID + userId uuid.UUID + expectOutput []*entity.Pet + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + userId: userId, + expectOutput: []*entity.Pet{}, + expectedError: nil, + }, + } - mockRepo.On("ListByUser", userID).Return([]*entity.Pet{}, nil) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("ListByUser", tcase.userId).Return(tcase.expectOutput, tcase.expectedError) - pets, err := usecase.ListUserPets(userID) + usecase := NewPetUseCase(tcase.repo) + pets, err := usecase.ListUserPets(tcase.userId) - assert.NoError(t, err) - assert.Len(t, pets, 0) + assert.NoError(t, err) + assert.Len(t, pets, 0) + assert.Equal(t, tcase.expectOutput, pets, "expected error mismatch") + }) + } } func TestListUserPetsErrorOnRepo(t *testing.T) { - userID := uniqueEntityId.NewID() - - mockRepo := mockInterfaces.NewMockPetRepository(t) - defer mockRepo.AssertExpectations(t) + userId := uniqueEntityId.NewID() + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + petId string + userId uuid.UUID + expectOutput []*entity.Pet + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + userId: userId, + expectOutput: nil, + expectedError: errors.New("this is a repository error"), + }, + } - mockRepo.On("ListByUser", userID).Return([]*entity.Pet{}, errors.New("this is a repository error")) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("ListByUser", tcase.userId).Return(tcase.expectOutput, tcase.expectedError) - pets, err := usecase.ListUserPets(userID) + usecase := NewPetUseCase(tcase.repo) + pets, err := usecase.ListUserPets(tcase.userId) - assert.Error(t, err) - assert.Nil(t, pets) - assert.EqualError(t, err, "failed to retrieve all user pets: this is a repository error") + assert.Error(t, err) + assert.Nil(t, pets) + assert.EqualError(t, err, "failed to retrieve all user pets: this is a repository error") + }) + } } func TestFindByID(t *testing.T) { - ID := uniqueEntityId.NewID() + petId := uniqueEntityId.NewID() var availabelToAdoption = true - expectedPet := &entity.Pet{ID: ID, UserID: uniqueEntityId.NewID(), Name: "Rex", AvailableToAdoption: &availabelToAdoption} - - mockRepo := mockInterfaces.NewMockPetRepository(t) - defer mockRepo.AssertExpectations(t) + expectedPet := &entity.Pet{ID: petId, UserID: uniqueEntityId.NewID(), Name: "Rex", AvailableToAdoption: &availabelToAdoption} + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + petId uuid.UUID + expectOutput *entity.Pet + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + petId: petId, + expectOutput: expectedPet, + expectedError: nil, + }, + } - mockRepo.On("FindByID", ID).Return(expectedPet, nil) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("FindByID", tcase.petId).Return(tcase.expectOutput, tcase.expectedError) - resultPet, err := usecase.FindByID(ID) + usecase := NewPetUseCase(tcase.repo) + pet, err := usecase.FindByID(tcase.petId) - assert.NoError(t, err) - assert.NotNil(t, resultPet) - assert.Equal(t, expectedPet, resultPet) + assert.NoError(t, err) + assert.NotNil(t, pet) + assert.Equal(t, tcase.expectOutput, pet, "expected error mismatch") + }) + } } func TestFindByIDNilResult(t *testing.T) { - petID := uniqueEntityId.NewID() - var pet *entity.Pet - - mockRepo := mockInterfaces.NewMockPetRepository(t) - defer mockRepo.AssertExpectations(t) + petId := uniqueEntityId.NewID() + + expectedPet := &entity.Pet{ID: petId} + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + petId uuid.UUID + expectOutput *entity.Pet + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + petId: petId, + expectOutput: expectedPet, + expectedError: errors.New("sql: no rows in result set"), + }, + } - mockRepo.On("FindByID", petID).Return(pet, errors.New("sql: no rows in result set")) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("FindByID", tcase.petId).Return(tcase.expectOutput, tcase.expectedError) - resultPet, err := usecase.FindByID(petID) + usecase := NewPetUseCase(tcase.repo) + pet, err := usecase.FindByID(tcase.petId) - assert.Error(t, err) - assert.Nil(t, resultPet) - assert.EqualError(t, err, "failed to retrieve pet: sql: no rows in result set") + assert.Error(t, err) + assert.Nil(t, pet) + assert.EqualError(t, err, "failed to retrieve pet: sql: no rows in result set") + }) + } } func TestFindByIDErrorOnRepo(t *testing.T) { - petID := uniqueEntityId.NewID() - var pet *entity.Pet - - mockRepo := mockInterfaces.NewMockPetRepository(t) - defer mockRepo.AssertExpectations(t) + petId := uniqueEntityId.NewID() + + expectedPet := &entity.Pet{ID: petId} + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + petId uuid.UUID + expectOutput *entity.Pet + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + petId: petId, + expectOutput: expectedPet, + expectedError: errors.New("this is a repository error"), + }, + } - mockRepo.On("FindByID", petID).Return(pet, errors.New("this is a repository error")) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("FindByID", petId).Return(tcase.expectOutput, tcase.expectedError) - resultPet, err := usecase.FindByID(petID) + usecase := NewPetUseCase(tcase.repo) + pet, err := usecase.FindByID(tcase.petId) - assert.Error(t, err) - assert.Nil(t, resultPet) - assert.EqualError(t, err, "failed to retrieve pet: this is a repository error") + assert.Error(t, err) + assert.Nil(t, pet) + assert.EqualError(t, err, "failed to retrieve pet: this is a repository error") + }) + } } + func TestPetUseCase_Save(t *testing.T) { birthdateString := "2016/10/21" adoptDateString := "2018/07/29" @@ -237,14 +510,30 @@ func TestPetUseCase_Save(t *testing.T) { AdoptionDate: &adoptDate, } - mockRepo.On("Save", mock.AnythingOfType("*entity.Pet")).Return(nil) + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + input dto.PetInsertDto + expectOutput error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: petToSave, + expectOutput: nil, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("Save", mock.AnythingOfType("*entity.Pet")).Return(tcase.expectOutput) - usecase := NewPetUseCase(mockRepo) - err := usecase.Save(petToSave) + usecase := NewPetUseCase(tcase.repo) + err := usecase.Save(tcase.input) - assert.NoError(t, err) + assert.NoError(t, err) - mockRepo.AssertExpectations(t) + tcase.repo.AssertExpectations(t) + }) + } } func TestPetUseCase_SaveErrorOnRepo(t *testing.T) { @@ -255,7 +544,7 @@ func TestPetUseCase_SaveErrorOnRepo(t *testing.T) { adoptDate, _ := time.Parse(config.StandardDateLayout, adoptDateString) petToSave := dto.PetInsertDto{ - Name: "", + Name: "Felpudo", UserID: uniqueEntityId.NewID(), BreedID: uniqueEntityId.NewID(), Weight: 4, @@ -264,18 +553,29 @@ func TestPetUseCase_SaveErrorOnRepo(t *testing.T) { AdoptionDate: &adoptDate, } - repoError := errors.New("error saving pet") + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + input dto.PetInsertDto + expectOutput error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: petToSave, + expectOutput: errors.New("error saving pet"), + }, + } - mockRepo := new(MockPetRepository) - defer mockRepo.AssertExpectations(t) - - mockRepo.On("Save", mock.AnythingOfType("*entity.Pet")).Return(repoError) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("Save", mock.AnythingOfType("*entity.Pet")).Return(tcase.expectOutput) - err := usecase.Save(petToSave) + usecase := NewPetUseCase(tcase.repo) + err := usecase.Save(tcase.input) - assert.EqualError(t, err, "failed to save pet: error saving pet") - mockRepo.AssertExpectations(t) + assert.EqualError(t, err, "failed to save pet: error saving pet") + tcase.repo.AssertExpectations(t) + }) + } } func TestListPetsUnauthenticated(t *testing.T) { @@ -295,54 +595,112 @@ func TestListPetsUnauthenticated(t *testing.T) { {ID: uniqueEntityId.NewID(), UserID: userID, Name: "Docinho", AvailableToAdoption: &availableToAdoption}, } - expectedPets := allPets[:len(allPets)-1] - - mockRepo := new(MockPetRepository) - defer mockRepo.AssertExpectations(t) + expectedPets := allPets[:6] + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + expectOutput []*entity.Pet + input int + isUnauthorized bool + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: 1, + isUnauthorized: isUnauthorized, + expectOutput: expectedPets, + expectedError: nil, + }, + } - mockRepo.On("ListAllByPage", 1).Return(expectedPets, nil) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("ListAllByPage", tcase.input).Return(tcase.expectOutput, tcase.expectedError) - pets, err := usecase.ListPetsByPage(1, isUnauthorized) + usecase := NewPetUseCase(tcase.repo) + pets, err := usecase.ListPetsByPage(tcase.input, tcase.isUnauthorized) - assert.NoError(t, err) - assert.Len(t, pets, 6) + assert.NoError(t, err) + assert.Len(t, pets, 6) + assert.Equal(t, tcase.expectOutput, pets) + }) + } } func TestListPetsUnauthenticatedNoPets(t *testing.T) { isUnauthorized := true - mockRepo := new(MockPetRepository) - defer mockRepo.AssertExpectations(t) + expectedPets := []*entity.Pet{} + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + expectOutput []*entity.Pet + input int + isUnauthorized bool + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: 1, + isUnauthorized: isUnauthorized, + expectOutput: expectedPets, + expectedError: nil, + }, + } - mockRepo.On("ListAllByPage", 1).Return([]*entity.Pet{}, nil) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("ListAllByPage", tcase.input).Return(tcase.expectOutput, tcase.expectedError) - pets, err := usecase.ListPetsByPage(1, isUnauthorized) + usecase := NewPetUseCase(tcase.repo) + pets, err := usecase.ListPetsByPage(tcase.input, tcase.isUnauthorized) - assert.NoError(t, err) - assert.Len(t, pets, 0) + assert.NoError(t, err) + assert.Len(t, pets, 0) + assert.Equal(t, tcase.expectOutput, pets) + }) + } } func TestListPetsUnauthenticatedErrorOnRepo(t *testing.T) { - mockRepo := new(MockPetRepository) - defer mockRepo.AssertExpectations(t) - isUnauthorized := true - mockRepo.On("ListAllByPage", 1).Return([]*entity.Pet{}, errors.New("repository error")) - usecase := NewPetUseCase(mockRepo) + expectedPets := []*entity.Pet{} + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + expectOutput []*entity.Pet + input int + isUnauthorized bool + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: 1, + isUnauthorized: isUnauthorized, + expectOutput: expectedPets, + expectedError: errors.New("repository error"), + }, + } - pets, err := usecase.ListPetsByPage(1, isUnauthorized) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("ListAllByPage", tcase.input).Return(tcase.expectOutput, tcase.expectedError) - assert.Error(t, err) - assert.Len(t, pets, 0) - assert.EqualError(t, err, "failed to retrieve all user pets: repository error") + usecase := NewPetUseCase(tcase.repo) + pets, err := usecase.ListPetsByPage(tcase.input, tcase.isUnauthorized) + + assert.Error(t, err) + assert.Len(t, pets, 0) + assert.EqualError(t, err, "failed to retrieve all user pets: repository error") + }) + } } func TestListPetsAuthenticated(t *testing.T) { userID := uniqueEntityId.NewID() + isUnauthorized := false var availableToAdoption = true allPets := []*entity.Pet{ {ID: uniqueEntityId.NewID(), UserID: userID, Name: "Rex", AvailableToAdoption: &availableToAdoption}, @@ -360,49 +718,106 @@ func TestListPetsAuthenticated(t *testing.T) { {ID: uniqueEntityId.NewID(), UserID: userID, Name: "Dogão", AvailableToAdoption: &availableToAdoption}, } - expectedPets := allPets[:len(allPets)-1] - isUnauthorized := false - - mockRepo := new(MockPetRepository) - defer mockRepo.AssertExpectations(t) + expectedPets := allPets[:12] + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + expectOutput []*entity.Pet + input int + isUnauthorized bool + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: 1, + isUnauthorized: isUnauthorized, + expectOutput: expectedPets, + expectedError: nil, + }, + } - mockRepo.On("ListAllByPage", 1).Return(expectedPets, nil) - usecase := NewPetUseCase(mockRepo) + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("ListAllByPage", tcase.input).Return(tcase.expectOutput, tcase.expectedError) - pets, err := usecase.ListPetsByPage(1, isUnauthorized) + usecase := NewPetUseCase(tcase.repo) + pets, err := usecase.ListPetsByPage(tcase.input, tcase.isUnauthorized) - assert.NoError(t, err) - assert.Len(t, pets, 12) - assert.Equal(t, pets, expectedPets) + assert.NoError(t, err) + assert.Len(t, pets, 12) + assert.Equal(t, tcase.expectOutput, pets) + }) + } } func TestListPetsAuthenticatedNoPets(t *testing.T) { isUnauthorized := false - mockRepo := new(MockPetRepository) - defer mockRepo.AssertExpectations(t) - mockRepo.On("ListAllByPage", 1).Return([]*entity.Pet{}, nil) - usecase := NewPetUseCase(mockRepo) + expectedPets := []*entity.Pet{} + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + expectOutput []*entity.Pet + input int + isUnauthorized bool + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: 1, + isUnauthorized: isUnauthorized, + expectOutput: expectedPets, + expectedError: nil, + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("ListAllByPage", tcase.input).Return(tcase.expectOutput, tcase.expectedError) - pets, err := usecase.ListPetsByPage(1, isUnauthorized) + usecase := NewPetUseCase(tcase.repo) + pets, err := usecase.ListPetsByPage(tcase.input, tcase.isUnauthorized) - assert.NoError(t, err) - assert.Len(t, pets, 0) + assert.NoError(t, err) + assert.Len(t, pets, 0) + assert.Equal(t, tcase.expectOutput, pets) + }) + } } func TestListPetsAuthenticatedErrorOnRepo(t *testing.T) { isUnauthorized := false - mockRepo := new(MockPetRepository) - defer mockRepo.AssertExpectations(t) - mockRepo.On("ListAllByPage", 1).Return([]*entity.Pet{}, errors.New("repository error")) - usecase := NewPetUseCase(mockRepo) + expectedPets := []*entity.Pet{} + + tcases := map[string]struct { + repo *mockInterfaces.MockPetRepository + expectOutput []*entity.Pet + input int + isUnauthorized bool + expectedError error + }{ + "success": { + repo: mockInterfaces.NewMockPetRepository(t), + input: 1, + isUnauthorized: isUnauthorized, + expectOutput: expectedPets, + expectedError: errors.New("repository error"), + }, + } + + for name, tcase := range tcases { + t.Run(name, func(t *testing.T) { + tcase.repo.On("ListAllByPage", tcase.input).Return(tcase.expectOutput, tcase.expectedError) - pets, err := usecase.ListPetsByPage(1, isUnauthorized) + usecase := NewPetUseCase(tcase.repo) + pets, err := usecase.ListPetsByPage(tcase.input, tcase.isUnauthorized) - assert.Error(t, err) - assert.Len(t, pets, 0) - assert.EqualError(t, err, "failed to retrieve pets page: repository error") -} \ No newline at end of file + assert.Error(t, err) + assert.Len(t, pets, 0) + assert.EqualError(t, err, "failed to retrieve pets page: repository error") + }) + } +} diff --git a/usecase/user.go b/usecase/user.go index 28e0f0fa..01c5c1da 100644 --- a/usecase/user.go +++ b/usecase/user.go @@ -2,7 +2,6 @@ package usecase import ( "errors" - "fmt" "pet-dex-backend/v2/entity" "pet-dex-backend/v2/entity/dto" "pet-dex-backend/v2/infra/config" @@ -92,37 +91,6 @@ func (uc *UserUsecase) Update(userID uniqueEntityId.ID, userDto dto.UserUpdateDt } -func (uc *UserUsecase) FindByID(ID uniqueEntityId.ID) (*entity.User, error) { - user, err := uc.repo.FindByID(ID) - - if err != nil { - uc.logger.Error("error finding user by id:", err) - return nil, err - } - - address, err := uc.repo.FindAddressByUserID(user.ID) - - if err != nil { - uc.logger.Error("error finding user address:", err) - return nil, err - } - - user.Adresses = *address - - return user, nil -} - -func (uc *UserUsecase) Delete(userID uniqueEntityId.ID) error { - err := uc.repo.Delete(userID) - - if err != nil { - uc.logger.Error(fmt.Errorf("#UserUsecase.Delete error: %w", err)) - return err - } - - return nil -} - func (uc *UserUsecase) FindByEmail(email string) (*entity.User, error) { user, err := uc.repo.FindByEmail(email) @@ -165,17 +133,6 @@ func (uc *UserUsecase) Delete(userID uniqueEntityId.ID) error { return nil } -func (uc *UserUsecase) FindByEmail(email string) (*entity.User, error) { - user, err := uc.repo.FindByEmail(email) - - if err != nil { - uc.logger.Error("error finding user by email:", err) - return nil, err - } - - return user, nil -} - func (uc *UserUsecase) ChangePassword(userChangePasswordDto dto.UserChangePasswordDto, userId uniqueEntityId.ID) error { user, err := uc.repo.FindByID(userId) if err != nil { @@ -200,3 +157,24 @@ func (uc *UserUsecase) ChangePassword(userChangePasswordDto dto.UserChangePasswo } return nil } + +func (uc *UserUsecase) UpdatePushNotificationSettings(userID uniqueEntityId.ID, userPushNotificationEnabled dto.UserPushNotificationEnabled) error { + user, err := uc.repo.FindByID(userID) + + if err != nil { + uc.logger.Error("error finding user by id: ", err) + return errors.New("user dont exists") + } + + user.PushNotificationsEnabled = &userPushNotificationEnabled.PushNotificationEnabled + + err = uc.repo.Update(userID, *user) + + if err != nil { + uc.logger.Error("error updating user by id: ", err) + return errors.New("error on updating push notification") + } + + return nil + +}