1package norm
2
3import (
4 "database/sql"
5 "testing"
6 "time"
7
8 _ "github.com/mattn/go-sqlite3"
9)
10
11type User struct {
12 ID int
13 Name string
14 Age int
15 Email string
16 Department sql.NullString
17 Active bool
18 Salary sql.NullFloat64
19 CreatedAt time.Time
20}
21
22type UserBasic struct {
23 ID int
24 Name string
25 Email string
26}
27
28type Department struct {
29 ID int
30 Name string
31 Budget float64
32}
33
34type SimpleStruct struct {
35 Value int
36}
37
38func TestScannerWithDepartments(t *testing.T) {
39 db := setupTestDB(t)
40 defer db.Close()
41
42 rows, err := db.Query("SELECT id, name, budget FROM departments ORDER BY id")
43 if err != nil {
44 t.Fatalf("Failed to query departments: %v", err)
45 }
46
47 var departments []Department
48 err = ScanAll(rows, &departments)
49 if err != nil {
50 t.Fatalf("Failed to scan departments: %v", err)
51 }
52
53 if len(departments) != 3 {
54 t.Errorf("Expected 3 departments, got %d", len(departments))
55 }
56
57 d1 := departments[0]
58 if d1.ID != 1 || d1.Name != "Engineering" || d1.Budget != 500000.0 {
59 t.Errorf("Engineering department data incorrect: %+v", d1)
60 }
61
62 d2 := departments[1]
63 if d2.ID != 2 || d2.Name != "Marketing" || d2.Budget != 300000.0 {
64 t.Errorf("Marketing department data incorrect: %+v", d2)
65 }
66}
67
68func TestScannerBasicFunctionality(t *testing.T) {
69 db := setupTestDB(t)
70 defer db.Close()
71
72 rows, err := db.Query("SELECT id, name, email FROM users ORDER BY id")
73 if err != nil {
74 t.Fatalf("Failed to query users: %v", err)
75 }
76
77 var users []UserBasic
78 err = ScanAll(rows, &users)
79 if err != nil {
80 t.Fatalf("Failed to scan users: %v", err)
81 }
82
83 if len(users) != 6 {
84 t.Errorf("Expected 6 users, got %d", len(users))
85 }
86
87 if users[0].ID != 1 || users[0].Name != "John Doe" || users[0].Email != "john@example.com" {
88 t.Errorf("Expected first user to be John Doe, got %+v", users[0])
89 }
90
91 if users[5].Name != "Diana Prince" || users[5].Email != "diana@example.com" {
92 t.Errorf("Expected last user to be Diana Prince, got %+v", users[5])
93 }
94}
95
96func TestScannerWithAllFields(t *testing.T) {
97 db := setupTestDB(t)
98 defer db.Close()
99
100 rows, err := db.Query("SELECT id, name, age, email, department, active, salary, created_at FROM users ORDER BY id")
101 if err != nil {
102 t.Fatalf("Failed to query users: %v", err)
103 }
104
105 var users []User
106 err = ScanAll(rows, &users)
107 if err != nil {
108 t.Fatalf("Failed to scan users: %v", err)
109 }
110
111 if len(users) != 6 {
112 t.Errorf("Expected 6 users, got %d", len(users))
113 }
114
115 u1 := users[0]
116 if u1.ID != 1 || u1.Name != "John Doe" || u1.Age != 30 || u1.Email != "john@example.com" || !u1.Active {
117 t.Errorf("User 1 basic data incorrect: %+v", u1)
118 }
119 if !u1.Department.Valid || u1.Department.String != "Engineering" {
120 t.Errorf("User 1 department incorrect: %v", u1.Department)
121 }
122 if !u1.Salary.Valid || u1.Salary.Float64 != 75000.0 {
123 t.Errorf("User 1 salary incorrect: %v", u1.Salary)
124 }
125
126 u3 := users[2]
127 if u3.Name != "Bob Johnson" || u3.Active {
128 t.Errorf("User 3 should be inactive Bob Johnson: %+v", u3)
129 }
130
131 if u1.CreatedAt.IsZero() {
132 t.Error("User 1 created_at should not be zero")
133 }
134}
135
136func TestScannerEarlyTermination(t *testing.T) {
137 db := setupTestDB(t)
138 defer db.Close()
139
140 rows, err := db.Query("SELECT id, name, email FROM users ORDER BY id")
141 if err != nil {
142 t.Fatalf("Failed to query users: %v", err)
143 }
144
145 scanner := NewScanner[UserBasic](rows)
146 defer scanner.Close()
147 var users []UserBasic
148 count := 0
149
150 for user := range scanner.Scan() {
151 users = append(users, user)
152 count++
153 if count == 1 {
154 break
155 }
156 }
157
158 if len(users) != 1 {
159 t.Errorf("Expected 1 user due to early termination, got %d", len(users))
160 }
161
162 if users[0].ID != 1 || users[0].Name != "John Doe" {
163 t.Errorf("Expected first user to be John Doe, got %+v", users[0])
164 }
165}
166
167func TestScannerEmptyResults(t *testing.T) {
168 db := setupTestDB(t)
169 defer db.Close()
170
171 rows, err := db.Query("SELECT id, name, email FROM users WHERE id = 999")
172 if err != nil {
173 t.Fatalf("Failed to query users: %v", err)
174 }
175
176 scanner := NewScanner[UserBasic](rows)
177 defer scanner.Close()
178 var users []UserBasic
179
180 for user := range scanner.Scan() {
181 users = append(users, user)
182 }
183
184 if len(users) != 0 {
185 t.Errorf("Expected 0 users from empty query, got %d", len(users))
186 }
187}
188
189func TestScannerMultipleIterations(t *testing.T) {
190 db := setupTestDB(t)
191 defer db.Close()
192
193 rows, err := db.Query("SELECT id, name, email FROM users ORDER BY id LIMIT 1")
194 if err != nil {
195 t.Fatalf("Failed to query users: %v", err)
196 }
197
198 scanner := NewScanner[UserBasic](rows)
199 defer scanner.Close()
200 seq := scanner.Scan()
201
202 var users1 []UserBasic
203 for user := range seq {
204 users1 = append(users1, user)
205 }
206
207 var users2 []UserBasic
208 for user := range seq {
209 users2 = append(users2, user)
210 }
211
212 if len(users1) != 1 {
213 t.Errorf("Expected 1 user from first iteration, got %d", len(users1))
214 }
215
216 if len(users2) != 0 {
217 t.Errorf("Expected 0 users from second iteration, got %d", len(users2))
218 }
219}
220
221func TestScannerResourceCleanup(t *testing.T) {
222 db := setupTestDB(t)
223 defer db.Close()
224
225 rows, err := db.Query("SELECT id, name, email FROM users")
226 if err != nil {
227 t.Fatalf("Failed to query users: %v", err)
228 }
229
230 scanner := NewScanner[UserBasic](rows)
231
232 for user := range scanner.Scan() {
233 _ = user
234 break
235 }
236
237 scanner.Close()
238 if err := rows.Err(); err != nil {
239 t.Errorf("Expected no error, got %s", err)
240 }
241}
242
243func TestScannerFilterByDepartment(t *testing.T) {
244 db := setupTestDB(t)
245 defer db.Close()
246
247 rows, err := db.Query("SELECT id, name, age, email, department, active, salary, created_at FROM users WHERE department = 'Engineering' ORDER BY id")
248 if err != nil {
249 t.Fatalf("Failed to query users: %v", err)
250 }
251
252 scanner := NewScanner[User](rows)
253 defer scanner.Close()
254 var users []User
255
256 for user := range scanner.Scan() {
257 users = append(users, user)
258 }
259
260 if len(users) != 3 {
261 t.Errorf("Expected 3 Engineering users, got %d", len(users))
262 }
263
264 for i, user := range users {
265 if !user.Department.Valid || user.Department.String != "Engineering" {
266 t.Errorf("User %d should be from Engineering: %+v", i, user)
267 }
268 }
269
270 expectedNames := []string{"John Doe", "Bob Johnson", "Charlie Wilson"}
271 for i, user := range users {
272 if user.Name != expectedNames[i] {
273 t.Errorf("Expected user %d to be %s, got %s", i, expectedNames[i], user.Name)
274 }
275 }
276}
277
278func TestScanOne(t *testing.T) {
279 db := setupTestDB(t)
280 defer db.Close()
281
282 row := db.QueryRow("SELECT * FROM users WHERE id = 1")
283
284 var u User
285 err := Scan(row, &u)
286 if err != nil {
287 t.Fatalf("Failed to scan user: %v", err)
288 }
289
290 if u.ID != 1 || u.Name != "John Doe" {
291 t.Errorf("user data incorrect: %+v", u)
292 }
293}