// Copyright 2026 Mihna123 Software // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. package user import ( "errors" "log/slog" "os" "testing" "golang.org/x/crypto/bcrypt" ) func TestMain(m *testing.M) { slog.SetDefault(slog.New(slog.DiscardHandler)) os.Exit(m.Run()) } func newTestUserService(t *testing.T) *Service { t.Helper() return &Service{repository: newEmptyRepository(), bcryptCost: bcrypt.MinCost} } func TestRegisterInputValidateFaultyData(t *testing.T) { badInputs := getInvalidRegisterInputs() for name, in := range badInputs { t.Run(name, func(t *testing.T) { err := in.validate() if err == nil { t.Errorf("bad input got through: %+v", in) } if !errors.Is(err, ErrInvalidInput) { t.Errorf("unexpected error: got %v, want ErrInvalidInput", err) } }) } } func TestRegisterBadInput(t *testing.T) { in := &RegisterInput{} s := newTestUserService(t) _, err := s.Register(in) if err == nil { t.Error("no error when registering with faulty input") } if !errors.Is(err, ErrInvalidInput) { t.Errorf("unexpected error: got %v, want ErrInvalidInput", err) } } func TestRegisterExistingUser(t *testing.T) { badInputs := map[string]RegisterInput{ "existing username": { Username: "johnsmith", Email: "thisemaildoesnt@exist.com", Phone: "123321", Password: "22332233", }, "existing email": { Username: "thisusernamedoesntexist", Email: "janedoe@email.com", Phone: "123321", Password: "22332233", }, } for name, in := range badInputs { t.Run(name, func(t *testing.T) { r := newEmptyRepository() r.fill() s := &Service{repository: r, bcryptCost: bcrypt.MinCost} _, err := s.Register(&in) if err == nil { t.Error("existing user registered") } if !errors.Is(err, ErrUserExists) { t.Errorf("unexpected error: got %v, want ErrUserExists", err) } }) } } func TestRegisterRepositoryError(t *testing.T) { s := &Service{ repository: &RepositoryMock{err: errors.New("db down")}, bcryptCost: bcrypt.MinCost, } in := &RegisterInput{Username: "bob", Email: "b@b.com", Password: "thisissecure"} _, err := s.Register(in) if err == nil { t.Error("register swallowed repository error") } if errors.Is(err, ErrUserExists) { t.Error("repository failure reported as ErrUserExists") } } func TestSuccessfulRegister(t *testing.T) { s := newTestUserService(t) in := &RegisterInput{ Username: "happyuser123", Email: "happyuser@email.com", Phone: "+381233232", Password: "supersecretpassword1234", } usr, err := s.Register(in) if err != nil { t.Fatalf("register with good input failed: %+v", in) } err = bcrypt.CompareHashAndPassword([]byte(usr.passwordHash), []byte(in.Password)) if err != nil { t.Errorf("hash and password compare error: %v", err) } } func TestRegisterSameUserTwice(t *testing.T) { s := newTestUserService(t) in := &RegisterInput{ Username: "happyuser123", Email: "happyuser@email.com", Phone: "+381233232", Password: "supersecretpassword1234", } if _, err := s.Register(in); err != nil { t.Fatalf("first register failed: %v", err) } _, err := s.Register(in) if err == nil { t.Errorf("registered same user twice: %+v", in) } if !errors.Is(err, ErrUserExists) { t.Errorf("unexpected error: got %v, want ErrUserExists", err) } }