package auth import ( "context" "errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "tercul/internal/domain" "testing" ) type AuthCommandsSuite struct { suite.Suite userRepo *mockUserRepository jwtManager *mockJWTManager commands *AuthCommands } func (s *AuthCommandsSuite) SetupTest() { s.userRepo = newMockUserRepository() s.jwtManager = &mockJWTManager{} s.commands = NewAuthCommands(s.userRepo, s.jwtManager) } func TestAuthCommandsSuite(t *testing.T) { suite.Run(t, new(AuthCommandsSuite)) } func (s *AuthCommandsSuite) TestLogin_Success() { user := domain.User{ Email: "test@example.com", Password: "password", Active: true, } s.userRepo.Create(context.Background(), &user) input := LoginInput{Email: "test@example.com", Password: "password"} resp, err := s.commands.Login(context.Background(), input) assert.NoError(s.T(), err) assert.NotNil(s.T(), resp) assert.Equal(s.T(), "test-token", resp.Token) assert.Equal(s.T(), user.ID, resp.User.ID) } func (s *AuthCommandsSuite) TestLogin_InvalidInput() { input := LoginInput{Email: "invalid-email", Password: "short"} resp, err := s.commands.Login(context.Background(), input) assert.Error(s.T(), err) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestValidateLoginInput_EmptyEmail() { input := LoginInput{Email: "", Password: "password"} err := validateLoginInput(input) assert.Error(s.T(), err) } func (s *AuthCommandsSuite) TestValidateLoginInput_ShortPassword() { input := LoginInput{Email: "test@example.com", Password: "short"} err := validateLoginInput(input) assert.Error(s.T(), err) } func (s *AuthCommandsSuite) TestValidateRegisterInput_ShortPassword() { input := RegisterInput{Email: "test@example.com", Password: "short"} err := validateRegisterInput(input) assert.Error(s.T(), err) } func (s *AuthCommandsSuite) TestValidateRegisterInput_ShortUsername() { input := RegisterInput{Username: "a", Email: "test@example.com", Password: "password"} err := validateRegisterInput(input) assert.Error(s.T(), err) } func (s *AuthCommandsSuite) TestValidateRegisterInput_LongUsername() { input := RegisterInput{Username: "a51characterusernameisdefinitelytoolongforthisvalidation", Email: "test@example.com", Password: "password"} err := validateRegisterInput(input) assert.Error(s.T(), err) } func (s *AuthCommandsSuite) TestLogin_SuccessUpdate() { user := domain.User{ Email: "test@example.com", Password: "password", Active: true, } s.userRepo.Create(context.Background(), &user) s.userRepo.updateFunc = func(ctx context.Context, user *domain.User) error { return nil } input := LoginInput{Email: "test@example.com", Password: "password"} resp, err := s.commands.Login(context.Background(), input) assert.NoError(s.T(), err) assert.NotNil(s.T(), resp) } func (s *AuthCommandsSuite) TestRegister_InvalidEmail() { input := RegisterInput{ Username: "newuser", Email: "invalid-email", Password: "password", FirstName: "New", LastName: "User", } resp, err := s.commands.Register(context.Background(), input) assert.Error(s.T(), err) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestLogin_UpdateUserError() { user := domain.User{ Email: "test@example.com", Password: "password", Active: true, } s.userRepo.Create(context.Background(), &user) s.userRepo.updateFunc = func(ctx context.Context, user *domain.User) error { return errors.New("update error") } input := LoginInput{Email: "test@example.com", Password: "password"} resp, err := s.commands.Login(context.Background(), input) assert.NoError(s.T(), err) assert.NotNil(s.T(), resp) } func (s *AuthCommandsSuite) TestRegister_InvalidUsername() { input := RegisterInput{ Username: "invalid username", Email: "new@example.com", Password: "password", FirstName: "New", LastName: "User", } resp, err := s.commands.Register(context.Background(), input) assert.Error(s.T(), err) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestLogin_UserNotFound() { input := LoginInput{Email: "notfound@example.com", Password: "password"} resp, err := s.commands.Login(context.Background(), input) assert.ErrorIs(s.T(), err, ErrInvalidCredentials) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestLogin_InactiveUser() { user := domain.User{ Email: "inactive@example.com", Password: "password", Active: false, } s.userRepo.Create(context.Background(), &user) input := LoginInput{Email: "inactive@example.com", Password: "password"} resp, err := s.commands.Login(context.Background(), input) assert.ErrorIs(s.T(), err, ErrInvalidCredentials) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestLogin_InvalidPassword() { user := domain.User{ Email: "test@example.com", Password: "password", Active: true, } s.userRepo.Create(context.Background(), &user) input := LoginInput{Email: "test@example.com", Password: "wrong-password"} resp, err := s.commands.Login(context.Background(), input) assert.ErrorIs(s.T(), err, ErrInvalidCredentials) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestLogin_TokenGenerationError() { user := domain.User{ Email: "test@example.com", Password: "password", Active: true, } s.userRepo.Create(context.Background(), &user) s.jwtManager.generateTokenFunc = func(user *domain.User) (string, error) { return "", errors.New("jwt error") } input := LoginInput{Email: "test@example.com", Password: "password"} resp, err := s.commands.Login(context.Background(), input) assert.Error(s.T(), err) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestRegister_Success() { input := RegisterInput{ Username: "newuser", Email: "new@example.com", Password: "password", FirstName: "New", LastName: "User", } resp, err := s.commands.Register(context.Background(), input) assert.NoError(s.T(), err) assert.NotNil(s.T(), resp) assert.Equal(s.T(), "test-token", resp.Token) assert.Equal(s.T(), "newuser", resp.User.Username) } func (s *AuthCommandsSuite) TestRegister_InvalidInput() { input := RegisterInput{Email: "invalid"} resp, err := s.commands.Register(context.Background(), input) assert.Error(s.T(), err) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestRegister_EmailExists() { user := domain.User{ Email: "exists@example.com", } s.userRepo.Create(context.Background(), &user) input := RegisterInput{ Username: "newuser", Email: "exists@example.com", Password: "password", FirstName: "New", LastName: "User", } resp, err := s.commands.Register(context.Background(), input) assert.ErrorIs(s.T(), err, ErrUserAlreadyExists) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestRegister_UsernameExists() { user := domain.User{ Username: "exists", } s.userRepo.Create(context.Background(), &user) input := RegisterInput{ Username: "exists", Email: "new@example.com", Password: "password", FirstName: "New", LastName: "User", } resp, err := s.commands.Register(context.Background(), input) assert.ErrorIs(s.T(), err, ErrUserAlreadyExists) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestRegister_CreateUserError() { s.userRepo.createFunc = func(ctx context.Context, user *domain.User) error { return errors.New("db error") } input := RegisterInput{ Username: "newuser", Email: "new@example.com", Password: "password", FirstName: "New", LastName: "User", } resp, err := s.commands.Register(context.Background(), input) assert.Error(s.T(), err) assert.Nil(s.T(), resp) } func (s *AuthCommandsSuite) TestRegister_TokenGenerationError() { s.jwtManager.generateTokenFunc = func(user *domain.User) (string, error) { return "", errors.New("jwt error") } input := RegisterInput{ Username: "newuser", Email: "new@example.com", Password: "password", FirstName: "New", LastName: "User", } resp, err := s.commands.Register(context.Background(), input) assert.Error(s.T(), err) assert.Nil(s.T(), resp) }