1 package redis
2
3 import (
4 "context"
5 "encoding/json"
6 "reflect"
7 "testing"
8 )
9
10 func TestVectorFP32_Value(t *testing.T) {
11 v := &VectorFP32{Val: []byte{1, 2, 3}}
12 got := v.Value()
13 want := []any{"FP32", []byte{1, 2, 3}}
14 if !reflect.DeepEqual(got, want) {
15 t.Errorf("VectorFP32.Value() = %v, want %v", got, want)
16 }
17 }
18
19 func TestVectorValues_Value(t *testing.T) {
20 v := &VectorValues{Val: []float64{1.1, 2.2}}
21 got := v.Value()
22 want := []any{"Values", 2, 1.1, 2.2}
23 if !reflect.DeepEqual(got, want) {
24 t.Errorf("VectorValues.Value() = %v, want %v", got, want)
25 }
26 }
27
28 func TestVectorRef_Value(t *testing.T) {
29 v := &VectorRef{Name: "foo"}
30 got := v.Value()
31 want := []any{"ele", "foo"}
32 if !reflect.DeepEqual(got, want) {
33 t.Errorf("VectorRef.Value() = %v, want %v", got, want)
34 }
35 }
36
37 func TestVAdd(t *testing.T) {
38 m := &mockCmdable{}
39 c := m.asCmdable()
40 vec := &VectorValues{Val: []float64{1, 2}}
41 c.VAdd(context.Background(), "k", "e", vec)
42 cmd, ok := m.lastCmd.(*BoolCmd)
43 if !ok {
44 t.Fatalf("expected BoolCmd, got %T", m.lastCmd)
45 }
46 if cmd.args[0] != "vadd" || cmd.args[1] != "k" || cmd.args[len(cmd.args)-1] != "e" {
47 t.Errorf("unexpected args: %v", cmd.args)
48 }
49 }
50
51 func TestVAddWithArgs_AllOptions(t *testing.T) {
52 m := &mockCmdable{}
53 c := m.asCmdable()
54 vec := &VectorValues{Val: []float64{1, 2}}
55 args := &VAddArgs{Reduce: 3, Cas: true, NoQuant: true, EF: 5, SetAttr: "attr", M: 2}
56 c.VAddWithArgs(context.Background(), "k", "e", vec, args)
57 cmd := m.lastCmd.(*BoolCmd)
58 found := map[string]bool{}
59 for _, a := range cmd.args {
60 if s, ok := a.(string); ok {
61 found[s] = true
62 }
63 }
64 for _, want := range []string{"reduce", "cas", "noquant", "ef", "setattr", "m"} {
65 if !found[want] {
66 t.Errorf("missing arg: %s", want)
67 }
68 }
69 }
70
71 func TestVCard(t *testing.T) {
72 m := &mockCmdable{}
73 c := m.asCmdable()
74 c.VCard(context.Background(), "k")
75 cmd := m.lastCmd.(*IntCmd)
76 if cmd.args[0] != "vcard" || cmd.args[1] != "k" {
77 t.Errorf("unexpected args: %v", cmd.args)
78 }
79 }
80
81 func TestVDim(t *testing.T) {
82 m := &mockCmdable{}
83 c := m.asCmdable()
84 c.VDim(context.Background(), "k")
85 cmd := m.lastCmd.(*IntCmd)
86 if cmd.args[0] != "vdim" || cmd.args[1] != "k" {
87 t.Errorf("unexpected args: %v", cmd.args)
88 }
89 }
90
91 func TestVEmb(t *testing.T) {
92 m := &mockCmdable{}
93 c := m.asCmdable()
94 c.VEmb(context.Background(), "k", "e", true)
95 cmd := m.lastCmd.(*SliceCmd)
96 if cmd.args[0] != "vemb" || cmd.args[1] != "k" || cmd.args[2] != "e" || cmd.args[3] != "raw" {
97 t.Errorf("unexpected args: %v", cmd.args)
98 }
99 }
100
101 func TestVGetAttr(t *testing.T) {
102 m := &mockCmdable{}
103 c := m.asCmdable()
104 c.VGetAttr(context.Background(), "k", "e")
105 cmd := m.lastCmd.(*StringCmd)
106 if cmd.args[0] != "vgetattr" || cmd.args[1] != "k" || cmd.args[2] != "e" {
107 t.Errorf("unexpected args: %v", cmd.args)
108 }
109 }
110
111 func TestVInfo(t *testing.T) {
112 m := &mockCmdable{}
113 c := m.asCmdable()
114 c.VInfo(context.Background(), "k")
115 cmd := m.lastCmd.(*MapStringInterfaceCmd)
116 if cmd.args[0] != "vinfo" || cmd.args[1] != "k" {
117 t.Errorf("unexpected args: %v", cmd.args)
118 }
119 }
120
121 func TestVLinks(t *testing.T) {
122 m := &mockCmdable{}
123 c := m.asCmdable()
124 c.VLinks(context.Background(), "k", "e")
125 cmd := m.lastCmd.(*StringSliceCmd)
126 if cmd.args[0] != "vlinks" || cmd.args[1] != "k" || cmd.args[2] != "e" {
127 t.Errorf("unexpected args: %v", cmd.args)
128 }
129 }
130
131 func TestVLinksWithScores(t *testing.T) {
132 m := &mockCmdable{}
133 c := m.asCmdable()
134 c.VLinksWithScores(context.Background(), "k", "e")
135 cmd := m.lastCmd.(*VectorScoreSliceCmd)
136 if cmd.args[0] != "vlinks" || cmd.args[1] != "k" || cmd.args[2] != "e" || cmd.args[3] != "withscores" {
137 t.Errorf("unexpected args: %v", cmd.args)
138 }
139 }
140
141 func TestVRandMember(t *testing.T) {
142 m := &mockCmdable{}
143 c := m.asCmdable()
144 c.VRandMember(context.Background(), "k")
145 cmd := m.lastCmd.(*StringCmd)
146 if cmd.args[0] != "vrandmember" || cmd.args[1] != "k" {
147 t.Errorf("unexpected args: %v", cmd.args)
148 }
149 }
150
151 func TestVRandMemberCount(t *testing.T) {
152 m := &mockCmdable{}
153 c := m.asCmdable()
154 c.VRandMemberCount(context.Background(), "k", 5)
155 cmd := m.lastCmd.(*StringSliceCmd)
156 if cmd.args[0] != "vrandmember" || cmd.args[1] != "k" || cmd.args[2] != 5 {
157 t.Errorf("unexpected args: %v", cmd.args)
158 }
159 }
160
161 func TestVRem(t *testing.T) {
162 m := &mockCmdable{}
163 c := m.asCmdable()
164 c.VRem(context.Background(), "k", "e")
165 cmd := m.lastCmd.(*BoolCmd)
166 if cmd.args[0] != "vrem" || cmd.args[1] != "k" || cmd.args[2] != "e" {
167 t.Errorf("unexpected args: %v", cmd.args)
168 }
169 }
170
171 func TestVSetAttr_String(t *testing.T) {
172 m := &mockCmdable{}
173 c := m.asCmdable()
174 c.VSetAttr(context.Background(), "k", "e", "foo")
175 cmd := m.lastCmd.(*BoolCmd)
176 if cmd.args[0] != "vsetattr" || cmd.args[1] != "k" || cmd.args[2] != "e" || cmd.args[3] != "foo" {
177 t.Errorf("unexpected args: %v", cmd.args)
178 }
179 }
180
181 func TestVSetAttr_Bytes(t *testing.T) {
182 m := &mockCmdable{}
183 c := m.asCmdable()
184 c.VSetAttr(context.Background(), "k", "e", []byte("bar"))
185 cmd := m.lastCmd.(*BoolCmd)
186 if cmd.args[3] != "bar" {
187 t.Errorf("expected 'bar', got %v", cmd.args[3])
188 }
189 }
190
191 func TestVSetAttr_MarshalStruct(t *testing.T) {
192 m := &mockCmdable{}
193 c := m.asCmdable()
194 val := struct{ A int }{A: 1}
195 c.VSetAttr(context.Background(), "k", "e", val)
196 cmd := m.lastCmd.(*BoolCmd)
197 want, _ := json.Marshal(val)
198 if cmd.args[3] != string(want) {
199 t.Errorf("expected marshalled struct, got %v", cmd.args[3])
200 }
201 }
202
203 func TestVSetAttr_MarshalError(t *testing.T) {
204 m := &mockCmdable{}
205 c := m.asCmdable()
206 bad := func() {}
207 cmd := c.VSetAttr(context.Background(), "k", "e", bad)
208 if cmd.Err() == nil {
209 t.Error("expected error for non-marshallable value")
210 }
211 }
212
213 func TestVClearAttributes(t *testing.T) {
214 m := &mockCmdable{}
215 c := m.asCmdable()
216 c.VClearAttributes(context.Background(), "k", "e")
217 cmd := m.lastCmd.(*BoolCmd)
218 if cmd.args[0] != "vsetattr" || cmd.args[3] != "" {
219 t.Errorf("unexpected args: %v", cmd.args)
220 }
221 }
222
223 func TestVSim(t *testing.T) {
224 m := &mockCmdable{}
225 c := m.asCmdable()
226 vec := &VectorValues{Val: []float64{1, 2}}
227 c.VSim(context.Background(), "k", vec)
228 cmd := m.lastCmd.(*StringSliceCmd)
229 if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
230 t.Errorf("unexpected args: %v", cmd.args)
231 }
232 }
233
234 func TestVSimWithScores(t *testing.T) {
235 m := &mockCmdable{}
236 c := m.asCmdable()
237 vec := &VectorValues{Val: []float64{1, 2}}
238 c.VSimWithScores(context.Background(), "k", vec)
239 cmd := m.lastCmd.(*VectorScoreSliceCmd)
240 if cmd.args[0] != "vsim" || cmd.args[1] != "k" || cmd.args[len(cmd.args)-1] != "withscores" {
241 t.Errorf("unexpected args: %v", cmd.args)
242 }
243 }
244
245 func TestVSimWithArgs_AllOptions(t *testing.T) {
246 m := &mockCmdable{}
247 c := m.asCmdable()
248 vec := &VectorValues{Val: []float64{1, 2}}
249 args := &VSimArgs{Count: 2, EF: 3, Filter: "f", FilterEF: 4, Truth: true, NoThread: true}
250 c.VSimWithArgs(context.Background(), "k", vec, args)
251 cmd := m.lastCmd.(*StringSliceCmd)
252 found := map[string]bool{}
253 for _, a := range cmd.args {
254 if s, ok := a.(string); ok {
255 found[s] = true
256 }
257 }
258 for _, want := range []string{"count", "ef", "filter", "filter-ef", "truth", "nothread"} {
259 if !found[want] {
260 t.Errorf("missing arg: %s", want)
261 }
262 }
263 }
264
265 func TestVSimWithArgsWithScores_AllOptions(t *testing.T) {
266 m := &mockCmdable{}
267 c := m.asCmdable()
268 vec := &VectorValues{Val: []float64{1, 2}}
269 args := &VSimArgs{Count: 2, EF: 3, Filter: "f", FilterEF: 4, Truth: true, NoThread: true}
270 c.VSimWithArgsWithScores(context.Background(), "k", vec, args)
271 cmd := m.lastCmd.(*VectorScoreSliceCmd)
272 found := map[string]bool{}
273 for _, a := range cmd.args {
274 if s, ok := a.(string); ok {
275 found[s] = true
276 }
277 }
278 for _, want := range []string{"count", "ef", "filter", "filter-ef", "truth", "nothread", "withscores"} {
279 if !found[want] {
280 t.Errorf("missing arg: %s", want)
281 }
282 }
283 }
284
285
286
287 func TestVectorValues_EmptySlice(t *testing.T) {
288 v := &VectorValues{Val: []float64{}}
289 got := v.Value()
290 want := []any{"Values", 0}
291 if !reflect.DeepEqual(got, want) {
292 t.Errorf("VectorValues.Value() with empty slice = %v, want %v", got, want)
293 }
294 }
295
296 func TestVEmb_WithoutRaw(t *testing.T) {
297 m := &mockCmdable{}
298 c := m.asCmdable()
299 c.VEmb(context.Background(), "k", "e", false)
300 cmd := m.lastCmd.(*SliceCmd)
301 if cmd.args[0] != "vemb" || cmd.args[1] != "k" || cmd.args[2] != "e" {
302 t.Errorf("unexpected args: %v", cmd.args)
303 }
304 if len(cmd.args) != 3 {
305 t.Errorf("expected 3 args when raw=false, got %d", len(cmd.args))
306 }
307 }
308
309 func TestVAddWithArgs_Q8Option(t *testing.T) {
310 m := &mockCmdable{}
311 c := m.asCmdable()
312 vec := &VectorValues{Val: []float64{1, 2}}
313 args := &VAddArgs{Q8: true}
314 c.VAddWithArgs(context.Background(), "k", "e", vec, args)
315 cmd := m.lastCmd.(*BoolCmd)
316 found := false
317 for _, a := range cmd.args {
318 if s, ok := a.(string); ok && s == "q8" {
319 found = true
320 break
321 }
322 }
323 if !found {
324 t.Error("missing q8 arg")
325 }
326 }
327
328 func TestVAddWithArgs_BinOption(t *testing.T) {
329 m := &mockCmdable{}
330 c := m.asCmdable()
331 vec := &VectorValues{Val: []float64{1, 2}}
332 args := &VAddArgs{Bin: true}
333 c.VAddWithArgs(context.Background(), "k", "e", vec, args)
334 cmd := m.lastCmd.(*BoolCmd)
335 found := false
336 for _, a := range cmd.args {
337 if s, ok := a.(string); ok && s == "bin" {
338 found = true
339 break
340 }
341 }
342 if !found {
343 t.Error("missing bin arg")
344 }
345 }
346
347 func TestVAddWithArgs_NilArgs(t *testing.T) {
348 m := &mockCmdable{}
349 c := m.asCmdable()
350 vec := &VectorValues{Val: []float64{1, 2}}
351 c.VAddWithArgs(context.Background(), "k", "e", vec, nil)
352 cmd := m.lastCmd.(*BoolCmd)
353 if cmd.args[0] != "vadd" || cmd.args[1] != "k" {
354 t.Errorf("unexpected args: %v", cmd.args)
355 }
356 }
357
358 func TestVSimWithArgs_NilArgs(t *testing.T) {
359 m := &mockCmdable{}
360 c := m.asCmdable()
361 vec := &VectorValues{Val: []float64{1, 2}}
362 c.VSimWithArgs(context.Background(), "k", vec, nil)
363 cmd := m.lastCmd.(*StringSliceCmd)
364 if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
365 t.Errorf("unexpected args: %v", cmd.args)
366 }
367 }
368
369 func TestVSimWithArgsWithScores_NilArgs(t *testing.T) {
370 m := &mockCmdable{}
371 c := m.asCmdable()
372 vec := &VectorValues{Val: []float64{1, 2}}
373 c.VSimWithArgsWithScores(context.Background(), "k", vec, nil)
374 cmd := m.lastCmd.(*VectorScoreSliceCmd)
375 if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
376 t.Errorf("unexpected args: %v", cmd.args)
377 }
378
379 found := false
380 for _, a := range cmd.args {
381 if s, ok := a.(string); ok && s == "withscores" {
382 found = true
383 break
384 }
385 }
386 if !found {
387 t.Error("missing withscores arg")
388 }
389 }
390
391 func TestVAdd_WithVectorFP32(t *testing.T) {
392 m := &mockCmdable{}
393 c := m.asCmdable()
394 vec := &VectorFP32{Val: []byte{1, 2, 3, 4}}
395 c.VAdd(context.Background(), "k", "e", vec)
396 cmd := m.lastCmd.(*BoolCmd)
397 if cmd.args[0] != "vadd" || cmd.args[1] != "k" {
398 t.Errorf("unexpected args: %v", cmd.args)
399 }
400
401 found := false
402 for _, a := range cmd.args {
403 if s, ok := a.(string); ok && s == "FP32" {
404 found = true
405 break
406 }
407 }
408 if !found {
409 t.Error("missing FP32 format in args")
410 }
411 }
412
413 func TestVAdd_WithVectorRef(t *testing.T) {
414 m := &mockCmdable{}
415 c := m.asCmdable()
416 vec := &VectorRef{Name: "ref-vector"}
417 c.VAdd(context.Background(), "k", "e", vec)
418 cmd := m.lastCmd.(*BoolCmd)
419 if cmd.args[0] != "vadd" || cmd.args[1] != "k" {
420 t.Errorf("unexpected args: %v", cmd.args)
421 }
422
423 found := false
424 for _, a := range cmd.args {
425 if s, ok := a.(string); ok && s == "ele" {
426 found = true
427 break
428 }
429 }
430 if !found {
431 t.Error("missing ele format in args")
432 }
433 }
434
435 func TestVSim_WithVectorFP32(t *testing.T) {
436 m := &mockCmdable{}
437 c := m.asCmdable()
438 vec := &VectorFP32{Val: []byte{1, 2, 3, 4}}
439 c.VSim(context.Background(), "k", vec)
440 cmd := m.lastCmd.(*StringSliceCmd)
441 if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
442 t.Errorf("unexpected args: %v", cmd.args)
443 }
444
445 found := false
446 for _, a := range cmd.args {
447 if s, ok := a.(string); ok && s == "FP32" {
448 found = true
449 break
450 }
451 }
452 if !found {
453 t.Error("missing FP32 format in args")
454 }
455 }
456
457 func TestVSim_WithVectorRef(t *testing.T) {
458 m := &mockCmdable{}
459 c := m.asCmdable()
460 vec := &VectorRef{Name: "ref-vector"}
461 c.VSim(context.Background(), "k", vec)
462 cmd := m.lastCmd.(*StringSliceCmd)
463 if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
464 t.Errorf("unexpected args: %v", cmd.args)
465 }
466
467 found := false
468 for _, a := range cmd.args {
469 if s, ok := a.(string); ok && s == "ele" {
470 found = true
471 break
472 }
473 }
474 if !found {
475 t.Error("missing ele format in args")
476 }
477 }
478
479 func TestVAddWithArgs_ReduceOption(t *testing.T) {
480 m := &mockCmdable{}
481 c := m.asCmdable()
482 vec := &VectorValues{Val: []float64{1, 2}}
483 args := &VAddArgs{Reduce: 128}
484 c.VAddWithArgs(context.Background(), "k", "e", vec, args)
485 cmd := m.lastCmd.(*BoolCmd)
486
487 if cmd.args[0] != "vadd" || cmd.args[1] != "k" || cmd.args[2] != "reduce" {
488 t.Errorf("unexpected args order: %v", cmd.args)
489 }
490 }
491
492 func TestVAddWithArgs_ZeroValues(t *testing.T) {
493 m := &mockCmdable{}
494 c := m.asCmdable()
495 vec := &VectorValues{Val: []float64{1, 2}}
496 args := &VAddArgs{Reduce: 0, EF: 0, M: 0}
497 c.VAddWithArgs(context.Background(), "k", "e", vec, args)
498 cmd := m.lastCmd.(*BoolCmd)
499
500 for _, a := range cmd.args {
501 if s, ok := a.(string); ok {
502 if s == "reduce" || s == "ef" || s == "m" {
503 t.Errorf("zero value option should not appear in args: %s", s)
504 }
505 }
506 }
507 }
508
509 func TestVSimArgs_IndividualOptions(t *testing.T) {
510 tests := []struct {
511 name string
512 args *VSimArgs
513 want string
514 }{
515 {"Count", &VSimArgs{Count: 5}, "count"},
516 {"EF", &VSimArgs{EF: 10}, "ef"},
517 {"Filter", &VSimArgs{Filter: "test"}, "filter"},
518 {"FilterEF", &VSimArgs{FilterEF: 15}, "filter-ef"},
519 {"Truth", &VSimArgs{Truth: true}, "truth"},
520 {"NoThread", &VSimArgs{NoThread: true}, "nothread"},
521 }
522
523 for _, tt := range tests {
524 t.Run(tt.name, func(t *testing.T) {
525 m := &mockCmdable{}
526 c := m.asCmdable()
527 vec := &VectorValues{Val: []float64{1, 2}}
528 c.VSimWithArgs(context.Background(), "k", vec, tt.args)
529 cmd := m.lastCmd.(*StringSliceCmd)
530 found := false
531 for _, a := range cmd.args {
532 if s, ok := a.(string); ok && s == tt.want {
533 found = true
534 break
535 }
536 }
537 if !found {
538 t.Errorf("missing arg: %s", tt.want)
539 }
540 })
541 }
542 }
543
View as plain text