1//go:build unit
2
3package auth
4
5import (
6 "context"
7 "errors"
8 "testing"
9
10 "github.com/samber/lo"
11
12 "git.sr.ht/~gabrielgio/img/pkg/ext"
13 "git.sr.ht/~gabrielgio/img/pkg/testkit"
14)
15
16type (
17 scene struct {
18 ctx context.Context
19 mockRepository *MockUserRepository
20 controller Controller
21 }
22
23 mockUser struct {
24 id uint
25 username string
26 password []byte
27 }
28
29 MockUserRepository struct {
30 index uint
31 users []*mockUser
32 err error
33 }
34)
35
36var (
37 _ Repository = &MockUserRepository{}
38 key = []byte("6368616e676520746869732070617373")
39)
40
41func setUp() *scene {
42 mockUserRepository := &MockUserRepository{}
43 return &scene{
44 ctx: context.Background(),
45 mockRepository: mockUserRepository,
46 controller: *NewController(mockUserRepository, key),
47 }
48}
49
50func TestRegisterAndLogin(t *testing.T) {
51 testCases := []struct {
52 name string
53 username string
54 password []byte
55 }{
56 {
57 name: "Normal register",
58 username: "username",
59 password: []byte("password"),
60 },
61 }
62
63 for _, tc := range testCases {
64 t.Run(tc.name, func(t *testing.T) {
65 scene := setUp()
66
67 err := scene.controller.Register(scene.ctx, []byte(tc.username), tc.password)
68 testkit.TestFatalError(t, "Register", err)
69
70 userID := scene.mockRepository.GetLastId()
71
72 user, err := scene.mockRepository.Get(scene.ctx, userID)
73 testkit.TestFatalError(t, "Get", err)
74 testkit.TestValue(t, "Register", tc.username, user.Username)
75
76 auth, err := scene.controller.Login(scene.ctx, []byte(tc.username), tc.password)
77 testkit.TestFatalError(t, "Login", err)
78
79 token, err := ext.ReadToken(auth, key)
80 testkit.TestFatalError(t, "Login", err)
81
82 testkit.TestValue(t, "Login", tc.username, token.Username)
83 testkit.TestValue(t, "Login", userID, token.UserID)
84 })
85 }
86}
87
88func toUser(m *mockUser, _ int) *User {
89 return &User{
90 ID: m.id,
91 Username: m.username,
92 }
93}
94
95func (m *MockUserRepository) GetLastId() uint {
96 return m.index
97}
98
99func (m *MockUserRepository) List(ctx context.Context) ([]*User, error) {
100 if m.err != nil {
101 return nil, m.err
102 }
103
104 return lo.Map(m.users, toUser), nil
105}
106
107func (m *MockUserRepository) Get(ctx context.Context, id uint) (*User, error) {
108 if m.err != nil {
109 return nil, m.err
110 }
111
112 for _, m := range m.users {
113 if m.id == id {
114 return toUser(m, 0), nil
115 }
116 }
117 return nil, errors.New("Item not found")
118}
119
120func (m *MockUserRepository) GetIDByUsername(ctx context.Context, username string) (uint, error) {
121 if m.err != nil {
122 return 0, m.err
123 }
124
125 for _, m := range m.users {
126 if m.username == username {
127 return m.id, nil
128 }
129 }
130 return 0, errors.New("Item not found")
131}
132
133func (m *MockUserRepository) GetPassword(ctx context.Context, id uint) ([]byte, error) {
134 if m.err != nil {
135 return nil, m.err
136 }
137
138 for _, m := range m.users {
139 if m.id == id {
140 return m.password, nil
141 }
142 }
143 return nil, errors.New("Item not found")
144}
145
146func (m *MockUserRepository) Create(ctx context.Context, createUser *CreateUser) (uint, error) {
147 if m.err != nil {
148 return 0, m.err
149 }
150
151 m.index++
152
153 m.users = append(m.users, &mockUser{
154 id: m.index,
155 username: createUser.Username,
156 password: createUser.Password,
157 })
158
159 return m.index, nil
160}
161
162func (m *MockUserRepository) Update(ctx context.Context, id uint, update *UpdateUser) error {
163 if m.err != nil {
164 return m.err
165 }
166
167 for _, m := range m.users {
168 if m.id == id {
169 m.username = update.Username
170 }
171 }
172 return nil
173}
174
175func remove[T any](slice []T, s int) []T {
176 return append(slice[:s], slice[s+1:]...)
177}
178
179func (r *MockUserRepository) Delete(ctx context.Context, id uint) error {
180 if r.err != nil {
181 return r.err
182 }
183
184 for i, m := range r.users {
185 if m.id == id {
186 r.users = remove(r.users, i)
187 }
188 }
189 return nil
190}