]> git.r.bdr.sh - rbdr/mobius/blame - hotline/transaction_handlers_test.go
Create go-proxy-warming
[rbdr/mobius] / hotline / transaction_handlers_test.go
CommitLineData
6988a057
JH
1package hotline
2
3import (
decc2fbf 4 "errors"
6988a057 5 "github.com/stretchr/testify/assert"
8eb43f95 6 "github.com/stretchr/testify/mock"
b129b7cb 7 "io"
00d1ef67 8 "io/fs"
00d1ef67 9 "os"
f22acf38 10 "path/filepath"
decc2fbf 11 "strings"
6988a057 12 "testing"
7cd900d6 13 "time"
6988a057
JH
14)
15
16func TestHandleSetChatSubject(t *testing.T) {
17 type args struct {
18 cc *ClientConn
a2ef262a 19 t Transaction
6988a057
JH
20 }
21 tests := []struct {
a2ef262a
JH
22 name string
23 args args
24 want []Transaction
6988a057
JH
25 }{
26 {
27 name: "sends chat subject to private chat members",
28 args: args{
29 cc: &ClientConn{
72dd37f1 30 UserName: []byte{0x00, 0x01},
6988a057 31 Server: &Server{
d9bc63a1
JH
32 ChatMgr: func() *MockChatManager {
33 m := MockChatManager{}
34 m.On("Members", ChatID{0x0, 0x0, 0x0, 0x1}).Return([]*ClientConn{
35 {
36 Account: &Account{
37 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 38 },
d9bc63a1
JH
39 ID: [2]byte{0, 1},
40 },
41 {
42 Account: &Account{
43 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 44 },
d9bc63a1 45 ID: [2]byte{0, 2},
6988a057 46 },
d9bc63a1
JH
47 })
48 m.On("SetSubject", ChatID{0x0, 0x0, 0x0, 0x1}, "Test Subject")
49 return &m
50 }(),
51 //PrivateChats: map[[4]byte]*PrivateChat{
52 // [4]byte{0, 0, 0, 1}: {
53 // Subject: "unset",
54 // ClientConn: map[[2]byte]*ClientConn{
55 // [2]byte{0, 1}: {
56 // Account: &Account{
57 // Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
58 // },
59 // ID: [2]byte{0, 1},
60 // },
61 // [2]byte{0, 2}: {
62 // Account: &Account{
63 // Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
64 // },
65 // ID: [2]byte{0, 2},
66 // },
67 // },
68 // },
69 //},
70 ClientMgr: func() *MockClientMgr {
71 m := MockClientMgr{}
72 m.On("List").Return([]*ClientConn{
73 {
74 Account: &Account{
75 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
76 },
77 ID: [2]byte{0, 1},
6988a057 78 },
d9bc63a1
JH
79 {
80 Account: &Account{
81 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
82 },
83 ID: [2]byte{0, 2},
6988a057 84 },
6988a057 85 },
d9bc63a1
JH
86 )
87 return &m
88 }(),
6988a057
JH
89 },
90 },
a2ef262a 91 t: Transaction{
153e2eac
JH
92 Type: [2]byte{0, 0x6a},
93 ID: [4]byte{0, 0, 0, 1},
6988a057 94 Fields: []Field{
d005ef04
JH
95 NewField(FieldChatID, []byte{0, 0, 0, 1}),
96 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
97 },
98 },
99 },
100 want: []Transaction{
101 {
a2ef262a 102 clientID: [2]byte{0, 1},
153e2eac 103 Type: [2]byte{0, 0x77},
6988a057 104 Fields: []Field{
d005ef04
JH
105 NewField(FieldChatID, []byte{0, 0, 0, 1}),
106 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
107 },
108 },
109 {
a2ef262a 110 clientID: [2]byte{0, 2},
153e2eac 111 Type: [2]byte{0, 0x77},
6988a057 112 Fields: []Field{
d005ef04
JH
113 NewField(FieldChatID, []byte{0, 0, 0, 1}),
114 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
115 },
116 },
117 },
6988a057
JH
118 },
119 }
120 for _, tt := range tests {
6988a057 121 t.Run(tt.name, func(t *testing.T) {
a2ef262a 122 got := HandleSetChatSubject(tt.args.cc, &tt.args.t)
f8e4cd54 123 if !tranAssertEqual(t, tt.want, got) {
6988a057
JH
124 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
125 }
126 })
127 }
128}
129
130func TestHandleLeaveChat(t *testing.T) {
131 type args struct {
132 cc *ClientConn
a2ef262a 133 t Transaction
6988a057
JH
134 }
135 tests := []struct {
a2ef262a
JH
136 name string
137 args args
138 want []Transaction
6988a057
JH
139 }{
140 {
d9bc63a1 141 name: "when client 2 leaves chat",
6988a057
JH
142 args: args{
143 cc: &ClientConn{
a2ef262a 144 ID: [2]byte{0, 2},
6988a057 145 Server: &Server{
d9bc63a1
JH
146 ChatMgr: func() *MockChatManager {
147 m := MockChatManager{}
148 m.On("Members", ChatID{0x0, 0x0, 0x0, 0x1}).Return([]*ClientConn{
149 {
150 Account: &Account{
151 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 152 },
d9bc63a1 153 ID: [2]byte{0, 1},
6988a057 154 },
d9bc63a1
JH
155 })
156 m.On("Leave", ChatID{0x0, 0x0, 0x0, 0x1}, [2]uint8{0x0, 0x2})
157 m.On("GetSubject").Return("unset")
158 return &m
159 }(),
160 ClientMgr: func() *MockClientMgr {
161 m := MockClientMgr{}
162 m.On("Get").Return([]*ClientConn{
163 {
164 Account: &Account{
165 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
166 },
167 ID: [2]byte{0, 1},
6988a057 168 },
d9bc63a1
JH
169 {
170 Account: &Account{
171 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
172 },
173 ID: [2]byte{0, 2},
6988a057 174 },
6988a057 175 },
d9bc63a1
JH
176 )
177 return &m
178 }(),
6988a057
JH
179 },
180 },
a2ef262a 181 t: NewTransaction(TranDeleteUser, [2]byte{}, NewField(FieldChatID, []byte{0, 0, 0, 1})),
6988a057
JH
182 },
183 want: []Transaction{
184 {
a2ef262a 185 clientID: [2]byte{0, 1},
153e2eac 186 Type: [2]byte{0, 0x76},
6988a057 187 Fields: []Field{
d005ef04
JH
188 NewField(FieldChatID, []byte{0, 0, 0, 1}),
189 NewField(FieldUserID, []byte{0, 2}),
6988a057
JH
190 },
191 },
192 },
6988a057
JH
193 },
194 }
195 for _, tt := range tests {
6988a057 196 t.Run(tt.name, func(t *testing.T) {
a2ef262a 197 got := HandleLeaveChat(tt.args.cc, &tt.args.t)
f8e4cd54 198 if !tranAssertEqual(t, tt.want, got) {
6988a057
JH
199 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
200 }
201 })
202 }
203}
204
6988a057
JH
205func TestHandleGetUserNameList(t *testing.T) {
206 type args struct {
207 cc *ClientConn
a2ef262a 208 t Transaction
6988a057
JH
209 }
210 tests := []struct {
a2ef262a
JH
211 name string
212 args args
213 want []Transaction
6988a057
JH
214 }{
215 {
216 name: "replies with userlist transaction",
217 args: args{
218 cc: &ClientConn{
a2ef262a 219 ID: [2]byte{0, 1},
6988a057 220 Server: &Server{
d9bc63a1
JH
221 ClientMgr: func() *MockClientMgr {
222 m := MockClientMgr{}
223 m.On("List").Return([]*ClientConn{
224 {
225 ID: [2]byte{0, 1},
226 Icon: []byte{0, 2},
227 Flags: [2]byte{0, 3},
228 UserName: []byte{0, 4},
229 },
230 {
231 ID: [2]byte{0, 2},
232 Icon: []byte{0, 2},
233 Flags: [2]byte{0, 3},
234 UserName: []byte{0, 4},
235 },
bd1ce113 236 },
d9bc63a1
JH
237 )
238 return &m
239 }(),
6988a057
JH
240 },
241 },
a2ef262a 242 t: Transaction{},
6988a057
JH
243 },
244 want: []Transaction{
245 {
a2ef262a 246 clientID: [2]byte{0, 1},
153e2eac 247 IsReply: 0x01,
6988a057
JH
248 Fields: []Field{
249 NewField(
d005ef04 250 FieldUsernameWithInfo,
6988a057
JH
251 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
252 ),
c7e932c0 253 NewField(
d005ef04 254 FieldUsernameWithInfo,
c7e932c0
JH
255 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
256 ),
6988a057
JH
257 },
258 },
259 },
6988a057
JH
260 },
261 }
262 for _, tt := range tests {
263 t.Run(tt.name, func(t *testing.T) {
a2ef262a 264 got := HandleGetUserNameList(tt.args.cc, &tt.args.t)
bd1ce113 265 assert.Equal(t, tt.want, got)
6988a057
JH
266 })
267 }
268}
269
270func TestHandleChatSend(t *testing.T) {
271 type args struct {
272 cc *ClientConn
a2ef262a 273 t Transaction
6988a057
JH
274 }
275 tests := []struct {
a2ef262a
JH
276 name string
277 args args
278 want []Transaction
6988a057
JH
279 }{
280 {
281 name: "sends chat msg transaction to all clients",
282 args: args{
283 cc: &ClientConn{
9ebf276d 284 Account: &Account{
187d6dc5 285 Access: func() accessBitmap {
9ebf276d 286 var bits accessBitmap
d9bc63a1 287 bits.Set(AccessSendChat)
187d6dc5 288 return bits
9ebf276d
JH
289 }(),
290 },
72dd37f1 291 UserName: []byte{0x00, 0x01},
6988a057 292 Server: &Server{
d9bc63a1
JH
293 ClientMgr: func() *MockClientMgr {
294 m := MockClientMgr{}
295 m.On("List").Return([]*ClientConn{
296 {
297 Account: &Account{
298 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
299 },
300 ID: [2]byte{0, 1},
6988a057 301 },
d9bc63a1
JH
302 {
303 Account: &Account{
304 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
305 },
306 ID: [2]byte{0, 2},
6988a057 307 },
6988a057 308 },
d9bc63a1
JH
309 )
310 return &m
311 }(),
6988a057
JH
312 },
313 },
a2ef262a 314 t: Transaction{
6988a057 315 Fields: []Field{
d005ef04 316 NewField(FieldData, []byte("hai")),
6988a057
JH
317 },
318 },
319 },
320 want: []Transaction{
321 {
a2ef262a 322 clientID: [2]byte{0, 1},
153e2eac
JH
323 Flags: 0x00,
324 IsReply: 0x00,
325 Type: [2]byte{0, 0x6a},
6988a057 326 Fields: []Field{
d005ef04 327 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
328 },
329 },
330 {
a2ef262a 331 clientID: [2]byte{0, 2},
153e2eac
JH
332 Flags: 0x00,
333 IsReply: 0x00,
334 Type: [2]byte{0, 0x6a},
6988a057 335 Fields: []Field{
d005ef04 336 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
337 },
338 },
339 },
6988a057 340 },
361928c9 341 {
d9bc63a1 342 name: "treats Chat Type 00 00 00 00 as a public chat message",
361928c9
JH
343 args: args{
344 cc: &ClientConn{
345 Account: &Account{
346 Access: func() accessBitmap {
347 var bits accessBitmap
d9bc63a1 348 bits.Set(AccessSendChat)
361928c9
JH
349 return bits
350 }(),
351 },
352 UserName: []byte{0x00, 0x01},
353 Server: &Server{
d9bc63a1
JH
354 ClientMgr: func() *MockClientMgr {
355 m := MockClientMgr{}
356 m.On("List").Return([]*ClientConn{
357 {
358 Account: &Account{
359 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
360 },
361 ID: [2]byte{0, 1},
361928c9 362 },
d9bc63a1
JH
363 {
364 Account: &Account{
365 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
366 },
367 ID: [2]byte{0, 2},
361928c9 368 },
361928c9 369 },
d9bc63a1
JH
370 )
371 return &m
372 }(),
361928c9
JH
373 },
374 },
a2ef262a 375 t: Transaction{
361928c9 376 Fields: []Field{
d005ef04
JH
377 NewField(FieldData, []byte("hai")),
378 NewField(FieldChatID, []byte{0, 0, 0, 0}),
361928c9
JH
379 },
380 },
381 },
382 want: []Transaction{
383 {
a2ef262a 384 clientID: [2]byte{0, 1},
153e2eac 385 Type: [2]byte{0, 0x6a},
361928c9 386 Fields: []Field{
d005ef04 387 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
361928c9
JH
388 },
389 },
390 {
a2ef262a 391 clientID: [2]byte{0, 2},
153e2eac 392 Type: [2]byte{0, 0x6a},
361928c9 393 Fields: []Field{
d005ef04 394 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
361928c9
JH
395 },
396 },
397 },
361928c9 398 },
9ebf276d
JH
399 {
400 name: "when user does not have required permission",
401 args: args{
402 cc: &ClientConn{
403 Account: &Account{
187d6dc5 404 Access: func() accessBitmap {
9ebf276d 405 var bits accessBitmap
187d6dc5 406 return bits
9ebf276d
JH
407 }(),
408 },
409 Server: &Server{
d9bc63a1 410 //Accounts: map[string]*Account{},
9ebf276d
JH
411 },
412 },
413 t: NewTransaction(
a2ef262a 414 TranChatSend, [2]byte{0, 1},
d005ef04 415 NewField(FieldData, []byte("hai")),
9ebf276d
JH
416 ),
417 },
418 want: []Transaction{
419 {
9ebf276d 420 IsReply: 0x01,
153e2eac 421 ErrorCode: [4]byte{0, 0, 0, 1},
9ebf276d 422 Fields: []Field{
d005ef04 423 NewField(FieldError, []byte("You are not allowed to participate in chat.")),
9ebf276d
JH
424 },
425 },
426 },
9ebf276d 427 },
72dd37f1 428 {
d005ef04 429 name: "sends chat msg as emote if FieldChatOptions is set to 1",
72dd37f1
JH
430 args: args{
431 cc: &ClientConn{
9ebf276d 432 Account: &Account{
187d6dc5 433 Access: func() accessBitmap {
9ebf276d 434 var bits accessBitmap
d9bc63a1 435 bits.Set(AccessSendChat)
187d6dc5 436 return bits
9ebf276d
JH
437 }(),
438 },
72dd37f1
JH
439 UserName: []byte("Testy McTest"),
440 Server: &Server{
d9bc63a1
JH
441 ClientMgr: func() *MockClientMgr {
442 m := MockClientMgr{}
443 m.On("List").Return([]*ClientConn{
444 {
445 Account: &Account{
446 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
447 },
448 ID: [2]byte{0, 1},
72dd37f1 449 },
d9bc63a1
JH
450 {
451 Account: &Account{
452 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
453 },
454 ID: [2]byte{0, 2},
72dd37f1 455 },
72dd37f1 456 },
d9bc63a1
JH
457 )
458 return &m
459 }(),
72dd37f1
JH
460 },
461 },
a2ef262a 462 t: Transaction{
72dd37f1 463 Fields: []Field{
d005ef04
JH
464 NewField(FieldData, []byte("performed action")),
465 NewField(FieldChatOptions, []byte{0x00, 0x01}),
72dd37f1
JH
466 },
467 },
468 },
469 want: []Transaction{
470 {
a2ef262a 471 clientID: [2]byte{0, 1},
153e2eac
JH
472 Flags: 0x00,
473 IsReply: 0x00,
474 Type: [2]byte{0, 0x6a},
72dd37f1 475 Fields: []Field{
d005ef04 476 NewField(FieldData, []byte("\r*** Testy McTest performed action")),
72dd37f1
JH
477 },
478 },
479 {
a2ef262a 480 clientID: [2]byte{0, 2},
153e2eac
JH
481 Flags: 0x00,
482 IsReply: 0x00,
483 Type: [2]byte{0, 0x6a},
72dd37f1 484 Fields: []Field{
d005ef04 485 NewField(FieldData, []byte("\r*** Testy McTest performed action")),
72dd37f1
JH
486 },
487 },
488 },
72dd37f1 489 },
2e43fd4e 490 {
d005ef04 491 name: "does not send chat msg as emote if FieldChatOptions is set to 0",
2e43fd4e
JH
492 args: args{
493 cc: &ClientConn{
494 Account: &Account{
495 Access: func() accessBitmap {
496 var bits accessBitmap
d9bc63a1 497 bits.Set(AccessSendChat)
2e43fd4e
JH
498 return bits
499 }(),
500 },
501 UserName: []byte("Testy McTest"),
502 Server: &Server{
d9bc63a1
JH
503 ClientMgr: func() *MockClientMgr {
504 m := MockClientMgr{}
505 m.On("List").Return([]*ClientConn{
506 {
507 Account: &Account{
508 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
509 },
510 ID: [2]byte{0, 1},
2e43fd4e 511 },
d9bc63a1
JH
512 {
513 Account: &Account{
514 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
515 },
516 ID: [2]byte{0, 2},
2e43fd4e 517 },
2e43fd4e 518 },
d9bc63a1
JH
519 )
520 return &m
521 }(),
2e43fd4e
JH
522 },
523 },
a2ef262a 524 t: Transaction{
2e43fd4e 525 Fields: []Field{
d005ef04
JH
526 NewField(FieldData, []byte("hello")),
527 NewField(FieldChatOptions, []byte{0x00, 0x00}),
2e43fd4e
JH
528 },
529 },
530 },
531 want: []Transaction{
532 {
a2ef262a 533 clientID: [2]byte{0, 1},
153e2eac 534 Type: [2]byte{0, 0x6a},
2e43fd4e 535 Fields: []Field{
d005ef04 536 NewField(FieldData, []byte("\r Testy McTest: hello")),
2e43fd4e
JH
537 },
538 },
539 {
a2ef262a 540 clientID: [2]byte{0, 2},
153e2eac 541 Type: [2]byte{0, 0x6a},
2e43fd4e 542 Fields: []Field{
d005ef04 543 NewField(FieldData, []byte("\r Testy McTest: hello")),
2e43fd4e
JH
544 },
545 },
546 },
2e43fd4e 547 },
6988a057 548 {
d9bc63a1 549 name: "only sends chat msg to clients with AccessReadChat permission",
6988a057
JH
550 args: args{
551 cc: &ClientConn{
9ebf276d 552 Account: &Account{
187d6dc5 553 Access: func() accessBitmap {
9ebf276d 554 var bits accessBitmap
d9bc63a1 555 bits.Set(AccessSendChat)
187d6dc5 556 return bits
9ebf276d
JH
557 }(),
558 },
72dd37f1 559 UserName: []byte{0x00, 0x01},
6988a057 560 Server: &Server{
d9bc63a1
JH
561 ClientMgr: func() *MockClientMgr {
562 m := MockClientMgr{}
563 m.On("List").Return([]*ClientConn{
564 {
565 Account: &Account{
566 Access: func() accessBitmap {
567 var bits accessBitmap
568 bits.Set(AccessReadChat)
569 return bits
570 }(),
571 },
572 ID: [2]byte{0, 1},
573 },
574 {
575 Account: &Account{},
576 ID: [2]byte{0, 2},
6988a057 577 },
6988a057 578 },
d9bc63a1
JH
579 )
580 return &m
581 }(),
6988a057
JH
582 },
583 },
a2ef262a 584 t: Transaction{
6988a057 585 Fields: []Field{
d005ef04 586 NewField(FieldData, []byte("hai")),
6988a057
JH
587 },
588 },
589 },
590 want: []Transaction{
591 {
a2ef262a 592 clientID: [2]byte{0, 1},
153e2eac 593 Type: [2]byte{0, 0x6a},
6988a057 594 Fields: []Field{
d005ef04 595 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
596 },
597 },
598 },
6988a057 599 },
481631f6
JH
600 {
601 name: "only sends private chat msg to members of private chat",
602 args: args{
603 cc: &ClientConn{
604 Account: &Account{
187d6dc5 605 Access: func() accessBitmap {
481631f6 606 var bits accessBitmap
d9bc63a1 607 bits.Set(AccessSendChat)
187d6dc5 608 return bits
481631f6
JH
609 }(),
610 },
611 UserName: []byte{0x00, 0x01},
612 Server: &Server{
d9bc63a1
JH
613 ChatMgr: func() *MockChatManager {
614 m := MockChatManager{}
615 m.On("Members", ChatID{0x0, 0x0, 0x0, 0x1}).Return([]*ClientConn{
616 {
617 ID: [2]byte{0, 1},
481631f6 618 },
d9bc63a1
JH
619 {
620 ID: [2]byte{0, 2},
481631f6 621 },
d9bc63a1
JH
622 })
623 m.On("GetSubject").Return("unset")
624 return &m
625 }(),
626 ClientMgr: func() *MockClientMgr {
627 m := MockClientMgr{}
628 m.On("List").Return([]*ClientConn{
629 {
630 Account: &Account{
631 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
632 },
633 ID: [2]byte{0, 1},
481631f6 634 },
d9bc63a1
JH
635 {
636 Account: &Account{
637 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
638 },
639 ID: [2]byte{0, 2},
640 },
641 {
642 Account: &Account{
643 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
644 },
645 ID: [2]byte{0, 3},
481631f6 646 },
481631f6 647 },
d9bc63a1
JH
648 )
649 return &m
650 }(),
481631f6
JH
651 },
652 },
a2ef262a 653 t: Transaction{
481631f6 654 Fields: []Field{
d005ef04
JH
655 NewField(FieldData, []byte("hai")),
656 NewField(FieldChatID, []byte{0, 0, 0, 1}),
481631f6
JH
657 },
658 },
659 },
660 want: []Transaction{
661 {
a2ef262a 662 clientID: [2]byte{0, 1},
153e2eac 663 Type: [2]byte{0, 0x6a},
481631f6 664 Fields: []Field{
d005ef04
JH
665 NewField(FieldChatID, []byte{0, 0, 0, 1}),
666 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
481631f6
JH
667 },
668 },
669 {
a2ef262a 670 clientID: [2]byte{0, 2},
153e2eac 671 Type: [2]byte{0, 0x6a},
481631f6 672 Fields: []Field{
d005ef04
JH
673 NewField(FieldChatID, []byte{0, 0, 0, 1}),
674 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
481631f6
JH
675 },
676 },
677 },
481631f6 678 },
6988a057
JH
679 }
680 for _, tt := range tests {
6988a057 681 t.Run(tt.name, func(t *testing.T) {
a2ef262a 682 got := HandleChatSend(tt.args.cc, &tt.args.t)
9ebf276d 683 tranAssertEqual(t, tt.want, got)
6988a057
JH
684 })
685 }
686}
72dd37f1
JH
687
688func TestHandleGetFileInfo(t *testing.T) {
72dd37f1
JH
689 type args struct {
690 cc *ClientConn
a2ef262a 691 t Transaction
72dd37f1
JH
692 }
693 tests := []struct {
694 name string
695 args args
696 wantRes []Transaction
72dd37f1
JH
697 }{
698 {
699 name: "returns expected fields when a valid file is requested",
700 args: args{
701 cc: &ClientConn{
a2ef262a 702 ID: [2]byte{0x00, 0x01},
72dd37f1 703 Server: &Server{
7cd900d6 704 FS: &OSFileStore{},
d9bc63a1 705 Config: Config{
29f329ae
JH
706 FileRoot: func() string {
707 path, _ := os.Getwd()
f22acf38 708 return filepath.Join(path, "/test/config/Files")
29f329ae 709 }(),
72dd37f1
JH
710 },
711 },
712 },
713 t: NewTransaction(
a2ef262a 714 TranGetFileInfo, [2]byte{},
d005ef04
JH
715 NewField(FieldFileName, []byte("testfile.txt")),
716 NewField(FieldFilePath, []byte{0x00, 0x00}),
72dd37f1
JH
717 ),
718 },
719 wantRes: []Transaction{
720 {
a2ef262a 721 clientID: [2]byte{0, 1},
153e2eac
JH
722 IsReply: 0x01,
723 Type: [2]byte{0, 0},
72dd37f1 724 Fields: []Field{
d005ef04
JH
725 NewField(FieldFileName, []byte("testfile.txt")),
726 NewField(FieldFileTypeString, []byte("Text File")),
727 NewField(FieldFileCreatorString, []byte("ttxt")),
d005ef04
JH
728 NewField(FieldFileType, []byte("TEXT")),
729 NewField(FieldFileCreateDate, make([]byte, 8)),
730 NewField(FieldFileModifyDate, make([]byte, 8)),
731 NewField(FieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
72dd37f1
JH
732 },
733 },
734 },
72dd37f1
JH
735 },
736 }
737 for _, tt := range tests {
738 t.Run(tt.name, func(t *testing.T) {
a2ef262a 739 gotRes := HandleGetFileInfo(tt.args.cc, &tt.args.t)
29f329ae 740
a2ef262a 741 // Clear the file timestamp fields to work around problems running the tests in multiple timezones
29f329ae 742 // TODO: revisit how to test this by mocking the stat calls
84f3e842 743 gotRes[0].Fields[4].Data = make([]byte, 8)
29f329ae 744 gotRes[0].Fields[5].Data = make([]byte, 8)
f8e4cd54
JH
745
746 if !tranAssertEqual(t, tt.wantRes, gotRes) {
72dd37f1
JH
747 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
748 }
749 })
750 }
751}
00d1ef67
JH
752
753func TestHandleNewFolder(t *testing.T) {
754 type args struct {
755 cc *ClientConn
a2ef262a 756 t Transaction
00d1ef67
JH
757 }
758 tests := []struct {
00d1ef67
JH
759 name string
760 args args
761 wantRes []Transaction
00d1ef67 762 }{
d4c152a4 763 {
b196a50a 764 name: "without required permission",
d4c152a4
JH
765 args: args{
766 cc: &ClientConn{
767 Account: &Account{
187d6dc5 768 Access: func() accessBitmap {
d4c152a4 769 var bits accessBitmap
187d6dc5 770 return bits
d4c152a4
JH
771 }(),
772 },
773 },
774 t: NewTransaction(
a2ef262a
JH
775 TranNewFolder,
776 [2]byte{0, 0},
d4c152a4
JH
777 ),
778 },
779 wantRes: []Transaction{
780 {
d4c152a4 781 IsReply: 0x01,
153e2eac 782 ErrorCode: [4]byte{0, 0, 0, 1},
d4c152a4 783 Fields: []Field{
d005ef04 784 NewField(FieldError, []byte("You are not allowed to create folders.")),
d4c152a4
JH
785 },
786 },
787 },
d4c152a4 788 },
00d1ef67
JH
789 {
790 name: "when path is nested",
791 args: args{
792 cc: &ClientConn{
d4c152a4 793 Account: &Account{
187d6dc5 794 Access: func() accessBitmap {
d4c152a4 795 var bits accessBitmap
d9bc63a1 796 bits.Set(AccessCreateFolder)
187d6dc5 797 return bits
d4c152a4
JH
798 }(),
799 },
a2ef262a 800 ID: [2]byte{0, 1},
00d1ef67 801 Server: &Server{
d9bc63a1 802 Config: Config{
00d1ef67
JH
803 FileRoot: "/Files/",
804 },
b196a50a
JH
805 FS: func() *MockFileStore {
806 mfs := &MockFileStore{}
807 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
808 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
809 return mfs
810 }(),
00d1ef67
JH
811 },
812 },
813 t: NewTransaction(
a2ef262a 814 TranNewFolder, [2]byte{0, 1},
d005ef04
JH
815 NewField(FieldFileName, []byte("testFolder")),
816 NewField(FieldFilePath, []byte{
00d1ef67
JH
817 0x00, 0x01,
818 0x00, 0x00,
819 0x03,
820 0x61, 0x61, 0x61,
821 }),
822 ),
823 },
00d1ef67
JH
824 wantRes: []Transaction{
825 {
a2ef262a 826 clientID: [2]byte{0, 1},
153e2eac 827 IsReply: 0x01,
00d1ef67
JH
828 },
829 },
00d1ef67
JH
830 },
831 {
832 name: "when path is not nested",
833 args: args{
834 cc: &ClientConn{
d4c152a4 835 Account: &Account{
187d6dc5 836 Access: func() accessBitmap {
d4c152a4 837 var bits accessBitmap
d9bc63a1 838 bits.Set(AccessCreateFolder)
187d6dc5 839 return bits
d4c152a4
JH
840 }(),
841 },
a2ef262a 842 ID: [2]byte{0, 1},
00d1ef67 843 Server: &Server{
d9bc63a1 844 Config: Config{
00d1ef67
JH
845 FileRoot: "/Files",
846 },
b196a50a
JH
847 FS: func() *MockFileStore {
848 mfs := &MockFileStore{}
849 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
850 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
851 return mfs
852 }(),
00d1ef67
JH
853 },
854 },
855 t: NewTransaction(
a2ef262a 856 TranNewFolder, [2]byte{0, 1},
d005ef04 857 NewField(FieldFileName, []byte("testFolder")),
00d1ef67
JH
858 ),
859 },
00d1ef67
JH
860 wantRes: []Transaction{
861 {
a2ef262a 862 clientID: [2]byte{0, 1},
153e2eac 863 IsReply: 0x01,
00d1ef67
JH
864 },
865 },
00d1ef67
JH
866 },
867 {
8fc43f8e 868 name: "when Write returns an err",
00d1ef67
JH
869 args: args{
870 cc: &ClientConn{
d4c152a4 871 Account: &Account{
187d6dc5 872 Access: func() accessBitmap {
d4c152a4 873 var bits accessBitmap
d9bc63a1 874 bits.Set(AccessCreateFolder)
187d6dc5 875 return bits
d4c152a4
JH
876 }(),
877 },
a2ef262a 878 ID: [2]byte{0, 1},
00d1ef67 879 Server: &Server{
d9bc63a1 880 Config: Config{
00d1ef67
JH
881 FileRoot: "/Files/",
882 },
b196a50a
JH
883 FS: func() *MockFileStore {
884 mfs := &MockFileStore{}
885 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
886 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
887 return mfs
888 }(),
00d1ef67
JH
889 },
890 },
891 t: NewTransaction(
a2ef262a 892 TranNewFolder, [2]byte{0, 1},
d005ef04
JH
893 NewField(FieldFileName, []byte("testFolder")),
894 NewField(FieldFilePath, []byte{
00d1ef67
JH
895 0x00,
896 }),
897 ),
898 },
00d1ef67 899 wantRes: []Transaction{},
00d1ef67
JH
900 },
901 {
d005ef04 902 name: "FieldFileName does not allow directory traversal",
00d1ef67
JH
903 args: args{
904 cc: &ClientConn{
d4c152a4 905 Account: &Account{
187d6dc5 906 Access: func() accessBitmap {
d4c152a4 907 var bits accessBitmap
d9bc63a1 908 bits.Set(AccessCreateFolder)
187d6dc5 909 return bits
d4c152a4
JH
910 }(),
911 },
a2ef262a 912 ID: [2]byte{0, 1},
00d1ef67 913 Server: &Server{
d9bc63a1 914 Config: Config{
00d1ef67
JH
915 FileRoot: "/Files/",
916 },
b196a50a
JH
917 FS: func() *MockFileStore {
918 mfs := &MockFileStore{}
919 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
920 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
921 return mfs
922 }(),
00d1ef67
JH
923 },
924 },
925 t: NewTransaction(
a2ef262a 926 TranNewFolder, [2]byte{0, 1},
d005ef04 927 NewField(FieldFileName, []byte("../../testFolder")),
00d1ef67
JH
928 ),
929 },
00d1ef67
JH
930 wantRes: []Transaction{
931 {
a2ef262a 932 clientID: [2]byte{0, 1},
153e2eac 933 IsReply: 0x01,
00d1ef67 934 },
a2ef262a 935 },
00d1ef67
JH
936 },
937 {
d005ef04 938 name: "FieldFilePath does not allow directory traversal",
00d1ef67
JH
939 args: args{
940 cc: &ClientConn{
d4c152a4 941 Account: &Account{
187d6dc5 942 Access: func() accessBitmap {
d4c152a4 943 var bits accessBitmap
d9bc63a1 944 bits.Set(AccessCreateFolder)
187d6dc5 945 return bits
d4c152a4
JH
946 }(),
947 },
a2ef262a 948 ID: [2]byte{0, 1},
00d1ef67 949 Server: &Server{
d9bc63a1 950 Config: Config{
00d1ef67
JH
951 FileRoot: "/Files/",
952 },
b196a50a
JH
953 FS: func() *MockFileStore {
954 mfs := &MockFileStore{}
955 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
956 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
957 return mfs
958 }(),
00d1ef67
JH
959 },
960 },
961 t: NewTransaction(
a2ef262a 962 TranNewFolder, [2]byte{0, 1},
d005ef04
JH
963 NewField(FieldFileName, []byte("testFolder")),
964 NewField(FieldFilePath, []byte{
00d1ef67
JH
965 0x00, 0x02,
966 0x00, 0x00,
967 0x03,
968 0x2e, 0x2e, 0x2f,
969 0x00, 0x00,
970 0x03,
971 0x66, 0x6f, 0x6f,
972 }),
973 ),
974 },
00d1ef67
JH
975 wantRes: []Transaction{
976 {
a2ef262a 977 clientID: [2]byte{0, 1},
153e2eac 978 IsReply: 0x01,
00d1ef67 979 },
a2ef262a 980 },
00d1ef67
JH
981 },
982 }
983 for _, tt := range tests {
984 t.Run(tt.name, func(t *testing.T) {
a2ef262a 985 gotRes := HandleNewFolder(tt.args.cc, &tt.args.t)
d4c152a4 986
00d1ef67
JH
987 if !tranAssertEqual(t, tt.wantRes, gotRes) {
988 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
989 }
990 })
991 }
992}
993
92a7e455
JH
994func TestHandleUploadFile(t *testing.T) {
995 type args struct {
996 cc *ClientConn
a2ef262a 997 t Transaction
92a7e455
JH
998 }
999 tests := []struct {
1000 name string
1001 args args
1002 wantRes []Transaction
92a7e455
JH
1003 }{
1004 {
7e2e07da 1005 name: "when request is valid and user has Upload Anywhere permission",
92a7e455
JH
1006 args: args{
1007 cc: &ClientConn{
1008 Server: &Server{
d9bc63a1
JH
1009 FS: &OSFileStore{},
1010 FileTransferMgr: NewMemFileTransferMgr(),
1011 Config: Config{
df1ade54
JH
1012 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1013 }},
d9bc63a1 1014 ClientFileTransferMgr: NewClientFileTransferMgr(),
92a7e455 1015 Account: &Account{
187d6dc5 1016 Access: func() accessBitmap {
92a7e455 1017 var bits accessBitmap
d9bc63a1
JH
1018 bits.Set(AccessUploadFile)
1019 bits.Set(AccessUploadAnywhere)
187d6dc5 1020 return bits
92a7e455
JH
1021 }(),
1022 },
1023 },
1024 t: NewTransaction(
a2ef262a 1025 TranUploadFile, [2]byte{0, 1},
d005ef04
JH
1026 NewField(FieldFileName, []byte("testFile")),
1027 NewField(FieldFilePath, []byte{
92a7e455
JH
1028 0x00, 0x01,
1029 0x00, 0x00,
1030 0x03,
1031 0x2e, 0x2e, 0x2f,
1032 }),
1033 ),
1034 },
1035 wantRes: []Transaction{
1036 {
153e2eac 1037 IsReply: 0x01,
92a7e455 1038 Fields: []Field{
d005ef04 1039 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
92a7e455
JH
1040 },
1041 },
1042 },
92a7e455
JH
1043 },
1044 {
1045 name: "when user does not have required access",
1046 args: args{
1047 cc: &ClientConn{
1048 Account: &Account{
187d6dc5 1049 Access: func() accessBitmap {
92a7e455 1050 var bits accessBitmap
187d6dc5 1051 return bits
92a7e455
JH
1052 }(),
1053 },
92a7e455
JH
1054 },
1055 t: NewTransaction(
a2ef262a 1056 TranUploadFile, [2]byte{0, 1},
d005ef04
JH
1057 NewField(FieldFileName, []byte("testFile")),
1058 NewField(FieldFilePath, []byte{
92a7e455
JH
1059 0x00, 0x01,
1060 0x00, 0x00,
1061 0x03,
1062 0x2e, 0x2e, 0x2f,
1063 }),
1064 ),
1065 },
1066 wantRes: []Transaction{
1067 {
92a7e455 1068 IsReply: 0x01,
153e2eac 1069 ErrorCode: [4]byte{0, 0, 0, 1},
92a7e455 1070 Fields: []Field{
d005ef04 1071 NewField(FieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
92a7e455
JH
1072 },
1073 },
1074 },
92a7e455
JH
1075 },
1076 }
1077 for _, tt := range tests {
1078 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1079 gotRes := HandleUploadFile(tt.args.cc, &tt.args.t)
aebc4d36 1080 tranAssertEqual(t, tt.wantRes, gotRes)
92a7e455
JH
1081 })
1082 }
1083}
decc2fbf
JH
1084
1085func TestHandleMakeAlias(t *testing.T) {
1086 type args struct {
1087 cc *ClientConn
a2ef262a 1088 t Transaction
decc2fbf
JH
1089 }
1090 tests := []struct {
1091 name string
decc2fbf
JH
1092 args args
1093 wantRes []Transaction
decc2fbf
JH
1094 }{
1095 {
1096 name: "with valid input and required permissions",
decc2fbf
JH
1097 args: args{
1098 cc: &ClientConn{
02b446d8 1099 logger: NewTestLogger(),
decc2fbf 1100 Account: &Account{
187d6dc5 1101 Access: func() accessBitmap {
decc2fbf 1102 var bits accessBitmap
d9bc63a1 1103 bits.Set(AccessMakeAlias)
187d6dc5 1104 return bits
decc2fbf
JH
1105 }(),
1106 },
1107 Server: &Server{
d9bc63a1 1108 Config: Config{
decc2fbf
JH
1109 FileRoot: func() string {
1110 path, _ := os.Getwd()
1111 return path + "/test/config/Files"
1112 }(),
1113 },
1114 Logger: NewTestLogger(),
b196a50a
JH
1115 FS: func() *MockFileStore {
1116 mfs := &MockFileStore{}
1117 path, _ := os.Getwd()
1118 mfs.On(
1119 "Symlink",
1120 path+"/test/config/Files/foo/testFile",
1121 path+"/test/config/Files/bar/testFile",
1122 ).Return(nil)
1123 return mfs
1124 }(),
decc2fbf
JH
1125 },
1126 },
1127 t: NewTransaction(
a2ef262a 1128 TranMakeFileAlias, [2]byte{0, 1},
d005ef04
JH
1129 NewField(FieldFileName, []byte("testFile")),
1130 NewField(FieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1131 NewField(FieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
decc2fbf
JH
1132 ),
1133 },
1134 wantRes: []Transaction{
1135 {
153e2eac
JH
1136 IsReply: 0x01,
1137 Fields: []Field(nil),
decc2fbf
JH
1138 },
1139 },
decc2fbf
JH
1140 },
1141 {
1142 name: "when symlink returns an error",
decc2fbf
JH
1143 args: args{
1144 cc: &ClientConn{
02b446d8 1145 logger: NewTestLogger(),
decc2fbf 1146 Account: &Account{
187d6dc5 1147 Access: func() accessBitmap {
decc2fbf 1148 var bits accessBitmap
d9bc63a1 1149 bits.Set(AccessMakeAlias)
187d6dc5 1150 return bits
decc2fbf
JH
1151 }(),
1152 },
1153 Server: &Server{
d9bc63a1 1154 Config: Config{
decc2fbf
JH
1155 FileRoot: func() string {
1156 path, _ := os.Getwd()
1157 return path + "/test/config/Files"
1158 }(),
1159 },
1160 Logger: NewTestLogger(),
b196a50a
JH
1161 FS: func() *MockFileStore {
1162 mfs := &MockFileStore{}
1163 path, _ := os.Getwd()
1164 mfs.On(
1165 "Symlink",
1166 path+"/test/config/Files/foo/testFile",
1167 path+"/test/config/Files/bar/testFile",
1168 ).Return(errors.New("ohno"))
1169 return mfs
1170 }(),
decc2fbf
JH
1171 },
1172 },
1173 t: NewTransaction(
a2ef262a 1174 TranMakeFileAlias, [2]byte{0, 1},
d005ef04
JH
1175 NewField(FieldFileName, []byte("testFile")),
1176 NewField(FieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1177 NewField(FieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
decc2fbf
JH
1178 ),
1179 },
1180 wantRes: []Transaction{
1181 {
decc2fbf 1182 IsReply: 0x01,
153e2eac 1183 ErrorCode: [4]byte{0, 0, 0, 1},
decc2fbf 1184 Fields: []Field{
d005ef04 1185 NewField(FieldError, []byte("Error creating alias")),
decc2fbf
JH
1186 },
1187 },
1188 },
decc2fbf
JH
1189 },
1190 {
b196a50a 1191 name: "when user does not have required permission",
decc2fbf
JH
1192 args: args{
1193 cc: &ClientConn{
02b446d8 1194 logger: NewTestLogger(),
decc2fbf 1195 Account: &Account{
d9bc63a1 1196 Access: accessBitmap{},
decc2fbf
JH
1197 },
1198 Server: &Server{
d9bc63a1 1199 Config: Config{
decc2fbf
JH
1200 FileRoot: func() string {
1201 path, _ := os.Getwd()
1202 return path + "/test/config/Files"
1203 }(),
1204 },
1205 },
1206 },
1207 t: NewTransaction(
a2ef262a 1208 TranMakeFileAlias, [2]byte{0, 1},
d005ef04
JH
1209 NewField(FieldFileName, []byte("testFile")),
1210 NewField(FieldFilePath, []byte{
decc2fbf
JH
1211 0x00, 0x01,
1212 0x00, 0x00,
1213 0x03,
1214 0x2e, 0x2e, 0x2e,
1215 }),
d005ef04 1216 NewField(FieldFileNewPath, []byte{
decc2fbf
JH
1217 0x00, 0x01,
1218 0x00, 0x00,
1219 0x03,
1220 0x2e, 0x2e, 0x2e,
1221 }),
1222 ),
1223 },
1224 wantRes: []Transaction{
1225 {
decc2fbf 1226 IsReply: 0x01,
153e2eac 1227 ErrorCode: [4]byte{0, 0, 0, 1},
decc2fbf 1228 Fields: []Field{
d005ef04 1229 NewField(FieldError, []byte("You are not allowed to make aliases.")),
decc2fbf
JH
1230 },
1231 },
1232 },
decc2fbf
JH
1233 },
1234 }
1235 for _, tt := range tests {
1236 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1237 gotRes := HandleMakeAlias(tt.args.cc, &tt.args.t)
decc2fbf
JH
1238 tranAssertEqual(t, tt.wantRes, gotRes)
1239 })
1240 }
1241}
9ebf276d
JH
1242
1243func TestHandleGetUser(t *testing.T) {
1244 type args struct {
1245 cc *ClientConn
a2ef262a 1246 t Transaction
9ebf276d
JH
1247 }
1248 tests := []struct {
1249 name string
1250 args args
1251 wantRes []Transaction
9ebf276d
JH
1252 }{
1253 {
1254 name: "when account is valid",
1255 args: args{
1256 cc: &ClientConn{
1257 Account: &Account{
187d6dc5 1258 Access: func() accessBitmap {
9ebf276d 1259 var bits accessBitmap
d9bc63a1 1260 bits.Set(AccessOpenUser)
187d6dc5 1261 return bits
9ebf276d
JH
1262 }(),
1263 },
1264 Server: &Server{
d9bc63a1
JH
1265 AccountManager: func() *MockAccountManager {
1266 m := MockAccountManager{}
1267 m.On("Get", "guest").Return(&Account{
9ebf276d
JH
1268 Login: "guest",
1269 Name: "Guest",
1270 Password: "password",
187d6dc5 1271 Access: accessBitmap{},
d9bc63a1
JH
1272 })
1273 return &m
1274 }(),
9ebf276d
JH
1275 },
1276 },
1277 t: NewTransaction(
a2ef262a 1278 TranGetUser, [2]byte{0, 1},
d005ef04 1279 NewField(FieldUserLogin, []byte("guest")),
9ebf276d
JH
1280 ),
1281 },
1282 wantRes: []Transaction{
1283 {
153e2eac 1284 IsReply: 0x01,
9ebf276d 1285 Fields: []Field{
d005ef04 1286 NewField(FieldUserName, []byte("Guest")),
76d0c1f6 1287 NewField(FieldUserLogin, encodeString([]byte("guest"))),
d005ef04
JH
1288 NewField(FieldUserPassword, []byte("password")),
1289 NewField(FieldUserAccess, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
9ebf276d
JH
1290 },
1291 },
1292 },
9ebf276d
JH
1293 },
1294 {
1295 name: "when user does not have required permission",
1296 args: args{
1297 cc: &ClientConn{
1298 Account: &Account{
187d6dc5 1299 Access: func() accessBitmap {
9ebf276d 1300 var bits accessBitmap
187d6dc5 1301 return bits
9ebf276d
JH
1302 }(),
1303 },
1304 Server: &Server{
d9bc63a1 1305 //Accounts: map[string]*Account{},
9ebf276d
JH
1306 },
1307 },
1308 t: NewTransaction(
a2ef262a 1309 TranGetUser, [2]byte{0, 1},
d005ef04 1310 NewField(FieldUserLogin, []byte("nonExistentUser")),
9ebf276d
JH
1311 ),
1312 },
1313 wantRes: []Transaction{
1314 {
9ebf276d 1315 IsReply: 0x01,
153e2eac 1316 ErrorCode: [4]byte{0, 0, 0, 1},
9ebf276d 1317 Fields: []Field{
d005ef04 1318 NewField(FieldError, []byte("You are not allowed to view accounts.")),
9ebf276d
JH
1319 },
1320 },
1321 },
9ebf276d
JH
1322 },
1323 {
1324 name: "when account does not exist",
1325 args: args{
1326 cc: &ClientConn{
1327 Account: &Account{
187d6dc5 1328 Access: func() accessBitmap {
9ebf276d 1329 var bits accessBitmap
d9bc63a1 1330 bits.Set(AccessOpenUser)
187d6dc5 1331 return bits
9ebf276d
JH
1332 }(),
1333 },
1334 Server: &Server{
d9bc63a1
JH
1335 AccountManager: func() *MockAccountManager {
1336 m := MockAccountManager{}
1337 m.On("Get", "nonExistentUser").Return((*Account)(nil))
1338 return &m
1339 }(),
9ebf276d
JH
1340 },
1341 },
1342 t: NewTransaction(
a2ef262a 1343 TranGetUser, [2]byte{0, 1},
d005ef04 1344 NewField(FieldUserLogin, []byte("nonExistentUser")),
9ebf276d
JH
1345 ),
1346 },
1347 wantRes: []Transaction{
1348 {
1349 Flags: 0x00,
1350 IsReply: 0x01,
153e2eac
JH
1351 Type: [2]byte{0, 0},
1352 ErrorCode: [4]byte{0, 0, 0, 1},
9ebf276d 1353 Fields: []Field{
d005ef04 1354 NewField(FieldError, []byte("Account does not exist.")),
9ebf276d
JH
1355 },
1356 },
1357 },
9ebf276d
JH
1358 },
1359 }
1360 for _, tt := range tests {
1361 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1362 gotRes := HandleGetUser(tt.args.cc, &tt.args.t)
9ebf276d
JH
1363 tranAssertEqual(t, tt.wantRes, gotRes)
1364 })
1365 }
1366}
1367
1368func TestHandleDeleteUser(t *testing.T) {
1369 type args struct {
1370 cc *ClientConn
a2ef262a 1371 t Transaction
9ebf276d
JH
1372 }
1373 tests := []struct {
1374 name string
9ebf276d
JH
1375 args args
1376 wantRes []Transaction
9ebf276d
JH
1377 }{
1378 {
d9bc63a1 1379 name: "when user exists",
9ebf276d
JH
1380 args: args{
1381 cc: &ClientConn{
1382 Account: &Account{
187d6dc5 1383 Access: func() accessBitmap {
9ebf276d 1384 var bits accessBitmap
d9bc63a1 1385 bits.Set(AccessDeleteUser)
187d6dc5 1386 return bits
9ebf276d
JH
1387 }(),
1388 },
1389 Server: &Server{
d9bc63a1
JH
1390 AccountManager: func() *MockAccountManager {
1391 m := MockAccountManager{}
1392 m.On("Delete", "testuser").Return(nil)
1393 return &m
1394 }(),
1395 ClientMgr: func() *MockClientMgr {
1396 m := MockClientMgr{}
1397 m.On("List").Return([]*ClientConn{}) // TODO
1398 return &m
b196a50a 1399 }(),
9ebf276d
JH
1400 },
1401 },
1402 t: NewTransaction(
a2ef262a 1403 TranDeleteUser, [2]byte{0, 1},
76d0c1f6 1404 NewField(FieldUserLogin, encodeString([]byte("testuser"))),
9ebf276d
JH
1405 ),
1406 },
1407 wantRes: []Transaction{
1408 {
153e2eac
JH
1409 Flags: 0x00,
1410 IsReply: 0x01,
1411 Type: [2]byte{0, 0},
1412 Fields: []Field(nil),
9ebf276d
JH
1413 },
1414 },
9ebf276d
JH
1415 },
1416 {
b196a50a 1417 name: "when user does not have required permission",
9ebf276d
JH
1418 args: args{
1419 cc: &ClientConn{
1420 Account: &Account{
d9bc63a1 1421 Access: accessBitmap{},
9ebf276d
JH
1422 },
1423 Server: &Server{
d9bc63a1 1424 //Accounts: map[string]*Account{},
9ebf276d
JH
1425 },
1426 },
1427 t: NewTransaction(
a2ef262a 1428 TranDeleteUser, [2]byte{0, 1},
76d0c1f6 1429 NewField(FieldUserLogin, encodeString([]byte("testuser"))),
9ebf276d
JH
1430 ),
1431 },
1432 wantRes: []Transaction{
1433 {
9ebf276d 1434 IsReply: 0x01,
153e2eac 1435 ErrorCode: [4]byte{0, 0, 0, 1},
9ebf276d 1436 Fields: []Field{
d005ef04 1437 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
9ebf276d
JH
1438 },
1439 },
1440 },
9ebf276d
JH
1441 },
1442 }
1443 for _, tt := range tests {
1444 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1445 gotRes := HandleDeleteUser(tt.args.cc, &tt.args.t)
9ebf276d
JH
1446 tranAssertEqual(t, tt.wantRes, gotRes)
1447 })
1448 }
1449}
481631f6
JH
1450
1451func TestHandleGetMsgs(t *testing.T) {
1452 type args struct {
1453 cc *ClientConn
a2ef262a 1454 t Transaction
481631f6
JH
1455 }
1456 tests := []struct {
1457 name string
1458 args args
1459 wantRes []Transaction
481631f6
JH
1460 }{
1461 {
1462 name: "returns news data",
1463 args: args{
1464 cc: &ClientConn{
1465 Account: &Account{
187d6dc5 1466 Access: func() accessBitmap {
481631f6 1467 var bits accessBitmap
d9bc63a1 1468 bits.Set(AccessNewsReadArt)
187d6dc5 1469 return bits
481631f6
JH
1470 }(),
1471 },
1472 Server: &Server{
d9bc63a1
JH
1473 MessageBoard: func() *mockReadWriteSeeker {
1474 m := mockReadWriteSeeker{}
1475 m.On("Seek", int64(0), 0).Return(int64(0), nil)
1476 m.On("Read", mock.AnythingOfType("[]uint8")).Run(func(args mock.Arguments) {
1477 arg := args.Get(0).([]uint8)
1478 copy(arg, "TEST")
1479 }).Return(4, io.EOF)
1480 return &m
1481 }(),
481631f6
JH
1482 },
1483 },
1484 t: NewTransaction(
a2ef262a 1485 TranGetMsgs, [2]byte{0, 1},
481631f6
JH
1486 ),
1487 },
1488 wantRes: []Transaction{
1489 {
153e2eac 1490 IsReply: 0x01,
481631f6 1491 Fields: []Field{
d005ef04 1492 NewField(FieldData, []byte("TEST")),
481631f6
JH
1493 },
1494 },
1495 },
481631f6
JH
1496 },
1497 {
1498 name: "when user does not have required permission",
1499 args: args{
1500 cc: &ClientConn{
1501 Account: &Account{
d9bc63a1 1502 Access: accessBitmap{},
481631f6
JH
1503 },
1504 Server: &Server{
d9bc63a1 1505 //Accounts: map[string]*Account{},
481631f6
JH
1506 },
1507 },
1508 t: NewTransaction(
a2ef262a 1509 TranGetMsgs, [2]byte{0, 1},
481631f6
JH
1510 ),
1511 },
1512 wantRes: []Transaction{
1513 {
481631f6 1514 IsReply: 0x01,
153e2eac 1515 ErrorCode: [4]byte{0, 0, 0, 1},
481631f6 1516 Fields: []Field{
d005ef04 1517 NewField(FieldError, []byte("You are not allowed to read news.")),
481631f6
JH
1518 },
1519 },
1520 },
481631f6
JH
1521 },
1522 }
1523 for _, tt := range tests {
1524 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1525 gotRes := HandleGetMsgs(tt.args.cc, &tt.args.t)
481631f6
JH
1526 tranAssertEqual(t, tt.wantRes, gotRes)
1527 })
1528 }
1529}
1530
1531func TestHandleNewUser(t *testing.T) {
1532 type args struct {
1533 cc *ClientConn
a2ef262a 1534 t Transaction
481631f6
JH
1535 }
1536 tests := []struct {
1537 name string
1538 args args
1539 wantRes []Transaction
481631f6
JH
1540 }{
1541 {
1542 name: "when user does not have required permission",
1543 args: args{
1544 cc: &ClientConn{
1545 Account: &Account{
187d6dc5 1546 Access: func() accessBitmap {
481631f6 1547 var bits accessBitmap
187d6dc5 1548 return bits
481631f6
JH
1549 }(),
1550 },
1551 Server: &Server{
d9bc63a1 1552 //Accounts: map[string]*Account{},
481631f6
JH
1553 },
1554 },
1555 t: NewTransaction(
a2ef262a 1556 TranNewUser, [2]byte{0, 1},
481631f6
JH
1557 ),
1558 },
1559 wantRes: []Transaction{
1560 {
481631f6 1561 IsReply: 0x01,
153e2eac 1562 ErrorCode: [4]byte{0, 0, 0, 1},
481631f6 1563 Fields: []Field{
d005ef04 1564 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
481631f6
JH
1565 },
1566 },
1567 },
481631f6 1568 },
ecb1fcd9
JH
1569 {
1570 name: "when user attempts to create account with greater access",
1571 args: args{
1572 cc: &ClientConn{
1573 Account: &Account{
1574 Access: func() accessBitmap {
1575 var bits accessBitmap
d9bc63a1 1576 bits.Set(AccessCreateUser)
ecb1fcd9
JH
1577 return bits
1578 }(),
1579 },
1580 Server: &Server{
d9bc63a1
JH
1581 AccountManager: func() *MockAccountManager {
1582 m := MockAccountManager{}
1583 m.On("Get", "userB").Return((*Account)(nil))
1584 return &m
1585 }(),
ecb1fcd9
JH
1586 },
1587 },
1588 t: NewTransaction(
a2ef262a 1589 TranNewUser, [2]byte{0, 1},
d9bc63a1 1590 NewField(FieldUserLogin, encodeString([]byte("userB"))),
ecb1fcd9 1591 NewField(
d005ef04 1592 FieldUserAccess,
ecb1fcd9
JH
1593 func() []byte {
1594 var bits accessBitmap
d9bc63a1 1595 bits.Set(AccessDisconUser)
ecb1fcd9
JH
1596 return bits[:]
1597 }(),
1598 ),
1599 ),
1600 },
1601 wantRes: []Transaction{
1602 {
ecb1fcd9 1603 IsReply: 0x01,
153e2eac 1604 ErrorCode: [4]byte{0, 0, 0, 1},
ecb1fcd9 1605 Fields: []Field{
d005ef04 1606 NewField(FieldError, []byte("Cannot create account with more access than yourself.")),
ecb1fcd9
JH
1607 },
1608 },
1609 },
ecb1fcd9 1610 },
481631f6
JH
1611 }
1612 for _, tt := range tests {
1613 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1614 gotRes := HandleNewUser(tt.args.cc, &tt.args.t)
481631f6
JH
1615 tranAssertEqual(t, tt.wantRes, gotRes)
1616 })
1617 }
1618}
1619
1620func TestHandleListUsers(t *testing.T) {
1621 type args struct {
1622 cc *ClientConn
a2ef262a 1623 t Transaction
481631f6
JH
1624 }
1625 tests := []struct {
1626 name string
1627 args args
1628 wantRes []Transaction
481631f6
JH
1629 }{
1630 {
1631 name: "when user does not have required permission",
1632 args: args{
1633 cc: &ClientConn{
1634 Account: &Account{
187d6dc5 1635 Access: func() accessBitmap {
481631f6 1636 var bits accessBitmap
187d6dc5 1637 return bits
481631f6
JH
1638 }(),
1639 },
1640 Server: &Server{
d9bc63a1 1641 //Accounts: map[string]*Account{},
481631f6
JH
1642 },
1643 },
1644 t: NewTransaction(
a2ef262a 1645 TranNewUser, [2]byte{0, 1},
481631f6
JH
1646 ),
1647 },
1648 wantRes: []Transaction{
1649 {
481631f6 1650 IsReply: 0x01,
153e2eac 1651 ErrorCode: [4]byte{0, 0, 0, 1},
481631f6 1652 Fields: []Field{
d005ef04 1653 NewField(FieldError, []byte("You are not allowed to view accounts.")),
481631f6
JH
1654 },
1655 },
1656 },
481631f6 1657 },
60ec6281
JH
1658 {
1659 name: "when user has required permission",
1660 args: args{
1661 cc: &ClientConn{
1662 Account: &Account{
187d6dc5 1663 Access: func() accessBitmap {
60ec6281 1664 var bits accessBitmap
d9bc63a1 1665 bits.Set(AccessOpenUser)
187d6dc5 1666 return bits
60ec6281
JH
1667 }(),
1668 },
1669 Server: &Server{
d9bc63a1
JH
1670 AccountManager: func() *MockAccountManager {
1671 m := MockAccountManager{}
1672 m.On("List").Return([]Account{
1673 {
1674 Name: "guest",
1675 Login: "guest",
1676 Password: "zz",
1677 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
1678 },
1679 })
1680 return &m
1681 }(),
60ec6281
JH
1682 },
1683 },
1684 t: NewTransaction(
a2ef262a 1685 TranGetClientInfoText, [2]byte{0, 1},
d005ef04 1686 NewField(FieldUserID, []byte{0, 1}),
60ec6281
JH
1687 ),
1688 },
1689 wantRes: []Transaction{
1690 {
153e2eac 1691 IsReply: 0x01,
60ec6281 1692 Fields: []Field{
d005ef04 1693 NewField(FieldData, []byte{
60ec6281
JH
1694 0x00, 0x04, 0x00, 0x66, 0x00, 0x05, 0x67, 0x75, 0x65, 0x73, 0x74, 0x00, 0x69, 0x00, 0x05, 0x98,
1695 0x8a, 0x9a, 0x8c, 0x8b, 0x00, 0x6e, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1696 0x00, 0x6a, 0x00, 0x01, 0x78,
1697 }),
1698 },
1699 },
1700 },
60ec6281 1701 },
481631f6
JH
1702 }
1703 for _, tt := range tests {
1704 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1705 gotRes := HandleListUsers(tt.args.cc, &tt.args.t)
481631f6
JH
1706
1707 tranAssertEqual(t, tt.wantRes, gotRes)
1708 })
1709 }
1710}
1711
1712func TestHandleDownloadFile(t *testing.T) {
1713 type args struct {
1714 cc *ClientConn
a2ef262a 1715 t Transaction
481631f6
JH
1716 }
1717 tests := []struct {
1718 name string
1719 args args
1720 wantRes []Transaction
481631f6
JH
1721 }{
1722 {
1723 name: "when user does not have required permission",
1724 args: args{
1725 cc: &ClientConn{
1726 Account: &Account{
187d6dc5 1727 Access: func() accessBitmap {
481631f6 1728 var bits accessBitmap
187d6dc5 1729 return bits
481631f6
JH
1730 }(),
1731 },
1732 Server: &Server{},
1733 },
a2ef262a 1734 t: NewTransaction(TranDownloadFile, [2]byte{0, 1}),
481631f6
JH
1735 },
1736 wantRes: []Transaction{
1737 {
481631f6 1738 IsReply: 0x01,
153e2eac 1739 ErrorCode: [4]byte{0, 0, 0, 1},
481631f6 1740 Fields: []Field{
d005ef04 1741 NewField(FieldError, []byte("You are not allowed to download files.")),
481631f6
JH
1742 },
1743 },
1744 },
481631f6
JH
1745 },
1746 {
1747 name: "with a valid file",
1748 args: args{
1749 cc: &ClientConn{
d9bc63a1 1750 ClientFileTransferMgr: NewClientFileTransferMgr(),
481631f6 1751 Account: &Account{
187d6dc5 1752 Access: func() accessBitmap {
481631f6 1753 var bits accessBitmap
d9bc63a1 1754 bits.Set(AccessDownloadFile)
187d6dc5 1755 return bits
481631f6
JH
1756 }(),
1757 },
1758 Server: &Server{
d9bc63a1
JH
1759 FS: &OSFileStore{},
1760 FileTransferMgr: NewMemFileTransferMgr(),
1761 Config: Config{
481631f6
JH
1762 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1763 },
481631f6
JH
1764 },
1765 },
1766 t: NewTransaction(
a2ef262a
JH
1767 TranDownloadFile,
1768 [2]byte{0, 1},
d005ef04
JH
1769 NewField(FieldFileName, []byte("testfile.txt")),
1770 NewField(FieldFilePath, []byte{0x0, 0x00}),
481631f6
JH
1771 ),
1772 },
1773 wantRes: []Transaction{
1774 {
153e2eac 1775 IsReply: 0x01,
481631f6 1776 Fields: []Field{
d005ef04
JH
1777 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1778 NewField(FieldWaitingCount, []byte{0x00, 0x00}),
1779 NewField(FieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1780 NewField(FieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
481631f6
JH
1781 },
1782 },
1783 },
481631f6 1784 },
7cd900d6
JH
1785 {
1786 name: "when client requests to resume 1k test file at offset 256",
1787 args: args{
1788 cc: &ClientConn{
d9bc63a1
JH
1789 ClientFileTransferMgr: NewClientFileTransferMgr(),
1790 Account: &Account{
187d6dc5 1791 Access: func() accessBitmap {
7cd900d6 1792 var bits accessBitmap
d9bc63a1 1793 bits.Set(AccessDownloadFile)
187d6dc5 1794 return bits
7cd900d6
JH
1795 }(),
1796 },
1797 Server: &Server{
1798 FS: &OSFileStore{},
df1ade54 1799
7cd900d6
JH
1800 // FS: func() *MockFileStore {
1801 // path, _ := os.Getwd()
1802 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1803 // if err != nil {
1804 // panic(err)
1805 // }
1806 //
1807 // mfi := &MockFileInfo{}
1808 // mfi.On("Mode").Return(fs.FileMode(0))
1809 // mfs := &MockFileStore{}
1810 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1811 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1812 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
1813 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
1814 //
1815 // return mfs
1816 // }(),
d9bc63a1
JH
1817 FileTransferMgr: NewMemFileTransferMgr(),
1818 Config: Config{
7cd900d6
JH
1819 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1820 },
d9bc63a1 1821 //Accounts: map[string]*Account{},
7cd900d6
JH
1822 },
1823 },
1824 t: NewTransaction(
a2ef262a
JH
1825 TranDownloadFile,
1826 [2]byte{0, 1},
d005ef04
JH
1827 NewField(FieldFileName, []byte("testfile-1k")),
1828 NewField(FieldFilePath, []byte{0x00, 0x00}),
7cd900d6 1829 NewField(
d005ef04 1830 FieldFileResumeData,
7cd900d6
JH
1831 func() []byte {
1832 frd := FileResumeData{
7cd900d6
JH
1833 ForkCount: [2]byte{0, 2},
1834 ForkInfoList: []ForkInfoList{
1835 {
1836 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
1837 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
7cd900d6
JH
1838 },
1839 {
1840 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
1841 DataSize: [4]byte{0, 0, 0, 0},
7cd900d6
JH
1842 },
1843 },
1844 }
1845 b, _ := frd.BinaryMarshal()
1846 return b
1847 }(),
1848 ),
1849 ),
1850 },
1851 wantRes: []Transaction{
1852 {
153e2eac 1853 IsReply: 0x01,
7cd900d6 1854 Fields: []Field{
d005ef04
JH
1855 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1856 NewField(FieldWaitingCount, []byte{0x00, 0x00}),
1857 NewField(FieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
1858 NewField(FieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
7cd900d6
JH
1859 },
1860 },
1861 },
7cd900d6 1862 },
481631f6
JH
1863 }
1864 for _, tt := range tests {
1865 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1866 gotRes := HandleDownloadFile(tt.args.cc, &tt.args.t)
481631f6
JH
1867 tranAssertEqual(t, tt.wantRes, gotRes)
1868 })
1869 }
1870}
d2810ae9
JH
1871
1872func TestHandleUpdateUser(t *testing.T) {
1873 type args struct {
1874 cc *ClientConn
a2ef262a 1875 t Transaction
d2810ae9
JH
1876 }
1877 tests := []struct {
1878 name string
1879 args args
1880 wantRes []Transaction
d2810ae9
JH
1881 }{
1882 {
1883 name: "when action is create user without required permission",
1884 args: args{
1885 cc: &ClientConn{
02b446d8 1886 logger: NewTestLogger(),
d2810ae9 1887 Server: &Server{
d9bc63a1
JH
1888 AccountManager: func() *MockAccountManager {
1889 m := MockAccountManager{}
1890 m.On("Get", "bbb").Return((*Account)(nil))
1891 return &m
1892 }(),
d2810ae9
JH
1893 Logger: NewTestLogger(),
1894 },
1895 Account: &Account{
d9bc63a1 1896 Access: accessBitmap{},
d2810ae9
JH
1897 },
1898 },
1899 t: NewTransaction(
d005ef04 1900 TranUpdateUser,
a2ef262a 1901 [2]byte{0, 0},
d005ef04 1902 NewField(FieldData, []byte{
d2810ae9
JH
1903 0x00, 0x04, // field count
1904
d005ef04 1905 0x00, 0x69, // FieldUserLogin = 105
d2810ae9
JH
1906 0x00, 0x03,
1907 0x9d, 0x9d, 0x9d,
1908
d005ef04 1909 0x00, 0x6a, // FieldUserPassword = 106
d2810ae9
JH
1910 0x00, 0x03,
1911 0x9c, 0x9c, 0x9c,
1912
d005ef04 1913 0x00, 0x66, // FieldUserName = 102
d2810ae9
JH
1914 0x00, 0x03,
1915 0x61, 0x61, 0x61,
1916
d005ef04 1917 0x00, 0x6e, // FieldUserAccess = 110
d2810ae9
JH
1918 0x00, 0x08,
1919 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1920 }),
1921 ),
1922 },
1923 wantRes: []Transaction{
1924 {
d2810ae9 1925 IsReply: 0x01,
153e2eac 1926 ErrorCode: [4]byte{0, 0, 0, 1},
d2810ae9 1927 Fields: []Field{
d005ef04 1928 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
d2810ae9
JH
1929 },
1930 },
1931 },
d2810ae9
JH
1932 },
1933 {
1934 name: "when action is modify user without required permission",
1935 args: args{
1936 cc: &ClientConn{
02b446d8 1937 logger: NewTestLogger(),
d2810ae9
JH
1938 Server: &Server{
1939 Logger: NewTestLogger(),
d9bc63a1
JH
1940 AccountManager: func() *MockAccountManager {
1941 m := MockAccountManager{}
1942 m.On("Get", "bbb").Return(&Account{})
1943 return &m
1944 }(),
d2810ae9
JH
1945 },
1946 Account: &Account{
187d6dc5 1947 Access: func() accessBitmap {
d2810ae9 1948 var bits accessBitmap
187d6dc5 1949 return bits
d2810ae9
JH
1950 }(),
1951 },
1952 },
1953 t: NewTransaction(
d005ef04 1954 TranUpdateUser,
a2ef262a 1955 [2]byte{0, 0},
d005ef04 1956 NewField(FieldData, []byte{
d2810ae9
JH
1957 0x00, 0x04, // field count
1958
d005ef04 1959 0x00, 0x69, // FieldUserLogin = 105
d2810ae9
JH
1960 0x00, 0x03,
1961 0x9d, 0x9d, 0x9d,
1962
d005ef04 1963 0x00, 0x6a, // FieldUserPassword = 106
d2810ae9
JH
1964 0x00, 0x03,
1965 0x9c, 0x9c, 0x9c,
1966
d005ef04 1967 0x00, 0x66, // FieldUserName = 102
d2810ae9
JH
1968 0x00, 0x03,
1969 0x61, 0x61, 0x61,
1970
d005ef04 1971 0x00, 0x6e, // FieldUserAccess = 110
d2810ae9
JH
1972 0x00, 0x08,
1973 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1974 }),
1975 ),
1976 },
1977 wantRes: []Transaction{
1978 {
d2810ae9 1979 IsReply: 0x01,
153e2eac 1980 ErrorCode: [4]byte{0, 0, 0, 1},
d2810ae9 1981 Fields: []Field{
d005ef04 1982 NewField(FieldError, []byte("You are not allowed to modify accounts.")),
d2810ae9
JH
1983 },
1984 },
1985 },
d2810ae9
JH
1986 },
1987 {
1988 name: "when action is delete user without required permission",
1989 args: args{
1990 cc: &ClientConn{
02b446d8 1991 logger: NewTestLogger(),
d9bc63a1 1992 Server: &Server{},
d2810ae9 1993 Account: &Account{
d9bc63a1 1994 Access: accessBitmap{},
d2810ae9
JH
1995 },
1996 },
1997 t: NewTransaction(
d005ef04 1998 TranUpdateUser,
a2ef262a 1999 [2]byte{0, 0},
d005ef04 2000 NewField(FieldData, []byte{
d2810ae9
JH
2001 0x00, 0x01,
2002 0x00, 0x65,
2003 0x00, 0x03,
2004 0x88, 0x9e, 0x8b,
2005 }),
2006 ),
2007 },
2008 wantRes: []Transaction{
2009 {
d2810ae9 2010 IsReply: 0x01,
153e2eac 2011 ErrorCode: [4]byte{0, 0, 0, 1},
d2810ae9 2012 Fields: []Field{
d005ef04 2013 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
d2810ae9
JH
2014 },
2015 },
2016 },
d2810ae9
JH
2017 },
2018 }
2019 for _, tt := range tests {
2020 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2021 gotRes := HandleUpdateUser(tt.args.cc, &tt.args.t)
d2810ae9
JH
2022 tranAssertEqual(t, tt.wantRes, gotRes)
2023 })
2024 }
2025}
d4c152a4
JH
2026
2027func TestHandleDelNewsArt(t *testing.T) {
2028 type args struct {
2029 cc *ClientConn
a2ef262a 2030 t Transaction
d4c152a4
JH
2031 }
2032 tests := []struct {
2033 name string
2034 args args
2035 wantRes []Transaction
d4c152a4
JH
2036 }{
2037 {
2038 name: "without required permission",
2039 args: args{
2040 cc: &ClientConn{
2041 Account: &Account{
187d6dc5 2042 Access: func() accessBitmap {
d4c152a4 2043 var bits accessBitmap
187d6dc5 2044 return bits
d4c152a4
JH
2045 }(),
2046 },
2047 },
2048 t: NewTransaction(
d005ef04 2049 TranDelNewsArt,
a2ef262a 2050 [2]byte{0, 0},
d4c152a4
JH
2051 ),
2052 },
2053 wantRes: []Transaction{
2054 {
d4c152a4 2055 IsReply: 0x01,
153e2eac 2056 ErrorCode: [4]byte{0, 0, 0, 1},
d4c152a4 2057 Fields: []Field{
d005ef04 2058 NewField(FieldError, []byte("You are not allowed to delete news articles.")),
d4c152a4
JH
2059 },
2060 },
2061 },
d4c152a4
JH
2062 },
2063 }
2064 for _, tt := range tests {
2065 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2066 gotRes := HandleDelNewsArt(tt.args.cc, &tt.args.t)
d4c152a4
JH
2067 tranAssertEqual(t, tt.wantRes, gotRes)
2068 })
2069 }
2070}
2071
2072func TestHandleDisconnectUser(t *testing.T) {
2073 type args struct {
2074 cc *ClientConn
a2ef262a 2075 t Transaction
d4c152a4
JH
2076 }
2077 tests := []struct {
2078 name string
2079 args args
2080 wantRes []Transaction
d4c152a4
JH
2081 }{
2082 {
2083 name: "without required permission",
2084 args: args{
2085 cc: &ClientConn{
2086 Account: &Account{
187d6dc5 2087 Access: func() accessBitmap {
d4c152a4 2088 var bits accessBitmap
187d6dc5 2089 return bits
d4c152a4
JH
2090 }(),
2091 },
2092 },
2093 t: NewTransaction(
d005ef04 2094 TranDelNewsArt,
a2ef262a 2095 [2]byte{0, 0},
d4c152a4
JH
2096 ),
2097 },
2098 wantRes: []Transaction{
2099 {
d4c152a4 2100 IsReply: 0x01,
153e2eac 2101 ErrorCode: [4]byte{0, 0, 0, 1},
d4c152a4 2102 Fields: []Field{
d005ef04 2103 NewField(FieldError, []byte("You are not allowed to disconnect users.")),
d4c152a4
JH
2104 },
2105 },
2106 },
d4c152a4
JH
2107 },
2108 {
2109 name: "when target user has 'cannot be disconnected' priv",
2110 args: args{
2111 cc: &ClientConn{
2112 Server: &Server{
d9bc63a1
JH
2113 ClientMgr: func() *MockClientMgr {
2114 m := MockClientMgr{}
2115 m.On("Get", ClientID{0x0, 0x1}).Return(&ClientConn{
d4c152a4
JH
2116 Account: &Account{
2117 Login: "unnamed",
187d6dc5 2118 Access: func() accessBitmap {
d4c152a4 2119 var bits accessBitmap
d9bc63a1 2120 bits.Set(AccessCannotBeDiscon)
187d6dc5 2121 return bits
d4c152a4
JH
2122 }(),
2123 },
2124 },
d9bc63a1
JH
2125 )
2126 return &m
2127 }(),
d4c152a4
JH
2128 },
2129 Account: &Account{
187d6dc5 2130 Access: func() accessBitmap {
d4c152a4 2131 var bits accessBitmap
d9bc63a1 2132 bits.Set(AccessDisconUser)
187d6dc5 2133 return bits
d4c152a4
JH
2134 }(),
2135 },
2136 },
2137 t: NewTransaction(
d005ef04 2138 TranDelNewsArt,
a2ef262a 2139 [2]byte{0, 0},
d005ef04 2140 NewField(FieldUserID, []byte{0, 1}),
d4c152a4
JH
2141 ),
2142 },
2143 wantRes: []Transaction{
2144 {
d4c152a4 2145 IsReply: 0x01,
153e2eac 2146 ErrorCode: [4]byte{0, 0, 0, 1},
d4c152a4 2147 Fields: []Field{
d005ef04 2148 NewField(FieldError, []byte("unnamed is not allowed to be disconnected.")),
d4c152a4
JH
2149 },
2150 },
2151 },
d4c152a4
JH
2152 },
2153 }
2154 for _, tt := range tests {
2155 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2156 gotRes := HandleDisconnectUser(tt.args.cc, &tt.args.t)
d4c152a4
JH
2157 tranAssertEqual(t, tt.wantRes, gotRes)
2158 })
2159 }
2160}
aeec1015
JH
2161
2162func TestHandleSendInstantMsg(t *testing.T) {
2163 type args struct {
2164 cc *ClientConn
a2ef262a 2165 t Transaction
aeec1015
JH
2166 }
2167 tests := []struct {
2168 name string
2169 args args
2170 wantRes []Transaction
aeec1015 2171 }{
69c2fb50
JH
2172 {
2173 name: "without required permission",
2174 args: args{
2175 cc: &ClientConn{
2176 Account: &Account{
187d6dc5 2177 Access: func() accessBitmap {
69c2fb50 2178 var bits accessBitmap
187d6dc5 2179 return bits
69c2fb50
JH
2180 }(),
2181 },
2182 },
2183 t: NewTransaction(
d005ef04 2184 TranDelNewsArt,
a2ef262a 2185 [2]byte{0, 0},
69c2fb50
JH
2186 ),
2187 },
2188 wantRes: []Transaction{
2189 {
69c2fb50 2190 IsReply: 0x01,
153e2eac 2191 ErrorCode: [4]byte{0, 0, 0, 1},
69c2fb50 2192 Fields: []Field{
d005ef04 2193 NewField(FieldError, []byte("You are not allowed to send private messages.")),
69c2fb50
JH
2194 },
2195 },
2196 },
69c2fb50 2197 },
aeec1015
JH
2198 {
2199 name: "when client 1 sends a message to client 2",
2200 args: args{
2201 cc: &ClientConn{
69c2fb50 2202 Account: &Account{
187d6dc5 2203 Access: func() accessBitmap {
69c2fb50 2204 var bits accessBitmap
d9bc63a1 2205 bits.Set(AccessSendPrivMsg)
187d6dc5 2206 return bits
69c2fb50
JH
2207 }(),
2208 },
a2ef262a 2209 ID: [2]byte{0, 1},
aeec1015
JH
2210 UserName: []byte("User1"),
2211 Server: &Server{
d9bc63a1
JH
2212 ClientMgr: func() *MockClientMgr {
2213 m := MockClientMgr{}
2214 m.On("Get", ClientID{0x0, 0x2}).Return(&ClientConn{
aeec1015 2215 AutoReply: []byte(nil),
a2ef262a 2216 Flags: [2]byte{0, 0},
aeec1015 2217 },
d9bc63a1
JH
2218 )
2219 return &m
2220 }(),
aeec1015
JH
2221 },
2222 },
2223 t: NewTransaction(
d005ef04 2224 TranSendInstantMsg,
a2ef262a 2225 [2]byte{0, 1},
d005ef04
JH
2226 NewField(FieldData, []byte("hai")),
2227 NewField(FieldUserID, []byte{0, 2}),
aeec1015
JH
2228 ),
2229 },
2230 wantRes: []Transaction{
a2ef262a 2231 NewTransaction(
d005ef04 2232 TranServerMsg,
a2ef262a 2233 [2]byte{0, 2},
d005ef04
JH
2234 NewField(FieldData, []byte("hai")),
2235 NewField(FieldUserName, []byte("User1")),
2236 NewField(FieldUserID, []byte{0, 1}),
2237 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2238 ),
2239 {
a2ef262a 2240 clientID: [2]byte{0, 1},
153e2eac
JH
2241 IsReply: 0x01,
2242 Fields: []Field(nil),
aeec1015
JH
2243 },
2244 },
aeec1015
JH
2245 },
2246 {
2247 name: "when client 2 has autoreply enabled",
2248 args: args{
2249 cc: &ClientConn{
69c2fb50 2250 Account: &Account{
187d6dc5 2251 Access: func() accessBitmap {
69c2fb50 2252 var bits accessBitmap
d9bc63a1 2253 bits.Set(AccessSendPrivMsg)
187d6dc5 2254 return bits
69c2fb50
JH
2255 }(),
2256 },
a2ef262a 2257 ID: [2]byte{0, 1},
aeec1015
JH
2258 UserName: []byte("User1"),
2259 Server: &Server{
d9bc63a1
JH
2260 ClientMgr: func() *MockClientMgr {
2261 m := MockClientMgr{}
2262 m.On("Get", ClientID{0x0, 0x2}).Return(&ClientConn{
a2ef262a
JH
2263 Flags: [2]byte{0, 0},
2264 ID: [2]byte{0, 2},
aeec1015
JH
2265 UserName: []byte("User2"),
2266 AutoReply: []byte("autohai"),
d9bc63a1
JH
2267 })
2268 return &m
2269 }(),
aeec1015
JH
2270 },
2271 },
2272 t: NewTransaction(
d005ef04 2273 TranSendInstantMsg,
a2ef262a 2274 [2]byte{0, 1},
d005ef04
JH
2275 NewField(FieldData, []byte("hai")),
2276 NewField(FieldUserID, []byte{0, 2}),
aeec1015
JH
2277 ),
2278 },
2279 wantRes: []Transaction{
a2ef262a 2280 NewTransaction(
d005ef04 2281 TranServerMsg,
a2ef262a 2282 [2]byte{0, 2},
d005ef04
JH
2283 NewField(FieldData, []byte("hai")),
2284 NewField(FieldUserName, []byte("User1")),
2285 NewField(FieldUserID, []byte{0, 1}),
2286 NewField(FieldOptions, []byte{0, 1}),
aeec1015 2287 ),
a2ef262a 2288 NewTransaction(
d005ef04 2289 TranServerMsg,
a2ef262a 2290 [2]byte{0, 1},
d005ef04
JH
2291 NewField(FieldData, []byte("autohai")),
2292 NewField(FieldUserName, []byte("User2")),
2293 NewField(FieldUserID, []byte{0, 2}),
2294 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2295 ),
2296 {
a2ef262a 2297 clientID: [2]byte{0, 1},
153e2eac
JH
2298 IsReply: 0x01,
2299 Fields: []Field(nil),
aeec1015
JH
2300 },
2301 },
aeec1015 2302 },
38f710ec
JH
2303 {
2304 name: "when client 2 has refuse private messages enabled",
2305 args: args{
2306 cc: &ClientConn{
2307 Account: &Account{
2308 Access: func() accessBitmap {
2309 var bits accessBitmap
d9bc63a1 2310 bits.Set(AccessSendPrivMsg)
38f710ec
JH
2311 return bits
2312 }(),
2313 },
a2ef262a 2314 ID: [2]byte{0, 1},
38f710ec
JH
2315 UserName: []byte("User1"),
2316 Server: &Server{
d9bc63a1
JH
2317 ClientMgr: func() *MockClientMgr {
2318 m := MockClientMgr{}
2319 m.On("Get", ClientID{0x0, 0x2}).Return(&ClientConn{
a2ef262a
JH
2320 Flags: [2]byte{255, 255},
2321 ID: [2]byte{0, 2},
38f710ec
JH
2322 UserName: []byte("User2"),
2323 },
d9bc63a1
JH
2324 )
2325 return &m
2326 }(),
38f710ec
JH
2327 },
2328 },
2329 t: NewTransaction(
d005ef04 2330 TranSendInstantMsg,
a2ef262a 2331 [2]byte{0, 1},
d005ef04
JH
2332 NewField(FieldData, []byte("hai")),
2333 NewField(FieldUserID, []byte{0, 2}),
38f710ec
JH
2334 ),
2335 },
2336 wantRes: []Transaction{
a2ef262a 2337 NewTransaction(
d005ef04 2338 TranServerMsg,
a2ef262a 2339 [2]byte{0, 1},
d005ef04
JH
2340 NewField(FieldData, []byte("User2 does not accept private messages.")),
2341 NewField(FieldUserName, []byte("User2")),
2342 NewField(FieldUserID, []byte{0, 2}),
2343 NewField(FieldOptions, []byte{0, 2}),
38f710ec
JH
2344 ),
2345 {
a2ef262a 2346 clientID: [2]byte{0, 1},
153e2eac
JH
2347 IsReply: 0x01,
2348 Fields: []Field(nil),
38f710ec
JH
2349 },
2350 },
38f710ec 2351 },
aeec1015
JH
2352 }
2353 for _, tt := range tests {
2354 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2355 gotRes := HandleSendInstantMsg(tt.args.cc, &tt.args.t)
aeec1015
JH
2356 tranAssertEqual(t, tt.wantRes, gotRes)
2357 })
2358 }
2359}
7cd900d6
JH
2360
2361func TestHandleDeleteFile(t *testing.T) {
2362 type args struct {
2363 cc *ClientConn
a2ef262a 2364 t Transaction
7cd900d6
JH
2365 }
2366 tests := []struct {
2367 name string
2368 args args
2369 wantRes []Transaction
7cd900d6
JH
2370 }{
2371 {
2372 name: "when user does not have required permission to delete a folder",
2373 args: args{
2374 cc: &ClientConn{
2375 Account: &Account{
187d6dc5 2376 Access: func() accessBitmap {
7cd900d6 2377 var bits accessBitmap
187d6dc5 2378 return bits
7cd900d6
JH
2379 }(),
2380 },
2381 Server: &Server{
d9bc63a1 2382 Config: Config{
7cd900d6
JH
2383 FileRoot: func() string {
2384 return "/fakeRoot/Files"
2385 }(),
2386 },
2387 FS: func() *MockFileStore {
2388 mfi := &MockFileInfo{}
2389 mfi.On("Mode").Return(fs.FileMode(0))
2390 mfi.On("Size").Return(int64(100))
2391 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2392 mfi.On("IsDir").Return(false)
2393 mfi.On("Name").Return("testfile")
2394
2395 mfs := &MockFileStore{}
2396 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2397 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2398 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2399
2400 return mfs
2401 }(),
d9bc63a1 2402 //Accounts: map[string]*Account{},
7cd900d6
JH
2403 },
2404 },
2405 t: NewTransaction(
a2ef262a 2406 TranDeleteFile, [2]byte{0, 1},
d005ef04
JH
2407 NewField(FieldFileName, []byte("testfile")),
2408 NewField(FieldFilePath, []byte{
7cd900d6
JH
2409 0x00, 0x01,
2410 0x00, 0x00,
2411 0x03,
2412 0x61, 0x61, 0x61,
2413 }),
2414 ),
2415 },
2416 wantRes: []Transaction{
2417 {
7cd900d6 2418 IsReply: 0x01,
153e2eac 2419 ErrorCode: [4]byte{0, 0, 0, 1},
7cd900d6 2420 Fields: []Field{
d005ef04 2421 NewField(FieldError, []byte("You are not allowed to delete files.")),
7cd900d6
JH
2422 },
2423 },
2424 },
7cd900d6
JH
2425 },
2426 {
2427 name: "deletes all associated metadata files",
2428 args: args{
2429 cc: &ClientConn{
2430 Account: &Account{
187d6dc5 2431 Access: func() accessBitmap {
7cd900d6 2432 var bits accessBitmap
d9bc63a1 2433 bits.Set(AccessDeleteFile)
187d6dc5 2434 return bits
7cd900d6
JH
2435 }(),
2436 },
2437 Server: &Server{
d9bc63a1 2438 Config: Config{
7cd900d6
JH
2439 FileRoot: func() string {
2440 return "/fakeRoot/Files"
2441 }(),
2442 },
2443 FS: func() *MockFileStore {
2444 mfi := &MockFileInfo{}
2445 mfi.On("Mode").Return(fs.FileMode(0))
2446 mfi.On("Size").Return(int64(100))
2447 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2448 mfi.On("IsDir").Return(false)
2449 mfi.On("Name").Return("testfile")
2450
2451 mfs := &MockFileStore{}
2452 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2453 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2454 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2455
2456 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2457 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2458 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2459 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2460
2461 return mfs
2462 }(),
d9bc63a1 2463 //Accounts: map[string]*Account{},
7cd900d6
JH
2464 },
2465 },
2466 t: NewTransaction(
a2ef262a 2467 TranDeleteFile, [2]byte{0, 1},
d005ef04
JH
2468 NewField(FieldFileName, []byte("testfile")),
2469 NewField(FieldFilePath, []byte{
7cd900d6
JH
2470 0x00, 0x01,
2471 0x00, 0x00,
2472 0x03,
2473 0x61, 0x61, 0x61,
2474 }),
2475 ),
2476 },
2477 wantRes: []Transaction{
2478 {
153e2eac
JH
2479 IsReply: 0x01,
2480 Fields: []Field(nil),
7cd900d6
JH
2481 },
2482 },
7cd900d6
JH
2483 },
2484 }
2485 for _, tt := range tests {
2486 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2487 gotRes := HandleDeleteFile(tt.args.cc, &tt.args.t)
7cd900d6
JH
2488 tranAssertEqual(t, tt.wantRes, gotRes)
2489
2490 tt.args.cc.Server.FS.(*MockFileStore).AssertExpectations(t)
2491 })
2492 }
2493}
2e08be58
JH
2494
2495func TestHandleGetFileNameList(t *testing.T) {
2496 type args struct {
2497 cc *ClientConn
a2ef262a 2498 t Transaction
2e08be58
JH
2499 }
2500 tests := []struct {
2501 name string
2502 args args
2503 wantRes []Transaction
2e08be58
JH
2504 }{
2505 {
d9bc63a1 2506 name: "when FieldFilePath is a drop box, but user does not have AccessViewDropBoxes ",
2e08be58
JH
2507 args: args{
2508 cc: &ClientConn{
2509 Account: &Account{
187d6dc5 2510 Access: func() accessBitmap {
2e08be58 2511 var bits accessBitmap
187d6dc5 2512 return bits
2e08be58
JH
2513 }(),
2514 },
2515 Server: &Server{
2516
d9bc63a1 2517 Config: Config{
2e08be58
JH
2518 FileRoot: func() string {
2519 path, _ := os.Getwd()
2520 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2521 }(),
2522 },
2523 },
2524 },
2525 t: NewTransaction(
a2ef262a 2526 TranGetFileNameList, [2]byte{0, 1},
d005ef04 2527 NewField(FieldFilePath, []byte{
2e08be58
JH
2528 0x00, 0x01,
2529 0x00, 0x00,
2530 0x08,
2531 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2532 }),
2533 ),
2534 },
2535 wantRes: []Transaction{
2536 {
2e08be58 2537 IsReply: 0x01,
153e2eac 2538 ErrorCode: [4]byte{0, 0, 0, 1},
2e08be58 2539 Fields: []Field{
d005ef04 2540 NewField(FieldError, []byte("You are not allowed to view drop boxes.")),
2e08be58
JH
2541 },
2542 },
2543 },
2e08be58
JH
2544 },
2545 {
2546 name: "with file root",
2547 args: args{
2548 cc: &ClientConn{
2549 Server: &Server{
d9bc63a1 2550 Config: Config{
2e08be58
JH
2551 FileRoot: func() string {
2552 path, _ := os.Getwd()
2553 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2554 }(),
2555 },
2556 },
2557 },
2558 t: NewTransaction(
a2ef262a 2559 TranGetFileNameList, [2]byte{0, 1},
d005ef04 2560 NewField(FieldFilePath, []byte{
2e08be58
JH
2561 0x00, 0x00,
2562 0x00, 0x00,
2563 }),
2564 ),
2565 },
2566 wantRes: []Transaction{
2567 {
153e2eac 2568 IsReply: 0x01,
2e08be58
JH
2569 Fields: []Field{
2570 NewField(
d005ef04 2571 FieldFileNameWithInfo,
2e08be58
JH
2572 func() []byte {
2573 fnwi := FileNameWithInfo{
2574 fileNameWithInfoHeader: fileNameWithInfoHeader{
2575 Type: [4]byte{0x54, 0x45, 0x58, 0x54},
2576 Creator: [4]byte{0x54, 0x54, 0x58, 0x54},
2577 FileSize: [4]byte{0, 0, 0x04, 0},
2578 RSVD: [4]byte{},
2579 NameScript: [2]byte{},
2580 NameSize: [2]byte{0, 0x0b},
2581 },
95159e55 2582 Name: []byte("testfile-1k"),
2e08be58 2583 }
b129b7cb 2584 b, _ := io.ReadAll(&fnwi)
2e08be58
JH
2585 return b
2586 }(),
2587 ),
2588 },
2589 },
2590 },
2e08be58
JH
2591 },
2592 }
2593 for _, tt := range tests {
2594 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2595 gotRes := HandleGetFileNameList(tt.args.cc, &tt.args.t)
2e08be58
JH
2596 tranAssertEqual(t, tt.wantRes, gotRes)
2597 })
2598 }
2599}
df1ade54
JH
2600
2601func TestHandleGetClientInfoText(t *testing.T) {
2602 type args struct {
2603 cc *ClientConn
a2ef262a 2604 t Transaction
df1ade54
JH
2605 }
2606 tests := []struct {
2607 name string
2608 args args
2609 wantRes []Transaction
df1ade54
JH
2610 }{
2611 {
2612 name: "when user does not have required permission",
2613 args: args{
2614 cc: &ClientConn{
2615 Account: &Account{
187d6dc5 2616 Access: func() accessBitmap {
df1ade54 2617 var bits accessBitmap
187d6dc5 2618 return bits
df1ade54
JH
2619 }(),
2620 },
2621 Server: &Server{
d9bc63a1 2622 //Accounts: map[string]*Account{},
df1ade54
JH
2623 },
2624 },
2625 t: NewTransaction(
a2ef262a 2626 TranGetClientInfoText, [2]byte{0, 1},
d005ef04 2627 NewField(FieldUserID, []byte{0, 1}),
df1ade54
JH
2628 ),
2629 },
2630 wantRes: []Transaction{
2631 {
df1ade54 2632 IsReply: 0x01,
153e2eac 2633 ErrorCode: [4]byte{0, 0, 0, 1},
df1ade54 2634 Fields: []Field{
d005ef04 2635 NewField(FieldError, []byte("You are not allowed to get client info.")),
df1ade54
JH
2636 },
2637 },
2638 },
df1ade54
JH
2639 },
2640 {
2641 name: "with a valid user",
2642 args: args{
2643 cc: &ClientConn{
2644 UserName: []byte("Testy McTest"),
2645 RemoteAddr: "1.2.3.4:12345",
2646 Account: &Account{
187d6dc5 2647 Access: func() accessBitmap {
df1ade54 2648 var bits accessBitmap
d9bc63a1 2649 bits.Set(AccessGetClientInfo)
187d6dc5 2650 return bits
df1ade54
JH
2651 }(),
2652 Name: "test",
2653 Login: "test",
2654 },
2655 Server: &Server{
d9bc63a1
JH
2656 ClientMgr: func() *MockClientMgr {
2657 m := MockClientMgr{}
2658 m.On("Get", ClientID{0x0, 0x1}).Return(&ClientConn{
df1ade54
JH
2659 UserName: []byte("Testy McTest"),
2660 RemoteAddr: "1.2.3.4:12345",
2661 Account: &Account{
187d6dc5 2662 Access: func() accessBitmap {
df1ade54 2663 var bits accessBitmap
d9bc63a1 2664 bits.Set(AccessGetClientInfo)
187d6dc5 2665 return bits
df1ade54
JH
2666 }(),
2667 Name: "test",
2668 Login: "test",
2669 },
2670 },
d9bc63a1
JH
2671 )
2672 return &m
2673 }(),
df1ade54 2674 },
d9bc63a1 2675 ClientFileTransferMgr: ClientFileTransferMgr{},
df1ade54
JH
2676 },
2677 t: NewTransaction(
a2ef262a 2678 TranGetClientInfoText, [2]byte{0, 1},
d005ef04 2679 NewField(FieldUserID, []byte{0, 1}),
df1ade54
JH
2680 ),
2681 },
2682 wantRes: []Transaction{
2683 {
153e2eac 2684 IsReply: 0x01,
df1ade54 2685 Fields: []Field{
d005ef04 2686 NewField(FieldData, []byte(
c8bfd606 2687 strings.ReplaceAll(`Nickname: Testy McTest
df1ade54
JH
2688Name: test
2689Account: test
2690Address: 1.2.3.4:12345
2691
2692-------- File Downloads ---------
2693
2694None.
2695
2696------- Folder Downloads --------
2697
2698None.
2699
2700--------- File Uploads ----------
2701
2702None.
2703
2704-------- Folder Uploads ---------
2705
2706None.
2707
2708------- Waiting Downloads -------
2709
2710None.
2711
c8bfd606 2712`, "\n", "\r")),
df1ade54 2713 ),
d005ef04 2714 NewField(FieldUserName, []byte("Testy McTest")),
df1ade54
JH
2715 },
2716 },
2717 },
df1ade54
JH
2718 },
2719 }
2720 for _, tt := range tests {
2721 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2722 gotRes := HandleGetClientInfoText(tt.args.cc, &tt.args.t)
df1ade54
JH
2723 tranAssertEqual(t, tt.wantRes, gotRes)
2724 })
2725 }
2726}
ea5d8c51
JH
2727
2728func TestHandleTranAgreed(t *testing.T) {
2729 type args struct {
2730 cc *ClientConn
a2ef262a 2731 t Transaction
ea5d8c51
JH
2732 }
2733 tests := []struct {
2734 name string
2735 args args
2736 wantRes []Transaction
ea5d8c51
JH
2737 }{
2738 {
2739 name: "normal request flow",
2740 args: args{
2741 cc: &ClientConn{
2742 Account: &Account{
187d6dc5 2743 Access: func() accessBitmap {
ea5d8c51 2744 var bits accessBitmap
d9bc63a1
JH
2745 bits.Set(AccessDisconUser)
2746 bits.Set(AccessAnyName)
187d6dc5 2747 return bits
ea5d8c51 2748 }()},
a7216f67 2749 Icon: []byte{0, 1},
a2ef262a 2750 Flags: [2]byte{0, 1},
a7216f67 2751 Version: []byte{0, 1},
a2ef262a 2752 ID: [2]byte{0, 1},
ea5d8c51
JH
2753 logger: NewTestLogger(),
2754 Server: &Server{
d9bc63a1 2755 Config: Config{
ea5d8c51
JH
2756 BannerFile: "banner.jpg",
2757 },
d9bc63a1
JH
2758 ClientMgr: func() *MockClientMgr {
2759 m := MockClientMgr{}
2760 m.On("List").Return([]*ClientConn{
2761 //{
2762 // ID: [2]byte{0, 2},
2763 // UserName: []byte("UserB"),
2764 //},
2765 },
2766 )
2767 return &m
2768 }(),
ea5d8c51
JH
2769 },
2770 },
2771 t: NewTransaction(
a2ef262a 2772 TranAgreed, [2]byte{},
d005ef04
JH
2773 NewField(FieldUserName, []byte("username")),
2774 NewField(FieldUserIconID, []byte{0, 1}),
2775 NewField(FieldOptions, []byte{0, 0}),
ea5d8c51
JH
2776 ),
2777 },
2778 wantRes: []Transaction{
2779 {
a2ef262a 2780 clientID: [2]byte{0, 1},
153e2eac 2781 Type: [2]byte{0, 0x7a},
ea5d8c51 2782 Fields: []Field{
d005ef04 2783 NewField(FieldBannerType, []byte("JPEG")),
ea5d8c51
JH
2784 },
2785 },
2786 {
a2ef262a 2787 clientID: [2]byte{0, 1},
153e2eac
JH
2788 IsReply: 0x01,
2789 Fields: []Field{},
ea5d8c51
JH
2790 },
2791 },
ea5d8c51
JH
2792 },
2793 }
2794 for _, tt := range tests {
2795 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2796 gotRes := HandleTranAgreed(tt.args.cc, &tt.args.t)
ea5d8c51
JH
2797 tranAssertEqual(t, tt.wantRes, gotRes)
2798 })
2799 }
2800}
264b7c27
JH
2801
2802func TestHandleSetClientUserInfo(t *testing.T) {
2803 type args struct {
2804 cc *ClientConn
a2ef262a 2805 t Transaction
264b7c27
JH
2806 }
2807 tests := []struct {
2808 name string
2809 args args
2810 wantRes []Transaction
264b7c27
JH
2811 }{
2812 {
d9bc63a1 2813 name: "when client does not have AccessAnyName",
264b7c27
JH
2814 args: args{
2815 cc: &ClientConn{
2816 Account: &Account{
187d6dc5 2817 Access: func() accessBitmap {
264b7c27 2818 var bits accessBitmap
187d6dc5 2819 return bits
264b7c27
JH
2820 }(),
2821 },
a2ef262a 2822 ID: [2]byte{0, 1},
264b7c27 2823 UserName: []byte("Guest"),
a2ef262a 2824 Flags: [2]byte{0, 1},
264b7c27 2825 Server: &Server{
d9bc63a1
JH
2826 ClientMgr: func() *MockClientMgr {
2827 m := MockClientMgr{}
2828 m.On("List").Return([]*ClientConn{
2829 {
2830 ID: [2]byte{0, 1},
2831 },
2832 })
2833 return &m
2834 }(),
264b7c27
JH
2835 },
2836 },
2837 t: NewTransaction(
a2ef262a 2838 TranSetClientUserInfo, [2]byte{},
d005ef04
JH
2839 NewField(FieldUserIconID, []byte{0, 1}),
2840 NewField(FieldUserName, []byte("NOPE")),
264b7c27
JH
2841 ),
2842 },
2843 wantRes: []Transaction{
2844 {
a2ef262a 2845 clientID: [2]byte{0, 1},
153e2eac 2846 Type: [2]byte{0x01, 0x2d},
264b7c27 2847 Fields: []Field{
d005ef04
JH
2848 NewField(FieldUserID, []byte{0, 1}),
2849 NewField(FieldUserIconID, []byte{0, 1}),
2850 NewField(FieldUserFlags, []byte{0, 1}),
2851 NewField(FieldUserName, []byte("Guest"))},
264b7c27
JH
2852 },
2853 },
264b7c27
JH
2854 },
2855 }
2856 for _, tt := range tests {
2857 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2858 gotRes := HandleSetClientUserInfo(tt.args.cc, &tt.args.t)
264b7c27
JH
2859 tranAssertEqual(t, tt.wantRes, gotRes)
2860 })
2861 }
2862}
8eb43f95
JH
2863
2864func TestHandleDelNewsItem(t *testing.T) {
2865 type args struct {
2866 cc *ClientConn
a2ef262a 2867 t Transaction
8eb43f95
JH
2868 }
2869 tests := []struct {
2870 name string
2871 args args
2872 wantRes []Transaction
8eb43f95
JH
2873 }{
2874 {
2875 name: "when user does not have permission to delete a news category",
2876 args: args{
2877 cc: &ClientConn{
2878 Account: &Account{
2879 Access: accessBitmap{},
2880 },
a2ef262a 2881 ID: [2]byte{0, 1},
8eb43f95 2882 Server: &Server{
d9bc63a1
JH
2883 ThreadedNewsMgr: func() *mockThreadNewsMgr {
2884 m := mockThreadNewsMgr{}
2885 m.On("NewsItem", []string{"test"}).Return(NewsCategoryListData15{
2886 Type: NewsCategory,
2887 })
2888 return &m
2889 }(),
8eb43f95
JH
2890 },
2891 },
2892 t: NewTransaction(
a2ef262a 2893 TranDelNewsItem, [2]byte{},
d005ef04 2894 NewField(FieldNewsPath,
8eb43f95
JH
2895 []byte{
2896 0, 1,
2897 0, 0,
2898 4,
2899 0x74, 0x65, 0x73, 0x74,
2900 },
2901 ),
2902 ),
2903 },
2904 wantRes: []Transaction{
2905 {
a2ef262a 2906 clientID: [2]byte{0, 1},
8eb43f95 2907 IsReply: 0x01,
153e2eac 2908 ErrorCode: [4]byte{0, 0, 0, 1},
8eb43f95 2909 Fields: []Field{
d005ef04 2910 NewField(FieldError, []byte("You are not allowed to delete news categories.")),
8eb43f95
JH
2911 },
2912 },
2913 },
8eb43f95
JH
2914 },
2915 {
2916 name: "when user does not have permission to delete a news folder",
2917 args: args{
2918 cc: &ClientConn{
2919 Account: &Account{
2920 Access: accessBitmap{},
2921 },
a2ef262a 2922 ID: [2]byte{0, 1},
8eb43f95 2923 Server: &Server{
d9bc63a1
JH
2924 ThreadedNewsMgr: func() *mockThreadNewsMgr {
2925 m := mockThreadNewsMgr{}
2926 m.On("NewsItem", []string{"test"}).Return(NewsCategoryListData15{
2927 Type: NewsBundle,
2928 })
2929 return &m
2930 }(),
8eb43f95
JH
2931 },
2932 },
2933 t: NewTransaction(
a2ef262a 2934 TranDelNewsItem, [2]byte{},
d005ef04 2935 NewField(FieldNewsPath,
8eb43f95
JH
2936 []byte{
2937 0, 1,
2938 0, 0,
2939 4,
2940 0x74, 0x65, 0x73, 0x74,
2941 },
2942 ),
2943 ),
2944 },
2945 wantRes: []Transaction{
2946 {
a2ef262a 2947 clientID: [2]byte{0, 1},
8eb43f95 2948 IsReply: 0x01,
153e2eac 2949 ErrorCode: [4]byte{0, 0, 0, 1},
8eb43f95 2950 Fields: []Field{
d005ef04 2951 NewField(FieldError, []byte("You are not allowed to delete news folders.")),
8eb43f95
JH
2952 },
2953 },
2954 },
8eb43f95
JH
2955 },
2956 {
2957 name: "when user deletes a news folder",
2958 args: args{
2959 cc: &ClientConn{
2960 Account: &Account{
2961 Access: func() accessBitmap {
2962 var bits accessBitmap
d9bc63a1 2963 bits.Set(AccessNewsDeleteFldr)
8eb43f95
JH
2964 return bits
2965 }(),
2966 },
a2ef262a 2967 ID: [2]byte{0, 1},
8eb43f95 2968 Server: &Server{
d9bc63a1
JH
2969 ThreadedNewsMgr: func() *mockThreadNewsMgr {
2970 m := mockThreadNewsMgr{}
2971 m.On("NewsItem", []string{"test"}).Return(NewsCategoryListData15{Type: NewsBundle})
2972 m.On("DeleteNewsItem", []string{"test"}).Return(nil)
2973 return &m
8eb43f95 2974 }(),
8eb43f95
JH
2975 },
2976 },
2977 t: NewTransaction(
a2ef262a 2978 TranDelNewsItem, [2]byte{},
d005ef04 2979 NewField(FieldNewsPath,
8eb43f95
JH
2980 []byte{
2981 0, 1,
2982 0, 0,
2983 4,
2984 0x74, 0x65, 0x73, 0x74,
2985 },
2986 ),
2987 ),
2988 },
2989 wantRes: []Transaction{
2990 {
a2ef262a 2991 clientID: [2]byte{0, 1},
153e2eac
JH
2992 IsReply: 0x01,
2993 Fields: []Field{},
8eb43f95
JH
2994 },
2995 },
8eb43f95
JH
2996 },
2997 }
2998 for _, tt := range tests {
2999 t.Run(tt.name, func(t *testing.T) {
a2ef262a
JH
3000 gotRes := HandleDelNewsItem(tt.args.cc, &tt.args.t)
3001
8eb43f95 3002 tranAssertEqual(t, tt.wantRes, gotRes)
969e6481
JH
3003 })
3004 }
3005}
8a1512f9
JH
3006
3007func TestHandleTranOldPostNews(t *testing.T) {
3008 type args struct {
3009 cc *ClientConn
a2ef262a 3010 t Transaction
8a1512f9
JH
3011 }
3012 tests := []struct {
3013 name string
3014 args args
3015 wantRes []Transaction
8a1512f9
JH
3016 }{
3017 {
3018 name: "when user does not have required permission",
3019 args: args{
3020 cc: &ClientConn{
3021 Account: &Account{
d9bc63a1 3022 Access: accessBitmap{},
8a1512f9
JH
3023 },
3024 },
3025 t: NewTransaction(
a2ef262a 3026 TranOldPostNews, [2]byte{0, 1},
d005ef04 3027 NewField(FieldData, []byte("hai")),
8a1512f9
JH
3028 ),
3029 },
3030 wantRes: []Transaction{
3031 {
8a1512f9 3032 IsReply: 0x01,
153e2eac 3033 ErrorCode: [4]byte{0, 0, 0, 1},
8a1512f9 3034 Fields: []Field{
d005ef04 3035 NewField(FieldError, []byte("You are not allowed to post news.")),
8a1512f9
JH
3036 },
3037 },
3038 },
8a1512f9
JH
3039 },
3040 {
3041 name: "when user posts news update",
3042 args: args{
3043 cc: &ClientConn{
3044 Account: &Account{
3045 Access: func() accessBitmap {
3046 var bits accessBitmap
d9bc63a1 3047 bits.Set(AccessNewsPostArt)
8a1512f9
JH
3048 return bits
3049 }(),
3050 },
3051 Server: &Server{
d9bc63a1
JH
3052 Config: Config{
3053 NewsDateFormat: "",
3054 },
3055 ClientMgr: func() *MockClientMgr {
3056 m := MockClientMgr{}
3057 m.On("List").Return([]*ClientConn{})
3058 return &m
3059 }(),
3060 MessageBoard: func() *mockReadWriteSeeker {
3061 m := mockReadWriteSeeker{}
3062 m.On("Seek", int64(0), 0).Return(int64(0), nil)
3063 m.On("Read", mock.AnythingOfType("[]uint8")).Run(func(args mock.Arguments) {
3064 arg := args.Get(0).([]uint8)
3065 copy(arg, "TEST")
3066 }).Return(4, io.EOF)
3067 m.On("Write", mock.AnythingOfType("[]uint8")).Return(3, nil)
3068 return &m
8a1512f9 3069 }(),
8a1512f9
JH
3070 },
3071 },
3072 t: NewTransaction(
a2ef262a 3073 TranOldPostNews, [2]byte{0, 1},
d005ef04 3074 NewField(FieldData, []byte("hai")),
8a1512f9
JH
3075 ),
3076 },
3077 wantRes: []Transaction{
3078 {
153e2eac 3079 IsReply: 0x01,
8a1512f9
JH
3080 },
3081 },
8a1512f9
JH
3082 },
3083 }
3084 for _, tt := range tests {
3085 t.Run(tt.name, func(t *testing.T) {
a2ef262a 3086 gotRes := HandleTranOldPostNews(tt.args.cc, &tt.args.t)
8a1512f9
JH
3087
3088 tranAssertEqual(t, tt.wantRes, gotRes)
3089 })
3090 }
3091}
c1c44744
JH
3092
3093func TestHandleInviteNewChat(t *testing.T) {
3094 type args struct {
3095 cc *ClientConn
a2ef262a 3096 t Transaction
c1c44744
JH
3097 }
3098 tests := []struct {
3099 name string
3100 args args
3101 wantRes []Transaction
c1c44744
JH
3102 }{
3103 {
3104 name: "when user does not have required permission",
3105 args: args{
3106 cc: &ClientConn{
3107 Account: &Account{
3108 Access: func() accessBitmap {
3109 var bits accessBitmap
3110 return bits
3111 }(),
3112 },
3113 },
a2ef262a 3114 t: NewTransaction(TranInviteNewChat, [2]byte{0, 1}),
c1c44744
JH
3115 },
3116 wantRes: []Transaction{
3117 {
c1c44744 3118 IsReply: 0x01,
153e2eac 3119 ErrorCode: [4]byte{0, 0, 0, 1},
c1c44744 3120 Fields: []Field{
d005ef04 3121 NewField(FieldError, []byte("You are not allowed to request private chat.")),
c1c44744
JH
3122 },
3123 },
3124 },
c1c44744
JH
3125 },
3126 {
3127 name: "when userA invites userB to new private chat",
3128 args: args{
3129 cc: &ClientConn{
a2ef262a 3130 ID: [2]byte{0, 1},
c1c44744
JH
3131 Account: &Account{
3132 Access: func() accessBitmap {
3133 var bits accessBitmap
d9bc63a1 3134 bits.Set(AccessOpenChat)
c1c44744
JH
3135 return bits
3136 }(),
3137 },
3138 UserName: []byte("UserA"),
3139 Icon: []byte{0, 1},
a2ef262a 3140 Flags: [2]byte{0, 0},
c1c44744 3141 Server: &Server{
d9bc63a1
JH
3142 ClientMgr: func() *MockClientMgr {
3143 m := MockClientMgr{}
3144 m.On("Get", ClientID{0x0, 0x2}).Return(&ClientConn{
a2ef262a 3145 ID: [2]byte{0, 2},
c1c44744 3146 UserName: []byte("UserB"),
d9bc63a1
JH
3147 })
3148 return &m
3149 }(),
3150 ChatMgr: func() *MockChatManager {
3151 m := MockChatManager{}
3152 m.On("New", mock.AnythingOfType("*hotline.ClientConn")).Return(ChatID{0x52, 0xfd, 0xfc, 0x07})
3153 return &m
3154 }(),
c1c44744
JH
3155 },
3156 },
3157 t: NewTransaction(
a2ef262a 3158 TranInviteNewChat, [2]byte{0, 1},
d005ef04 3159 NewField(FieldUserID, []byte{0, 2}),
c1c44744
JH
3160 ),
3161 },
3162 wantRes: []Transaction{
3163 {
a2ef262a 3164 clientID: [2]byte{0, 2},
153e2eac 3165 Type: [2]byte{0, 0x71},
c1c44744 3166 Fields: []Field{
d005ef04
JH
3167 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3168 NewField(FieldUserName, []byte("UserA")),
3169 NewField(FieldUserID, []byte{0, 1}),
c1c44744
JH
3170 },
3171 },
c1c44744 3172 {
a2ef262a 3173 clientID: [2]byte{0, 1},
153e2eac 3174 IsReply: 0x01,
c1c44744 3175 Fields: []Field{
d005ef04
JH
3176 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3177 NewField(FieldUserName, []byte("UserA")),
3178 NewField(FieldUserID, []byte{0, 1}),
3179 NewField(FieldUserIconID, []byte{0, 1}),
3180 NewField(FieldUserFlags, []byte{0, 0}),
c1c44744
JH
3181 },
3182 },
3183 },
c1c44744
JH
3184 },
3185 {
3186 name: "when userA invites userB to new private chat, but UserB has refuse private chat enabled",
3187 args: args{
3188 cc: &ClientConn{
a2ef262a 3189 ID: [2]byte{0, 1},
c1c44744
JH
3190 Account: &Account{
3191 Access: func() accessBitmap {
3192 var bits accessBitmap
d9bc63a1 3193 bits.Set(AccessOpenChat)
c1c44744
JH
3194 return bits
3195 }(),
3196 },
3197 UserName: []byte("UserA"),
3198 Icon: []byte{0, 1},
a2ef262a 3199 Flags: [2]byte{0, 0},
c1c44744 3200 Server: &Server{
d9bc63a1
JH
3201 ClientMgr: func() *MockClientMgr {
3202 m := MockClientMgr{}
3203 m.On("Get", ClientID{0, 2}).Return(&ClientConn{
a2ef262a 3204 ID: [2]byte{0, 2},
d9bc63a1 3205 Icon: []byte{0, 1},
c1c44744 3206 UserName: []byte("UserB"),
a2ef262a 3207 Flags: [2]byte{255, 255},
d9bc63a1
JH
3208 })
3209 return &m
3210 }(),
3211 ChatMgr: func() *MockChatManager {
3212 m := MockChatManager{}
3213 m.On("New", mock.AnythingOfType("*hotline.ClientConn")).Return(ChatID{0x52, 0xfd, 0xfc, 0x07})
3214 return &m
3215 }(),
c1c44744
JH
3216 },
3217 },
3218 t: NewTransaction(
a2ef262a 3219 TranInviteNewChat, [2]byte{0, 1},
d005ef04 3220 NewField(FieldUserID, []byte{0, 2}),
c1c44744
JH
3221 ),
3222 },
3223 wantRes: []Transaction{
3224 {
a2ef262a 3225 clientID: [2]byte{0, 1},
153e2eac 3226 Type: [2]byte{0, 0x68},
c1c44744 3227 Fields: []Field{
d005ef04
JH
3228 NewField(FieldData, []byte("UserB does not accept private chats.")),
3229 NewField(FieldUserName, []byte("UserB")),
3230 NewField(FieldUserID, []byte{0, 2}),
3231 NewField(FieldOptions, []byte{0, 2}),
c1c44744
JH
3232 },
3233 },
3234 {
a2ef262a 3235 clientID: [2]byte{0, 1},
153e2eac 3236 IsReply: 0x01,
c1c44744 3237 Fields: []Field{
d005ef04
JH
3238 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3239 NewField(FieldUserName, []byte("UserA")),
3240 NewField(FieldUserID, []byte{0, 1}),
3241 NewField(FieldUserIconID, []byte{0, 1}),
3242 NewField(FieldUserFlags, []byte{0, 0}),
c1c44744
JH
3243 },
3244 },
3245 },
c1c44744
JH
3246 },
3247 }
3248 for _, tt := range tests {
3249 t.Run(tt.name, func(t *testing.T) {
d9bc63a1 3250
a2ef262a
JH
3251 gotRes := HandleInviteNewChat(tt.args.cc, &tt.args.t)
3252
c1c44744
JH
3253 tranAssertEqual(t, tt.wantRes, gotRes)
3254 })
3255 }
3256}
33265393
JH
3257
3258func TestHandleGetNewsArtData(t *testing.T) {
3259 type args struct {
3260 cc *ClientConn
a2ef262a 3261 t Transaction
33265393
JH
3262 }
3263 tests := []struct {
3264 name string
3265 args args
3266 wantRes []Transaction
33265393
JH
3267 }{
3268 {
3269 name: "when user does not have required permission",
d9bc63a1
JH
3270 args: args{
3271 cc: &ClientConn{Account: &Account{}},
3272 t: NewTransaction(
3273 TranGetNewsArtData, [2]byte{0, 1},
3274 ),
3275 },
3276 wantRes: []Transaction{
3277 {
3278 IsReply: 0x01,
3279 ErrorCode: [4]byte{0, 0, 0, 1},
3280 Fields: []Field{
3281 NewField(FieldError, []byte("You are not allowed to read news.")),
3282 },
3283 },
3284 },
3285 },
3286 {
3287 name: "when user has required permission",
33265393
JH
3288 args: args{
3289 cc: &ClientConn{
3290 Account: &Account{
3291 Access: func() accessBitmap {
3292 var bits accessBitmap
d9bc63a1 3293 bits.Set(AccessNewsReadArt)
33265393
JH
3294 return bits
3295 }(),
3296 },
3297 Server: &Server{
d9bc63a1
JH
3298 ThreadedNewsMgr: func() *mockThreadNewsMgr {
3299 m := mockThreadNewsMgr{}
3300 m.On("GetArticle", []string{"Example Category"}, uint32(1)).Return(&NewsArtData{
3301 Title: "title",
3302 Poster: "poster",
3303 Date: [8]byte{},
3304 PrevArt: [4]byte{0, 0, 0, 1},
3305 NextArt: [4]byte{0, 0, 0, 2},
3306 ParentArt: [4]byte{0, 0, 0, 3},
3307 FirstChildArt: [4]byte{0, 0, 0, 4},
3308 DataFlav: []byte("text/plain"),
3309 Data: "article data",
3310 })
3311 return &m
3312 }(),
33265393
JH
3313 },
3314 },
3315 t: NewTransaction(
a2ef262a 3316 TranGetNewsArtData, [2]byte{0, 1},
d9bc63a1
JH
3317 NewField(FieldNewsPath, []byte{
3318 // Example Category
3319 0x00, 0x01, 0x00, 0x00, 0x10, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79,
3320 }),
3321 NewField(FieldNewsArtID, []byte{0, 1}),
33265393
JH
3322 ),
3323 },
3324 wantRes: []Transaction{
3325 {
d9bc63a1 3326 IsReply: 1,
33265393 3327 Fields: []Field{
d9bc63a1
JH
3328 NewField(FieldNewsArtTitle, []byte("title")),
3329 NewField(FieldNewsArtPoster, []byte("poster")),
3330 NewField(FieldNewsArtDate, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
3331 NewField(FieldNewsArtPrevArt, []byte{0, 0, 0, 1}),
3332 NewField(FieldNewsArtNextArt, []byte{0, 0, 0, 2}),
3333 NewField(FieldNewsArtParentArt, []byte{0, 0, 0, 3}),
3334 NewField(FieldNewsArt1stChildArt, []byte{0, 0, 0, 4}),
3335 NewField(FieldNewsArtDataFlav, []byte("text/plain")),
3336 NewField(FieldNewsArtData, []byte("article data")),
33265393
JH
3337 },
3338 },
3339 },
33265393
JH
3340 },
3341 }
3342 for _, tt := range tests {
3343 t.Run(tt.name, func(t *testing.T) {
a2ef262a 3344 gotRes := HandleGetNewsArtData(tt.args.cc, &tt.args.t)
33265393
JH
3345 tranAssertEqual(t, tt.wantRes, gotRes)
3346 })
3347 }
3348}
860861f2
JH
3349
3350func TestHandleGetNewsArtNameList(t *testing.T) {
3351 type args struct {
3352 cc *ClientConn
a2ef262a 3353 t Transaction
860861f2
JH
3354 }
3355 tests := []struct {
3356 name string
3357 args args
3358 wantRes []Transaction
860861f2
JH
3359 }{
3360 {
3361 name: "when user does not have required permission",
3362 args: args{
3363 cc: &ClientConn{
3364 Account: &Account{
3365 Access: func() accessBitmap {
3366 var bits accessBitmap
3367 return bits
3368 }(),
3369 },
3370 Server: &Server{
d9bc63a1 3371 //Accounts: map[string]*Account{},
860861f2
JH
3372 },
3373 },
3374 t: NewTransaction(
a2ef262a 3375 TranGetNewsArtNameList, [2]byte{0, 1},
860861f2
JH
3376 ),
3377 },
3378 wantRes: []Transaction{
3379 {
3380 Flags: 0x00,
3381 IsReply: 0x01,
153e2eac
JH
3382 Type: [2]byte{0, 0},
3383 ErrorCode: [4]byte{0, 0, 0, 1},
860861f2 3384 Fields: []Field{
d005ef04 3385 NewField(FieldError, []byte("You are not allowed to read news.")),
860861f2
JH
3386 },
3387 },
3388 },
860861f2 3389 },
d9bc63a1
JH
3390 //{
3391 // name: "when user has required access",
3392 // args: args{
3393 // cc: &ClientConn{
3394 // Account: &Account{
3395 // Access: func() accessBitmap {
3396 // var bits accessBitmap
3397 // bits.Set(AccessNewsReadArt)
3398 // return bits
3399 // }(),
3400 // },
3401 // Server: &Server{
3402 // ThreadedNewsMgr: func() *mockThreadNewsMgr {
3403 // m := mockThreadNewsMgr{}
3404 // m.On("ListArticles", []string{"Example Category"}).Return(NewsArtListData{
3405 // Name: []byte("testTitle"),
3406 // NewsArtList: []byte{},
3407 // })
3408 // return &m
3409 // }(),
3410 // },
3411 // },
3412 // t: NewTransaction(
3413 // TranGetNewsArtNameList,
3414 // [2]byte{0, 1},
3415 // // 00000000 00 01 00 00 10 45 78 61 6d 70 6c 65 20 43 61 74 |.....Example Cat|
3416 // // 00000010 65 67 6f 72 79 |egory|
3417 // NewField(FieldNewsPath, []byte{
3418 // 0x00, 0x01, 0x00, 0x00, 0x10, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79,
3419 // }),
3420 // ),
3421 // },
3422 // wantRes: []Transaction{
3423 // {
3424 // IsReply: 0x01,
3425 // Fields: []Field{
3426 // NewField(FieldNewsArtListData, []byte{
3427 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
3428 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
3429 // 0x09, 0x74, 0x65, 0x73, 0x74, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x50,
3430 // 0x6f, 0x73, 0x74, 0x65, 0x72, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e,
3431 // 0x00, 0x08,
3432 // },
3433 // ),
3434 // },
3435 // },
3436 // },
3437 //},
860861f2
JH
3438 }
3439 for _, tt := range tests {
3440 t.Run(tt.name, func(t *testing.T) {
a2ef262a
JH
3441 gotRes := HandleGetNewsArtNameList(tt.args.cc, &tt.args.t)
3442
860861f2 3443 tranAssertEqual(t, tt.wantRes, gotRes)
860861f2
JH
3444 })
3445 }
3446}
3447
3448func TestHandleNewNewsFldr(t *testing.T) {
3449 type args struct {
3450 cc *ClientConn
a2ef262a 3451 t Transaction
860861f2
JH
3452 }
3453 tests := []struct {
3454 name string
3455 args args
3456 wantRes []Transaction
860861f2
JH
3457 }{
3458 {
3459 name: "when user does not have required permission",
3460 args: args{
3461 cc: &ClientConn{
3462 Account: &Account{
3463 Access: func() accessBitmap {
3464 var bits accessBitmap
3465 return bits
3466 }(),
3467 },
3468 Server: &Server{
d9bc63a1 3469 //Accounts: map[string]*Account{},
860861f2
JH
3470 },
3471 },
3472 t: NewTransaction(
a2ef262a 3473 TranGetNewsArtNameList, [2]byte{0, 1},
860861f2
JH
3474 ),
3475 },
3476 wantRes: []Transaction{
3477 {
3478 Flags: 0x00,
3479 IsReply: 0x01,
153e2eac
JH
3480 Type: [2]byte{0, 0},
3481 ErrorCode: [4]byte{0, 0, 0, 1},
860861f2 3482 Fields: []Field{
d005ef04 3483 NewField(FieldError, []byte("You are not allowed to create news folders.")),
860861f2
JH
3484 },
3485 },
3486 },
860861f2
JH
3487 },
3488 {
3489 name: "with a valid request",
3490 args: args{
3491 cc: &ClientConn{
3492 Account: &Account{
3493 Access: func() accessBitmap {
3494 var bits accessBitmap
d9bc63a1 3495 bits.Set(AccessNewsCreateFldr)
860861f2
JH
3496 return bits
3497 }(),
3498 },
3499 logger: NewTestLogger(),
a2ef262a 3500 ID: [2]byte{0, 1},
860861f2 3501 Server: &Server{
d9bc63a1
JH
3502 ThreadedNewsMgr: func() *mockThreadNewsMgr {
3503 m := mockThreadNewsMgr{}
3504 m.On("CreateGrouping", []string{"test"}, "testFolder", NewsBundle).Return(nil)
3505 return &m
860861f2 3506 }(),
860861f2
JH
3507 },
3508 },
3509 t: NewTransaction(
a2ef262a 3510 TranGetNewsArtNameList, [2]byte{0, 1},
d005ef04
JH
3511 NewField(FieldFileName, []byte("testFolder")),
3512 NewField(FieldNewsPath,
860861f2
JH
3513 []byte{
3514 0, 1,
3515 0, 0,
3516 4,
3517 0x74, 0x65, 0x73, 0x74,
3518 },
3519 ),
3520 ),
3521 },
3522 wantRes: []Transaction{
3523 {
a2ef262a 3524 clientID: [2]byte{0, 1},
153e2eac
JH
3525 IsReply: 0x01,
3526 Fields: []Field{},
860861f2
JH
3527 },
3528 },
860861f2
JH
3529 },
3530 //{
95159e55 3531 // Name: "when there is an error writing the threaded news file",
860861f2
JH
3532 // args: args{
3533 // cc: &ClientConn{
3534 // Account: &Account{
3535 // Access: func() accessBitmap {
3536 // var bits accessBitmap
d9bc63a1 3537 // bits.Set(AccessNewsCreateFldr)
860861f2
JH
3538 // return bits
3539 // }(),
3540 // },
3541 // logger: NewTestLogger(),
d9bc63a1 3542 // Type: [2]byte{0, 1},
860861f2
JH
3543 // Server: &Server{
3544 // ConfigDir: "/fakeConfigRoot",
3545 // FS: func() *MockFileStore {
3546 // mfs := &MockFileStore{}
3547 // mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(os.ErrNotExist)
3548 // return mfs
3549 // }(),
3550 // ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3551 // "test": {
3552 // Type: []byte{0, 2},
3553 // Count: nil,
3554 // NameSize: 0,
3555 // Name: "test",
3556 // SubCats: make(map[string]NewsCategoryListData15),
3557 // },
3558 // }},
3559 // },
3560 // },
3561 // t: NewTransaction(
a2ef262a 3562 // TranGetNewsArtNameList, [2]byte{0, 1},
d005ef04
JH
3563 // NewField(FieldFileName, []byte("testFolder")),
3564 // NewField(FieldNewsPath,
860861f2
JH
3565 // []byte{
3566 // 0, 1,
3567 // 0, 0,
3568 // 4,
3569 // 0x74, 0x65, 0x73, 0x74,
3570 // },
3571 // ),
3572 // ),
3573 // },
3574 // wantRes: []Transaction{
3575 // {
a2ef262a 3576 // clientID: [2]byte{0, 1},
860861f2
JH
3577 // Flags: 0x00,
3578 // IsReply: 0x01,
153e2eac
JH
3579 // Type: [2]byte{0, 0},
3580 // ErrorCode: [4]byte{0, 0, 0, 1},
860861f2 3581 // Fields: []Field{
d005ef04 3582 // NewField(FieldError, []byte("Error creating news folder.")),
860861f2
JH
3583 // },
3584 // },
3585 // },
860861f2
JH
3586 }
3587 for _, tt := range tests {
3588 t.Run(tt.name, func(t *testing.T) {
a2ef262a
JH
3589 gotRes := HandleNewNewsFldr(tt.args.cc, &tt.args.t)
3590
860861f2
JH
3591 tranAssertEqual(t, tt.wantRes, gotRes)
3592 })
3593 }
3594}
0ed51327
JH
3595
3596func TestHandleDownloadBanner(t *testing.T) {
3597 type args struct {
3598 cc *ClientConn
a2ef262a 3599 t Transaction
0ed51327
JH
3600 }
3601 tests := []struct {
3602 name string
3603 args args
3604 wantRes []Transaction
0ed51327
JH
3605 }{
3606 // TODO: Add test cases.
3607 }
3608 for _, tt := range tests {
3609 t.Run(tt.name, func(t *testing.T) {
a2ef262a
JH
3610 gotRes := HandleDownloadBanner(tt.args.cc, &tt.args.t)
3611
3612 assert.Equalf(t, tt.wantRes, gotRes, "HandleDownloadBanner(%v, %v)", tt.args.cc, &tt.args.t)
3613 })
3614 }
3615}
3616
3617func TestHandlePostNewsArt(t *testing.T) {
3618 type args struct {
3619 cc *ClientConn
3620 t Transaction
3621 }
3622 tests := []struct {
3623 name string
3624 args args
3625 wantRes []Transaction
3626 }{
3627 {
3628 name: "without required permission",
3629 args: args{
3630 cc: &ClientConn{
3631 Account: &Account{
3632 Access: func() accessBitmap {
3633 var bits accessBitmap
3634 return bits
3635 }(),
3636 },
3637 },
3638 t: NewTransaction(
3639 TranPostNewsArt,
3640 [2]byte{0, 0},
3641 ),
3642 },
3643 wantRes: []Transaction{
3644 {
3645 IsReply: 0x01,
3646 ErrorCode: [4]byte{0, 0, 0, 1},
3647 Fields: []Field{
3648 NewField(FieldError, []byte("You are not allowed to post news articles.")),
3649 },
3650 },
3651 },
3652 },
3653 {
3654 name: "with required permission",
3655 args: args{
3656 cc: &ClientConn{
3657 Server: &Server{
d9bc63a1
JH
3658 ThreadedNewsMgr: func() *mockThreadNewsMgr {
3659 m := mockThreadNewsMgr{}
3660 m.On("PostArticle", []string{"www"}, uint32(0), mock.AnythingOfType("hotline.NewsArtData")).Return(nil)
3661 return &m
a2ef262a 3662 }(),
a2ef262a
JH
3663 },
3664 Account: &Account{
3665 Access: func() accessBitmap {
3666 var bits accessBitmap
d9bc63a1 3667 bits.Set(AccessNewsPostArt)
a2ef262a
JH
3668 return bits
3669 }(),
3670 },
3671 },
3672 t: NewTransaction(
3673 TranPostNewsArt,
3674 [2]byte{0, 0},
3675 NewField(FieldNewsPath, []byte{0x00, 0x01, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77}),
3676 NewField(FieldNewsArtID, []byte{0x00, 0x00, 0x00, 0x00}),
3677 ),
3678 },
3679 wantRes: []Transaction{
3680 {
3681 IsReply: 0x01,
3682 ErrorCode: [4]byte{0, 0, 0, 0},
3683 Fields: []Field{},
3684 },
3685 },
3686 },
3687 }
3688 for _, tt := range tests {
3689 t.Run(tt.name, func(t *testing.T) {
3690 tranAssertEqual(t, tt.wantRes, HandlePostNewsArt(tt.args.cc, &tt.args.t))
0ed51327
JH
3691 })
3692 }
3693}