package service import ( "errors" "github.com/stretchr/testify/assert" "go.uber.org/mock/gomock" "testing" "time" "git.urec56.ru/urec/chat_back_go/internal/domain" mock_logger "git.urec56.ru/urec/chat_back_go/internal/logger/mocks" mock_repository "git.urec56.ru/urec/chat_back_go/internal/repository/mocks" mock_service "git.urec56.ru/urec/chat_back_go/internal/service/mocks" ) func Test_newUserService(t *testing.T) { c := gomock.NewController(t) defer c.Finish() repo := mock_repository.NewMockUser(c) auth := mock_service.NewMockAuth(c) log := mock_logger.NewMockLog(c) serv := newUserService(repo, auth, log) assert.Equal(t, &userService{ur: repo, auth: auth, l: log}, serv) } func TestUserService_Get(t *testing.T) { type mockBehavior func(r *mock_repository.MockUser, userID int, user domain.User, err error) testTable := []struct { name string mockBehavior mockBehavior userID int expectedUser domain.User repoErr error expectedErr error }{ { name: "ok", mockBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) { r.EXPECT().GetByID(userID).Return(user, err) }, userID: 1, expectedUser: domain.User{ ID: 1, }, }, { name: "user_not_found", mockBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) { r.EXPECT().GetByID(userID).Return(user, err) }, repoErr: domain.UserNotFoundError, expectedErr: domain.UserNotFoundError, }, { name: "internal_error", mockBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) { r.EXPECT().GetByID(userID).Return(user, err) }, repoErr: domain.InternalServerError, expectedErr: domain.InternalServerError, }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { c := gomock.NewController(t) defer c.Finish() repo := mock_repository.NewMockUser(c) serv := userService{ur: repo} tc.mockBehavior(repo, tc.userID, tc.expectedUser, tc.repoErr) u, err := serv.Get(tc.userID) assert.Equal(t, tc.expectedUser, u) assert.ErrorIs(t, err, tc.expectedErr) }) } } func TestUserService_GetVerificated(t *testing.T) { type mockBehavior func(r *mock_repository.MockUser, userID int, user domain.User, err error) testTable := []struct { name string mockBehavior mockBehavior userID int expectedUser domain.User repoErr error expectedErr error }{ { name: "ok", mockBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) { r.EXPECT().GetByID(userID).Return(user, err) }, userID: 1, expectedUser: domain.User{ ID: 1, Role: domain.VerificatedUser, }, }, { name: "user_not_found", mockBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) { r.EXPECT().GetByID(userID).Return(user, err) }, userID: 1, repoErr: domain.UserNotFoundError, expectedErr: domain.UserNotFoundError, }, { name: "user_unverified", mockBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) { r.EXPECT().GetByID(userID).Return(user, err) }, userID: 1, expectedUser: domain.User{ ID: 1, Role: domain.UnverifiedUser, }, expectedErr: domain.UnverifiedUserError, }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { c := gomock.NewController(t) defer c.Finish() repo := mock_repository.NewMockUser(c) serv := userService{ur: repo} tc.mockBehavior(repo, tc.userID, tc.expectedUser, tc.repoErr) u, err := serv.GetVerificated(tc.userID) assert.Equal(t, tc.expectedUser, u) assert.ErrorIs(t, err, tc.expectedErr) }) } } func TestUserService_GetAll(t *testing.T) { type mockBehavior func(r *mock_repository.MockUser, username string, users []domain.User, err error) testTable := []struct { name string mockBehavior mockBehavior username string expectedUsers []domain.User repoErr error expectedErr error }{ { name: "ok", mockBehavior: func(r *mock_repository.MockUser, username string, users []domain.User, err error) { r.EXPECT().GetAll(username).Return(users, err) }, expectedUsers: []domain.User{ {ID: 1}, }, }, { name: "internal_error", mockBehavior: func(r *mock_repository.MockUser, username string, users []domain.User, err error) { r.EXPECT().GetAll(username).Return(users, err) }, repoErr: domain.InternalServerError, expectedErr: domain.InternalServerError, }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { c := gomock.NewController(t) defer c.Finish() repo := mock_repository.NewMockUser(c) serv := userService{ur: repo} tc.mockBehavior(repo, tc.username, tc.expectedUsers, tc.repoErr) u, err := serv.GetAll(tc.username) assert.Equal(t, tc.expectedUsers, u) assert.ErrorIs(t, err, tc.expectedErr) }) } } func TestUserService_FindOne(t *testing.T) { type mockBehavior func(r *mock_repository.MockUser, username, email string, user domain.User, err error) testTable := []struct { name string mockBehavior mockBehavior username string email string expectedUser domain.User repoErr error expectedErr error }{ { name: "ok", mockBehavior: func(r *mock_repository.MockUser, username, email string, user domain.User, err error) { r.EXPECT().FindOne(username, email).Return(user, err) }, expectedUser: domain.User{ ID: 1, Role: domain.UnverifiedUser, }, }, { name: "any_error", mockBehavior: func(r *mock_repository.MockUser, username, email string, user domain.User, err error) { r.EXPECT().FindOne(username, email).Return(user, err) }, repoErr: errors.New("some error"), expectedErr: domain.InternalServerError, }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { c := gomock.NewController(t) defer c.Finish() repo := mock_repository.NewMockUser(c) serv := userService{ur: repo} tc.mockBehavior(repo, tc.username, tc.email, tc.expectedUser, tc.repoErr) u, err := serv.FindOne(tc.username, tc.email) assert.Equal(t, tc.expectedUser, u) assert.ErrorIs(t, err, tc.expectedErr) }) } } func TestUserService_Register(t *testing.T) { type hashMockBehavior func(s *mock_service.MockAuth, p, hp string, err error) type repoMockBehavior func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) type encodeMockBehavior func(s *mock_service.MockAuth, userID int, token string, err error) testTable := []struct { name string hashMockBehavior hashMockBehavior repoMockBehavior repoMockBehavior encodeMockBehavior encodeMockBehavior ud domain.UserRegister hp string repoUser domain.User hashErr error repoErr error encodeErr error expectedToken string expectedErr error }{ { name: "ok", hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) { s.EXPECT().HashPassword(p).Return(hp, err) }, repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) { r.EXPECT().Register(email, hp, username, dateOfBirth).Return(user, err) }, encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) { s.EXPECT().EncodeAuthToken(userID).Return(token, err) }, ud: domain.UserRegister{ Email: "mail@mail.ru", Username: "username", Password: "pass", }, hp: "hp", repoUser: domain.User{ID: 1}, expectedToken: "token", }, { name: "user_already_exists", hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) { s.EXPECT().HashPassword(p).Return(hp, err) }, repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) { r.EXPECT().Register(email, hp, username, dateOfBirth).Return(user, err) }, encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) {}, repoErr: domain.UserAlreadyExistsError, expectedErr: domain.UserAlreadyExistsError, }, { name: "hash_failed", hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) { s.EXPECT().HashPassword(p).Return(hp, err) }, repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) { }, encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) {}, hashErr: errors.New("some error"), expectedErr: domain.InternalServerError, }, { name: "db_error", hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) { s.EXPECT().HashPassword(p).Return(hp, err) }, repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) { r.EXPECT().Register(email, hp, username, dateOfBirth).Return(user, err) }, encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) {}, repoErr: errors.New("some error"), expectedErr: domain.InternalServerError, }, { name: "token_encoding_error", hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) { s.EXPECT().HashPassword(p).Return(hp, err) }, repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) { r.EXPECT().Register(email, hp, username, dateOfBirth).Return(user, err) }, encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) { s.EXPECT().EncodeAuthToken(userID).Return(token, err) }, encodeErr: errors.New("some error"), expectedErr: domain.InternalServerError, }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { c := gomock.NewController(t) defer c.Finish() repo := mock_repository.NewMockUser(c) auth := mock_service.NewMockAuth(c) log := mock_logger.NewMockLog(c) serv := userService{ur: repo, auth: auth, l: log} tc.hashMockBehavior(auth, tc.ud.Password, tc.hp, tc.hashErr) tc.repoMockBehavior(repo, tc.ud.Email, tc.hp, tc.ud.Username, tc.ud.DateOfBirth.Time, tc.repoUser, tc.repoErr) tc.encodeMockBehavior(auth, tc.repoUser.ID, tc.expectedToken, tc.encodeErr) token, err := serv.Register(tc.ud) assert.Equal(t, tc.expectedToken, token) assert.ErrorIs(t, err, tc.expectedErr) }) } }